dsh-workbuddy-connect 0.7.5 → 0.7.7

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/README.en.md CHANGED
@@ -13,7 +13,7 @@ Brings the models available in your signed-in WorkBuddy / WorkBuddy AI desktop a
13
13
  ```text
14
14
  Please install and verify the DSH (DeepSeek Harness) plugin dsh-workbuddy-connect for me (project: https://github.com/corrinehu/dsh-workbuddy-connect).
15
15
  Start by reading the project README and confirming which interface I actually use (Web / Desktop / TUI) and its DSH core version — for the Desktop app, the bundled core, never the standalone CLI's version.
16
- Then install from the official npm package per the version mapping (0.2.0-rc.2 -> 0.7.5, rc.1 -> 0.7.0, 0.1.5-0.1.7 -> 0.6.5), preferring a locally supported non-market channel; on some Desktop distributions (the official Electron app in particular) the profile is app-managed and rules vary by distribution — check mine first, then explore its compliant install route, but never bypass its validation.
16
+ Then install from the official npm package per the version mapping (0.2.1-rc.1 -> 0.7.7, 0.2.0-rc.2 -> 0.7.6, rc.1 -> 0.7.0, 0.1.5-0.1.7 -> 0.6.5), preferring a locally supported non-market channel; on some Desktop distributions (the official Electron app in particular) the profile is app-managed and rules vary by distribution — check mine first, then explore its compliant install route, but never bypass its validation.
17
17
  Ask for my consent and make backups before changing any local files or configuration.
18
18
  After installing, verify the WorkBuddy group appears in the model picker and walk me through one short conversation.
19
19
  If the Desktop install still fails generation validation (e.g. the @types/retry false positive), report it honestly, reference upstream dataelement/dsh-desktop#688, and suggest switching to the standalone Web / TUI — do not modify dependency packages or bypass the check.
@@ -23,7 +23,8 @@ Core-to-plugin quick reference (full table in "Compatibility and release history
23
23
 
24
24
  | DSH core | Recommended plugin |
25
25
  |---|---|
26
- | 0.2.0-rc.2 | 0.7.5 (npm latest) |
26
+ | 0.2.1-rc.1 | 0.7.7 (npm latest) |
27
+ | 0.2.0-rc.2 | 0.7.6 |
27
28
  | 0.2.0-rc.1 | 0.7.0 |
28
29
  | 0.1.5 – 0.1.7 | 0.6.5 |
29
30
 
@@ -31,8 +32,8 @@ Core-to-plugin quick reference (full table in "Compatibility and release history
31
32
  <summary>Manual install (command line, Web / TUI only)</summary>
32
33
 
33
34
  ```sh
34
- # Web (pin per your actual core — example: 0.2.0-rc.2 -> 0.7.5; or install from source via github:corrinehu/dsh-workbuddy-connect)
35
- dsh plugin --profile web add dsh-workbuddy-connect@0.7.5
35
+ # Web (pin per your actual core — example: 0.2.0-rc.2 -> 0.7.6; or install from source via github:corrinehu/dsh-workbuddy-connect)
36
+ dsh plugin --profile web add dsh-workbuddy-connect@0.7.6
36
37
  dsh web
37
38
 
38
39
  # TUI (example for a 0.1.x core; that profile needs pnpm 11, e.g. npx pnpm@11)
@@ -126,7 +127,8 @@ The plugin version must match the DSH core — a mismatched combination fails to
126
127
 
127
128
  | DSH core | Recommended plugin | Notes |
128
129
  |---|---|---|
129
- | `0.2.0-rc.2` | `0.7.5` (npm latest) | Current line; fixes disappearing composer controls and WSL helper environment forwarding. Avoid 0.7.2 with its registry regression. |
130
+ | `0.2.1-rc.1` | `0.7.7` | Current line; the core moved to `@earendil-works/pi-ai` 1.3.0, so the plugin bundles 1.3.0 too — a leftover 0.87.1 overrides entry must be removed (see the pi-ai note below). |
131
+ | `0.2.0-rc.2` | `0.7.6` | Previous core line; fixes enterprise catalog gaps and international chat requests blocked by the upstream channel check. Avoid 0.7.2 with its registry regression. |
130
132
  | `0.2.0-rc.1` | `0.7.0` | 0.7.1 drops rc.1 support; stay on this version. |
131
133
  | `0.1.5` – `0.1.7` | `0.6.5` | Final release for the old cores; 0.7.0 targets 0.2.0 only. |
132
134
  | `0.1.2-rc.1` | `0.3.1` | Older line, historical maintenance only. |
@@ -134,6 +136,8 @@ The plugin version must match the DSH core — a mismatched combination fails to
134
136
 
135
137
  Release history (full records at [releases](https://github.com/corrinehu/dsh-workbuddy-connect/releases)):
136
138
 
139
+ - **0.7.7**: adapts to the DSH 0.2.1-rc.1 core: peers narrow to 0.2.1-rc.1 and the plugin-bundled `@earendil-works/pi-ai` moves to 1.3.0 with it (a profile-level leftover 0.87.1 overrides entry must be removed, or the plugin fails to load).
140
+ - **0.7.6**: fixes enterprise accounts missing `glm-5.3-flashx` from the model catalog ([#123](https://github.com/corrinehu/dsh-workbuddy-connect/issues/123)), and fixes international chat requests being blocked by the upstream channel check ([#139](https://github.com/corrinehu/dsh-workbuddy-connect/issues/139) / [#142](https://github.com/corrinehu/dsh-workbuddy-connect/issues/142)).
137
141
  - **0.7.5**: restores composer controls after session switching ([#125](https://github.com/corrinehu/dsh-workbuddy-connect/issues/125) / [#132](https://github.com/corrinehu/dsh-workbuddy-connect/issues/132)), fixes WSL helper environment forwarding ([#133](https://github.com/corrinehu/dsh-workbuddy-connect/issues/133)), and adds community projects to both READMEs.
138
142
  - **0.7.4**: Windows diagnostics and stability improvements: accurate classification of oversized registry-subprocess output, cross-platform test-assumption fixes ([#62](https://github.com/corrinehu/dsh-workbuddy-connect/issues/62)), and a reworked install section.
139
143
  - **0.7.3**: fixes Windows registry auto-discovery failing on non-default install paths ([#105](https://github.com/corrinehu/dsh-workbuddy-connect/issues/105)).
@@ -142,9 +146,9 @@ Release history (full records at [releases](https://github.com/corrinehu/dsh-wor
142
146
  - **0.7.0**: adapts to DSH 0.2.0's settings-service rework and drops 0.1.x support.
143
147
  - **0.6.5**: final release of the 0.1.x line.
144
148
 
145
- Pinned-version install example: `dsh plugin --profile web add dsh-workbuddy-connect@0.7.5`.
149
+ Pinned-version install example: `dsh plugin --profile web add dsh-workbuddy-connect@0.7.6`.
146
150
 
147
- **Do not upgrade the profile-level `@earendil-works/pi-ai` to 1.x**: this plugin and the `0.2.0-rc.2` generation of the DSH core both require `^0.87.1` (bundled by the plugin since 0.7.2), and third-party plugin managers' "updatable" prompts do not check peer constraints — do not act on them ([#86](https://github.com/corrinehu/dsh-workbuddy-connect/issues/86)); likewise, do not blindly remove a leftover `overrides: {'@earendil-works/pi-ai': '0.87.1'}` until you have confirmed nothing else depends on it.
151
+ **pi-ai versions are per core line and must not be mixed**: the 0.2.1-rc.1 core line (plugin 0.7.7+) moved to `@earendil-works/pi-ai` 1.3.0 (bundled by the plugin), so a profile-level leftover `overrides: {'@earendil-works/pi-ai': '0.87.1'}` **must be removed** or the plugin fails to load; the 0.2.0-rc.2 core line (plugin 0.7.6) still requires `^0.87.1` — on that line, **do not** upgrade the profile-level pi-ai to 1.x, and do not act on third-party plugin managers' "updatable" prompts, which do not check peer constraints ([#86](https://github.com/corrinehu/dsh-workbuddy-connect/issues/86)).
148
152
 
149
153
  ## Disclaimer
150
154
 
package/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  ```text
14
14
  请帮我安装并验证 DSH(DeepSeek Harness)插件 dsh-workbuddy-connect(项目地址:https://github.com/corrinehu/dsh-workbuddy-connect):
15
15
  先阅读项目 README,确认我实际使用的界面(Web / Desktop / TUI)与 DSH 内核版本,桌面版以 App 内置核心为准,不要用独立 CLI 的版本代替;
16
- 再按版本对应关系从 npm 正式包安装(0.2.0-rc.2→0.7.5、rc.1→0.7.0、0.1.5–0.1.7→0.6.5),优先走本机受支持的非插件市场渠道;部分 Desktop 发行版(尤其官方 Electron 版)的 profile 由 App 管理,各发行版规则未必相同,先确认我所用的发行版,再探查其合规的安装方式,但不得绕过其校验;
16
+ 再按版本对应关系从 npm 正式包安装(0.2.1-rc.1→0.7.7、0.2.0-rc.2→0.7.6、rc.1→0.7.0、0.1.5–0.1.7→0.6.5),优先走本机受支持的非插件市场渠道;部分 Desktop 发行版(尤其官方 Electron 版)的 profile 由 App 管理,各发行版规则未必相同,先确认我所用的发行版,再探查其合规的安装方式,但不得绕过其校验;
17
17
  任何本地文件或配置改动,先征得我同意并做好备份;
18
18
  装完后验证模型选择器里出现 WorkBuddy 分组,并陪我完成一次简短对话;
19
19
  若 Desktop 安装仍因 generation 校验失败(如 @types/retry 误报),请如实报告、参照上游 dataelement/dsh-desktop#688,并建议我改用独立的 Web / TUI,不要修改依赖包或绕过校验。
@@ -23,7 +23,8 @@
23
23
 
24
24
  | DSH 内核 | 推荐插件版 |
25
25
  |---|---|
26
- | 0.2.0-rc.2 | 0.7.5(npm latest) |
26
+ | 0.2.1-rc.1 | 0.7.7(npm latest) |
27
+ | 0.2.0-rc.2 | 0.7.6 |
27
28
  | 0.2.0-rc.1 | 0.7.0 |
28
29
  | 0.1.5 – 0.1.7 | 0.6.5 |
29
30
 
@@ -31,8 +32,8 @@
31
32
  <summary>手动安装(命令行,仅 Web / TUI)</summary>
32
33
 
33
34
  ```sh
34
- # Web(按实际内核固定版本,示例为 0.2.0-rc.2 → 0.7.5;也可用 github:corrinehu/dsh-workbuddy-connect 从源码安装)
35
- dsh plugin --profile web add dsh-workbuddy-connect@0.7.5
35
+ # Web(按实际内核固定版本,示例为 0.2.0-rc.2 → 0.7.6;也可用 github:corrinehu/dsh-workbuddy-connect 从源码安装)
36
+ dsh plugin --profile web add dsh-workbuddy-connect@0.7.6
36
37
  dsh web
37
38
 
38
39
  # TUI(示例为 0.1.x 内核;该 profile 需用 pnpm 11 安装,如 npx pnpm@11)
@@ -127,7 +128,8 @@ dsh plugin --profile web exec dsh-workbuddy-connect doctor --provider workbuddy-
127
128
 
128
129
  | DSH 内核 | 推荐插件版 | 注意事项 |
129
130
  |---|---|---|
130
- | `0.2.0-rc.2` | `0.7.5`(npm latest) | 当前最新线;修复输入框组件消失与 WSL helper 环境转发,勿停留在有注册表回归的 0.7.2。 |
131
+ | `0.2.1-rc.1` | `0.7.7` | 当前最新线;内核升级到 `@earendil-works/pi-ai` 1.3.0,插件同步自带 1.3.0,历史遗留的 0.87.1 overrides 必须移除(见下方 pi-ai 说明)。 |
132
+ | `0.2.0-rc.2` | `0.7.6` | 上一代内核线;修复企业账号模型目录缺项与国际版对话被渠道校验拦截,勿停留在有注册表回归的 0.7.2。 |
131
133
  | `0.2.0-rc.1` | `0.7.0` | 0.7.1 起不再支持 rc.1,请停留本版。 |
132
134
  | `0.1.5` – `0.1.7` | `0.6.5` | 旧内核最终版;0.7.0 起仅面向 0.2.0。 |
133
135
  | `0.1.2-rc.1` | `0.3.1` | 更早旧线,仅历史维护。 |
@@ -135,6 +137,9 @@ dsh plugin --profile web exec dsh-workbuddy-connect doctor --provider workbuddy-
135
137
 
136
138
  历次更新(完整记录见 [releases](https://github.com/corrinehu/dsh-workbuddy-connect/releases)):
137
139
 
140
+ - **0.7.7**:适配 DSH 0.2.1-rc.1 内核:peer 收窄到 0.2.1-rc.1,插件自带的 `@earendil-works/pi-ai` 随内核升级到 1.3.0(profile 级历史遗留的 0.87.1 overrides 必须移除,否则插件无法加载);修复国际版与国内版推理档位检测停留「检测未完成」——上游把档位拒绝码改拼为 `invalid_parameter_value`([#143](https://github.com/corrinehu/dsh-workbuddy-connect/issues/143) / [#148](https://github.com/corrinehu/dsh-workbuddy-connect/issues/148),PR [#145](https://github.com/corrinehu/dsh-workbuddy-connect/pull/145));修复中文 Windows 控制台下注册表缺键诊断因 GBK 编码被误判(zh-CN 实机验证)。
141
+ - **0.7.6**:修复企业账号模型目录缺少 `glm-5.3-flashx`([#123](https://github.com/corrinehu/dsh-workbuddy-connect/issues/123)),修复国际版对话请求被上游渠道校验拦截([#139](https://github.com/corrinehu/dsh-workbuddy-connect/issues/139) / [#142](https://github.com/corrinehu/dsh-workbuddy-connect/issues/142))。
142
+ - **0.7.5**:修复切换会话后输入框余额与刷新按钮消失([#125](https://github.com/corrinehu/dsh-workbuddy-connect/issues/125) / [#132](https://github.com/corrinehu/dsh-workbuddy-connect/issues/132)),修复 WSL 调用 Windows 凭据解密程序的环境转发([#133](https://github.com/corrinehu/dsh-workbuddy-connect/issues/133)),README 收录社区项目([#130](https://github.com/corrinehu/dsh-workbuddy-connect/issues/130))。
138
143
  - **0.7.4**:Windows 诊断与稳定性改进:注册表子进程输出超限准确分类、跨平台测试假设修正([#62](https://github.com/corrinehu/dsh-workbuddy-connect/issues/62)),安装说明重排。
139
144
  - **0.7.3**:修复 Windows 非默认安装路径下注册表自动发现失败([#105](https://github.com/corrinehu/dsh-workbuddy-connect/issues/105))。
140
145
  - **0.7.2**:pi-ai 改为插件自带依赖,并修复推理字段请求被拒([#92](https://github.com/corrinehu/dsh-workbuddy-connect/issues/92));该版存在 Windows 注册表回归,请使用 0.7.4 或更新的正式版本。
@@ -142,9 +147,9 @@ dsh plugin --profile web exec dsh-workbuddy-connect doctor --provider workbuddy-
142
147
  - **0.7.0**:适配 DSH 0.2.0 的设置服务改造,不再支持 0.1.x。
143
148
  - **0.6.5**:0.1.x 线最终版本。
144
149
 
145
- 固定版本安装示例:`dsh plugin --profile web add dsh-workbuddy-connect@0.7.5`。
150
+ 固定版本安装示例:`dsh plugin --profile web add dsh-workbuddy-connect@0.7.6`。
146
151
 
147
- **不要把 profile 级的 `@earendil-works/pi-ai` 升到 1.x**:本插件与 `0.2.0-rc.2` 这一代内核都要求 `^0.87.1`(0.7.2 起由插件自带),第三方插件管理器的「可更新」提示不校验 peer 约束、不能照做([#86](https://github.com/corrinehu/dsh-workbuddy-connect/issues/86));为此历史遗留的 `overrides: {'@earendil-works/pi-ai': '0.87.1'}` 在确认其他插件不依赖前也不要盲目移除。
152
+ **pi-ai 版本按内核线区分,不能混**:0.2.1-rc.1 内核线(插件 0.7.7+)已升级到 `@earendil-works/pi-ai` 1.3.0(由插件自带),profile 级历史遗留的 `overrides: {'@earendil-works/pi-ai': '0.87.1'}` **必须移除**,否则插件会因加载到旧一代 pi-ai 而启动失败;0.2.0-rc.2 内核线(插件 0.7.6)仍要求 `^0.87.1`,在这条线上**不要**把 profile 级的 pi-ai 升到 1.x,第三方插件管理器的「可更新」提示不校验 peer 约束、不能照做([#86](https://github.com/corrinehu/dsh-workbuddy-connect/issues/86))。
148
153
 
149
154
  ## 免责声明
150
155
 
package/lib/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as WORKBUDDY_VARIANTS, O as WorkBuddyUpstreamClient, Q as resolveAppVersion, S as CN_VARIANT, a as readHostHeartbeat, b as atRestKeyProviderFor, c as WORKBUDDY_CONNECT_VERSION, l as FALLBACK_WORKBUDDY_AI_MODELS, m as WorkBuddyCredentialStore, o as workbuddyHostHeartbeatPath, r as isHeartbeatProcessAlive, u as FALLBACK_WORKBUDDY_MODELS, w as variantFor } from "./host-heartbeat-CvtbpuQi.js";
2
+ import { C as WORKBUDDY_VARIANTS, O as WorkBuddyUpstreamClient, Q as resolveAppVersion, S as CN_VARIANT, a as readHostHeartbeat, b as atRestKeyProviderFor, c as WORKBUDDY_CONNECT_VERSION, l as FALLBACK_WORKBUDDY_AI_MODELS, m as WorkBuddyCredentialStore, o as workbuddyHostHeartbeatPath, r as isHeartbeatProcessAlive, u as FALLBACK_WORKBUDDY_MODELS, w as variantFor } from "./host-heartbeat-FytEpUGO.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
@@ -2772,7 +2772,7 @@ window.__ModuleLoader__.load({
2772
2772
  };
2773
2773
  //#endregion
2774
2774
  //#region src/version.ts
2775
- const WORKBUDDY_CONNECT_VERSION = "0.7.5";
2775
+ const WORKBUDDY_CONNECT_VERSION = "0.7.7";
2776
2776
  //#endregion
2777
2777
  //#region src/client/WorkBuddyConfigPage.tsx
2778
2778
  /**
@@ -3,7 +3,7 @@ import { homedir, release } from "node:os";
3
3
  import { basename, dirname, join } from "node:path";
4
4
  import { withFileLock, writeFileAtomic } from "@deepseek-ai/dsh-atomic-write";
5
5
  import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
6
- import { createDecipheriv, createHash, randomBytes } from "node:crypto";
6
+ import { createDecipheriv, createHash, randomBytes, randomUUID } from "node:crypto";
7
7
  import { execFile, execFileSync } from "node:child_process";
8
8
  import { accessSync, constants, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
9
9
  //#region src/app-version.ts
@@ -396,22 +396,37 @@ function randomSentinel() {
396
396
  * - `model_param_invalid` — the global endpoint, measured 2026-10-01. A
397
397
  * non-canonical value is answered `400` / `11133` with this code, which names
398
398
  * no field (`extError.param` is empty), instead of one that names the effort.
399
- * It is generic enough to be readable here only because the baseline step has
400
- * already proved the *same* request without `reasoning_effort` succeeds,
401
- * leaving the sentinel as the only difference between the two attempts. A
402
- * sibling code in the same `11133` envelope that names another parameter
403
- * (`integer_below_min_value`, the `max_tokens` floor) and a body carrying no
404
- * `extError` at all (`11102`, unknown model) are therefore not mistaken for
405
- * it, and neither is a level-sweep answer. It is *not* added to `cn`: that
406
- * endpoint was measured answering the specific code, and reading a generic
407
- * code there would widen attribution beyond what was observed.
399
+ * - `invalid_parameter_value` — both endpoints. Measured on the global
400
+ * endpoint 2026-10-16 (issue #143); observed on the China endpoint the same
401
+ * day (`deepseek-v4-pro`, PR #145 discussion) and reproduced there
402
+ * 2026-10-17 on WorkBuddy CN 5.8.2. The *same* `400` / `11133` envelope as
403
+ * `model_param_invalid`, with `extError.code` respelled and the `msg`
404
+ * unchanged; a non-canonical value is again what triggers it and the
405
+ * baseline still answers 200. Kept alongside the old spellings rather than
406
+ * replacing them: the rename was observed on the gateways, not promised for
407
+ * every model behind them.
408
408
  *
409
- * Neither is treated as a permanent protocol promise: anything unrecognized
410
- * still degrades to `unknown` rather than to a capability conclusion.
409
+ * The generic codes name no effort field. They are readable here only
410
+ * because the baseline step has already proved the *same* request without
411
+ * `reasoning_effort` succeeds, leaving the sentinel as the only difference
412
+ * between the two attempts — an isolation that holds per endpoint, which is
413
+ * why both regions read the respelled spelling once each was observed on it.
414
+ * A sibling code in the same `11133` envelope that names another parameter
415
+ * (`integer_below_min_value`, the `max_tokens` floor) and a body carrying no
416
+ * `extError` at all (`11102`, unknown model) are therefore not mistaken for
417
+ * them, and neither is a level-sweep answer.
418
+ *
419
+ * None of these is treated as a permanent protocol promise: anything
420
+ * unrecognized still degrades to `unknown` rather than to a capability
421
+ * conclusion.
411
422
  */
412
423
  const INVALID_EFFORT_CODES = {
413
- cn: /* @__PURE__ */ new Set(["invalid_reasoning_effort"]),
414
- global: /* @__PURE__ */ new Set(["invalid_reasoning_effort", "model_param_invalid"])
424
+ cn: /* @__PURE__ */ new Set(["invalid_reasoning_effort", "invalid_parameter_value"]),
425
+ global: /* @__PURE__ */ new Set([
426
+ "invalid_reasoning_effort",
427
+ "model_param_invalid",
428
+ "invalid_parameter_value"
429
+ ])
415
430
  };
416
431
  /** Whether an attempt is an attributable rejection of the effort value. */
417
432
  function isEffortRejection(attempt, region) {
@@ -709,11 +724,39 @@ function commonHeaders(credential) {
709
724
  };
710
725
  }
711
726
  /**
727
+ * The conversation-channel trio the chat endpoints require.
728
+ *
729
+ * Since 2026-10-16 `www.workbuddy.ai` answers any `/v2/chat/completions`
730
+ * request that omits all three `X-Conversation-*` headers with `400` /
731
+ * `code 11128` / `msg: "conversation id missing"`, whose `displayMsg.zh` is
732
+ * 「请求被拦截,请重新发送」 (issue #139). The official desktop client sends
733
+ * the trio on chat and speech alike — read out of `resources/app.asar`, where
734
+ * the names are `X-Conversation-ID`, `X-Conversation-Request-ID` and
735
+ * `X-Conversation-Message-ID`.
736
+ *
737
+ * A fresh UUID per request is enough, and is what the wire measurement
738
+ * supports: the upstream keeps no history keyed by the id (two calls sharing
739
+ * one id, the second carrying only `system` + `user`, still answered "I don't
740
+ * know"), so the trio marks the channel rather than carrying conversation
741
+ * state. Fresh ids also keep concurrent sub-agents off one shared
742
+ * conversation. The CN gateway was measured accepting the same trio (200 with
743
+ * and without), so both regions carry it and the two paths cannot drift.
744
+ */
745
+ function conversationHeaders() {
746
+ return {
747
+ "X-Conversation-ID": randomUUID(),
748
+ "X-Conversation-Request-ID": randomUUID(),
749
+ "X-Conversation-Message-ID": randomUUID()
750
+ };
751
+ }
752
+ /**
712
753
  * Chat request headers, including the X-No-* conventions the official CLI uses.
713
754
  *
714
755
  * `userAgent` and `clientVersion` carry the same resolved desktop identity for
715
756
  * chat and probe requests. Refresh shares `commonHeaders` but never this
716
- * override, so the two paths cannot drift into each other.
757
+ * override, so the two paths cannot drift into each other. The
758
+ * `X-Conversation-*` trio rides along too — see {@link conversationHeaders} —
759
+ * because the international gateway rejects a chat that omits it.
717
760
  */
718
761
  function chatHeaders(credential, userAgent, clientVersion) {
719
762
  return {
@@ -726,7 +769,8 @@ function chatHeaders(credential, userAgent, clientVersion) {
726
769
  "X-IDE-Type": "WorkBuddy",
727
770
  "X-IDE-Name": "WorkBuddy",
728
771
  "X-IDE-Version": clientVersion,
729
- "X-Product": "SaaS"
772
+ "X-Product": "SaaS",
773
+ ...conversationHeaders()
730
774
  };
731
775
  }
732
776
  /** Refresh-endpoint headers; X-Refresh-Token appears here and nowhere else. */
@@ -755,6 +799,28 @@ function billingHeaders(credential) {
755
799
  return headers;
756
800
  }
757
801
  /**
802
+ * Account-identity headers for the CN catalog requests (`/v3/config` and the
803
+ * console badge read). The gateway also splits `/v3/config` by account
804
+ * identity: an enterprise account without this pair is silently answered with
805
+ * the personal roster (issue #123 — 18 vs 19 models, FlashX missing), and the
806
+ * pair is all-or-nothing there: `X-Enterprise-Id` alone is rejected outright
807
+ * while `X-User-Id` alone selects nothing. So the block is emitted only when
808
+ * both parts exist, and personal accounts keep the bare headers their roster
809
+ * was already correct under. `X-Tenant-Id`/`X-Domain` ride along in the
810
+ * spelling `billingHeaders` already proved the gateway accepts.
811
+ */
812
+ function identityHeaders(credential) {
813
+ if (credential.uid === "") return {};
814
+ if (credential.enterpriseId === void 0 || credential.enterpriseId === "") return {};
815
+ const headers = {
816
+ "X-User-Id": credential.uid,
817
+ "X-Enterprise-Id": credential.enterpriseId,
818
+ "X-Tenant-Id": credential.enterpriseId
819
+ };
820
+ if (credential.domain !== "") headers["X-Domain"] = credential.domain;
821
+ return headers;
822
+ }
823
+ /**
758
824
  * Normalize an OpenAI chat-completions body for the WorkBuddy upstream:
759
825
  * force `stream: true` (the upstream rejects non-streaming), flatten
760
826
  * `tool_choice` (the upstream's field is a string; object forms return 400),
@@ -1036,6 +1102,13 @@ var WorkBuddyUpstreamClient = class {
1036
1102
  * advertises is exactly the one its own requests can use. The international
1037
1103
  * variant has no CLI identity, so it keeps the App-shaped UA.
1038
1104
  *
1105
+ * The same split has an account-identity axis (issue #123): an enterprise
1106
+ * account must also present `X-User-Id` + `X-Enterprise-Id`, or the gateway
1107
+ * answers with the personal roster. CN sends that pair via
1108
+ * {@link identityHeaders} whenever the credential carries both halves; the
1109
+ * international gateway's split was never measured against account headers,
1110
+ * so it keeps its documented shape.
1111
+ *
1039
1112
  * Membership is the `cli` roster intersected with the usable rows (see
1040
1113
  * {@link parseModelCatalog}); the promo badges the product document does
1041
1114
  * not carry are merged in from a best-effort console read — see
@@ -1057,7 +1130,7 @@ var WorkBuddyUpstreamClient = class {
1057
1130
  ...international ? {
1058
1131
  "X-Requested-With": "XMLHttpRequest",
1059
1132
  "X-Product": "SaaS"
1060
- } : {},
1133
+ } : identityHeaders(credential),
1061
1134
  "User-Agent": appVersion === void 0 ? CLIENT_UA : appUserAgent(appVersion.version)
1062
1135
  },
1063
1136
  signal: signal === void 0 ? AbortSignal.timeout(JSON_TIMEOUT_MS) : AbortSignal.any([signal, AbortSignal.timeout(JSON_TIMEOUT_MS)])
@@ -1094,6 +1167,7 @@ var WorkBuddyUpstreamClient = class {
1094
1167
  Accept: "application/json",
1095
1168
  Origin: originReferer(credential),
1096
1169
  Referer: `${originReferer(credential)}/`,
1170
+ ...identityHeaders(credential),
1097
1171
  "User-Agent": CLIENT_UA
1098
1172
  },
1099
1173
  signal: signal === void 0 ? AbortSignal.timeout(JSON_TIMEOUT_MS) : AbortSignal.any([signal, AbortSignal.timeout(JSON_TIMEOUT_MS)])
@@ -2351,7 +2425,7 @@ function workBuddyWindowsDiscoveryTools() {
2351
2425
  if (settled) return;
2352
2426
  settled = true;
2353
2427
  if (error !== null && error !== void 0) {
2354
- if (error.killed !== true && (error.code === 1 || error.code === "1") && windowsRegistryKeyMissing(stderr.toString("utf8"))) {
2428
+ if (error.killed !== true && (error.code === 1 || error.code === "1") && windowsRegistryKeyMissingFromBytes(stderr)) {
2355
2429
  resolve(Buffer.alloc(0));
2356
2430
  return;
2357
2431
  }
@@ -2770,6 +2844,24 @@ function windowsRegistryKeyMissing(stderr) {
2770
2844
  return /^ERROR:\s*The system was unable to find the specified registry key or value\.?$/iu.test(detail) || /^错误[::]\s*系统找不到指定的注册表项或值[。.]?$/u.test(detail);
2771
2845
  }
2772
2846
  /**
2847
+ * Reg.exe speaks the console OEM code page, not UTF-8: on a zh-CN install the
2848
+ * missing-key diagnostic arrives as cp936 bytes, which UTF-8 decoding turns
2849
+ * into mojibake no diagnostic regex can match — the query then reads as
2850
+ * "incomplete" on every absent root. Extension of #88's byte-level principle:
2851
+ * the bytes decide, so decode as UTF-8 first and then as GBK. ASCII — every
2852
+ * English diagnostic — is identical under both, so a match is unambiguous and
2853
+ * recognition only ever widens; a genuine failure (access denied, unknown
2854
+ * diagnostics) still stays incomplete in either decode.
2855
+ */
2856
+ function windowsRegistryKeyMissingFromBytes(stderr) {
2857
+ if (windowsRegistryKeyMissing(stderr.toString("utf8"))) return true;
2858
+ try {
2859
+ return windowsRegistryKeyMissing(new TextDecoder("gbk").decode(stderr));
2860
+ } catch {
2861
+ return false;
2862
+ }
2863
+ }
2864
+ /**
2773
2865
  * Parse the value columns emitted by `reg query ... /s`.
2774
2866
  *
2775
2867
  * Entries are filtered by the product's DisplayName pattern *before* the
@@ -4118,7 +4210,7 @@ var WorkBuddyCatalog = class {
4118
4210
  };
4119
4211
  //#endregion
4120
4212
  //#region src/version.ts
4121
- const WORKBUDDY_CONNECT_VERSION = "0.7.5";
4213
+ const WORKBUDDY_CONNECT_VERSION = "0.7.7";
4122
4214
  //#endregion
4123
4215
  //#region src/host-heartbeat.ts
4124
4216
  /**
package/lib/index.d.ts CHANGED
@@ -508,6 +508,13 @@ declare class WorkBuddyUpstreamClient {
508
508
  * advertises is exactly the one its own requests can use. The international
509
509
  * variant has no CLI identity, so it keeps the App-shaped UA.
510
510
  *
511
+ * The same split has an account-identity axis (issue #123): an enterprise
512
+ * account must also present `X-User-Id` + `X-Enterprise-Id`, or the gateway
513
+ * answers with the personal roster. CN sends that pair via
514
+ * {@link identityHeaders} whenever the credential carries both halves; the
515
+ * international gateway's split was never measured against account headers,
516
+ * so it keeps its documented shape.
517
+ *
511
518
  * Membership is the `cli` roster intersected with the usable rows (see
512
519
  * {@link parseModelCatalog}); the promo badges the product document does
513
520
  * not carry are merged in from a best-effort console read — see
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as validAppVersion, A as extractDisplayErrorMessage, B as randomSentinel, C as WORKBUDDY_VARIANTS, D as WORKBUDDY_UPDATE_PATH, F as prepareCnChatBody, G as readCliVersion, H as FALLBACK_CN_APP_VERSION, I as prepareInternationalChatBody, J as WORKBUDDY_APP_VERSION_FILENAME, K as resolveChatIdentity, L as regionOf, M as normalizeCredits, N as parseModelCatalog, O as WorkBuddyUpstreamClient, P as prepareChatBody, Q as resolveAppVersion, R as PROBE_EFFORT_CANDIDATES, S as CN_VARIANT, U as chatUserAgent, V as CN_APP_VERSION_FILENAME, W as fallbackChatIdentity, X as installedAppVersion, Y as appUserAgent, Z as readBundleVersion, _ as desktopAuthCandidatesFor, a as readHostHeartbeat, b as atRestKeyProviderFor, c as WORKBUDDY_CONNECT_VERSION, d as WorkBuddyCatalog, f as WORKBUDDY_AUTH_FILENAME, g as defaultDesktopAuthPath, h as defaultDesktopAuthCandidates, i as processStartTimeMs, j as modelWithCurrentPromotion, k as classifyUpstreamError, l as FALLBACK_WORKBUDDY_AI_MODELS, m as WorkBuddyCredentialStore, n as clearHostHeartbeat, o as workbuddyHostHeartbeatPath, p as WORKBUDDY_AUTH_FILE_ENV, q as validCliVersion, r as isHeartbeatProcessAlive, s as writeHostHeartbeat, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, u as FALLBACK_WORKBUDDY_MODELS, v as parseWorkBuddyAuth, w as variantFor, x as AI_VARIANT, y as workbuddyOwnAuthPath, z as probeModel } from "./host-heartbeat-CvtbpuQi.js";
1
+ import { $ as validAppVersion, A as extractDisplayErrorMessage, B as randomSentinel, C as WORKBUDDY_VARIANTS, D as WORKBUDDY_UPDATE_PATH, F as prepareCnChatBody, G as readCliVersion, H as FALLBACK_CN_APP_VERSION, I as prepareInternationalChatBody, J as WORKBUDDY_APP_VERSION_FILENAME, K as resolveChatIdentity, L as regionOf, M as normalizeCredits, N as parseModelCatalog, O as WorkBuddyUpstreamClient, P as prepareChatBody, Q as resolveAppVersion, R as PROBE_EFFORT_CANDIDATES, S as CN_VARIANT, U as chatUserAgent, V as CN_APP_VERSION_FILENAME, W as fallbackChatIdentity, X as installedAppVersion, Y as appUserAgent, Z as readBundleVersion, _ as desktopAuthCandidatesFor, a as readHostHeartbeat, b as atRestKeyProviderFor, c as WORKBUDDY_CONNECT_VERSION, d as WorkBuddyCatalog, f as WORKBUDDY_AUTH_FILENAME, g as defaultDesktopAuthPath, h as defaultDesktopAuthCandidates, i as processStartTimeMs, j as modelWithCurrentPromotion, k as classifyUpstreamError, l as FALLBACK_WORKBUDDY_AI_MODELS, m as WorkBuddyCredentialStore, n as clearHostHeartbeat, o as workbuddyHostHeartbeatPath, p as WORKBUDDY_AUTH_FILE_ENV, q as validCliVersion, r as isHeartbeatProcessAlive, s as writeHostHeartbeat, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, u as FALLBACK_WORKBUDDY_MODELS, v as parseWorkBuddyAuth, w as variantFor, x as AI_VARIANT, y as workbuddyOwnAuthPath, z as probeModel } from "./host-heartbeat-FytEpUGO.js";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { resolveImageAttachmentAccess, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
4
4
  import { dirname, join, resolve } from "node:path";
@@ -1159,7 +1159,7 @@ var WorkBuddyProbeService = class {
1159
1159
  //#region src/pi-ai-guard.ts
1160
1160
  /**
1161
1161
  * Confirm the pi-ai copy this plugin actually loaded is the generation the DSH
1162
- * 0.2.0-rc.2 host was built against.
1162
+ * 0.2.1-rc.1 host was built against.
1163
1163
  *
1164
1164
  * #92's failure mode: a pnpm profile with `nodeLinker: hoisted` and
1165
1165
  * `autoInstallPeers: false` installs no peer for us, so a co-installed
@@ -1178,7 +1178,7 @@ var WorkBuddyProbeService = class {
1178
1178
  * @module dsh-workbuddy-connect/pi-ai-guard
1179
1179
  */
1180
1180
  /** The pi-ai generation this plugin is built and tested against. */
1181
- const REQUIRED_PI_AI_VERSION = "0.87.1";
1181
+ const REQUIRED_PI_AI_VERSION = "1.3.0";
1182
1182
  /**
1183
1183
  * Read the version of the pi-ai copy Node resolves for *this* module.
1184
1184
  *
@@ -1225,7 +1225,7 @@ function resolvedPiAiVersion() {
1225
1225
  */
1226
1226
  function piAiVersionWarning(resolved) {
1227
1227
  const version = arguments.length === 0 ? resolvedPiAiVersion() : resolved;
1228
- if (version === void 0 || version === "0.87.1") return void 0;
1228
+ if (version === void 0 || version === "1.3.0") return void 0;
1229
1229
  return `loaded @earendil-works/pi-ai ${version}, but this plugin is built for ${REQUIRED_PI_AI_VERSION}. The wrong copy is being resolved — check the profile's pi-ai install (a pnpm profile with nodeLinker "hoisted" and autoInstallPeers false can expose another package's older copy). Reinstalling the plugin so it installs its own ${REQUIRED_PI_AI_VERSION} copy resolves it`;
1230
1230
  }
1231
1231
  //#endregion
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "dsh-workbuddy-connect",
3
3
  "displayName": "DSH WorkBuddy Connect",
4
4
  "description": "将 WorkBuddy 桌面 App 包含的模型自动接入 DeepSeek Harness — bring WorkBuddy desktop app models into DeepSeek Harness with zero configuration.",
5
- "version": "0.7.5",
5
+ "version": "0.7.7",
6
6
  "author": "corrinehu",
7
7
  "keywords": [
8
8
  "dsh-plugin",
@@ -67,42 +67,42 @@
67
67
  }
68
68
  },
69
69
  "dependencies": {
70
- "@earendil-works/pi-ai": "0.87.1"
70
+ "@earendil-works/pi-ai": "1.3.0"
71
71
  },
72
72
  "peerDependencies": {
73
- "@deepseek-ai/cordis": "^4.0.2",
74
- "@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
75
- "@deepseek-ai/dsh-attachment": "0.2.0-rc.2",
76
- "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
77
- "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2",
78
- "@deepseek-ai/dsh-llm": "0.2.0-rc.2",
79
- "@deepseek-ai/dsh-llm-pi-ai": "0.2.0-rc.2",
80
- "@deepseek-ai/dsh-settings": "0.2.0-rc.2",
81
- "@deepseek-ai/schemastery": "^3.18.2",
73
+ "@deepseek-ai/cordis": "^4.0.5",
74
+ "@deepseek-ai/dsh-atomic-write": "0.2.1-rc.1",
75
+ "@deepseek-ai/dsh-attachment": "0.2.1-rc.1",
76
+ "@deepseek-ai/dsh-home-paths": "0.2.1-rc.1",
77
+ "@deepseek-ai/dsh-host-webserver": "0.2.1-rc.1",
78
+ "@deepseek-ai/dsh-llm": "0.2.1-rc.1",
79
+ "@deepseek-ai/dsh-llm-pi-ai": "0.2.1-rc.1",
80
+ "@deepseek-ai/dsh-settings": "0.2.1-rc.1",
81
+ "@deepseek-ai/schemastery": "^3.18.5",
82
82
  "react": "^18.2.0"
83
83
  },
84
84
  "devDependencies": {
85
- "@deepseek-ai/cordis": "^4.0.4",
86
- "@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
87
- "@deepseek-ai/dsh-attachment": "0.2.0-rc.2",
88
- "@deepseek-ai/dsh-client-locale": "0.2.0-rc.2",
89
- "@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.2",
90
- "@deepseek-ai/dsh-client-ui-model-selection": "0.2.0-rc.2",
91
- "@deepseek-ai/dsh-client-ui-plugin-manager": "0.2.0-rc.2",
92
- "@deepseek-ai/dsh-client-ui-settings-plugins": "0.2.0-rc.2",
93
- "@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.2",
94
- "@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.2",
95
- "@deepseek-ai/dsh-credentials": "0.2.0-rc.2",
96
- "@deepseek-ai/dsh-authorization": "0.2.0-rc.2",
97
- "@deepseek-ai/dsh-fs": "0.2.0-rc.2",
98
- "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2",
99
- "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
100
- "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2",
101
- "@deepseek-ai/dsh-llm": "0.2.0-rc.2",
102
- "@deepseek-ai/dsh-llm-pi-ai": "0.2.0-rc.2",
103
- "@deepseek-ai/dsh-settings": "0.2.0-rc.2",
104
- "@deepseek-ai/schemastery": "^3.18.2",
105
- "@earendil-works/pi-ai": "0.87.1",
85
+ "@deepseek-ai/cordis": "^4.0.5",
86
+ "@deepseek-ai/dsh-atomic-write": "0.2.1-rc.1",
87
+ "@deepseek-ai/dsh-attachment": "0.2.1-rc.1",
88
+ "@deepseek-ai/dsh-client-locale": "0.2.1-rc.1",
89
+ "@deepseek-ai/dsh-client-ui-conversation": "0.2.1-rc.1",
90
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.2.1-rc.1",
91
+ "@deepseek-ai/dsh-client-ui-plugin-manager": "0.2.1-rc.1",
92
+ "@deepseek-ai/dsh-client-ui-settings-plugins": "0.2.1-rc.1",
93
+ "@deepseek-ai/dsh-client-ui-renderer": "0.2.1-rc.1",
94
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.1-rc.1",
95
+ "@deepseek-ai/dsh-credentials": "0.2.1-rc.1",
96
+ "@deepseek-ai/dsh-authorization": "0.2.1-rc.1",
97
+ "@deepseek-ai/dsh-fs": "0.2.1-rc.1",
98
+ "@deepseek-ai/dsh-launch-environment": "0.2.1-rc.1",
99
+ "@deepseek-ai/dsh-home-paths": "0.2.1-rc.1",
100
+ "@deepseek-ai/dsh-host-webserver": "0.2.1-rc.1",
101
+ "@deepseek-ai/dsh-llm": "0.2.1-rc.1",
102
+ "@deepseek-ai/dsh-llm-pi-ai": "0.2.1-rc.1",
103
+ "@deepseek-ai/dsh-settings": "0.2.1-rc.1",
104
+ "@deepseek-ai/schemastery": "^3.18.5",
105
+ "@earendil-works/pi-ai": "1.3.0",
106
106
  "@types/node": "^22.20.0",
107
107
  "@types/react": "~18.3.1",
108
108
  "@types/react-test-renderer": "^18.3.1",