dsh-connect-workbuddy 4.5.0 → 4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.5.1 (2026-10-14)
4
+
5
+ ### Fixes
6
+
7
+ - **`6004`(账号频率超限)在对话里被显示成「当前请求的额度已用尽」,而账号余额还剩 6,788 —— 现在那句话下面补了一句说明。**(issue #63;维护者判定:**保持不进重试**,只补文案)
8
+ - **根因(实测,不是读代码猜的)**:宿主对失败按**码**路由,而插件这条链是 —— shim 的错误响应 → pi-ai 抛出的 message → `classifyPiAiError(message)` → 宿主码 → 客户端文案。三个环节的出货代码取出来直接跑之后:`quota_exceeded` 这个拼写里的下划线**恰好命中** `@deepseek-ai/dsh-llm` 的 `isQuotaExceededError` 正则(`quota[\s_-]+exceeded` 的 `[\s_-]+` 能匹配 `_`),于是归成 `QUOTA`;而 `@deepseek-ai/dsh-client-ui-chat` 对 `QUOTA`/`ACCOUNT_QUOTA` **硬编码**成那句固定文案、并**丢弃**插件自己的 message。**这一版之前我在 #56/#61 里把它说成「插件挑了宿主认识的词」,那个解释是错的。**
9
+ - **为什么不改分类(维护者的决定,也是实测支持的)**:把拼写换成任何一个不再被 quota 正则命中的值,都会落进 `RATE_LIMIT` —— 而它在 `DEFAULT_RETRYABLE_CODES` 里(`EMPTY_RESPONSE`/`RATE_LIMIT`/`SERVER`/`TIMEOUT`/`TRANSPORT`)。按出货默认(`initialDelayMs=500`、指数退避、封顶 10s、`maxRetries=5`)这是**5 次原地重试、标称 15.5 秒退避**,而 `6004` 的恢复点在报文里明写了是**几小时后** —— 退避窗口内不可能恢复。所以「不进重试」保留,「那句话不够准确」用**补充**解决。
10
+ - **修法**:用宿主**专门为此留的扩展点** `shell.quota-notice`(链式插槽,其自有文档写着「the first entry whose selector claims its code takes over the surface」)。本插件注册一条 `select: owner => code === 'QUOTA' ? owner : null` 的链项:
11
+ - **只 claim `QUOTA`** —— 其余码(`AUTH`、`ACCOUNT_SIGNED_OUT`、`ACCOUNT_QUOTA` 等)继续走宿主自己的兜底 Toast,本插件不接管自己说不清的提示;
12
+ - **宿主那句话原样保留**(`matched.message`),补充是**第二行**而不是改写 —— 那句话在别处也显示,重写会让插件与 shell 的用词互相矛盾;
13
+ - 补充文案:**「部分模型另有每日额度限制,与积分余额无关 —— 也可能确实是本账号积分耗尽。账号池那一行会写明上游给出的恢复时刻;也可以先换个账号或换个模型继续。」** 措辞对 `QUOTA` 覆盖的**两种**情况都成立,因为上游是用中文散文区分的,而插件不允许解析它来下政策判断;中英双语都写。
14
+ - 带一个「知道了」按钮,调用宿主自己的 `dismiss`;宿主没给 `dismiss` 时只渲染文字而不崩 —— 这是**全窗口**的提示,在这里抛错会连别的插件的提示一起带走。
15
+ - **组件用本插件自己的 DOM 与样式类**,不引 `@deepseek-ai/dsh-client-ui-primitives`:客户端刻意不依赖它(那条 stale 的 `inject` 曾让整张卡片的到达依赖上宿主最易变的包,见 `tests/client-host-contract.spec.ts` 的说明),所以这里沿用本插件其它组件的做法。
16
+ - **实机核对**:构建后用 Slot 检查器读运行中的插槽树,`shell.quota-notice` 的 occupants 已包含 `dsh-connect-workbuddy-client`(`active: true`),与宿主自己的 `mf` 并列;插槽目录给出的 `ownerProps`(`code`/`message`/`dismiss`/`keepOpen`)与组件读取的字段一致。
17
+ - **守卫**:`tests/issue63-quota-notice.spec.tsx`(7 例)覆盖:claim 恰好是 `QUOTA`、其余码(含 `QUOTA_EXCEEDED`、空串、数字、对象)一律不 claim、宿主句子原样保留且补充可见、dismiss 按钮调用宿主回调、无 `dismiss` 时不崩、宿主没给 message 时回退到自己的标题。**变异验证**:把 claim 扩到 `AUTH`/`ACCOUNT_QUOTA` → 2 例红;删掉补充那一行 → 2 例红。
18
+ - **未做**:没有改任何分类/HTTP 状态,也没有动 `KIND_HOST_CODE` 里 `soft_rate`/`model_busy` → `quota_exceeded` 的翻译(那正是 #56 修复的核心)。
19
+
3
20
  ## 4.5.0 (2026-10-14)
4
21
 
5
22
  > 版本号是 **minor** 而不是 patch:这一版新增了一个**用户可见的设置**(积分读数的位置)和一个**新的渲染席位**,而且配置 schema 多了一个字段 —— 按语义化版本这是特性,不是修错。`4.4.6` 之后没有任何以 4.4.7 发布过的产物或 Release(tag 已撤回重打)。
package/lib/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as defaultDesktopAuthDirs, F as WorkBuddyUpstreamClient, K as WORKBUDDY_APP_EXECUTABLE_ENV, O as legacyWorkbuddyOwnAuthPath, Q as findWorkbuddyAppExecutableWithSource, S as defaultDesktopAuthCandidates, a as readHostHeartbeat, c as WORKBUDDY_CONNECT_VERSION, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, j as workbuddyOwnAuthPath, l as piAiRuntimeInfo, o as workbuddyHostHeartbeatPath, ot as hostPeersInfo, r as isHeartbeatProcessAlive, u as FALLBACK_WORKBUDDY_MODELS, v as WORKBUDDY_AUTH_FILE_ENV, y as WorkBuddyCredentialStore } from "./host-heartbeat-DvcOd-3C.js";
2
+ import { C as defaultDesktopAuthDirs, F as WorkBuddyUpstreamClient, K as WORKBUDDY_APP_EXECUTABLE_ENV, O as legacyWorkbuddyOwnAuthPath, Q as findWorkbuddyAppExecutableWithSource, S as defaultDesktopAuthCandidates, a as readHostHeartbeat, c as WORKBUDDY_CONNECT_VERSION, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, j as workbuddyOwnAuthPath, l as piAiRuntimeInfo, o as workbuddyHostHeartbeatPath, ot as hostPeersInfo, r as isHeartbeatProcessAlive, u as FALLBACK_WORKBUDDY_MODELS, v as WORKBUDDY_AUTH_FILE_ENV, y as WorkBuddyCredentialStore } from "./host-heartbeat-Vd2tNdsv.js";
3
3
  import { realpathSync } from "node:fs";
4
4
  import { fileURLToPath } from "node:url";
5
5
  //#region src/bin.ts
package/lib/client.js CHANGED
@@ -3081,6 +3081,13 @@ window.__ModuleLoader__.load({
3081
3081
  /* Its OWN label class, deliberately not the switch's: a query for "the
3082
3082
  sidebar-credit switch" must not be able to pick this control up, and the two
3083
3083
  are different widgets (a checkbox and a two-way picker). */
3084
+ /* The supplement to the host's fixed quota sentence (issue #63). It sits in the
3085
+ frame-wide overlay seat, so it must read on its own and stay narrow: a column
3086
+ with the host's sentence first (verbatim) and the supplement under it. */
3087
+ .dsm-workbuddy-quota-notice{display:flex;flex-direction:column;gap:4px;max-width:420px;padding:10px 12px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,#23242a);border:1px solid var(--dsw-alias-border-l1,#2c2d31);font-size:12px;line-height:17px}
3088
+ .dsm-workbuddy-quota-notice-head{font-weight:600;color:var(--dsw-alias-label-primary,#e6e6e6)}
3089
+ .dsm-workbuddy-quota-notice-body{color:var(--dsw-alias-label-secondary,#c6c9d0)}
3090
+ .dsm-workbuddy-quota-notice-dismiss{align-self:flex-start;margin-top:2px;padding:2px 10px;font-size:12px}
3084
3091
  .dsm-workbuddy-credit-position-switch{display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary,#c6c9d0)}
3085
3092
  .dsm-workbuddy-credit-position{max-width:150px;padding:2px 6px;font-size:12px}
3086
3093
  .dsm-workbuddy-credits-switch-row .dsm-workbuddy-credit-position-switch{margin-left:12px}
@@ -5574,6 +5581,77 @@ window.__ModuleLoader__.load({
5574
5581
  });
5575
5582
  }
5576
5583
  //#endregion
5584
+ //#region src/client/WorkBuddyQuotaNotice.tsx
5585
+ /**
5586
+ * The supplement this plugin adds to the host's quota notice (issue #63).
5587
+ *
5588
+ * WHY THIS EXISTS. When an upstream failure is classified `QUOTA`, the host
5589
+ * renders ONE fixed sentence — 「当前请求的额度已用尽」 — and (measured on the
5590
+ * shipped client) it DISCARDS the provider's own message to do so:
5591
+ *
5592
+ * function failureMessage(message, code, t) {
5593
+ * if (code === 'QUOTA' || code === 'ACCOUNT_QUOTA') return t('message.failure.quota')
5594
+ * return code === 'AUTH' ? t('message.failure.auth') : message
5595
+ * }
5596
+ *
5597
+ * That sentence is right for a genuinely exhausted account (14018), and wrong
5598
+ * for `6004` — the upstream's own words are 「您的使用量已超出频率限制,将在
5599
+ * <时刻> 重置」, and the reporter's account still held 6,788 credits. The
5600
+ * plugin cannot fix that by re-classifying: measured against the shipped
5601
+ * classifier, every spelling that stops reading as `QUOTA` falls into
5602
+ * `RATE_LIMIT`, which IS in `DEFAULT_RETRYABLE_CODES` — so it would buy an
5603
+ * honest sentence with 5 in-place retries and ~15.5s of backoff on a limit that
5604
+ * resets hours later. Staying out of the retry set is the behaviour we keep
5605
+ * (the maintainer's call on issue #63); the sentence is what we supplement.
5606
+ *
5607
+ * HOW. The host ships a CHAIN seat for exactly this: `shell.quota-notice`, a
5608
+ * frame-wide overlay whose own comment says "a `shell.quota-notice` entry may
5609
+ * replace the generic Toast for codes it claims". The chain hands a claiming
5610
+ * entry the host's own owner object — `{ code, message, dismiss, keepOpen }` —
5611
+ * so this component can keep the host's sentence VERBATIM and append the one
5612
+ * fact the sentence is missing. Claiming only `QUOTA` leaves every other code on
5613
+ * the host's fallback Toast.
5614
+ *
5615
+ * WHY THE HOST'S SENTENCE IS KEPT, not rewritten: it is the string the shell
5616
+ * shows everywhere else for this code, and a plugin that reworded it would
5617
+ * contradict the shell's own vocabulary. The supplement is additive, and it is
5618
+ * written to be TRUE FOR BOTH CASES the code covers — a model's own daily quota
5619
+ * (not credits) and a genuinely empty balance — because the plugin cannot always
5620
+ * tell which one it is: the upstream states it in Chinese prose the plugin is
5621
+ * not allowed to parse for policy.
5622
+ *
5623
+ * Rendered as plain DOM with this plugin's own classes: the client half
5624
+ * deliberately does not depend on `@deepseek-ai/dsh-client-ui-primitives` (see
5625
+ * the note in `src/client/index.tsx` — a stale inject entry there once made the
5626
+ * whole card's arrival depend on the churn-heaviest host package), so the
5627
+ * notice is built from the same primitives every other component here uses.
5628
+ */
5629
+ /**
5630
+ * Which notice codes this plugin claims.
5631
+ *
5632
+ * `QUOTA` only — it is what the shipped classifier produces for BOTH failures
5633
+ * this plugin raises (`6004` account rate limit and `14018` exhausted credits),
5634
+ * and claiming anything else would take over a notice this plugin knows nothing
5635
+ * about. Exported so the claim is unit-testable without a host.
5636
+ */
5637
+ const WORKBUDDY_QUOTA_NOTICE_CODES = ["QUOTA"];
5638
+ /** Whether this plugin should take over the notice for one owner object. */
5639
+ function claimsQuotaNotice(code) {
5640
+ return typeof code === "string" && WORKBUDDY_QUOTA_NOTICE_CODES.includes(code);
5641
+ }
5642
+ /** The frame-wide supplement shown under the host's sentence. */
5643
+ function WorkBuddyQuotaNotice(props) {
5644
+ const { matched, t } = props;
5645
+ return (0, react.createElement)("div", {
5646
+ className: "dsm-workbuddy-quota-notice",
5647
+ role: "status"
5648
+ }, (0, react.createElement)("span", { className: "dsm-workbuddy-quota-notice-head" }, matched.message ?? t("quotaNotice.fallbackHead")), (0, react.createElement)("span", { className: "dsm-workbuddy-quota-notice-body" }, t("quotaNotice.supplement")), matched.dismiss === void 0 ? null : (0, react.createElement)("button", {
5649
+ type: "button",
5650
+ className: "dsm-btn dsm-btn-outline dsm-workbuddy-quota-notice-dismiss",
5651
+ onClick: () => matched.dismiss?.()
5652
+ }, t("quotaNotice.dismiss")));
5653
+ }
5654
+ //#endregion
5577
5655
  //#region src/client/locales.ts
5578
5656
  /**
5579
5657
  * Plugin-card copy registered under the settings.workbuddy locale namespace.
@@ -5838,6 +5916,9 @@ window.__ModuleLoader__.load({
5838
5916
  "row.creditPositionComposer": "composer toolbar",
5839
5917
  "row.creditPositionStats": "below the input box",
5840
5918
  "row.creditPositionAria": "Credit readout position for {region}",
5919
+ "quotaNotice.fallbackHead": "The quota for this request is exhausted",
5920
+ "quotaNotice.supplement": "Some models have their own daily limit that is unrelated to your credit balance — check the account pool row for the stated reset time, or switch account or model to continue.",
5921
+ "quotaNotice.dismiss": "Got it",
5841
5922
  "row.creditPositionHint": "Where the credit readout sits. \"composer toolbar\" is the default (the row with the model picker). Choose \"below the input box\" — the row carrying the round / step / token statistics — if another plugin occupies the composer toolbar and the readout does not appear.",
5842
5923
  "row.showCreditsGlobalHint": "Show the international (WB AI) credit balance in the composer toolbar, but only while this session uses a WB AI model. Click it for per-account balances and a manual refresh (refreshes by itself every 5 minutes).",
5843
5924
  "composer.pointsCn": "WB CN",
@@ -6114,6 +6195,9 @@ window.__ModuleLoader__.load({
6114
6195
  "row.creditPositionComposer": "输入框工具栏",
6115
6196
  "row.creditPositionStats": "输入框下方",
6116
6197
  "row.creditPositionAria": "{region} 的积分显示位置",
6198
+ "quotaNotice.fallbackHead": "当前请求的额度已用尽",
6199
+ "quotaNotice.supplement": "部分模型另有每日额度限制,与积分余额无关 —— 也可能确实是本账号积分耗尽。账号池那一行会写明上游给出的恢复时刻;也可以先换个账号或换个模型继续。",
6200
+ "quotaNotice.dismiss": "知道了",
6117
6201
  "row.creditPositionHint": "积分显示在哪里。「输入框工具栏」是默认位置(与模型选择同一行)。如果装了别的插件后读数不显示,改成「输入框下方」—— 那是「轮次 / 步数 / token」统计所在的那一行。",
6118
6202
  "row.showCreditsGlobalHint": "在对话输入框工具栏显示国际版(WB AI)剩余积分,仅当本会话使用 WB AI 模型时出现。点击可看各账号余额并手动刷新(每 5 分钟也会自动刷新)。",
6119
6203
  "composer.pointsCn": "WB CN",
@@ -6293,6 +6377,40 @@ window.__ModuleLoader__.load({
6293
6377
  }
6294
6378
  };
6295
6379
  /**
6380
+ * The frame-wide quota notice, claimed so the supplement can be shown
6381
+ * (issue #63).
6382
+ *
6383
+ * The host renders ONE fixed sentence for a `QUOTA` failure — 「当前请求的
6384
+ * 额度已用尽」 — and discards the provider's message while doing it. For
6385
+ * `6004` that sentence is wrong (the upstream's own words say 「频率限制」,
6386
+ * with a reset time, and the reporting account still held thousands of
6387
+ * credits), but re-classifying is NOT the fix: measured against the shipped
6388
+ * classifier, every spelling that stops reading as `QUOTA` lands in
6389
+ * `RATE_LIMIT`, which is IN the host's retry set — 5 in-place retries and
6390
+ * ~15.5s of backoff on a limit that resets hours later. So the behaviour
6391
+ * (no retry) stays and the sentence gets a SUPPLEMENT.
6392
+ *
6393
+ * `select` claims `QUOTA` only, and the chain is the host's own designed
6394
+ * extension point for this ("a shell.quota-notice entry may replace the
6395
+ * generic Toast for codes it claims") — every other code keeps the host's
6396
+ * fallback Toast untouched.
6397
+ */
6398
+ const registerQuotaNotice = () => {
6399
+ try {
6400
+ return ctx.slots.inject("shell.quota-notice", () => ctx.slots.register({
6401
+ name: "shell.quota-notice",
6402
+ locale: namespace,
6403
+ select: (owner) => {
6404
+ return claimsQuotaNotice(typeof owner === "object" && owner !== null ? owner.code : void 0) ? owner : null;
6405
+ },
6406
+ inject: () => ({ t })
6407
+ }, WorkBuddyQuotaNotice));
6408
+ } catch (error) {
6409
+ console.error("[dsh-connect-workbuddy] quota notice slot failed to register (host provider unaffected):", error);
6410
+ return;
6411
+ }
6412
+ };
6413
+ /**
6296
6414
  * Every slot this plugin contributes, and how to (re)create them.
6297
6415
  *
6298
6416
  * Kept as one list because the binding of `settingsScope` and the slot
@@ -6311,7 +6429,8 @@ window.__ModuleLoader__.load({
6311
6429
  ...WORKBUDDY_CARD_KEYS.map((key) => registerCard("plugins.bundle.config", key)),
6312
6430
  ...WORKBUDDY_CARD_KEYS.map((key) => registerCard("plugins.row.config", `${key}#${key}`)),
6313
6431
  registerComposerCredits(),
6314
- registerStatsCredits()
6432
+ registerStatsCredits(),
6433
+ registerQuotaNotice()
6315
6434
  ].filter((disposer) => disposer !== void 0);
6316
6435
  /**
6317
6436
  * Disposers of the slots registered for the CURRENT binding.
@@ -3825,7 +3825,7 @@ function generationOf(version) {
3825
3825
  //#endregion
3826
3826
  //#region src/version.ts
3827
3827
  /** The npm package version this build was produced from. */
3828
- const WORKBUDDY_CONNECT_VERSION = "4.5.0";
3828
+ const WORKBUDDY_CONNECT_VERSION = "4.5.1";
3829
3829
  //#endregion
3830
3830
  //#region src/host-heartbeat.ts
3831
3831
  /**
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as isEncryptedFieldWrapper, A as workbuddyAccountId, B as modelIdOfBody, C as defaultDesktopAuthDirs, D as isVaultAccountId, E as isEncryptedCredentialError, F as WorkBuddyUpstreamClient, G as regionOf, H as parseReasoning, I as classifyUpstreamError, J as deriveAtRestKey, K as WORKBUDDY_APP_EXECUTABLE_ENV, L as declaredTools, M as CREDENTIAL_REJECTED_CODE, N as WORKBUDDY_FALLBACK_SYSTEM_PROMPT, O as legacyWorkbuddyOwnAuthPath, P as WorkBuddyCredentialRejectedError, R as isCredentialRejectedError, S as defaultDesktopAuthCandidates, T as hasEncryptedCredentialFields, U as parseUpstreamModel, V as parseCreditMultiplier, W as prepareChatBody, X as fetchAtRestKeyPayload, Y as deriveAtRestKeyId, Z as findWorkbuddyAppExecutable, _ as WORKBUDDY_AUTH_FILENAME, a as readHostHeartbeat, at as workbuddyAppExecutableCandidates, b as WorkBuddyEncryptedCredentialError, c as WORKBUDDY_CONNECT_VERSION, ct as withFileLock, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, et as isWorkbuddyBundle, f as WorkBuddyCatalog, g as ENCRYPTED_CREDENTIAL_CODE, h as fallbackModelsFor, i as processStartTimeMs, it as readAtRestKey, j as workbuddyOwnAuthPath, k as parseWorkBuddyAuth, l as piAiRuntimeInfo, lt as writeFileAtomic, m as deriveCatalog, n as clearHostHeartbeat, nt as macosNestedAppBundles, o as workbuddyHostHeartbeatPath, p as applyContextBudgets, q as clearAtRestKeyCache, r as isHeartbeatProcessAlive, rt as openEncryptedField, s as writeHostHeartbeat, st as resolveDshHome, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, tt as macosBundleExecutable, u as FALLBACK_WORKBUDDY_MODELS, v as WORKBUDDY_AUTH_FILE_ENV, w as defaultDesktopAuthPath, x as authFileName, y as WorkBuddyCredentialStore, z as knownRegionOf } from "./host-heartbeat-DvcOd-3C.js";
1
+ import { $ as isEncryptedFieldWrapper, A as workbuddyAccountId, B as modelIdOfBody, C as defaultDesktopAuthDirs, D as isVaultAccountId, E as isEncryptedCredentialError, F as WorkBuddyUpstreamClient, G as regionOf, H as parseReasoning, I as classifyUpstreamError, J as deriveAtRestKey, K as WORKBUDDY_APP_EXECUTABLE_ENV, L as declaredTools, M as CREDENTIAL_REJECTED_CODE, N as WORKBUDDY_FALLBACK_SYSTEM_PROMPT, O as legacyWorkbuddyOwnAuthPath, P as WorkBuddyCredentialRejectedError, R as isCredentialRejectedError, S as defaultDesktopAuthCandidates, T as hasEncryptedCredentialFields, U as parseUpstreamModel, V as parseCreditMultiplier, W as prepareChatBody, X as fetchAtRestKeyPayload, Y as deriveAtRestKeyId, Z as findWorkbuddyAppExecutable, _ as WORKBUDDY_AUTH_FILENAME, a as readHostHeartbeat, at as workbuddyAppExecutableCandidates, b as WorkBuddyEncryptedCredentialError, c as WORKBUDDY_CONNECT_VERSION, ct as withFileLock, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, et as isWorkbuddyBundle, f as WorkBuddyCatalog, g as ENCRYPTED_CREDENTIAL_CODE, h as fallbackModelsFor, i as processStartTimeMs, it as readAtRestKey, j as workbuddyOwnAuthPath, k as parseWorkBuddyAuth, l as piAiRuntimeInfo, lt as writeFileAtomic, m as deriveCatalog, n as clearHostHeartbeat, nt as macosNestedAppBundles, o as workbuddyHostHeartbeatPath, p as applyContextBudgets, q as clearAtRestKeyCache, r as isHeartbeatProcessAlive, rt as openEncryptedField, s as writeHostHeartbeat, st as resolveDshHome, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, tt as macosBundleExecutable, u as FALLBACK_WORKBUDDY_MODELS, v as WORKBUDDY_AUTH_FILE_ENV, w as defaultDesktopAuthPath, x as authFileName, y as WorkBuddyCredentialStore, z as knownRegionOf } from "./host-heartbeat-Vd2tNdsv.js";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { appendFile, mkdir, readFile } from "node:fs/promises";
4
4
  import { randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "dsh-connect-workbuddy",
3
3
  "displayName": "DSH Connect WorkBuddy",
4
4
  "description": "把本机登录的 WorkBuddy 模型接入 DeepSeek Harness,并提供只读的积分概览与模型管理。",
5
- "version": "4.5.0",
5
+ "version": "4.5.1",
6
6
  "author": "dingminhua",
7
7
  "copyright": "Copyright (c) 2026 LaoDing",
8
8
  "license": "MIT",