@eddyskywalker/dsh-chatgpt-subscription 0.64.1 → 0.66.0

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.
Files changed (115) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/lib/client.js +120 -9
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +2286 -1054
  5. package/lib/types/client/kimi-code/KimiCodeSection.d.ts.map +1 -1
  6. package/lib/types/client/kimi-code/locales.d.ts +8 -2
  7. package/lib/types/client/kimi-code/locales.d.ts.map +1 -1
  8. package/lib/types/client/locales-ru/kimi-code.d.ts.map +1 -1
  9. package/lib/types/client/locales-ru/progress-updates.d.ts.map +1 -1
  10. package/lib/types/client/locales-ru/step-code.d.ts.map +1 -1
  11. package/lib/types/client/progress-updates/locales.d.ts +23 -11
  12. package/lib/types/client/progress-updates/locales.d.ts.map +1 -1
  13. package/lib/types/client/progress-updates/settings-binding.d.ts +11 -1
  14. package/lib/types/client/progress-updates/settings-binding.d.ts.map +1 -1
  15. package/lib/types/client/progress-updates/settings-section.d.ts +2 -2
  16. package/lib/types/client/progress-updates/settings-section.d.ts.map +1 -1
  17. package/lib/types/client/step-code/StepCodeSection.d.ts.map +1 -1
  18. package/lib/types/client/step-code/locales.d.ts +5 -2
  19. package/lib/types/client/step-code/locales.d.ts.map +1 -1
  20. package/lib/types/compat.d.ts +1 -1
  21. package/lib/types/host/antigravity/adapter.d.ts +2 -0
  22. package/lib/types/host/antigravity/adapter.d.ts.map +1 -1
  23. package/lib/types/host/antigravity/client-version.d.ts +55 -0
  24. package/lib/types/host/antigravity/client-version.d.ts.map +1 -0
  25. package/lib/types/host/antigravity/client.d.ts +13 -1
  26. package/lib/types/host/antigravity/client.d.ts.map +1 -1
  27. package/lib/types/host/antigravity/image-tool.d.ts.map +1 -1
  28. package/lib/types/host/antigravity/mapper.d.ts.map +1 -1
  29. package/lib/types/host/antigravity/oauth.d.ts +9 -0
  30. package/lib/types/host/antigravity/oauth.d.ts.map +1 -1
  31. package/lib/types/host/antigravity/types.d.ts +52 -3
  32. package/lib/types/host/antigravity/types.d.ts.map +1 -1
  33. package/lib/types/host/cache-warmup/budget.d.ts +2 -2
  34. package/lib/types/host/cache-warmup/budget.d.ts.map +1 -1
  35. package/lib/types/host/cache-warmup/contracts.d.ts +2 -0
  36. package/lib/types/host/cache-warmup/contracts.d.ts.map +1 -1
  37. package/lib/types/host/cache-warmup/install.d.ts +4 -4
  38. package/lib/types/host/cache-warmup/install.d.ts.map +1 -1
  39. package/lib/types/host/cache-warmup/result-tool.d.ts +3 -1
  40. package/lib/types/host/cache-warmup/result-tool.d.ts.map +1 -1
  41. package/lib/types/host/cache-warmup/settings.d.ts +5 -1
  42. package/lib/types/host/cache-warmup/settings.d.ts.map +1 -1
  43. package/lib/types/host/cache-warmup/usage.d.ts +1 -1
  44. package/lib/types/host/cache-warmup/usage.d.ts.map +1 -1
  45. package/lib/types/host/claude/adapter.d.ts +3 -0
  46. package/lib/types/host/claude/adapter.d.ts.map +1 -1
  47. package/lib/types/host/cline-pass/mapper.d.ts.map +1 -1
  48. package/lib/types/host/common/account-pool.d.ts +27 -1
  49. package/lib/types/host/common/account-pool.d.ts.map +1 -1
  50. package/lib/types/host/common/cache-activity.d.ts +14 -0
  51. package/lib/types/host/common/cache-activity.d.ts.map +1 -0
  52. package/lib/types/host/common/cache-affinity.d.ts +23 -0
  53. package/lib/types/host/common/cache-affinity.d.ts.map +1 -0
  54. package/lib/types/host/common/cache-hint.d.ts +18 -0
  55. package/lib/types/host/common/cache-hint.d.ts.map +1 -0
  56. package/lib/types/host/common/failure-classification.d.ts +21 -0
  57. package/lib/types/host/common/failure-classification.d.ts.map +1 -0
  58. package/lib/types/host/common/hosted-media.d.ts +36 -0
  59. package/lib/types/host/common/hosted-media.d.ts.map +1 -0
  60. package/lib/types/host/common/prefix-request-coordinator.d.ts +46 -0
  61. package/lib/types/host/common/prefix-request-coordinator.d.ts.map +1 -0
  62. package/lib/types/host/common/prefix-stability.d.ts +24 -0
  63. package/lib/types/host/common/prefix-stability.d.ts.map +1 -0
  64. package/lib/types/host/common/prompt-cache-policy.d.ts +43 -0
  65. package/lib/types/host/common/prompt-cache-policy.d.ts.map +1 -0
  66. package/lib/types/host/common/reasoning-dialect.d.ts +24 -0
  67. package/lib/types/host/common/reasoning-dialect.d.ts.map +1 -0
  68. package/lib/types/host/common/session-cache-state.d.ts +29 -0
  69. package/lib/types/host/common/session-cache-state.d.ts.map +1 -0
  70. package/lib/types/host/common/sticky-image-budget.d.ts +10 -0
  71. package/lib/types/host/common/sticky-image-budget.d.ts.map +1 -0
  72. package/lib/types/host/common/tool-runaway.d.ts +52 -0
  73. package/lib/types/host/common/tool-runaway.d.ts.map +1 -0
  74. package/lib/types/host/kimi-code/account-pool.d.ts +19 -2
  75. package/lib/types/host/kimi-code/account-pool.d.ts.map +1 -1
  76. package/lib/types/host/kimi-code/adapter.d.ts +44 -30
  77. package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
  78. package/lib/types/host/kimi-code/cache-affinity.d.ts +112 -0
  79. package/lib/types/host/kimi-code/cache-affinity.d.ts.map +1 -0
  80. package/lib/types/host/kimi-code/cache-hint.d.ts +3 -28
  81. package/lib/types/host/kimi-code/cache-hint.d.ts.map +1 -1
  82. package/lib/types/host/kimi-code/cache-wait.d.ts +6 -4
  83. package/lib/types/host/kimi-code/cache-wait.d.ts.map +1 -1
  84. package/lib/types/host/kimi-code/mapper.d.ts +2 -6
  85. package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
  86. package/lib/types/host/kimi-code/media-files.d.ts +2 -28
  87. package/lib/types/host/kimi-code/media-files.d.ts.map +1 -1
  88. package/lib/types/host/kimi-code/repeat-breaker.d.ts +13 -16
  89. package/lib/types/host/kimi-code/repeat-breaker.d.ts.map +1 -1
  90. package/lib/types/host/kimi-code/routes.d.ts.map +1 -1
  91. package/lib/types/host/kimi-code/session-cache-state.d.ts +16 -53
  92. package/lib/types/host/kimi-code/session-cache-state.d.ts.map +1 -1
  93. package/lib/types/host/minimax-code/adapter.d.ts +5 -1
  94. package/lib/types/host/minimax-code/adapter.d.ts.map +1 -1
  95. package/lib/types/host/minimax-code/files-api.d.ts.map +1 -1
  96. package/lib/types/host/minimax-code/runtime-enhancements.d.ts.map +1 -1
  97. package/lib/types/host/opendesign/mapper.d.ts.map +1 -1
  98. package/lib/types/host/proxy-manager.d.ts +87 -1
  99. package/lib/types/host/proxy-manager.d.ts.map +1 -1
  100. package/lib/types/host/qoder/mapper.d.ts.map +1 -1
  101. package/lib/types/host/responses-client.d.ts +4 -0
  102. package/lib/types/host/responses-client.d.ts.map +1 -1
  103. package/lib/types/host/step-code/account-pool.d.ts +2 -2
  104. package/lib/types/host/step-code/account-pool.d.ts.map +1 -1
  105. package/lib/types/host/step-code/adapter.d.ts +10 -0
  106. package/lib/types/host/step-code/adapter.d.ts.map +1 -1
  107. package/lib/types/host/step-code/routes.d.ts +3 -0
  108. package/lib/types/host/step-code/routes.d.ts.map +1 -1
  109. package/lib/types/index.d.ts +22 -3
  110. package/lib/types/index.d.ts.map +1 -1
  111. package/lib/types/shared/kimi-code-contracts.d.ts +16 -0
  112. package/lib/types/shared/kimi-code-contracts.d.ts.map +1 -1
  113. package/lib/types/shared/step-code-contracts.d.ts +5 -0
  114. package/lib/types/shared/step-code-contracts.d.ts.map +1 -1
  115. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,58 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.66.0 - 2026-11-09
6
+
7
+ - **[shared / cache] Kimi Code 的缓存与运行时优化沉淀为跨线路共享能力,并按上游证据启用**
8
+ - **共享机制**:新增缓存策略注册表、静态前缀稳定化、冷启动请求协调、账号缓存亲和、持久化活动/图片状态、推理方言学习、失败冷却边界与 hosted-media 单飞内核。Codex、Antigravity、Step、Claude、MiniMax 获得静态前缀与 in-flight 冷启动协调;Cline、OpenDesign、Qoder 可学习并回放实际 reasoning 字段;Claude/MiniMax 的粘性图片状态可跨重启恢复。
9
+ - **全线低风险收益**:重复工具调用检测与分级提醒覆盖受控线路;大工具结果 `ref://` 预览及 `cache_warmup_result` 精确补读不再绑死 Kimi。只有 Kimi 保留第 12 次强停,MiniMax 保留官方错误族、ABAB 与轮询规则,其他线路不继承强停。
10
+ - **证据门控**:新增 `toolRunawayGuard`、`cacheWarmupProviders` 与非 volatile 的 `promptCacheOverrides`。Kimi 的 25 分钟 TTL、等待续热、账号级亲和与 `ms://` 协议保持原语义;其他线路只有在明确 TTL、账号隔离或上传协议证据时才开启对应行为。Step 另获官方 5 分钟 TTL 的缓存过期提示与可选亲和选号。
11
+ - **回归与界面**:新增策略、前缀、协调、活动、推理、媒体和 UI 测试;设置区新增工具失控治理开关,中英俄三语同步,并在原 GUI 同视口/主题完成 Before/After 复核。强制类型检查、构建、打包检查与全量 Vitest 均通过(6952 例通过 / 9 跳过 / 0 失败)。
12
+
13
+ - **[kimi-code / 号池] 多账号轮换按「前缀缓存还热着」选账号;冷启动组键补上账号维度**
14
+ - **问题**:服务端的前缀缓存是**按账号**各存一份,而内核 `selectAccount` 只看冷却、令牌与最近使用,永远看不到「这条前缀在哪个账号上还热着」——于是轮换可能把请求发给一个从没见过这段前缀的账号。更糟的是冷启动组键 `region:model:systemPromptHash:toolsHash[:staticPrefixHash]` **不含账号**,插件会在另一个账号烤热之后误判「这组是热的」,跟随者白等 2.5 秒预算,而它那条请求本来就不会命中。
15
+ - **改法**(`src/host/common/account-pool.ts`、`src/host/kimi-code/{account-pool,adapter,cache-affinity}.ts`、`src/index.ts`):内核新增 `AccountSelectionHint` 与 `getEffectiveAccount(..., selection)`——顺序是**钉住账号 > 请求偏好 > 轮换策略**,偏好里不可用/已尝试的 id 直接跳过,全跳过则回落策略(辅助工具的 `getCredentialAccount` 不消费偏好,读凭据不动轮换);`coldStartGroupKey` 追加 `|accountScope`,并新增 `prefixGroupKey` / `isWarmPrefixGroup` 让两处共用同一个「热」定义;新模块 `cache-affinity.ts` 把取舍写成纯函数(剩余额度取**最紧窗口**、`=20%` 仍可用、配额未知按「没证明不足」处理、同份额保持池序);适配器在取凭据之前算一次偏好,只对真的热着的账号读配额。新增默认开启的 volatile 开关 `cacheAffinity`,设置页「进展更新」一格加一行,三语齐备,`DSH_KIMI_CODE_CACHE_AFFINITY` 可覆盖。
16
+ - **刻意不做**:不把亲和做成第四种轮换策略(用户不必为了收益改策略);不因亲和失败而报错(热账号不可用就照旧回落);组键变更会让现存会话各自冷启动一次,这是一次性成本。
17
+ - **回归**:新增 `test/kimi-code-cache-affinity.test.ts` 15 例(最紧窗口、20% 边界、未知配额、冷账号永不入列、稳定排序、开关解析与环境变量);`test/account-pool-core.test.ts` 3 例(偏好压过策略、钉住压过偏好、偏好不可用时回落);`test/kimi-code-adapter.test.ts` 3 例(组键按账号区分、跨账号不再共享冷启动闸门、热账号被优先选中且开关关闭后回到池的选择)——其中「跨账号不再共享闸门」做了反向验证:把组键改回不带账号,该用例立刻失败。
18
+
19
+ - **[kimi-code / 诊断] 卡片显示「开局继承」:这个会话的第一条请求有多少 token 是继承来的**
20
+ - **背景**:跨会话前缀继承是真实存在的(同账号的另一个会话写下的头段,25 分钟内可被新会话读回),但它此前只体现在滚动命中率里,看不出「开局那一两千到上万 token 是谁付的」。同一台机器上的实测:新会话在另一会话结束 3 分钟后开工,首轮读到 14,080 / 21,527(65%);隔 5 小时续跑则只剩 2,304(14%)。
21
+ - **改法**(`src/host/kimi-code/{session-cache-state,adapter,routes}.ts`、`src/shared/kimi-code-contracts.ts`、`src/client/kimi-code/`):持久记录新增 `firstRequestCachedTokens` / `firstRequestPromptTokens`,只在会话首轮写入且之后原样保留(滚动合计会淹没这个数字);DTO 增 `opening`,卡片在「最近前缀状态」下方显示 `开局继承 14,080 / 21,527 tok(65.4%)`,无数据时不画这一行(旧记录与单账号首轮冷启动都属于「没有可说的」)。
22
+ - **回归**:`test/kimi-code-adapter.test.ts` 1 例(首轮写入、次轮不覆盖);`test/kimi-code-k31-card-ui.test.tsx` 2 例(有数据时的三个数字、无数据时不画该行)。
23
+
24
+ - **[kimi-code / 结论归档] 「把全局与工作区 AGENTS.md 拆成两条以提高跨工作区继承」经证伪,不实施**
25
+ - **依据**:宿主 `@deepseek-ai/dsh-agent-instructions` 的 `render.ts` 把每个指令文件渲染成 `Instructions from: <path>\n\n<content>`,全部 section 拼进**同一条** `<system-reminder>`,且 `USER_GLOBAL_DIRECTORIES` 决定全局段本来就在前;本仓库 mapper 的 `orderStaticPrefixMessages` 只按 tier 重排,不改变块内字节顺序。因此拆成两条消息后,跨工作区能匹配到的前缀长度**一个字节都不会变**。
26
+ - **还有一个反效果**:现有重排按 tier 只提升**首次出现**(`seenTiers` / `hoistedByTier`),第二条 tier-2 会被当成 rank 5 挤到用户消息之后——照原方案做会实实在在变差。
27
+ - **仍成立的部分**:工具说明与 `code_run` 恒定说明段本来就在 system prompt 里、已包含在共享的约 14k 头段内;要扩大共享头段只能让更多「全工作区相同」的内容排在第一个工作区相关字节之前,而目前除了语言覆盖已没有这类内容。
28
+
29
+ ## 0.65.0 - 2026-11-08
30
+
31
+ - **[antigravity] 出站请求身份、版本清单跟随与控制面契约对齐官方客户端**
32
+ - **问题**:
33
+ 1. **推理与生图请求带自造特征**:`systemInstruction` 使用了官方 persona 的改写版,并在末尾叠了 `Please ignore following [ignore]…[/ignore]` 与 `NEVER output rule checks…` 两段自造指令;chat / 生图两个信封的 `requestId` 是 `req_<毫秒>_<6位36进制>`、`img_<毫秒>_…` 自造格式(官方形态为 `agent-<uuid>`);项目发现为空时信封里的 `project` 兜底填 `antigravity-default`(任何真实客户端都不会发送的字符串);每个内容请求还额外携带 `X-Goog-Api-Client` 与 `Client-Metadata` 两个非推理头。
34
+ 2. **UA 版本写死 `2.23.0`**:恰好停在社区参考实现标注的最低可接受版本;Cloud Code 按 UA 版本下发模型目录与 Gemini 配额桶,写死意味着同一账号看到的模型与配额桶少于官方客户端。
35
+ 3. **控制面与推理面混用同一套身份**:`onboardUser`(新账号开通)原沿用推理请求的 camelCase `metadata.ideType` 与裸 UA;而官方在 `loadCodeAssist` 只发 `{ ideType }`,在 `onboardUser` 控制面则使用蛇形 `{ ide_type, ide_version, ide_name }`、UA 追加 `google-api-nodejs-client/10.3.0` 并携带 `X-Goog-Api-Client: gl-node/22.21.1`。
36
+ - **依据**:官方 `/v1internal:*` 请求由 Electron 壳内启动的 Go `language_server` 发出;persona 开头两句原文、默认兜底项目 `rising-fact-p41fc`、`agent-<uuid>` 请求 ID、`loadCodeAssist` / `onboardUser` 的控制面契约,以及 Hub 自动更新清单地址 `https://antigravity-hub-auto-updater-974169037036.us-central1.run.app/manifest/latest-arm64-mac.yml`(读取时 UA 为 `electron-builder`)与版本→CL 对照表(`opencode-antigravity-auth` 及 CLIProxyAPI `internal/misc/antigravity_version.go`,更新至 `2.29.0` → `1013060670`)均与抓包和社区参考实现核对一致;persona 截断残片(`**Absolute paths only****Proactiveness**`)之后的不可考下文不作臆造。
37
+ - **改法**:
38
+ - **信封与请求头**(`src/host/antigravity/types.ts`、`mapper.ts`、`adapter.ts`、`client.ts`、`image-tool.ts`):`ANTIGRAVITY_SYSTEM_INSTRUCTION` 恢复为可考的两句官方原文并删除 `ANTIGRAVITY_NO_PREAMBLE_INSTRUCTION`(`systemInstruction.parts` 只保留官方 persona 与 DSH 自身 system 提示);两个信封的 `requestId` 统一改为 `agent-${randomUUID()}`;三处 `'antigravity-default'` 兜底改用 `FALLBACK_PROJECT_ID`(`rising-fact-p41fc`);`antigravityHeaders()` 默认只发 `Authorization` / `Content-Type` / `Accept` / `User-Agent` 四个头,旧的两个头收拢至 `DSH_ANTIGRAVITY_LEGACY_HEADERS` 开关之后。
39
+ - **版本跟随与控制面拆分**(`src/host/antigravity/client-version.ts`、`client.ts`、`oauth.ts`、`types.ts`):新增 `client-version.ts`,启动时(及每次拉额度时按 TTL)读取一次 Hub 更新清单(6 小时信任窗口、30 分钟失败重试、单飞、永不抛错),内置基线版本抬升至 `2.29.0` / `cl=1013060670`,清单返回未知新版本时按官方规则省略 `cl=`,`DSH_ANTIGRAVITY_VERSION` / `DSH_ANTIGRAVITY_CL` 环境变量优先并完全跳过清单请求;新增 `antigravityControlPlaneHeaders()` 专供 `onboardUser`(及其 LRO 轮询)使用,`loadCodeAssist` 的 metadata 只留 `{ ideType }`;`oauth.ts` 新增 `selectOnboardTier()`(默认 tier → 免费 tier → 首个 allowed tier → current tier → `free-tier`)。
40
+ - **回归**:新增 `test/antigravity-wire-identity.test.ts` 与 `test/antigravity-hub-version.test.ts`,更新 `test/antigravity-mapper.test.ts` 与 `test/antigravity-oauth.test.ts`——覆盖默认 4 头集合、`DSH_ANTIGRAVITY_LEGACY_HEADERS` 布尔解析、两个信封 `agent-<uuid>` 格式、官方 persona 原文与已删段落断言、`FALLBACK_PROJECT_ID` 值、Hub 清单解析/6 小时缓存/失败回退/未知版本省略 `cl=`/环境变量钉死、以及 `loadCodeAssist` 与 `onboardUser` 的契约分离。
41
+
42
+ - **[antigravity / proxy] 每凭据独立 HTTP/1.1 连接池、剥离 `fetch` 浏览器头与直连无 ALPN**
43
+ - **问题**:
44
+ 1. **多账号共用同一条 TLS 连接**:官方客户端是「一凭据一进程」,一条连接只服务一个账号;本插件单进程多账号在代理路径共用单个 `ProxyAgent`、直连路径共用 Node 全局 fetch 的进程级连接池,上游能看到同一条连接先后出现多个不同的 `Authorization`。
45
+ 2. **代理与直连协议不一致**:undici 8 的 `ProxyAgent` 默认允许 ALPN 协商出 h2(实测 GFE 在 `http/1.1,h2` 与 `h2,http/1.1` 下均选 h2),而直连路径是 HTTP/1.1。
46
+ 3. **Node `fetch` 自带浏览器头与默认 ALPN**:undici 的 `fetch` 会为每条出站请求追加 `sec-fetch-mode: cors` 与 `accept-language: *`(原生 Go HTTP 客户端均不发);直连 TLS ClientHello 默认还会 offer `http/1.1`(原生 `language_server` 不发任何 ALPN 扩展)。
47
+ - **改法**(`src/host/proxy-manager.ts`、`src/index.ts`、`src/host/antigravity/types.ts`):
48
+ - **HTTP/1.1 协议钉死与按凭据分池**:`ProxyManager` 新增 `proxyAgentOptions()` 与 `createFetch({ allowH2: false, credentialPools: true })`。池键取自请求 `Authorization` 头 SHA-256 的前 16 位(映射表不存原始 token);代理路径按 `poolKey` 细分 pin 到 HTTP/1.1 的 `ProxyAgent`,直连路径改走 undici `fetch` + 每凭据独立 `Agent`(池总数上限 64,超限时对最旧池调 `close()` 平滑排空);不带 `Authorization` 的请求(Hub 清单、OAuth 换票)继续走共享池。其余 12 条线路的 dispatcher 与行为零变化。
49
+ - **Dispatcher 层剥离浏览器头与直连省略 ALPN**:`ProxyManager.createFetch()` 新增 `stripHeaders`(`stripDispatchHeaders` 在 dispatcher 层过滤 `ANTIGRAVITY_ABSENT_HEADERS`,`WeakMap` 缓存包装层保持池身份稳定;`connection: keep-alive` 会被 undici HTTP/1.1 writer 重加故不列入)与 `omitAlpn`(`buildNativeConnector` 自定义 TLS connector 不设 `ALPNProtocols`、显式填充 `servername` SNI、30 秒连接超时、HTTP 目标退回普通 TCP)。
50
+ - **回归**:`test/proxy-manager.test.ts` 与 `test/antigravity-proxy.test.ts` 新增 HTTP/1.1 协议钉死、按凭据分池(同 token 复用、异 token 隔离、无凭据走共享池、直连走独立 `Agent`)、对象/数组双形态 header 剥离、真实本地 HTTP 服务 `rawHeaders` 抓包、以及无 ALPN connector SNI 透传等用例。
51
+
52
+ - **[antigravity] 实测确认 TLS ClientHello 指纹无法在 Node 进程内对齐:不做原生模块,结论归档**
53
+ - **实测**(完整数据见 [`docs/antigravity-tls-fingerprint-probe.md`](docs/antigravity-tls-fingerprint-probe.md)):`tls-impersonate@0.2.2` 在 **Node 24.14.1** 上调用 `impersonate()` 会触发原生层崩溃(exit 127,无 JS 异常);在 **Node 24.20.0 / OpenSSL 3.5.7** 上虽可运行,但 OpenSSL 固定将 `ec_point_formats` 设为 `[0,1,2]`(Go 只发 `[0]`)、不支持自定义扩展 `50`,且**恒定把 TLS 1.3 套件排在 cipher 列表最前**(`0x1301,0x1302,0x1303,0xc02b,…,0xc014`),而 Go `crypto/tls` 是 TLS 1.2 列表在前、TLS 1.3 追加在后。
54
+ - **决定与残余边界**:不引入原生依赖、不加实验开关(低于 Node 24.15 会崩进程,且无法真正复刻 Go ClientHello;同时无任何实测表明 GFE 按 JA3/JA4 拦截)。本轮收敛后留存的已知差异仅剩:工具名与 schema 为 DSH 自有契约、TLS ClientHello 为 Node/OpenSSL、代理路径受 undici `ProxyAgent` 内部 endpoint connector 封装限制仍会携带 `http/1.1` ALPN、以及不带 `Authorization` 头的 OAuth 表单换票请求共用连接池。
55
+ - **验证**:`npm run typecheck`、`npx tsc -b --force`、全量 `npm test`(374 个文件 / 6880 例通过)与 `npm run build` 通过。
56
+
5
57
  ## 0.64.1 - 2026-11-08
6
58
 
7
59
  - **[client] 修复 0.64.0 的派发卡片撞车:整个客户端插件被回滚,设置枢纽与全部工具卡片一起消失**
package/lib/client.js CHANGED
@@ -5072,6 +5072,8 @@ window.__ModuleLoader__.load({
5072
5072
  unknownMetric: "暂无",
5073
5073
  cacheExpired: "本会话已空闲超过缓存有效期,下一轮将重新处理约 {tokens} 个 token。",
5074
5074
  cacheDrift: "最近前缀状态",
5075
+ cacheOpening: "开局继承",
5076
+ cacheOpeningValue: "{cached} / {tokens} tok({ratio})",
5075
5077
  cacheDriftFirst: "首个请求(缓存为空)",
5076
5078
  cacheDriftStable: "稳定(前缀未变)",
5077
5079
  cacheDriftSystemPrompt: "系统提示已变化(缓存失效)",
@@ -5243,6 +5245,8 @@ window.__ModuleLoader__.load({
5243
5245
  cacheWarmupSettled: "Steady state ({hits}/{required}) · cap {chars} chars",
5244
5246
  unknownMetric: "n/a",
5245
5247
  cacheDrift: "Last prefix state",
5248
+ cacheOpening: "Opening inheritance",
5249
+ cacheOpeningValue: "{cached} / {tokens} tok ({ratio})",
5246
5250
  cacheDriftFirst: "First request (cache cold)",
5247
5251
  cacheDriftStable: "Stable (prefix unchanged)",
5248
5252
  cacheDriftSystemPrompt: "System prompt changed (cache invalidated)",
@@ -6436,6 +6440,16 @@ window.__ModuleLoader__.load({
6436
6440
  children: driftLabel(status.cache.lastDrift, t)
6437
6441
  })]
6438
6442
  }),
6443
+ status.cache.opening !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6444
+ className: "dsha-row",
6445
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6446
+ className: "dsha-label",
6447
+ children: t.cacheOpening
6448
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6449
+ className: "dsha-value",
6450
+ children: t.cacheOpeningValue.replace("{cached}", status.cache.opening.cachedTokens.toLocaleString()).replace("{tokens}", status.cache.opening.promptTokens.toLocaleString()).replace("{ratio}", `${(status.cache.opening.hitRatio * 100).toFixed(1)}%`)
6451
+ })]
6452
+ }),
6439
6453
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6440
6454
  className: "dsha-row",
6441
6455
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -12286,6 +12300,7 @@ window.__ModuleLoader__.load({
12286
12300
  cacheRequestParamsOnHint: "已打开能力位:请求会带上缓存参数。该字段未在 Step 文档中说明,官方对 Step 端点默认也不发。",
12287
12301
  cachePricingNote: "单价未文档化(官方模型表里四个 cost 键全是 0),因此本页只展示 token 维度,不展示任何金额。",
12288
12302
  cacheEmpty: "本进程还没有任何请求回报过用量,跑一次对话后再看。",
12303
+ cacheExpiredHint: "缓存可能已过期:距上次请求约 {minutes} 分钟,下次会重新处理前缀。",
12289
12304
  cacheHitRatioUnavailable: "—"
12290
12305
  };
12291
12306
  const en$8 = {
@@ -12453,6 +12468,7 @@ window.__ModuleLoader__.load({
12453
12468
  cacheRequestParamsOnHint: "The capability is on: requests carry cache parameters. Step does not document them, and the official client does not send them to Step either.",
12454
12469
  cachePricingNote: "Unit prices are undocumented (all four cost keys are 0 in the official model table), so this page shows TOKENS ONLY and no money figure at all.",
12455
12470
  cacheEmpty: "No request on this machine has reported usage yet — run a conversation and look again.",
12471
+ cacheExpiredHint: "The cache has likely expired: about {minutes} minutes since the last request, so the next turn will reprocess the prefix.",
12456
12472
  cacheHitRatioUnavailable: "—"
12457
12473
  };
12458
12474
  const dictionaries$8 = {
@@ -13597,6 +13613,11 @@ window.__ModuleLoader__.load({
13597
13613
  })
13598
13614
  ]
13599
13615
  }),
13616
+ status?.cacheHint !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
13617
+ className: "dsha-muted",
13618
+ "data-dsh-part": "step-cache-hint",
13619
+ children: t.cacheExpiredHint.replace("{minutes}", String(Math.floor(status.cacheHint.idleMs / 6e4)))
13620
+ }),
13600
13621
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13601
13622
  className: "dsha-pref-row",
13602
13623
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.cacheRequestParams }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -21656,15 +21677,19 @@ window.__ModuleLoader__.load({
21656
21677
  settingsEnabledName: "进展更新",
21657
21678
  settingsEnabledNote: "让 agent 在对话中发布进展更新;本插件的所有线路都可用",
21658
21679
  settingsCacheWarmupName: "缓存预热",
21659
- settingsCacheWarmupNote: "Kimi Code 专用:投影大型日志结果,原文可通过 ref 按需补读;非 Kimi 线路开关无影响",
21680
+ settingsCacheWarmupNote: "按线路配置:投影大型日志结果,原文可通过 ref 按需补读;只影响之后的新结果",
21660
21681
  settingsRetrievalName: "检索结果投影",
21661
- settingsRetrievalNote: "Kimi Code 专用:导航任务中投影文件、网页与搜索,编辑审查保留原文;非 Kimi 线路开关无影响",
21682
+ settingsRetrievalNote: "按线路配置:导航任务中投影文件、网页与搜索,编辑审查保留原文;只影响之后的新结果",
21662
21683
  settingsCacheWaitWarmupName: "等待缓存续热",
21663
- settingsCacheWaitWarmupNote: "Kimi Code 专用:等待子代理期间每满 20 分钟自动触发一次轻量续热,只要子代理未完成就持续保活;非 Kimi 线路开关无影响",
21684
+ settingsCacheWaitWarmupNote: "等待子代理期间按缓存 TTL 轻量续热;默认用于 Kimi,其他线路需明确 TTL 并显式启用",
21685
+ settingsCacheAffinityName: "账号缓存亲和",
21686
+ settingsCacheAffinityNote: "多账号轮换时优先选前缀仍热的账号,低额度时让位;默认用于 Kimi,其他线路需证明账号级缓存并显式启用",
21664
21687
  settingsPlanModePipelineName: "计划模式管线",
21665
21688
  settingsPlanModePipelineNote: "澄清访谈收敛后自动进入计划模式出计划,再交审批(仅调度模式生效);关闭后该模式会请用户手动输入 /plan",
21666
21689
  settingsDispatchExecutionGuardName: "调度执行守卫",
21667
21690
  settingsDispatchExecutionGuardNote: "执行期拦截子代理越权调用主控工具及等待子代理时的纯 sleep 空等;不改工具声明面,零损耗保护 Kimi 缓存",
21691
+ settingsToolRunawayGuardName: "工具失控治理",
21692
+ settingsToolRunawayGuardNote: "同一工具与参数连续重复时分级提醒;Kimi 保留第 12 次强停,其他线路只提醒",
21668
21693
  settingsTeamPolicyCacheGuardName: "智能体团队策略段",
21669
21694
  settingsTeamPolicyCacheGuardNote: "把内置 Agent Teams 的策略段从系统提示词摘掉,改为开启团队协作时以尾部消息投递一次;会话中途切开关不再刷掉整段前缀缓存(默认开启)",
21670
21695
  settingsThresholdName: "催促阈值",
@@ -21705,15 +21730,19 @@ window.__ModuleLoader__.load({
21705
21730
  settingsEnabledName: "Progress updates",
21706
21731
  settingsEnabledNote: "Let the agent post progress updates in the conversation; every line of this plugin can use it",
21707
21732
  settingsCacheWarmupName: "Cache warmup",
21708
- settingsCacheWarmupNote: "Kimi Code only: project large log results and read the original on demand through a ref; no effect on other lines",
21733
+ settingsCacheWarmupNote: "Per-line control: project large log results and read the original through a ref on demand; only new results are affected",
21709
21734
  settingsRetrievalName: "Retrieval projection",
21710
- settingsRetrievalNote: "Kimi Code only: project files, pages, and searches for navigation; keep source verbatim for editing and review; no effect on other lines",
21735
+ settingsRetrievalNote: "Per-line control: project files, pages, and searches for navigation; keep source verbatim for editing and review; only new results are affected",
21711
21736
  settingsCacheWaitWarmupName: "Wait-time cache keepalive",
21712
- settingsCacheWaitWarmupNote: "Kimi Code only: trigger a lightweight warmup every 20 minutes while waiting for subagents so the prefix cache stays warm until they finish; no effect on other lines",
21737
+ settingsCacheWaitWarmupNote: "Keep the prefix warm while subagents run, using the line TTL; on by default for Kimi, other lines need a known TTL and explicit opt-in",
21738
+ settingsCacheAffinityName: "Account cache affinity",
21739
+ settingsCacheAffinityNote: "Prefer the account whose prefix is still warm, but yield when quota runs low; on by default for Kimi, other lines need proven account-scoped caching and explicit opt-in",
21713
21740
  settingsPlanModePipelineName: "Plan-mode pipeline",
21714
21741
  settingsPlanModePipelineNote: "After the clarification interview converges, enter plan mode, write the plan and send it for approval (dispatch mode only); turning it off makes that mode ask the user to type /plan",
21715
21742
  settingsDispatchExecutionGuardName: "Dispatch execution guard",
21716
21743
  settingsDispatchExecutionGuardNote: "Block subagents from calling dispatcher-only tools at execution time and reject pure sleep waits while child agents run; keeps tool declarations untouched to protect the Kimi prefix cache",
21744
+ settingsToolRunawayGuardName: "Tool runaway guard",
21745
+ settingsToolRunawayGuardNote: "Remind the agent when the same tool call repeats; Kimi keeps its 12th-call handoff, while other lines receive reminders only",
21717
21746
  settingsTeamPolicyCacheGuardName: "Agent Teams policy section",
21718
21747
  settingsTeamPolicyCacheGuardNote: "Lift the built-in Agent Teams policy section out of the system prompt and deliver it as one tail message when team collaboration is switched on, so toggling mid-session no longer rebuilds the whole prefix cache (on by default)",
21719
21748
  settingsThresholdName: "Nudge threshold",
@@ -22645,6 +22674,8 @@ window.__ModuleLoader__.load({
22645
22674
  unknownMetric: "нет данных",
22646
22675
  cacheExpired: "Сессия простаивала дольше времени жизни кеша, поэтому следующий ход заново обработает около {tokens} токенов.",
22647
22676
  cacheDrift: "Состояние последнего префикса",
22677
+ cacheOpening: "Наследование на старте",
22678
+ cacheOpeningValue: "{cached} / {tokens} ток. ({ratio})",
22648
22679
  cacheDriftFirst: "Первый запрос (кеш пуст)",
22649
22680
  cacheDriftStable: "Стабильно (префикс не менялся)",
22650
22681
  cacheDriftSystemPrompt: "Системный промпт изменился (кеш сброшен)",
@@ -23127,15 +23158,19 @@ window.__ModuleLoader__.load({
23127
23158
  settingsEnabledName: "Ход работы",
23128
23159
  settingsEnabledNote: "Разрешить агенту публиковать ход работы в диалоге; доступно на всех линиях этого плагина",
23129
23160
  settingsCacheWarmupName: "Прогрев кеша",
23130
- settingsCacheWarmupNote: "Только Kimi Code: проецировать большие журналы и читать оригинал по ref при необходимости; на других линиях переключатель ничего не меняет",
23161
+ settingsCacheWarmupNote: "По линиям: проецировать большие журналы и читать оригинал по ref при необходимости; затрагиваются только новые результаты",
23131
23162
  settingsRetrievalName: "Проекция результатов поиска",
23132
- settingsRetrievalNote: "Только Kimi Code: проецировать файлы, страницы и поиск при навигации; сохранять код при правке и ревью; на других линиях переключатель ничего не меняет",
23163
+ settingsRetrievalNote: "По линиям: проецировать файлы, страницы и поиск при навигации; сохранять код при правке и ревью; затрагиваются только новые результаты",
23133
23164
  settingsCacheWaitWarmupName: "Поддержание кеша при ожидании",
23134
- settingsCacheWaitWarmupNote: "Только Kimi Code: каждые 20 минут ожидания субагентов отправлять лёгкий прогрев, пока субагенты работают, чтобы префиксный кеш не остывал; на других линиях переключатель ничего не меняет",
23165
+ settingsCacheWaitWarmupNote: "Поддерживать префиксный кеш во время ожидания субагентов по TTL линии; по умолчанию для Kimi, другие линии требуют известный TTL и явного включения",
23166
+ settingsCacheAffinityName: "Сродство кеша учётных записей",
23167
+ settingsCacheAffinityNote: "Предпочитать учётную запись с ещё тёплым префиксом, уступая при низкой квоте; по умолчанию для Kimi, другие линии требуют доказанного разделения кеша по учётным записям и явного включения",
23135
23168
  settingsPlanModePipelineName: "Конвейер режима плана",
23136
23169
  settingsPlanModePipelineNote: "После схождения уточняющего интервью автоматически войти в режим плана, подготовить план и отправить его на утверждение (только в режиме диспетчера); если выключено, этот режим попросит пользователя ввести /plan вручную",
23137
23170
  settingsDispatchExecutionGuardName: "Защита выполнения диспетчера",
23138
23171
  settingsDispatchExecutionGuardNote: "Блокировать вызовы инструментов диспетчера субагентами во время выполнения и запрещать пустое ожидание sleep при активных дочерних агентах; не меняет объявления инструментов и сохраняет префиксный кеш Kimi",
23172
+ settingsToolRunawayGuardName: "Защита от циклов инструментов",
23173
+ settingsToolRunawayGuardNote: "Напоминать агенту о повторяющихся вызовах; Kimi сохраняет передачу управления на 12-м вызове, другие линии получают только напоминания",
23139
23174
  settingsTeamPolicyCacheGuardName: "Раздел политики Agent Teams",
23140
23175
  settingsTeamPolicyCacheGuardNote: "Убрать встроенный раздел политики Agent Teams из системного промпта и передавать его одним сообщением в хвосте при включении командной работы, чтобы переключение посреди сессии больше не пересобирало весь префиксный кеш (включено по умолчанию)",
23141
23176
  settingsThresholdName: "Порог напоминания",
@@ -23439,6 +23474,7 @@ window.__ModuleLoader__.load({
23439
23474
  cacheRequestParamsOnHint: "Возможность включена: запросы несут параметры кеша. Step их не документирует, и официальный клиент для Step их тоже не отправляет.",
23440
23475
  cachePricingNote: "Цены за единицу не документированы (все четыре ключа cost в официальной таблице моделей равны 0), поэтому страница показывает только токены и никаких сумм.",
23441
23476
  cacheEmpty: "Ни один запрос на этой машине ещё не сообщил расход — проведите диалог и посмотрите снова.",
23477
+ cacheExpiredHint: "Кеш, вероятно, истёк: с последнего запроса прошло около {minutes} мин., поэтому следующий шаг снова обработает префикс.",
23442
23478
  cacheHitRatioUnavailable: "—"
23443
23479
  };
23444
23480
  //#endregion
@@ -55503,6 +55539,37 @@ window.__ModuleLoader__.load({
55503
55539
  ]
55504
55540
  });
55505
55541
  }
55542
+ /** 账号缓存亲和那一行的标记:号池两层里靠上的那层带勾(优先用缓存还热的账号)。 */
55543
+ function CacheAffinityMark() {
55544
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
55545
+ viewBox: "0 0 20 20",
55546
+ width: "20",
55547
+ height: "20",
55548
+ fill: "none",
55549
+ stroke: "currentColor",
55550
+ strokeWidth: "1.6",
55551
+ strokeLinecap: "round",
55552
+ strokeLinejoin: "round",
55553
+ "aria-hidden": "true",
55554
+ children: [
55555
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
55556
+ x: "3.5",
55557
+ y: "3.8",
55558
+ width: "13",
55559
+ height: "5",
55560
+ rx: "1.6"
55561
+ }),
55562
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
55563
+ x: "3.5",
55564
+ y: "11.2",
55565
+ width: "13",
55566
+ height: "5",
55567
+ rx: "1.6"
55568
+ }),
55569
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m6.2 6.3 1.2 1.2 2.1-2.3" })
55570
+ ]
55571
+ });
55572
+ }
55506
55573
  /** 计划模式管线那一行的标记:一份带勾的计划(计划先出、再交审批)。 */
55507
55574
  function PlanModeMark() {
55508
55575
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
@@ -55643,8 +55710,10 @@ window.__ModuleLoader__.load({
55643
55710
  const cacheWarmup = value.cacheWarmup !== false;
55644
55711
  const retrieval = value.cacheWarmupRetrieval !== false;
55645
55712
  const cacheWaitWarmup = value.cacheWaitWarmup !== false;
55713
+ const cacheAffinity = value.cacheAffinity !== false;
55646
55714
  const planModePipeline = value.planModePipeline !== false;
55647
55715
  const dispatchExecutionGuard = value.dispatchExecutionGuard !== false;
55716
+ const toolRunawayGuard = value.toolRunawayGuard !== false;
55648
55717
  const teamPolicyCacheGuard = value.teamPolicyCacheGuard !== false;
55649
55718
  const threshold = typeof value.progressUpdatesNudgeThreshold === "number" ? value.progressUpdatesNudgeThreshold : 8;
55650
55719
  const language = value.progressUpdatesLanguage === "zh" || value.progressUpdatesLanguage === "en" || value.progressUpdatesLanguage === "ru" ? value.progressUpdatesLanguage : "auto";
@@ -55804,6 +55873,27 @@ window.__ModuleLoader__.load({
55804
55873
  }
55805
55874
  })
55806
55875
  }),
55876
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardRow, {
55877
+ part: "settings-row-cache-affinity",
55878
+ brand: "#1f7a52",
55879
+ mark: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CacheAffinityMark, {}),
55880
+ name: translate("settingsCacheAffinityName"),
55881
+ note: failure?.row === "cacheAffinity" ? failure.text : translate("settingsCacheAffinityNote"),
55882
+ danger: failure?.row === "cacheAffinity",
55883
+ enabled: cacheAffinity,
55884
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
55885
+ type: "button",
55886
+ role: "switch",
55887
+ "aria-checked": cacheAffinity,
55888
+ "aria-label": translate("settingsCacheAffinityName"),
55889
+ className: "dsh-progress-switch",
55890
+ "data-dsh-part": "settings-cache-affinity-switch",
55891
+ disabled: !writable,
55892
+ onClick: () => {
55893
+ write("cacheAffinity", "cacheAffinity", !cacheAffinity);
55894
+ }
55895
+ })
55896
+ }),
55807
55897
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardRow, {
55808
55898
  part: "settings-row-plan-mode-pipeline",
55809
55899
  brand: "#566179",
@@ -55846,6 +55936,27 @@ window.__ModuleLoader__.load({
55846
55936
  }
55847
55937
  })
55848
55938
  }),
55939
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardRow, {
55940
+ part: "settings-row-tool-runaway-guard",
55941
+ brand: "#a15c34",
55942
+ mark: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DispatchGuardMark, {}),
55943
+ name: translate("settingsToolRunawayGuardName"),
55944
+ note: failure?.row === "toolRunawayGuard" ? failure.text : translate("settingsToolRunawayGuardNote"),
55945
+ danger: failure?.row === "toolRunawayGuard",
55946
+ enabled: toolRunawayGuard,
55947
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
55948
+ type: "button",
55949
+ role: "switch",
55950
+ "aria-checked": toolRunawayGuard,
55951
+ "aria-label": translate("settingsToolRunawayGuardName"),
55952
+ className: "dsh-progress-switch",
55953
+ "data-dsh-part": "settings-tool-runaway-guard-switch",
55954
+ disabled: !writable,
55955
+ onClick: () => {
55956
+ write("toolRunawayGuard", "toolRunawayGuard", !toolRunawayGuard);
55957
+ }
55958
+ })
55959
+ }),
55849
55960
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardRow, {
55850
55961
  part: "settings-row-team-policy-cache-guard",
55851
55962
  brand: "#8a5a9e",