dsh-connect-workbuddy 3.4.1 → 3.4.2

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,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.4.2 (2026-10-03)
4
+
5
+ ### Fixes
6
+
7
+ - **换号重试之间补上 2 秒间隔,不再零延迟连发。**
8
+ - **现象**:一次请求撞上限流后,换号循环会**零间隔**地把池里剩下的账号挨个试一遍——实测 4 个账号在 **35 秒内全部失败**(最后两次只隔 1 秒),而它们全部撞的是同一个 429。
9
+ - **根因**:上游的限流(业务码 6004)**按请求体积/频率触发**,零间隔连发等于自己把每个候选都推到同一堵墙上。批量测试早就为此在账号之间等 `POOL_BATCH_GAP_MS`(400ms),**换号循环却什么都没有**——两者的差别没有理由。
10
+ - **修法**:每次换号前等待 `FAILOVER_ACCOUNT_GAP_MS`(2 秒)。比批测的 400ms 更长,因为换号重试是**用户在等的真实请求**,不是探测——它需要给上游的窗口留出喘息,而不只是避免自己踩到限流。
11
+ - **等待是可中断的**:客户端断开时立刻结束等待并退出循环,不会白等 2 秒,也不会拿一个已经作废的 signal 去把剩余账号试完。
12
+ - 顺带修正:等待结束后重新检查一次中断状态——否则客户端已断开时,剩余账号会被逐个发出去(每个都立即因 signal 作废而失败),白白写下一串假的账号失败测量。
13
+ - 测试:新增一条用例钉住「两次尝试之间确实等待了 ≥1.9 秒」,变异验证(把间隔改成 0)必红。
14
+
3
15
  ## 3.4.1 (2026-10-02)
4
16
 
5
17
  ### Fixes
package/lib/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { E as legacyWorkbuddyOwnAuthPath, H as WORKBUDDY_APP_EXECUTABLE_ENV, N as WorkBuddyUpstreamClient, S as defaultDesktopAuthDirs, _ as WORKBUDDY_AUTH_FILE_ENV, a as readHostHeartbeat, c as WORKBUDDY_CONNECT_VERSION, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, k as workbuddyOwnAuthPath, l as piAiRuntimeInfo, o as workbuddyHostHeartbeatPath, q as findWorkbuddyAppExecutable, r as isHeartbeatProcessAlive, u as FALLBACK_WORKBUDDY_MODELS, v as WorkBuddyCredentialStore, x as defaultDesktopAuthCandidates } from "./host-heartbeat-DSO-07lc.js";
2
+ import { E as legacyWorkbuddyOwnAuthPath, H as WORKBUDDY_APP_EXECUTABLE_ENV, N as WorkBuddyUpstreamClient, S as defaultDesktopAuthDirs, _ as WORKBUDDY_AUTH_FILE_ENV, a as readHostHeartbeat, c as WORKBUDDY_CONNECT_VERSION, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, k as workbuddyOwnAuthPath, l as piAiRuntimeInfo, o as workbuddyHostHeartbeatPath, q as findWorkbuddyAppExecutable, r as isHeartbeatProcessAlive, u as FALLBACK_WORKBUDDY_MODELS, v as WorkBuddyCredentialStore, x as defaultDesktopAuthCandidates } from "./host-heartbeat-Sq5JwluI.js";
3
3
  import { realpathSync } from "node:fs";
4
4
  import { fileURLToPath } from "node:url";
5
5
  //#region src/bin.ts
@@ -2552,7 +2552,7 @@ function generationOf(version) {
2552
2552
  //#endregion
2553
2553
  //#region src/version.ts
2554
2554
  /** The npm package version this build was produced from. */
2555
- const WORKBUDDY_CONNECT_VERSION = "3.4.1";
2555
+ const WORKBUDDY_CONNECT_VERSION = "3.4.2";
2556
2556
  //#endregion
2557
2557
  //#region src/host-heartbeat.ts
2558
2558
  /**
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as readAtRestKey, A as CREDENTIAL_REJECTED_CODE, B as prepareChatBody, C as defaultDesktopAuthPath, D as parseWorkBuddyAuth, E as legacyWorkbuddyOwnAuthPath, F as declaredTools, G as deriveAtRestKeyId, H as WORKBUDDY_APP_EXECUTABLE_ENV, I as isCredentialRejectedError, J as isEncryptedFieldWrapper, K as fetchAtRestKeyPayload, L as parseCreditMultiplier, M as WorkBuddyCredentialRejectedError, N as WorkBuddyUpstreamClient, O as workbuddyAccountId, P as classifyUpstreamError, Q as openEncryptedField, R as parseReasoning, S as defaultDesktopAuthDirs, T as isEncryptedCredentialError, U as clearAtRestKeyCache, V as regionOf, W as deriveAtRestKey, X as macosBundleExecutable, Y as isWorkbuddyBundle, Z as macosNestedAppBundles, _ as WORKBUDDY_AUTH_FILE_ENV, a as readHostHeartbeat, b as authFileName, c as WORKBUDDY_CONNECT_VERSION, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, et as workbuddyAppExecutableCandidates, f as WorkBuddyCatalog, g as WORKBUDDY_AUTH_FILENAME, h as ENCRYPTED_CREDENTIAL_CODE, i as processStartTimeMs, j as WORKBUDDY_FALLBACK_SYSTEM_PROMPT, k as workbuddyOwnAuthPath, l as piAiRuntimeInfo, m as fallbackModelsFor, n as clearHostHeartbeat, o as workbuddyHostHeartbeatPath, p as deriveCatalog, q as findWorkbuddyAppExecutable, r as isHeartbeatProcessAlive, s as writeHostHeartbeat, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, u as FALLBACK_WORKBUDDY_MODELS, v as WorkBuddyCredentialStore, w as hasEncryptedCredentialFields, x as defaultDesktopAuthCandidates, y as WorkBuddyEncryptedCredentialError, z as parseUpstreamModel } from "./host-heartbeat-DSO-07lc.js";
1
+ import { $ as readAtRestKey, A as CREDENTIAL_REJECTED_CODE, B as prepareChatBody, C as defaultDesktopAuthPath, D as parseWorkBuddyAuth, E as legacyWorkbuddyOwnAuthPath, F as declaredTools, G as deriveAtRestKeyId, H as WORKBUDDY_APP_EXECUTABLE_ENV, I as isCredentialRejectedError, J as isEncryptedFieldWrapper, K as fetchAtRestKeyPayload, L as parseCreditMultiplier, M as WorkBuddyCredentialRejectedError, N as WorkBuddyUpstreamClient, O as workbuddyAccountId, P as classifyUpstreamError, Q as openEncryptedField, R as parseReasoning, S as defaultDesktopAuthDirs, T as isEncryptedCredentialError, U as clearAtRestKeyCache, V as regionOf, W as deriveAtRestKey, X as macosBundleExecutable, Y as isWorkbuddyBundle, Z as macosNestedAppBundles, _ as WORKBUDDY_AUTH_FILE_ENV, a as readHostHeartbeat, b as authFileName, c as WORKBUDDY_CONNECT_VERSION, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, et as workbuddyAppExecutableCandidates, f as WorkBuddyCatalog, g as WORKBUDDY_AUTH_FILENAME, h as ENCRYPTED_CREDENTIAL_CODE, i as processStartTimeMs, j as WORKBUDDY_FALLBACK_SYSTEM_PROMPT, k as workbuddyOwnAuthPath, l as piAiRuntimeInfo, m as fallbackModelsFor, n as clearHostHeartbeat, o as workbuddyHostHeartbeatPath, p as deriveCatalog, q as findWorkbuddyAppExecutable, r as isHeartbeatProcessAlive, s as writeHostHeartbeat, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, u as FALLBACK_WORKBUDDY_MODELS, v as WorkBuddyCredentialStore, w as hasEncryptedCredentialFields, x as defaultDesktopAuthCandidates, y as WorkBuddyEncryptedCredentialError, z as parseUpstreamModel } from "./host-heartbeat-Sq5JwluI.js";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { readFile } from "node:fs/promises";
4
4
  import { randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
@@ -1118,6 +1118,19 @@ function finish(parts, calls) {
1118
1118
  * @module dsh-connect-workbuddy/shim
1119
1119
  */
1120
1120
  const REQUEST_BODY_LIMIT = 67108864;
1121
+ /**
1122
+ * Pause between failover attempts, after one account's request failed.
1123
+ *
1124
+ * The upstream's rate limit (6004) fires on request volume — firing retries at
1125
+ * zero gap makes every candidate hit the same wall, and 4 accounts can all fail
1126
+ * in under a second. The batch test already waits `POOL_BATCH_GAP_MS` (400ms)
1127
+ * between accounts for exactly this reason; the failover loop used to wait
1128
+ * nothing. 2 seconds is longer than the batch's 400 because a failover retry is
1129
+ * a real request the user is waiting on, not a probe — it needs enough room for
1130
+ * the upstream's window to breathe, not just enough to avoid self-inflicted
1131
+ * rate-limiting.
1132
+ */
1133
+ const FAILOVER_ACCOUNT_GAP_MS = 2e3;
1121
1134
  /** Loopback hostnames the shim's own in-process client uses. */
1122
1135
  const LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
1123
1136
  "127.0.0.1",
@@ -1745,6 +1758,16 @@ function createWorkBuddyShim(options) {
1745
1758
  const next = await failoverAccount(triedAccountIds).catch(() => void 0);
1746
1759
  if (next === void 0) break;
1747
1760
  if (triedAccountIds.includes(workbuddyAccountId(next))) break;
1761
+ if (controller.signal.aborted) break;
1762
+ await new Promise((resolve) => {
1763
+ if (controller.signal.aborted) return resolve();
1764
+ const timer = setTimeout(resolve, FAILOVER_ACCOUNT_GAP_MS);
1765
+ controller.signal.addEventListener("abort", () => {
1766
+ clearTimeout(timer);
1767
+ resolve();
1768
+ }, { once: true });
1769
+ });
1770
+ if (controller.signal.aborted) break;
1748
1771
  logger?.warn(`dsh-connect-workbuddy: retrying chat on another pool account after ${result.kind} (http ${result.status})`);
1749
1772
  credential = next;
1750
1773
  result = await client.chatStream(credential, prepared, controller.signal);
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": "3.4.1",
5
+ "version": "3.4.2",
6
6
  "author": "dingminhua",
7
7
  "copyright": "Copyright (c) 2026 LaoDing",
8
8
  "license": "MIT",