@dsh-plugins/dsh-llm-hub 1.3.2 → 1.3.3
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/CHANGELOG.md +12 -0
- package/lib/client.js +48 -6
- package/lib/index.js +23 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)。
|
|
4
4
|
|
|
5
|
+
## [1.3.3] - 2026-09-25
|
|
6
|
+
|
|
7
|
+
### ✨ 订阅制配额可视化进度条与重置倒计时
|
|
8
|
+
|
|
9
|
+
- **📊 订阅制可视化进度条胶囊(Subscription Quota Gauge)**:
|
|
10
|
+
- 参考 `claude-usage-statusline` 经典轨道式设计,在 Provider 卡片中引入高质感平滑迷你进度条;
|
|
11
|
+
- 动态三色渐变指示:`> 50%` 充裕翡翠绿(`#10b981`)、`15%~50%` 预警金黄(`#f59e0b`)、`<= 15%` 告急珊瑚红(`#ef4444`);
|
|
12
|
+
- 同时支持主限额(如 MiniMax 5 小时滚动配额、智谱 5h 配额)与次级周限额的双重进度条并列展示;
|
|
13
|
+
- **⏱️ 重置时刻与倒计时精准指示(Reset Time Tracking)**:
|
|
14
|
+
- 在配额进度条后实时标注重置时刻(如 `(15:40 重置)`),悬浮卡片提供完整余量与周期说明;
|
|
15
|
+
- 适配器底层自动解析服务端返回的 `current_interval_end_time` / `next_reset_time` / `expire_time` 真实重置时刻。
|
|
16
|
+
|
|
5
17
|
## [1.3.2] - 2026-09-24
|
|
6
18
|
|
|
7
19
|
### 🐛 修复与健壮性提升
|
package/lib/client.js
CHANGED
|
@@ -547,6 +547,18 @@ window.__ModuleLoader__.load({
|
|
|
547
547
|
'.dsh-llm-hub-latency-badge.is-fast{background:rgba(16,185,129,.08);color:var(--dsw-alias-state-success-primary,#10b981);border:.5px solid rgba(16,185,129,.2)}',
|
|
548
548
|
'.dsh-llm-hub-latency-badge.is-normal{background:rgba(234,179,8,.08);color:var(--dsw-alias-state-warn-primary,#eab308);border:.5px solid rgba(234,179,8,.2)}',
|
|
549
549
|
'.dsh-llm-hub-latency-badge.is-slow{background:rgba(239,68,68,.08);color:var(--dsw-alias-state-error-primary,#ef4444);border:.5px solid rgba(239,68,68,.2)}',
|
|
550
|
+
// 订阅制配额可视化进度条与重置倒计时(参考 claude-usage-statusline 规范)
|
|
551
|
+
'.dsh-llm-hub-quota-group{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap;vertical-align:middle}',
|
|
552
|
+
'.dsh-llm-hub-quota-bar{display:inline-flex;align-items:center;gap:4.5px;padding:1.5px 6px;border-radius:4px;background:var(--dsw-alias-bg-layer-2,rgba(255,255,255,.03));border:.5px solid var(--dsw-alias-border-l1,rgba(255,255,255,.08));font-size:10.5px;line-height:1;transition:all .15s ease}',
|
|
553
|
+
'.dsh-llm-hub-quota-bar:hover{border-color:var(--dsw-alias-brand-primary,rgba(59,130,246,.4));background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.06))}',
|
|
554
|
+
'.dsh-llm-hub-quota-label{font-weight:600;color:var(--dsw-alias-label-primary);font-size:10px}',
|
|
555
|
+
'.dsh-llm-hub-quota-track{width:46px;height:4.5px;border-radius:2.5px;background:rgba(255,255,255,.12);overflow:hidden;position:relative;display:inline-block;vertical-align:middle}',
|
|
556
|
+
'.dsh-llm-hub-quota-fill{height:100%;border-radius:2.5px;display:block;transition:width .3s cubic-bezier(0.4,0,0.2,1)}',
|
|
557
|
+
'.dsh-llm-hub-quota-fill.is-high{background:linear-gradient(90deg,#10b981,#34d399)}',
|
|
558
|
+
'.dsh-llm-hub-quota-fill.is-mid{background:linear-gradient(90deg,#f59e0b,#fbbf24)}',
|
|
559
|
+
'.dsh-llm-hub-quota-fill.is-low{background:linear-gradient(90deg,#ef4444,#f87171)}',
|
|
560
|
+
'.dsh-llm-hub-quota-pct{font-variant-numeric:tabular-nums;font-weight:600;color:var(--dsw-alias-label-primary);font-size:10.5px}',
|
|
561
|
+
'.dsh-llm-hub-quota-time{font-size:9.5px;color:var(--dsw-alias-label-secondary);opacity:.8;font-variant-numeric:tabular-nums;display:inline-flex;align-items:center;margin-left:1px}',
|
|
550
562
|
// Webkubor 插件全家桶互导矩阵
|
|
551
563
|
'.dsh-suite-dock{margin-top:14px;padding:14px 16px;background:var(--dsw-alias-bg-layer-2,rgba(255,255,255,0.03));border:1px solid var(--dsw-alias-border-l1,rgba(255,255,255,0.08));border-radius:10px;backdrop-filter:blur(10px)}',
|
|
552
564
|
'.dsh-suite-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;flex-wrap:wrap;gap:8px}',
|
|
@@ -861,14 +873,44 @@ window.__ModuleLoader__.load({
|
|
|
861
873
|
return `${t('balance')} ${symbol}${first.amount}${voucher}`
|
|
862
874
|
}
|
|
863
875
|
const meaning = balance.meaning === 'used' ? t('used') : t('remain')
|
|
864
|
-
const
|
|
876
|
+
const isUsed = balance.meaning === 'used'
|
|
877
|
+
const bars = []
|
|
865
878
|
for (const item of items.slice(0, 2)) {
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
879
|
+
const remainPct = isUsed ? Math.max(0, 100 - (item.percent ?? 0)) : (item.percent ?? 0)
|
|
880
|
+
const fillPct = Math.min(Math.max(remainPct, 0), 100)
|
|
881
|
+
const levelClass = fillPct > 50 ? 'is-high' : (fillPct > 20 ? 'is-mid' : 'is-low')
|
|
882
|
+
const labelText = item.label || '5h'
|
|
883
|
+
const resetTimeNote = item.resetsAt ? `(${item.resetsAt} 重置)` : ''
|
|
884
|
+
bars.push(h('span', {
|
|
885
|
+
key: labelText,
|
|
886
|
+
className: 'dsh-llm-hub-quota-bar',
|
|
887
|
+
title: `${labelText} ${meaning} ${item.percent}%${resetTimeNote ? ` · ${resetTimeNote}` : ''}`
|
|
888
|
+
},
|
|
889
|
+
h('span', { className: 'dsh-llm-hub-quota-label' }, labelText),
|
|
890
|
+
h('span', { className: 'dsh-llm-hub-quota-track' },
|
|
891
|
+
h('span', { className: `dsh-llm-hub-quota-fill ${levelClass}`, style: { width: `${fillPct}%` } })
|
|
892
|
+
),
|
|
893
|
+
h('span', { className: 'dsh-llm-hub-quota-pct' }, `${item.percent}%`),
|
|
894
|
+
resetTimeNote ? h('span', { className: 'dsh-llm-hub-quota-time' }, resetTimeNote) : null
|
|
895
|
+
))
|
|
896
|
+
if (typeof item.weeklyPercent === 'number') {
|
|
897
|
+
const weeklyRemain = isUsed ? Math.max(0, 100 - item.weeklyPercent) : item.weeklyPercent
|
|
898
|
+
const weeklyFill = Math.min(Math.max(weeklyRemain, 0), 100)
|
|
899
|
+
const weeklyClass = weeklyFill > 50 ? 'is-high' : (weeklyFill > 20 ? 'is-mid' : 'is-low')
|
|
900
|
+
bars.push(h('span', {
|
|
901
|
+
key: 'week',
|
|
902
|
+
className: 'dsh-llm-hub-quota-bar',
|
|
903
|
+
title: `${t('week')} ${meaning} ${item.weeklyPercent}%`
|
|
904
|
+
},
|
|
905
|
+
h('span', { className: 'dsh-llm-hub-quota-label' }, t('week')),
|
|
906
|
+
h('span', { className: 'dsh-llm-hub-quota-track' },
|
|
907
|
+
h('span', { className: `dsh-llm-hub-quota-fill ${weeklyClass}`, style: { width: `${weeklyFill}%` } })
|
|
908
|
+
),
|
|
909
|
+
h('span', { className: 'dsh-llm-hub-quota-pct' }, `${item.weeklyPercent}%`)
|
|
910
|
+
))
|
|
911
|
+
}
|
|
869
912
|
}
|
|
870
|
-
|
|
871
|
-
return `${t('planQuota')} ${level}${parts.join(' / ')}`
|
|
913
|
+
return h('span', { className: 'dsh-llm-hub-quota-group' }, bars)
|
|
872
914
|
}
|
|
873
915
|
|
|
874
916
|
/**
|
package/lib/index.js
CHANGED
|
@@ -923,10 +923,21 @@ export function apply(ctx) {
|
|
|
923
923
|
if (row === null || typeof row !== 'object') continue
|
|
924
924
|
const percent = percentage(row.current_interval_remaining_percent)
|
|
925
925
|
if (percent === undefined) continue
|
|
926
|
+
let resetsAt = undefined
|
|
927
|
+
const rawTime = row.current_interval_end_time ?? row.end_time ?? row.reset_time
|
|
928
|
+
if (typeof rawTime === 'number' && rawTime > 0) {
|
|
929
|
+
const date = new Date(rawTime > 1e11 ? rawTime : rawTime * 1000)
|
|
930
|
+
if (!isNaN(date.getTime())) {
|
|
931
|
+
resetsAt = `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
|
|
932
|
+
}
|
|
933
|
+
} else if (typeof rawTime === 'string' && rawTime.trim() !== '') {
|
|
934
|
+
resetsAt = rawTime.trim()
|
|
935
|
+
}
|
|
926
936
|
items.push({
|
|
927
937
|
label: label(row.model_name) ?? 'plan',
|
|
928
938
|
percent,
|
|
929
|
-
weeklyPercent: percentage(row.current_weekly_remaining_percent)
|
|
939
|
+
weeklyPercent: percentage(row.current_weekly_remaining_percent),
|
|
940
|
+
resetsAt
|
|
930
941
|
})
|
|
931
942
|
}
|
|
932
943
|
return { items }
|
|
@@ -953,7 +964,17 @@ export function apply(ctx) {
|
|
|
953
964
|
if (tier === undefined) continue
|
|
954
965
|
const percent = percentage(lim.percentage)
|
|
955
966
|
if (percent === undefined) continue
|
|
956
|
-
|
|
967
|
+
let resetsAt = undefined
|
|
968
|
+
const rawTime = lim.reset_time ?? lim.next_reset_time ?? body?.data?.expire_time
|
|
969
|
+
if (typeof rawTime === 'number' && rawTime > 0) {
|
|
970
|
+
const date = new Date(rawTime > 1e11 ? rawTime : rawTime * 1000)
|
|
971
|
+
if (!isNaN(date.getTime())) {
|
|
972
|
+
resetsAt = `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
|
|
973
|
+
}
|
|
974
|
+
} else if (typeof rawTime === 'string' && rawTime.trim() !== '') {
|
|
975
|
+
resetsAt = rawTime.trim()
|
|
976
|
+
}
|
|
977
|
+
items.push({ label: tier, percent, resetsAt })
|
|
957
978
|
}
|
|
958
979
|
return { level: label(body?.data?.level), items }
|
|
959
980
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-plugins/dsh-llm-hub",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3",
|
|
4
4
|
"description": "DSH 模型管理层:网关可达性探测、模型目录拉取、DeepSeek + MiniMax/智谱/Moonshot/StepFun 余额与配额、本月用量统计、余额预警、Provider 健康看板,再把本机装好的 codex / claude / agy 注册成子代理(装了才出现)。零运行时依赖,不改动 DSH 安装。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|