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 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-BgysmR2W.js";
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: formatPercent(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.jsx)("span", { children: label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: display })]
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: formatPercent(status.credits.total) })
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 : `${Math.round(percent)}%`,
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.jsx)("span", {
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
- .qdp-footPct{flex:none;width:34px;color:var(--dsw-alias-label-secondary);text-align:right;font-size:11px;line-height:16px;font-variant-numeric:tabular-nums}
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-BgysmR2W.js";
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.3";
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.3",
5
+ "version": "0.2.4",
6
6
  "author": "corrinehu",
7
7
  "keywords": [
8
8
  "dsh-plugin",