dsh-connect-workbuddy 4.3.2 → 4.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/README.en.md +43 -0
- package/README.md +43 -0
- package/lib/bin.js +1 -1
- package/lib/{host-heartbeat-DyU_tIIj.js → host-heartbeat-DkdNZKKY.js} +5 -3
- package/lib/index.d.ts +35 -1
- package/lib/index.js +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.3.4 (2026-10-12)
|
|
4
|
+
|
|
5
|
+
### Fixes
|
|
6
|
+
|
|
7
|
+
- **移除一条只会在 Windows 上失败的测试断言,CI 恢复全绿。**(PR #49)
|
|
8
|
+
- **现象**:4.3.2 与 4.3.3 的 CI 在 `windows-latest` 上红、`ubuntu-latest` 全绿,失败点只有一处:
|
|
9
|
+
```
|
|
10
|
+
AssertionError: expected 'D:\explicit\home' to be '/explicit/home'
|
|
11
|
+
```
|
|
12
|
+
- **根因**:`tests/host-peers.spec.ts` 把 `resolveDshHome('/explicit/home')` 与**字面量** `/explicit/home` 比较。而 `resolveDshHome` 会对入参跑 `path.resolve`,win32 下 `/explicit/home` 被规范成 `\explicit\home`——这条断言把「哪个平台在跑测试」写进了期望值,正是 `docs/WINDOWS.md` §4 那条「断言行为,不要断言跑测试的机器」要拦的形态。
|
|
13
|
+
- **修法**:改为与 `path.resolve` **自身**比较(两侧同一个解析器),因此在任何平台都成立;并补一条不含分隔符的用例,证明胜出的是「显式入参」而不是某个字符串的写法。守卫本身(解析优先级、后备实现行为)一条未减。
|
|
14
|
+
- **验证**:先在本地按 win32 路径语义逐形态核对(`/explicit/home`、`relative-ish`、`C:\…`、`~/dsh` 两侧全部一致),再经 **CI 的 `windows-latest` 真机跑通**——本次缺陷恰恰属于「本机(macOS)永远绿」的那一类,所以最终判据只能是在 Windows 上跑出来的结果。
|
|
15
|
+
- **注意**:本次只改了 `tests/`,**`lib/` 与 `package.json` 的发布产物逐字未变**(`tests/` 不在 `files` 白名单内,从不随包分发)。因此 4.3.2 / 4.3.3 对用户而言没有问题,本版存在只为让 tag 上的 CI 结论与事实一致。
|
|
16
|
+
|
|
17
|
+
#### Docs
|
|
18
|
+
|
|
19
|
+
- **README 增补「在服务器上使用:搬运已登录的凭据」一节**(承接 issue #47 报告者 tuoyuangui 在 #47 评论中贡献的做法)。
|
|
20
|
+
- **内容**:给出从「已登录 WorkBuddy 的机器」打包 `CodeBuddyExtension` 目录 → 传到服务器 → 解到插件实际读取的目录 → 用 `status` 验证的完整三步命令;中英双语同步(`README.md` / `README.en.md`)。
|
|
21
|
+
- **更正了报告者原话里的一处平台细节**:报告者写的是 `cp -r 其他位置的 ~/.local/share[~/.config]/CodeBuddyExtension …`,其中 `~/.local/share` 在 **Linux 上插件不会读取**。`src/auth.ts` 的 `defaultDesktopAuthDirs()` 在 Linux 只返回 `${XDG_CONFIG_HOME:-~/.config}/CodeBuddyExtension/Data/Public/auth` 一项。README 因此列出三平台**实际**读取路径的对照表,并明确「只解到 `~/.local/share` 不会被读到」,同时给出 `WORKBUDDY_AUTH_FILE` 这条兜底(显式指定时同级备份仍会被扫描,账号切换照常可用)。
|
|
22
|
+
- **补了两条报告者未提及、但读者必须知道的边界**:其一,**5.6.0 起的加密凭据无法靠搬运解决**——密钥在运行时由 App 原生绑定现取、不落盘,所以没有 App 的服务器上即使拿到加密后的 auth 文件也读不出来(插件会如实报未登录,不会退化成读出一个残缺 token,该行为见 `src/at-rest.ts` 与[已知限制](README.md#已知限制));其二,凭据文件本身**等同于账号**,必须走加密通道传输并 `chmod 600`。
|
|
23
|
+
- **本版只改文档**,未触动 `src/`、`tests/` 与构建产物。措辞中的每条行为断言(候选路径、加密凭据的失败形态、`doctor` 的输出文本)均对照 `src/auth.ts`、`src/at-rest.ts`、`src/bin.ts` 逐条核过,不是照抄 issue 评论。
|
|
24
|
+
|
|
25
|
+
## 4.3.3 (2026-10-12)
|
|
26
|
+
|
|
27
|
+
### Fixes
|
|
28
|
+
|
|
29
|
+
- **月度套餐的余额改用容量池(`CapacityRemain`),不再用本周期余额(`CycleCapacityRemain`)——国际版账号不再被误报「积分耗尽」为 0。**(issue #48)
|
|
30
|
+
- **现象(报告者,`global` 区域 / macOS)**:两个国际版账号在 DSH 里显示积分耗尽,而同一账号在 WorkBuddy 客户端里完全正常;用同批 token 直接打 `/v2/chat/completions` 返回 **200**,证明账号并未耗尽。
|
|
31
|
+
- **根因**:上游对**同一个月度套餐**(`CapacityType === 4`)同时返回**两套容量字段**,它们回答的是两个不同的问题——`CapacityRemain`/`CapacitySize`/`CapacityUsed` 是**容量池**,`CycleCapacityRemain`/`CycleCapacitySize`/`CycleCapacityUsed` 是**本计费周期**。旧代码对月度套餐只读周期字段 `remain = monthly ? numberField('CycleCapacityRemain') : …`。
|
|
32
|
+
- **本机以真实账单接口复现(3 个国际版账号全部命中)**:`CapacityRemain=100` 而 `CycleCapacityRemain=0`、`CycleCapacityUsed=100`,且 `CycleEndTime="2026-10-31 23:59:59"`(**周期尚未结束**)、`Status=0`、`ExpiredTime=""`。即套餐有效、池里还有 100,插件却报 **0**。对照组:同机 CN 账号两字段一致(500/500),读数为 2267,**所以国内版看不出异常**——但 CN 也在受影响之列:本机 `老丁`/`LaoDing` 两个 CN 账号的月度套餐同样是池 500 而周期余额更小(实测同一时刻分别为 `CycleCapacityRemain=125` 与 `0`),修复后读数分别为 **1343→1718** 与 **768→1268**;`老丁` 的增量 +375 恰等于 `500 − 125`,正好说明这一个字段差异在两个区域都存在、且月度套餐的周期余额会随消耗变化。报告者「cn 是否受影响未能对照」一节由此有答案。
|
|
33
|
+
- **修法**:余额一律读容量池 `CapacityRemain`(两种套餐都是),`size` 同理统一读 `CapacitySize`(真实月度行上 `CapacitySize` 与 `CycleCapacitySize` 同时存在且相等,取前者;后者保留为回退)。**周期字段继续读取**并作为新的 `cycleRemain` 随包透出——它回答的是「本周期额度是否用完」这个**不同**的问题,而 `refreshAtMs`(周期续期点)的提示文案只有靠它才成立。**没有采用报告者建议的 `Math.max(两者)`**:那两个字段不是同一量的两种口径,取较大值会把「本周期已用完、等 10/31 续期」误报成「仍有余额」,正是 `quotaRefreshAtMs` 冷却提示要避免的误导。
|
|
34
|
+
- **修法未触动 gift 路径**(`CapacityType 1`):仍读 `CapacityRemain`、仍按「耗尽或过期即丢弃」处理——本缺陷只存在于月度分支。
|
|
35
|
+
- **实测(真实接口,修复前后对照)**:3 个国际版账号 `0 → 100`(各自 `CapacityRemain=100`);CN `17749714179` 保持 2267 不变(该账号两字段本来就一致);CN `老丁` 1343→1718、`LaoDing` 768→1268。**CN 侧读数上升不是回归,是修正**:这两个账号的月度套餐池余额(500)一直高于本周期余额,旧代码只读了后者。
|
|
36
|
+
- **守卫 `tests/issue48-monthly-pool-credits.spec.ts`(8 例)**:直接驱动**真实的 `fetchCredits` 解析器**(stub 掉的只有 `fetch`),用**真实账单行的原始字段值**(池 100 / 周期 0 / 周期未结束)构造夹具。原有的全部套件都在边界上 mock 掉整个 `fetchCredits`,**这正是该缺陷能漏出去的原因**——字段解析这一层此前零覆盖。覆盖:读池而非周期(回归本体)、`cycleRemain` 单独透出且 `refreshAtMs` 仍在、多账号求和、两字段一致时不受影响(同时通过新旧代码,用来说明「CN 没有开始按另一种方式读」)、周期耗尽但池充足时账号不被丢弃、gift 路径不变(含耗尽/过期两条丢弃分支)、负值不进入 total、月度与 gift 混合不重复计数。**变异验证**:把 `remain` 改回 `numberField('CycleCapacityRemain')` → 3 例变红,报错正是 `expected +0 to be 100`(与现场症状同形)。
|
|
37
|
+
- **边界透传守卫**:`tests/web-status.spec.ts` 增补断言,钉住 `remain` 与 `cycleRemain` **各自独立**地跨 host→client 边界存活(`toMatchObject` 不会因字段丢失而变红),并钉住 gift **不带**该字段(缺失而非 0)。**变异验证**:删掉 `web-status.ts` 里的透传 → 立即变红。
|
|
38
|
+
|
|
3
39
|
## 4.3.2 (2026-10-12)
|
|
4
40
|
|
|
5
41
|
### Fixes
|
package/README.en.md
CHANGED
|
@@ -205,6 +205,49 @@ All three platforms are supported targets; the differences below are **implement
|
|
|
205
205
|
2. **Credential paths are partly verified on real Windows hardware.** The candidate list is derived from platform conventions and pinned by unit tests (including both the unset and the blank-string fallback for `LOCALAPPDATA` / `APPDATA`). On a real Windows 11 machine, `%LOCALAPPDATA%\CodeBuddyExtension\Data\Public\auth` and `%LOCALAPPDATA%\Programs\WorkBuddy\WorkBuddy.exe` **did resolve**, and the encrypted credential's `keyId` matched the registered vector verbatim. **The remaining candidates are still not verified per-item** — if your credential or app lives elsewhere, point `WORKBUDDY_AUTH_FILE` / `WORKBUDDY_APP_EXECUTABLE` at it and please report what you see.
|
|
206
206
|
3. **Encrypted credentials (from 5.6.0) require the desktop app to be present**, on Windows exactly as on macOS; if the app lives in a custom directory (e.g. `E:\WorkBuddy\WorkBuddy.exe`), point `WORKBUDDY_APP_EXECUTABLE` at it.
|
|
207
207
|
|
|
208
|
+
### Using it on a server: carry the credential over
|
|
209
|
+
|
|
210
|
+
On a headless server (or any machine where you would rather not install the WorkBuddy desktop app), the plugin has no local credential to read. The way around it is to **copy the credential directory over from a machine that has already signed in to WorkBuddy** — the plugin only reads that file and does not require the app to be present (**provided the credential itself is not encrypted**, see below):
|
|
211
|
+
|
|
212
|
+
```sh
|
|
213
|
+
# 1) On the machine that is already signed in to WorkBuddy, locate and pack the credential dir
|
|
214
|
+
# macOS: ~/Library/Application Support/CodeBuddyExtension
|
|
215
|
+
# Linux: ${XDG_CONFIG_HOME:-~/.config}/CodeBuddyExtension
|
|
216
|
+
# Windows: %LOCALAPPDATA%\CodeBuddyExtension and %APPDATA%\CodeBuddyExtension
|
|
217
|
+
tar czf codebuddy-cred.tgz -C <the parent directory above> CodeBuddyExtension
|
|
218
|
+
|
|
219
|
+
# 2) Move codebuddy-cred.tgz to the server and unpack it into the directory the plugin reads
|
|
220
|
+
# Linux:
|
|
221
|
+
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}"
|
|
222
|
+
tar xzf codebuddy-cred.tgz -C "${XDG_CONFIG_HOME:-$HOME/.config}"
|
|
223
|
+
|
|
224
|
+
# 3) Confirm the plugin sees it
|
|
225
|
+
dsh plugin --profile web exec dsh-connect-workbuddy status
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
> ⚠️ **On Linux there is no `~/.local/share` path.** The candidate directories come from `defaultDesktopAuthDirs()` in `src/auth.ts`, and **Linux reads only `$XDG_CONFIG_HOME` (defaulting to `~/.config`)**:
|
|
229
|
+
>
|
|
230
|
+
> | Platform | The credential directory the plugin actually reads |
|
|
231
|
+
> | --- | --- |
|
|
232
|
+
> | macOS | `~/Library/Application Support/CodeBuddyExtension/Data/Public/auth` |
|
|
233
|
+
> | Linux | `${XDG_CONFIG_HOME:-~/.config}/CodeBuddyExtension/Data/Public/auth` |
|
|
234
|
+
> | Windows | `CodeBuddyExtension\Data\Public\auth` under `%LOCALAPPDATA%` and `%APPDATA%` |
|
|
235
|
+
>
|
|
236
|
+
> So **unpacking into `~/.local/share` alone will not be seen** — either unpack into the directories listed above, or point `WORKBUDDY_AUTH_FILE` straight at the auth file (when set explicitly, sibling backup files in that directory are still scanned, so account switching keeps working).
|
|
237
|
+
|
|
238
|
+
> 🔐 **Encrypted credentials (WorkBuddy 5.6.0 and later) cannot be carried over this way.** Recent desktop builds encrypt the token fields inside the auth file, and the key is fetched at runtime from the app's native binding and never written to disk. On a server without the app, copying the encrypted auth file over **will not be readable** (the plugin reports not-signed-in honestly rather than degrading into reading a truncated token). What works: carry the credential from a machine still running a pre-5.6.0 version or an unencrypted credential, or install the app on that server to obtain the key.
|
|
239
|
+
>
|
|
240
|
+
> Two `doctor` lines tell you which case you are in:
|
|
241
|
+
>
|
|
242
|
+
> ```
|
|
243
|
+
> Desktop auth file: present (…/CodeBuddyExtension/Data/Public/auth/.workbuddy-auth.json)
|
|
244
|
+
> Encrypted-credential support: unavailable (…)
|
|
245
|
+
> ```
|
|
246
|
+
>
|
|
247
|
+
> `Desktop auth file: present` means the file was found; if `status` still reports not-signed-in while `Encrypted-credential support` is `unavailable` (no app on the server), that is the encrypted-credential-without-key case — carrying the file over cannot fix it.
|
|
248
|
+
|
|
249
|
+
> 🔒 **The credential is the account**: that file is a directly usable session. Transfer it over an encrypted channel (`scp` / private network), tighten it with `chmod 600` once on the server, and keep it out of anything that gets packaged or committed.
|
|
250
|
+
|
|
208
251
|
## Command line
|
|
209
252
|
|
|
210
253
|
```sh
|
package/README.md
CHANGED
|
@@ -215,6 +215,49 @@ dsh plugin --profile dsh-tui add dsh-connect-workbuddy # TUI
|
|
|
215
215
|
2. **凭据路径已部分经真机验证**。候选列表按平台约定推导并有单元测试钉住(含 `LOCALAPPDATA` / `APPDATA` 缺省与空白串两种回落)。已在真实 Windows 11 上确认:`%LOCALAPPDATA%\CodeBuddyExtension\Data\Public\auth` 与 `%LOCALAPPDATA%\Programs\WorkBuddy\WorkBuddy.exe` **命中**,加密凭据的 `keyId` 与登记向量逐字一致。**其余候选仍未经真机逐项验证**——若你的凭据或 App 不在默认位置,用 `WORKBUDDY_AUTH_FILE` / `WORKBUDDY_APP_EXECUTABLE` 指定,并欢迎回报现场。
|
|
216
216
|
3. **加密凭据(5.6.0 起)需要桌面 App 在场**,Windows 与 macOS 同样如此;App 装在自定义目录(如 `E:\WorkBuddy\WorkBuddy.exe`)时用 `WORKBUDDY_APP_EXECUTABLE` 指定。
|
|
217
217
|
|
|
218
|
+
### 在服务器上使用:搬运已登录的凭据
|
|
219
|
+
|
|
220
|
+
在无桌面环境的服务器(或任何不想安装 WorkBuddy 桌面 App 的机器)上,插件读不到本机凭据。办法是**从一台已经登录过 WorkBuddy 的机器上,把凭据目录整体拷过来**——插件只读这份文件,不要求 App 在场(**前提是凭据本身未加密**,见下):
|
|
221
|
+
|
|
222
|
+
```sh
|
|
223
|
+
# 1) 在「已登录 WorkBuddy 的机器」上,找到并打包凭据目录
|
|
224
|
+
# macOS: ~/Library/Application Support/CodeBuddyExtension
|
|
225
|
+
# Linux: ${XDG_CONFIG_HOME:-~/.config}/CodeBuddyExtension
|
|
226
|
+
# Windows:%LOCALAPPDATA%\CodeBuddyExtension 以及 %APPDATA%\CodeBuddyExtension
|
|
227
|
+
tar czf codebuddy-cred.tgz -C <上面的父目录> CodeBuddyExtension
|
|
228
|
+
|
|
229
|
+
# 2) 把 codebuddy-cred.tgz 传到服务器,解到「插件会读的那个目录」
|
|
230
|
+
# Linux:
|
|
231
|
+
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}"
|
|
232
|
+
tar xzf codebuddy-cred.tgz -C "${XDG_CONFIG_HOME:-$HOME/.config}"
|
|
233
|
+
|
|
234
|
+
# 3) 确认插件读到了
|
|
235
|
+
dsh plugin --profile web exec dsh-connect-workbuddy status
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
> ⚠️ **Linux 上没有 `~/.local/share` 这条路。** 插件的候选目录由 `src/auth.ts` 的 `defaultDesktopAuthDirs()` 决定,**Linux 只读 `$XDG_CONFIG_HOME`(缺省 `~/.config`)**:
|
|
239
|
+
>
|
|
240
|
+
> | 平台 | 插件实际读取的凭据目录 |
|
|
241
|
+
> | --- | --- |
|
|
242
|
+
> | macOS | `~/Library/Application Support/CodeBuddyExtension/Data/Public/auth` |
|
|
243
|
+
> | Linux | `${XDG_CONFIG_HOME:-~/.config}/CodeBuddyExtension/Data/Public/auth` |
|
|
244
|
+
> | Windows | `%LOCALAPPDATA%` 与 `%APPDATA%` 下的 `CodeBuddyExtension\Data\Public\auth` |
|
|
245
|
+
>
|
|
246
|
+
> 所以**只把凭据解到 `~/.local/share` 是不会被读到的**——要么解到上面列出的目录,要么用 `WORKBUDDY_AUTH_FILE` 直接指向那份 auth 文件(显式指定时该目录下的同级备份文件仍会一并扫描,账号切换照常可用)。
|
|
247
|
+
|
|
248
|
+
> 🔐 **加密凭据(WorkBuddy 5.6.0 起)不能靠搬运解决。** 新版桌面端把 auth 文件里的 token 字段加密了,密钥由 App 的原生绑定在**运行时现取**、不落盘。因此一台没有 App 的服务器上,即使把加密后的 auth 文件拷过去也**读不出来**(插件会如实报告未登录,而不会退化成读出一个残缺 token)。可行的做法是**从一台仍在运行 5.6.0 之前版本、或凭据未加密的机器上搬运**,或者在该服务器上安装 App 以取得密钥。
|
|
249
|
+
>
|
|
250
|
+
> 判断当前处于哪种情况,看 `doctor` 的两行输出即可:
|
|
251
|
+
>
|
|
252
|
+
> ```
|
|
253
|
+
> Desktop auth file: present (…/CodeBuddyExtension/Data/Public/auth/.workbuddy-auth.json)
|
|
254
|
+
> Encrypted-credential support: unavailable (…)
|
|
255
|
+
> ```
|
|
256
|
+
>
|
|
257
|
+
> `Desktop auth file: present` 说明文件找到了;此时若 `status` 仍报未登录、而 `Encrypted-credential support` 为 `unavailable`(服务器上没有 App),那就是加密凭据 + 缺密钥的场景——搬运救不了它。
|
|
258
|
+
|
|
259
|
+
> 🔒 **凭据等同于账号**:这份文件里是可直接使用的登录态。传输时请走加密通道(`scp` / 私网),落到服务器后用 `chmod 600` 收紧权限,别放进任何会被打包或提交的目录。
|
|
260
|
+
|
|
218
261
|
## 命令行
|
|
219
262
|
|
|
220
263
|
```sh
|
package/lib/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { C as defaultDesktopAuthDirs, F as WorkBuddyUpstreamClient, G as WORKBUDDY_APP_EXECUTABLE_ENV, O as legacyWorkbuddyOwnAuthPath, S as defaultDesktopAuthCandidates, Z as findWorkbuddyAppExecutableWithSource, a as readHostHeartbeat, at as hostPeersInfo, c as WORKBUDDY_CONNECT_VERSION, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, j as workbuddyOwnAuthPath, l as piAiRuntimeInfo, o as workbuddyHostHeartbeatPath, r as isHeartbeatProcessAlive, u as FALLBACK_WORKBUDDY_MODELS, v as WORKBUDDY_AUTH_FILE_ENV, y as WorkBuddyCredentialStore } from "./host-heartbeat-
|
|
2
|
+
import { C as defaultDesktopAuthDirs, F as WorkBuddyUpstreamClient, G as WORKBUDDY_APP_EXECUTABLE_ENV, O as legacyWorkbuddyOwnAuthPath, S as defaultDesktopAuthCandidates, Z as findWorkbuddyAppExecutableWithSource, a as readHostHeartbeat, at as hostPeersInfo, c as WORKBUDDY_CONNECT_VERSION, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, j as workbuddyOwnAuthPath, l as piAiRuntimeInfo, o as workbuddyHostHeartbeatPath, r as isHeartbeatProcessAlive, u as FALLBACK_WORKBUDDY_MODELS, v as WORKBUDDY_AUTH_FILE_ENV, y as WorkBuddyCredentialStore } from "./host-heartbeat-DkdNZKKY.js";
|
|
3
3
|
import { realpathSync } from "node:fs";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
//#region src/bin.ts
|
|
@@ -1763,8 +1763,9 @@ var WorkBuddyUpstreamClient = class {
|
|
|
1763
1763
|
const account = raw;
|
|
1764
1764
|
const numberField = (key) => typeof account[key] === "number" ? account[key] : 0;
|
|
1765
1765
|
const monthly = numberField("CapacityType") === 4;
|
|
1766
|
-
const size =
|
|
1767
|
-
const remain =
|
|
1766
|
+
const size = numberField("CapacitySize") || numberField("CycleCapacitySize");
|
|
1767
|
+
const remain = numberField("CapacityRemain");
|
|
1768
|
+
const cycleRemain = monthly ? numberField("CycleCapacityRemain") : void 0;
|
|
1768
1769
|
const cappedRemain = remain < 0 ? 0 : remain;
|
|
1769
1770
|
const cycleEndMs = parseDate(account["CycleEndTime"]);
|
|
1770
1771
|
const expiresAtMs = monthly ? void 0 : parseDate(account["ExpiredTime"]) ?? cycleEndMs;
|
|
@@ -1781,6 +1782,7 @@ var WorkBuddyUpstreamClient = class {
|
|
|
1781
1782
|
remain: cappedRemain,
|
|
1782
1783
|
size,
|
|
1783
1784
|
monthly,
|
|
1785
|
+
...cycleRemain === void 0 ? {} : { cycleRemain: Math.max(0, cycleRemain) },
|
|
1784
1786
|
...refreshAtMs === void 0 ? {} : { refreshAtMs },
|
|
1785
1787
|
...expiresAtMs === void 0 ? {} : { expiresAtMs }
|
|
1786
1788
|
});
|
|
@@ -3707,7 +3709,7 @@ function generationOf(version) {
|
|
|
3707
3709
|
//#endregion
|
|
3708
3710
|
//#region src/version.ts
|
|
3709
3711
|
/** The npm package version this build was produced from. */
|
|
3710
|
-
const WORKBUDDY_CONNECT_VERSION = "4.3.
|
|
3712
|
+
const WORKBUDDY_CONNECT_VERSION = "4.3.4";
|
|
3711
3713
|
//#endregion
|
|
3712
3714
|
//#region src/host-heartbeat.ts
|
|
3713
3715
|
/**
|
package/lib/index.d.ts
CHANGED
|
@@ -605,10 +605,26 @@ interface WorkBuddyUpstreamModel {
|
|
|
605
605
|
descriptionEn?: string;
|
|
606
606
|
supportsToolCall?: boolean;
|
|
607
607
|
}
|
|
608
|
-
/** One billing package and its remaining credit, already aggregated. */
|
|
609
608
|
/** One billing package as the upstream returns it, dates already parsed. */
|
|
610
609
|
interface WorkBuddyCreditPackage {
|
|
611
610
|
packageName: string;
|
|
611
|
+
/**
|
|
612
|
+
* Remaining credit, always read from `CapacityRemain` (issue #48).
|
|
613
|
+
*
|
|
614
|
+
* The upstream reports a monthly resource (`CapacityType 4`) with TWO
|
|
615
|
+
* capacity families, and they answer different questions:
|
|
616
|
+
*
|
|
617
|
+
* - `CapacityRemain` / `CapacitySize` / `CapacityUsed` — the capacity POOL.
|
|
618
|
+
* - `CycleCapacityRemain` / `CycleCapacitySize` / `CycleCapacityUsed` — the
|
|
619
|
+
* CURRENT BILLING CYCLE.
|
|
620
|
+
*
|
|
621
|
+
* "How much credit do I have" is the pool, so that is what this field
|
|
622
|
+
* carries. Reading `CycleCapacityRemain` here was the defect: on three real
|
|
623
|
+
* global accounts the upstream returned `CapacityRemain=100` together with
|
|
624
|
+
* `CycleCapacityRemain=0` and `CycleCapacityUsed=100` inside an UNFINISHED
|
|
625
|
+
* cycle (`CycleEndTime` days out, `Status=0`), so the plugin reported 0
|
|
626
|
+
* credits for accounts that were not exhausted at all.
|
|
627
|
+
*/
|
|
612
628
|
remain: number;
|
|
613
629
|
size: number;
|
|
614
630
|
/** CapacityType 4: refreshed every cycle and never expires. */
|
|
@@ -617,6 +633,16 @@ interface WorkBuddyCreditPackage {
|
|
|
617
633
|
refreshAtMs?: number;
|
|
618
634
|
/** One-off expiry; the package disappears from the account at this time. */
|
|
619
635
|
expiresAtMs?: number;
|
|
636
|
+
/**
|
|
637
|
+
* Remaining credit in the CURRENT cycle; only on monthly packages.
|
|
638
|
+
*
|
|
639
|
+
* Kept beside {@link remain} because it answers the one question the pool
|
|
640
|
+
* total cannot: whether THIS cycle's allowance is spent. That is what makes
|
|
641
|
+
* `refreshAtMs` meaningful — "you are out until the cycle resets" is a
|
|
642
|
+
* different statement from "you are out of credit", and only the cycle
|
|
643
|
+
* figure can tell them apart.
|
|
644
|
+
*/
|
|
645
|
+
cycleRemain?: number;
|
|
620
646
|
}
|
|
621
647
|
/** Aggregated credit answer for one credential. */
|
|
622
648
|
interface WorkBuddyCredits {
|
|
@@ -2017,10 +2043,18 @@ declare function nextRegionEnabled(value: unknown, region: WorkBuddyWebRegion, e
|
|
|
2017
2043
|
/** One credit package as the upstream returns it, node-free. */
|
|
2018
2044
|
interface WorkBuddyWebCreditPackage {
|
|
2019
2045
|
packageName: string;
|
|
2046
|
+
/** Capacity-pool balance (`CapacityRemain`); see the host-side type for issue #48. */
|
|
2020
2047
|
remain: number;
|
|
2021
2048
|
size: number;
|
|
2022
2049
|
/** CapacityType 4: refreshed every cycle and never expires. */
|
|
2023
2050
|
monthly: boolean;
|
|
2051
|
+
/**
|
|
2052
|
+
* Balance of the CURRENT cycle (`CycleCapacityRemain`); only on monthly
|
|
2053
|
+
* packages. `0` on a live package means this cycle's allowance is spent,
|
|
2054
|
+
* which is what {@link cycleRefreshMs} is telling the user to wait for — and
|
|
2055
|
+
* is deliberately NOT the same as {@link remain} being 0 (issue #48).
|
|
2056
|
+
*/
|
|
2057
|
+
cycleRemain?: number;
|
|
2024
2058
|
/** Next cycle start (the monthly refresh point) in ms; only on monthly packages. */
|
|
2025
2059
|
cycleRefreshMs?: number;
|
|
2026
2060
|
/** One-off expiry in ms; the package disappears from the account then. */
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as isWorkbuddyBundle, A as workbuddyAccountId, B as parseCreditMultiplier, C as defaultDesktopAuthDirs, D as isVaultAccountId, E as isEncryptedCredentialError, F as WorkBuddyUpstreamClient, G as WORKBUDDY_APP_EXECUTABLE_ENV, H as parseUpstreamModel, I as classifyUpstreamError, J as deriveAtRestKeyId, K as clearAtRestKeyCache, L as declaredTools, M as CREDENTIAL_REJECTED_CODE, N as WORKBUDDY_FALLBACK_SYSTEM_PROMPT, O as legacyWorkbuddyOwnAuthPath, P as WorkBuddyCredentialRejectedError, Q as isEncryptedFieldWrapper, R as isCredentialRejectedError, S as defaultDesktopAuthCandidates, T as hasEncryptedCredentialFields, U as prepareChatBody, V as parseReasoning, W as regionOf, X as findWorkbuddyAppExecutable, Y as fetchAtRestKeyPayload, _ as WORKBUDDY_AUTH_FILENAME, a as readHostHeartbeat, b as WorkBuddyEncryptedCredentialError, c as WORKBUDDY_CONNECT_VERSION, ct as writeFileAtomic, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, et as macosBundleExecutable, f as WorkBuddyCatalog, g as ENCRYPTED_CREDENTIAL_CODE, h as fallbackModelsFor, i as processStartTimeMs, it as workbuddyAppExecutableCandidates, j as workbuddyOwnAuthPath, k as parseWorkBuddyAuth, l as piAiRuntimeInfo, m as deriveCatalog, n as clearHostHeartbeat, nt as openEncryptedField, o as workbuddyHostHeartbeatPath, ot as resolveDshHome, p as applyContextBudgets, q as deriveAtRestKey, r as isHeartbeatProcessAlive, rt as readAtRestKey, s as writeHostHeartbeat, st as withFileLock, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, tt as macosNestedAppBundles, u as FALLBACK_WORKBUDDY_MODELS, v as WORKBUDDY_AUTH_FILE_ENV, w as defaultDesktopAuthPath, x as authFileName, y as WorkBuddyCredentialStore, z as knownRegionOf } from "./host-heartbeat-
|
|
1
|
+
import { $ as isWorkbuddyBundle, A as workbuddyAccountId, B as parseCreditMultiplier, C as defaultDesktopAuthDirs, D as isVaultAccountId, E as isEncryptedCredentialError, F as WorkBuddyUpstreamClient, G as WORKBUDDY_APP_EXECUTABLE_ENV, H as parseUpstreamModel, I as classifyUpstreamError, J as deriveAtRestKeyId, K as clearAtRestKeyCache, L as declaredTools, M as CREDENTIAL_REJECTED_CODE, N as WORKBUDDY_FALLBACK_SYSTEM_PROMPT, O as legacyWorkbuddyOwnAuthPath, P as WorkBuddyCredentialRejectedError, Q as isEncryptedFieldWrapper, R as isCredentialRejectedError, S as defaultDesktopAuthCandidates, T as hasEncryptedCredentialFields, U as prepareChatBody, V as parseReasoning, W as regionOf, X as findWorkbuddyAppExecutable, Y as fetchAtRestKeyPayload, _ as WORKBUDDY_AUTH_FILENAME, a as readHostHeartbeat, b as WorkBuddyEncryptedCredentialError, c as WORKBUDDY_CONNECT_VERSION, ct as writeFileAtomic, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, et as macosBundleExecutable, f as WorkBuddyCatalog, g as ENCRYPTED_CREDENTIAL_CODE, h as fallbackModelsFor, i as processStartTimeMs, it as workbuddyAppExecutableCandidates, j as workbuddyOwnAuthPath, k as parseWorkBuddyAuth, l as piAiRuntimeInfo, m as deriveCatalog, n as clearHostHeartbeat, nt as openEncryptedField, o as workbuddyHostHeartbeatPath, ot as resolveDshHome, p as applyContextBudgets, q as deriveAtRestKey, r as isHeartbeatProcessAlive, rt as readAtRestKey, s as writeHostHeartbeat, st as withFileLock, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, tt as macosNestedAppBundles, u as FALLBACK_WORKBUDDY_MODELS, v as WORKBUDDY_AUTH_FILE_ENV, w as defaultDesktopAuthPath, x as authFileName, y as WorkBuddyCredentialStore, z as knownRegionOf } from "./host-heartbeat-DkdNZKKY.js";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { readFile } from "node:fs/promises";
|
|
4
4
|
import { randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
@@ -3619,6 +3619,7 @@ function toCredits(answer) {
|
|
|
3619
3619
|
remain: pack.remain,
|
|
3620
3620
|
size: pack.size,
|
|
3621
3621
|
monthly: pack.monthly,
|
|
3622
|
+
...pack.cycleRemain === void 0 ? {} : { cycleRemain: pack.cycleRemain },
|
|
3622
3623
|
...pack.refreshAtMs === void 0 ? {} : { cycleRefreshMs: pack.refreshAtMs },
|
|
3623
3624
|
...pack.expiresAtMs === void 0 ? {} : { expiresAtMs: pack.expiresAtMs }
|
|
3624
3625
|
})),
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dsh-connect-workbuddy",
|
|
3
3
|
"displayName": "DSH Connect WorkBuddy",
|
|
4
4
|
"description": "把本机登录的 WorkBuddy 模型接入 DeepSeek Harness,并提供只读的积分概览与模型管理。",
|
|
5
|
-
"version": "4.3.
|
|
5
|
+
"version": "4.3.4",
|
|
6
6
|
"author": "dingminhua",
|
|
7
7
|
"copyright": "Copyright (c) 2026 LaoDing",
|
|
8
8
|
"license": "MIT",
|