dsh-qoder-connect 0.2.3-alpha.2 → 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 +184 -133
- package/lib/index.d.ts +3 -3
- package/lib/index.js +1 -1
- package/lib/{variants-UX2MxZaz.js → variants-OJKPI_c7.js} +2 -2
- 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,
|
|
@@ -1760,17 +1921,17 @@ window.__ModuleLoader__.load({
|
|
|
1760
1921
|
height: 6,
|
|
1761
1922
|
borderRadius: "50%",
|
|
1762
1923
|
flexShrink: 0,
|
|
1763
|
-
background: log.status === "claimed" ? "var(--dsw-alias-status-success, #52c41a)" : log.status === "already-claimed" ? "var(--dsw-alias-status-info, #1890ff)" : log.status === "no-campaign" ? "var(--dsw-alias-label-tertiary, #999)" : "var(--dsw-alias-status-error, #f5222d)"
|
|
1764
|
-
} }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: log.status === "claimed" ? t("autoCheckInStatusClaimed", { amount: log.amount ?? 100 }) : log.status === "already-claimed" ? t("autoCheckInStatusAlready") : log.status === "no-campaign" ? t("autoCheckInStatusNoCampaign") : t("autoCheckInStatusError", { message: log.message ?? "" }) })]
|
|
1924
|
+
background: log.status === "claimed" ? "var(--dsw-alias-status-success, #52c41a)" : log.status === "already-claimed" ? "var(--dsw-alias-status-info, #1890ff)" : log.status === "no-campaign" || log.status === "before-window" ? "var(--dsw-alias-label-tertiary, #999)" : "var(--dsw-alias-status-error, #f5222d)"
|
|
1925
|
+
} }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: log.status === "claimed" ? t("autoCheckInStatusClaimed", { amount: log.amount ?? 100 }) : log.status === "already-claimed" ? t("autoCheckInStatusAlready") : log.status === "no-campaign" ? t("autoCheckInStatusNoCampaign") : log.status === "before-window" ? t("autoCheckInStatusBeforeWindow") : t("autoCheckInStatusError", { message: log.message ?? "" }) })]
|
|
1765
1926
|
}),
|
|
1766
1927
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1767
1928
|
style: {
|
|
1768
1929
|
flex: 1,
|
|
1769
1930
|
textAlign: "right",
|
|
1770
1931
|
fontWeight: 600,
|
|
1771
|
-
color: log.
|
|
1932
|
+
color: log.status === "claimed" ? "var(--dsw-alias-brand-primary)" : "inherit"
|
|
1772
1933
|
},
|
|
1773
|
-
children: log.
|
|
1934
|
+
children: log.status === "claimed" ? `+${log.amount ?? 100}` : "-"
|
|
1774
1935
|
})
|
|
1775
1936
|
]
|
|
1776
1937
|
}, log.id))]
|
|
@@ -1950,6 +2111,7 @@ window.__ModuleLoader__.load({
|
|
|
1950
2111
|
if (result.state === "claimed") setCheckInNotice(t("autoCheckInStatusClaimed", { amount: result.amount ?? 100 }));
|
|
1951
2112
|
else if (result.state === "already-claimed") setCheckInNotice(t("autoCheckInStatusAlready"));
|
|
1952
2113
|
else if (result.state === "no-campaign") setCheckInNotice(t("autoCheckInStatusNoCampaign"));
|
|
2114
|
+
else if (result.state === "before-window") setCheckInNotice(t("autoCheckInStatusBeforeWindow"));
|
|
1953
2115
|
else if (result.reason) setCheckInNotice(t("autoCheckInStatusError", { message: result.reason }));
|
|
1954
2116
|
} catch (error) {
|
|
1955
2117
|
if (mounted.current && controller.signal.aborted !== true) setCheckInNotice(error instanceof Error ? error.message : t("requestFailed"));
|
|
@@ -2449,7 +2611,7 @@ window.__ModuleLoader__.load({
|
|
|
2449
2611
|
children: t("creditsHeading")
|
|
2450
2612
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2451
2613
|
style: bodyStyle,
|
|
2452
|
-
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) })
|
|
2453
2615
|
})]
|
|
2454
2616
|
}), status.credits.cycleResetTime === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2455
2617
|
style: descriptionStyle,
|
|
@@ -3079,124 +3241,6 @@ window.__ModuleLoader__.load({
|
|
|
3079
3241
|
}
|
|
3080
3242
|
};
|
|
3081
3243
|
//#endregion
|
|
3082
|
-
//#region src/client/quota-merge.ts
|
|
3083
|
-
/**
|
|
3084
|
-
* Group credit accounts by (packageName, packageEndTime) and sum each group.
|
|
3085
|
-
*
|
|
3086
|
-
* A missing figure counts as 0 (the user's ruling): a package whose total the
|
|
3087
|
-
* upstream did not report contributes nothing to the group's `size` rather
|
|
3088
|
-
* than poisoning the bar into "unknown". A group whose summed `size` is still
|
|
3089
|
-
* 0 keeps an honest "unknown total" rendering in the card — the merge never
|
|
3090
|
-
* invents a denominator. `unlimited` is sticky: one unlimited member makes the
|
|
3091
|
-
* whole group unlimited, and its sums are not displayed as a quota.
|
|
3092
|
-
*
|
|
3093
|
-
* MERGE KEY IS THE NAME ALONE (the user's correction): same-named packages
|
|
3094
|
-
* whose expiries differ by seconds (stacked purchase batches) must still be
|
|
3095
|
-
* one overview row — keying on the expiry exploded 28 same-named packages
|
|
3096
|
-
* back into 28 separate bars the moment the host started reporting real
|
|
3097
|
-
* dates. The expiry travels on the group (earliest of the members) for the
|
|
3098
|
-
* sort/visibility rules; the itemised per-expiry breakdown lives in the
|
|
3099
|
-
* dashboard's table.
|
|
3100
|
-
*
|
|
3101
|
-
* @param accounts - the status document's per-package credit entries.
|
|
3102
|
-
* @returns one group per distinct package NAME, in first-seen order.
|
|
3103
|
-
*/
|
|
3104
|
-
function mergeCreditAccounts(accounts) {
|
|
3105
|
-
const groups = /* @__PURE__ */ new Map();
|
|
3106
|
-
for (const account of accounts) {
|
|
3107
|
-
const key = account.packageName;
|
|
3108
|
-
const existing = groups.get(key);
|
|
3109
|
-
if (existing === void 0) {
|
|
3110
|
-
groups.set(key, {
|
|
3111
|
-
packageName: account.packageName,
|
|
3112
|
-
packageEndTime: account.packageEndTime,
|
|
3113
|
-
remain: account.remain,
|
|
3114
|
-
size: account.size,
|
|
3115
|
-
unlimited: account.unlimited === true
|
|
3116
|
-
});
|
|
3117
|
-
continue;
|
|
3118
|
-
}
|
|
3119
|
-
existing.remain += account.remain;
|
|
3120
|
-
existing.size += account.size;
|
|
3121
|
-
existing.unlimited = existing.unlimited || account.unlimited === true;
|
|
3122
|
-
if (existing.packageEndTime !== void 0 && account.packageEndTime !== void 0) {
|
|
3123
|
-
const a = Date.parse(existing.packageEndTime);
|
|
3124
|
-
const b = Date.parse(account.packageEndTime);
|
|
3125
|
-
if (!Number.isNaN(a) && !Number.isNaN(b) && b < a) existing.packageEndTime = account.packageEndTime;
|
|
3126
|
-
} else existing.packageEndTime = existing.packageEndTime ?? account.packageEndTime;
|
|
3127
|
-
}
|
|
3128
|
-
return [...groups.values()];
|
|
3129
|
-
}
|
|
3130
|
-
/** Clamp helper shared by the card's percent math. */
|
|
3131
|
-
function clampPercent(remain, size) {
|
|
3132
|
-
if (!(size > 0)) return void 0;
|
|
3133
|
-
const percent = remain / size * 100;
|
|
3134
|
-
if (!Number.isFinite(percent)) return void 0;
|
|
3135
|
-
return Math.min(100, Math.max(0, percent));
|
|
3136
|
-
}
|
|
3137
|
-
/** Parse an upstream expiry string ("YYYY-MM-DD HH:mm:ss") into a timestamp; undefined when unparseable. */
|
|
3138
|
-
function parseExpiry(value) {
|
|
3139
|
-
if (value === void 0) return void 0;
|
|
3140
|
-
const parsed = Date.parse(value);
|
|
3141
|
-
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
3142
|
-
}
|
|
3143
|
-
/** Whether a group is spent (remain 0) and NOT unlimited. */
|
|
3144
|
-
function isSpent(group) {
|
|
3145
|
-
return !group.unlimited && group.remain <= 0;
|
|
3146
|
-
}
|
|
3147
|
-
/** Whether a spent group's expiry date has already passed (undated → false: no proof of expiry). */
|
|
3148
|
-
function isExpired(group, now) {
|
|
3149
|
-
if (!isSpent(group)) return false;
|
|
3150
|
-
const expiry = parseExpiry(group.packageEndTime);
|
|
3151
|
-
return expiry !== void 0 && expiry < now;
|
|
3152
|
-
}
|
|
3153
|
-
/**
|
|
3154
|
-
* SIDEBAR overview rule (the user's spec, restored after it was wrongly
|
|
3155
|
-
* applied to the panel):
|
|
3156
|
-
*
|
|
3157
|
-
* - A group with credit LEFT (remain > 0, or unlimited) renders.
|
|
3158
|
-
* - A SPENT group (remain 0) renders ONLY when EVERY group is spent AND it
|
|
3159
|
-
* is not expired — the account's standing quota whose emptiness is itself
|
|
3160
|
-
* the news. When anything still has credit, spent rows are noise.
|
|
3161
|
-
* - An EXPIRED group (spent and its expiry date has passed) renders
|
|
3162
|
-
* NOWHERE, whatever the rest of the account looks like.
|
|
3163
|
-
*
|
|
3164
|
-
* Applied AFTER the merge so the sums are settled before the test.
|
|
3165
|
-
* "Now" is injectable for tests.
|
|
3166
|
-
*
|
|
3167
|
-
* @param groups - merged groups, in first-seen order.
|
|
3168
|
-
* @param now - current timestamp (defaults to Date.now()).
|
|
3169
|
-
* @returns the groups to display, in first-seen order.
|
|
3170
|
-
*/
|
|
3171
|
-
function visibleQuotaGroups(groups, now = Date.now()) {
|
|
3172
|
-
const hasCredit = groups.some((group) => group.unlimited || group.remain > 0);
|
|
3173
|
-
return groups.filter((group) => {
|
|
3174
|
-
if (group.unlimited || group.remain > 0) return true;
|
|
3175
|
-
return !hasCredit && !isExpired(group, now);
|
|
3176
|
-
});
|
|
3177
|
-
}
|
|
3178
|
-
/**
|
|
3179
|
-
* PANEL detail-table ordering (the user's spec): every row renders — the
|
|
3180
|
-
* panel is the itemised ledger — but spent-yet-still-active rows sink to the
|
|
3181
|
-
* BOTTOM (lowest priority), and expired rows are dropped entirely. Rows keep
|
|
3182
|
-
* their first-seen order within each band.
|
|
3183
|
-
*
|
|
3184
|
-
* @param rows - per-package rows, unmerged, in first-seen order.
|
|
3185
|
-
* @param now - current timestamp (defaults to Date.now()).
|
|
3186
|
-
*/
|
|
3187
|
-
function sortPackageRows(rows, now = Date.now()) {
|
|
3188
|
-
const live = [];
|
|
3189
|
-
const spent = [];
|
|
3190
|
-
for (const row of rows) {
|
|
3191
|
-
const unlimited = row.unlimited === true;
|
|
3192
|
-
const expiry = parseExpiry(row.packageEndTime);
|
|
3193
|
-
if (!unlimited && row.remain <= 0 && expiry !== void 0 && expiry < now) continue;
|
|
3194
|
-
if (unlimited || row.remain > 0) live.push(row);
|
|
3195
|
-
else spent.push(row);
|
|
3196
|
-
}
|
|
3197
|
-
return [...live, ...spent];
|
|
3198
|
-
}
|
|
3199
|
-
//#endregion
|
|
3200
3244
|
//#region src/client/SidebarQuotaCard.tsx
|
|
3201
3245
|
/**
|
|
3202
3246
|
* The sidebar footer quota card + the center-column dashboard it opens.
|
|
@@ -3237,7 +3281,8 @@ window.__ModuleLoader__.load({
|
|
|
3237
3281
|
bars.push({
|
|
3238
3282
|
label: group.packageName,
|
|
3239
3283
|
detail,
|
|
3240
|
-
percent: percent === void 0 ? void 0 : `${
|
|
3284
|
+
percent: percent === void 0 ? void 0 : `${formatPercentText(percent)}%`,
|
|
3285
|
+
usedPercent: usedPercentText(group.remain, group.size),
|
|
3241
3286
|
barPercent: percent === void 0 ? 0 : Math.max(2, percent),
|
|
3242
3287
|
warn: !group.unlimited && percent !== void 0 && percent < 20,
|
|
3243
3288
|
packageEndTime: group.packageEndTime
|
|
@@ -3344,7 +3389,7 @@ window.__ModuleLoader__.load({
|
|
|
3344
3389
|
const fetchedAt = quotaStatusFetchedAt(variantId);
|
|
3345
3390
|
const title = [
|
|
3346
3391
|
t(nameKey),
|
|
3347
|
-
...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 })}`}`),
|
|
3348
3393
|
fetchedAt !== void 0 ? `${t("quotaUpdated")} ${timeText(fetchedAt)}` : ""
|
|
3349
3394
|
].filter((part) => part !== "").join(" · ");
|
|
3350
3395
|
if (!wide) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -3412,10 +3457,10 @@ window.__ModuleLoader__.load({
|
|
|
3412
3457
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3413
3458
|
className: "qdp-footHead",
|
|
3414
3459
|
children: [
|
|
3415
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3460
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3416
3461
|
className: "qdp-footLabel",
|
|
3417
3462
|
title: bar.packageEndTime !== void 0 ? `${t("quotaExpires")} ${bar.packageEndTime}` : t("quotaNoExpiry"),
|
|
3418
|
-
children: bar.label
|
|
3463
|
+
children: [bar.label, bar.usedPercent === void 0 ? null : t("quotaPackageUsed", { percent: bar.usedPercent })]
|
|
3419
3464
|
}),
|
|
3420
3465
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3421
3466
|
className: "qdp-footAmount",
|
|
@@ -3739,7 +3784,9 @@ window.__ModuleLoader__.load({
|
|
|
3739
3784
|
.qdp-footBar{display:block;background:var(--dsw-alias-bg-layer-2);border-radius:999px;height:5px;overflow:hidden}
|
|
3740
3785
|
.qdp-footFill{display:block;background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}
|
|
3741
3786
|
.qdp-footFillWarn{background:var(--dsw-alias-state-error-primary)}
|
|
3742
|
-
|
|
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}
|
|
3743
3790
|
|
|
3744
3791
|
/* The 56px rail: one icon button on the shell's own rail geometry (36px cell),
|
|
3745
3792
|
so the collapsed column keeps a single glyph like its siblings. */
|
|
@@ -3968,6 +4015,7 @@ window.__ModuleLoader__.load({
|
|
|
3968
4015
|
autoCheckInStatusClaimed: "Checked in today (+{amount} Credits)",
|
|
3969
4016
|
autoCheckInStatusAlready: "Already checked in today",
|
|
3970
4017
|
autoCheckInStatusNoCampaign: "No active benefit campaign today",
|
|
4018
|
+
autoCheckInStatusBeforeWindow: "Benefit window not open yet",
|
|
3971
4019
|
autoCheckInStatusError: "Auto check-in error: {message}",
|
|
3972
4020
|
quotaSignInRequired: "Save a PAT for this variant first to enable this card.",
|
|
3973
4021
|
quotaPollLabel: "Refresh interval",
|
|
@@ -3999,6 +4047,7 @@ window.__ModuleLoader__.load({
|
|
|
3999
4047
|
quotaTotalRemain: "Remaining",
|
|
4000
4048
|
quotaTotalShare: "{percent} of this cycle’s granted total ({remain} / {size})",
|
|
4001
4049
|
quotaCycleUsed: "Used this cycle: {percent}%",
|
|
4050
|
+
quotaPackageUsed: "(used {percent}%)",
|
|
4002
4051
|
quotaColPackage: "Package",
|
|
4003
4052
|
quotaColRemain: "Remaining / Total",
|
|
4004
4053
|
quotaColExpiry: "Expires"
|
|
@@ -4139,6 +4188,7 @@ window.__ModuleLoader__.load({
|
|
|
4139
4188
|
autoCheckInStatusClaimed: "今日已自动签到(+{amount} Credits)",
|
|
4140
4189
|
autoCheckInStatusAlready: "今日已完成签到",
|
|
4141
4190
|
autoCheckInStatusNoCampaign: "今日无可用签到福利活动",
|
|
4191
|
+
autoCheckInStatusBeforeWindow: "签到活动尚未开启",
|
|
4142
4192
|
autoCheckInStatusError: "自动签到出错:{message}",
|
|
4143
4193
|
quotaSignInRequired: "请先为该变体保存 PAT,再开启此开关。",
|
|
4144
4194
|
quotaPollLabel: "刷新间隔",
|
|
@@ -4170,6 +4220,7 @@ window.__ModuleLoader__.load({
|
|
|
4170
4220
|
quotaTotalRemain: "剩余额度",
|
|
4171
4221
|
quotaTotalShare: "占本轮总额度 {percent}({remain} / {size})",
|
|
4172
4222
|
quotaCycleUsed: "本轮已用 {percent}%",
|
|
4223
|
+
quotaPackageUsed: "(已使用{percent}%)",
|
|
4173
4224
|
quotaColPackage: "资源包",
|
|
4174
4225
|
quotaColRemain: "剩余 / 总量",
|
|
4175
4226
|
quotaColExpiry: "到期时间"
|
package/lib/index.d.ts
CHANGED
|
@@ -269,7 +269,7 @@ type QoderWebStatus = {
|
|
|
269
269
|
checkIn?: {
|
|
270
270
|
lastDate: string;
|
|
271
271
|
lastAt: number;
|
|
272
|
-
status: 'claimed' | 'already-claimed' | 'no-campaign' | 'error';
|
|
272
|
+
status: 'claimed' | 'already-claimed' | 'before-window' | 'no-campaign' | 'error';
|
|
273
273
|
amount?: number | undefined;
|
|
274
274
|
message?: string | undefined;
|
|
275
275
|
/**
|
|
@@ -284,7 +284,7 @@ type QoderWebStatus = {
|
|
|
284
284
|
id: string;
|
|
285
285
|
date: string;
|
|
286
286
|
timestamp: number;
|
|
287
|
-
status: 'claimed' | 'already-claimed' | 'no-campaign' | 'error';
|
|
287
|
+
status: 'claimed' | 'already-claimed' | 'before-window' | 'no-campaign' | 'error';
|
|
288
288
|
amount?: number | undefined;
|
|
289
289
|
campaignKey?: string | undefined;
|
|
290
290
|
message?: string | undefined;
|
|
@@ -747,7 +747,7 @@ interface QoderCheckInResult {
|
|
|
747
747
|
variantId: string;
|
|
748
748
|
date: string;
|
|
749
749
|
timestamp: number;
|
|
750
|
-
status: 'claimed' | 'already-claimed' | 'no-campaign' | 'error';
|
|
750
|
+
status: 'claimed' | 'already-claimed' | 'before-window' | 'no-campaign' | 'error';
|
|
751
751
|
amount?: number | undefined;
|
|
752
752
|
campaignKey?: string | undefined;
|
|
753
753
|
message?: string | undefined;
|
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";
|
|
@@ -2849,7 +2849,7 @@ var QoderCheckInService = class {
|
|
|
2849
2849
|
variantId: this.variantId,
|
|
2850
2850
|
date: today,
|
|
2851
2851
|
timestamp: nowMs,
|
|
2852
|
-
status: "
|
|
2852
|
+
status: "before-window",
|
|
2853
2853
|
campaignKey: benefitCampaign.campaignKey,
|
|
2854
2854
|
message: campaignWindow.kind === "not-open" ? "Today's benefit window has not opened yet" : `Upstream is still serving the benefit window of ${campaignWindow.date}`
|
|
2855
2855
|
};
|
|
@@ -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",
|