dsh-qoder-connect 0.2.3 → 0.2.4
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/lib/bin.js +1 -1
- package/lib/client.js +177 -129
- package/lib/index.js +1 -1
- package/lib/{variants-BgysmR2W.js → variants-OJKPI_c7.js} +1 -1
- package/package.json +1 -1
package/lib/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { D as QoderCatalogStore, O as qoderCatalogPath, U as qoderCredentialIdentity, V as QoderCredentialStore, b as createQoderTransport, f as QODER_CONNECT_VERSION, i as variantFor, k as FALLBACK_QODER_MODELS, l as qoderHostHeartbeatPath, m as QoderUpstreamClient, r as QODER_VARIANTS, s as isHeartbeatProcessAlive, t as CHINA_VARIANT, u as readHostHeartbeat, y as validateApiKey } from "./variants-
|
|
2
|
+
import { D as QoderCatalogStore, O as qoderCatalogPath, U as qoderCredentialIdentity, V as QoderCredentialStore, b as createQoderTransport, f as QODER_CONNECT_VERSION, i as variantFor, k as FALLBACK_QODER_MODELS, l as qoderHostHeartbeatPath, m as QoderUpstreamClient, r as QODER_VARIANTS, s as isHeartbeatProcessAlive, t as CHINA_VARIANT, u as readHostHeartbeat, y as validateApiKey } from "./variants-OJKPI_c7.js";
|
|
3
3
|
import { readFile } from "node:fs/promises";
|
|
4
4
|
import { realpathSync } from "node:fs";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
package/lib/client.js
CHANGED
|
@@ -40,6 +40,169 @@ window.__ModuleLoader__.load({
|
|
|
40
40
|
const QODER_GLOBAL_PROBE_PATH = "/plugins/dsh-qoder-connect/global/probe";
|
|
41
41
|
const QODER_GLOBAL_AUTH_PATH = "/plugins/dsh-qoder-connect/global/auth";
|
|
42
42
|
//#endregion
|
|
43
|
+
//#region src/client/quota-merge.ts
|
|
44
|
+
/**
|
|
45
|
+
* Group credit accounts by (packageName, packageEndTime) and sum each group.
|
|
46
|
+
*
|
|
47
|
+
* A missing figure counts as 0 (the user's ruling): a package whose total the
|
|
48
|
+
* upstream did not report contributes nothing to the group's `size` rather
|
|
49
|
+
* than poisoning the bar into "unknown". A group whose summed `size` is still
|
|
50
|
+
* 0 keeps an honest "unknown total" rendering in the card — the merge never
|
|
51
|
+
* invents a denominator. `unlimited` is sticky: one unlimited member makes the
|
|
52
|
+
* whole group unlimited, and its sums are not displayed as a quota.
|
|
53
|
+
*
|
|
54
|
+
* MERGE KEY IS THE NAME ALONE (the user's correction): same-named packages
|
|
55
|
+
* whose expiries differ by seconds (stacked purchase batches) must still be
|
|
56
|
+
* one overview row — keying on the expiry exploded 28 same-named packages
|
|
57
|
+
* back into 28 separate bars the moment the host started reporting real
|
|
58
|
+
* dates. The expiry travels on the group (earliest of the members) for the
|
|
59
|
+
* sort/visibility rules; the itemised per-expiry breakdown lives in the
|
|
60
|
+
* dashboard's table.
|
|
61
|
+
*
|
|
62
|
+
* @param accounts - the status document's per-package credit entries.
|
|
63
|
+
* @returns one group per distinct package NAME, in first-seen order.
|
|
64
|
+
*/
|
|
65
|
+
function mergeCreditAccounts(accounts) {
|
|
66
|
+
const groups = /* @__PURE__ */ new Map();
|
|
67
|
+
for (const account of accounts) {
|
|
68
|
+
const key = account.packageName;
|
|
69
|
+
const existing = groups.get(key);
|
|
70
|
+
if (existing === void 0) {
|
|
71
|
+
groups.set(key, {
|
|
72
|
+
packageName: account.packageName,
|
|
73
|
+
packageEndTime: account.packageEndTime,
|
|
74
|
+
remain: account.remain,
|
|
75
|
+
size: account.size,
|
|
76
|
+
unlimited: account.unlimited === true
|
|
77
|
+
});
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
existing.remain += account.remain;
|
|
81
|
+
existing.size += account.size;
|
|
82
|
+
existing.unlimited = existing.unlimited || account.unlimited === true;
|
|
83
|
+
if (existing.packageEndTime !== void 0 && account.packageEndTime !== void 0) {
|
|
84
|
+
const a = Date.parse(existing.packageEndTime);
|
|
85
|
+
const b = Date.parse(account.packageEndTime);
|
|
86
|
+
if (!Number.isNaN(a) && !Number.isNaN(b) && b < a) existing.packageEndTime = account.packageEndTime;
|
|
87
|
+
} else existing.packageEndTime = existing.packageEndTime ?? account.packageEndTime;
|
|
88
|
+
}
|
|
89
|
+
return [...groups.values()];
|
|
90
|
+
}
|
|
91
|
+
/** Clamp helper shared by the card's percent math. */
|
|
92
|
+
function clampPercent(remain, size) {
|
|
93
|
+
if (!(size > 0)) return void 0;
|
|
94
|
+
const percent = remain / size * 100;
|
|
95
|
+
if (!Number.isFinite(percent)) return void 0;
|
|
96
|
+
return Math.min(100, Math.max(0, percent));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The percent format every surface prints a RATIO with: at most two decimals,
|
|
100
|
+
* with a whole value left whole — "100", never "100.00".
|
|
101
|
+
*
|
|
102
|
+
* Both cards show the SAME package, so they must print the SAME number: while
|
|
103
|
+
* the sidebar rounded to whole percent and the settings card kept one decimal,
|
|
104
|
+
* 2,291 / 2,300 read "100%" in one place and "99.6%" in the other, and the two
|
|
105
|
+
* surfaces contradicted each other about one figure.
|
|
106
|
+
*
|
|
107
|
+
* Two decimals, not a fixed two: the padding would buy no accuracy, and the
|
|
108
|
+
* sidebar's percent column is 38px wide, where "99.61%" measures 36px while
|
|
109
|
+
* "100.00%" measures 42px.
|
|
110
|
+
*
|
|
111
|
+
* @param percent - an already-clamped percentage value.
|
|
112
|
+
* @returns the percent as text, without the trailing sign.
|
|
113
|
+
*/
|
|
114
|
+
function formatPercentText(percent) {
|
|
115
|
+
return new Intl.NumberFormat(void 0, { maximumFractionDigits: 2 }).format(percent);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The same ratio read the other way round: the cycle's USED percentage as a
|
|
119
|
+
* bare number string ("3"), ready for the `quotaPackageUsed` copy.
|
|
120
|
+
*
|
|
121
|
+
* Both surfaces that print it call this ONE function — the sidebar card's label
|
|
122
|
+
* suffix and the settings card's credit bar — because they must never disagree
|
|
123
|
+
* about the same package.
|
|
124
|
+
*
|
|
125
|
+
* Unlike {@link formatPercentText}, this one stays whole percent on purpose:
|
|
126
|
+
* the suffix rides inside the package label, and at two decimals the sidebar's
|
|
127
|
+
* label measures 105px against the 93px its row can spare, which would ellipsize
|
|
128
|
+
* the very suffix it exists to show.
|
|
129
|
+
*
|
|
130
|
+
* Derived from remain/size rather than read from the upstream's per-package
|
|
131
|
+
* `used`: the transport normalizes `remaining` from `used`, so the value is the
|
|
132
|
+
* same, while a package the upstream reports without `used` normalizes to a
|
|
133
|
+
* literal 0 — adopting that field would print "已使用0%" under a half-empty bar.
|
|
134
|
+
*
|
|
135
|
+
* @param remain - the package's remaining credit.
|
|
136
|
+
* @param size - the package's granted total; a non-positive size has no ratio.
|
|
137
|
+
* @returns the used percentage as a bare number string, or undefined when there is no ratio to state.
|
|
138
|
+
*/
|
|
139
|
+
function usedPercentText(remain, size) {
|
|
140
|
+
const percent = clampPercent(remain, size);
|
|
141
|
+
return percent === void 0 ? void 0 : String(Math.round(100 - percent));
|
|
142
|
+
}
|
|
143
|
+
/** Parse an upstream expiry string ("YYYY-MM-DD HH:mm:ss") into a timestamp; undefined when unparseable. */
|
|
144
|
+
function parseExpiry(value) {
|
|
145
|
+
if (value === void 0) return void 0;
|
|
146
|
+
const parsed = Date.parse(value);
|
|
147
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
148
|
+
}
|
|
149
|
+
/** Whether a group is spent (remain 0) and NOT unlimited. */
|
|
150
|
+
function isSpent(group) {
|
|
151
|
+
return !group.unlimited && group.remain <= 0;
|
|
152
|
+
}
|
|
153
|
+
/** Whether a spent group's expiry date has already passed (undated → false: no proof of expiry). */
|
|
154
|
+
function isExpired(group, now) {
|
|
155
|
+
if (!isSpent(group)) return false;
|
|
156
|
+
const expiry = parseExpiry(group.packageEndTime);
|
|
157
|
+
return expiry !== void 0 && expiry < now;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* SIDEBAR overview rule (the user's spec, restored after it was wrongly
|
|
161
|
+
* applied to the panel):
|
|
162
|
+
*
|
|
163
|
+
* - A group with credit LEFT (remain > 0, or unlimited) renders.
|
|
164
|
+
* - A SPENT group (remain 0) renders ONLY when EVERY group is spent AND it
|
|
165
|
+
* is not expired — the account's standing quota whose emptiness is itself
|
|
166
|
+
* the news. When anything still has credit, spent rows are noise.
|
|
167
|
+
* - An EXPIRED group (spent and its expiry date has passed) renders
|
|
168
|
+
* NOWHERE, whatever the rest of the account looks like.
|
|
169
|
+
*
|
|
170
|
+
* Applied AFTER the merge so the sums are settled before the test.
|
|
171
|
+
* "Now" is injectable for tests.
|
|
172
|
+
*
|
|
173
|
+
* @param groups - merged groups, in first-seen order.
|
|
174
|
+
* @param now - current timestamp (defaults to Date.now()).
|
|
175
|
+
* @returns the groups to display, in first-seen order.
|
|
176
|
+
*/
|
|
177
|
+
function visibleQuotaGroups(groups, now = Date.now()) {
|
|
178
|
+
const hasCredit = groups.some((group) => group.unlimited || group.remain > 0);
|
|
179
|
+
return groups.filter((group) => {
|
|
180
|
+
if (group.unlimited || group.remain > 0) return true;
|
|
181
|
+
return !hasCredit && !isExpired(group, now);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* PANEL detail-table ordering (the user's spec): every row renders — the
|
|
186
|
+
* panel is the itemised ledger — but spent-yet-still-active rows sink to the
|
|
187
|
+
* BOTTOM (lowest priority), and expired rows are dropped entirely. Rows keep
|
|
188
|
+
* their first-seen order within each band.
|
|
189
|
+
*
|
|
190
|
+
* @param rows - per-package rows, unmerged, in first-seen order.
|
|
191
|
+
* @param now - current timestamp (defaults to Date.now()).
|
|
192
|
+
*/
|
|
193
|
+
function sortPackageRows(rows, now = Date.now()) {
|
|
194
|
+
const live = [];
|
|
195
|
+
const spent = [];
|
|
196
|
+
for (const row of rows) {
|
|
197
|
+
const unlimited = row.unlimited === true;
|
|
198
|
+
const expiry = parseExpiry(row.packageEndTime);
|
|
199
|
+
if (!unlimited && row.remain <= 0 && expiry !== void 0 && expiry < now) continue;
|
|
200
|
+
if (unlimited || row.remain > 0) live.push(row);
|
|
201
|
+
else spent.push(row);
|
|
202
|
+
}
|
|
203
|
+
return [...live, ...spent];
|
|
204
|
+
}
|
|
205
|
+
//#endregion
|
|
43
206
|
//#region src/client/status-document.ts
|
|
44
207
|
/**
|
|
45
208
|
* Whether a parsed status response really is a status document.
|
|
@@ -1235,9 +1398,6 @@ window.__ModuleLoader__.load({
|
|
|
1235
1398
|
function formatNumber(value) {
|
|
1236
1399
|
return new Intl.NumberFormat(void 0).format(value);
|
|
1237
1400
|
}
|
|
1238
|
-
function formatPercent(value) {
|
|
1239
|
-
return new Intl.NumberFormat(void 0, { maximumFractionDigits: 1 }).format(value);
|
|
1240
|
-
}
|
|
1241
1401
|
function formatTime(ms) {
|
|
1242
1402
|
return new Intl.DateTimeFormat(void 0, {
|
|
1243
1403
|
dateStyle: "medium",
|
|
@@ -1301,13 +1461,14 @@ window.__ModuleLoader__.load({
|
|
|
1301
1461
|
size: formatNumber(size)
|
|
1302
1462
|
}) : t("creditPackageUnknownSize", { remain: formatNumber(remain) });
|
|
1303
1463
|
const percent = sizeKnown ? remain / size * 100 : void 0;
|
|
1304
|
-
const display = percent === void 0 ? t("percentUnknown") : t("percentRemaining", { percent:
|
|
1464
|
+
const display = percent === void 0 ? t("percentUnknown") : t("percentRemaining", { percent: formatPercentText(percent) });
|
|
1465
|
+
const usedPercent = usedPercentText(remain, size);
|
|
1305
1466
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1306
1467
|
style: quotaGroupStyle,
|
|
1307
1468
|
children: [
|
|
1308
1469
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1309
1470
|
style: quotaLabelStyle,
|
|
1310
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1471
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [label, usedPercent === void 0 ? null : t("quotaPackageUsed", { percent: usedPercent })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: display })]
|
|
1311
1472
|
}),
|
|
1312
1473
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1313
1474
|
style: progressTrackStyle,
|
|
@@ -2450,7 +2611,7 @@ window.__ModuleLoader__.load({
|
|
|
2450
2611
|
children: t("creditsHeading")
|
|
2451
2612
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2452
2613
|
style: bodyStyle,
|
|
2453
|
-
children: status.credits.unlimited === true ? t("creditsTotalUnlimited") : t("creditsUsed", { percent:
|
|
2614
|
+
children: status.credits.unlimited === true ? t("creditsTotalUnlimited") : t("creditsUsed", { percent: formatPercentText(status.credits.total) })
|
|
2454
2615
|
})]
|
|
2455
2616
|
}), status.credits.cycleResetTime === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2456
2617
|
style: descriptionStyle,
|
|
@@ -3080,124 +3241,6 @@ window.__ModuleLoader__.load({
|
|
|
3080
3241
|
}
|
|
3081
3242
|
};
|
|
3082
3243
|
//#endregion
|
|
3083
|
-
//#region src/client/quota-merge.ts
|
|
3084
|
-
/**
|
|
3085
|
-
* Group credit accounts by (packageName, packageEndTime) and sum each group.
|
|
3086
|
-
*
|
|
3087
|
-
* A missing figure counts as 0 (the user's ruling): a package whose total the
|
|
3088
|
-
* upstream did not report contributes nothing to the group's `size` rather
|
|
3089
|
-
* than poisoning the bar into "unknown". A group whose summed `size` is still
|
|
3090
|
-
* 0 keeps an honest "unknown total" rendering in the card — the merge never
|
|
3091
|
-
* invents a denominator. `unlimited` is sticky: one unlimited member makes the
|
|
3092
|
-
* whole group unlimited, and its sums are not displayed as a quota.
|
|
3093
|
-
*
|
|
3094
|
-
* MERGE KEY IS THE NAME ALONE (the user's correction): same-named packages
|
|
3095
|
-
* whose expiries differ by seconds (stacked purchase batches) must still be
|
|
3096
|
-
* one overview row — keying on the expiry exploded 28 same-named packages
|
|
3097
|
-
* back into 28 separate bars the moment the host started reporting real
|
|
3098
|
-
* dates. The expiry travels on the group (earliest of the members) for the
|
|
3099
|
-
* sort/visibility rules; the itemised per-expiry breakdown lives in the
|
|
3100
|
-
* dashboard's table.
|
|
3101
|
-
*
|
|
3102
|
-
* @param accounts - the status document's per-package credit entries.
|
|
3103
|
-
* @returns one group per distinct package NAME, in first-seen order.
|
|
3104
|
-
*/
|
|
3105
|
-
function mergeCreditAccounts(accounts) {
|
|
3106
|
-
const groups = /* @__PURE__ */ new Map();
|
|
3107
|
-
for (const account of accounts) {
|
|
3108
|
-
const key = account.packageName;
|
|
3109
|
-
const existing = groups.get(key);
|
|
3110
|
-
if (existing === void 0) {
|
|
3111
|
-
groups.set(key, {
|
|
3112
|
-
packageName: account.packageName,
|
|
3113
|
-
packageEndTime: account.packageEndTime,
|
|
3114
|
-
remain: account.remain,
|
|
3115
|
-
size: account.size,
|
|
3116
|
-
unlimited: account.unlimited === true
|
|
3117
|
-
});
|
|
3118
|
-
continue;
|
|
3119
|
-
}
|
|
3120
|
-
existing.remain += account.remain;
|
|
3121
|
-
existing.size += account.size;
|
|
3122
|
-
existing.unlimited = existing.unlimited || account.unlimited === true;
|
|
3123
|
-
if (existing.packageEndTime !== void 0 && account.packageEndTime !== void 0) {
|
|
3124
|
-
const a = Date.parse(existing.packageEndTime);
|
|
3125
|
-
const b = Date.parse(account.packageEndTime);
|
|
3126
|
-
if (!Number.isNaN(a) && !Number.isNaN(b) && b < a) existing.packageEndTime = account.packageEndTime;
|
|
3127
|
-
} else existing.packageEndTime = existing.packageEndTime ?? account.packageEndTime;
|
|
3128
|
-
}
|
|
3129
|
-
return [...groups.values()];
|
|
3130
|
-
}
|
|
3131
|
-
/** Clamp helper shared by the card's percent math. */
|
|
3132
|
-
function clampPercent(remain, size) {
|
|
3133
|
-
if (!(size > 0)) return void 0;
|
|
3134
|
-
const percent = remain / size * 100;
|
|
3135
|
-
if (!Number.isFinite(percent)) return void 0;
|
|
3136
|
-
return Math.min(100, Math.max(0, percent));
|
|
3137
|
-
}
|
|
3138
|
-
/** Parse an upstream expiry string ("YYYY-MM-DD HH:mm:ss") into a timestamp; undefined when unparseable. */
|
|
3139
|
-
function parseExpiry(value) {
|
|
3140
|
-
if (value === void 0) return void 0;
|
|
3141
|
-
const parsed = Date.parse(value);
|
|
3142
|
-
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
3143
|
-
}
|
|
3144
|
-
/** Whether a group is spent (remain 0) and NOT unlimited. */
|
|
3145
|
-
function isSpent(group) {
|
|
3146
|
-
return !group.unlimited && group.remain <= 0;
|
|
3147
|
-
}
|
|
3148
|
-
/** Whether a spent group's expiry date has already passed (undated → false: no proof of expiry). */
|
|
3149
|
-
function isExpired(group, now) {
|
|
3150
|
-
if (!isSpent(group)) return false;
|
|
3151
|
-
const expiry = parseExpiry(group.packageEndTime);
|
|
3152
|
-
return expiry !== void 0 && expiry < now;
|
|
3153
|
-
}
|
|
3154
|
-
/**
|
|
3155
|
-
* SIDEBAR overview rule (the user's spec, restored after it was wrongly
|
|
3156
|
-
* applied to the panel):
|
|
3157
|
-
*
|
|
3158
|
-
* - A group with credit LEFT (remain > 0, or unlimited) renders.
|
|
3159
|
-
* - A SPENT group (remain 0) renders ONLY when EVERY group is spent AND it
|
|
3160
|
-
* is not expired — the account's standing quota whose emptiness is itself
|
|
3161
|
-
* the news. When anything still has credit, spent rows are noise.
|
|
3162
|
-
* - An EXPIRED group (spent and its expiry date has passed) renders
|
|
3163
|
-
* NOWHERE, whatever the rest of the account looks like.
|
|
3164
|
-
*
|
|
3165
|
-
* Applied AFTER the merge so the sums are settled before the test.
|
|
3166
|
-
* "Now" is injectable for tests.
|
|
3167
|
-
*
|
|
3168
|
-
* @param groups - merged groups, in first-seen order.
|
|
3169
|
-
* @param now - current timestamp (defaults to Date.now()).
|
|
3170
|
-
* @returns the groups to display, in first-seen order.
|
|
3171
|
-
*/
|
|
3172
|
-
function visibleQuotaGroups(groups, now = Date.now()) {
|
|
3173
|
-
const hasCredit = groups.some((group) => group.unlimited || group.remain > 0);
|
|
3174
|
-
return groups.filter((group) => {
|
|
3175
|
-
if (group.unlimited || group.remain > 0) return true;
|
|
3176
|
-
return !hasCredit && !isExpired(group, now);
|
|
3177
|
-
});
|
|
3178
|
-
}
|
|
3179
|
-
/**
|
|
3180
|
-
* PANEL detail-table ordering (the user's spec): every row renders — the
|
|
3181
|
-
* panel is the itemised ledger — but spent-yet-still-active rows sink to the
|
|
3182
|
-
* BOTTOM (lowest priority), and expired rows are dropped entirely. Rows keep
|
|
3183
|
-
* their first-seen order within each band.
|
|
3184
|
-
*
|
|
3185
|
-
* @param rows - per-package rows, unmerged, in first-seen order.
|
|
3186
|
-
* @param now - current timestamp (defaults to Date.now()).
|
|
3187
|
-
*/
|
|
3188
|
-
function sortPackageRows(rows, now = Date.now()) {
|
|
3189
|
-
const live = [];
|
|
3190
|
-
const spent = [];
|
|
3191
|
-
for (const row of rows) {
|
|
3192
|
-
const unlimited = row.unlimited === true;
|
|
3193
|
-
const expiry = parseExpiry(row.packageEndTime);
|
|
3194
|
-
if (!unlimited && row.remain <= 0 && expiry !== void 0 && expiry < now) continue;
|
|
3195
|
-
if (unlimited || row.remain > 0) live.push(row);
|
|
3196
|
-
else spent.push(row);
|
|
3197
|
-
}
|
|
3198
|
-
return [...live, ...spent];
|
|
3199
|
-
}
|
|
3200
|
-
//#endregion
|
|
3201
3244
|
//#region src/client/SidebarQuotaCard.tsx
|
|
3202
3245
|
/**
|
|
3203
3246
|
* The sidebar footer quota card + the center-column dashboard it opens.
|
|
@@ -3238,7 +3281,8 @@ window.__ModuleLoader__.load({
|
|
|
3238
3281
|
bars.push({
|
|
3239
3282
|
label: group.packageName,
|
|
3240
3283
|
detail,
|
|
3241
|
-
percent: percent === void 0 ? void 0 : `${
|
|
3284
|
+
percent: percent === void 0 ? void 0 : `${formatPercentText(percent)}%`,
|
|
3285
|
+
usedPercent: usedPercentText(group.remain, group.size),
|
|
3242
3286
|
barPercent: percent === void 0 ? 0 : Math.max(2, percent),
|
|
3243
3287
|
warn: !group.unlimited && percent !== void 0 && percent < 20,
|
|
3244
3288
|
packageEndTime: group.packageEndTime
|
|
@@ -3345,7 +3389,7 @@ window.__ModuleLoader__.load({
|
|
|
3345
3389
|
const fetchedAt = quotaStatusFetchedAt(variantId);
|
|
3346
3390
|
const title = [
|
|
3347
3391
|
t(nameKey),
|
|
3348
|
-
...bars.map((bar) => `${bar.label} ${bar.detail}${bar.percent === void 0 ? "" : ` (${bar.percent})`}`),
|
|
3392
|
+
...bars.map((bar) => `${bar.label} ${bar.detail}${bar.percent === void 0 ? "" : ` (${bar.percent})`}${bar.usedPercent === void 0 ? "" : ` ${t("quotaPackageUsed", { percent: bar.usedPercent })}`}`),
|
|
3349
3393
|
fetchedAt !== void 0 ? `${t("quotaUpdated")} ${timeText(fetchedAt)}` : ""
|
|
3350
3394
|
].filter((part) => part !== "").join(" · ");
|
|
3351
3395
|
if (!wide) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -3413,10 +3457,10 @@ window.__ModuleLoader__.load({
|
|
|
3413
3457
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3414
3458
|
className: "qdp-footHead",
|
|
3415
3459
|
children: [
|
|
3416
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3460
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3417
3461
|
className: "qdp-footLabel",
|
|
3418
3462
|
title: bar.packageEndTime !== void 0 ? `${t("quotaExpires")} ${bar.packageEndTime}` : t("quotaNoExpiry"),
|
|
3419
|
-
children: bar.label
|
|
3463
|
+
children: [bar.label, bar.usedPercent === void 0 ? null : t("quotaPackageUsed", { percent: bar.usedPercent })]
|
|
3420
3464
|
}),
|
|
3421
3465
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3422
3466
|
className: "qdp-footAmount",
|
|
@@ -3740,7 +3784,9 @@ window.__ModuleLoader__.load({
|
|
|
3740
3784
|
.qdp-footBar{display:block;background:var(--dsw-alias-bg-layer-2);border-radius:999px;height:5px;overflow:hidden}
|
|
3741
3785
|
.qdp-footFill{display:block;background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}
|
|
3742
3786
|
.qdp-footFillWarn{background:var(--dsw-alias-state-error-primary)}
|
|
3743
|
-
|
|
3787
|
+
/* 38px, not 34px: two-decimal copy is wider, and "99.61%" measures 36px in this
|
|
3788
|
+
font. nowrap keeps a long value from wrapping the row into a second line. */
|
|
3789
|
+
.qdp-footPct{flex:none;width:38px;color:var(--dsw-alias-label-secondary);text-align:right;font-size:11px;line-height:16px;font-variant-numeric:tabular-nums;white-space:nowrap}
|
|
3744
3790
|
|
|
3745
3791
|
/* The 56px rail: one icon button on the shell's own rail geometry (36px cell),
|
|
3746
3792
|
so the collapsed column keeps a single glyph like its siblings. */
|
|
@@ -4001,6 +4047,7 @@ window.__ModuleLoader__.load({
|
|
|
4001
4047
|
quotaTotalRemain: "Remaining",
|
|
4002
4048
|
quotaTotalShare: "{percent} of this cycle’s granted total ({remain} / {size})",
|
|
4003
4049
|
quotaCycleUsed: "Used this cycle: {percent}%",
|
|
4050
|
+
quotaPackageUsed: "(used {percent}%)",
|
|
4004
4051
|
quotaColPackage: "Package",
|
|
4005
4052
|
quotaColRemain: "Remaining / Total",
|
|
4006
4053
|
quotaColExpiry: "Expires"
|
|
@@ -4173,6 +4220,7 @@ window.__ModuleLoader__.load({
|
|
|
4173
4220
|
quotaTotalRemain: "剩余额度",
|
|
4174
4221
|
quotaTotalShare: "占本轮总额度 {percent}({remain} / {size})",
|
|
4175
4222
|
quotaCycleUsed: "本轮已用 {percent}%",
|
|
4223
|
+
quotaPackageUsed: "(已使用{percent}%)",
|
|
4176
4224
|
quotaColPackage: "资源包",
|
|
4177
4225
|
quotaColRemain: "剩余 / 总量",
|
|
4178
4226
|
quotaColExpiry: "到期时间"
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as QoderCatalog, B as QODER_PAT_ENV_GLOBAL, C as getMachineId, D as QoderCatalogStore, E as randomSentinel, F as QODER_PROBE_PATH, G as QODER_DATA_DIR_ENV, H as patTail, I as QODER_SETTINGS_FACE_PATH, J as qoderPluginDataDir, K as QODER_DATA_DIR_NAME, L as QODER_STATUS_PATH, M as QODER_GLOBAL_AUTH_PATH, N as QODER_GLOBAL_PROBE_PATH, O as qoderCatalogPath, P as QODER_GLOBAL_STATUS_PATH, R as QODER_AUTH_FILENAME, S as utc8WallClock, T as probeModel, U as qoderCredentialIdentity, V as QoderCredentialStore, W as qoderOwnAuthPath, Y as qoderStateDir, _ as modelInfoOf, a as QODER_HOST_HEARTBEAT_FILENAME, b as createQoderTransport, c as processStartTimeMs, d as writeHostHeartbeat, f as QODER_CONNECT_VERSION, g as kindFromQoderFailure, h as classifyUpstreamError, i as variantFor, j as QODER_AUTH_PATH, k as FALLBACK_QODER_MODELS, l as qoderHostHeartbeatPath, m as QoderUpstreamClient, n as GLOBAL_VARIANT, o as clearHostHeartbeat, p as KIND_STATUS, q as qoderMachineIdPath, r as QODER_VARIANTS, s as isHeartbeatProcessAlive, t as CHINA_VARIANT, u as readHostHeartbeat, v as normalizeCredits, w as PROBE_EFFORT_CANDIDATES, x as formatUtc8Date, y as validateApiKey, z as QODER_PAT_ENV_CN } from "./variants-
|
|
1
|
+
import { A as QoderCatalog, B as QODER_PAT_ENV_GLOBAL, C as getMachineId, D as QoderCatalogStore, E as randomSentinel, F as QODER_PROBE_PATH, G as QODER_DATA_DIR_ENV, H as patTail, I as QODER_SETTINGS_FACE_PATH, J as qoderPluginDataDir, K as QODER_DATA_DIR_NAME, L as QODER_STATUS_PATH, M as QODER_GLOBAL_AUTH_PATH, N as QODER_GLOBAL_PROBE_PATH, O as qoderCatalogPath, P as QODER_GLOBAL_STATUS_PATH, R as QODER_AUTH_FILENAME, S as utc8WallClock, T as probeModel, U as qoderCredentialIdentity, V as QoderCredentialStore, W as qoderOwnAuthPath, Y as qoderStateDir, _ as modelInfoOf, a as QODER_HOST_HEARTBEAT_FILENAME, b as createQoderTransport, c as processStartTimeMs, d as writeHostHeartbeat, f as QODER_CONNECT_VERSION, g as kindFromQoderFailure, h as classifyUpstreamError, i as variantFor, j as QODER_AUTH_PATH, k as FALLBACK_QODER_MODELS, l as qoderHostHeartbeatPath, m as QoderUpstreamClient, n as GLOBAL_VARIANT, o as clearHostHeartbeat, p as KIND_STATUS, q as qoderMachineIdPath, r as QODER_VARIANTS, s as isHeartbeatProcessAlive, t as CHINA_VARIANT, u as readHostHeartbeat, v as normalizeCredits, w as PROBE_EFFORT_CANDIDATES, x as formatUtc8Date, y as validateApiKey, z as QODER_PAT_ENV_CN } from "./variants-OJKPI_c7.js";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
@@ -4662,7 +4662,7 @@ const DEFAULT_MAX_TOKENS = 32768;
|
|
|
4662
4662
|
const DEFAULT_CONTEXT_WINDOW = 18e4;
|
|
4663
4663
|
//#endregion
|
|
4664
4664
|
//#region src/version.ts
|
|
4665
|
-
const QODER_CONNECT_VERSION = "0.2.
|
|
4665
|
+
const QODER_CONNECT_VERSION = "0.2.4";
|
|
4666
4666
|
//#endregion
|
|
4667
4667
|
//#region src/host-heartbeat.ts
|
|
4668
4668
|
/**
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dsh-qoder-connect",
|
|
3
3
|
"displayName": "DSH Qoder Connect",
|
|
4
4
|
"description": "将 Qoder(国内版 / 国际版)的模型接入 DeepSeek Harness — bring Qoder (CN & international) models into DeepSeek Harness.",
|
|
5
|
-
"version": "0.2.
|
|
5
|
+
"version": "0.2.4",
|
|
6
6
|
"author": "corrinehu",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"dsh-plugin",
|