dsh-workbuddy-connect 0.7.4 → 0.7.5

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.4, 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.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.
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,7 @@ 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.4 (npm latest) |
26
+ | 0.2.0-rc.2 | 0.7.5 (npm latest) |
27
27
  | 0.2.0-rc.1 | 0.7.0 |
28
28
  | 0.1.5 – 0.1.7 | 0.6.5 |
29
29
 
@@ -31,8 +31,8 @@ Core-to-plugin quick reference (full table in "Compatibility and release history
31
31
  <summary>Manual install (command line, Web / TUI only)</summary>
32
32
 
33
33
  ```sh
34
- # Web (pin per your actual core — example: 0.2.0-rc.2 -> 0.7.4; or install from source via github:corrinehu/dsh-workbuddy-connect)
35
- dsh plugin --profile web add dsh-workbuddy-connect@0.7.4
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
36
36
  dsh web
37
37
 
38
38
  # TUI (example for a 0.1.x core; that profile needs pnpm 11, e.g. npx pnpm@11)
@@ -62,7 +62,7 @@ dsh --profile dsh-tui
62
62
 
63
63
  - **Reasoning levels**: levels explicitly declared by WorkBuddy appear directly — for example, GLM-5.3 and GLM-5.3-Flash offer low / high / max. For models without declared levels, Web and Desktop offer a manual check in the model picker (it sends a few requests and may consume credit); models without a check result or selectable levels keep using WorkBuddy's default.
64
64
 
65
- - **Balance at a glance**: with a WorkBuddy / WorkBuddy AI model selected, the composer shows the account's remaining credit next to the model selector (e.g. `WB.3,401 credits`, `WB AI.3,401 credits` on the international app). Credit is not polled automatically (every status read is a real billing query): one read on mount, then refresh on demand with the ↻ beside it.
65
+ - **Balance at a glance**: with a WorkBuddy / WorkBuddy AI model selected, the composer shows the account's remaining credit next to the model selector (e.g. `WB.3,401 credits`, `WB AI.3,401 credits` on the international app). Credit is not polled automatically (every status read is a real billing query): one read on mount, then refresh on demand with the ↻ beside it. During session switching, the controls may briefly hide until the model selection is ready, then return automatically. The refresh button remains available even when the model has no reasoning-level detection entry or the balance cannot be read.
66
66
 
67
67
  - **Status and detection**: Settings → Plugins → the matching card shows the account, token validity, remaining credit, and model offers; it also refreshes the model list manually, shows whether the current list came from the upstream or the built-in fallback, and runs manual reasoning-level detection for eligible models. On DSH 0.1.5 the entry lives under Settings → Plugins; on 0.1.6+ it moved to the left-sidebar Plugins panel (workbuddy-connect → View) — and the Settings → Models page shows no WorkBuddy entries on either generation, by design.
68
68
 
@@ -112,7 +112,7 @@ dsh plugin --profile web exec dsh-workbuddy-connect doctor --provider workbuddy-
112
112
  ## Known limitations
113
113
 
114
114
  - Verified on macOS with the DSH Web / Desktop / TUI profiles (as of 0.3.2 this requires `0.1.5-rc.1`+ and Node 22+; TUI requires the terminal UI package `0.10.0-beta.5` or newer — see the Install section). Windows probes Local and Roaming AppData in order; WSL first reads credentials from the mounted Windows user profile. If the Windows and Linux user names differ and Windows environment variables are not forwarded into WSL, point `WORKBUDDY_AUTH_FILE` (or `WORKBUDDY_AI_AUTH_FILE` for the international version) at the actual file.
115
- - **Encrypted desktop credential helper discovery**: the helper is auto-detected on macOS and Windows; on Windows the CN app checks the default path `%LOCALAPPDATA%\Programs\WorkBuddy\WorkBuddy.exe` first and then the uninstall registry records, while the international app has no verified default path and checks the registry only. If auto-detection fails, set `WORKBUDDY_ELECTRON_BIN` (CN) or `WORKBUDDY_AI_ELECTRON_BIN` (international) to the executable explicitly, then fully quit and restart DSH for the change to take effect. Linux has no auto-discovery; an explicit environment variable is required.
115
+ - **Encrypted desktop credential helper discovery**: the helper is auto-detected on macOS and Windows; on Windows the CN app checks the default path `%LOCALAPPDATA%\Programs\WorkBuddy\WorkBuddy.exe` first and then the uninstall registry records, while the international app has no verified default path and checks the registry only. If auto-detection fails, set `WORKBUDDY_ELECTRON_BIN` (CN) or `WORKBUDDY_AI_ELECTRON_BIN` (international) to the executable explicitly, then fully quit and restart DSH for the change to take effect. Linux has no auto-discovery; an explicit environment variable is required. When WSL invokes the Windows-side helper, the plugin automatically normalizes the `ELECTRON_RUN_AS_NODE` entry in the child's `WSLENV` to a single safe flag set (carrying `/w` for forwarding, with no path translation; all other entries are preserved) — no manual `WSLENV` setup is needed. This change has passed offline regression tests; real WSL2 / Windows verification remains outstanding.
116
116
  - **The international version's model catalog comes from the app's own interface**: the service splits it by User-Agent, which is a private implementation detail that a server-side change can break. When that happens the plugin degrades to this account's last successful catalog and then to its built-in roster, showing the source (live / saved / built-in), the fetch time, and the failure reason on the card — but long-term compatibility is not guaranteed. The CN version's catalog uses the same interface as the official CLI and is unaffected.
117
117
  - **International-version environments not yet covered**: on Windows / WSL / Linux no reliable source for the international app's version has been located yet, so the saved value or the built-in default is used. On macOS, real-shim checks covered complete GPT-family replies, tool calls, and continued turns.
118
118
  - **Behaviour change with no credentials**: a version whose app was never signed in — and that left no plugin-owned copy — no longer shows a model group. The CN version used to display a built-in fallback list, but every model on it failed when selected.
@@ -126,7 +126,7 @@ The plugin version must match the DSH core — a mismatched combination fails to
126
126
 
127
127
  | DSH core | Recommended plugin | Notes |
128
128
  |---|---|---|
129
- | `0.2.0-rc.2` | `0.7.4` (npm latest) | Current line; Windows registry discovery fixed, diagnostics and stability improved — do not stay on 0.7.2. |
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
130
  | `0.2.0-rc.1` | `0.7.0` | 0.7.1 drops rc.1 support; stay on this version. |
131
131
  | `0.1.5` – `0.1.7` | `0.6.5` | Final release for the old cores; 0.7.0 targets 0.2.0 only. |
132
132
  | `0.1.2-rc.1` | `0.3.1` | Older line, historical maintenance only. |
@@ -134,14 +134,15 @@ The plugin version must match the DSH core — a mismatched combination fails to
134
134
 
135
135
  Release history (full records at [releases](https://github.com/corrinehu/dsh-workbuddy-connect/releases)):
136
136
 
137
+ - **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.
137
138
  - **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.
138
139
  - **0.7.3**: fixes Windows registry auto-discovery failing on non-default install paths ([#105](https://github.com/corrinehu/dsh-workbuddy-connect/issues/105)).
139
- - **0.7.2**: pi-ai becomes a plugin-bundled dependency and rejected inference-field requests are fixed ([#92](https://github.com/corrinehu/dsh-workbuddy-connect/issues/92)); this release carries a Windows registry regression — use 0.7.4 directly.
140
+ - **0.7.2**: pi-ai becomes a plugin-bundled dependency and rejected inference-field requests are fixed ([#92](https://github.com/corrinehu/dsh-workbuddy-connect/issues/92)); this release carries a Windows registry regression — use 0.7.4 or a newer stable release.
140
141
  - **0.7.1**: narrows the pi-ai dependency range.
141
142
  - **0.7.0**: adapts to DSH 0.2.0's settings-service rework and drops 0.1.x support.
142
143
  - **0.6.5**: final release of the 0.1.x line.
143
144
 
144
- Pinned-version install example: `dsh plugin --profile web add dsh-workbuddy-connect@0.7.4`.
145
+ Pinned-version install example: `dsh plugin --profile web add dsh-workbuddy-connect@0.7.5`.
145
146
 
146
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.
147
148
 
@@ -152,6 +153,13 @@ Pinned-version install example: `dsh plugin --profile web add dsh-workbuddy-conn
152
153
  - The author is not liable for any direct or indirect loss arising from the use or misuse of this project.
153
154
  - This project is not affiliated with, endorsed by, or sponsored by Tencent, WorkBuddy, or DeepSeek. Product names are used for compatibility description only; trademarks belong to their respective owners.
154
155
 
156
+ ## Related Projects / Community Ecosystem
157
+
158
+ - **[HanaAgent](https://github.com/liliMozi/openhanako)**: an independent personal AI Agent project.
159
+ - **[hana-workbuddy-connect](https://github.com/miaoyongxu/hana-workbuddy-connect)**: a community-maintained unofficial adapter project that reuses parts of the `dsh-workbuddy-connect` implementation to bring WorkBuddy / WorkBuddy AI models to HanaAgent.
160
+
161
+ Both projects are maintained independently by third parties. The compatibility, security, and usage support of `hana-workbuddy-connect` are the responsibility of its maintainer. Listing them here is not an official endorsement, nor does it imply any stability or compatibility commitment on this plugin's internal interfaces.
162
+
155
163
  ## Acknowledgements
156
164
 
157
165
  - [Sliverkiss/workbuddy2api](https://github.com/Sliverkiss/workbuddy2api) (MIT) — reference implementation of the WorkBuddy upstream protocol.
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.4、rc.1→0.7.0、0.1.5–0.1.7→0.6.5),优先走本机受支持的非插件市场渠道;部分 Desktop 发行版(尤其官方 Electron 版)的 profile 由 App 管理,各发行版规则未必相同,先确认我所用的发行版,再探查其合规的安装方式,但不得绕过其校验;
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 管理,各发行版规则未必相同,先确认我所用的发行版,再探查其合规的安装方式,但不得绕过其校验;
17
17
  任何本地文件或配置改动,先征得我同意并做好备份;
18
18
  装完后验证模型选择器里出现 WorkBuddy 分组,并陪我完成一次简短对话;
19
19
  若 Desktop 安装仍因 generation 校验失败(如 @types/retry 误报),请如实报告、参照上游 dataelement/dsh-desktop#688,并建议我改用独立的 Web / TUI,不要修改依赖包或绕过校验。
@@ -23,7 +23,7 @@
23
23
 
24
24
  | DSH 内核 | 推荐插件版 |
25
25
  |---|---|
26
- | 0.2.0-rc.2 | 0.7.4(npm latest) |
26
+ | 0.2.0-rc.2 | 0.7.5(npm latest) |
27
27
  | 0.2.0-rc.1 | 0.7.0 |
28
28
  | 0.1.5 – 0.1.7 | 0.6.5 |
29
29
 
@@ -31,8 +31,8 @@
31
31
  <summary>手动安装(命令行,仅 Web / TUI)</summary>
32
32
 
33
33
  ```sh
34
- # Web(按实际内核固定版本,示例为 0.2.0-rc.2 → 0.7.4;也可用 github:corrinehu/dsh-workbuddy-connect 从源码安装)
35
- dsh plugin --profile web add dsh-workbuddy-connect@0.7.4
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
36
36
  dsh web
37
37
 
38
38
  # TUI(示例为 0.1.x 内核;该 profile 需用 pnpm 11 安装,如 npx pnpm@11)
@@ -62,7 +62,7 @@ dsh --profile dsh-tui
62
62
 
63
63
  - **推理档位**:WorkBuddy 明确声明的档位会直接显示,例如 GLM-5.3 和 GLM-5.3-Flash 可选 low / high / max。未声明档位的模型可在 Web 和 Desktop 的模型选择器中手动检测(发送少量请求,可能消耗积分);未检测或没有可用档位的模型使用 WorkBuddy 默认档位。
64
64
 
65
- - **余额速览**:选中 WorkBuddy / WorkBuddy AI 模型时,输入框底部在模型选择器旁显示当前账号的剩余积分(如 `WB.3,401(积分)`、国际版 `WB AI.3,401(积分)`)。积分不自动轮询(每次读取都是真实计费查询),挂载时读取一次后可点旁边的 ↻ 手动刷新。
65
+ - **余额速览**:选中 WorkBuddy / WorkBuddy AI 模型时,输入框底部在模型选择器旁显示当前账号的剩余积分(如 `WB.3,401(积分)`、国际版 `WB AI.3,401(积分)`)。积分不自动轮询(每次读取都是真实计费查询),挂载时读取一次后可点旁边的 ↻ 手动刷新。切换会话时组件可能短暂隐藏,模型选择就绪后自动恢复;即使模型没有推理档位检测入口或余额读取失败,刷新按钮仍保留。
66
66
 
67
67
  - **信息查看与检测**:设置 → 插件 → 对应卡片可查看账号、令牌有效期、剩余积分和模型优惠,也可手动刷新模型列表并查看当前列表来自上游还是内置兜底,或对可检测模型手动检测推理档位。DSH 0.1.5 的入口在「设置 → 插件」,0.1.6+ 移到主界面左侧栏「插件」面板(workbuddy-connect → 查看);「设置 → 模型」页两代都不显示 WorkBuddy 条目,属有意设计。
68
68
 
@@ -113,7 +113,7 @@ dsh plugin --profile web exec dsh-workbuddy-connect doctor --provider workbuddy-
113
113
  ## 已知限制
114
114
 
115
115
  - 在 macOS 的 DSH Web / Desktop / TUI 下验证通过(0.3.2 起要求 `0.1.5-rc.1`+、Node 22+;TUI 需终端界面插件 `0.10.0-beta.5` 及以上,见安装章节说明)。Windows 会依次探测 Local 与 Roaming AppData;WSL 会优先从挂载的 Windows 用户目录读取登录凭据。若 Windows 与 Linux 用户名不同且 Windows 环境变量未传入 WSL,请通过 `WORKBUDDY_AUTH_FILE`(国际版为 `WORKBUDDY_AI_AUTH_FILE`)指定实际位置。
116
- - **加密桌面凭据的解密程序定位**:解密程序在 macOS 与 Windows 上会自动探测;Windows 上国内版先查默认路径 `%LOCALAPPDATA%\Programs\WorkBuddy\WorkBuddy.exe`,再查卸载注册表记录,国际版没有已验证的默认路径、仅查注册表。自动探测失败时,可用 `WORKBUDDY_ELECTRON_BIN`(国内版)或 `WORKBUDDY_AI_ELECTRON_BIN`(国际版)显式指定可执行文件,设置后需完全退出并重启 DSH 才生效。Linux 无法自动发现,需显式指定。
116
+ - **加密桌面凭据的解密程序定位**:解密程序在 macOS 与 Windows 上会自动探测;Windows 上国内版先查默认路径 `%LOCALAPPDATA%\Programs\WorkBuddy\WorkBuddy.exe`,再查卸载注册表记录,国际版没有已验证的默认路径、仅查注册表。自动探测失败时,可用 `WORKBUDDY_ELECTRON_BIN`(国内版)或 `WORKBUDDY_AI_ELECTRON_BIN`(国际版)显式指定可执行文件,设置后需完全退出并重启 DSH 才生效。Linux 无法自动发现,需显式指定。WSL 下调用 Windows 侧解密程序时,插件会自动把子进程 `WSLENV` 中的 `ELECTRON_RUN_AS_NODE` 条目规范化为单一安全旗标(含 `/w` 转发、不做路径转换,其余条目原样保留),无需手动设置。此改动已通过离线回归测试,尚未完成 WSL2 / Windows 真机验证。
117
117
  - **国际版的模型目录来自 App 界面接口**:服务端按 User-Agent 分流下发,属私有实现,上游改动可能使其失效。届时插件按「本账号上次成功目录 → 内置目录」降级,并在卡片上标明来源(实时 / 已保存 / 内置)、更新时间与失败原因,但不能保证长期兼容。国内版目录走官方 CLI 同款接口,不受此影响。
118
118
  - **国际版仍未覆盖的环境**:Windows / WSL / Linux 下国际版 App 的版本读取尚未找到可靠来源,会退回最近保存的版本或内置值。macOS 上已通过真实 shim 验证 GPT 系完整回复、工具调用与续轮。
119
119
  - **无凭据时的行为变化**:某版 App 从未登录、也没留下插件自留副本时,该版模型分组不再显示。此前国内版会显示一份内置兜底列表,但那些模型选了必然报错。
@@ -127,7 +127,7 @@ dsh plugin --profile web exec dsh-workbuddy-connect doctor --provider workbuddy-
127
127
 
128
128
  | DSH 内核 | 推荐插件版 | 注意事项 |
129
129
  |---|---|---|
130
- | `0.2.0-rc.2` | `0.7.4`(npm latest) | 当前最新线;Windows 注册表发现已修复,诊断与稳定性改进,勿停留在 0.7.2。 |
130
+ | `0.2.0-rc.2` | `0.7.5`(npm latest) | 当前最新线;修复输入框组件消失与 WSL helper 环境转发,勿停留在有注册表回归的 0.7.2。 |
131
131
  | `0.2.0-rc.1` | `0.7.0` | 0.7.1 起不再支持 rc.1,请停留本版。 |
132
132
  | `0.1.5` – `0.1.7` | `0.6.5` | 旧内核最终版;0.7.0 起仅面向 0.2.0。 |
133
133
  | `0.1.2-rc.1` | `0.3.1` | 更早旧线,仅历史维护。 |
@@ -137,12 +137,12 @@ dsh plugin --profile web exec dsh-workbuddy-connect doctor --provider workbuddy-
137
137
 
138
138
  - **0.7.4**:Windows 诊断与稳定性改进:注册表子进程输出超限准确分类、跨平台测试假设修正([#62](https://github.com/corrinehu/dsh-workbuddy-connect/issues/62)),安装说明重排。
139
139
  - **0.7.3**:修复 Windows 非默认安装路径下注册表自动发现失败([#105](https://github.com/corrinehu/dsh-workbuddy-connect/issues/105))。
140
- - **0.7.2**:pi-ai 改为插件自带依赖,并修复推理字段请求被拒([#92](https://github.com/corrinehu/dsh-workbuddy-connect/issues/92));该版存在 Windows 注册表回归,请直接使用 0.7.4。
140
+ - **0.7.2**:pi-ai 改为插件自带依赖,并修复推理字段请求被拒([#92](https://github.com/corrinehu/dsh-workbuddy-connect/issues/92));该版存在 Windows 注册表回归,请使用 0.7.4 或更新的正式版本。
141
141
  - **0.7.1**:收窄 pi-ai 依赖范围。
142
142
  - **0.7.0**:适配 DSH 0.2.0 的设置服务改造,不再支持 0.1.x。
143
143
  - **0.6.5**:0.1.x 线最终版本。
144
144
 
145
- 固定版本安装示例:`dsh plugin --profile web add dsh-workbuddy-connect@0.7.4`。
145
+ 固定版本安装示例:`dsh plugin --profile web add dsh-workbuddy-connect@0.7.5`。
146
146
 
147
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'}` 在确认其他插件不依赖前也不要盲目移除。
148
148
 
@@ -153,6 +153,13 @@ dsh plugin --profile web exec dsh-workbuddy-connect doctor --provider workbuddy-
153
153
  - 本项目作者不对任何因使用或滥用本项目产生的直接或间接损失负责。
154
154
  - 本项目与腾讯、WorkBuddy、DeepSeek 均无关联,未获其授权或认可;文中出现的名称仅用于描述兼容关系,其商标权利归各自所有。
155
155
 
156
+ ## 相关项目 / 社区生态
157
+
158
+ - **[HanaAgent](https://github.com/liliMozi/openhanako)**:独立的个人 AI Agent 项目。
159
+ - **[hana-workbuddy-connect](https://github.com/miaoyongxu/hana-workbuddy-connect)**:社区维护的非官方适配项目,复用 `dsh-workbuddy-connect` 的部分实现,为 HanaAgent 接入 WorkBuddy / WorkBuddy AI 模型。
160
+
161
+ 以上项目均由第三方独立维护。其中,`hana-workbuddy-connect` 的兼容性、安全性及使用支持由其维护者负责。收录不代表官方背书,也不意味着本插件对内部接口提供稳定性或兼容性承诺。
162
+
156
163
  ## 致谢
157
164
 
158
165
  - [Sliverkiss/workbuddy2api](https://github.com/Sliverkiss/workbuddy2api)(MIT)— WorkBuddy 上游协议的参照实现。
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-DVlbwIIo.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-CvtbpuQi.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
@@ -1746,14 +1746,14 @@ window.__ModuleLoader__.load({
1746
1746
  const subscribe = (0, react.useCallback)((listener) => directory.subscribe(listener), [directory]);
1747
1747
  const snapshot = (0, react.useCallback)(() => directory.getSnapshot(), [directory]);
1748
1748
  const selection = (0, react.useSyncExternalStore)(subscribe, snapshot, snapshot).current;
1749
- const card = selection === void 0 ? void 0 : cardVariantFor(selection.provider);
1750
- const key = card === void 0 || selection === void 0 ? void 0 : `${card.id}:${selection.model}`;
1751
- return card === void 0 || selection === void 0 || key === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelProbe, {
1749
+ if (selection == null) return null;
1750
+ const card = cardVariantFor(selection.provider);
1751
+ return card === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelProbe, {
1752
1752
  model: selection.model,
1753
1753
  card,
1754
1754
  label: useLabel(t),
1755
1755
  t
1756
- }, key);
1756
+ }, `${card.id}:${selection.model}`);
1757
1757
  }
1758
1758
  function ModelProbe({ model, card, label, t }) {
1759
1759
  const [status, setStatus] = (0, react.useState)();
@@ -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.4";
2775
+ const WORKBUDDY_CONNECT_VERSION = "0.7.5";
2776
2776
  //#endregion
2777
2777
  //#region src/client/WorkBuddyConfigPage.tsx
2778
2778
  /**
@@ -1625,6 +1625,23 @@ const INTERNATIONAL_SYSTEM_PROMPT = "You are a helpful assistant.";
1625
1625
  */
1626
1626
  const INTERNATIONAL_PROBE_MAX_TOKENS = 16;
1627
1627
  //#endregion
1628
+ //#region src/wsl.ts
1629
+ /**
1630
+ * Whether this Linux process is running inside Windows Subsystem for Linux.
1631
+ *
1632
+ * Shared by the desktop-auth candidate probe (`auth.ts`) and the at-rest key
1633
+ * helper spawn (`desktop-credential-protection.ts`), so both agree on what
1634
+ * "WSL" means. Covers WSL1 and WSL2: WSL2 sets `WSL_DISTRO_NAME` /
1635
+ * `WSL_INTEROP`, and every WSL kernel release string carries "microsoft"
1636
+ * (e.g. `6.18.33.2-microsoft-standard-WSL2`), which also catches a WSL2
1637
+ * session whose env vars were stripped.
1638
+ */
1639
+ function isWsl() {
1640
+ if (process.platform !== "linux") return false;
1641
+ if (process.env["WSL_DISTRO_NAME"] !== void 0 || process.env["WSL_INTEROP"] !== void 0) return true;
1642
+ return release().toLowerCase().includes("microsoft");
1643
+ }
1644
+ //#endregion
1628
1645
  //#region src/status-paths.ts
1629
1646
  /** Node-free constants and types shared by the Host and browser halves. */
1630
1647
  /** Plugin-owned status endpoint consumed by its browser half. */
@@ -2140,6 +2157,86 @@ const PLUTIL_MAX_OUTPUT_BYTES = 65536;
2140
2157
  */
2141
2158
  var DiscoveryIncompleteError = class extends Error {};
2142
2159
  /**
2160
+ * Merge a `WSLENV` value so `ELECTRON_RUN_AS_NODE` crosses WSL→Windows
2161
+ * interop (#133).
2162
+ *
2163
+ * WSL only forwards listed variables to a Windows child, and only when the
2164
+ * entry carries the `/w` (WSL→Windows) direction flag — a plain
2165
+ * `env: { …, ELECTRON_RUN_AS_NODE: '1' }` stays on the Linux side, so the
2166
+ * WorkBuddy exe starts in GUI mode and its stdout is app log rather than the
2167
+ * key payload.
2168
+ *
2169
+ * The target variable is consolidated into exactly ONE safe entry, because
2170
+ * duplicate same-name entries leave the forwarding direction indeterminate:
2171
+ *
2172
+ * - the single entry always carries `w` (the plugin's requirement) and takes
2173
+ * the position of the first same-name occurrence;
2174
+ * - `u` (Windows→WSL) is kept when ANY existing same-name entry asked for it,
2175
+ * so a user's bidirectional setup survives as `/uw`;
2176
+ * - the path flags are dropped: `p` (path translation) and `l` (path list)
2177
+ * would mangle the value, which here is the numeric switch `1` —
2178
+ * `ELECTRON_RUN_AS_NODE=1` must arrive byte-for-byte, never as a converted
2179
+ * path. An inherited `/pw`, `/lw`, or `/l` therefore normalizes to a
2180
+ * path-free flag set rather than being appended to;
2181
+ * - a BARE name carries no direction at all, so it counts as neither `w` nor
2182
+ * `u` — it only consolidates;
2183
+ * - with no same-name entry at all, `ELECTRON_RUN_AS_NODE/w` is appended;
2184
+ * - every OTHER entry keeps its order and bytes; empty segments (the
2185
+ * trailing colons Windows Terminal tends to leave) and exact duplicates
2186
+ * among them are dropped.
2187
+ *
2188
+ * The result is idempotent: merging it again yields the same string.
2189
+ *
2190
+ * @param value - the inherited `WSLENV` value, or `undefined` when unset.
2191
+ * @returns the `WSLENV` value the child should receive.
2192
+ */
2193
+ function wslenvForwardRunAsNode(value) {
2194
+ const merged = [];
2195
+ /** Index of the consolidated target entry inside `merged`, once placed. */
2196
+ let targetIndex = -1;
2197
+ /** The safe flag set for the target: always `w`, plus `u` if asked for. */
2198
+ let targetFlags = "/w";
2199
+ for (const entry of (value ?? "").split(":")) {
2200
+ if (entry === "") continue;
2201
+ const slash = entry.indexOf("/");
2202
+ if ((slash === -1 ? entry : entry.slice(0, slash)) !== "ELECTRON_RUN_AS_NODE") {
2203
+ if (!merged.includes(entry)) merged.push(entry);
2204
+ continue;
2205
+ }
2206
+ if ((slash === -1 ? "" : entry.slice(slash + 1)).includes("u")) targetFlags = "/uw";
2207
+ if (targetIndex === -1) {
2208
+ targetIndex = merged.length;
2209
+ merged.push(`ELECTRON_RUN_AS_NODE${targetFlags}`);
2210
+ } else merged[targetIndex] = `ELECTRON_RUN_AS_NODE${targetFlags}`;
2211
+ }
2212
+ if (targetIndex === -1) merged.push(`ELECTRON_RUN_AS_NODE${targetFlags}`);
2213
+ return merged.join(":");
2214
+ }
2215
+ /**
2216
+ * The environment the at-rest key helper is spawned with (#133).
2217
+ *
2218
+ * Always a fresh object — the parent (`process.env` in production) is never
2219
+ * mutated. `ELECTRON_RUN_AS_NODE=1` forces the Electron binary into plain
2220
+ * Node mode; when the spawn crosses WSL→Windows interop — a WSL host and a
2221
+ * helper that is itself a Windows executable — the child's `WSLENV` is
2222
+ * additionally merged via {@link wslenvForwardRunAsNode} so the interop layer
2223
+ * actually forwards that variable. Every other platform and path combination
2224
+ * gets the previous behaviour byte-for-byte.
2225
+ *
2226
+ * @param parent - the environment to inherit (a copy is taken).
2227
+ * @param electronPath - the helper binary about to be spawned.
2228
+ * @param wsl - whether the current process runs inside WSL.
2229
+ * @returns the child process environment.
2230
+ */
2231
+ function helperChildEnv(parent, electronPath, wsl) {
2232
+ const childEnv = {
2233
+ ...parent,
2234
+ ELECTRON_RUN_AS_NODE: "1"
2235
+ };
2236
+ if (wsl && basename(electronPath).toLowerCase().endsWith(".exe")) childEnv["WSLENV"] = wslenvForwardRunAsNode(childEnv["WSLENV"]);
2237
+ return childEnv;
2238
+ }
2239
+ /**
2143
2240
  * The default discovery tools: Spotlight for the bundle, `/usr/bin/plutil` for
2144
2241
  * identity. Every failure that means "we could not tell" — a missing tool, a
2145
2242
  * timeout, an oversized answer — is raised as {@link DiscoveryIncompleteError}
@@ -2412,6 +2509,7 @@ function parseWindowsUninstallJson(output) {
2412
2509
  platform;
2413
2510
  discoveryBudgetMs;
2414
2511
  timeoutMs;
2512
+ wsl;
2415
2513
  source;
2416
2514
  spawnHelper;
2417
2515
  /**
@@ -2434,6 +2532,7 @@ function parseWindowsUninstallJson(output) {
2434
2532
  this.windowsTools = options.windowsTools ?? workBuddyWindowsDiscoveryTools();
2435
2533
  this.discoveryBudgetMs = options.discoveryBudgetMs ?? 1e4;
2436
2534
  this.timeoutMs = options.timeoutMs ?? 1e4;
2535
+ this.wsl = options.wsl ?? isWsl;
2437
2536
  this.spawnHelper = options.spawnHelper ?? ((path) => this.spawnAt(path));
2438
2537
  this.source = options.source ?? (() => this.spawnPayload());
2439
2538
  }
@@ -2636,10 +2735,7 @@ function parseWindowsUninstallJson(output) {
2636
2735
  timeout: this.timeoutMs,
2637
2736
  maxBuffer: 1048576,
2638
2737
  windowsHide: true,
2639
- env: {
2640
- ...process.env,
2641
- ELECTRON_RUN_AS_NODE: "1"
2642
- }
2738
+ env: helperChildEnv(process.env, electronPath, this.wsl())
2643
2739
  }, (error, stdout) => {
2644
2740
  if (error !== null && error !== void 0) {
2645
2741
  reject(new WorkBuddyElectronPathError("encrypted-credential-unreadable", `the WorkBuddy key helper (${electronPath}) ${error.killed === true ? `timed out or was killed after ${String(this.timeoutMs)}ms` : error.code !== void 0 ? `exited with code ${String(error.code)}` : "could not be started"}`));
@@ -2843,12 +2939,6 @@ const DESKTOP_AUTH_RELATIVE_PATH = [
2843
2939
  "auth",
2844
2940
  "workbuddy-desktop.info"
2845
2941
  ];
2846
- /** Whether this Linux process is running inside Windows Subsystem for Linux. */
2847
- function isWsl() {
2848
- if (process.platform !== "linux") return false;
2849
- if (process.env["WSL_DISTRO_NAME"] !== void 0 || process.env["WSL_INTEROP"] !== void 0) return true;
2850
- return release().toLowerCase().includes("microsoft");
2851
- }
2852
2942
  /** Convert a Windows drive path to WSL's conventional `/mnt/<drive>` form. */
2853
2943
  function windowsPathForWsl(value) {
2854
2944
  const path = value?.trim();
@@ -4028,7 +4118,7 @@ var WorkBuddyCatalog = class {
4028
4118
  };
4029
4119
  //#endregion
4030
4120
  //#region src/version.ts
4031
- const WORKBUDDY_CONNECT_VERSION = "0.7.4";
4121
+ const WORKBUDDY_CONNECT_VERSION = "0.7.5";
4032
4122
  //#endregion
4033
4123
  //#region src/host-heartbeat.ts
4034
4124
  /**
package/lib/index.d.ts CHANGED
@@ -851,6 +851,13 @@ interface WorkBuddyAtRestKeyProviderOptions {
851
851
  windowsTools?: WorkBuddyWindowsDiscoveryTools;
852
852
  /** Platform override for deterministic discovery tests. */
853
853
  platform?: NodeJS.Platform;
854
+ /**
855
+ * Whether the helper spawn crosses WSL→Windows interop. Injectable so tests
856
+ * can simulate a WSL host on any platform; defaults to the shared
857
+ * {@link isWsl} check. Only consulted for the key-helper spawn (#133) —
858
+ * never for discovery.
859
+ */
860
+ wsl?: () => boolean;
854
861
  /**
855
862
  * Total budget for one discovery run, covering the search and every
856
863
  * candidate check. Injectable so tests can exercise exhaustion without
@@ -878,6 +885,7 @@ interface WorkBuddyAtRestKeyProviderOptions {
878
885
  private readonly platform;
879
886
  private readonly discoveryBudgetMs;
880
887
  private readonly timeoutMs;
888
+ private readonly wsl;
881
889
  private readonly source;
882
890
  private readonly spawnHelper;
883
891
  /**
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-DVlbwIIo.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-CvtbpuQi.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";
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.4",
5
+ "version": "0.7.5",
6
6
  "author": "corrinehu",
7
7
  "keywords": [
8
8
  "dsh-plugin",