dsh-llm-local-token 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/README.zh.md +2 -1
- package/lib/client.js +93 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -135,7 +135,8 @@ The badge shows **only the provider serving the currently selected model**: pick
|
|
|
135
135
|
Codex's windows, switch to Claude and it swaps — the two are never mixed into one number. When the
|
|
136
136
|
selected model belongs to another adapter (a plain API key, another plugin) the badge hides itself,
|
|
137
137
|
because that quota is not this plugin's to report. The popover still lists every route, with the
|
|
138
|
-
active one first
|
|
138
|
+
active one first, marked "current" and expanded; the rest are collapsed to a header carrying their
|
|
139
|
+
first two windows, and open on click. Switching model re-applies that default. The selection comes from
|
|
139
140
|
`ctx.modelDirectories`; a composition without that service (non-Web) falls back to the previous
|
|
140
141
|
union-of-all-routes view.
|
|
141
142
|
|
package/README.zh.md
CHANGED
|
@@ -120,7 +120,8 @@ GLM 的凭据按下面的顺序解析,这个顺序保证数字是诚实的 —
|
|
|
120
120
|
|
|
121
121
|
徽标**只显示当前选中模型所属 provider** 的用量:选 Codex 就是 Codex 的窗口,切到 Claude 就换成
|
|
122
122
|
Claude 的,不会把两家的数字混在一起。选中的模型由别的 adapter 提供(普通 API key、其他插件)时徽标
|
|
123
|
-
直接隐藏 ——
|
|
123
|
+
直接隐藏 —— 那份额度不属于本插件。展开的弹层仍列出所有路由:当前那条排在最前、标注「当前」并默认展开;
|
|
124
|
+
其余折叠成一行,行内保留前两个窗口的百分比,点击即可展开。切换模型会重新套用这个默认。
|
|
124
125
|
当前选中项来自 `ctx.modelDirectories`;组合里没有该服务时(非 Web)退回旧的「全部路由合并」显示。
|
|
125
126
|
|
|
126
127
|
## 环境要求
|
package/lib/client.js
CHANGED
|
@@ -27,6 +27,25 @@ window.__ModuleLoader__.load({
|
|
|
27
27
|
".ltk_cur{padding:0 6px;border-radius:999px;font-size:10px;line-height:16px;background:var(--dsw-alias-state-success-tertiary,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-label-primary)}" +
|
|
28
28
|
".ltk_provHead{display:flex;align-items:center;gap:6px;margin-bottom:6px}" +
|
|
29
29
|
".ltk_provName{flex:1;font-size:12px;font-weight:600;color:var(--dsw-alias-label-primary)}" +
|
|
30
|
+
".ltk_provToggle{width:100%;padding:0;border:none;background:none;font:inherit;color:inherit;cursor:pointer;text-align:left}" +
|
|
31
|
+
".ltk_provFlat{margin-bottom:0}" +
|
|
32
|
+
// The chevron is the supplied 16px icon, inlined rather than fetched: one
|
|
33
|
+
// path, so it costs no request and no asset route. Source: docs/arrow.svg.
|
|
34
|
+
//
|
|
35
|
+
// Its artwork sits in the right half of the source canvas (x 8..12.1 of 16),
|
|
36
|
+
// so the viewBox is cropped square around the stroke instead of using the
|
|
37
|
+
// original 0 0 16 16 — otherwise nearly half the box is padding and the
|
|
38
|
+
// arrow looks indented against the window rows below it. Square keeps the
|
|
39
|
+
// 90deg open-state rotation pivoting on the artwork's own centre, so the
|
|
40
|
+
// row's left edge never moves when it toggles.
|
|
41
|
+
//
|
|
42
|
+
// Sized with the row's 10px badges, the smallest type in the panel. Note
|
|
43
|
+
// the box is all ink: a cropped SVG at 10px draws a 10px arrow, where a
|
|
44
|
+
// 10px text glyph drew roughly half that inside its em box — so this
|
|
45
|
+
// still reads larger than the character it replaced.
|
|
46
|
+
".ltk_chev{flex:none;display:block;width:10px;height:10px;color:var(--dsw-alias-label-secondary);transform-origin:50% 50%;transition:transform .12s ease}" +
|
|
47
|
+
".ltk_chevOpen{transform:rotate(90deg)}" +
|
|
48
|
+
".ltk_sum{flex:none;font-size:11px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums}" +
|
|
30
49
|
".ltk_plan{padding:0 6px;border-radius:999px;font-size:10px;line-height:16px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary)}" +
|
|
31
50
|
".ltk_row{margin-top:6px}" +
|
|
32
51
|
".ltk_rowTop{display:flex;align-items:baseline;gap:6px;font-size:11px;color:var(--dsw-alias-label-tertiary)}" +
|
|
@@ -54,6 +73,7 @@ window.__ModuleLoader__.load({
|
|
|
54
73
|
current: "current",
|
|
55
74
|
"unit.d": "{n} days", "unit.h": "{n} hours", "unit.m": "{n} min",
|
|
56
75
|
readAt: "read {when} ago",
|
|
76
|
+
expand: "Show {name} quota", collapse: "Hide {name} quota",
|
|
57
77
|
};
|
|
58
78
|
const zh = {
|
|
59
79
|
label: "额度", title: "订阅用量",
|
|
@@ -65,6 +85,7 @@ window.__ModuleLoader__.load({
|
|
|
65
85
|
current: "当前",
|
|
66
86
|
"unit.d": "{n} 天", "unit.h": "{n} 小时", "unit.m": "{n} 分钟",
|
|
67
87
|
readAt: "{when}前读取",
|
|
88
|
+
expand: "展开 {name} 额度", collapse: "收起 {name} 额度",
|
|
68
89
|
};
|
|
69
90
|
|
|
70
91
|
/** Green under 60%, amber under 85%, red above. */
|
|
@@ -151,6 +172,18 @@ window.__ModuleLoader__.load({
|
|
|
151
172
|
const activeProvider = props.useModelSelection((snapshot) => snapshot.current?.provider ?? null);
|
|
152
173
|
const wrapRef = react.useRef(null);
|
|
153
174
|
const [pos, setPos] = react.useState(null);
|
|
175
|
+
/**
|
|
176
|
+
* Which provider blocks the reader has explicitly opened or closed, by id.
|
|
177
|
+
*
|
|
178
|
+
* Only the route serving the current model is open by default; the rest
|
|
179
|
+
* fold away but stay one click from their numbers. An override is dropped
|
|
180
|
+
* when the selection changes, so switching model re-applies that default
|
|
181
|
+
* instead of stranding an unrelated block open.
|
|
182
|
+
*/
|
|
183
|
+
const [openOverrides, setOpenOverrides] = react.useState({});
|
|
184
|
+
react.useEffect(() => {
|
|
185
|
+
setOpenOverrides({});
|
|
186
|
+
}, [activeProvider]);
|
|
154
187
|
react.useEffect(() => {
|
|
155
188
|
props.start();
|
|
156
189
|
props.ensureSelection();
|
|
@@ -241,35 +274,69 @@ window.__ModuleLoader__.load({
|
|
|
241
274
|
style: pos === null ? { left: "16px", bottom: "72px" } : { left: pos.left + "px", top: pos.top + "px", width: pos.width + "px", transform: pos.transform },
|
|
242
275
|
children: [
|
|
243
276
|
jsx("p", { className: "ltk_title", children: t("title") }),
|
|
244
|
-
...ordered.map((entry) =>
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
entry
|
|
256
|
-
|
|
257
|
-
|
|
277
|
+
...ordered.map((entry) => {
|
|
278
|
+
// Default: only the route serving the current model is open, because
|
|
279
|
+
// that is the one number this session is actually spending. With no
|
|
280
|
+
// model-selection service there is no "current", so everything opens,
|
|
281
|
+
// matching the union-of-all-routes fallback the badge already uses.
|
|
282
|
+
const defaultOpen = activeProvider === null || covers(entry, activeProvider);
|
|
283
|
+
const open = openOverrides[entry.provider] ?? defaultOpen;
|
|
284
|
+
// A collapsed row still carries its first two windows, so folding a
|
|
285
|
+
// route away costs the detail but not the glance.
|
|
286
|
+
const summary = entry.usage === null ? [] : entry.usage.windows.map((w) => Math.round(w.used * 100)).slice(0, 2);
|
|
287
|
+
return jsxs("div", {
|
|
288
|
+
className: activeProvider !== null && !covers(entry, activeProvider) ? "ltk_prov ltk_provDim" : "ltk_prov",
|
|
289
|
+
children: [
|
|
290
|
+
jsxs("button", {
|
|
291
|
+
type: "button",
|
|
292
|
+
className: open ? "ltk_provHead ltk_provToggle" : "ltk_provHead ltk_provToggle ltk_provFlat",
|
|
293
|
+
"aria-expanded": open,
|
|
294
|
+
title: t(open ? "collapse" : "expand", { name: entry.displayName }),
|
|
295
|
+
onClick: () => setOpenOverrides((prev) => ({ ...prev, [entry.provider]: !open })),
|
|
258
296
|
children: [
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
: jsx("
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
297
|
+
jsx("svg", {
|
|
298
|
+
className: open ? "ltk_chev ltk_chevOpen" : "ltk_chev",
|
|
299
|
+
viewBox: "5.2 3.04 9.7 9.7",
|
|
300
|
+
"aria-hidden": "true",
|
|
301
|
+
// non-scaling-stroke keeps the 1.5px weight the icon was drawn with,
|
|
302
|
+
// independent of how far the cropped viewBox is scaled up.
|
|
303
|
+
children: jsx("path", {
|
|
304
|
+
d: "M8 3.79297L12.1012 7.89419L8 11.9954",
|
|
305
|
+
fill: "none",
|
|
306
|
+
stroke: "currentColor",
|
|
307
|
+
strokeWidth: 1.5,
|
|
308
|
+
strokeLinecap: "round",
|
|
309
|
+
strokeLinejoin: "round",
|
|
310
|
+
vectorEffect: "non-scaling-stroke",
|
|
311
|
+
}),
|
|
312
|
+
}),
|
|
313
|
+
jsx("span", { className: "ltk_provName", children: entry.displayName }),
|
|
314
|
+
activeProvider === null || !covers(entry, activeProvider) ? null : jsx("span", { className: "ltk_cur", children: t("current") }),
|
|
315
|
+
entry.usage?.plan === undefined ? null : jsx("span", { className: "ltk_plan", children: entry.usage.plan }),
|
|
316
|
+
open || summary.length === 0 ? null : jsx("span", { className: "ltk_sum", children: summary.map((p) => p + "%").join(" · ") }),
|
|
269
317
|
],
|
|
270
318
|
}),
|
|
271
|
-
|
|
272
|
-
|
|
319
|
+
!open
|
|
320
|
+
? null
|
|
321
|
+
: entry.usage === null
|
|
322
|
+
? jsx("p", { className: "ltk_hint", children: t("empty") })
|
|
323
|
+
: jsxs("div", {
|
|
324
|
+
children: [
|
|
325
|
+
// Keyed by position: a provider may report two windows of the
|
|
326
|
+
// same kind (GLM sends two token windows), so the label is not
|
|
327
|
+
// unique and the order is stable.
|
|
328
|
+
...entry.usage.windows.map((w, index) => jsx(UsageRow, { t, entry: w }, index)),
|
|
329
|
+
entry.usage.credits === undefined || entry.usage.creditsUnlimited === true
|
|
330
|
+
? null
|
|
331
|
+
: jsx("p", { className: "ltk_hint", children: t("credits", { balance: String(entry.usage.credits) }) }),
|
|
332
|
+
agoOf(entry.usage.at).length === 0
|
|
333
|
+
? null
|
|
334
|
+
: jsx("p", { className: "ltk_hint", children: t("readAt", { when: agoOf(entry.usage.at) }) }),
|
|
335
|
+
],
|
|
336
|
+
}),
|
|
337
|
+
],
|
|
338
|
+
}, entry.provider);
|
|
339
|
+
}),
|
|
273
340
|
],
|
|
274
341
|
}),
|
|
275
342
|
],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-llm-local-token",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "DeepSeek Harness plugin: serve LLM calls with the OAuth tokens your local Codex CLI and Claude Code already hold, instead of a separately configured API key — plus a composer badge showing subscription usage for those routes and for GLM Coding Plan.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|