dsh-connect-workbuddy 5.0.0 → 5.0.1
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 -2
- package/lib/bin.js +1 -1
- package/lib/client.js +35 -14
- package/lib/{host-heartbeat-D313ENPV.js → host-heartbeat-DtMzOwZr.js} +53 -16
- package/lib/index.js +7 -4
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.0.1 (2026-10-22)
|
|
4
|
+
|
|
5
|
+
> 版本号是 **patch**:改卡面上的一个字符串(标题)、去掉模型列表的一条 CSS 规则与两行路由项,以及几处描述它们的文档。没有接口或配置结构的变更——但如果你的配置里存着 `auto` / `default-model`,升级后它不再出现在列表里。
|
|
6
|
+
|
|
7
|
+
### Fixes
|
|
8
|
+
|
|
9
|
+
- **国际区的 `Auto` 行也从模型列表里去掉了** —— 它和国内区的 `auto` 是**同一个东西的两个 id**:都是该区的默认路由(`isDefault: true`、都叫 `Auto`),也都是各自名册里**唯一不声明积分倍率**的那一行(实测 2026-10-22:国内 20 个里 19 个标了价,国际 28 个里 27 个)。国内区的 `auto` 早就被过滤了,国际区的 `default-model` 一直漏着——一个插件无法标价的行,就是它无法向你交代成本的行。
|
|
10
|
+
- **判据不是名字**:`fast-model` / `balanced-model` / `primary-model` 也是别名,但它们都声明了真实倍率(x0.34 / x0.59 / x3.31),所以保留。丢掉它们会平白拿走三个用户真正会选的模型。
|
|
11
|
+
- **顺带修掉一个会把它带回来的漏洞**:`keepIds` 分支(让用户正在用的模型不被刷新撤掉,issue #32)原本不过滤路由,于是**旧配置里 `enabledModelIds` 还留着 `auto` 的人,每次刷新都会把这行重新加回来**——而且取消勾选也去不掉。现在两条路径都过滤。
|
|
12
|
+
- **在读取点过滤,而不是迁移已保存的配置**:`lastCatalog` 是配置里带着的历史快照,卡片读的就是它。只改刷新逻辑的话,升级后这一行会继续显示到下次刷新为止,看起来就像「没修好」。现在 `withoutRouters()` 在 `displayModels` 与 `configuredModels` 两处读取时过滤,存进去的值不动——升级后立刻消失,而不是等一次刷新。
|
|
13
|
+
|
|
14
|
+
- **模型页不再有内部滚动条,所有模型一次全部呈现** —— 设置卡片「模型」栏的列表此前带 `max-height: 520px` + `overflow-y: auto`,20 多个模型只显示七行左右,其余藏在一条需要先发现、再拖动的滚动条后面;而面板本身已经在滚动,于是是两条滚动条叠在一起。
|
|
15
|
+
- **`overflow: hidden` 保留**,而且是必要的:圆角由这个带边框的盒子绘制,不裁剪的话首行与末行会把直角画到圆角上。只是现在盒子的高度就等于内容高度,不会再裁掉任何东西。
|
|
16
|
+
- **5.0.0 的描述写错了**,本版一并更正:当时记的是「模型表自己内滚」,与最终代码不符。
|
|
17
|
+
|
|
18
|
+
- **插件卡片的标题改回包名 `dsh-connect-workbuddy`** —— 5.0.0 里补 `locale/{en,zh}.json` 时,`meta.title` 写成了「WorkBuddy 模型接入」/「WorkBuddy Model Access」,于是卡片标题从裸包名变成了那个名字。这个插件的身份就是包名——仓库、npm 页面、issue 里都是这个叫法——所以改回去。
|
|
19
|
+
- **显式写出包名,而不是删掉 `meta.title` 留空**。两种做法渲染出的字完全一样(宿主 `localizedText` 的 fallback 就是 `manifest.name`),但留空之后文件里没有任何地方记录「标题应当等于包名」这件事,下一次「给它起个好听点的名字」看起来就会像一次免费改进,而不是一次回退。`tests/locale-meta.spec.ts` 现在钉住它。
|
|
20
|
+
- **简介不受影响**:仍由 `locale/zh.json` / `locale/en.json` 各自的 `meta.description` 提供,中英分离如初。
|
|
21
|
+
|
|
22
|
+
### Docs
|
|
23
|
+
|
|
24
|
+
- `docs/DESIGN.md` 更正一处过时说法(原文写「本仓库的 `package.json.description` 是英文」,那是 PR 原本的写法,合并时按「保持中文」处理了);并补上第 4 条机制事实:`meta.title` 就写成包名,以及为什么写出来而不是留空。
|
|
25
|
+
- `CHANGELOG` 的 5.0.0 条目同步改成包名口径。
|
|
26
|
+
- 顺带说明 `package.json` 里那个 `DSH Connect WorkBuddy`(`displayName`)**不参与任何渲染**——宿主标题的回退是 `manifest.name`,不是它。保留只是历史遗留。
|
|
27
|
+
|
|
28
|
+
### Tests
|
|
29
|
+
|
|
30
|
+
- `tests/locale-meta.spec.ts` 那条从「标题**不**等于包名」改为「两种语言的标题**都**等于包名」,并把理由写进用例:这是一个决定,不是一个默认值。
|
|
31
|
+
- `tests/client-host-contract.spec.ts` 新增 1 条守卫:`.dsm-workbuddy-model-list` 的规则里**不得**出现 `max-height` 或 `overflow-y`,同时**必须**保留 `overflow:hidden`(只断言「没有上限」会让人以后把裁剪也顺手删掉,而那是圆角所依赖的)。
|
|
32
|
+
- `tests/catalog.spec.ts` 新增 4 条 `withoutRouters` 用例:过滤旧快照里的路由、CN 的 `auto` 与国��的 `default-model` 都被认出、`fast`/`balanced`/`primary` 不受牵连、不修改入参;并把「两个区的 fallback 名册都不含各自的路由」从只查 `auto` 扩到两个 id。
|
|
33
|
+
- `tests/upstream.spec.ts` 新增 4 条 `selectCliModels` 用例:两个区各自的 `auto` 都被丢掉、**旧配置里仍写着 `auto` 时不会借 `keepIds` 复活**、真正的「已下架但你在用」的模型仍然被保住(issue #32 那一半不能被这次过滤破坏)。
|
|
34
|
+
- `tests/native-modality.spec.ts` 的路由用例扩成两个 id,并明确 `fast`/`balanced`/`primary`/`deep` 不算路由。
|
|
35
|
+
- 全量 `npx vitest run` = **107 文件 / 1760 测试全绿**;`tsc` 两个 project 均 exit 0;`npm run build` 成功。
|
|
36
|
+
|
|
3
37
|
## 5.0.0 (2026-10-21)
|
|
4
38
|
|
|
5
39
|
> 版本号是 **major**:接口与配置项没有破坏性变更(顶层配置字段一个不少,也没有导出被删),但这一版把「花不花钱」的决定权**第一次交给了模型**。在此之前,本插件每一次花钱都跟一个人工动作绑在一起:一条聊天请求是你发的,模型行的「测试」按钮是你点的。5.0.0 新增的 `workbuddy_draw_image` 是模型自己决定调的——约 5.71 积分一张,而宿主没有「调用前先确认」的机制(`needsApproval` / `toolApproval` 在 `app.asar` 里都不存在)。
|
|
@@ -18,7 +52,7 @@
|
|
|
18
52
|
- **设置卡片按「账号 / 模型 / 诊断」分栏** —— 这张卡片原来是一条 3538 像素的长页,把两类提交语义完全不同的事情混排在一根竖线上:账号改动点一下立刻生效,目录改动是草稿、必须按「保存」,而用户在第 1 屏勾完模型后要滚三屏才能找到那个按钮。
|
|
19
53
|
- **三栏**:**账号**(地区说明、积分开关、凭据类错误、账号池的切换/签到/导入导出/日志)、**模型**(模型表、保存/放弃)、**诊断**(只读事实表:区域、上游域名、当前服务的账号名、登录有效期、目录模型数、已启用数、上游最近一次错误的原文)。地区的「国内版 / 国际版」两个 tab 原样保留在最上面,它是这三栏共同的作用域。
|
|
20
54
|
- **切栏不重新拉、不丢草稿**:非活动栏用 `hidden` 留在页面里而不是卸载,所以改了几个勾、切去看一眼余额、再切回来的改动还在,账号池的日志也不重建。`hidden` 同时把非活动栏移出无障碍树,`role="tabpanel"` 的语义成立(用 CSS `display:none` 反而会被后续样式覆盖)。
|
|
21
|
-
-
|
|
55
|
+
- 模型表**全部展开,不设内部滚动**。(5.0.0 原本写成 `max-height: 520px` 内滚,5.0.2 改掉:见该版说明。)
|
|
22
56
|
- **签出态不画分栏**:没有登录时这张卡片就是一屏说明,套三个空 tab 只会把唯一的说明藏起来。
|
|
23
57
|
- **诊断栏没有任何控件**,它存在的唯一理由是能被整段贴进问题反馈:账号显示**名字**而不是 id(测试里专门断言不出现 id),上游错误是原文引用、不翻译不概括。
|
|
24
58
|
|
|
@@ -32,7 +66,7 @@
|
|
|
32
66
|
- **`locale/en.json` 是锚点**:读取端遍历的是「英文资源所在目录」,没有它 `zh.json` 永远不会被读——而且不报错。
|
|
33
67
|
- **`exports` 缺 `"./locale/*.json"` 通配 = 静默失败**:解析抛 `ERR_PACKAGE_PATH_NOT_EXPORTED`,读取端把它连同其它失败一起吞掉。
|
|
34
68
|
- **`files` 必须带裸目录 `locale`**,否则发布出去的 tarball 里没有它自己那份文案。
|
|
35
|
-
-
|
|
69
|
+
- 现在中文界面读 `locale/zh.json`、英文界面读 `locale/en.json`,两边各有自己的简介。**标题就是包名 `dsh-connect-workbuddy`**(两处 `meta.title` 都这么写):这个插件的身份就是那个包名,仓库、npm 页面与 issue 里都是这个叫法;写出来而不是留空,是因为留空也会经 `localizedText` 的 `fallback` 渲染出同样的字,但文件里就没有任何地方记录「这是决定」。`package.json` 的 `description` **保持中文**:它同时是 npm 包页面的简介、GitHub 的仓库简介,和「万一 locale 读不到」的最后兜底——英文文案住在 `locale/en.json` 里,那才是能覆盖兜底的那一份。
|
|
36
70
|
|
|
37
71
|
- **新增生图工具 `workbuddy_draw_image`(国内区,默认关闭,需显式授权)** —— 把 WorkBuddy 官方 CLI 的文生图能力暴露成一个 DSH agent 工具,模型可以按用户的描述直接画一张图。
|
|
38
72
|
- **为什么它是 opt-in,而其他功能不是**:这是本插件唯一「由模型决定花钱」的能力。聊天请求是你发的,「测试」按钮是你点的,而工具调用是模型自己发起的——约 5.71 积分一张,宿主又没有逐次确认的机制。所以开关归你:`regions.cn.imageToolEnabled`,默认 `false`,关着时工具不注册。这与 3.0.0 给账号池的处理是同一个道理(能改变账单落点的功能必须显式打开)。
|
package/lib/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { C as
|
|
2
|
+
import { C as defaultDesktopAuthCandidates, I as WorkBuddyUpstreamClient, M as workbuddyOwnAuthPath, a as readHostHeartbeat, b as WorkBuddyCredentialStore, c as WORKBUDDY_CONNECT_VERSION, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, ht as WORKBUDDY_APP_EXECUTABLE_ENV, k as legacyWorkbuddyOwnAuthPath, kt as hostPeersInfo, l as piAiRuntimeInfo, o as workbuddyHostHeartbeatPath, r as isHeartbeatProcessAlive, u as FALLBACK_WORKBUDDY_MODELS, w as defaultDesktopAuthDirs, xt as findWorkbuddyAppExecutableWithSource, y as WORKBUDDY_AUTH_FILE_ENV } from "./host-heartbeat-DtMzOwZr.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
|
@@ -1556,17 +1556,30 @@ window.__ModuleLoader__.load({
|
|
|
1556
1556
|
/**
|
|
1557
1557
|
* Ids the upstream lists in the model roster that are ROUTERS, not models.
|
|
1558
1558
|
*
|
|
1559
|
-
*
|
|
1560
|
-
*
|
|
1561
|
-
*
|
|
1562
|
-
*
|
|
1563
|
-
*
|
|
1559
|
+
* Two of them are known, one per region, and they are the SAME concept under
|
|
1560
|
+
* two ids:
|
|
1561
|
+
*
|
|
1562
|
+
* - `auto` (CN gateway) — the gateway resolves it to whichever model it
|
|
1563
|
+
* considers the best fit (measured: CN `auto` → `hy4-preview`), and its own
|
|
1564
|
+
* description says so outright: 「平衡效果与速度。自动为每个任务匹配最优模型,
|
|
1565
|
+
* 积分倍率随之浮动」 ("picks the best model per task; the credit multiplier
|
|
1566
|
+
* floats accordingly").
|
|
1567
|
+
* - `default-model` (international gateway) — identical role (name "Auto",
|
|
1568
|
+
* `isDefault: true`, the region's default pick), also the ONLY entry in that
|
|
1569
|
+
* roster that declares no `credits` at all.
|
|
1570
|
+
*
|
|
1571
|
+
* The evidence for treating both as routers is the shared, self-describing
|
|
1572
|
+
* shape, not the name: measured 2026-10-22 against both live gateways, these
|
|
1573
|
+
* two entries are the ONLY ones whose `credits` field is absent/empty (CN 19
|
|
1574
|
+
* of 20 priced, global 27 of 28), and the ones carrying `isDefault: true`.
|
|
1575
|
+
* A row the plugin cannot price is a row whose cost it cannot state, and the
|
|
1576
|
+
* router duplicates a real row already in the same roster.
|
|
1564
1577
|
*
|
|
1565
1578
|
* Kept as an explicit table rather than a heuristic: a router is an upstream
|
|
1566
1579
|
* concept with no declared flag, and guessing from the name would eventually
|
|
1567
1580
|
* hide a real model. Add an id here only after the same kind of evidence.
|
|
1568
1581
|
*/
|
|
1569
|
-
const ROUTER_MODEL_IDS = /* @__PURE__ */ new Set(["auto"]);
|
|
1582
|
+
const ROUTER_MODEL_IDS = /* @__PURE__ */ new Set(["auto", "default-model"]);
|
|
1570
1583
|
/** Whether this id is an upstream router rather than a model. */
|
|
1571
1584
|
function isRouterModelId(modelId) {
|
|
1572
1585
|
return ROUTER_MODEL_IDS.has(modelId);
|
|
@@ -4231,14 +4244,22 @@ window.__ModuleLoader__.load({
|
|
|
4231
4244
|
an error banner, because the fact it states is normal product behaviour
|
|
4232
4245
|
rather than a failure. Weight is the only signal it needs. */
|
|
4233
4246
|
.dsm-workbuddy-free-quota-warn{font-weight:600}
|
|
4234
|
-
/*
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4247
|
+
/* Every model is laid out in full — NO inner scroll box.
|
|
4248
|
+
*
|
|
4249
|
+
* The previous rule capped this at max-height 520px with overflow-y auto, so a
|
|
4250
|
+
* 20-model roster showed about seven rows and hid the rest behind a scrollbar
|
|
4251
|
+
* the user had to discover and then drag inside a panel that already scrolls.
|
|
4252
|
+
* A model picker whose whole job is "let me see and tick models" should not
|
|
4253
|
+
* have two scrollbars stacked on top of each other.
|
|
4254
|
+
*
|
|
4255
|
+
* overflow:hidden stays, and it is load-bearing rather than vestigial: the
|
|
4256
|
+
* rounded corners are drawn by this bordered box, so without clipping the first
|
|
4257
|
+
* and last row would paint square corners over it. Nothing is CLIPPED by it any
|
|
4258
|
+
* more, because the box is now exactly as tall as its contents.
|
|
4259
|
+
*
|
|
4260
|
+
* NOTE: no backticks in CSS comments inside this template literal — one would
|
|
4261
|
+
* terminate the string early and silently drop every rule after it. */
|
|
4262
|
+
.dsm-workbuddy-model-list{display:flex;flex-direction:column;border:1px solid var(--dsw-alias-border-l2,#36373b);border-radius:10px;overflow:hidden}
|
|
4242
4263
|
.dsm-workbuddy-model{display:grid;grid-template-columns:minmax(0,1fr);gap:7px;padding:10px 12px;background:var(--dsw-alias-bg-layer-2,#232529);transition:opacity .16s}
|
|
4243
4264
|
.dsm-workbuddy-model-disabled{opacity:.55}
|
|
4244
4265
|
.dsm-workbuddy-model+.dsm-workbuddy-model{border-top:1px solid var(--dsw-alias-border-l2,#36373b)}
|
|
@@ -985,17 +985,30 @@ const NATIVE_MODALITY_BY_MODEL_ID = {
|
|
|
985
985
|
/**
|
|
986
986
|
* Ids the upstream lists in the model roster that are ROUTERS, not models.
|
|
987
987
|
*
|
|
988
|
-
*
|
|
989
|
-
*
|
|
990
|
-
*
|
|
991
|
-
*
|
|
992
|
-
*
|
|
988
|
+
* Two of them are known, one per region, and they are the SAME concept under
|
|
989
|
+
* two ids:
|
|
990
|
+
*
|
|
991
|
+
* - `auto` (CN gateway) — the gateway resolves it to whichever model it
|
|
992
|
+
* considers the best fit (measured: CN `auto` → `hy4-preview`), and its own
|
|
993
|
+
* description says so outright: 「平衡效果与速度。自动为每个任务匹配最优模型,
|
|
994
|
+
* 积分倍率随之浮动」 ("picks the best model per task; the credit multiplier
|
|
995
|
+
* floats accordingly").
|
|
996
|
+
* - `default-model` (international gateway) — identical role (name "Auto",
|
|
997
|
+
* `isDefault: true`, the region's default pick), also the ONLY entry in that
|
|
998
|
+
* roster that declares no `credits` at all.
|
|
999
|
+
*
|
|
1000
|
+
* The evidence for treating both as routers is the shared, self-describing
|
|
1001
|
+
* shape, not the name: measured 2026-10-22 against both live gateways, these
|
|
1002
|
+
* two entries are the ONLY ones whose `credits` field is absent/empty (CN 19
|
|
1003
|
+
* of 20 priced, global 27 of 28), and the ones carrying `isDefault: true`.
|
|
1004
|
+
* A row the plugin cannot price is a row whose cost it cannot state, and the
|
|
1005
|
+
* router duplicates a real row already in the same roster.
|
|
993
1006
|
*
|
|
994
1007
|
* Kept as an explicit table rather than a heuristic: a router is an upstream
|
|
995
1008
|
* concept with no declared flag, and guessing from the name would eventually
|
|
996
1009
|
* hide a real model. Add an id here only after the same kind of evidence.
|
|
997
1010
|
*/
|
|
998
|
-
const ROUTER_MODEL_IDS = /* @__PURE__ */ new Set(["auto"]);
|
|
1011
|
+
const ROUTER_MODEL_IDS = /* @__PURE__ */ new Set(["auto", "default-model"]);
|
|
999
1012
|
/** Whether this id is an upstream router rather than a model. */
|
|
1000
1013
|
function isRouterModelId(modelId) {
|
|
1001
1014
|
return ROUTER_MODEL_IDS.has(modelId);
|
|
@@ -3233,7 +3246,7 @@ function selectCliModels(rawModels, agents, keepIds = []) {
|
|
|
3233
3246
|
}
|
|
3234
3247
|
const ids = cliIds !== void 0 && cliIds.length > 0 ? cliIds : [...byId.keys()];
|
|
3235
3248
|
const models = ids.filter((id) => !isRouterModelId(id)).map((id) => byId.get(id)).filter((model) => model !== void 0);
|
|
3236
|
-
const kept = keepIds.filter((id) => !ids.includes(id)).map((id) => byId.get(id)).filter((model) => model !== void 0);
|
|
3249
|
+
const kept = keepIds.filter((id) => !ids.includes(id) && !isRouterModelId(id)).map((id) => byId.get(id)).filter((model) => model !== void 0);
|
|
3237
3250
|
const resolved = [...models, ...kept];
|
|
3238
3251
|
if (resolved.length === 0) throw new Error("workbuddy model catalog resolved to an empty list");
|
|
3239
3252
|
return resolved;
|
|
@@ -5229,6 +5242,22 @@ var WorkBuddyCredentialStore = class {
|
|
|
5229
5242
|
//#endregion
|
|
5230
5243
|
//#region src/catalog.ts
|
|
5231
5244
|
/**
|
|
5245
|
+
* WorkBuddy model catalog: a static fallback list, replaced by the upstream's
|
|
5246
|
+
* dynamic catalog once it loads, and filtered by the user's explicit selection.
|
|
5247
|
+
*
|
|
5248
|
+
* 参考:dingminhua/dsh-connect-trae(MIT,Copyright (c) 2026 LaoDing)
|
|
5249
|
+
* — 「上次刷新的完整目录(lastCatalog)与用户勾选分离,运行时目录由两者
|
|
5250
|
+
* 推导」的模型来自该项目。它让卡片永远展示最新目录而不是陈旧快照,
|
|
5251
|
+
* 并让上游刷新成为草稿操作(用户点保存才生效)。
|
|
5252
|
+
* 静态 fallback 目录的做法来自
|
|
5253
|
+
* corrinehu/dsh-workbuddy-connect(MIT):上游不可用时 provider 不为空。
|
|
5254
|
+
* 改动:WorkBuddy 直接用各模型的 `maxInputTokens` 声明实际上下文窗口;
|
|
5255
|
+
* 上游没有独立的长上下文开关或第二个模型 id,因此不会虚构 `@1m` 变体。
|
|
5256
|
+
* 本目录额外承载上游给出的积分倍率、多模态与推理档位。
|
|
5257
|
+
*
|
|
5258
|
+
* @module dsh-connect-workbuddy/catalog
|
|
5259
|
+
*/
|
|
5260
|
+
/**
|
|
5232
5261
|
* Static CLI models captured from the CN endpoint (2026-08-30). The upstream
|
|
5233
5262
|
* refresh replaces this list at startup; it exists so the provider registers
|
|
5234
5263
|
* with a usable catalog even while the first fetch is in flight or offline.
|
|
@@ -5316,13 +5345,6 @@ const FALLBACK_WORKBUDDY_MODELS = [
|
|
|
5316
5345
|
* usable before the first fetch lands. Order and rates mirror the upstream.
|
|
5317
5346
|
*/
|
|
5318
5347
|
const FALLBACK_WORKBUDDY_MODELS_GLOBAL = [
|
|
5319
|
-
{
|
|
5320
|
-
id: "default-model",
|
|
5321
|
-
name: "Auto",
|
|
5322
|
-
contextWindow: 176e3,
|
|
5323
|
-
maxTokens: 24e3,
|
|
5324
|
-
creditMultiplier: .79
|
|
5325
|
-
},
|
|
5326
5348
|
{
|
|
5327
5349
|
id: "fast-model",
|
|
5328
5350
|
name: "Fast",
|
|
@@ -5466,6 +5488,21 @@ function fallbackModelsFor(region) {
|
|
|
5466
5488
|
return region === "global" ? FALLBACK_WORKBUDDY_MODELS_GLOBAL : FALLBACK_WORKBUDDY_MODELS;
|
|
5467
5489
|
}
|
|
5468
5490
|
/**
|
|
5491
|
+
* Drop the upstream's ROUTER rows from a roster that came from settings.
|
|
5492
|
+
*
|
|
5493
|
+
* The static lists and `selectCliModels` both refuse routers already, but
|
|
5494
|
+
* `lastCatalog` is a SNAPSHOT the user's profile carries from an earlier
|
|
5495
|
+
* version — and every read of it (the card's list, the runtime catalog, the
|
|
5496
|
+
* provider's advertisement) would otherwise keep showing the row long after the
|
|
5497
|
+
* code stopped offering it. Filtering at the READ point instead of migrating the
|
|
5498
|
+
* saved value is deliberate: the stored slot stays exactly what the last refresh
|
|
5499
|
+
* wrote, so nothing is silently rewritten on load, and the row disappears the
|
|
5500
|
+
* moment the new code runs rather than at the next refresh.
|
|
5501
|
+
*/
|
|
5502
|
+
function withoutRouters(models) {
|
|
5503
|
+
return models.filter((model) => !isRouterModelId(model.id));
|
|
5504
|
+
}
|
|
5505
|
+
/**
|
|
5469
5506
|
* Apply the saved local DSH budget. A budget is an UPPER LIMIT the user sets,
|
|
5470
5507
|
* never a default: a model without an explicit budget keeps its own window, and
|
|
5471
5508
|
* a budget can only ever LOWER a window (`Math.min`), so a value above the
|
|
@@ -5762,7 +5799,7 @@ function generationOf(version) {
|
|
|
5762
5799
|
//#endregion
|
|
5763
5800
|
//#region src/version.ts
|
|
5764
5801
|
/** The npm package version this build was produced from. */
|
|
5765
|
-
const WORKBUDDY_CONNECT_VERSION = "5.0.
|
|
5802
|
+
const WORKBUDDY_CONNECT_VERSION = "5.0.1";
|
|
5766
5803
|
//#endregion
|
|
5767
5804
|
//#region src/host-heartbeat.ts
|
|
5768
5805
|
/**
|
|
@@ -5920,4 +5957,4 @@ async function clearHostHeartbeat() {
|
|
|
5920
5957
|
await rm(workbuddyHostHeartbeatPath(), { force: true });
|
|
5921
5958
|
}
|
|
5922
5959
|
//#endregion
|
|
5923
|
-
export {
|
|
5960
|
+
export { busyDisplaySuffix as $, parseWorkBuddyAuth as A, resolveDshHome as At, isConversationIdGateBody as B, defaultDesktopAuthCandidates as C, isWorkbuddyBundle as Ct, isEncryptedCredentialError as D, readAtRestKey as Dt, hasEncryptedCredentialFields as E, openEncryptedField as Et, WorkBuddyCredentialRejectedError as F, openingEvidenceOfBody as G, isFirstMessageGateBody as H, WorkBuddyUpstreamClient as I, parseUpstreamModel as J, parseCreditMultiplier as K, classifyUpstreamError as L, workbuddyOwnAuthPath as M, writeFileAtomic as Mt, CREDENTIAL_REJECTED_CODE as N, isVaultAccountId as O, workbuddyAppExecutableCandidates as Ot, WORKBUDDY_FALLBACK_SYSTEM_PROMPT as P, attachBusyLevels as Q, declaredTools as R, authFileName as S, isEncryptedFieldWrapper as St, defaultDesktopAuthPath as T, macosNestedAppBundles as Tt, knownRegionOf as U, isCredentialRejectedError as V, modelIdOfBody as W, prepareChatBody as X, perturbChannelFingerprints as Y, regionOf as Z, ENCRYPTED_CREDENTIAL_CODE as _, deriveAtRestKey as _t, readHostHeartbeat as a, recordRefusal as at, WorkBuddyCredentialStore as b, findWorkbuddyAppExecutable as bt, WORKBUDDY_CONNECT_VERSION as c, WorkBuddyImageError as ct, FALLBACK_WORKBUDDY_MODELS_GLOBAL as d, queueNoticeText as dt, REFUSES_OFF_MODEL_IDS as et, WorkBuddyCatalog as f, NATIVE_MODALITY_BY_MODEL_ID as ft, withoutRouters as g, clearAtRestKeyCache as gt, fallbackModelsFor as h, WORKBUDDY_APP_EXECUTABLE_ENV as ht, processStartTimeMs as i, offRefused as it, workbuddyAccountId as j, withFileLock as jt, legacyWorkbuddyOwnAuthPath as k, hostPeersInfo as kt, piAiRuntimeInfo as l, pickImageModel as lt, deriveCatalog as m, nativeModalityOf as mt, clearHostHeartbeat as n, lastRefusalFor as nt, workbuddyHostHeartbeatPath as o, withEffectiveOff as ot, applyContextBudgets as p, imageDefaultFor as pt, parseReasoning as q, isHeartbeatProcessAlive as r, offDefaultFor as rt, writeHostHeartbeat as s, DEFAULT_IMAGE_SIZE as st, WORKBUDDY_HOST_HEARTBEAT_FILENAME as t, defaultOffModelIds as tt, FALLBACK_WORKBUDDY_MODELS as u, parseQueueAnswer as ut, WORKBUDDY_AUTH_FILENAME as v, deriveAtRestKeyId as vt, defaultDesktopAuthDirs as w, macosBundleExecutable as wt, WorkBuddyEncryptedCredentialError as x, findWorkbuddyAppExecutableWithSource as xt, WORKBUDDY_AUTH_FILE_ENV as y, fetchAtRestKeyPayload as yt, forceNeutralHead as z };
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as busyDisplaySuffix, A as parseWorkBuddyAuth, At as resolveDshHome, B as isConversationIdGateBody, C as defaultDesktopAuthCandidates, Ct as isWorkbuddyBundle, D as isEncryptedCredentialError, Dt as readAtRestKey, E as hasEncryptedCredentialFields, Et as openEncryptedField, F as WorkBuddyCredentialRejectedError, G as openingEvidenceOfBody, H as isFirstMessageGateBody, I as WorkBuddyUpstreamClient, J as parseUpstreamModel, K as parseCreditMultiplier, L as classifyUpstreamError, M as workbuddyOwnAuthPath, Mt as writeFileAtomic, N as CREDENTIAL_REJECTED_CODE, O as isVaultAccountId, Ot as workbuddyAppExecutableCandidates, P as WORKBUDDY_FALLBACK_SYSTEM_PROMPT, Q as attachBusyLevels, R as declaredTools, S as authFileName, St as isEncryptedFieldWrapper, T as defaultDesktopAuthPath, Tt as macosNestedAppBundles, U as knownRegionOf, V as isCredentialRejectedError, W as modelIdOfBody, X as prepareChatBody, Y as perturbChannelFingerprints, Z as regionOf, _ as ENCRYPTED_CREDENTIAL_CODE, _t as deriveAtRestKey, a as readHostHeartbeat, at as recordRefusal, b as WorkBuddyCredentialStore, bt as findWorkbuddyAppExecutable, c as WORKBUDDY_CONNECT_VERSION, ct as WorkBuddyImageError, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, dt as queueNoticeText, et as REFUSES_OFF_MODEL_IDS, f as WorkBuddyCatalog, ft as NATIVE_MODALITY_BY_MODEL_ID, g as withoutRouters, gt as clearAtRestKeyCache, h as fallbackModelsFor, ht as WORKBUDDY_APP_EXECUTABLE_ENV, i as processStartTimeMs, it as offRefused, j as workbuddyAccountId, jt as withFileLock, k as legacyWorkbuddyOwnAuthPath, l as piAiRuntimeInfo, lt as pickImageModel, m as deriveCatalog, mt as nativeModalityOf, n as clearHostHeartbeat, nt as lastRefusalFor, o as workbuddyHostHeartbeatPath, ot as withEffectiveOff, p as applyContextBudgets, pt as imageDefaultFor, q as parseReasoning, r as isHeartbeatProcessAlive, rt as offDefaultFor, s as writeHostHeartbeat, st as DEFAULT_IMAGE_SIZE, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, tt as defaultOffModelIds, u as FALLBACK_WORKBUDDY_MODELS, ut as parseQueueAnswer, v as WORKBUDDY_AUTH_FILENAME, vt as deriveAtRestKeyId, w as defaultDesktopAuthDirs, wt as macosBundleExecutable, x as WorkBuddyEncryptedCredentialError, y as WORKBUDDY_AUTH_FILE_ENV, yt as fetchAtRestKeyPayload, z as forceNeutralHead } from "./host-heartbeat-DtMzOwZr.js";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
4
4
|
import { randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
@@ -673,7 +673,10 @@ const NO_REASONING_EFFORTS = { efforts: [{
|
|
|
673
673
|
* catalog has six of them (`default`, `glm-5.0`, `glm-4.7`, `glm-4.6`,
|
|
674
674
|
* `hunyuan-chat`, `hunyuan-image-alpha`), the live global one two
|
|
675
675
|
* (`default-model`, `deep-model`), and EVERY entry of both static fallback lists
|
|
676
|
-
* — the inherited `high` is not a tier that model has. `
|
|
676
|
+
* — the inherited `high` is not a tier that model has. (`default-model` is the
|
|
677
|
+
* international `auto` router and is not offered as a row since 5.0.1; the
|
|
678
|
+
* measurement is kept verbatim because the defect it documents was observed
|
|
679
|
+
* against the full roster.) `resolveReasoningLevel`
|
|
677
680
|
* then throws `UNSUPPORTED_REASONING_EFFORT` before the request is even built,
|
|
678
681
|
* so the model is unusable locally: no wire call, no upstream error, nothing to
|
|
679
682
|
* retry. Introduced by v4.11.0, which made the profile default explicit; before
|
|
@@ -6889,7 +6892,7 @@ function apply(ctx, config) {
|
|
|
6889
6892
|
}));
|
|
6890
6893
|
const configuredModels = (value, region, liveModels = []) => {
|
|
6891
6894
|
const state = regionStateOf(value, region);
|
|
6892
|
-
const roster = state.lastCatalog?.length ? state.lastCatalog : liveModels.length ? liveModels : fallbackModelsFor(region);
|
|
6895
|
+
const roster = state.lastCatalog?.length ? withoutRouters(state.lastCatalog) : liveModels.length ? liveModels : fallbackModelsFor(region);
|
|
6893
6896
|
const declared = withImageSelection(deriveCatalog(roster, new Set(state.enabledModelIds ?? []), state.contextBudgets ?? {}), new Set(state.imageModelIds ?? []));
|
|
6894
6897
|
return withEffectiveOff(declared, new Set(savedOffModelIds(state, declared))).map((model) => model.reasoning === void 0 || lastRefusalFor(model.id) === void 0 ? model : {
|
|
6895
6898
|
...model,
|
|
@@ -6911,7 +6914,7 @@ function apply(ctx, config) {
|
|
|
6911
6914
|
const savedOffModelIds = (state, roster) => state.offModelIds ?? defaultOffModelIds(roster);
|
|
6912
6915
|
const displayModels = (value, region) => {
|
|
6913
6916
|
const state = regionStateOf(value, region);
|
|
6914
|
-
if (state.lastCatalog?.length) return state.lastCatalog;
|
|
6917
|
+
if (state.lastCatalog?.length) return withoutRouters(state.lastCatalog);
|
|
6915
6918
|
const live = stacks[region]?.catalog?.current();
|
|
6916
6919
|
return live?.length ? live : fallbackModelsFor(region);
|
|
6917
6920
|
};
|
package/locale/en.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
|
-
"title": "
|
|
3
|
+
"title": "dsh-connect-workbuddy",
|
|
4
4
|
"description": "Connects locally signed-in WorkBuddy models, CN and international alike, to DSH, reading each model's credit multiplier from the upstream catalog on every refresh, with per-model image input toggles, account switching backed by an auto-failing-over pool, manual daily check-in, and read-only credit overviews shown as compact pills on the card and in the composer."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/zh.json
CHANGED
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": "5.0.
|
|
5
|
+
"version": "5.0.1",
|
|
6
6
|
"author": "dingminhua",
|
|
7
7
|
"copyright": "Copyright (c) 2026 LaoDing",
|
|
8
8
|
"license": "MIT",
|