@cassius0924/dsh-usage-dashboard 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/lib/client.js +397 -336
- package/lib/client.js.map +4 -4
- package/lib/types/client/boundary.d.ts +26 -0
- package/lib/types/client/cache.d.ts +1 -1
- package/lib/types/client/index.d.ts +0 -5
- package/lib/types/client/styles.d.ts +1 -1
- package/package.json +1 -1
package/lib/client.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/client/index.tsx", "../src/client/dashboard.tsx", "../src/client/cache.ts", "../src/client/api.ts", "../src/client/charts.tsx", "../src/client/prefs.ts", "../src/client/store.ts", "../src/client/styles.ts", "../src/client/widget.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * dsh-usage-dashboard client half: mounts the floating balance widget\n * (`shell.overlay`) and the \u300C\u989D\u5EA6\u300D view tab (`conversation.view`).\n * Data arrives through the package's own host API via same-origin fetch.\n */\nimport type { ClientContext } from './context.ts'\nimport { BalanceDashboard } from './dashboard.tsx'\nimport { css } from './styles.ts'\nimport { QuotaWidget } from './widget.tsx'\n\n/** Plugin identity for the client bundle. */\nexport const name = 'dsh-usage-dashboard'\n\n/** Services required before load. */\nexport const inject = ['slots']\n\n/**\n * Mount the two surfaces.\n * @param ctx - client Cordis context.\n */\nexport function apply(ctx: ClientContext): void {\n // One stylesheet for the whole plugin; the module loader claims and removes\n // plugin-owned style tags on unload.\n if (typeof document !== 'undefined') {\n const tag = document.createElement('style')\n tag.dataset.plugin = 'dsh-usage-dashboard'\n tag.textContent = css\n document.head.appendChild(tag)\n }\n\n ctx.slots.inject('shell.overlay', () => ctx.slots.register(\n { name: 'shell.overlay', id: 'deepseek-quota', order: 1000, label: 'DeepSeek \u989D\u5EA6' },\n () => <QuotaWidget />,\n ))\n\n ctx.slots.inject('conversation.view', () => ctx.slots.register(\n { name: 'conversation.view', id: 'balance', order: 20, label: '\u989D\u5EA6' },\n () => <BalanceDashboard />,\n ))\n}\n", "/** The \u300C\u989D\u5EA6\u300D conversation view tab: full balance & usage dashboard.\n *\n * Caching: the first render comes straight from the package-local cache\n * (see ./api.ts), so reopening the tab shows data instantly. A background\n * refresh then updates it without blocking; a full-screen \u52A0\u8F7D\u4E2D only\n * appears when nothing has ever been cached.\n */\nimport { Fragment, useEffect, useRef, useState, type ReactElement, type ReactNode } from 'react'\nimport { fetchBalance, fetchUsage, getCachedBalance, getCachedUsage } from './api.ts'\nimport { Bars, GroupedBars, Heatmap, MODEL_COLORS, fmt, fmtCompact, fmtInt } from './charts.tsx'\nimport type { BalanceData, ModelUsage, PeakSplit, PeriodUsage, PricingInfo, SessionCost, UsageData } from '../contract.ts'\nimport { lowBalanceStore, widgetVisibleStore } from './store.ts'\n\n/** One shimmering placeholder block, sized by the caller. */\nfunction Skel(props: { w: number; h: number }): ReactElement {\n return <div className=\"dq-skel\" style={{ width: `${props.w}px`, height: `${props.h}px` }} />\n}\n\n/** Placeholder for the balance card while the first fetch is in flight. */\nfunction BalanceSkeleton(): ReactElement {\n return (\n <div className=\"dq-balance-grid\">\n <div className=\"dq-stat\"><Skel w={56} h={11} /><Skel w={150} h={22} /></div>\n <div className=\"dq-stat\"><Skel w={28} h={11} /><Skel w={48} h={22} /></div>\n </div>\n )\n}\n\n/** Placeholder for the usage card: replaying every session log takes seconds,\n * and an empty-state string there would read as \"you have no usage\". */\nfunction UsageSkeleton(): ReactElement {\n return (\n <>\n <div className=\"dq-usage-totals\">\n {[44, 44, 62, 62].map((w, i) => (\n <div key={i} className=\"dq-stat\"><Skel w={w} h={11} /><Skel w={w > 70 ? 84 : 56} h={20} /></div>\n ))}\n </div>\n <Skel w={140} h={12} />\n <div className=\"dq-skel-bars\">\n {Array.from({ length: 30 }, (_, i) => (\n <div key={i} className=\"dq-skel dq-skel-bar\" style={{ height: `${18 + ((i * 37) % 82)}px` }} />\n ))}\n </div>\n </>\n )\n}\n\n/** Percentage chip comparing a window against the one before it. */\nfunction Delta(props: { current: number; previous: number; label: string }): ReactElement | null {\n const { current, previous, label } = props\n if (previous <= 0) {\n if (current <= 0) return null\n return <span className=\"dq-delta dq-delta--new\" title={`${label}\u6CA1\u6709\u7528\u91CF\uFF0C\u65E0\u4ECE\u5BF9\u6BD4`}>\u65E0\u5BF9\u6BD4</span>\n }\n const percent = Math.round(((current - previous) / previous) * 100)\n const title = `${label} \u00A5${fmt(previous)}`\n if (percent === 0) return <span className=\"dq-delta dq-delta--flat\" title={title}>\u6301\u5E73</span>\n const up = percent > 0\n return (\n <span className={`dq-delta ${up ? 'dq-delta--up' : 'dq-delta--down'}`} title={title}>\n {up ? '\u2191' : '\u2193'}{Math.abs(percent)}% <span className=\"dq-delta-label\">{label}</span>\n </span>\n )\n}\n\n/** One window of the \u6D88\u8017\u6982\u89C8 card: cost headline, volume underneath. */\nfunction Period(props: {\n label: string\n period: PeriodUsage\n previous?: PeriodUsage\n compare?: string\n}): ReactElement {\n const { period, previous, compare } = props\n return (\n <div className=\"dq-period\">\n <div className=\"dq-period-head\">\n <span className=\"dq-period-label\">{props.label}</span>\n {previous !== undefined && compare !== undefined && (\n <Delta current={period.cost} previous={previous.cost} label={compare} />\n )}\n </div>\n <div className=\"dq-period-cost\">\u00A5 {fmt(period.cost)}</div>\n <div className=\"dq-period-sub\">{fmtCompact(period.total)} tokens \u00B7 {fmtInt(period.calls)} \u6B21\u8C03\u7528</div>\n </div>\n )\n}\n\nconst rate = (value: number): string => `\u00A5${value.toLocaleString(undefined, { maximumFractionDigits: 3 })}`\n\n/** Auditable breakdown of the rates the cost estimate was computed with \u2014\n * a `<details>` so it is keyboard-reachable without any extra state. */\nfunction PricingNote(props: { pricing: PricingInfo }): ReactElement {\n const { pricing } = props\n const split = pricing.splitActive\n return (\n <details className=\"dq-pricing\">\n <summary className=\"dq-pricing-summary\">\n \u8BA1\u4EF7\u8BF4\u660E\n {split && (\n <span className={`dq-pricing-now${pricing.inPeakNow ? ' dq-pricing-now--peak' : ''}`}>\n \u5F53\u524D {pricing.inPeakNow ? '\u9AD8\u5CF0\u65F6\u6BB5' : '\u95F2\u65F6'}\n </span>\n )}\n </summary>\n <div className=\"dq-pricing-body\">\n <table className=\"dq-pricing-table\">\n <thead>\n <tr>\n <th>\u6A21\u578B</th>\n <th>{split ? '\u65F6\u6BB5' : '\u5355\u4EF7'}</th>\n <th>\u8F93\u5165\u00B7\u7F13\u5B58\u547D\u4E2D</th>\n <th>\u8F93\u5165\u00B7\u672A\u547D\u4E2D</th>\n <th>\u8F93\u51FA</th>\n </tr>\n </thead>\n <tbody>\n {pricing.tiers.map(tier => (\n <Fragment key={tier.model}>\n <tr>\n <td rowSpan={tier.offPeak !== null ? 2 : 1}>{tier.model}</td>\n <td>{split ? '\u9AD8\u5CF0' : '\u56FA\u5B9A'}</td>\n <td>{rate(tier.peak.cacheHit)}</td>\n <td>{rate(tier.peak.input)}</td>\n <td>{rate(tier.peak.output)}</td>\n </tr>\n {tier.offPeak !== null && (\n <tr>\n <td>\u95F2\u65F6</td>\n <td>{rate(tier.offPeak.cacheHit)}</td>\n <td>{rate(tier.offPeak.input)}</td>\n <td>{rate(tier.offPeak.output)}</td>\n </tr>\n )}\n </Fragment>\n ))}\n </tbody>\n </table>\n <p className=\"dq-pricing-foot\">\n \u5355\u4F4D\uFF1A{pricing.currency} / \u767E\u4E07 tokens\u3002\n {split\n ? `\u9AD8\u5CF0\u65F6\u6BB5\u4E3A\u5317\u4EAC\u65F6\u95F4 ${pricing.peakWindows.join('\u3001')}\uFF0C\u5176\u4F59\u4E3A\u95F2\u65F6\uFF08\u4EF7\u683C\u51CF\u534A\uFF09\uFF1B${pricing.switchDate} \u4E4B\u524D\u7684\u7528\u91CF\u4ECD\u6309\u65E7\u4EF7\u4F30\u7B97\u3002`\n : `${pricing.switchDate} 00:00 \u8D77\u6539\u4E3A\u5CF0\u8C37\u5B9A\u4EF7\uFF08\u9AD8\u5CF0 ${pricing.peakWindows.join('\u3001')}\uFF0C\u95F2\u65F6\u4EF7\u683C\u51CF\u534A\uFF09\uFF0C\u5C4A\u65F6\u672C\u9875\u4F1A\u6309\u6BCF\u6761\u8BB0\u5F55\u7684\u65F6\u95F4\u81EA\u52A8\u5206\u6BB5\u8BA1\u4EF7\u3002`}\n \u672A\u77E5\u6A21\u578B\u6309 deepseek-v4-pro \u8BA1\u4EF7\u3002\n </p>\n </div>\n </details>\n )\n}\n\nfunction Stat(props: { label: string; children: ReactNode }): ReactElement {\n return (\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{props.label}</div>\n {props.children}\n </div>\n )\n}\n\nfunction Link(props: { href: string; children: ReactNode }): ReactElement {\n return (\n <a className=\"dq-link\" href={props.href} target=\"_blank\" rel=\"noreferrer\">{props.children}</a>\n )\n}\n\nexport const modelKeyOf = (m: ModelUsage): string => (m.provider !== '' ? `${m.provider}/${m.model}` : m.model)\n\nexport const modelNameOf = (m: ModelUsage): string => (m.model !== '' ? m.model : '\u672A\u77E5\u6A21\u578B')\n\n/**\n * What prefix caching is doing for the bill. Cache-hit tokens are priced at a\n * small fraction of cache-miss tokens, so on a DSH workload this is usually the\n * single biggest lever on cost \u2014 and it was invisible before.\n */\nfunction CacheCard(props: { totals: UsageData['totals'] }): ReactElement {\n const { totals } = props\n const prompt = totals.input + totals.cache\n if (prompt === 0) return <div className=\"dq-empty\">\u8FD8\u6CA1\u6709 prompt token \u53EF\u7EDF\u8BA1\u7F13\u5B58\u547D\u4E2D\u3002</div>\n const rate = totals.cache / prompt\n const wouldHaveCost = totals.cost + totals.cacheSavings\n const low = rate < 0.6\n return (\n <div className=\"dq-cache\">\n <div className=\"dq-cache-figures\">\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u7F13\u5B58\u547D\u4E2D\u7387</div>\n <div className={`dq-stat-value${low ? ' dq-stat-value--warn' : ' dq-stat-value--ok'}`}>\n {(rate * 100).toFixed(1)}%\n </div>\n </div>\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u5DF2\u8282\u7701\u8D39\u7528\uFF08\u4F30\u7B97\uFF09</div>\n <div className=\"dq-stat-value\">\u00A5 {fmt(totals.cacheSavings)}</div>\n </div>\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u82E5\u5168\u90E8\u672A\u547D\u4E2D</div>\n <div className=\"dq-stat-value dq-muted-value\">\u00A5 {fmt(wouldHaveCost)}</div>\n </div>\n </div>\n <div className=\"dq-cache-track\" role=\"img\" aria-label={`\u7F13\u5B58\u547D\u4E2D ${(rate * 100).toFixed(1)}%\uFF0C\u672A\u547D\u4E2D ${((1 - rate) * 100).toFixed(1)}%`}>\n <div className=\"dq-cache-fill\" style={{ width: `${rate * 100}%` }} />\n </div>\n <div className=\"dq-cache-legend\">\n <span><span className=\"dq-legend-swatch dq-legend-swatch--hit\" />\u7F13\u5B58\u547D\u4E2D {fmtCompact(totals.cache)}</span>\n <span><span className=\"dq-legend-swatch dq-legend-swatch--miss\" />\u672A\u547D\u4E2D {fmtCompact(totals.input)}\uFF08\u6309\u672A\u547D\u4E2D\u4EF7\u8BA1\u8D39\uFF09</span>\n </div>\n <p className=\"dq-cache-foot\">\n {low\n ? '\u547D\u4E2D\u7387\u504F\u4F4E\uFF1A\u9891\u7E41\u6539\u52A8 system prompt / \u5DE5\u5177\u5B9A\u4E49\u4F1A\u8BA9\u524D\u7F00\u7F13\u5B58\u5931\u6548\uFF0C\u628A\u7A33\u5B9A\u5185\u5BB9\u653E\u5728\u5BF9\u8BDD\u6700\u524D\u9762\u80FD\u63D0\u9AD8\u547D\u4E2D\u7387\u3002'\n : '\u524D\u7F00\u7F13\u5B58\u628A\u91CD\u590D\u7684 prompt \u524D\u7F00\u6309\u547D\u4E2D\u4EF7\u8BA1\u8D39\uFF0C\u662F\u8FD9\u4EFD\u8D26\u5355\u4E0A\u6700\u5927\u7684\u7701\u94B1\u6760\u6746\u3002'}\n </p>\n </div>\n )\n}\n\n/**\n * Peak vs off-peak: which side of DeepSeek's price windows the usage falls on.\n * Before the 2026-08-17 switch this answers \"what will the new prices cost me\";\n * after it, \"what would shifting work off-peak save me\".\n */\nfunction PeakCard(props: { split: PeakSplit; pricing: PricingInfo; currentCost: number }): ReactElement {\n const { split, pricing, currentCost } = props\n const total = split.peak.total + split.offPeak.total\n if (total === 0) return <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u53EF\u6309\u65F6\u6BB5\u5F52\u7C7B\u7684\u7528\u91CF\u3002</div>\n const peakShare = split.peak.total / total\n const shiftSaving = split.peakEraCost - split.offPeakEraCost\n const increase = split.peakEraCost - currentCost\n const increasePercent = currentCost > 0 ? (increase / currentCost) * 100 : 0\n return (\n <div className=\"dq-peak\">\n <div\n className=\"dq-peak-track\"\n role=\"img\"\n aria-label={`\u9AD8\u5CF0\u65F6\u6BB5 ${(peakShare * 100).toFixed(1)}%\uFF0C\u95F2\u65F6 ${((1 - peakShare) * 100).toFixed(1)}%`}\n >\n <div className=\"dq-peak-fill\" style={{ width: `${peakShare * 100}%` }} />\n </div>\n <div className=\"dq-peak-legend\">\n <span><span className=\"dq-legend-swatch dq-legend-swatch--peak\" />\u9AD8\u5CF0 {(peakShare * 100).toFixed(1)}% \u00B7 {fmtCompact(split.peak.total)} tokens \u00B7 {fmtInt(split.peak.calls)} \u6B21</span>\n <span><span className=\"dq-legend-swatch dq-legend-swatch--offpeak\" />\u95F2\u65F6 {((1 - peakShare) * 100).toFixed(1)}% \u00B7 {fmtCompact(split.offPeak.total)} tokens \u00B7 {fmtInt(split.offPeak.calls)} \u6B21</span>\n </div>\n <div className=\"dq-peak-figures\">\n {!pricing.splitActive && (\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u540C\u6837\u7528\u91CF\u5728\u65B0\u4EF7\u4E0B</div>\n <div className=\"dq-stat-value\">\n \u00A5 {fmt(split.peakEraCost)}\n <span className=\"dq-peak-delta\">\u8F83\u73B0\u4EF7 +{increasePercent.toFixed(0)}%</span>\n </div>\n </div>\n )}\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u82E5\u9AD8\u5CF0\u7528\u91CF\u90FD\u632A\u5230\u95F2\u65F6</div>\n <div className=\"dq-stat-value\">\n \u00A5 {fmt(split.offPeakEraCost)}\n <span className=\"dq-peak-delta dq-peak-delta--save\">\u53EF\u7701 \u00A5{fmt(shiftSaving)}</span>\n </div>\n </div>\n </div>\n <p className=\"dq-peak-foot\">\n \u9AD8\u5CF0\u65F6\u6BB5\u4E3A\u5317\u4EAC\u65F6\u95F4 {pricing.peakWindows.join('\u3001')}\uFF0C\u95F2\u65F6\u4EF7\u683C\u51CF\u534A\u3002\n {pricing.splitActive\n ? '\u628A\u6279\u91CF\u3001\u53EF\u5EF6\u540E\u7684\u4EFB\u52A1\u653E\u5230\u95F2\u65F6\u8DD1\uFF0C\u540C\u6837\u7684 token \u53EA\u8981\u4E00\u534A\u7684\u94B1\u3002'\n : `\u65B0\u4EF7 ${pricing.switchDate} 00:00 \u751F\u6548\uFF1B\u4E0A\u9762\u4E24\u4E2A\u6570\u5B57\u662F\u6309\u4F60\u5DF2\u6709\u7684\u5168\u90E8\u7528\u91CF\u91CD\u7B97\u7684\u3002`}\n </p>\n </div>\n )\n}\n\n/** Coarse \"how long ago\", enough to tell a live session from last week's. */\nfunction agoText(ms: number): string {\n const minutes = Math.floor((Date.now() - ms) / 60_000)\n if (minutes < 1) return '\u521A\u521A'\n if (minutes < 60) return `${minutes} \u5206\u949F\u524D`\n const hours = Math.floor(minutes / 60)\n if (hours < 24) return `${hours} \u5C0F\u65F6\u524D`\n return `${Math.floor(hours / 24)} \u5929\u524D`\n}\n\n/**\n * Which sessions burned the money. Per-model and per-day views say what and\n * when; this says *which run*, which is the one an agent user can act on \u2014\n * a single expensive session is a prompt or a loop worth looking at.\n */\nfunction SessionRanking(props: { sessions: SessionCost[]; count: number; totalCost: number }): ReactElement {\n const { sessions, count, totalCost } = props\n if (sessions.length === 0) return <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u4EA7\u751F\u8D39\u7528\u7684\u4F1A\u8BDD\u3002</div>\n const top = sessions[0].cost\n return (\n <>\n <ol className=\"dq-sessions\">\n {sessions.map(s => (\n <li key={s.id} className=\"dq-session\">\n <div className=\"dq-session-head\">\n <span className=\"dq-session-title\" title={`${s.title}\\n${s.id}`}>{s.title}</span>\n <span className=\"dq-session-cost\">\u00A5 {fmt(s.cost)}</span>\n </div>\n <div className=\"dq-session-track\">\n <div className=\"dq-session-fill\" style={{ width: `${Math.max((s.cost / (top || 1)) * 100, 1.5)}%` }} />\n </div>\n <div className=\"dq-session-sub\">\n {fmtCompact(s.total)} tokens \u00B7 {fmtInt(s.calls)} \u6B21\u8C03\u7528 \u00B7 {agoText(s.lastActive)}\n {totalCost > 0 && <> \u00B7 \u5360 {((s.cost / totalCost) * 100).toFixed(1)}%</>}\n </div>\n </li>\n ))}\n </ol>\n {count > sessions.length && (\n <p className=\"dq-session-foot\">\u5171 {fmtInt(count)} \u4E2A\u4F1A\u8BDD\u6709\u7528\u91CF\uFF0C\u4E0A\u9762\u662F\u6700\u8D35\u7684 {sessions.length} \u4E2A\u3002</p>\n )}\n </>\n )\n}\n\n/** Which model the money actually goes to, most expensive first. */\nfunction ModelRanking(props: {\n models: ModelUsage[]\n totalCost: number\n colorOf: (key: string) => string\n}): ReactElement {\n const { models, totalCost } = props\n if (models.length === 0) return <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u53EF\u5F52\u7C7B\u7684\u6A21\u578B\u7528\u91CF\u3002</div>\n return (\n <div className=\"dq-rank\">\n {models.map(m => {\n const key = modelKeyOf(m)\n const share = totalCost > 0 ? m.cost / totalCost : 0\n return (\n <div key={key} className=\"dq-rank-row\">\n <div className=\"dq-rank-head\">\n <span className=\"dq-rank-name\" title={key}>\n <span className=\"dq-legend-swatch\" style={{ background: props.colorOf(key) }} />\n {modelNameOf(m)}\n </span>\n <span className=\"dq-rank-cost\">\n \u00A5 {fmt(m.cost)}\n <span className=\"dq-rank-share\">{(share * 100).toFixed(1)}%</span>\n </span>\n </div>\n <div\n className=\"dq-rank-track\"\n role=\"img\"\n aria-label={`${modelNameOf(m)} \u5360\u603B\u8D39\u7528 ${(share * 100).toFixed(1)}%`}\n >\n <div className=\"dq-rank-fill\" style={{ width: `${Math.max(share * 100, 1.5)}%`, background: props.colorOf(key) }} />\n </div>\n <div className=\"dq-rank-sub\">\n {fmtCompact(m.total)} tokens \u00B7 {fmtInt(m.calls)} \u6B21\u8C03\u7528 \u00B7 \u8F93\u5165 {fmtCompact(m.input)} / \u8F93\u51FA {fmtCompact(m.output)} / \u7F13\u5B58 {fmtCompact(m.cache)}\n </div>\n </div>\n )\n })}\n </div>\n )\n}\n\n/** Multi-select model dropdown feeding the grouped bar chart. */\nfunction ModelPicker(props: {\n models: ModelUsage[]\n selected: string[]\n colorOf: (key: string) => string\n onChange: (keys: string[]) => void\n}): ReactElement | null {\n const { models } = props\n if (models.length === 0) return null\n const [open, setOpen] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n if (!open) return\n const onDown = (e: MouseEvent): void => {\n if (rootRef.current !== null && !rootRef.current.contains(e.target as Node)) setOpen(false)\n }\n document.addEventListener('mousedown', onDown)\n return () => document.removeEventListener('mousedown', onDown)\n }, [open])\n\n const toggle = (key: string): void => {\n props.onChange(\n props.selected.includes(key)\n ? props.selected.filter(k => k !== key)\n : [...props.selected, key],\n )\n }\n\n const label = props.selected.length === 0 ? '\u5168\u90E8\u6A21\u578B' : `\u6A21\u578B \u00D7${props.selected.length}`\n\n return (\n <div className=\"dq-model-picker\" ref={rootRef}>\n <button type=\"button\" className=\"dq-model-btn\" onClick={() => setOpen(!open)}>{label}</button>\n {open && (\n <div className=\"dq-model-menu\">\n <label className=\"dq-model-item dq-model-item--all\">\n <input\n type=\"checkbox\"\n checked={props.selected.length === 0}\n onChange={() => props.onChange([])}\n />\n <span>\u5168\u90E8\u6A21\u578B</span>\n </label>\n {models.map(m => {\n const key = modelKeyOf(m)\n return (\n <label key={key} className=\"dq-model-item\">\n <input type=\"checkbox\" checked={props.selected.includes(key)} onChange={() => toggle(key)} />\n <span className=\"dq-legend-swatch\" style={{ background: props.colorOf(key) }} />\n <span>{modelNameOf(m)}</span>\n <span className=\"dq-model-tag\">{fmtCompact(m.total)}</span>\n </label>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n\nexport function BalanceDashboard(): ReactElement {\n // Seed state from the cache so the tab never waits on the network when\n // data has been fetched before (stale-while-revalidate).\n const cachedBalance = getCachedBalance()\n const cachedUsage = getCachedUsage()\n const [balance, setBalance] = useState<BalanceData | null>(cachedBalance?.data ?? null)\n const [usage, setUsage] = useState<UsageData | null>(cachedUsage?.data ?? null)\n const [error, setError] = useState<string | null>(null)\n const [notice, setNotice] = useState<string | null>(null)\n // Balance answers in well under a second, usage replays every session log and\n // takes seconds \u2014 so they get their own loading flags and paint independently\n // instead of the fast one waiting on the slow one.\n const [loadingBalance, setLoadingBalance] = useState(cachedBalance === null)\n const [loadingUsage, setLoadingUsage] = useState(cachedUsage === null)\n const [refreshing, setRefreshing] = useState(false)\n const hadDataRef = useRef(cachedBalance !== null || cachedUsage !== null)\n const [widgetOn, setWidgetOn] = useState(widgetVisibleStore.get())\n const [lowBalance, setLowBalance] = useState(lowBalanceStore.get())\n const [barMode, setBarMode] = useState<'daily' | 'hourly'>('daily')\n const [selectedModels, setSelectedModels] = useState<string[]>([])\n\n const errText = (err: unknown): string => (err as { message?: string } | null)?.message ?? String(err)\n\n /** Load both resources; each resolves to null on success or to its error\n * string on failure, so a partial failure can name the half that broke. */\n const load = async (force: boolean): Promise<void> => {\n setError(null)\n setNotice(null)\n setRefreshing(true)\n const balanceTask = fetchBalance(force).then(res => {\n if (res.ok && res.data !== undefined) {\n setBalance(res.data)\n hadDataRef.current = true\n return null\n }\n return res.error ?? '\u4F59\u989D\u52A0\u8F7D\u5931\u8D25'\n }, err => errText(err)).then(result => {\n setLoadingBalance(false)\n return result\n })\n const usageTask = fetchUsage(force).then(res => {\n if (res.ok && res.data !== undefined) {\n setUsage(res.data)\n hadDataRef.current = true\n return null\n }\n return res.error ?? '\u7528\u91CF\u52A0\u8F7D\u5931\u8D25'\n }, err => errText(err)).then(result => {\n setLoadingUsage(false)\n return result\n })\n const [balanceError, usageError] = await Promise.all([balanceTask, usageTask])\n setRefreshing(false)\n if (balanceError !== null && usageError !== null) {\n // Nothing came back at all: an error only when there is nothing to show.\n if (hadDataRef.current) setNotice(`\u5237\u65B0\u5931\u8D25\uFF0C\u6B63\u5728\u5C55\u793A\u7F13\u5B58\u6570\u636E\uFF08${balanceError}\uFF09`)\n else setError(balanceError)\n } else if (balanceError !== null) {\n setNotice(`\u4F59\u989D\u5237\u65B0\u5931\u8D25\uFF0C\u6B63\u5728\u5C55\u793A\u7F13\u5B58\u4F59\u989D\uFF08${balanceError}\uFF09`)\n } else if (usageError !== null) {\n setNotice(`\u7528\u91CF\u5237\u65B0\u5931\u8D25\uFF0C\u6B63\u5728\u5C55\u793A\u7F13\u5B58\u7528\u91CF\uFF08${usageError}\uFF09`)\n }\n }\n\n useEffect(() => {\n void load(false)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const toggle = (): void => {\n const next = !widgetOn\n setWidgetOn(next)\n widgetVisibleStore.set(next)\n }\n\n const changeLowBalance = (value: number): void => {\n setLowBalance(value)\n lowBalanceStore.set(value)\n }\n\n const primary = balance !== null && balance.balances.length > 0 ? balance.balances[0] : null\n\n // Runway: balance divided by the last 7 calendar days' average spend. Idle\n // days are included on purpose \u2014 that is the burn rate, not the busy-day rate.\n const recentDays = (usage?.daily ?? []).slice(-7)\n const avgDailyCost = recentDays.length > 0\n ? recentDays.reduce((sum, d) => sum + d.cost, 0) / recentDays.length\n : 0\n const balanceValue = primary !== null ? Number(primary.total) : Number.NaN\n // 0 disables the warning; an unreadable balance never triggers it.\n const balanceLow = lowBalance > 0 && Number.isFinite(balanceValue) && balanceValue < lowBalance\n const daysLeft = avgDailyCost > 0 && Number.isFinite(balanceValue) ? balanceValue / avgDailyCost : null\n const daysLeftText = daysLeft === null\n ? '\u2014'\n : daysLeft >= 365 ? '> 365 \u5929' : `${daysLeft < 10 ? daysLeft.toFixed(1) : Math.round(daysLeft)} \u5929`\n const runwayTitle = daysLeft === null\n ? `\u8FD1 ${recentDays.length || 7} \u5929\u6CA1\u6709\u7528\u91CF\uFF0C\u65E0\u6CD5\u4F30\u7B97`\n : `\u6309\u8FD1 ${recentDays.length} \u5929\u65E5\u5747 \u00A5${fmt(avgDailyCost)} \u4F30\u7B97\uFF08\u542B\u65E0\u7528\u91CF\u7684\u65E5\u5B50\uFF1B\u4ECA\u5929\u5C1A\u672A\u8FC7\u5B8C\uFF09`\n\n const dailyBars = (usage?.daily ?? []).map(d => ({\n label: d.date.slice(8, 10),\n value: d.total,\n title: `${d.date} \u00B7 ${fmtInt(d.total)} tokens \u00B7 \u00A5${fmt(d.cost)} \u00B7 ${d.calls} \u6B21\u8C03\u7528`,\n }))\n const hourlyBars = (usage?.hourly ?? []).map(h => ({\n label: String(h.hour),\n value: h.total,\n title: `${h.hour} \u70B9 \u00B7 ${fmtInt(h.total)} tokens \u00B7 ${h.calls} \u6B21\u8C03\u7528`,\n }))\n\n // One canonical model order \u2014 most expensive first \u2014 shared by the ranking\n // card, the picker and the chart, so a model keeps its colour everywhere\n // instead of being coloured by the order it happened to be ticked in.\n // Tallest bar currently on screen \u2014 the chart has no y axis, so this is the\n // only thing giving the bars a magnitude.\n const chartPeak = (barMode === 'daily' ? dailyBars : hourlyBars)\n .reduce((peak, bar) => (bar.value > peak ? bar.value : peak), 0)\n\n const modelList = [...(usage?.models ?? [])].sort((a, b) => b.cost - a.cost)\n const availableModelKeys = new Set(modelList.map(modelKeyOf))\n const effectiveSelection = selectedModels.filter(k => availableModelKeys.has(k))\n const colorOf = (key: string): string => {\n const index = modelList.findIndex(m => modelKeyOf(m) === key)\n return MODEL_COLORS[(index < 0 ? 0 : index) % MODEL_COLORS.length]\n }\n const modelCostTotal = modelList.reduce((sum, m) => sum + m.cost, 0)\n\n // Per-model series for the grouped bar chart (only when models are selected).\n const grouped = effectiveSelection.map(key => {\n const m = modelList.find(x => modelKeyOf(x) === key)\n const name = m === undefined ? key : modelNameOf(m)\n const color = colorOf(key)\n if (barMode === 'daily') {\n return {\n key,\n name,\n color,\n bars: (m?.daily ?? []).map((p, i) => ({\n label: (usage?.daily ?? [])[i]?.date.slice(8, 10) ?? '',\n value: p.total,\n title: `${name} \u00B7 ${(usage?.daily ?? [])[i]?.date ?? ''} \u00B7 ${fmtInt(p.total)} tokens \u00B7 \u00A5${fmt(p.cost)} \u00B7 ${p.calls} \u6B21\u8C03\u7528`,\n })),\n }\n }\n return {\n key,\n name,\n color,\n bars: (m?.hourly ?? []).map((p, i) => ({\n label: String(i),\n value: p.total,\n title: `${name} \u00B7 ${i} \u70B9 \u00B7 ${fmtInt(p.total)} tokens \u00B7 \u00A5${fmt(p.cost)} \u00B7 ${p.calls} \u6B21\u8C03\u7528`,\n })),\n }\n })\n\n return (\n <div className=\"dq-balance\">\n <div className=\"dq-status-row\">\n <div>\n {(loadingBalance || loadingUsage) && <span className=\"dq-muted\">\u52A0\u8F7D\u4E2D\u2026</span>}\n {!loadingBalance && !loadingUsage && refreshing && <span className=\"dq-muted\">\u66F4\u65B0\u4E2D\u2026</span>}\n {notice !== null && <span className=\"dq-warn\">{notice}</span>}\n {error !== null && <span className=\"dq-error\">{error}</span>}\n </div>\n <button\n type=\"button\"\n className=\"dq-refresh-btn\"\n title=\"\u5F3A\u5236\u5237\u65B0\uFF08\u7ED5\u8FC7\u7F13\u5B58\uFF09\"\n disabled={refreshing}\n aria-busy={refreshing}\n onClick={() => { void load(true) }}\n >\n <span className={`dq-refresh-icon${refreshing ? ' dq-refresh-icon--spin' : ''}`}>\u21BB</span>\n {refreshing ? '\u5237\u65B0\u4E2D' : '\u5237\u65B0'}\n </button>\n </div>\n\n {balanceLow && (\n <div className=\"dq-alert\" role=\"status\">\n <span className=\"dq-alert-icon\" aria-hidden=\"true\">!</span>\n <div>\n <strong>\u4F59\u989D {fmt(balanceValue)} {primary?.currency} \u5DF2\u4F4E\u4E8E\u9884\u8B66\u7EBF {fmt(lowBalance)}</strong>\n {daysLeft !== null && <>\uFF0C\u6309\u8FD1\u671F\u7528\u91CF\u4F30\u8BA1\u8FD8\u80FD\u6491 {daysLeftText}</>}\u3002\n <a className=\"dq-alert-link\" href=\"https://platform.deepseek.com/top_up\" target=\"_blank\" rel=\"noreferrer\">\u53BB\u5145\u503C</a>\n </div>\n </div>\n )}\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u8D26\u6237\u4F59\u989D</div>\n {primary !== null ? (\n <div className=\"dq-balance-grid\">\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u5269\u4F59\u4F59\u989D</div>\n <div className=\"dq-stat-value dq-remaining\">\n <span>{fmt(primary.total)} {primary.currency}</span>\n <div className=\"dq-remaining-breakdown\">\n <span>\u5145\u503C\u989D\u5EA6 {fmt(primary.toppedUp)}</span>\n <span className=\"dq-remaining-granted\">\u8D60\u9001\u989D\u5EA6 {fmt(primary.granted)}</span>\n </div>\n </div>\n </div>\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u9884\u8BA1\u53EF\u7528</div>\n <div\n className={`dq-stat-value dq-runway${daysLeft !== null && daysLeft < 3 ? ' dq-stat-value--bad' : ''}`}\n title={runwayTitle}\n >\n {daysLeftText}\n </div>\n </div>\n <Stat label=\"\u72B6\u6001\">\n <div className={`dq-stat-value${balance?.isAvailable === false ? ' dq-stat-value--bad' : ' dq-stat-value--ok'}`}>\n {balance?.isAvailable === false ? '\u4E0D\u53EF\u7528' : '\u53EF\u7528'}\n </div>\n </Stat>\n </div>\n ) : loadingBalance ? (\n <BalanceSkeleton />\n ) : (\n <div className=\"dq-empty\">\u8BFB\u4E0D\u5230\u4F59\u989D\u3002\u8BF7\u786E\u8BA4\u300C\u8BBE\u7F6E \u2192 \u6A21\u578B\u300D\u91CC\u5DF2\u586B DEEPSEEK_API_KEY\uFF0C\u7136\u540E\u70B9\u53F3\u4E0A\u89D2\u5237\u65B0\u3002</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u6D88\u8017\u6982\u89C8\uFF08\u8D39\u7528\u4E3A\u4F30\u7B97\uFF09</div>\n {usage !== null ? (\n <div className=\"dq-period-grid\">\n <Period label=\"\u4ECA\u65E5\" period={usage.summary.today} previous={usage.summary.yesterday} compare=\"\u8F83\u6628\u65E5\" />\n <Period label=\"\u672C\u6708\" period={usage.summary.month} previous={usage.summary.lastMonthToDate} compare=\"\u8F83\u4E0A\u6708\u540C\u671F\" />\n <Period\n label=\"\u7D2F\u8BA1\"\n period={{ total: usage.totals.total, cost: usage.totals.cost, calls: usage.totals.calls }}\n />\n </div>\n ) : loadingUsage ? (\n\n <div className=\"dq-period-grid\">\n {[0, 1, 2].map(i => (\n <div key={i} className=\"dq-period\">\n <Skel w={40} h={11} /><Skel w={104} h={24} /><Skel w={132} h={11} />\n </div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u53EF\u7EDF\u8BA1\u7684\u6D88\u8017\u3002</div>\n )}\n {usage !== null && <PricingNote pricing={usage.pricing} />}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">DSH \u7528\u91CF\uFF08tokens\uFF09</div>\n {usage !== null ? (\n <>\n <div className=\"dq-usage-totals\">\n <Stat label=\"\u8F93\u5165\"><div className=\"dq-stat-value\">{fmtCompact(usage.totals.input)}</div></Stat>\n <Stat label=\"\u8F93\u51FA\"><div className=\"dq-stat-value\">{fmtCompact(usage.totals.output)}</div></Stat>\n <Stat label=\"\u7F13\u5B58\u547D\u4E2D\"><div className=\"dq-stat-value\">{fmtCompact(usage.totals.cache)}</div></Stat>\n <Stat label=\"\u6A21\u578B\u8C03\u7528\"><div className=\"dq-stat-value\">{fmtInt(usage.totals.calls)}</div></Stat>\n </div>\n <div className=\"dq-chart-block-head\">\n <div className=\"dq-chart-title\">\n {barMode === 'daily' ? '\u8FD1 30 \u5929 \u00B7 \u9010\u5929\u7528\u91CF' : '\u6309\u5C0F\u65F6\u5206\u5E03\uFF080\u201323 \u70B9\uFF09'}\n {chartPeak > 0 && <span className=\"dq-chart-peak\">\u5CF0\u503C {fmtCompact(chartPeak)} tokens</span>}\n </div>\n <div className=\"dq-chart-controls\">\n <ModelPicker models={modelList} selected={effectiveSelection} colorOf={colorOf} onChange={setSelectedModels} />\n <div className=\"dq-chart-switch\" role=\"tablist\" aria-label=\"\u5207\u6362\u56FE\u8868\u7EF4\u5EA6\">\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={barMode === 'daily'}\n className={`dq-chart-switch-btn${barMode === 'daily' ? ' dq-chart-switch-btn--on' : ''}`}\n onClick={() => setBarMode('daily')}\n >\n \u9010\u5929\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={barMode === 'hourly'}\n className={`dq-chart-switch-btn${barMode === 'hourly' ? ' dq-chart-switch-btn--on' : ''}`}\n onClick={() => setBarMode('hourly')}\n >\n \u9010\u5C0F\u65F6\n </button>\n </div>\n </div>\n </div>\n {grouped.length > 0 ? (\n <>\n <GroupedBars\n series={grouped}\n height={barMode === 'daily' ? 120 : 100}\n labelEvery={barMode === 'daily' ? 5 : 3}\n />\n <div className=\"dq-legend\">\n {grouped.map(s => (\n <span key={s.key} className=\"dq-legend-item\">\n <span className=\"dq-legend-swatch\" style={{ background: s.color }} />\n {s.name}\n </span>\n ))}\n </div>\n </>\n ) : barMode === 'daily' ? (\n <Bars data={dailyBars} height={120} labelEvery={5} />\n ) : (\n <Bars data={hourlyBars} height={100} labelEvery={3} />\n )}\n <div className=\"dq-chart-title\">\u8FD1 12 \u5468 \u00B7 \u6BCF\u65E5\u7528\u91CF\u70ED\u529B\u56FE</div>\n <Heatmap data={usage.heatmap} />\n </>\n ) : loadingUsage ? (\n <UsageSkeleton />\n ) : (\n <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u7528\u91CF\u8BB0\u5F55\u3002\u5728 DSH \u91CC\u8DD1\u4E00\u8F6E\u5BF9\u8BDD\uFF0C\u8FD9\u91CC\u4F1A\u51FA\u73B0\u9010\u5929 / \u9010\u5C0F\u65F6\u7EDF\u8BA1\u4E0E\u8D39\u7528\u4F30\u7B97\u3002</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u9AD8\u5CF0 / \u95F2\u65F6\u5206\u5E03</div>\n {usage !== null ? (\n <PeakCard split={usage.peakSplit} pricing={usage.pricing} currentCost={usage.totals.cost} />\n ) : loadingUsage ? (\n <>\n <div className=\"dq-peak-track\" />\n <div className=\"dq-peak-figures\"><Skel w={120} h={11} /><Skel w={96} h={20} /></div>\n </>\n ) : (\n <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u53EF\u6309\u65F6\u6BB5\u5F52\u7C7B\u7684\u7528\u91CF\u3002</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u7F13\u5B58\u547D\u4E2D\u4E0E\u8282\u7701</div>\n {usage !== null ? (\n <CacheCard totals={usage.totals} />\n ) : loadingUsage ? (\n <div className=\"dq-cache-figures\">\n {[60, 96, 72].map((w, i) => (\n <div key={i} className=\"dq-stat\"><Skel w={w} h={11} /><Skel w={72} h={20} /></div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">\u8FD8\u6CA1\u6709 prompt token \u53EF\u7EDF\u8BA1\u7F13\u5B58\u547D\u4E2D\u3002</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u6A21\u578B\u6210\u672C\u6392\u884C</div>\n {usage !== null ? (\n <ModelRanking models={modelList} totalCost={modelCostTotal} colorOf={colorOf} />\n ) : loadingUsage ? (\n <div className=\"dq-rank\">\n {[0, 1].map(i => (\n <div key={i} className=\"dq-rank-row\">\n <Skel w={148} h={13} />\n <div className=\"dq-rank-track\" />\n <Skel w={230} h={11} />\n </div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u53EF\u5F52\u7C7B\u7684\u6A21\u578B\u7528\u91CF\u3002</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u4F1A\u8BDD\u6210\u672C\u6392\u884C</div>\n {usage !== null ? (\n <SessionRanking sessions={usage.sessions} count={usage.sessionCount} totalCost={usage.totals.cost} />\n ) : loadingUsage ? (\n <div className=\"dq-sessions\">\n {[0, 1, 2].map(i => (\n <div key={i} className=\"dq-session\">\n <Skel w={200} h={13} />\n <div className=\"dq-session-track\" />\n <Skel w={250} h={11} />\n </div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u4EA7\u751F\u8D39\u7528\u7684\u4F1A\u8BDD\u3002</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u5B98\u65B9\u5E73\u53F0</div>\n <div className=\"dq-links\">\n <Link href=\"https://platform.deepseek.com/usage\">\u67E5\u770B\u989D\u5EA6 / \u7528\u91CF</Link>\n <Link href=\"https://platform.deepseek.com/api_keys\">\u751F\u6210 API Key</Link>\n <Link href=\"https://status.deepseek.com\">\u670D\u52A1\u72B6\u6001</Link>\n </div>\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u8BBE\u7F6E</div>\n <label className=\"dq-toggle\">\n <input type=\"checkbox\" checked={widgetOn} onChange={toggle} />\n <span>\u663E\u793A\u53F3\u4E0B\u89D2\u60AC\u6D6E\u989D\u5EA6\u7A97\u53E3</span>\n </label>\n <div className=\"dq-setting\">\n <label className=\"dq-setting-label\" htmlFor=\"dq-low-balance\">\u4F59\u989D\u9884\u8B66\u7EBF</label>\n <div className=\"dq-setting-control\">\n <input\n id=\"dq-low-balance\"\n className=\"dq-number\"\n type=\"number\"\n min={0}\n step={1}\n value={lowBalance}\n onChange={e => changeLowBalance(Math.max(0, Number(e.target.value) || 0))}\n />\n <span className=\"dq-setting-hint\">\n {lowBalance > 0\n ? `\u4F59\u989D\u4F4E\u4E8E ${fmt(lowBalance)} ${primary?.currency ?? 'CNY'} \u65F6\uFF0C\u8FD9\u91CC\u548C\u60AC\u6D6E\u7A97\u90FD\u4F1A\u8F6C\u4E3A\u8B66\u793A\u8272\u3002\u586B 0 \u5173\u95ED\u3002`\n : '\u5DF2\u5173\u95ED\u4F59\u989D\u9884\u8B66\u3002\u586B\u4E00\u4E2A\u5927\u4E8E 0 \u7684\u6570\u5F00\u542F\u3002'}\n </span>\n </div>\n </div>\n </div>\n </div>\n )\n}\n", "/**\n * Package-local TTL caches shared by the widget, the dashboard, and every\n * tab switch. Cached values outlive the TTL: `get()` still returns them\n * (marked by `at`) so a reopening tab can render instantly and refresh in\n * the background, while `getFresh()` is the cache-aware fetch path.\n *\n * When a `storageKey` is given, every `put()` also mirrors the entry to\n * localStorage so a page refresh keeps the instant first paint (the data\n * shown is the last known good value; a background refresh updates it).\n */\n\nconst LS_VERSION = 1\n\nexport interface CacheHit<T> {\n data: T\n at: number\n}\n\nexport interface ResourceCache<T> {\n /** Last cached value even when stale; null when never cached. */\n get(): CacheHit<T> | null\n /** Value only when it is still within the TTL. */\n getFresh(): T | null\n put(data: T): void\n}\n\nfunction loadPersisted<T>(storageKey: string): CacheHit<T> | null {\n if (typeof localStorage === 'undefined') return null\n try {\n const raw = localStorage.getItem(`${storageKey}:v${LS_VERSION}`)\n if (raw === null) return null\n const parsed = JSON.parse(raw) as { data?: T; at?: number }\n if (parsed.data === undefined || typeof parsed.at !== 'number') return null\n return { data: parsed.data, at: parsed.at }\n } catch {\n return null\n }\n}\n\nfunction persist<T>(storageKey: string, hit: CacheHit<T>): void {\n if (typeof localStorage === 'undefined') return\n try {\n localStorage.setItem(`${storageKey}:v${LS_VERSION}`, JSON.stringify(hit))\n } catch {\n // Quota / private-mode failures must never break the in-memory path.\n }\n}\n\nexport function createCache<T>(ttlMs: number, storageKey?: string): ResourceCache<T> {\n let hit: CacheHit<T> | null = storageKey === undefined ? null : loadPersisted<T>(storageKey)\n return {\n get: () => hit,\n getFresh: () => (hit !== null && Date.now() - hit.at < ttlMs ? hit.data : null),\n put: (data) => {\n hit = { data, at: Date.now() }\n if (storageKey !== undefined) persist(storageKey, hit)\n },\n }\n}\n", "/**\n * Same-origin fetchers for the host half's JSON API, backed by package-local\n * TTL caches (see ./cache.ts). A fresh cache hit resolves without any network\n * work, so tab switches render instantly; `force` bypasses both the memory\n * cache and the HTTP cache (fetch cache: 'no-store') and asks the host to\n * bypass its own memo via `?refresh=1`.\n */\nimport { createCache } from './cache.ts'\nimport type { BalanceResponse, UsageResponse } from '../contract.ts'\n\n/** Mirror the host memos: balance 60s, usage 5min. */\nconst BALANCE_TTL_MS = 60_000\nconst USAGE_TTL_MS = 5 * 60_000\n\nasync function getJson<T>(path: string, cache: RequestCache): Promise<T> {\n const res = await fetch(path, { headers: { accept: 'application/json' }, cache })\n if (!res.ok) {\n return { ok: false, error: `HTTP ${res.status}` } as unknown as T\n }\n return res.json() as Promise<T>\n}\n\nconst balanceCache = createCache<BalanceResponse>(BALANCE_TTL_MS, 'dsh-usage-dashboard:balance')\nconst usageCache = createCache<UsageResponse>(USAGE_TTL_MS, 'dsh-usage-dashboard:usage')\n\n/** Last cached value (possibly stale), for an instant first render. */\nexport const getCachedBalance = (): BalanceResponse | null => balanceCache.get()?.data ?? null\nexport const getCachedUsage = (): UsageResponse | null => usageCache.get()?.data ?? null\n/** When the cached usage was fetched, so a consumer can say how old it is. */\nexport const getCachedUsageAt = (): number | null => usageCache.get()?.at ?? null\n\n/**\n * Notified whenever usage is (re)fetched. The floating widget reads usage\n * straight from this cache rather than fetching on its own: aggregating every\n * session log takes seconds, and a background widget must not pay that\n * repeatedly. It subscribes here so it still updates when the dashboard \u2014 or\n * its own refresh button \u2014 brings fresh data in.\n */\nconst usageListeners = new Set<() => void>()\n\nexport const subscribeUsage = (fn: () => void): (() => void) => {\n usageListeners.add(fn)\n return () => {\n usageListeners.delete(fn)\n }\n}\n\nexport async function fetchBalance(force = false): Promise<BalanceResponse> {\n if (!force) {\n const hit = balanceCache.getFresh()\n if (hit !== null) return hit\n }\n const suffix = force ? '?refresh=1' : ''\n const res = await getJson<BalanceResponse>(`/api/dsh-usage-dashboard/balance${suffix}`, force ? 'no-store' : 'default')\n if (res.ok) balanceCache.put(res)\n return res\n}\n\nexport async function fetchUsage(force = false): Promise<UsageResponse> {\n if (!force) {\n const hit = usageCache.getFresh()\n if (hit !== null) return hit\n }\n const suffix = force ? '?refresh=1' : ''\n const res = await getJson<UsageResponse>(`/api/dsh-usage-dashboard/usage${suffix}`, force ? 'no-store' : 'default')\n if (res.ok) {\n usageCache.put(res)\n for (const listener of [...usageListeners]) listener()\n }\n return res\n}\n", "/** Dependency-free bar chart and heatmap primitives. */\nimport { useRef, useState, type MutableRefObject, type PointerEvent as ReactPointerEvent, type ReactElement } from 'react'\n\nexport interface BarDatum {\n label: string\n value: number\n /** Tooltip text, composed as `heading \u00B7 row \u00B7 row`; each ` \u00B7 ` segment is\n * rendered on its own line, the first as the heading. */\n title?: string\n}\n\ninterface TipState {\n x: number\n y: number\n lines: string[]\n}\n\n/**\n * Cursor-following tooltip shared by every chart. The native `title` attribute\n * this replaces waited about a second, could not be styled to match the shell,\n * and never appeared on touch.\n */\nfunction useChartTip(): {\n wrapRef: MutableRefObject<HTMLDivElement | null>\n tip: TipState | null\n show: (e: ReactPointerEvent<HTMLElement>, text: string | undefined) => void\n hide: () => void\n} {\n const wrapRef = useRef<HTMLDivElement | null>(null)\n const [tip, setTip] = useState<TipState | null>(null)\n const show = (e: ReactPointerEvent<HTMLElement>, text: string | undefined): void => {\n const wrap = wrapRef.current\n if (text === undefined || text === '' || wrap === null) return\n const rect = wrap.getBoundingClientRect()\n // Keep the (centred) bubble inside the chart's own box.\n const x = Math.min(Math.max(e.clientX - rect.left, 70), Math.max(rect.width - 70, 70))\n setTip({ x, y: e.clientY - rect.top, lines: text.split(' \u00B7 ') })\n }\n return { wrapRef, tip, show, hide: () => setTip(null) }\n}\n\nfunction ChartTip(props: { tip: TipState | null }): ReactElement | null {\n const { tip } = props\n if (tip === null) return null\n const [head, ...rows] = tip.lines\n return (\n <div className=\"dq-tip\" style={{ left: `${tip.x}px`, top: `${tip.y}px` }} role=\"tooltip\">\n <div className=\"dq-tip-head\">{head}</div>\n {rows.map((row, i) => <div key={i} className=\"dq-tip-row\">{row}</div>)}\n </div>\n )\n}\n\n/** Color palette for per-model grouped bars, cycled by model order. */\nexport const MODEL_COLORS = ['#4176e6', '#2da44e', '#e16f24', '#8250df', '#bf8700', '#cf222e', '#1f883d', '#0969da']\n\nexport function Bars(props: { data: BarDatum[]; height?: number; labelEvery?: number }): ReactElement {\n const { data, height = 120, labelEvery = 1 } = props\n const { wrapRef, tip, show, hide } = useChartTip()\n let max = 0\n for (const datum of data) if (datum.value > max) max = datum.value\n const scale = max > 0 ? max : 1\n return (\n <div className=\"dq-chart-wrap\" ref={wrapRef} onPointerLeave={hide}>\n <div className=\"dq-bars\" style={{ height: `${height + 18}px` }}>\n {data.map((datum, i) => {\n const h = Math.max(1, Math.round((datum.value / scale) * height))\n const text = datum.title ?? `${datum.label}: ${datum.value.toLocaleString()}`\n return (\n <div\n key={i}\n className=\"dq-bar-col\"\n aria-label={text}\n onPointerMove={e => show(e, text)}\n >\n <div className=\"dq-bar\" style={{ height: `${h}px` }} />\n <div className=\"dq-bar-label\" style={{ visibility: i % labelEvery === 0 ? 'visible' : 'hidden' }}>{datum.label}</div>\n </div>\n )\n })}\n </div>\n <ChartTip tip={tip} />\n </div>\n )\n}\n\nexport interface HeatDatum {\n date: string\n total: number\n cost: number\n calls: number\n}\n\n/** Multi-series bar chart: one bar per series, side by side, per slot. */\nexport function GroupedBars(props: {\n series: Array<{ key: string; color: string; bars: BarDatum[] }>\n height?: number\n labelEvery?: number\n}): ReactElement {\n const { series, height = 120, labelEvery = 1 } = props\n const { wrapRef, tip, show, hide } = useChartTip()\n const count = series.length > 0 ? series[0].bars.length : 0\n let max = 0\n for (const s of series) for (const datum of s.bars) if (datum.value > max) max = datum.value\n const scale = max > 0 ? max : 1\n return (\n <div className=\"dq-chart-wrap\" ref={wrapRef} onPointerLeave={hide}>\n <div className=\"dq-bars\" style={{ height: `${height + 18}px` }}>\n {Array.from({ length: count }, (_, i) => (\n <div key={i} className=\"dq-bar-col\">\n <div className=\"dq-bar-group\">\n {series.map(s => {\n const datum = s.bars[i]\n const h = Math.max(1, Math.round((datum.value / scale) * height))\n const text = datum.title ?? `${s.key}: ${datum.value.toLocaleString()}`\n return (\n <div\n key={s.key}\n className=\"dq-bar\"\n style={{ height: `${h}px`, background: s.color }}\n aria-label={text}\n onPointerMove={e => show(e, text)}\n />\n )\n })}\n </div>\n <div className=\"dq-bar-label\" style={{ visibility: i % labelEvery === 0 ? 'visible' : 'hidden' }}>\n {series[0].bars[i].label}\n </div>\n </div>\n ))}\n </div>\n <ChartTip tip={tip} />\n </div>\n )\n}\n\nfunction heatColor(level: number): string {\n if (level <= 0) return 'rgba(120,130,150,0.12)'\n if (level === 1) return 'rgba(65,118,230,0.25)'\n if (level === 2) return 'rgba(65,118,230,0.5)'\n if (level === 3) return 'rgba(65,118,230,0.75)'\n return 'rgba(65,118,230,1)'\n}\n\n/** Row 0 is Sunday, matching Date#getDay(); only alternate rows are labelled\n * so the column stays readable at 12px cells. */\nconst DOW_LABELS = ['', '\u4E00', '', '\u4E09', '', '\u4E94', '']\n\n/**\n * Calendar heatmap with the axes it was missing: weekday labels down the left,\n * month labels along the top (drawn where a column starts a new month) and a\n * \u5C11\u2192\u591A scale legend, so a cell can actually be located in time.\n */\nexport function Heatmap(props: { data: HeatDatum[] }): ReactElement {\n const { data } = props\n const { wrapRef, tip, show, hide } = useChartTip()\n let max = 0\n for (const datum of data) if (datum.total > max) max = datum.total\n let firstDow = 0\n if (data.length > 0) {\n const dt = new Date(`${data[0].date}T00:00:00`)\n firstDow = Number.isNaN(dt.getTime()) ? 0 : dt.getDay()\n }\n const cells: Array<HeatDatum | null> = []\n for (let i = 0; i < firstDow; i++) cells.push(null)\n for (const datum of data) cells.push(datum)\n while (cells.length % 7 !== 0) cells.push(null)\n\n const weeks: Array<Array<HeatDatum | null>> = []\n for (let i = 0; i < cells.length; i += 7) weeks.push(cells.slice(i, i + 7))\n\n // Label a column with its month when it is the first column of that month.\n let lastMonth = ''\n const monthLabels = weeks.map(week => {\n const first = week.find(cell => cell !== null)\n if (first === undefined || first === null) return ''\n const month = first.date.slice(0, 7)\n if (month === lastMonth) return ''\n lastMonth = month\n return `${Number(first.date.slice(5, 7))}\u6708`\n })\n\n const levelOf = (total: number): number => {\n if (total <= 0) return 0\n const r = max > 0 ? total / max : 0\n return r < 0.25 ? 1 : r < 0.5 ? 2 : r < 0.75 ? 3 : 4\n }\n\n return (\n <div className=\"dq-heat dq-chart-wrap\" ref={wrapRef} onPointerLeave={hide}>\n <div className=\"dq-heat-grid\">\n <div className=\"dq-heat-dows\" aria-hidden=\"true\">\n {DOW_LABELS.map((label, i) => <div key={i} className=\"dq-heat-dow\">{label}</div>)}\n </div>\n <div className=\"dq-heat-cols\">\n <div className=\"dq-heat-months\" aria-hidden=\"true\">\n {monthLabels.map((label, i) => <div key={i} className=\"dq-heat-month\">{label}</div>)}\n </div>\n <div className=\"dq-heatmap\">\n {weeks.map((week, w) => (\n <div key={w} className=\"dq-heat-week\">\n {week.map((datum, d) => {\n if (datum === null) return <div key={d} className=\"dq-heat-cell dq-heat-cell--pad\" />\n const text = `${datum.date} \u00B7 ${datum.total.toLocaleString()} tokens \u00B7 \u00A5${datum.cost.toFixed(2)} \u00B7 ${datum.calls} \u6B21\u8C03\u7528`\n return (\n <div\n key={d}\n className=\"dq-heat-cell\"\n style={{ background: heatColor(levelOf(datum.total)) }}\n aria-label={text}\n onPointerMove={e => show(e, text)}\n />\n )\n })}\n </div>\n ))}\n </div>\n </div>\n </div>\n <ChartTip tip={tip} />\n <div className=\"dq-heat-scale\">\n <span>\u5C11</span>\n {[0, 1, 2, 3, 4].map(level => (\n <span key={level} className=\"dq-heat-key\" style={{ background: heatColor(level) }} />\n ))}\n <span>\u591A</span>\n </div>\n </div>\n )\n}\n\nexport const fmt = (v: string | number): string => {\n const n = Number(v)\n if (!Number.isFinite(n)) return String(v)\n return n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })\n}\n\nexport const fmtInt = (v: number | undefined): string => Math.round(Number(v) || 0).toLocaleString()\n\nexport const fmtCompact = (v: number | undefined): string => {\n const n = Number(v) || 0\n if (n >= 100_000_000) return `${(n / 100_000_000).toFixed(1)}\u4EBF`\n if (n >= 10_000) return `${(n / 10_000).toFixed(1)}\u4E07`\n return Math.round(n).toLocaleString()\n}\n", "/**\n * localStorage-backed user preferences for the plugin.\n *\n * Everything the user deliberately sets (widget visibility, the corner it was\n * dragged to, whether it is collapsed) belongs here so a page refresh does not\n * throw the choice away. Keys share one prefix and carry a version suffix so\n * the shape can evolve without reading back stale values.\n *\n * Every read is validated by the caller's guard: a corrupted or hand-edited\n * entry falls back instead of poisoning the UI.\n */\n\nconst PREFIX = 'dsh-usage-dashboard:pref:'\nconst VERSION = 1\n\nconst keyOf = (key: string): string => `${PREFIX}${key}:v${VERSION}`\n\nexport function loadPref<T>(key: string, isValid: (value: unknown) => boolean, fallback: T): T {\n if (typeof localStorage === 'undefined') return fallback\n try {\n const raw = localStorage.getItem(keyOf(key))\n if (raw === null) return fallback\n const parsed = JSON.parse(raw) as unknown\n return isValid(parsed) ? (parsed as T) : fallback\n } catch {\n return fallback\n }\n}\n\nexport function savePref(key: string, value: unknown): void {\n if (typeof localStorage === 'undefined') return\n try {\n localStorage.setItem(keyOf(key), JSON.stringify(value))\n } catch {\n // Quota / private-mode failures must never break the UI.\n }\n}\n\nexport const isBoolean = (value: unknown): boolean => typeof value === 'boolean'\n", "/**\n * Package-local stores for settings both surfaces read: the dashboard writes\n * them, the floating widget reacts. Every value is persisted (see ./prefs.ts),\n * so a choice survives a page refresh.\n */\nimport { isBoolean, loadPref, savePref } from './prefs.ts'\n\nexport interface Store<T> {\n get(): T\n set(value: T): void\n subscribe(fn: () => void): () => void\n}\n\nfunction createStore<T>(key: string, isValid: (value: unknown) => boolean, fallback: T): Store<T> {\n let current = loadPref<T>(key, isValid, fallback)\n const listeners = new Set<() => void>()\n return {\n get: () => current,\n set: (value: T) => {\n current = value\n savePref(key, value)\n for (const listener of [...listeners]) listener()\n },\n subscribe: (fn: () => void) => {\n listeners.add(fn)\n return () => {\n listeners.delete(fn)\n }\n },\n }\n}\n\nconst isThreshold = (value: unknown): boolean =>\n typeof value === 'number' && Number.isFinite(value) && value >= 0\n\n/** Whether the floating balance widget is shown. */\nexport const widgetVisibleStore = createStore<boolean>('widget.visible', isBoolean, true)\n\n/** Balance (in the account's own currency) below which both surfaces warn.\n * 0 turns the warning off. */\nexport const lowBalanceStore = createStore<number>('alert.lowBalance', isThreshold, 10)\n", "/** All plugin styles in one sheet, injected once at client load. */\n\nexport const css = `\n.dsh-quota-root{position:absolute;right:16px;bottom:16px;z-index:2147483000;pointer-events:auto;font-family:system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;font-size:13px;line-height:1.45;color:var(--dsw-alias-label-primary,#1f2328);transition:left .28s cubic-bezier(.22,1,.36,1),top .28s cubic-bezier(.22,1,.36,1)}\n.dsh-quota-root.dsh-quota-dragging{transition:none}\n.dsh-quota-card,.dsh-quota-card *{box-sizing:border-box}\n.dsh-quota-card{background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);padding:12px 14px;min-width:208px;max-width:270px;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none}\n.dsh-quota-root.dsh-quota-dragging .dsh-quota-card{cursor:grabbing;box-shadow:0 12px 32px rgba(0,0,0,.28)}\n.dsh-quota-header{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px;min-width:0}\n.dsh-quota-title{font-weight:600;font-size:13px;color:var(--dsw-alias-label-primary,#1f2328);display:flex;align-items:center;gap:6px;min-width:0;overflow:hidden}\n.dsh-quota-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dsh-quota-grip{color:var(--dsw-alias-label-secondary,#59636e);opacity:.7;font-size:11px;letter-spacing:0;cursor:grab;flex:none}\n.dsh-quota-dot{width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-state-success-primary,#2da44e);flex:none}\n.dsh-quota-dot--error{background:var(--dsw-alias-state-error-primary,#cf222e)}\n.dsh-quota-dot--warn{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dsh-quota-total--low{color:var(--dsw-alias-state-warning-primary,#9a6700)!important}\n.dsh-quota-dot--idle{background:var(--dsw-alias-label-secondary,#59636e);opacity:.6}\n.dsh-quota-collapsed-total{font-weight:700;font-size:13px;color:var(--dsw-alias-brand-primary,#0969da);flex:none;font-variant-numeric:tabular-nums}\n.dsh-quota-actions{display:flex;gap:2px;flex:none}\n.dsh-quota-btn{border:none;background:transparent;cursor:pointer;color:var(--dsw-alias-label-secondary,#59636e);padding:3px 7px;border-radius:6px;font-size:13px;line-height:1}\n.dsh-quota-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06));color:var(--dsw-alias-label-primary,#1f2328)}\n.dsh-quota-btn:active:not(:disabled){transform:scale(.92)}\n.dsh-quota-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dsh-quota-btn:disabled{opacity:.5;cursor:default}\n.dsh-quota-body{color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-remaining-label{font-size:11px;color:var(--dsw-alias-label-tertiary,#59636e);margin-bottom:2px}\n.dsh-quota-total{font-size:24px;font-weight:700;color:var(--dsw-alias-label-primary,#1f2328);letter-spacing:-.02em;font-variant-numeric:tabular-nums}\n.dsh-quota-currency{font-size:14px;font-weight:600;margin-left:3px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-row{display:flex;justify-content:space-between;gap:12px;margin-top:6px;font-size:12px}\n.dsh-quota-label{color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-value{color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dsh-quota-error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-balance{display:flex;flex-direction:column;gap:16px;padding:20px 24px 48px;max-width:860px;margin:0 auto;font-family:system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;font-size:13px;line-height:1.5;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-card{background:var(--dsw-alias-bg-layer-1,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08));border-radius:12px;padding:16px}\n.dq-card-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e);margin:0 0 12px;letter-spacing:.02em}\n.dq-balance-grid{display:flex;flex-wrap:wrap;gap:12px 24px}\n.dq-stat{min-width:110px}\n.dq-stat-label{font-size:11px;color:var(--dsw-alias-label-tertiary,#59636e);margin-bottom:2px}\n.dq-stat-value{font-size:18px;font-weight:650;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-stat-value--ok{color:var(--dsw-alias-state-success-primary,#2da44e)}\n.dq-stat-value--bad{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-runway{cursor:help;text-decoration:underline dotted var(--dsw-alias-border-l2,rgba(0,0,0,.25));text-underline-offset:4px}\n.dq-remaining{position:relative;cursor:help}\n.dq-remaining-breakdown{display:none;position:absolute;top:calc(100% + 6px);left:0;z-index:20;flex-direction:column;gap:4px;padding:8px 10px;background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.15);white-space:nowrap;font-size:12px;font-weight:500;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-remaining:hover .dq-remaining-breakdown{display:flex}\n.dq-remaining-granted{color:var(--dsw-alias-label-tertiary,#59636e);font-weight:400;font-size:11px}\n.dq-period-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}\n@media (max-width:620px){.dq-period-grid{grid-template-columns:1fr}}\n.dq-period{background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.06));border-radius:10px;padding:12px 14px;min-width:0}\n.dq-period-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:4px}\n.dq-period-label{font-size:11px;color:var(--dsw-alias-label-tertiary,#59636e)}\n.dq-period-cost{font-size:22px;font-weight:680;letter-spacing:-.01em;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;line-height:1.25}\n.dq-period-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);margin-top:2px;font-variant-numeric:tabular-nums;line-height:1.45}\n.dq-delta{display:inline-flex;align-items:center;gap:3px;font-size:11px;font-weight:600;padding:1px 6px;border-radius:999px;white-space:nowrap;cursor:help;font-variant-numeric:tabular-nums}\n.dq-delta--up{color:var(--dsw-alias-state-warning-primary,#9a6700);background:rgba(191,135,0,.14)}\n.dq-delta--down{color:var(--dsw-alias-state-success-primary,#1a7f37);background:rgba(45,164,78,.14)}\n.dq-delta--flat,.dq-delta--new{color:var(--dsw-alias-label-tertiary,#59636e);background:rgba(120,130,150,.14);font-weight:500}\n.dq-delta-label{font-weight:400;opacity:.8}\n.dq-pricing{margin-top:12px;border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08));padding-top:10px}\n.dq-pricing-summary{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);cursor:pointer;list-style:none;width:fit-content;border-radius:6px;padding:2px 4px;margin-left:-4px}\n.dq-pricing-summary::-webkit-details-marker{display:none}\n.dq-pricing-summary::before{content:\"\u25B8\";display:inline-block;font-size:10px;opacity:.7;transition:transform .15s ease}\n.dq-pricing[open] .dq-pricing-summary::before{transform:rotate(90deg)}\n.dq-pricing-summary:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-pricing-summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-pricing-now{font-size:11px;font-weight:600;padding:1px 7px;border-radius:999px;color:var(--dsw-alias-label-tertiary,#59636e);background:rgba(120,130,150,.14)}\n.dq-pricing-now--peak{color:var(--dsw-alias-state-warning-primary,#9a6700);background:rgba(191,135,0,.14)}\n.dq-pricing-body{margin-top:10px;overflow-x:auto}\n.dq-pricing-table{border-collapse:collapse;font-size:11.5px;font-variant-numeric:tabular-nums;min-width:100%}\n.dq-pricing-table th{text-align:left;font-weight:500;color:var(--dsw-alias-label-tertiary,#59636e);padding:4px 12px 4px 0;white-space:nowrap;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08))}\n.dq-pricing-table td{padding:4px 12px 4px 0;color:var(--dsw-alias-label-primary,#1f2328);white-space:nowrap;vertical-align:top}\n.dq-pricing-table tbody tr+tr td{border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.05))}\n.dq-pricing-foot{margin:8px 0 0;font-size:11.5px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-peak-track{height:8px;border-radius:999px;background:var(--dsw-alias-state-success-primary,#2da44e);opacity:.85;overflow:hidden}\n.dq-peak-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-warning-primary,#bf8700);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-peak-legend{display:flex;flex-wrap:wrap;gap:6px 20px;margin-top:8px;font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-peak-legend span{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch--peak{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-legend-swatch--offpeak{background:var(--dsw-alias-state-success-primary,#2da44e);opacity:.85}\n.dq-peak-figures{display:flex;flex-wrap:wrap;gap:12px 32px;margin-top:14px}\n.dq-peak-delta{font-size:11px;font-weight:500;margin-left:8px;color:var(--dsw-alias-state-warning-primary,#9a6700)}\n.dq-peak-delta--save{color:var(--dsw-alias-state-success-primary,#1a7f37)}\n.dq-peak-foot{margin:10px 0 0;font-size:11.5px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-cache-figures{display:flex;flex-wrap:wrap;gap:12px 32px;margin-bottom:12px}\n.dq-muted-value{color:var(--dsw-alias-label-secondary,#59636e)!important;font-weight:550}\n.dq-stat-value--warn{color:var(--dsw-alias-state-warning-primary,#9a6700)}\n.dq-cache-track{height:8px;border-radius:999px;background:var(--dsw-alias-state-warning-primary,#bf8700);overflow:hidden}\n.dq-cache-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-success-primary,#2da44e);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-cache-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin-top:8px;font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-cache-legend span{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch--hit{background:var(--dsw-alias-state-success-primary,#2da44e)}\n.dq-legend-swatch--miss{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-cache-foot{margin:10px 0 0;font-size:11.5px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-sessions{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:14px}\n.dq-session{display:flex;flex-direction:column;gap:5px;min-width:0}\n.dq-session-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}\n.dq-session-title{font-size:13px;font-weight:550;color:var(--dsw-alias-label-primary,#1f2328);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-session-cost{font-size:14px;font-weight:650;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;flex:none}\n.dq-session-track{height:6px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.12));overflow:hidden}\n.dq-session-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-business-primary,#4176e6);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-session-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;line-height:1.5}\n.dq-session-foot{margin:12px 0 0;font-size:11.5px;color:var(--dsw-alias-label-tertiary,#59636e)}\n.dq-rank{display:flex;flex-direction:column;gap:14px}\n.dq-rank-row{display:flex;flex-direction:column;gap:5px;min-width:0}\n.dq-rank-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}\n.dq-rank-name{display:inline-flex;align-items:center;gap:7px;font-size:13px;font-weight:550;color:var(--dsw-alias-label-primary,#1f2328);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-rank-cost{display:inline-flex;align-items:baseline;gap:8px;font-size:14px;font-weight:650;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;flex:none}\n.dq-rank-share{font-size:11px;font-weight:500;color:var(--dsw-alias-label-tertiary,#59636e);min-width:30px;text-align:right}\n.dq-rank-track{height:6px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.12));overflow:hidden}\n.dq-rank-fill{height:100%;border-radius:999px;transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-rank-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;line-height:1.5}\n.dq-alert{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border-radius:10px;font-size:12.5px;line-height:1.6;color:var(--dsw-alias-state-warning-primary,#7a5200);background:rgba(191,135,0,.12);border:1px solid rgba(191,135,0,.35)}\n.dq-alert-icon{flex:none;width:18px;height:18px;border-radius:50%;background:var(--dsw-alias-state-warning-primary,#bf8700);color:#fff;font-weight:700;font-size:12px;line-height:18px;text-align:center}\n.dq-alert strong{font-weight:650}\n.dq-alert-link{margin-left:8px;color:inherit;text-decoration:underline;text-underline-offset:2px;white-space:nowrap}\n.dq-setting{display:flex;align-items:flex-start;gap:12px;margin-top:14px;padding-top:14px;border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08))}\n.dq-setting-label{font-size:13px;color:var(--dsw-alias-label-primary,#1f2328);padding-top:6px;flex:none}\n.dq-setting-control{display:flex;align-items:center;gap:10px;flex-wrap:wrap;min-width:0}\n.dq-setting-hint{font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);line-height:1.5}\n.dq-number{width:82px;padding:5px 8px;font-size:13px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.16));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-number:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px;border-color:transparent}\n.dq-links{display:flex;flex-wrap:wrap;gap:8px}\n.dq-link{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));border-radius:8px;background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-state-business-primary,#0969da);text-decoration:none;font-size:13px;font-weight:500;cursor:pointer}\n.dq-link:hover{border-color:var(--dsw-alias-state-business-primary,#0969da);background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}\n.dq-toggle{display:flex;align-items:center;gap:10px;cursor:pointer;font-size:13px}\n.dq-toggle input{width:16px;height:16px;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer}\n.dq-toggle input:focus-visible,.dq-model-item input:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-link:focus-visible,.dq-model-btn:focus-visible,.dq-chart-switch-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-usage-totals{display:flex;flex-wrap:wrap;gap:12px 24px;margin-bottom:16px}\n.dq-chart-peak{margin-left:10px;font-size:11px;font-weight:400;color:var(--dsw-alias-label-tertiary,#59636e);font-variant-numeric:tabular-nums}\n.dq-chart-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e);margin:18px 0 8px}\n.dq-chart-title:first-of-type{margin-top:0}\n.dq-chart-block-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:18px 0 8px}\n.dq-chart-block-head .dq-chart-title{margin:0}\n.dq-chart-controls{display:flex;align-items:center;gap:8px;flex:none}\n.dq-model-picker{position:relative}\n.dq-model-btn{border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:4px 10px;font-size:12px;cursor:pointer;display:inline-flex;align-items:center;gap:6px}\n.dq-model-btn:hover{border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-model-btn::after{content:\"\u25BE\";font-size:10px;opacity:.7}\n.dq-model-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;min-width:190px;max-height:280px;overflow-y:auto;background:var(--dsw-alias-bg-overlay,#fff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.16);padding:6px;display:flex;flex-direction:column;gap:2px}\n.dq-model-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;font-size:12px;cursor:pointer;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-model-item:hover{background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06))}\n.dq-model-item input{width:14px;height:14px;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer;flex:none}\n.dq-model-item span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-model-item--all{border-bottom:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08));padding-bottom:8px;margin-bottom:2px;border-radius:6px}\n.dq-model-tag{color:var(--dsw-alias-label-tertiary,#59636e);font-size:11px;flex:none}\n.dq-bar-group{display:flex;align-items:flex-end;gap:2px;height:100%;width:100%}\n.dq-bar-group .dq-bar{flex:1 1 0;min-width:0}\n.dq-legend{display:flex;flex-wrap:wrap;gap:6px 14px;margin-top:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-legend-item{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch{width:10px;height:10px;border-radius:3px;flex:none}\n.dq-chart-switch{display:inline-flex;align-items:center;gap:2px;padding:2px;background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06));border-radius:999px;flex:none}\n.dq-chart-switch-btn{border:none;background:transparent;color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;line-height:1;padding:5px 12px;border-radius:999px;cursor:pointer;transition:background .15s ease,color .15s ease}\n.dq-chart-switch-btn:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-chart-switch-btn--on{background:var(--dsw-alias-bg-overlay,#fff);color:var(--dsw-alias-label-primary,#1f2328);box-shadow:0 1px 3px rgba(0,0,0,.14)}\n.dq-chart-wrap{position:relative}\n.dq-tip{position:absolute;transform:translate(-50%,14px);z-index:40;pointer-events:none;background:var(--dsw-alias-bg-inverse,#1f2328);color:var(--dsw-alias-label-inverse,#fff);border-radius:8px;padding:7px 10px;font-size:11.5px;line-height:1.55;white-space:nowrap;box-shadow:0 6px 20px rgba(0,0,0,.28);font-variant-numeric:tabular-nums}\n.dq-tip-head{font-weight:650;margin-bottom:2px}\n.dq-tip-row{opacity:.85}\n.dq-bars{display:flex;align-items:flex-end;gap:2px;width:100%}\n.dq-bar-col{flex:1 1 0;min-width:0;display:flex;flex-direction:column;justify-content:flex-end;align-items:stretch}\n.dq-bar{background:var(--dsw-alias-state-business-primary,#4176e6);border-radius:2px 2px 0 0;min-height:1px;transition:filter .12s ease}\n.dq-bar-col{cursor:default}\n.dq-bar-col:hover .dq-bar{filter:brightness(1.18) saturate(1.1)}\n.dq-heat-cell:not(.dq-heat-cell--pad):hover{outline:1.5px solid var(--dsw-alias-label-primary,#1f2328);outline-offset:1px}\n.dq-bar-label{font-size:9px;color:var(--dsw-alias-label-tertiary,#59636e);text-align:center;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-heat{display:flex;flex-direction:column;gap:8px;max-width:100%}\n.dq-heat-grid{display:flex;gap:6px;overflow-x:auto;padding-bottom:2px}\n.dq-heat-dows{display:flex;flex-direction:column;gap:3px;padding-top:17px;flex:none}\n.dq-heat-dow{height:12px;line-height:12px;font-size:9px;color:var(--dsw-alias-label-tertiary,#59636e);text-align:right;width:12px}\n.dq-heat-cols{display:flex;flex-direction:column;gap:2px;min-width:0}\n.dq-heat-months{display:flex;gap:3px;height:12px}\n.dq-heat-month{width:12px;flex:none;font-size:9px;line-height:12px;color:var(--dsw-alias-label-tertiary,#59636e);white-space:nowrap;overflow:visible}\n.dq-heatmap{display:flex;gap:3px;width:max-content}\n.dq-heat-week{display:flex;flex-direction:column;gap:3px}\n.dq-heat-cell{width:12px;height:12px;border-radius:2px;flex:none}\n.dq-heat-cell--pad{background:transparent}\n.dq-heat-key{width:12px;height:12px;border-radius:2px;flex:none}\n.dq-heat-scale{display:flex;align-items:center;gap:3px;font-size:10px;color:var(--dsw-alias-label-tertiary,#59636e);align-self:flex-end}\n.dq-heat-scale>span:first-child{margin-right:2px}\n.dq-heat-scale>span:last-child{margin-left:2px}\n.dq-muted{color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-warn{color:var(--dsw-alias-state-warning-primary,#9a6700)}\n.dq-empty{color:var(--dsw-alias-label-secondary,#59636e);font-size:12.5px;line-height:1.6;padding:6px 0}\n.dq-skel{background:linear-gradient(90deg,rgba(125,135,155,.10) 25%,rgba(125,135,155,.20) 37%,rgba(125,135,155,.10) 63%);background-size:400% 100%;border-radius:5px;animation:dq-shimmer 1.5s ease-in-out infinite}\n.dq-stat .dq-skel+.dq-skel{margin-top:6px}\n.dq-skel-bars{display:flex;align-items:flex-end;gap:2px;width:100%;height:120px;margin-top:10px}\n.dq-skel-bar{flex:1 1 0;min-width:0;border-radius:2px 2px 0 0}\n@keyframes dq-shimmer{0%{background-position:100% 50%}100%{background-position:0 50%}}\n@media (prefers-reduced-motion:reduce){.dq-skel{animation:none}.dq-refresh-icon--spin{animation:none}}\n.dq-status-row{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:20px}\n.dq-status-row .dq-muted,.dq-status-row .dq-error{font-size:12px}\n.dq-refresh-btn{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:5px 10px;font-size:12px;cursor:pointer;transition:border-color .15s ease,color .15s ease}\n.dq-refresh-btn:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-refresh-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-refresh-btn:disabled{cursor:default;opacity:.6}\n.dq-refresh-icon{display:inline-block;line-height:1}\n.dq-refresh-icon--spin{animation:dq-spin .9s linear infinite}\n@keyframes dq-spin{to{transform:rotate(360deg)}}\n`\n", "/** The draggable bottom-right floating balance widget.\n *\n * Where it sits (corner) and whether it is collapsed are user choices, so both\n * are persisted (see ./prefs.ts) and restored before the first paint; the\n * widget also re-snaps to its corner when the frame resizes (window resize,\n * sidebar collapse) instead of stranding itself at stale pixel coordinates.\n */\nimport { useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type PointerEvent as ReactPointerEvent, type ReactElement } from 'react'\nimport { fetchBalance, fetchUsage, getCachedBalance, getCachedUsage, getCachedUsageAt, subscribeUsage } from './api.ts'\nimport { fmt } from './charts.tsx'\nimport type { BalanceData, UsageData } from '../contract.ts'\nimport { isBoolean, loadPref, savePref } from './prefs.ts'\nimport { lowBalanceStore, widgetVisibleStore } from './store.ts'\n\nconst MARGIN = 16\n\ntype Corner = 'tl' | 'tr' | 'bl' | 'br'\n\nconst CORNER_KEY = 'widget.corner'\nconst COLLAPSED_KEY = 'widget.collapsed'\n\nconst isCorner = (value: unknown): boolean =>\n value === 'tl' || value === 'tr' || value === 'bl' || value === 'br'\n\ninterface Bounds {\n left: number\n top: number\n right: number\n bottom: number\n}\n\ninterface DragSession {\n pointerId: number\n startX: number\n startY: number\n originX: number\n originY: number\n width: number\n height: number\n bounds: Bounds\n}\n\n/** The shell's main column: the region between the sidebar and the details\n * panel. Found through the stable `conversation` slot anchor rather than the\n * hashed layout class names. */\nfunction getMainColumn(frame: HTMLElement): HTMLElement | null {\n const anchor = frame.querySelector('[data-slot=\"conversation\"]')\n const column = anchor?.parentElement ?? null\n return column === frame ? null : column\n}\n\n/**\n * The laid-out box behind a slot. Slot wrappers are 0\u00D70, and which neighbour\n * carries the real box differs per slot: the session header renders inside its\n * wrapper (`'child'`), while the composer's wrapper sits inside the seat that\n * reserves the space (`'ancestor'`). Picking the wrong side silently yields a\n * box in the wrong place, so the caller says which one it means.\n */\nfunction slotBox(frame: HTMLElement, slot: string, side: 'child' | 'ancestor'): DOMRect | null {\n const anchor = frame.querySelector(`[data-slot=\"${slot}\"]`)\n if (anchor === null) return null\n if (side === 'child') {\n const rect = (anchor.firstElementChild as HTMLElement | null)?.getBoundingClientRect() ?? null\n return rect !== null && rect.height > 0 ? rect : null\n }\n let el: HTMLElement | null = anchor.parentElement\n for (let depth = 0; depth < 4 && el !== null && el !== frame; depth++) {\n const rect = el.getBoundingClientRect()\n if (rect.height > 0) return rect\n el = el.parentElement\n }\n return null\n}\n\n/** Below this the region is too short to park a widget in, so an exclusion is\n * skipped rather than squeezing the widget out of the frame. */\nconst MIN_REGION_HEIGHT = 140\n\n/**\n * Draggable area = the main column minus the session header and the composer.\n *\n * Using the main column (rather than the whole frame minus the sidebar) also\n * keeps the widget clear of the right-hand details panel when it is open.\n * The header is excluded so the widget can never park on the Chat / Trajectory\n * / \u989D\u5EA6 tab row and swallow its clicks, and the composer is excluded because a\n * bottom-right widget otherwise covers the model picker and the send button \u2014\n * the two controls the user reaches for most.\n */\nfunction getBounds(node: HTMLElement | null): Bounds {\n const fallback: Bounds = { left: 0, top: 0, right: 100000, bottom: 100000 }\n if (node === null) return fallback\n const overlay = typeof node.closest === 'function' ? node.closest('[data-shell-overlay]') : null\n const frame = overlay?.parentElement ?? null\n if (frame === null) return fallback\n const frameRect = frame.getBoundingClientRect()\n let left = frameRect.left\n let right = frameRect.right\n let top = frameRect.top\n const mainRect = getMainColumn(frame)?.getBoundingClientRect() ?? null\n if (mainRect !== null && mainRect.width > 0) {\n left = mainRect.left\n right = mainRect.right\n top = mainRect.top\n } else {\n const sidebarRect = (frame.children[0] as HTMLElement | undefined)?.getBoundingClientRect() ?? null\n if (sidebarRect !== null) left = sidebarRect.right\n }\n let bottom = frameRect.bottom\n const headerRect = slotBox(frame, 'conversation.session.header', 'child')\n if (headerRect !== null && headerRect.bottom > top && headerRect.bottom < bottom - MIN_REGION_HEIGHT) {\n top = headerRect.bottom\n }\n const composerRect = slotBox(frame, 'conversation.composer.dock', 'ancestor')\n if (composerRect !== null && composerRect.top < bottom && composerRect.top > top + MIN_REGION_HEIGHT) {\n bottom = composerRect.top\n }\n return { left, top, right, bottom }\n}\n\nfunction cornerPos(corner: Corner, node: HTMLElement | null, bounds: Bounds): { x: number; y: number } {\n const rect = node?.getBoundingClientRect()\n const w = rect?.width ?? 0\n const h = rect?.height ?? 0\n const xLeft = bounds.left + MARGIN\n const yTop = bounds.top + MARGIN\n const xRight = bounds.right - w - MARGIN\n const yBottom = bounds.bottom - h - MARGIN\n if (corner === 'tl') return { x: xLeft, y: yTop }\n if (corner === 'tr') return { x: xRight, y: yTop }\n if (corner === 'bl') return { x: xLeft, y: yBottom }\n return { x: xRight, y: yBottom }\n}\n\nexport function QuotaWidget(): ReactElement | null {\n const [visible, setVisible] = useState(widgetVisibleStore.get())\n useEffect(() => widgetVisibleStore.subscribe(() => setVisible(widgetVisibleStore.get())), [])\n const [lowBalance, setLowBalance] = useState(lowBalanceStore.get())\n useEffect(() => lowBalanceStore.subscribe(() => setLowBalance(lowBalanceStore.get())), [])\n\n const cachedBalance = getCachedBalance()\n const [data, setData] = useState<BalanceData | null>(cachedBalance?.data ?? null)\n const [error, setError] = useState<string | null>(null)\n const [loading, setLoading] = useState(cachedBalance === null)\n const [collapsed, setCollapsed] = useState(() => loadPref<boolean>(COLLAPSED_KEY, isBoolean, false))\n const [pos, setPos] = useState<{ x: number; y: number } | null>(null)\n const [corner, setCorner] = useState<Corner>(() => loadPref<Corner>(CORNER_KEY, isCorner, 'br'))\n const [dragging, setDragging] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const dragRef = useRef<DragSession | null>(null)\n\n // Today's spend comes from the shared usage cache \u2014 never fetched on the\n // widget's own poll, since aggregating the session logs takes seconds. A\n // manual refresh (below) is the one place the widget pays for it.\n const readUsage = (): { data: UsageData | null; at: number | null } => {\n const cached = getCachedUsage()\n return { data: cached?.ok === true ? cached.data ?? null : null, at: getCachedUsageAt() }\n }\n const [usage, setUsage] = useState(readUsage)\n useEffect(() => subscribeUsage(() => setUsage(readUsage())), [])\n\n const load = async (showLoading: boolean, force = false): Promise<void> => {\n if (showLoading) setLoading(true)\n try {\n const res = await fetchBalance(force)\n if (res.ok && res.data !== undefined) {\n setData(res.data)\n setError(null)\n } else {\n setData(null)\n setError(res.error ?? '\u67E5\u8BE2\u5931\u8D25')\n }\n } catch (err) {\n setData(null)\n setError((err as { message?: string } | null)?.message ?? String(err))\n } finally {\n setLoading(false)\n }\n }\n\n useEffect(() => {\n void load(true)\n const id = setInterval(() => { void load(false) }, 60_000)\n return () => clearInterval(id)\n }, [])\n\n /**\n * Keep the widget parked in its corner: on mount (restoring the persisted\n * corner before the first paint), when collapse/expand changes its size, and\n * whenever the layout moves under it \u2014 window resize, sidebar collapse or\n * the details panel opening (observed), plus a slow poll that catches the\n * one change no observer reports: the session header mounting *after* the\n * overlay, which would otherwise leave the widget parked over the tab row.\n *\n * `place` keeps the previous object when the corner has not actually moved,\n * so repeated triggers cost one rect read and no re-render.\n */\n useLayoutEffect(() => {\n if (!visible) return\n const node = rootRef.current\n if (node === null) return\n const place = (): void => {\n if (dragRef.current !== null) return\n const next = cornerPos(corner, node, getBounds(node))\n setPos(prev => (prev !== null && prev.x === next.x && prev.y === next.y ? prev : next))\n }\n place()\n const frame = node.closest('[data-shell-overlay]')?.parentElement as HTMLElement | null\n let observer: ResizeObserver | null = null\n if (frame !== null && typeof ResizeObserver === 'function') {\n observer = new ResizeObserver(place)\n observer.observe(frame)\n const main = getMainColumn(frame)\n if (main !== null) observer.observe(main)\n }\n window.addEventListener('resize', place)\n const poll = setInterval(place, 1000)\n return () => {\n observer?.disconnect()\n window.removeEventListener('resize', place)\n clearInterval(poll)\n }\n }, [visible, corner, collapsed])\n\n const snapToNearest = (session: DragSession): void => {\n const node = rootRef.current\n if (node === null) return\n const { width: w, height: h, bounds: b } = session\n const corners: Array<{ c: Corner; x: number; y: number }> = [\n { c: 'tl', x: b.left + MARGIN, y: b.top + MARGIN },\n { c: 'tr', x: b.right - w - MARGIN, y: b.top + MARGIN },\n { c: 'bl', x: b.left + MARGIN, y: b.bottom - h - MARGIN },\n { c: 'br', x: b.right - w - MARGIN, y: b.bottom - h - MARGIN },\n ]\n const rect = node.getBoundingClientRect()\n const cx = rect.left + rect.width / 2\n const cy = rect.top + rect.height / 2\n let best = corners[0]\n let bestDistance = Number.POSITIVE_INFINITY\n for (const candidate of corners) {\n const ccx = candidate.x + w / 2\n const ccy = candidate.y + h / 2\n const distance = (ccx - cx) ** 2 + (ccy - cy) ** 2\n if (distance < bestDistance) {\n bestDistance = distance\n best = candidate\n }\n }\n setCorner(best.c)\n savePref(CORNER_KEY, best.c)\n setPos({ x: best.x, y: best.y })\n }\n\n /** Idempotent end-of-drag; also the missed-pointerup backstop. */\n const endDrag = (snap: boolean): void => {\n const session = dragRef.current\n if (session === null) return\n dragRef.current = null\n setDragging(false)\n const node = rootRef.current\n if (node !== null && typeof node.releasePointerCapture === 'function') {\n try {\n node.releasePointerCapture(session.pointerId)\n } catch {\n // capture already released\n }\n }\n if (snap) {\n if (typeof requestAnimationFrame === 'function') {\n requestAnimationFrame(() => snapToNearest(session))\n } else {\n snapToNearest(session)\n }\n }\n }\n\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>): void => {\n if (e.button !== 0) return\n const target = e.target as Element | null\n if (target !== null && typeof target.closest === 'function' && target.closest('button') !== null) return\n const node = rootRef.current\n if (node === null) return\n const bounds = getBounds(node)\n const rect = node.getBoundingClientRect()\n dragRef.current = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n originX: rect.left,\n originY: rect.top,\n width: rect.width,\n height: rect.height,\n bounds,\n }\n node.setPointerCapture(e.pointerId)\n setDragging(true)\n e.preventDefault()\n }\n\n const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const session = dragRef.current\n if (session === null || session.pointerId !== e.pointerId) return\n if ((e.buttons & 1) === 0) {\n endDrag(true)\n return\n }\n const dx = e.clientX - session.startX\n const dy = e.clientY - session.startY\n const maxX = session.bounds.right - session.width - MARGIN\n const maxY = session.bounds.bottom - session.height - MARGIN\n const minX = session.bounds.left + MARGIN\n const minY = session.bounds.top + MARGIN\n setPos({\n x: Math.max(minX, Math.min(session.originX + dx, maxX)),\n y: Math.max(minY, Math.min(session.originY + dy, maxY)),\n })\n }\n\n const onPointerUp = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const session = dragRef.current\n if (session === null || session.pointerId !== e.pointerId) return\n endDrag(true)\n }\n\n if (!visible) return null\n\n const primary = data !== null && data.balances.length > 0 ? data.balances[0] : null\n const balanceValue = primary !== null ? Number(primary.total) : Number.NaN\n const low = lowBalance > 0 && Number.isFinite(balanceValue) && balanceValue < lowBalance\n const dotClass = primary === null\n ? 'dsh-quota-dot dsh-quota-dot--idle'\n : data?.isAvailable === false\n ? 'dsh-quota-dot dsh-quota-dot--error'\n : low ? 'dsh-quota-dot dsh-quota-dot--warn' : 'dsh-quota-dot'\n\n // The usage figure can be minutes old (it is only refreshed on demand), so\n // say how old rather than presenting it as live.\n const ageMinutes = usage.at === null ? null : Math.floor((Date.now() - usage.at) / 60_000)\n const usageAgeText = ageMinutes === null || ageMinutes < 1 ? '\u521A\u521A\u66F4\u65B0' : `${ageMinutes} \u5206\u949F\u524D\u7684\u6570\u636E\uFF0C\u70B9 \u21BB \u66F4\u65B0`\n\n let body: ReactElement | null = null\n if (!collapsed) {\n if (loading && data === null && error === null) {\n body = <div className=\"dsh-quota-body\">\u67E5\u8BE2\u4E2D\u2026</div>\n } else if (error !== null && data === null) {\n body = <div className=\"dsh-quota-body dsh-quota-error\">{error}</div>\n } else if (primary !== null) {\n body = (\n <div className=\"dsh-quota-body\">\n <div className=\"dsh-quota-remaining-label\">\u5269\u4F59\u4F59\u989D</div>\n <div title={low ? `\u4F59\u989D\u4F4E\u4E8E\u9884\u8B66\u7EBF ${fmt(lowBalance)}` : undefined}>\n <span className={`dsh-quota-total${low ? ' dsh-quota-total--low' : ''}`}>{fmt(primary.total)}</span>\n <span className=\"dsh-quota-currency\">{primary.currency}</span>\n </div>\n {usage.data !== null && (\n <div className=\"dsh-quota-row\" title={`\u4ECA\u65E5\u6D88\u8017\uFF08\u4F30\u7B97\uFF09\u00B7 ${usageAgeText}`}>\n <span className=\"dsh-quota-label\">\u4ECA\u65E5\u6D88\u8017</span>\n <span className=\"dsh-quota-value\">\u00A5 {fmt(usage.data.summary.today.cost)}</span>\n </div>\n )}\n {data?.isAvailable === false && (\n <div className=\"dsh-quota-row\">\n <span className=\"dsh-quota-label\">\u72B6\u6001</span>\n <span className=\"dsh-quota-value dsh-quota-error\">\u4E0D\u53EF\u7528</span>\n </div>\n )}\n </div>\n )\n } else {\n body = <div className=\"dsh-quota-body dsh-quota-error\">\u6682\u65E0\u4F59\u989D\u6570\u636E</div>\n }\n }\n\n const style: CSSProperties | undefined = pos !== null\n ? { left: `${pos.x}px`, top: `${pos.y}px`, right: 'auto', bottom: 'auto' }\n : undefined\n\n return (\n <div className={`dsh-quota-root${dragging ? ' dsh-quota-dragging' : ''}`} style={style}>\n <div\n ref={rootRef}\n className=\"dsh-quota-card\"\n title=\"\u62D6\u52A8\u5230\u56DB\u4E2A\u89D2\u843D\"\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={() => endDrag(false)}\n onLostPointerCapture={() => endDrag(false)}\n >\n <div className=\"dsh-quota-header\">\n <div className=\"dsh-quota-title\">\n <span className=\"dsh-quota-grip\" title=\"\u62D6\u52A8\u4EE5\u79FB\u52A8\">\u2807</span>\n <span className={dotClass} />\n <span className=\"dsh-quota-name\">DeepSeek \u989D\u5EA6</span>\n {collapsed && primary !== null && (\n <span className={`dsh-quota-collapsed-total${low ? ' dsh-quota-total--low' : ''}`}>{fmt(primary.total)} {primary.currency}</span>\n )}\n </div>\n <div className=\"dsh-quota-actions\">\n <button\n className=\"dsh-quota-btn\"\n type=\"button\"\n title=\"\u5237\u65B0\u4F59\u989D\u4E0E\u4ECA\u65E5\u7528\u91CF\"\n aria-label=\"\u5237\u65B0\u4F59\u989D\u4E0E\u4ECA\u65E5\u7528\u91CF\"\n disabled={loading}\n onClick={() => {\n void load(true, true)\n void fetchUsage(true)\n }}\n >\n \u21BB\n </button>\n <button\n className=\"dsh-quota-btn\"\n type=\"button\"\n title={collapsed ? '\u5C55\u5F00' : '\u6536\u8D77'}\n aria-label={collapsed ? '\u5C55\u5F00\u989D\u5EA6\u7A97\u53E3' : '\u6536\u8D77\u989D\u5EA6\u7A97\u53E3'}\n aria-expanded={!collapsed}\n onClick={() => {\n const next = !collapsed\n setCollapsed(next)\n savePref(COLLAPSED_KEY, next)\n }}\n >\n {collapsed ? '+' : '\u2212'}\n </button>\n </div>\n </div>\n {body}\n </div>\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["import_react", "import_jsx_runtime", "rate", "name", "import_react", "import_jsx_runtime", "import_jsx_runtime"]
|
|
3
|
+
"sources": ["../src/client/index.tsx", "../src/client/boundary.tsx", "../src/client/dashboard.tsx", "../src/client/cache.ts", "../src/client/api.ts", "../src/client/charts.tsx", "../src/client/prefs.ts", "../src/client/store.ts", "../src/client/styles.ts", "../src/client/widget.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * dsh-usage-dashboard client half: mounts the floating balance widget\n * (`shell.overlay`) and the \u300C\u989D\u5EA6\u300D view tab (`conversation.view`).\n * Data arrives through the package's own host API via same-origin fetch.\n */\nimport { ErrorBoundary } from './boundary.tsx'\nimport type { ClientContext } from './context.ts'\nimport { BalanceDashboard } from './dashboard.tsx'\nimport { css } from './styles.ts'\nimport { QuotaWidget } from './widget.tsx'\n\n/** Plugin identity for the client bundle. */\nexport const name = 'dsh-usage-dashboard'\n\n/** Services required before load. */\nexport const inject = ['slots']\n\n/**\n * Mount the two surfaces.\n * @param ctx - client Cordis context.\n */\nexport function apply(ctx: ClientContext): void {\n // One stylesheet for the whole plugin; the module loader claims and removes\n // plugin-owned style tags on unload.\n if (typeof document !== 'undefined') {\n const tag = document.createElement('style')\n tag.dataset.plugin = 'dsh-usage-dashboard'\n tag.textContent = css\n document.head.appendChild(tag)\n }\n\n ctx.slots.inject('shell.overlay', () => ctx.slots.register(\n { name: 'shell.overlay', id: 'deepseek-quota', order: 1000, label: 'DeepSeek \u989D\u5EA6' },\n () => <ErrorBoundary silent><QuotaWidget /></ErrorBoundary>,\n ))\n\n ctx.slots.inject('conversation.view', () => ctx.slots.register(\n { name: 'conversation.view', id: 'balance', order: 20, label: '\u989D\u5EA6' },\n () => <ErrorBoundary><BalanceDashboard /></ErrorBoundary>,\n ))\n}\n", "/**\n * Error boundary for the plugin's two slot entries.\n *\n * A slot component that throws while rendering takes its whole subtree down \u2014\n * for the \u300C\u989D\u5EA6\u300D view that meant a blank tab, and the only thing that fixed it\n * was a browser profile with no localStorage. A crash should degrade to\n * something the user can act on, and it should never be the tab's silent\n * default state.\n */\nimport { Component, type ErrorInfo, type ReactNode } from 'react'\n\nconst PREFIX = 'dsh-usage-dashboard:'\n\n/** Drop every key this plugin owns \u2014 caches and preferences alike. */\nfunction clearPluginStorage(): void {\n if (typeof localStorage === 'undefined') return\n try {\n for (const key of Object.keys(localStorage)) {\n if (key.startsWith(PREFIX)) localStorage.removeItem(key)\n }\n } catch {\n // Nothing better to do; the reload below is still worth attempting.\n }\n}\n\ninterface Props {\n /** Shown instead of the fallback UI when the surface has no room for it. */\n silent?: boolean\n children: ReactNode\n}\n\ninterface State {\n message: string | null\n}\n\nexport class ErrorBoundary extends Component<Props, State> {\n state: State = { message: null }\n\n static getDerivedStateFromError(error: unknown): State {\n return { message: (error as { message?: string } | null)?.message ?? String(error) }\n }\n\n componentDidCatch(error: unknown, info: ErrorInfo): void {\n console.error('[dsh-usage-dashboard] render failed', error, info.componentStack)\n }\n\n private readonly reset = (): void => {\n clearPluginStorage()\n location.reload()\n }\n\n render(): ReactNode {\n const { message } = this.state\n if (message === null) return this.props.children\n if (this.props.silent === true) return null\n return (\n <div className=\"dq-balance\">\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u989D\u5EA6\u9762\u677F\u51FA\u9519\u4E86</div>\n <p className=\"dq-empty\">\n \u6E32\u67D3\u65F6\u629B\u4E86\u5F02\u5E38\uFF0C\u901A\u5E38\u662F\u6D4F\u89C8\u5668\u91CC\u5B58\u7740\u65E7\u7248\u672C\u7684\u7F13\u5B58\u6570\u636E\u3002\u6E05\u6389\u672C\u63D2\u4EF6\u7684\u672C\u5730\u6570\u636E\u518D\u91CD\u65B0\u52A0\u8F7D\u5C31\u80FD\u6062\u590D\u3002\n </p>\n <pre className=\"dq-crash\">{message}</pre>\n <button type=\"button\" className=\"dq-refresh-btn\" onClick={this.reset}>\n \u6E05\u9664\u672C\u5730\u6570\u636E\u5E76\u91CD\u65B0\u52A0\u8F7D\n </button>\n </div>\n </div>\n )\n }\n}\n", "/** The \u300C\u989D\u5EA6\u300D conversation view tab: full balance & usage dashboard.\n *\n * Caching: the first render comes straight from the package-local cache\n * (see ./api.ts), so reopening the tab shows data instantly. A background\n * refresh then updates it without blocking; a full-screen \u52A0\u8F7D\u4E2D only\n * appears when nothing has ever been cached.\n */\nimport { Fragment, useEffect, useRef, useState, type ReactElement, type ReactNode } from 'react'\nimport { fetchBalance, fetchUsage, getCachedBalance, getCachedUsage } from './api.ts'\nimport { Bars, GroupedBars, Heatmap, MODEL_COLORS, fmt, fmtCompact, fmtInt } from './charts.tsx'\nimport type { BalanceData, ModelUsage, PeakSplit, PeriodUsage, PricingInfo, SessionCost, UsageData } from '../contract.ts'\nimport { lowBalanceStore, widgetVisibleStore } from './store.ts'\n\n/** One shimmering placeholder block, sized by the caller. */\nfunction Skel(props: { w: number; h: number }): ReactElement {\n return <div className=\"dq-skel\" style={{ width: `${props.w}px`, height: `${props.h}px` }} />\n}\n\n/** Placeholder for the balance card while the first fetch is in flight. */\nfunction BalanceSkeleton(): ReactElement {\n return (\n <div className=\"dq-balance-grid\">\n <div className=\"dq-stat\"><Skel w={56} h={11} /><Skel w={150} h={22} /></div>\n <div className=\"dq-stat\"><Skel w={28} h={11} /><Skel w={48} h={22} /></div>\n </div>\n )\n}\n\n/** Placeholder for the usage card: replaying every session log takes seconds,\n * and an empty-state string there would read as \"you have no usage\". */\nfunction UsageSkeleton(): ReactElement {\n return (\n <>\n <div className=\"dq-usage-totals\">\n {[44, 44, 62, 62].map((w, i) => (\n <div key={i} className=\"dq-stat\"><Skel w={w} h={11} /><Skel w={w > 70 ? 84 : 56} h={20} /></div>\n ))}\n </div>\n <Skel w={140} h={12} />\n <div className=\"dq-skel-bars\">\n {Array.from({ length: 30 }, (_, i) => (\n <div key={i} className=\"dq-skel dq-skel-bar\" style={{ height: `${18 + ((i * 37) % 82)}px` }} />\n ))}\n </div>\n </>\n )\n}\n\n/** Percentage chip comparing a window against the one before it. */\nfunction Delta(props: { current: number; previous: number; label: string }): ReactElement | null {\n const { current, previous, label } = props\n if (previous <= 0) {\n if (current <= 0) return null\n return <span className=\"dq-delta dq-delta--new\" title={`${label}\u6CA1\u6709\u7528\u91CF\uFF0C\u65E0\u4ECE\u5BF9\u6BD4`}>\u65E0\u5BF9\u6BD4</span>\n }\n const percent = Math.round(((current - previous) / previous) * 100)\n const title = `${label} \u00A5${fmt(previous)}`\n if (percent === 0) return <span className=\"dq-delta dq-delta--flat\" title={title}>\u6301\u5E73</span>\n const up = percent > 0\n return (\n <span className={`dq-delta ${up ? 'dq-delta--up' : 'dq-delta--down'}`} title={title}>\n {up ? '\u2191' : '\u2193'}{Math.abs(percent)}% <span className=\"dq-delta-label\">{label}</span>\n </span>\n )\n}\n\n/** One window of the \u6D88\u8017\u6982\u89C8 card: cost headline, volume underneath. */\nfunction Period(props: {\n label: string\n period: PeriodUsage\n previous?: PeriodUsage\n compare?: string\n}): ReactElement {\n const { period, previous, compare } = props\n return (\n <div className=\"dq-period\">\n <div className=\"dq-period-head\">\n <span className=\"dq-period-label\">{props.label}</span>\n {previous !== undefined && compare !== undefined && (\n <Delta current={period.cost} previous={previous.cost} label={compare} />\n )}\n </div>\n <div className=\"dq-period-cost\">\u00A5 {fmt(period.cost)}</div>\n <div className=\"dq-period-sub\">{fmtCompact(period.total)} tokens \u00B7 {fmtInt(period.calls)} \u6B21\u8C03\u7528</div>\n </div>\n )\n}\n\nconst rate = (value: number): string => `\u00A5${value.toLocaleString(undefined, { maximumFractionDigits: 3 })}`\n\n/** Auditable breakdown of the rates the cost estimate was computed with \u2014\n * a `<details>` so it is keyboard-reachable without any extra state. */\nfunction PricingNote(props: { pricing: PricingInfo }): ReactElement {\n const { pricing } = props\n const split = pricing.splitActive\n return (\n <details className=\"dq-pricing\">\n <summary className=\"dq-pricing-summary\">\n \u8BA1\u4EF7\u8BF4\u660E\n {split && (\n <span className={`dq-pricing-now${pricing.inPeakNow ? ' dq-pricing-now--peak' : ''}`}>\n \u5F53\u524D {pricing.inPeakNow ? '\u9AD8\u5CF0\u65F6\u6BB5' : '\u95F2\u65F6'}\n </span>\n )}\n </summary>\n <div className=\"dq-pricing-body\">\n <table className=\"dq-pricing-table\">\n <thead>\n <tr>\n <th>\u6A21\u578B</th>\n <th>{split ? '\u65F6\u6BB5' : '\u5355\u4EF7'}</th>\n <th>\u8F93\u5165\u00B7\u7F13\u5B58\u547D\u4E2D</th>\n <th>\u8F93\u5165\u00B7\u672A\u547D\u4E2D</th>\n <th>\u8F93\u51FA</th>\n </tr>\n </thead>\n <tbody>\n {pricing.tiers.map(tier => (\n <Fragment key={tier.model}>\n <tr>\n <td rowSpan={tier.offPeak !== null ? 2 : 1}>{tier.model}</td>\n <td>{split ? '\u9AD8\u5CF0' : '\u56FA\u5B9A'}</td>\n <td>{rate(tier.peak.cacheHit)}</td>\n <td>{rate(tier.peak.input)}</td>\n <td>{rate(tier.peak.output)}</td>\n </tr>\n {tier.offPeak !== null && (\n <tr>\n <td>\u95F2\u65F6</td>\n <td>{rate(tier.offPeak.cacheHit)}</td>\n <td>{rate(tier.offPeak.input)}</td>\n <td>{rate(tier.offPeak.output)}</td>\n </tr>\n )}\n </Fragment>\n ))}\n </tbody>\n </table>\n <p className=\"dq-pricing-foot\">\n \u5355\u4F4D\uFF1A{pricing.currency} / \u767E\u4E07 tokens\u3002\n {split\n ? `\u9AD8\u5CF0\u65F6\u6BB5\u4E3A\u5317\u4EAC\u65F6\u95F4 ${pricing.peakWindows.join('\u3001')}\uFF0C\u5176\u4F59\u4E3A\u95F2\u65F6\uFF08\u4EF7\u683C\u51CF\u534A\uFF09\uFF1B${pricing.switchDate} \u4E4B\u524D\u7684\u7528\u91CF\u4ECD\u6309\u65E7\u4EF7\u4F30\u7B97\u3002`\n : `${pricing.switchDate} 00:00 \u8D77\u6539\u4E3A\u5CF0\u8C37\u5B9A\u4EF7\uFF08\u9AD8\u5CF0 ${pricing.peakWindows.join('\u3001')}\uFF0C\u95F2\u65F6\u4EF7\u683C\u51CF\u534A\uFF09\uFF0C\u5C4A\u65F6\u672C\u9875\u4F1A\u6309\u6BCF\u6761\u8BB0\u5F55\u7684\u65F6\u95F4\u81EA\u52A8\u5206\u6BB5\u8BA1\u4EF7\u3002`}\n \u672A\u77E5\u6A21\u578B\u6309 deepseek-v4-pro \u8BA1\u4EF7\u3002\n </p>\n </div>\n </details>\n )\n}\n\nfunction Stat(props: { label: string; children: ReactNode }): ReactElement {\n return (\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{props.label}</div>\n {props.children}\n </div>\n )\n}\n\nfunction Link(props: { href: string; children: ReactNode }): ReactElement {\n return (\n <a className=\"dq-link\" href={props.href} target=\"_blank\" rel=\"noreferrer\">{props.children}</a>\n )\n}\n\nexport const modelKeyOf = (m: ModelUsage): string => (m.provider !== '' ? `${m.provider}/${m.model}` : m.model)\n\nexport const modelNameOf = (m: ModelUsage): string => (m.model !== '' ? m.model : '\u672A\u77E5\u6A21\u578B')\n\n/**\n * What prefix caching is doing for the bill. Cache-hit tokens are priced at a\n * small fraction of cache-miss tokens, so on a DSH workload this is usually the\n * single biggest lever on cost \u2014 and it was invisible before.\n */\nfunction CacheCard(props: { totals: UsageData['totals'] }): ReactElement {\n const { totals } = props\n const prompt = totals.input + totals.cache\n if (prompt === 0) return <div className=\"dq-empty\">\u8FD8\u6CA1\u6709 prompt token \u53EF\u7EDF\u8BA1\u7F13\u5B58\u547D\u4E2D\u3002</div>\n const rate = totals.cache / prompt\n const wouldHaveCost = totals.cost + totals.cacheSavings\n const low = rate < 0.6\n return (\n <div className=\"dq-cache\">\n <div className=\"dq-cache-figures\">\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u7F13\u5B58\u547D\u4E2D\u7387</div>\n <div className={`dq-stat-value${low ? ' dq-stat-value--warn' : ' dq-stat-value--ok'}`}>\n {(rate * 100).toFixed(1)}%\n </div>\n </div>\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u5DF2\u8282\u7701\u8D39\u7528\uFF08\u4F30\u7B97\uFF09</div>\n <div className=\"dq-stat-value\">\u00A5 {fmt(totals.cacheSavings)}</div>\n </div>\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u82E5\u5168\u90E8\u672A\u547D\u4E2D</div>\n <div className=\"dq-stat-value dq-muted-value\">\u00A5 {fmt(wouldHaveCost)}</div>\n </div>\n </div>\n <div className=\"dq-cache-track\" role=\"img\" aria-label={`\u7F13\u5B58\u547D\u4E2D ${(rate * 100).toFixed(1)}%\uFF0C\u672A\u547D\u4E2D ${((1 - rate) * 100).toFixed(1)}%`}>\n <div className=\"dq-cache-fill\" style={{ width: `${rate * 100}%` }} />\n </div>\n <div className=\"dq-cache-legend\">\n <span><span className=\"dq-legend-swatch dq-legend-swatch--hit\" />\u7F13\u5B58\u547D\u4E2D {fmtCompact(totals.cache)}</span>\n <span><span className=\"dq-legend-swatch dq-legend-swatch--miss\" />\u672A\u547D\u4E2D {fmtCompact(totals.input)}\uFF08\u6309\u672A\u547D\u4E2D\u4EF7\u8BA1\u8D39\uFF09</span>\n </div>\n <p className=\"dq-cache-foot\">\n {low\n ? '\u547D\u4E2D\u7387\u504F\u4F4E\uFF1A\u9891\u7E41\u6539\u52A8 system prompt / \u5DE5\u5177\u5B9A\u4E49\u4F1A\u8BA9\u524D\u7F00\u7F13\u5B58\u5931\u6548\uFF0C\u628A\u7A33\u5B9A\u5185\u5BB9\u653E\u5728\u5BF9\u8BDD\u6700\u524D\u9762\u80FD\u63D0\u9AD8\u547D\u4E2D\u7387\u3002'\n : '\u524D\u7F00\u7F13\u5B58\u628A\u91CD\u590D\u7684 prompt \u524D\u7F00\u6309\u547D\u4E2D\u4EF7\u8BA1\u8D39\uFF0C\u662F\u8FD9\u4EFD\u8D26\u5355\u4E0A\u6700\u5927\u7684\u7701\u94B1\u6760\u6746\u3002'}\n </p>\n </div>\n )\n}\n\n/**\n * Peak vs off-peak: which side of DeepSeek's price windows the usage falls on.\n * Before the 2026-08-17 switch this answers \"what will the new prices cost me\";\n * after it, \"what would shifting work off-peak save me\".\n */\nfunction PeakCard(props: { split: PeakSplit; pricing: PricingInfo; currentCost: number }): ReactElement {\n const { split, pricing, currentCost } = props\n const total = split.peak.total + split.offPeak.total\n if (total === 0) return <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u53EF\u6309\u65F6\u6BB5\u5F52\u7C7B\u7684\u7528\u91CF\u3002</div>\n const peakShare = split.peak.total / total\n const shiftSaving = split.peakEraCost - split.offPeakEraCost\n const increase = split.peakEraCost - currentCost\n const increasePercent = currentCost > 0 ? (increase / currentCost) * 100 : 0\n return (\n <div className=\"dq-peak\">\n <div\n className=\"dq-peak-track\"\n role=\"img\"\n aria-label={`\u9AD8\u5CF0\u65F6\u6BB5 ${(peakShare * 100).toFixed(1)}%\uFF0C\u95F2\u65F6 ${((1 - peakShare) * 100).toFixed(1)}%`}\n >\n <div className=\"dq-peak-fill\" style={{ width: `${peakShare * 100}%` }} />\n </div>\n <div className=\"dq-peak-legend\">\n <span><span className=\"dq-legend-swatch dq-legend-swatch--peak\" />\u9AD8\u5CF0 {(peakShare * 100).toFixed(1)}% \u00B7 {fmtCompact(split.peak.total)} tokens \u00B7 {fmtInt(split.peak.calls)} \u6B21</span>\n <span><span className=\"dq-legend-swatch dq-legend-swatch--offpeak\" />\u95F2\u65F6 {((1 - peakShare) * 100).toFixed(1)}% \u00B7 {fmtCompact(split.offPeak.total)} tokens \u00B7 {fmtInt(split.offPeak.calls)} \u6B21</span>\n </div>\n <div className=\"dq-peak-figures\">\n {!pricing.splitActive && (\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u540C\u6837\u7528\u91CF\u5728\u65B0\u4EF7\u4E0B</div>\n <div className=\"dq-stat-value\">\n \u00A5 {fmt(split.peakEraCost)}\n <span className=\"dq-peak-delta\">\u8F83\u73B0\u4EF7 +{increasePercent.toFixed(0)}%</span>\n </div>\n </div>\n )}\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u82E5\u9AD8\u5CF0\u7528\u91CF\u90FD\u632A\u5230\u95F2\u65F6</div>\n <div className=\"dq-stat-value\">\n \u00A5 {fmt(split.offPeakEraCost)}\n <span className=\"dq-peak-delta dq-peak-delta--save\">\u53EF\u7701 \u00A5{fmt(shiftSaving)}</span>\n </div>\n </div>\n </div>\n <p className=\"dq-peak-foot\">\n \u9AD8\u5CF0\u65F6\u6BB5\u4E3A\u5317\u4EAC\u65F6\u95F4 {pricing.peakWindows.join('\u3001')}\uFF0C\u95F2\u65F6\u4EF7\u683C\u51CF\u534A\u3002\n {pricing.splitActive\n ? '\u628A\u6279\u91CF\u3001\u53EF\u5EF6\u540E\u7684\u4EFB\u52A1\u653E\u5230\u95F2\u65F6\u8DD1\uFF0C\u540C\u6837\u7684 token \u53EA\u8981\u4E00\u534A\u7684\u94B1\u3002'\n : `\u65B0\u4EF7 ${pricing.switchDate} 00:00 \u751F\u6548\uFF1B\u4E0A\u9762\u4E24\u4E2A\u6570\u5B57\u662F\u6309\u4F60\u5DF2\u6709\u7684\u5168\u90E8\u7528\u91CF\u91CD\u7B97\u7684\u3002`}\n </p>\n </div>\n )\n}\n\n/** Coarse \"how long ago\", enough to tell a live session from last week's. */\nfunction agoText(ms: number): string {\n const minutes = Math.floor((Date.now() - ms) / 60_000)\n if (minutes < 1) return '\u521A\u521A'\n if (minutes < 60) return `${minutes} \u5206\u949F\u524D`\n const hours = Math.floor(minutes / 60)\n if (hours < 24) return `${hours} \u5C0F\u65F6\u524D`\n return `${Math.floor(hours / 24)} \u5929\u524D`\n}\n\n/**\n * Which sessions burned the money. Per-model and per-day views say what and\n * when; this says *which run*, which is the one an agent user can act on \u2014\n * a single expensive session is a prompt or a loop worth looking at.\n */\nfunction SessionRanking(props: { sessions: SessionCost[]; count: number; totalCost: number }): ReactElement {\n const { sessions, count, totalCost } = props\n if (sessions.length === 0) return <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u4EA7\u751F\u8D39\u7528\u7684\u4F1A\u8BDD\u3002</div>\n const top = sessions[0].cost\n return (\n <>\n <ol className=\"dq-sessions\">\n {sessions.map(s => (\n <li key={s.id} className=\"dq-session\">\n <div className=\"dq-session-head\">\n <span className=\"dq-session-title\" title={`${s.title}\\n${s.id}`}>{s.title}</span>\n <span className=\"dq-session-cost\">\u00A5 {fmt(s.cost)}</span>\n </div>\n <div className=\"dq-session-track\">\n <div className=\"dq-session-fill\" style={{ width: `${Math.max((s.cost / (top || 1)) * 100, 1.5)}%` }} />\n </div>\n <div className=\"dq-session-sub\">\n {fmtCompact(s.total)} tokens \u00B7 {fmtInt(s.calls)} \u6B21\u8C03\u7528 \u00B7 {agoText(s.lastActive)}\n {totalCost > 0 && <> \u00B7 \u5360 {((s.cost / totalCost) * 100).toFixed(1)}%</>}\n </div>\n </li>\n ))}\n </ol>\n {count > sessions.length && (\n <p className=\"dq-session-foot\">\u5171 {fmtInt(count)} \u4E2A\u4F1A\u8BDD\u6709\u7528\u91CF\uFF0C\u4E0A\u9762\u662F\u6700\u8D35\u7684 {sessions.length} \u4E2A\u3002</p>\n )}\n </>\n )\n}\n\n/** Which model the money actually goes to, most expensive first. */\nfunction ModelRanking(props: {\n models: ModelUsage[]\n totalCost: number\n colorOf: (key: string) => string\n}): ReactElement {\n const { models, totalCost } = props\n if (models.length === 0) return <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u53EF\u5F52\u7C7B\u7684\u6A21\u578B\u7528\u91CF\u3002</div>\n return (\n <div className=\"dq-rank\">\n {models.map(m => {\n const key = modelKeyOf(m)\n const share = totalCost > 0 ? m.cost / totalCost : 0\n return (\n <div key={key} className=\"dq-rank-row\">\n <div className=\"dq-rank-head\">\n <span className=\"dq-rank-name\" title={key}>\n <span className=\"dq-legend-swatch\" style={{ background: props.colorOf(key) }} />\n {modelNameOf(m)}\n </span>\n <span className=\"dq-rank-cost\">\n \u00A5 {fmt(m.cost)}\n <span className=\"dq-rank-share\">{(share * 100).toFixed(1)}%</span>\n </span>\n </div>\n <div\n className=\"dq-rank-track\"\n role=\"img\"\n aria-label={`${modelNameOf(m)} \u5360\u603B\u8D39\u7528 ${(share * 100).toFixed(1)}%`}\n >\n <div className=\"dq-rank-fill\" style={{ width: `${Math.max(share * 100, 1.5)}%`, background: props.colorOf(key) }} />\n </div>\n <div className=\"dq-rank-sub\">\n {fmtCompact(m.total)} tokens \u00B7 {fmtInt(m.calls)} \u6B21\u8C03\u7528 \u00B7 \u8F93\u5165 {fmtCompact(m.input)} / \u8F93\u51FA {fmtCompact(m.output)} / \u7F13\u5B58 {fmtCompact(m.cache)}\n </div>\n </div>\n )\n })}\n </div>\n )\n}\n\n/** Multi-select model dropdown feeding the grouped bar chart. */\nfunction ModelPicker(props: {\n models: ModelUsage[]\n selected: string[]\n colorOf: (key: string) => string\n onChange: (keys: string[]) => void\n}): ReactElement | null {\n const { models } = props\n if (models.length === 0) return null\n const [open, setOpen] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n if (!open) return\n const onDown = (e: MouseEvent): void => {\n if (rootRef.current !== null && !rootRef.current.contains(e.target as Node)) setOpen(false)\n }\n document.addEventListener('mousedown', onDown)\n return () => document.removeEventListener('mousedown', onDown)\n }, [open])\n\n const toggle = (key: string): void => {\n props.onChange(\n props.selected.includes(key)\n ? props.selected.filter(k => k !== key)\n : [...props.selected, key],\n )\n }\n\n const label = props.selected.length === 0 ? '\u5168\u90E8\u6A21\u578B' : `\u6A21\u578B \u00D7${props.selected.length}`\n\n return (\n <div className=\"dq-model-picker\" ref={rootRef}>\n <button type=\"button\" className=\"dq-model-btn\" onClick={() => setOpen(!open)}>{label}</button>\n {open && (\n <div className=\"dq-model-menu\">\n <label className=\"dq-model-item dq-model-item--all\">\n <input\n type=\"checkbox\"\n checked={props.selected.length === 0}\n onChange={() => props.onChange([])}\n />\n <span>\u5168\u90E8\u6A21\u578B</span>\n </label>\n {models.map(m => {\n const key = modelKeyOf(m)\n return (\n <label key={key} className=\"dq-model-item\">\n <input type=\"checkbox\" checked={props.selected.includes(key)} onChange={() => toggle(key)} />\n <span className=\"dq-legend-swatch\" style={{ background: props.colorOf(key) }} />\n <span>{modelNameOf(m)}</span>\n <span className=\"dq-model-tag\">{fmtCompact(m.total)}</span>\n </label>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n\nexport function BalanceDashboard(): ReactElement {\n // Seed state from the cache so the tab never waits on the network when\n // data has been fetched before (stale-while-revalidate).\n const cachedBalance = getCachedBalance()\n const cachedUsage = getCachedUsage()\n const [balance, setBalance] = useState<BalanceData | null>(cachedBalance?.data ?? null)\n const [usage, setUsage] = useState<UsageData | null>(cachedUsage?.data ?? null)\n const [error, setError] = useState<string | null>(null)\n const [notice, setNotice] = useState<string | null>(null)\n // Balance answers in well under a second, usage replays every session log and\n // takes seconds \u2014 so they get their own loading flags and paint independently\n // instead of the fast one waiting on the slow one.\n const [loadingBalance, setLoadingBalance] = useState(cachedBalance === null)\n const [loadingUsage, setLoadingUsage] = useState(cachedUsage === null)\n const [refreshing, setRefreshing] = useState(false)\n const hadDataRef = useRef(cachedBalance !== null || cachedUsage !== null)\n const [widgetOn, setWidgetOn] = useState(widgetVisibleStore.get())\n const [lowBalance, setLowBalance] = useState(lowBalanceStore.get())\n const [barMode, setBarMode] = useState<'daily' | 'hourly'>('daily')\n const [selectedModels, setSelectedModels] = useState<string[]>([])\n\n const errText = (err: unknown): string => (err as { message?: string } | null)?.message ?? String(err)\n\n /** Load both resources; each resolves to null on success or to its error\n * string on failure, so a partial failure can name the half that broke. */\n const load = async (force: boolean): Promise<void> => {\n setError(null)\n setNotice(null)\n setRefreshing(true)\n const balanceTask = fetchBalance(force).then(res => {\n if (res.ok && res.data !== undefined) {\n setBalance(res.data)\n hadDataRef.current = true\n return null\n }\n return res.error ?? '\u4F59\u989D\u52A0\u8F7D\u5931\u8D25'\n }, err => errText(err)).then(result => {\n setLoadingBalance(false)\n return result\n })\n const usageTask = fetchUsage(force).then(res => {\n if (res.ok && res.data !== undefined) {\n setUsage(res.data)\n hadDataRef.current = true\n return null\n }\n return res.error ?? '\u7528\u91CF\u52A0\u8F7D\u5931\u8D25'\n }, err => errText(err)).then(result => {\n setLoadingUsage(false)\n return result\n })\n const [balanceError, usageError] = await Promise.all([balanceTask, usageTask])\n setRefreshing(false)\n if (balanceError !== null && usageError !== null) {\n // Nothing came back at all: an error only when there is nothing to show.\n if (hadDataRef.current) setNotice(`\u5237\u65B0\u5931\u8D25\uFF0C\u6B63\u5728\u5C55\u793A\u7F13\u5B58\u6570\u636E\uFF08${balanceError}\uFF09`)\n else setError(balanceError)\n } else if (balanceError !== null) {\n setNotice(`\u4F59\u989D\u5237\u65B0\u5931\u8D25\uFF0C\u6B63\u5728\u5C55\u793A\u7F13\u5B58\u4F59\u989D\uFF08${balanceError}\uFF09`)\n } else if (usageError !== null) {\n setNotice(`\u7528\u91CF\u5237\u65B0\u5931\u8D25\uFF0C\u6B63\u5728\u5C55\u793A\u7F13\u5B58\u7528\u91CF\uFF08${usageError}\uFF09`)\n }\n }\n\n useEffect(() => {\n void load(false)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const toggle = (): void => {\n const next = !widgetOn\n setWidgetOn(next)\n widgetVisibleStore.set(next)\n }\n\n const changeLowBalance = (value: number): void => {\n setLowBalance(value)\n lowBalanceStore.set(value)\n }\n\n const primary = balance !== null && balance.balances.length > 0 ? balance.balances[0] : null\n\n // Runway: balance divided by the last 7 calendar days' average spend. Idle\n // days are included on purpose \u2014 that is the burn rate, not the busy-day rate.\n const recentDays = (usage?.daily ?? []).slice(-7)\n const avgDailyCost = recentDays.length > 0\n ? recentDays.reduce((sum, d) => sum + d.cost, 0) / recentDays.length\n : 0\n const balanceValue = primary !== null ? Number(primary.total) : Number.NaN\n // 0 disables the warning; an unreadable balance never triggers it.\n const balanceLow = lowBalance > 0 && Number.isFinite(balanceValue) && balanceValue < lowBalance\n const daysLeft = avgDailyCost > 0 && Number.isFinite(balanceValue) ? balanceValue / avgDailyCost : null\n const daysLeftText = daysLeft === null\n ? '\u2014'\n : daysLeft >= 365 ? '> 365 \u5929' : `${daysLeft < 10 ? daysLeft.toFixed(1) : Math.round(daysLeft)} \u5929`\n const runwayTitle = daysLeft === null\n ? `\u8FD1 ${recentDays.length || 7} \u5929\u6CA1\u6709\u7528\u91CF\uFF0C\u65E0\u6CD5\u4F30\u7B97`\n : `\u6309\u8FD1 ${recentDays.length} \u5929\u65E5\u5747 \u00A5${fmt(avgDailyCost)} \u4F30\u7B97\uFF08\u542B\u65E0\u7528\u91CF\u7684\u65E5\u5B50\uFF1B\u4ECA\u5929\u5C1A\u672A\u8FC7\u5B8C\uFF09`\n\n const dailyBars = (usage?.daily ?? []).map(d => ({\n label: d.date.slice(8, 10),\n value: d.total,\n title: `${d.date} \u00B7 ${fmtInt(d.total)} tokens \u00B7 \u00A5${fmt(d.cost)} \u00B7 ${d.calls} \u6B21\u8C03\u7528`,\n }))\n const hourlyBars = (usage?.hourly ?? []).map(h => ({\n label: String(h.hour),\n value: h.total,\n title: `${h.hour} \u70B9 \u00B7 ${fmtInt(h.total)} tokens \u00B7 ${h.calls} \u6B21\u8C03\u7528`,\n }))\n\n // One canonical model order \u2014 most expensive first \u2014 shared by the ranking\n // card, the picker and the chart, so a model keeps its colour everywhere\n // instead of being coloured by the order it happened to be ticked in.\n // Tallest bar currently on screen \u2014 the chart has no y axis, so this is the\n // only thing giving the bars a magnitude.\n const chartPeak = (barMode === 'daily' ? dailyBars : hourlyBars)\n .reduce((peak, bar) => (bar.value > peak ? bar.value : peak), 0)\n\n const modelList = [...(usage?.models ?? [])].sort((a, b) => b.cost - a.cost)\n const availableModelKeys = new Set(modelList.map(modelKeyOf))\n const effectiveSelection = selectedModels.filter(k => availableModelKeys.has(k))\n const colorOf = (key: string): string => {\n const index = modelList.findIndex(m => modelKeyOf(m) === key)\n return MODEL_COLORS[(index < 0 ? 0 : index) % MODEL_COLORS.length]\n }\n const modelCostTotal = modelList.reduce((sum, m) => sum + m.cost, 0)\n\n // Per-model series for the grouped bar chart (only when models are selected).\n const grouped = effectiveSelection.map(key => {\n const m = modelList.find(x => modelKeyOf(x) === key)\n const name = m === undefined ? key : modelNameOf(m)\n const color = colorOf(key)\n if (barMode === 'daily') {\n return {\n key,\n name,\n color,\n bars: (m?.daily ?? []).map((p, i) => ({\n label: (usage?.daily ?? [])[i]?.date.slice(8, 10) ?? '',\n value: p.total,\n title: `${name} \u00B7 ${(usage?.daily ?? [])[i]?.date ?? ''} \u00B7 ${fmtInt(p.total)} tokens \u00B7 \u00A5${fmt(p.cost)} \u00B7 ${p.calls} \u6B21\u8C03\u7528`,\n })),\n }\n }\n return {\n key,\n name,\n color,\n bars: (m?.hourly ?? []).map((p, i) => ({\n label: String(i),\n value: p.total,\n title: `${name} \u00B7 ${i} \u70B9 \u00B7 ${fmtInt(p.total)} tokens \u00B7 \u00A5${fmt(p.cost)} \u00B7 ${p.calls} \u6B21\u8C03\u7528`,\n })),\n }\n })\n\n return (\n <div className=\"dq-balance\">\n <div className=\"dq-status-row\">\n <div>\n {(loadingBalance || loadingUsage) && <span className=\"dq-muted\">\u52A0\u8F7D\u4E2D\u2026</span>}\n {!loadingBalance && !loadingUsage && refreshing && <span className=\"dq-muted\">\u66F4\u65B0\u4E2D\u2026</span>}\n {notice !== null && <span className=\"dq-warn\">{notice}</span>}\n {error !== null && <span className=\"dq-error\">{error}</span>}\n </div>\n <button\n type=\"button\"\n className=\"dq-refresh-btn\"\n title=\"\u5F3A\u5236\u5237\u65B0\uFF08\u7ED5\u8FC7\u7F13\u5B58\uFF09\"\n disabled={refreshing}\n aria-busy={refreshing}\n onClick={() => { void load(true) }}\n >\n <span className={`dq-refresh-icon${refreshing ? ' dq-refresh-icon--spin' : ''}`}>\u21BB</span>\n {refreshing ? '\u5237\u65B0\u4E2D' : '\u5237\u65B0'}\n </button>\n </div>\n\n {balanceLow && (\n <div className=\"dq-alert\" role=\"status\">\n <span className=\"dq-alert-icon\" aria-hidden=\"true\">!</span>\n <div>\n <strong>\u4F59\u989D {fmt(balanceValue)} {primary?.currency} \u5DF2\u4F4E\u4E8E\u9884\u8B66\u7EBF {fmt(lowBalance)}</strong>\n {daysLeft !== null && <>\uFF0C\u6309\u8FD1\u671F\u7528\u91CF\u4F30\u8BA1\u8FD8\u80FD\u6491 {daysLeftText}</>}\u3002\n <a className=\"dq-alert-link\" href=\"https://platform.deepseek.com/top_up\" target=\"_blank\" rel=\"noreferrer\">\u53BB\u5145\u503C</a>\n </div>\n </div>\n )}\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u8D26\u6237\u4F59\u989D</div>\n {primary !== null ? (\n <div className=\"dq-balance-grid\">\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u5269\u4F59\u4F59\u989D</div>\n <div className=\"dq-stat-value dq-remaining\">\n <span>{fmt(primary.total)} {primary.currency}</span>\n <div className=\"dq-remaining-breakdown\">\n <span>\u5145\u503C\u989D\u5EA6 {fmt(primary.toppedUp)}</span>\n <span className=\"dq-remaining-granted\">\u8D60\u9001\u989D\u5EA6 {fmt(primary.granted)}</span>\n </div>\n </div>\n </div>\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">\u9884\u8BA1\u53EF\u7528</div>\n <div\n className={`dq-stat-value dq-runway${daysLeft !== null && daysLeft < 3 ? ' dq-stat-value--bad' : ''}`}\n title={runwayTitle}\n >\n {daysLeftText}\n </div>\n </div>\n <Stat label=\"\u72B6\u6001\">\n <div className={`dq-stat-value${balance?.isAvailable === false ? ' dq-stat-value--bad' : ' dq-stat-value--ok'}`}>\n {balance?.isAvailable === false ? '\u4E0D\u53EF\u7528' : '\u53EF\u7528'}\n </div>\n </Stat>\n </div>\n ) : loadingBalance ? (\n <BalanceSkeleton />\n ) : (\n <div className=\"dq-empty\">\u8BFB\u4E0D\u5230\u4F59\u989D\u3002\u8BF7\u786E\u8BA4\u300C\u8BBE\u7F6E \u2192 \u6A21\u578B\u300D\u91CC\u5DF2\u586B DEEPSEEK_API_KEY\uFF0C\u7136\u540E\u70B9\u53F3\u4E0A\u89D2\u5237\u65B0\u3002</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u6D88\u8017\u6982\u89C8\uFF08\u8D39\u7528\u4E3A\u4F30\u7B97\uFF09</div>\n {usage !== null ? (\n <div className=\"dq-period-grid\">\n <Period label=\"\u4ECA\u65E5\" period={usage.summary.today} previous={usage.summary.yesterday} compare=\"\u8F83\u6628\u65E5\" />\n <Period label=\"\u672C\u6708\" period={usage.summary.month} previous={usage.summary.lastMonthToDate} compare=\"\u8F83\u4E0A\u6708\u540C\u671F\" />\n <Period\n label=\"\u7D2F\u8BA1\"\n period={{ total: usage.totals.total, cost: usage.totals.cost, calls: usage.totals.calls }}\n />\n </div>\n ) : loadingUsage ? (\n\n <div className=\"dq-period-grid\">\n {[0, 1, 2].map(i => (\n <div key={i} className=\"dq-period\">\n <Skel w={40} h={11} /><Skel w={104} h={24} /><Skel w={132} h={11} />\n </div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u53EF\u7EDF\u8BA1\u7684\u6D88\u8017\u3002</div>\n )}\n {usage !== null && <PricingNote pricing={usage.pricing} />}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">DSH \u7528\u91CF\uFF08tokens\uFF09</div>\n {usage !== null ? (\n <>\n <div className=\"dq-usage-totals\">\n <Stat label=\"\u8F93\u5165\"><div className=\"dq-stat-value\">{fmtCompact(usage.totals.input)}</div></Stat>\n <Stat label=\"\u8F93\u51FA\"><div className=\"dq-stat-value\">{fmtCompact(usage.totals.output)}</div></Stat>\n <Stat label=\"\u7F13\u5B58\u547D\u4E2D\"><div className=\"dq-stat-value\">{fmtCompact(usage.totals.cache)}</div></Stat>\n <Stat label=\"\u6A21\u578B\u8C03\u7528\"><div className=\"dq-stat-value\">{fmtInt(usage.totals.calls)}</div></Stat>\n </div>\n <div className=\"dq-chart-block-head\">\n <div className=\"dq-chart-title\">\n {barMode === 'daily' ? '\u8FD1 30 \u5929 \u00B7 \u9010\u5929\u7528\u91CF' : '\u6309\u5C0F\u65F6\u5206\u5E03\uFF080\u201323 \u70B9\uFF09'}\n {chartPeak > 0 && <span className=\"dq-chart-peak\">\u5CF0\u503C {fmtCompact(chartPeak)} tokens</span>}\n </div>\n <div className=\"dq-chart-controls\">\n <ModelPicker models={modelList} selected={effectiveSelection} colorOf={colorOf} onChange={setSelectedModels} />\n <div className=\"dq-chart-switch\" role=\"tablist\" aria-label=\"\u5207\u6362\u56FE\u8868\u7EF4\u5EA6\">\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={barMode === 'daily'}\n className={`dq-chart-switch-btn${barMode === 'daily' ? ' dq-chart-switch-btn--on' : ''}`}\n onClick={() => setBarMode('daily')}\n >\n \u9010\u5929\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={barMode === 'hourly'}\n className={`dq-chart-switch-btn${barMode === 'hourly' ? ' dq-chart-switch-btn--on' : ''}`}\n onClick={() => setBarMode('hourly')}\n >\n \u9010\u5C0F\u65F6\n </button>\n </div>\n </div>\n </div>\n {grouped.length > 0 ? (\n <>\n <GroupedBars\n series={grouped}\n height={barMode === 'daily' ? 120 : 100}\n labelEvery={barMode === 'daily' ? 5 : 3}\n />\n <div className=\"dq-legend\">\n {grouped.map(s => (\n <span key={s.key} className=\"dq-legend-item\">\n <span className=\"dq-legend-swatch\" style={{ background: s.color }} />\n {s.name}\n </span>\n ))}\n </div>\n </>\n ) : barMode === 'daily' ? (\n <Bars data={dailyBars} height={120} labelEvery={5} />\n ) : (\n <Bars data={hourlyBars} height={100} labelEvery={3} />\n )}\n <div className=\"dq-chart-title\">\u8FD1 12 \u5468 \u00B7 \u6BCF\u65E5\u7528\u91CF\u70ED\u529B\u56FE</div>\n <Heatmap data={usage.heatmap} />\n </>\n ) : loadingUsage ? (\n <UsageSkeleton />\n ) : (\n <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u7528\u91CF\u8BB0\u5F55\u3002\u5728 DSH \u91CC\u8DD1\u4E00\u8F6E\u5BF9\u8BDD\uFF0C\u8FD9\u91CC\u4F1A\u51FA\u73B0\u9010\u5929 / \u9010\u5C0F\u65F6\u7EDF\u8BA1\u4E0E\u8D39\u7528\u4F30\u7B97\u3002</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u9AD8\u5CF0 / \u95F2\u65F6\u5206\u5E03</div>\n {usage !== null ? (\n <PeakCard split={usage.peakSplit} pricing={usage.pricing} currentCost={usage.totals.cost} />\n ) : loadingUsage ? (\n <>\n <div className=\"dq-peak-track\" />\n <div className=\"dq-peak-figures\"><Skel w={120} h={11} /><Skel w={96} h={20} /></div>\n </>\n ) : (\n <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u53EF\u6309\u65F6\u6BB5\u5F52\u7C7B\u7684\u7528\u91CF\u3002</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u7F13\u5B58\u547D\u4E2D\u4E0E\u8282\u7701</div>\n {usage !== null ? (\n <CacheCard totals={usage.totals} />\n ) : loadingUsage ? (\n <div className=\"dq-cache-figures\">\n {[60, 96, 72].map((w, i) => (\n <div key={i} className=\"dq-stat\"><Skel w={w} h={11} /><Skel w={72} h={20} /></div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">\u8FD8\u6CA1\u6709 prompt token \u53EF\u7EDF\u8BA1\u7F13\u5B58\u547D\u4E2D\u3002</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u6A21\u578B\u6210\u672C\u6392\u884C</div>\n {usage !== null ? (\n <ModelRanking models={modelList} totalCost={modelCostTotal} colorOf={colorOf} />\n ) : loadingUsage ? (\n <div className=\"dq-rank\">\n {[0, 1].map(i => (\n <div key={i} className=\"dq-rank-row\">\n <Skel w={148} h={13} />\n <div className=\"dq-rank-track\" />\n <Skel w={230} h={11} />\n </div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u53EF\u5F52\u7C7B\u7684\u6A21\u578B\u7528\u91CF\u3002</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u4F1A\u8BDD\u6210\u672C\u6392\u884C</div>\n {usage !== null ? (\n <SessionRanking sessions={usage.sessions} count={usage.sessionCount} totalCost={usage.totals.cost} />\n ) : loadingUsage ? (\n <div className=\"dq-sessions\">\n {[0, 1, 2].map(i => (\n <div key={i} className=\"dq-session\">\n <Skel w={200} h={13} />\n <div className=\"dq-session-track\" />\n <Skel w={250} h={11} />\n </div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">\u8FD8\u6CA1\u6709\u4EA7\u751F\u8D39\u7528\u7684\u4F1A\u8BDD\u3002</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u5B98\u65B9\u5E73\u53F0</div>\n <div className=\"dq-links\">\n <Link href=\"https://platform.deepseek.com/usage\">\u67E5\u770B\u989D\u5EA6 / \u7528\u91CF</Link>\n <Link href=\"https://platform.deepseek.com/api_keys\">\u751F\u6210 API Key</Link>\n <Link href=\"https://status.deepseek.com\">\u670D\u52A1\u72B6\u6001</Link>\n </div>\n </div>\n\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">\u8BBE\u7F6E</div>\n <label className=\"dq-toggle\">\n <input type=\"checkbox\" checked={widgetOn} onChange={toggle} />\n <span>\u663E\u793A\u53F3\u4E0B\u89D2\u60AC\u6D6E\u989D\u5EA6\u7A97\u53E3</span>\n </label>\n <div className=\"dq-setting\">\n <label className=\"dq-setting-label\" htmlFor=\"dq-low-balance\">\u4F59\u989D\u9884\u8B66\u7EBF</label>\n <div className=\"dq-setting-control\">\n <input\n id=\"dq-low-balance\"\n className=\"dq-number\"\n type=\"number\"\n min={0}\n step={1}\n value={lowBalance}\n onChange={e => changeLowBalance(Math.max(0, Number(e.target.value) || 0))}\n />\n <span className=\"dq-setting-hint\">\n {lowBalance > 0\n ? `\u4F59\u989D\u4F4E\u4E8E ${fmt(lowBalance)} ${primary?.currency ?? 'CNY'} \u65F6\uFF0C\u8FD9\u91CC\u548C\u60AC\u6D6E\u7A97\u90FD\u4F1A\u8F6C\u4E3A\u8B66\u793A\u8272\u3002\u586B 0 \u5173\u95ED\u3002`\n : '\u5DF2\u5173\u95ED\u4F59\u989D\u9884\u8B66\u3002\u586B\u4E00\u4E2A\u5927\u4E8E 0 \u7684\u6570\u5F00\u542F\u3002'}\n </span>\n </div>\n </div>\n </div>\n </div>\n )\n}\n", "/**\n * Package-local TTL caches shared by the widget, the dashboard, and every\n * tab switch. Cached values outlive the TTL: `get()` still returns them\n * (marked by `at`) so a reopening tab can render instantly and refresh in\n * the background, while `getFresh()` is the cache-aware fetch path.\n *\n * When a `storageKey` is given, every `put()` also mirrors the entry to\n * localStorage so a page refresh keeps the instant first paint (the data\n * shown is the last known good value; a background refresh updates it).\n */\n\n/** Bump whenever the persisted shape changes in a way `isUsable` cannot catch. */\nconst LS_VERSION = 2\n\nexport interface CacheHit<T> {\n data: T\n at: number\n}\n\nexport interface ResourceCache<T> {\n /** Last cached value even when stale; null when never cached. */\n get(): CacheHit<T> | null\n /** Value only when it is still within the TTL. */\n getFresh(): T | null\n put(data: T): void\n}\n\n/**\n * Read a persisted entry, but only trust it if it still matches the shape the\n * current code reads. A payload written by an older build can be missing fields\n * this one dereferences, and because the first render is seeded straight from\n * here, an unchecked stale entry crashes the view \u2014 for the user it looks like\n * a blank tab that only a fresh browser profile fixes.\n */\nfunction loadPersisted<T>(storageKey: string, isUsable?: (data: T) => boolean): CacheHit<T> | null {\n if (typeof localStorage === 'undefined') return null\n const key = `${storageKey}:v${LS_VERSION}`\n try {\n const raw = localStorage.getItem(key)\n if (raw === null) return null\n const parsed = JSON.parse(raw) as { data?: T; at?: number }\n if (parsed.data === undefined || typeof parsed.at !== 'number') return null\n if (isUsable !== undefined && !isUsable(parsed.data)) {\n localStorage.removeItem(key)\n return null\n }\n return { data: parsed.data, at: parsed.at }\n } catch {\n return null\n }\n}\n\n/** Drop entries this key wrote under earlier versions; nothing reads them again. */\nfunction pruneOldVersions(storageKey: string): void {\n if (typeof localStorage === 'undefined') return\n try {\n const current = `${storageKey}:v${LS_VERSION}`\n for (const key of Object.keys(localStorage)) {\n if (key.startsWith(`${storageKey}:v`) && key !== current) localStorage.removeItem(key)\n }\n } catch {\n // Leaving stale keys behind is harmless; they are never read.\n }\n}\n\nfunction persist<T>(storageKey: string, hit: CacheHit<T>): void {\n if (typeof localStorage === 'undefined') return\n try {\n localStorage.setItem(`${storageKey}:v${LS_VERSION}`, JSON.stringify(hit))\n } catch {\n // Quota / private-mode failures must never break the in-memory path.\n }\n}\n\nexport function createCache<T>(ttlMs: number, storageKey?: string, isUsable?: (data: T) => boolean): ResourceCache<T> {\n if (storageKey !== undefined) pruneOldVersions(storageKey)\n let hit: CacheHit<T> | null = storageKey === undefined ? null : loadPersisted<T>(storageKey, isUsable)\n return {\n get: () => hit,\n getFresh: () => (hit !== null && Date.now() - hit.at < ttlMs ? hit.data : null),\n put: (data) => {\n hit = { data, at: Date.now() }\n if (storageKey !== undefined) persist(storageKey, hit)\n },\n }\n}\n", "/**\n * Same-origin fetchers for the host half's JSON API, backed by package-local\n * TTL caches (see ./cache.ts). A fresh cache hit resolves without any network\n * work, so tab switches render instantly; `force` bypasses both the memory\n * cache and the HTTP cache (fetch cache: 'no-store') and asks the host to\n * bypass its own memo via `?refresh=1`.\n */\nimport { createCache } from './cache.ts'\nimport type { BalanceResponse, UsageResponse } from '../contract.ts'\n\n/** Mirror the host memos: balance 60s, usage 5min. */\nconst BALANCE_TTL_MS = 60_000\nconst USAGE_TTL_MS = 5 * 60_000\n\nasync function getJson<T>(path: string, cache: RequestCache): Promise<T> {\n const res = await fetch(path, { headers: { accept: 'application/json' }, cache })\n if (!res.ok) {\n return { ok: false, error: `HTTP ${res.status}` } as unknown as T\n }\n return res.json() as Promise<T>\n}\n\n/**\n * Every field the UI dereferences off a cached payload. A persisted entry that\n * predates one of them would otherwise be rendered as if it were current and\n * take the whole view down; listing them here keeps that failure impossible\n * instead of merely unlikely. Add a line whenever the UI starts reading a new\n * top-level field.\n */\nconst usageIsUsable = (res: UsageResponse): boolean => {\n if (res.ok !== true) return false\n const data = res.data\n return data !== undefined\n && Array.isArray(data.daily) && Array.isArray(data.hourly) && Array.isArray(data.heatmap)\n && Array.isArray(data.models) && Array.isArray(data.sessions)\n && typeof data.sessionCount === 'number'\n && data.totals !== undefined && typeof data.totals.cacheSavings === 'number'\n && data.summary?.today !== undefined\n && Array.isArray(data.pricing?.tiers)\n && data.peakSplit?.peak !== undefined\n}\n\nconst balanceIsUsable = (res: BalanceResponse): boolean =>\n res.ok === true && Array.isArray(res.data?.balances)\n\nconst balanceCache = createCache<BalanceResponse>(BALANCE_TTL_MS, 'dsh-usage-dashboard:balance', balanceIsUsable)\nconst usageCache = createCache<UsageResponse>(USAGE_TTL_MS, 'dsh-usage-dashboard:usage', usageIsUsable)\n\n/** Last cached value (possibly stale), for an instant first render. */\nexport const getCachedBalance = (): BalanceResponse | null => balanceCache.get()?.data ?? null\nexport const getCachedUsage = (): UsageResponse | null => usageCache.get()?.data ?? null\n/** When the cached usage was fetched, so a consumer can say how old it is. */\nexport const getCachedUsageAt = (): number | null => usageCache.get()?.at ?? null\n\n/**\n * Notified whenever usage is (re)fetched. The floating widget reads usage\n * straight from this cache rather than fetching on its own: aggregating every\n * session log takes seconds, and a background widget must not pay that\n * repeatedly. It subscribes here so it still updates when the dashboard \u2014 or\n * its own refresh button \u2014 brings fresh data in.\n */\nconst usageListeners = new Set<() => void>()\n\nexport const subscribeUsage = (fn: () => void): (() => void) => {\n usageListeners.add(fn)\n return () => {\n usageListeners.delete(fn)\n }\n}\n\nexport async function fetchBalance(force = false): Promise<BalanceResponse> {\n if (!force) {\n const hit = balanceCache.getFresh()\n if (hit !== null) return hit\n }\n const suffix = force ? '?refresh=1' : ''\n const res = await getJson<BalanceResponse>(`/api/dsh-usage-dashboard/balance${suffix}`, force ? 'no-store' : 'default')\n if (res.ok) balanceCache.put(res)\n return res\n}\n\nexport async function fetchUsage(force = false): Promise<UsageResponse> {\n if (!force) {\n const hit = usageCache.getFresh()\n if (hit !== null) return hit\n }\n const suffix = force ? '?refresh=1' : ''\n const res = await getJson<UsageResponse>(`/api/dsh-usage-dashboard/usage${suffix}`, force ? 'no-store' : 'default')\n if (res.ok) {\n usageCache.put(res)\n for (const listener of [...usageListeners]) listener()\n }\n return res\n}\n", "/** Dependency-free bar chart and heatmap primitives. */\nimport { useRef, useState, type MutableRefObject, type PointerEvent as ReactPointerEvent, type ReactElement } from 'react'\n\nexport interface BarDatum {\n label: string\n value: number\n /** Tooltip text, composed as `heading \u00B7 row \u00B7 row`; each ` \u00B7 ` segment is\n * rendered on its own line, the first as the heading. */\n title?: string\n}\n\ninterface TipState {\n x: number\n y: number\n lines: string[]\n}\n\n/**\n * Cursor-following tooltip shared by every chart. The native `title` attribute\n * this replaces waited about a second, could not be styled to match the shell,\n * and never appeared on touch.\n */\nfunction useChartTip(): {\n wrapRef: MutableRefObject<HTMLDivElement | null>\n tip: TipState | null\n show: (e: ReactPointerEvent<HTMLElement>, text: string | undefined) => void\n hide: () => void\n} {\n const wrapRef = useRef<HTMLDivElement | null>(null)\n const [tip, setTip] = useState<TipState | null>(null)\n const show = (e: ReactPointerEvent<HTMLElement>, text: string | undefined): void => {\n const wrap = wrapRef.current\n if (text === undefined || text === '' || wrap === null) return\n const rect = wrap.getBoundingClientRect()\n // Keep the (centred) bubble inside the chart's own box.\n const x = Math.min(Math.max(e.clientX - rect.left, 70), Math.max(rect.width - 70, 70))\n setTip({ x, y: e.clientY - rect.top, lines: text.split(' \u00B7 ') })\n }\n return { wrapRef, tip, show, hide: () => setTip(null) }\n}\n\nfunction ChartTip(props: { tip: TipState | null }): ReactElement | null {\n const { tip } = props\n if (tip === null) return null\n const [head, ...rows] = tip.lines\n return (\n <div className=\"dq-tip\" style={{ left: `${tip.x}px`, top: `${tip.y}px` }} role=\"tooltip\">\n <div className=\"dq-tip-head\">{head}</div>\n {rows.map((row, i) => <div key={i} className=\"dq-tip-row\">{row}</div>)}\n </div>\n )\n}\n\n/** Color palette for per-model grouped bars, cycled by model order. */\nexport const MODEL_COLORS = ['#4176e6', '#2da44e', '#e16f24', '#8250df', '#bf8700', '#cf222e', '#1f883d', '#0969da']\n\nexport function Bars(props: { data: BarDatum[]; height?: number; labelEvery?: number }): ReactElement {\n const { data, height = 120, labelEvery = 1 } = props\n const { wrapRef, tip, show, hide } = useChartTip()\n let max = 0\n for (const datum of data) if (datum.value > max) max = datum.value\n const scale = max > 0 ? max : 1\n return (\n <div className=\"dq-chart-wrap\" ref={wrapRef} onPointerLeave={hide}>\n <div className=\"dq-bars\" style={{ height: `${height + 18}px` }}>\n {data.map((datum, i) => {\n const h = Math.max(1, Math.round((datum.value / scale) * height))\n const text = datum.title ?? `${datum.label}: ${datum.value.toLocaleString()}`\n return (\n <div\n key={i}\n className=\"dq-bar-col\"\n aria-label={text}\n onPointerMove={e => show(e, text)}\n >\n <div className=\"dq-bar\" style={{ height: `${h}px` }} />\n <div className=\"dq-bar-label\" style={{ visibility: i % labelEvery === 0 ? 'visible' : 'hidden' }}>{datum.label}</div>\n </div>\n )\n })}\n </div>\n <ChartTip tip={tip} />\n </div>\n )\n}\n\nexport interface HeatDatum {\n date: string\n total: number\n cost: number\n calls: number\n}\n\n/** Multi-series bar chart: one bar per series, side by side, per slot. */\nexport function GroupedBars(props: {\n series: Array<{ key: string; color: string; bars: BarDatum[] }>\n height?: number\n labelEvery?: number\n}): ReactElement {\n const { series, height = 120, labelEvery = 1 } = props\n const { wrapRef, tip, show, hide } = useChartTip()\n const count = series.length > 0 ? series[0].bars.length : 0\n let max = 0\n for (const s of series) for (const datum of s.bars) if (datum.value > max) max = datum.value\n const scale = max > 0 ? max : 1\n return (\n <div className=\"dq-chart-wrap\" ref={wrapRef} onPointerLeave={hide}>\n <div className=\"dq-bars\" style={{ height: `${height + 18}px` }}>\n {Array.from({ length: count }, (_, i) => (\n <div key={i} className=\"dq-bar-col\">\n <div className=\"dq-bar-group\">\n {series.map(s => {\n const datum = s.bars[i]\n const h = Math.max(1, Math.round((datum.value / scale) * height))\n const text = datum.title ?? `${s.key}: ${datum.value.toLocaleString()}`\n return (\n <div\n key={s.key}\n className=\"dq-bar\"\n style={{ height: `${h}px`, background: s.color }}\n aria-label={text}\n onPointerMove={e => show(e, text)}\n />\n )\n })}\n </div>\n <div className=\"dq-bar-label\" style={{ visibility: i % labelEvery === 0 ? 'visible' : 'hidden' }}>\n {series[0].bars[i].label}\n </div>\n </div>\n ))}\n </div>\n <ChartTip tip={tip} />\n </div>\n )\n}\n\nfunction heatColor(level: number): string {\n if (level <= 0) return 'rgba(120,130,150,0.12)'\n if (level === 1) return 'rgba(65,118,230,0.25)'\n if (level === 2) return 'rgba(65,118,230,0.5)'\n if (level === 3) return 'rgba(65,118,230,0.75)'\n return 'rgba(65,118,230,1)'\n}\n\n/** Row 0 is Sunday, matching Date#getDay(); only alternate rows are labelled\n * so the column stays readable at 12px cells. */\nconst DOW_LABELS = ['', '\u4E00', '', '\u4E09', '', '\u4E94', '']\n\n/**\n * Calendar heatmap with the axes it was missing: weekday labels down the left,\n * month labels along the top (drawn where a column starts a new month) and a\n * \u5C11\u2192\u591A scale legend, so a cell can actually be located in time.\n */\nexport function Heatmap(props: { data: HeatDatum[] }): ReactElement {\n const { data } = props\n const { wrapRef, tip, show, hide } = useChartTip()\n let max = 0\n for (const datum of data) if (datum.total > max) max = datum.total\n let firstDow = 0\n if (data.length > 0) {\n const dt = new Date(`${data[0].date}T00:00:00`)\n firstDow = Number.isNaN(dt.getTime()) ? 0 : dt.getDay()\n }\n const cells: Array<HeatDatum | null> = []\n for (let i = 0; i < firstDow; i++) cells.push(null)\n for (const datum of data) cells.push(datum)\n while (cells.length % 7 !== 0) cells.push(null)\n\n const weeks: Array<Array<HeatDatum | null>> = []\n for (let i = 0; i < cells.length; i += 7) weeks.push(cells.slice(i, i + 7))\n\n // Label a column with its month when it is the first column of that month.\n let lastMonth = ''\n const monthLabels = weeks.map(week => {\n const first = week.find(cell => cell !== null)\n if (first === undefined || first === null) return ''\n const month = first.date.slice(0, 7)\n if (month === lastMonth) return ''\n lastMonth = month\n return `${Number(first.date.slice(5, 7))}\u6708`\n })\n\n const levelOf = (total: number): number => {\n if (total <= 0) return 0\n const r = max > 0 ? total / max : 0\n return r < 0.25 ? 1 : r < 0.5 ? 2 : r < 0.75 ? 3 : 4\n }\n\n return (\n <div className=\"dq-heat dq-chart-wrap\" ref={wrapRef} onPointerLeave={hide}>\n <div className=\"dq-heat-grid\">\n <div className=\"dq-heat-dows\" aria-hidden=\"true\">\n {DOW_LABELS.map((label, i) => <div key={i} className=\"dq-heat-dow\">{label}</div>)}\n </div>\n <div className=\"dq-heat-cols\">\n <div className=\"dq-heat-months\" aria-hidden=\"true\">\n {monthLabels.map((label, i) => <div key={i} className=\"dq-heat-month\">{label}</div>)}\n </div>\n <div className=\"dq-heatmap\">\n {weeks.map((week, w) => (\n <div key={w} className=\"dq-heat-week\">\n {week.map((datum, d) => {\n if (datum === null) return <div key={d} className=\"dq-heat-cell dq-heat-cell--pad\" />\n const text = `${datum.date} \u00B7 ${datum.total.toLocaleString()} tokens \u00B7 \u00A5${datum.cost.toFixed(2)} \u00B7 ${datum.calls} \u6B21\u8C03\u7528`\n return (\n <div\n key={d}\n className=\"dq-heat-cell\"\n style={{ background: heatColor(levelOf(datum.total)) }}\n aria-label={text}\n onPointerMove={e => show(e, text)}\n />\n )\n })}\n </div>\n ))}\n </div>\n </div>\n </div>\n <ChartTip tip={tip} />\n <div className=\"dq-heat-scale\">\n <span>\u5C11</span>\n {[0, 1, 2, 3, 4].map(level => (\n <span key={level} className=\"dq-heat-key\" style={{ background: heatColor(level) }} />\n ))}\n <span>\u591A</span>\n </div>\n </div>\n )\n}\n\nexport const fmt = (v: string | number): string => {\n const n = Number(v)\n if (!Number.isFinite(n)) return String(v)\n return n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })\n}\n\nexport const fmtInt = (v: number | undefined): string => Math.round(Number(v) || 0).toLocaleString()\n\nexport const fmtCompact = (v: number | undefined): string => {\n const n = Number(v) || 0\n if (n >= 100_000_000) return `${(n / 100_000_000).toFixed(1)}\u4EBF`\n if (n >= 10_000) return `${(n / 10_000).toFixed(1)}\u4E07`\n return Math.round(n).toLocaleString()\n}\n", "/**\n * localStorage-backed user preferences for the plugin.\n *\n * Everything the user deliberately sets (widget visibility, the corner it was\n * dragged to, whether it is collapsed) belongs here so a page refresh does not\n * throw the choice away. Keys share one prefix and carry a version suffix so\n * the shape can evolve without reading back stale values.\n *\n * Every read is validated by the caller's guard: a corrupted or hand-edited\n * entry falls back instead of poisoning the UI.\n */\n\nconst PREFIX = 'dsh-usage-dashboard:pref:'\nconst VERSION = 1\n\nconst keyOf = (key: string): string => `${PREFIX}${key}:v${VERSION}`\n\nexport function loadPref<T>(key: string, isValid: (value: unknown) => boolean, fallback: T): T {\n if (typeof localStorage === 'undefined') return fallback\n try {\n const raw = localStorage.getItem(keyOf(key))\n if (raw === null) return fallback\n const parsed = JSON.parse(raw) as unknown\n return isValid(parsed) ? (parsed as T) : fallback\n } catch {\n return fallback\n }\n}\n\nexport function savePref(key: string, value: unknown): void {\n if (typeof localStorage === 'undefined') return\n try {\n localStorage.setItem(keyOf(key), JSON.stringify(value))\n } catch {\n // Quota / private-mode failures must never break the UI.\n }\n}\n\nexport const isBoolean = (value: unknown): boolean => typeof value === 'boolean'\n", "/**\n * Package-local stores for settings both surfaces read: the dashboard writes\n * them, the floating widget reacts. Every value is persisted (see ./prefs.ts),\n * so a choice survives a page refresh.\n */\nimport { isBoolean, loadPref, savePref } from './prefs.ts'\n\nexport interface Store<T> {\n get(): T\n set(value: T): void\n subscribe(fn: () => void): () => void\n}\n\nfunction createStore<T>(key: string, isValid: (value: unknown) => boolean, fallback: T): Store<T> {\n let current = loadPref<T>(key, isValid, fallback)\n const listeners = new Set<() => void>()\n return {\n get: () => current,\n set: (value: T) => {\n current = value\n savePref(key, value)\n for (const listener of [...listeners]) listener()\n },\n subscribe: (fn: () => void) => {\n listeners.add(fn)\n return () => {\n listeners.delete(fn)\n }\n },\n }\n}\n\nconst isThreshold = (value: unknown): boolean =>\n typeof value === 'number' && Number.isFinite(value) && value >= 0\n\n/** Whether the floating balance widget is shown. */\nexport const widgetVisibleStore = createStore<boolean>('widget.visible', isBoolean, true)\n\n/** Balance (in the account's own currency) below which both surfaces warn.\n * 0 turns the warning off. */\nexport const lowBalanceStore = createStore<number>('alert.lowBalance', isThreshold, 10)\n", "/** All plugin styles in one sheet, injected once at client load. */\n\nexport const css = `\n.dsh-quota-root{position:absolute;right:16px;bottom:16px;z-index:2147483000;pointer-events:auto;font-family:system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;font-size:13px;line-height:1.45;color:var(--dsw-alias-label-primary,#1f2328);transition:left .28s cubic-bezier(.22,1,.36,1),top .28s cubic-bezier(.22,1,.36,1)}\n.dsh-quota-root.dsh-quota-dragging{transition:none}\n.dsh-quota-card,.dsh-quota-card *{box-sizing:border-box}\n.dsh-quota-card{background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);padding:12px 14px;min-width:208px;max-width:270px;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none}\n.dsh-quota-root.dsh-quota-dragging .dsh-quota-card{cursor:grabbing;box-shadow:0 12px 32px rgba(0,0,0,.28)}\n.dsh-quota-header{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px;min-width:0}\n.dsh-quota-title{font-weight:600;font-size:13px;color:var(--dsw-alias-label-primary,#1f2328);display:flex;align-items:center;gap:6px;min-width:0;overflow:hidden}\n.dsh-quota-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dsh-quota-grip{color:var(--dsw-alias-label-secondary,#59636e);opacity:.7;font-size:11px;letter-spacing:0;cursor:grab;flex:none}\n.dsh-quota-dot{width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-state-success-primary,#2da44e);flex:none}\n.dsh-quota-dot--error{background:var(--dsw-alias-state-error-primary,#cf222e)}\n.dsh-quota-dot--warn{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dsh-quota-total--low{color:var(--dsw-alias-state-warning-primary,#9a6700)!important}\n.dsh-quota-dot--idle{background:var(--dsw-alias-label-secondary,#59636e);opacity:.6}\n.dsh-quota-collapsed-total{font-weight:700;font-size:13px;color:var(--dsw-alias-brand-primary,#0969da);flex:none;font-variant-numeric:tabular-nums}\n.dsh-quota-actions{display:flex;gap:2px;flex:none}\n.dsh-quota-btn{border:none;background:transparent;cursor:pointer;color:var(--dsw-alias-label-secondary,#59636e);padding:3px 7px;border-radius:6px;font-size:13px;line-height:1}\n.dsh-quota-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06));color:var(--dsw-alias-label-primary,#1f2328)}\n.dsh-quota-btn:active:not(:disabled){transform:scale(.92)}\n.dsh-quota-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dsh-quota-btn:disabled{opacity:.5;cursor:default}\n.dsh-quota-body{color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-remaining-label{font-size:11px;color:var(--dsw-alias-label-tertiary,#59636e);margin-bottom:2px}\n.dsh-quota-total{font-size:24px;font-weight:700;color:var(--dsw-alias-label-primary,#1f2328);letter-spacing:-.02em;font-variant-numeric:tabular-nums}\n.dsh-quota-currency{font-size:14px;font-weight:600;margin-left:3px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-row{display:flex;justify-content:space-between;gap:12px;margin-top:6px;font-size:12px}\n.dsh-quota-label{color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-value{color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dsh-quota-error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-balance{display:flex;flex-direction:column;gap:16px;padding:20px 24px 48px;max-width:860px;margin:0 auto;font-family:system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;font-size:13px;line-height:1.5;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-card{background:var(--dsw-alias-bg-layer-1,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08));border-radius:12px;padding:16px}\n.dq-card-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e);margin:0 0 12px;letter-spacing:.02em}\n.dq-balance-grid{display:flex;flex-wrap:wrap;gap:12px 24px}\n.dq-stat{min-width:110px}\n.dq-stat-label{font-size:11px;color:var(--dsw-alias-label-tertiary,#59636e);margin-bottom:2px}\n.dq-stat-value{font-size:18px;font-weight:650;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-stat-value--ok{color:var(--dsw-alias-state-success-primary,#2da44e)}\n.dq-stat-value--bad{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-runway{cursor:help;text-decoration:underline dotted var(--dsw-alias-border-l2,rgba(0,0,0,.25));text-underline-offset:4px}\n.dq-remaining{position:relative;cursor:help}\n.dq-remaining-breakdown{display:none;position:absolute;top:calc(100% + 6px);left:0;z-index:20;flex-direction:column;gap:4px;padding:8px 10px;background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.15);white-space:nowrap;font-size:12px;font-weight:500;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-remaining:hover .dq-remaining-breakdown{display:flex}\n.dq-remaining-granted{color:var(--dsw-alias-label-tertiary,#59636e);font-weight:400;font-size:11px}\n.dq-period-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}\n@media (max-width:620px){.dq-period-grid{grid-template-columns:1fr}}\n.dq-period{background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.06));border-radius:10px;padding:12px 14px;min-width:0}\n.dq-period-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:4px}\n.dq-period-label{font-size:11px;color:var(--dsw-alias-label-tertiary,#59636e)}\n.dq-period-cost{font-size:22px;font-weight:680;letter-spacing:-.01em;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;line-height:1.25}\n.dq-period-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);margin-top:2px;font-variant-numeric:tabular-nums;line-height:1.45}\n.dq-delta{display:inline-flex;align-items:center;gap:3px;font-size:11px;font-weight:600;padding:1px 6px;border-radius:999px;white-space:nowrap;cursor:help;font-variant-numeric:tabular-nums}\n.dq-delta--up{color:var(--dsw-alias-state-warning-primary,#9a6700);background:rgba(191,135,0,.14)}\n.dq-delta--down{color:var(--dsw-alias-state-success-primary,#1a7f37);background:rgba(45,164,78,.14)}\n.dq-delta--flat,.dq-delta--new{color:var(--dsw-alias-label-tertiary,#59636e);background:rgba(120,130,150,.14);font-weight:500}\n.dq-delta-label{font-weight:400;opacity:.8}\n.dq-pricing{margin-top:12px;border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08));padding-top:10px}\n.dq-pricing-summary{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);cursor:pointer;list-style:none;width:fit-content;border-radius:6px;padding:2px 4px;margin-left:-4px}\n.dq-pricing-summary::-webkit-details-marker{display:none}\n.dq-pricing-summary::before{content:\"\u25B8\";display:inline-block;font-size:10px;opacity:.7;transition:transform .15s ease}\n.dq-pricing[open] .dq-pricing-summary::before{transform:rotate(90deg)}\n.dq-pricing-summary:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-pricing-summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-pricing-now{font-size:11px;font-weight:600;padding:1px 7px;border-radius:999px;color:var(--dsw-alias-label-tertiary,#59636e);background:rgba(120,130,150,.14)}\n.dq-pricing-now--peak{color:var(--dsw-alias-state-warning-primary,#9a6700);background:rgba(191,135,0,.14)}\n.dq-pricing-body{margin-top:10px;overflow-x:auto}\n.dq-pricing-table{border-collapse:collapse;font-size:11.5px;font-variant-numeric:tabular-nums;min-width:100%}\n.dq-pricing-table th{text-align:left;font-weight:500;color:var(--dsw-alias-label-tertiary,#59636e);padding:4px 12px 4px 0;white-space:nowrap;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08))}\n.dq-pricing-table td{padding:4px 12px 4px 0;color:var(--dsw-alias-label-primary,#1f2328);white-space:nowrap;vertical-align:top}\n.dq-pricing-table tbody tr+tr td{border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.05))}\n.dq-pricing-foot{margin:8px 0 0;font-size:11.5px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-peak-track{height:8px;border-radius:999px;background:var(--dsw-alias-state-success-primary,#2da44e);opacity:.85;overflow:hidden}\n.dq-peak-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-warning-primary,#bf8700);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-peak-legend{display:flex;flex-wrap:wrap;gap:6px 20px;margin-top:8px;font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-peak-legend span{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch--peak{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-legend-swatch--offpeak{background:var(--dsw-alias-state-success-primary,#2da44e);opacity:.85}\n.dq-peak-figures{display:flex;flex-wrap:wrap;gap:12px 32px;margin-top:14px}\n.dq-peak-delta{font-size:11px;font-weight:500;margin-left:8px;color:var(--dsw-alias-state-warning-primary,#9a6700)}\n.dq-peak-delta--save{color:var(--dsw-alias-state-success-primary,#1a7f37)}\n.dq-peak-foot{margin:10px 0 0;font-size:11.5px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-cache-figures{display:flex;flex-wrap:wrap;gap:12px 32px;margin-bottom:12px}\n.dq-muted-value{color:var(--dsw-alias-label-secondary,#59636e)!important;font-weight:550}\n.dq-stat-value--warn{color:var(--dsw-alias-state-warning-primary,#9a6700)}\n.dq-cache-track{height:8px;border-radius:999px;background:var(--dsw-alias-state-warning-primary,#bf8700);overflow:hidden}\n.dq-cache-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-success-primary,#2da44e);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-cache-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin-top:8px;font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-cache-legend span{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch--hit{background:var(--dsw-alias-state-success-primary,#2da44e)}\n.dq-legend-swatch--miss{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-cache-foot{margin:10px 0 0;font-size:11.5px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-sessions{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:14px}\n.dq-session{display:flex;flex-direction:column;gap:5px;min-width:0}\n.dq-session-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}\n.dq-session-title{font-size:13px;font-weight:550;color:var(--dsw-alias-label-primary,#1f2328);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-session-cost{font-size:14px;font-weight:650;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;flex:none}\n.dq-session-track{height:6px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.12));overflow:hidden}\n.dq-session-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-business-primary,#4176e6);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-session-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;line-height:1.5}\n.dq-session-foot{margin:12px 0 0;font-size:11.5px;color:var(--dsw-alias-label-tertiary,#59636e)}\n.dq-rank{display:flex;flex-direction:column;gap:14px}\n.dq-rank-row{display:flex;flex-direction:column;gap:5px;min-width:0}\n.dq-rank-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}\n.dq-rank-name{display:inline-flex;align-items:center;gap:7px;font-size:13px;font-weight:550;color:var(--dsw-alias-label-primary,#1f2328);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-rank-cost{display:inline-flex;align-items:baseline;gap:8px;font-size:14px;font-weight:650;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;flex:none}\n.dq-rank-share{font-size:11px;font-weight:500;color:var(--dsw-alias-label-tertiary,#59636e);min-width:30px;text-align:right}\n.dq-rank-track{height:6px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.12));overflow:hidden}\n.dq-rank-fill{height:100%;border-radius:999px;transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-rank-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;line-height:1.5}\n.dq-alert{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border-radius:10px;font-size:12.5px;line-height:1.6;color:var(--dsw-alias-state-warning-primary,#7a5200);background:rgba(191,135,0,.12);border:1px solid rgba(191,135,0,.35)}\n.dq-alert-icon{flex:none;width:18px;height:18px;border-radius:50%;background:var(--dsw-alias-state-warning-primary,#bf8700);color:#fff;font-weight:700;font-size:12px;line-height:18px;text-align:center}\n.dq-alert strong{font-weight:650}\n.dq-alert-link{margin-left:8px;color:inherit;text-decoration:underline;text-underline-offset:2px;white-space:nowrap}\n.dq-setting{display:flex;align-items:flex-start;gap:12px;margin-top:14px;padding-top:14px;border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08))}\n.dq-setting-label{font-size:13px;color:var(--dsw-alias-label-primary,#1f2328);padding-top:6px;flex:none}\n.dq-setting-control{display:flex;align-items:center;gap:10px;flex-wrap:wrap;min-width:0}\n.dq-setting-hint{font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);line-height:1.5}\n.dq-number{width:82px;padding:5px 8px;font-size:13px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.16));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-number:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px;border-color:transparent}\n.dq-links{display:flex;flex-wrap:wrap;gap:8px}\n.dq-link{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));border-radius:8px;background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-state-business-primary,#0969da);text-decoration:none;font-size:13px;font-weight:500;cursor:pointer}\n.dq-link:hover{border-color:var(--dsw-alias-state-business-primary,#0969da);background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}\n.dq-toggle{display:flex;align-items:center;gap:10px;cursor:pointer;font-size:13px}\n.dq-toggle input{width:16px;height:16px;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer}\n.dq-toggle input:focus-visible,.dq-model-item input:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-link:focus-visible,.dq-model-btn:focus-visible,.dq-chart-switch-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-usage-totals{display:flex;flex-wrap:wrap;gap:12px 24px;margin-bottom:16px}\n.dq-chart-peak{margin-left:10px;font-size:11px;font-weight:400;color:var(--dsw-alias-label-tertiary,#59636e);font-variant-numeric:tabular-nums}\n.dq-chart-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e);margin:18px 0 8px}\n.dq-chart-title:first-of-type{margin-top:0}\n.dq-chart-block-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:18px 0 8px}\n.dq-chart-block-head .dq-chart-title{margin:0}\n.dq-chart-controls{display:flex;align-items:center;gap:8px;flex:none}\n.dq-model-picker{position:relative}\n.dq-model-btn{border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:4px 10px;font-size:12px;cursor:pointer;display:inline-flex;align-items:center;gap:6px}\n.dq-model-btn:hover{border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-model-btn::after{content:\"\u25BE\";font-size:10px;opacity:.7}\n.dq-model-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;min-width:190px;max-height:280px;overflow-y:auto;background:var(--dsw-alias-bg-overlay,#fff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.16);padding:6px;display:flex;flex-direction:column;gap:2px}\n.dq-model-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;font-size:12px;cursor:pointer;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-model-item:hover{background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06))}\n.dq-model-item input{width:14px;height:14px;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer;flex:none}\n.dq-model-item span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-model-item--all{border-bottom:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08));padding-bottom:8px;margin-bottom:2px;border-radius:6px}\n.dq-model-tag{color:var(--dsw-alias-label-tertiary,#59636e);font-size:11px;flex:none}\n.dq-bar-group{display:flex;align-items:flex-end;gap:2px;height:100%;width:100%}\n.dq-bar-group .dq-bar{flex:1 1 0;min-width:0}\n.dq-legend{display:flex;flex-wrap:wrap;gap:6px 14px;margin-top:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-legend-item{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch{width:10px;height:10px;border-radius:3px;flex:none}\n.dq-chart-switch{display:inline-flex;align-items:center;gap:2px;padding:2px;background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06));border-radius:999px;flex:none}\n.dq-chart-switch-btn{border:none;background:transparent;color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;line-height:1;padding:5px 12px;border-radius:999px;cursor:pointer;transition:background .15s ease,color .15s ease}\n.dq-chart-switch-btn:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-chart-switch-btn--on{background:var(--dsw-alias-bg-overlay,#fff);color:var(--dsw-alias-label-primary,#1f2328);box-shadow:0 1px 3px rgba(0,0,0,.14)}\n.dq-chart-wrap{position:relative}\n.dq-tip{position:absolute;transform:translate(-50%,14px);z-index:40;pointer-events:none;background:var(--dsw-alias-bg-inverse,#1f2328);color:var(--dsw-alias-label-inverse,#fff);border-radius:8px;padding:7px 10px;font-size:11.5px;line-height:1.55;white-space:nowrap;box-shadow:0 6px 20px rgba(0,0,0,.28);font-variant-numeric:tabular-nums}\n.dq-tip-head{font-weight:650;margin-bottom:2px}\n.dq-tip-row{opacity:.85}\n.dq-bars{display:flex;align-items:flex-end;gap:2px;width:100%}\n.dq-bar-col{flex:1 1 0;min-width:0;display:flex;flex-direction:column;justify-content:flex-end;align-items:stretch}\n.dq-bar{background:var(--dsw-alias-state-business-primary,#4176e6);border-radius:2px 2px 0 0;min-height:1px;transition:filter .12s ease}\n.dq-bar-col{cursor:default}\n.dq-bar-col:hover .dq-bar{filter:brightness(1.18) saturate(1.1)}\n.dq-heat-cell:not(.dq-heat-cell--pad):hover{outline:1.5px solid var(--dsw-alias-label-primary,#1f2328);outline-offset:1px}\n.dq-bar-label{font-size:9px;color:var(--dsw-alias-label-tertiary,#59636e);text-align:center;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-heat{display:flex;flex-direction:column;gap:8px;max-width:100%}\n.dq-heat-grid{display:flex;gap:6px;overflow-x:auto;padding-bottom:2px}\n.dq-heat-dows{display:flex;flex-direction:column;gap:3px;padding-top:17px;flex:none}\n.dq-heat-dow{height:12px;line-height:12px;font-size:9px;color:var(--dsw-alias-label-tertiary,#59636e);text-align:right;width:12px}\n.dq-heat-cols{display:flex;flex-direction:column;gap:2px;min-width:0}\n.dq-heat-months{display:flex;gap:3px;height:12px}\n.dq-heat-month{width:12px;flex:none;font-size:9px;line-height:12px;color:var(--dsw-alias-label-tertiary,#59636e);white-space:nowrap;overflow:visible}\n.dq-heatmap{display:flex;gap:3px;width:max-content}\n.dq-heat-week{display:flex;flex-direction:column;gap:3px}\n.dq-heat-cell{width:12px;height:12px;border-radius:2px;flex:none}\n.dq-heat-cell--pad{background:transparent}\n.dq-heat-key{width:12px;height:12px;border-radius:2px;flex:none}\n.dq-heat-scale{display:flex;align-items:center;gap:3px;font-size:10px;color:var(--dsw-alias-label-tertiary,#59636e);align-self:flex-end}\n.dq-heat-scale>span:first-child{margin-right:2px}\n.dq-heat-scale>span:last-child{margin-left:2px}\n.dq-muted{color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-warn{color:var(--dsw-alias-state-warning-primary,#9a6700)}\n.dq-crash{margin:10px 0 14px;padding:10px 12px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.10));border-radius:8px;font-size:11.5px;line-height:1.5;color:var(--dsw-alias-state-error-primary,#cf222e);white-space:pre-wrap;word-break:break-word;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}\n.dq-empty{color:var(--dsw-alias-label-secondary,#59636e);font-size:12.5px;line-height:1.6;padding:6px 0}\n.dq-skel{background:linear-gradient(90deg,rgba(125,135,155,.10) 25%,rgba(125,135,155,.20) 37%,rgba(125,135,155,.10) 63%);background-size:400% 100%;border-radius:5px;animation:dq-shimmer 1.5s ease-in-out infinite}\n.dq-stat .dq-skel+.dq-skel{margin-top:6px}\n.dq-skel-bars{display:flex;align-items:flex-end;gap:2px;width:100%;height:120px;margin-top:10px}\n.dq-skel-bar{flex:1 1 0;min-width:0;border-radius:2px 2px 0 0}\n@keyframes dq-shimmer{0%{background-position:100% 50%}100%{background-position:0 50%}}\n@media (prefers-reduced-motion:reduce){.dq-skel{animation:none}.dq-refresh-icon--spin{animation:none}}\n.dq-status-row{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:20px}\n.dq-status-row .dq-muted,.dq-status-row .dq-error{font-size:12px}\n.dq-refresh-btn{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:5px 10px;font-size:12px;cursor:pointer;transition:border-color .15s ease,color .15s ease}\n.dq-refresh-btn:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-refresh-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-refresh-btn:disabled{cursor:default;opacity:.6}\n.dq-refresh-icon{display:inline-block;line-height:1}\n.dq-refresh-icon--spin{animation:dq-spin .9s linear infinite}\n@keyframes dq-spin{to{transform:rotate(360deg)}}\n`\n", "/** The draggable bottom-right floating balance widget.\n *\n * Where it sits (corner) and whether it is collapsed are user choices, so both\n * are persisted (see ./prefs.ts) and restored before the first paint; the\n * widget also re-snaps to its corner when the frame resizes (window resize,\n * sidebar collapse) instead of stranding itself at stale pixel coordinates.\n */\nimport { useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type PointerEvent as ReactPointerEvent, type ReactElement } from 'react'\nimport { fetchBalance, fetchUsage, getCachedBalance, getCachedUsage, getCachedUsageAt, subscribeUsage } from './api.ts'\nimport { fmt } from './charts.tsx'\nimport type { BalanceData, UsageData } from '../contract.ts'\nimport { isBoolean, loadPref, savePref } from './prefs.ts'\nimport { lowBalanceStore, widgetVisibleStore } from './store.ts'\n\nconst MARGIN = 16\n\ntype Corner = 'tl' | 'tr' | 'bl' | 'br'\n\nconst CORNER_KEY = 'widget.corner'\nconst COLLAPSED_KEY = 'widget.collapsed'\n\nconst isCorner = (value: unknown): boolean =>\n value === 'tl' || value === 'tr' || value === 'bl' || value === 'br'\n\ninterface Bounds {\n left: number\n top: number\n right: number\n bottom: number\n}\n\ninterface DragSession {\n pointerId: number\n startX: number\n startY: number\n originX: number\n originY: number\n width: number\n height: number\n bounds: Bounds\n}\n\n/** The shell's main column: the region between the sidebar and the details\n * panel. Found through the stable `conversation` slot anchor rather than the\n * hashed layout class names. */\nfunction getMainColumn(frame: HTMLElement): HTMLElement | null {\n const anchor = frame.querySelector('[data-slot=\"conversation\"]')\n const column = anchor?.parentElement ?? null\n return column === frame ? null : column\n}\n\n/**\n * The laid-out box behind a slot. Slot wrappers are 0\u00D70, and which neighbour\n * carries the real box differs per slot: the session header renders inside its\n * wrapper (`'child'`), while the composer's wrapper sits inside the seat that\n * reserves the space (`'ancestor'`). Picking the wrong side silently yields a\n * box in the wrong place, so the caller says which one it means.\n */\nfunction slotBox(frame: HTMLElement, slot: string, side: 'child' | 'ancestor'): DOMRect | null {\n const anchor = frame.querySelector(`[data-slot=\"${slot}\"]`)\n if (anchor === null) return null\n if (side === 'child') {\n const rect = (anchor.firstElementChild as HTMLElement | null)?.getBoundingClientRect() ?? null\n return rect !== null && rect.height > 0 ? rect : null\n }\n let el: HTMLElement | null = anchor.parentElement\n for (let depth = 0; depth < 4 && el !== null && el !== frame; depth++) {\n const rect = el.getBoundingClientRect()\n if (rect.height > 0) return rect\n el = el.parentElement\n }\n return null\n}\n\n/** Below this the region is too short to park a widget in, so an exclusion is\n * skipped rather than squeezing the widget out of the frame. */\nconst MIN_REGION_HEIGHT = 140\n\n/**\n * Draggable area = the main column minus the session header and the composer.\n *\n * Using the main column (rather than the whole frame minus the sidebar) also\n * keeps the widget clear of the right-hand details panel when it is open.\n * The header is excluded so the widget can never park on the Chat / Trajectory\n * / \u989D\u5EA6 tab row and swallow its clicks, and the composer is excluded because a\n * bottom-right widget otherwise covers the model picker and the send button \u2014\n * the two controls the user reaches for most.\n */\nfunction getBounds(node: HTMLElement | null): Bounds {\n const fallback: Bounds = { left: 0, top: 0, right: 100000, bottom: 100000 }\n if (node === null) return fallback\n const overlay = typeof node.closest === 'function' ? node.closest('[data-shell-overlay]') : null\n const frame = overlay?.parentElement ?? null\n if (frame === null) return fallback\n const frameRect = frame.getBoundingClientRect()\n let left = frameRect.left\n let right = frameRect.right\n let top = frameRect.top\n const mainRect = getMainColumn(frame)?.getBoundingClientRect() ?? null\n if (mainRect !== null && mainRect.width > 0) {\n left = mainRect.left\n right = mainRect.right\n top = mainRect.top\n } else {\n const sidebarRect = (frame.children[0] as HTMLElement | undefined)?.getBoundingClientRect() ?? null\n if (sidebarRect !== null) left = sidebarRect.right\n }\n let bottom = frameRect.bottom\n const headerRect = slotBox(frame, 'conversation.session.header', 'child')\n if (headerRect !== null && headerRect.bottom > top && headerRect.bottom < bottom - MIN_REGION_HEIGHT) {\n top = headerRect.bottom\n }\n const composerRect = slotBox(frame, 'conversation.composer.dock', 'ancestor')\n if (composerRect !== null && composerRect.top < bottom && composerRect.top > top + MIN_REGION_HEIGHT) {\n bottom = composerRect.top\n }\n return { left, top, right, bottom }\n}\n\nfunction cornerPos(corner: Corner, node: HTMLElement | null, bounds: Bounds): { x: number; y: number } {\n const rect = node?.getBoundingClientRect()\n const w = rect?.width ?? 0\n const h = rect?.height ?? 0\n const xLeft = bounds.left + MARGIN\n const yTop = bounds.top + MARGIN\n const xRight = bounds.right - w - MARGIN\n const yBottom = bounds.bottom - h - MARGIN\n if (corner === 'tl') return { x: xLeft, y: yTop }\n if (corner === 'tr') return { x: xRight, y: yTop }\n if (corner === 'bl') return { x: xLeft, y: yBottom }\n return { x: xRight, y: yBottom }\n}\n\nexport function QuotaWidget(): ReactElement | null {\n const [visible, setVisible] = useState(widgetVisibleStore.get())\n useEffect(() => widgetVisibleStore.subscribe(() => setVisible(widgetVisibleStore.get())), [])\n const [lowBalance, setLowBalance] = useState(lowBalanceStore.get())\n useEffect(() => lowBalanceStore.subscribe(() => setLowBalance(lowBalanceStore.get())), [])\n\n const cachedBalance = getCachedBalance()\n const [data, setData] = useState<BalanceData | null>(cachedBalance?.data ?? null)\n const [error, setError] = useState<string | null>(null)\n const [loading, setLoading] = useState(cachedBalance === null)\n const [collapsed, setCollapsed] = useState(() => loadPref<boolean>(COLLAPSED_KEY, isBoolean, false))\n const [pos, setPos] = useState<{ x: number; y: number } | null>(null)\n const [corner, setCorner] = useState<Corner>(() => loadPref<Corner>(CORNER_KEY, isCorner, 'br'))\n const [dragging, setDragging] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const dragRef = useRef<DragSession | null>(null)\n\n // Today's spend comes from the shared usage cache \u2014 never fetched on the\n // widget's own poll, since aggregating the session logs takes seconds. A\n // manual refresh (below) is the one place the widget pays for it.\n const readUsage = (): { data: UsageData | null; at: number | null } => {\n const cached = getCachedUsage()\n return { data: cached?.ok === true ? cached.data ?? null : null, at: getCachedUsageAt() }\n }\n const [usage, setUsage] = useState(readUsage)\n useEffect(() => subscribeUsage(() => setUsage(readUsage())), [])\n\n const load = async (showLoading: boolean, force = false): Promise<void> => {\n if (showLoading) setLoading(true)\n try {\n const res = await fetchBalance(force)\n if (res.ok && res.data !== undefined) {\n setData(res.data)\n setError(null)\n } else {\n setData(null)\n setError(res.error ?? '\u67E5\u8BE2\u5931\u8D25')\n }\n } catch (err) {\n setData(null)\n setError((err as { message?: string } | null)?.message ?? String(err))\n } finally {\n setLoading(false)\n }\n }\n\n useEffect(() => {\n void load(true)\n const id = setInterval(() => { void load(false) }, 60_000)\n return () => clearInterval(id)\n }, [])\n\n /**\n * Keep the widget parked in its corner: on mount (restoring the persisted\n * corner before the first paint), when collapse/expand changes its size, and\n * whenever the layout moves under it \u2014 window resize, sidebar collapse or\n * the details panel opening (observed), plus a slow poll that catches the\n * one change no observer reports: the session header mounting *after* the\n * overlay, which would otherwise leave the widget parked over the tab row.\n *\n * `place` keeps the previous object when the corner has not actually moved,\n * so repeated triggers cost one rect read and no re-render.\n */\n useLayoutEffect(() => {\n if (!visible) return\n const node = rootRef.current\n if (node === null) return\n const place = (): void => {\n if (dragRef.current !== null) return\n const next = cornerPos(corner, node, getBounds(node))\n setPos(prev => (prev !== null && prev.x === next.x && prev.y === next.y ? prev : next))\n }\n place()\n const frame = node.closest('[data-shell-overlay]')?.parentElement as HTMLElement | null\n let observer: ResizeObserver | null = null\n if (frame !== null && typeof ResizeObserver === 'function') {\n observer = new ResizeObserver(place)\n observer.observe(frame)\n const main = getMainColumn(frame)\n if (main !== null) observer.observe(main)\n }\n window.addEventListener('resize', place)\n const poll = setInterval(place, 1000)\n return () => {\n observer?.disconnect()\n window.removeEventListener('resize', place)\n clearInterval(poll)\n }\n }, [visible, corner, collapsed])\n\n const snapToNearest = (session: DragSession): void => {\n const node = rootRef.current\n if (node === null) return\n const { width: w, height: h, bounds: b } = session\n const corners: Array<{ c: Corner; x: number; y: number }> = [\n { c: 'tl', x: b.left + MARGIN, y: b.top + MARGIN },\n { c: 'tr', x: b.right - w - MARGIN, y: b.top + MARGIN },\n { c: 'bl', x: b.left + MARGIN, y: b.bottom - h - MARGIN },\n { c: 'br', x: b.right - w - MARGIN, y: b.bottom - h - MARGIN },\n ]\n const rect = node.getBoundingClientRect()\n const cx = rect.left + rect.width / 2\n const cy = rect.top + rect.height / 2\n let best = corners[0]\n let bestDistance = Number.POSITIVE_INFINITY\n for (const candidate of corners) {\n const ccx = candidate.x + w / 2\n const ccy = candidate.y + h / 2\n const distance = (ccx - cx) ** 2 + (ccy - cy) ** 2\n if (distance < bestDistance) {\n bestDistance = distance\n best = candidate\n }\n }\n setCorner(best.c)\n savePref(CORNER_KEY, best.c)\n setPos({ x: best.x, y: best.y })\n }\n\n /** Idempotent end-of-drag; also the missed-pointerup backstop. */\n const endDrag = (snap: boolean): void => {\n const session = dragRef.current\n if (session === null) return\n dragRef.current = null\n setDragging(false)\n const node = rootRef.current\n if (node !== null && typeof node.releasePointerCapture === 'function') {\n try {\n node.releasePointerCapture(session.pointerId)\n } catch {\n // capture already released\n }\n }\n if (snap) {\n if (typeof requestAnimationFrame === 'function') {\n requestAnimationFrame(() => snapToNearest(session))\n } else {\n snapToNearest(session)\n }\n }\n }\n\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>): void => {\n if (e.button !== 0) return\n const target = e.target as Element | null\n if (target !== null && typeof target.closest === 'function' && target.closest('button') !== null) return\n const node = rootRef.current\n if (node === null) return\n const bounds = getBounds(node)\n const rect = node.getBoundingClientRect()\n dragRef.current = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n originX: rect.left,\n originY: rect.top,\n width: rect.width,\n height: rect.height,\n bounds,\n }\n node.setPointerCapture(e.pointerId)\n setDragging(true)\n e.preventDefault()\n }\n\n const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const session = dragRef.current\n if (session === null || session.pointerId !== e.pointerId) return\n if ((e.buttons & 1) === 0) {\n endDrag(true)\n return\n }\n const dx = e.clientX - session.startX\n const dy = e.clientY - session.startY\n const maxX = session.bounds.right - session.width - MARGIN\n const maxY = session.bounds.bottom - session.height - MARGIN\n const minX = session.bounds.left + MARGIN\n const minY = session.bounds.top + MARGIN\n setPos({\n x: Math.max(minX, Math.min(session.originX + dx, maxX)),\n y: Math.max(minY, Math.min(session.originY + dy, maxY)),\n })\n }\n\n const onPointerUp = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const session = dragRef.current\n if (session === null || session.pointerId !== e.pointerId) return\n endDrag(true)\n }\n\n if (!visible) return null\n\n const primary = data !== null && data.balances.length > 0 ? data.balances[0] : null\n const balanceValue = primary !== null ? Number(primary.total) : Number.NaN\n const low = lowBalance > 0 && Number.isFinite(balanceValue) && balanceValue < lowBalance\n const dotClass = primary === null\n ? 'dsh-quota-dot dsh-quota-dot--idle'\n : data?.isAvailable === false\n ? 'dsh-quota-dot dsh-quota-dot--error'\n : low ? 'dsh-quota-dot dsh-quota-dot--warn' : 'dsh-quota-dot'\n\n // The usage figure can be minutes old (it is only refreshed on demand), so\n // say how old rather than presenting it as live.\n const ageMinutes = usage.at === null ? null : Math.floor((Date.now() - usage.at) / 60_000)\n const usageAgeText = ageMinutes === null || ageMinutes < 1 ? '\u521A\u521A\u66F4\u65B0' : `${ageMinutes} \u5206\u949F\u524D\u7684\u6570\u636E\uFF0C\u70B9 \u21BB \u66F4\u65B0`\n\n let body: ReactElement | null = null\n if (!collapsed) {\n if (loading && data === null && error === null) {\n body = <div className=\"dsh-quota-body\">\u67E5\u8BE2\u4E2D\u2026</div>\n } else if (error !== null && data === null) {\n body = <div className=\"dsh-quota-body dsh-quota-error\">{error}</div>\n } else if (primary !== null) {\n body = (\n <div className=\"dsh-quota-body\">\n <div className=\"dsh-quota-remaining-label\">\u5269\u4F59\u4F59\u989D</div>\n <div title={low ? `\u4F59\u989D\u4F4E\u4E8E\u9884\u8B66\u7EBF ${fmt(lowBalance)}` : undefined}>\n <span className={`dsh-quota-total${low ? ' dsh-quota-total--low' : ''}`}>{fmt(primary.total)}</span>\n <span className=\"dsh-quota-currency\">{primary.currency}</span>\n </div>\n {usage.data !== null && (\n <div className=\"dsh-quota-row\" title={`\u4ECA\u65E5\u6D88\u8017\uFF08\u4F30\u7B97\uFF09\u00B7 ${usageAgeText}`}>\n <span className=\"dsh-quota-label\">\u4ECA\u65E5\u6D88\u8017</span>\n <span className=\"dsh-quota-value\">\u00A5 {fmt(usage.data.summary.today.cost)}</span>\n </div>\n )}\n {data?.isAvailable === false && (\n <div className=\"dsh-quota-row\">\n <span className=\"dsh-quota-label\">\u72B6\u6001</span>\n <span className=\"dsh-quota-value dsh-quota-error\">\u4E0D\u53EF\u7528</span>\n </div>\n )}\n </div>\n )\n } else {\n body = <div className=\"dsh-quota-body dsh-quota-error\">\u6682\u65E0\u4F59\u989D\u6570\u636E</div>\n }\n }\n\n const style: CSSProperties | undefined = pos !== null\n ? { left: `${pos.x}px`, top: `${pos.y}px`, right: 'auto', bottom: 'auto' }\n : undefined\n\n return (\n <div className={`dsh-quota-root${dragging ? ' dsh-quota-dragging' : ''}`} style={style}>\n <div\n ref={rootRef}\n className=\"dsh-quota-card\"\n title=\"\u62D6\u52A8\u5230\u56DB\u4E2A\u89D2\u843D\"\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={() => endDrag(false)}\n onLostPointerCapture={() => endDrag(false)}\n >\n <div className=\"dsh-quota-header\">\n <div className=\"dsh-quota-title\">\n <span className=\"dsh-quota-grip\" title=\"\u62D6\u52A8\u4EE5\u79FB\u52A8\">\u2807</span>\n <span className={dotClass} />\n <span className=\"dsh-quota-name\">DeepSeek \u989D\u5EA6</span>\n {collapsed && primary !== null && (\n <span className={`dsh-quota-collapsed-total${low ? ' dsh-quota-total--low' : ''}`}>{fmt(primary.total)} {primary.currency}</span>\n )}\n </div>\n <div className=\"dsh-quota-actions\">\n <button\n className=\"dsh-quota-btn\"\n type=\"button\"\n title=\"\u5237\u65B0\u4F59\u989D\u4E0E\u4ECA\u65E5\u7528\u91CF\"\n aria-label=\"\u5237\u65B0\u4F59\u989D\u4E0E\u4ECA\u65E5\u7528\u91CF\"\n disabled={loading}\n onClick={() => {\n void load(true, true)\n void fetchUsage(true)\n }}\n >\n \u21BB\n </button>\n <button\n className=\"dsh-quota-btn\"\n type=\"button\"\n title={collapsed ? '\u5C55\u5F00' : '\u6536\u8D77'}\n aria-label={collapsed ? '\u5C55\u5F00\u989D\u5EA6\u7A97\u53E3' : '\u6536\u8D77\u989D\u5EA6\u7A97\u53E3'}\n aria-expanded={!collapsed}\n onClick={() => {\n const next = !collapsed\n setCollapsed(next)\n savePref(COLLAPSED_KEY, next)\n }}\n >\n {collapsed ? '+' : '\u2212'}\n </button>\n </div>\n </div>\n {body}\n </div>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_react", "import_react", "import_jsx_runtime", "PREFIX", "import_jsx_runtime", "rate", "name", "import_react", "import_jsx_runtime", "import_jsx_runtime"]
|
|
7
7
|
}
|