dsh-workbuddy-bridge 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -54
- package/README_en.md +61 -63
- package/lib/bin.js +1 -1
- package/lib/client.js +671 -133
- package/lib/index.d.ts +175 -1
- package/lib/index.js +581 -86
- package/lib/{variants-DP0Ho0Tc.js → variants-3SmUZ0e_.js} +40 -18
- package/locale/README.md +10 -0
- package/package.json +40 -28
|
@@ -12,9 +12,8 @@ import { accessSync, constants, realpathSync, statSync } from "node:fs";
|
|
|
12
12
|
* The international desktop app's version, used as the `/v3/config` UA.
|
|
13
13
|
*
|
|
14
14
|
* The App-shaped catalog is served only to a User-Agent carrying the product
|
|
15
|
-
* name
|
|
16
|
-
*
|
|
17
|
-
* re-measured on 2026-09-11 the *space* form is rejected (HTTP 400, code
|
|
15
|
+
* name. The 2026-09-11 research recommended the space form `WorkBuddy AI/<v>`;
|
|
16
|
+
* re-measured the same day the *space* form is rejected (HTTP 400, code
|
|
18
17
|
* 12403) while the terse `WorkBuddyAI/<v>` form — with or without the space
|
|
19
18
|
* removed — returns the 21-model App document. The UA is therefore built from
|
|
20
19
|
* the form verified in code, not from the earlier prose.
|
|
@@ -150,8 +149,9 @@ function appUserAgent(version) {
|
|
|
150
149
|
//#endregion
|
|
151
150
|
//#region src/protocol/client-identity.ts
|
|
152
151
|
/**
|
|
153
|
-
* The desktop-client identity chat requests present as (phase 1 of
|
|
154
|
-
* `
|
|
152
|
+
* The desktop-client identity chat requests present as (phase 1 of the upstream
|
|
153
|
+
* identity alignment — unit-covered by `tests/client-identity.spec.ts`, and
|
|
154
|
+
* re-checked against the real upstream by `scripts/client-identity-live-matrix.mjs`).
|
|
155
155
|
*
|
|
156
156
|
* Chat and its probe sibling carry the User-Agent shape the official desktop
|
|
157
157
|
* client composes — `WorkBuddy/<v> <product>/<v> CLI/<cli>` — where the
|
|
@@ -163,7 +163,7 @@ function appUserAgent(version) {
|
|
|
163
163
|
* a missing extension).
|
|
164
164
|
*
|
|
165
165
|
* Scope: chat and probe requests ONLY. Refresh, catalog, and billing keep
|
|
166
|
-
* the headers they have always sent;
|
|
166
|
+
* the headers they have always sent; this phase holds the blast radius to
|
|
167
167
|
* one variable so the live verification matrix stays readable.
|
|
168
168
|
*
|
|
169
169
|
* @module dsh-workbuddy-bridge/client-identity
|
|
@@ -500,7 +500,7 @@ function parseJson(body) {
|
|
|
500
500
|
* The reasoning-effort probe: decide whether a model's `reasoning_effort`
|
|
501
501
|
* parameter is actually validated, and if so which canonical values it accepts.
|
|
502
502
|
*
|
|
503
|
-
*
|
|
503
|
+
* The order below is what `tests/probe.spec.ts` asserts. It matters and is
|
|
504
504
|
* not an optimization:
|
|
505
505
|
*
|
|
506
506
|
* 1. **Baseline** (no `reasoning_effort`) proves the model, credential, and
|
|
@@ -774,10 +774,10 @@ function originReferer(credential) {
|
|
|
774
774
|
/** Headers every upstream request shares. */
|
|
775
775
|
function commonHeaders(credential) {
|
|
776
776
|
return {
|
|
777
|
-
|
|
777
|
+
Accept: "application/json, text/plain, */*",
|
|
778
778
|
"X-Requested-With": "XMLHttpRequest",
|
|
779
|
-
|
|
780
|
-
|
|
779
|
+
Origin: originReferer(credential),
|
|
780
|
+
Referer: `${originReferer(credential)}/`,
|
|
781
781
|
"User-Agent": CLIENT_UA
|
|
782
782
|
};
|
|
783
783
|
}
|
|
@@ -812,8 +812,8 @@ function refreshHeaders(credential) {
|
|
|
812
812
|
/** Billing request headers. */
|
|
813
813
|
function billingHeaders(credential) {
|
|
814
814
|
const headers = {
|
|
815
|
-
|
|
816
|
-
|
|
815
|
+
Authorization: `Bearer ${credential.accessToken}`,
|
|
816
|
+
Accept: "application/json",
|
|
817
817
|
"Content-Type": "application/json"
|
|
818
818
|
};
|
|
819
819
|
if (credential.uid !== "") headers["X-User-Id"] = credential.uid;
|
|
@@ -952,7 +952,7 @@ var WorkBuddyUpstreamClient = class {
|
|
|
952
952
|
method: "POST",
|
|
953
953
|
headers: {
|
|
954
954
|
...chatHeaders(credential, userAgent),
|
|
955
|
-
|
|
955
|
+
Authorization: `Bearer ${credential.accessToken}`
|
|
956
956
|
},
|
|
957
957
|
body: region === "global" ? prepareInternationalChatBody(bodyJson) : bodyJson,
|
|
958
958
|
...signal === void 0 ? {} : { signal }
|
|
@@ -1288,7 +1288,7 @@ var WorkBuddyUpstreamClient = class {
|
|
|
1288
1288
|
method: "POST",
|
|
1289
1289
|
headers: {
|
|
1290
1290
|
...chatHeaders(credential, userAgent),
|
|
1291
|
-
|
|
1291
|
+
Authorization: `Bearer ${credential.accessToken}`
|
|
1292
1292
|
},
|
|
1293
1293
|
body: JSON.stringify(payload),
|
|
1294
1294
|
signal
|
|
@@ -2663,7 +2663,7 @@ var WorkBuddyCredentialStore = class {
|
|
|
2663
2663
|
return refreshed;
|
|
2664
2664
|
} catch (error) {
|
|
2665
2665
|
if (credential.expiresAtMs > Date.now() + 3e4) return credential;
|
|
2666
|
-
throw new Error(`workbuddy: token refresh failed and the access token is expired (${String(error)}); open the WorkBuddy desktop app once to sign in again
|
|
2666
|
+
throw new Error(`workbuddy: token refresh failed and the access token is expired (${String(error)}); open the WorkBuddy desktop app once to sign in again`, { cause: error });
|
|
2667
2667
|
}
|
|
2668
2668
|
}
|
|
2669
2669
|
async saveOwn(credential) {
|
|
@@ -3563,7 +3563,7 @@ const WORKBUDDY_STATUS_PATH = "/plugins/dsh-workbuddy-bridge/status";
|
|
|
3563
3563
|
* Separate from the status route because it accepts writes: the status route's
|
|
3564
3564
|
* loopback Host/Origin guard protects against a DNS-rebinding *page*, which is
|
|
3565
3565
|
* not the same as authorizing a state-changing action. This route therefore
|
|
3566
|
-
* also requires the in-
|
|
3566
|
+
* also requires the in-memory key the browser half receives with the status
|
|
3567
3567
|
* document.
|
|
3568
3568
|
*/
|
|
3569
3569
|
const WORKBUDDY_PROBE_PATH = "/plugins/dsh-workbuddy-bridge/probe";
|
|
@@ -3577,9 +3577,31 @@ const WORKBUDDY_PROBE_PATH = "/plugins/dsh-workbuddy-bridge/probe";
|
|
|
3577
3577
|
*/
|
|
3578
3578
|
const WORKBUDDY_AI_STATUS_PATH = "/plugins/dsh-workbuddy-bridge/ai/status";
|
|
3579
3579
|
const WORKBUDDY_AI_PROBE_PATH = "/plugins/dsh-workbuddy-bridge/ai/probe";
|
|
3580
|
+
/**
|
|
3581
|
+
* Plugin-owned per-message credit route.
|
|
3582
|
+
*
|
|
3583
|
+
* A read-only GET taking `?sessionId=…`, answering `messageId → credit` for one
|
|
3584
|
+
* Session. It is its own route rather than a field of the status document
|
|
3585
|
+
* because the two have different lifetimes: the status document is per
|
|
3586
|
+
* *account* and is re-read when the account changes, while credit accounting
|
|
3587
|
+
* is per *Session* and grows as messages are sent.
|
|
3588
|
+
*
|
|
3589
|
+
* **One route for both variants, on purpose.** The accounting is attributed to
|
|
3590
|
+
* a DSH `messageId` before it is stored, and a message id belongs to one
|
|
3591
|
+
* Session regardless of which provider served it — a conversation can switch
|
|
3592
|
+
* between the two WorkBuddy products (or away from both) mid-thread. A route
|
|
3593
|
+
* per variant would force the message row to know which provider answered a
|
|
3594
|
+
* message *it is merely labelling*, and would strand every message whose turn
|
|
3595
|
+
* ran under the other variant.
|
|
3596
|
+
*
|
|
3597
|
+
* No key is required: the route only reads what this plugin already observed on
|
|
3598
|
+
* its own loopback stream, carries no credential material, and answers loopback
|
|
3599
|
+
* requests through the same Host/Origin guard as the status route.
|
|
3600
|
+
*/
|
|
3601
|
+
const WORKBUDDY_CREDIT_PATH = "/plugins/dsh-workbuddy-bridge/credit";
|
|
3580
3602
|
//#endregion
|
|
3581
3603
|
//#region src/version.ts
|
|
3582
|
-
const WORKBUDDY_BRIDGE_VERSION = "0.
|
|
3604
|
+
const WORKBUDDY_BRIDGE_VERSION = "0.3.0";
|
|
3583
3605
|
//#endregion
|
|
3584
3606
|
//#region src/web/heartbeat.ts
|
|
3585
3607
|
/**
|
|
@@ -3804,4 +3826,4 @@ function variantFor(id) {
|
|
|
3804
3826
|
return WORKBUDDY_VARIANTS.find((variant) => variant.id === id);
|
|
3805
3827
|
}
|
|
3806
3828
|
//#endregion
|
|
3807
|
-
export {
|
|
3829
|
+
export { modelWithCurrentPromotion as A, CN_APP_VERSION_FILENAME as B, defaultDesktopAuthPath as C, WorkBuddyAtRestKeyProvider as D, workbuddyOwnAuthPath as E, regionOf as F, resolveChatIdentity as G, chatUserAgent as H, PROBE_EFFORT_CANDIDATES as I, appUserAgent as J, validCliVersion as K, probeModel as L, parseModelCatalog as M, prepareChatBody as N, cnAppDiscovery as O, prepareInternationalChatBody as P, validAppVersion as Q, randomSentinel as R, defaultDesktopAuthCandidates as S, parseWorkBuddyAuth as T, fallbackChatIdentity as U, FALLBACK_CN_APP_VERSION as V, readCliVersion as W, readBundleVersion as X, installedAppVersion as Y, resolveAppVersion as Z, FALLBACK_WORKBUDDY_MODELS as _, WORKBUDDY_HOST_HEARTBEAT_FILENAME as a, WORKBUDDY_AUTH_FILE_ENV as b, processStartTimeMs as c, writeHostHeartbeat as d, WORKBUDDY_BRIDGE_VERSION as f, FALLBACK_WORKBUDDY_AI_MODELS as g, WORKBUDDY_STATUS_PATH as h, variantFor as i, normalizeCredits as j, WorkBuddyUpstreamClient as k, readHostHeartbeat as l, WORKBUDDY_PROBE_PATH as m, CN_VARIANT as n, clearHostHeartbeat as o, WORKBUDDY_CREDIT_PATH as p, WORKBUDDY_APP_VERSION_FILENAME as q, WORKBUDDY_VARIANTS as r, isHeartbeatProcessAlive as s, AI_VARIANT as t, workbuddyHostHeartbeatPath as u, WorkBuddyCatalog as v, desktopAuthCandidatesFor as w, WorkBuddyCredentialStore as x, WORKBUDDY_AUTH_FILENAME as y, classifyUpstreamError as z };
|
package/locale/README.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# locale/ — 包展示元数据
|
|
2
|
+
|
|
3
|
+
- 职责:宿主直读的**包展示元数据**(插件页上的标题与一句话说明)。
|
|
4
|
+
不是插件界面文案 —— 那在 [../src/client/locales.ts](../src/client/locales.ts),运行时经 `ctx.locale` 注册。
|
|
5
|
+
- `en.json`:`meta.title` + `meta.description` 的英文。宿主先解析这一份,它不在就不会读其他语言文件。
|
|
6
|
+
- `zh.json`:同一键集的中文。
|
|
7
|
+
- 生效条件:随包发布(`package.json` 的 `files` 收了 `locale/*.json`),宿主从 `<包名>/locale/<语言>.json` 读;
|
|
8
|
+
不进 `lib/`,本仓代码一个字节都不读它。
|
|
9
|
+
- 被谁依赖:宿主插件页;发布面断言在 [../scripts/check-release.mjs](../scripts/check-release.mjs)。
|
|
10
|
+
- 回落链、字段形状、改动波及面(规则层)→ 见 [AGENTS.md](AGENTS.md)
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dsh-workbuddy-bridge",
|
|
3
3
|
"displayName": "DSH WorkBuddy Bridge",
|
|
4
4
|
"description": "将 WorkBuddy 桌面 App 包含的模型自动接入 DeepSeek Harness — bring WorkBuddy desktop app models into DeepSeek Harness with zero configuration.",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.3.0",
|
|
6
6
|
"author": "zlZayn",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"dsh",
|
|
@@ -20,17 +20,16 @@
|
|
|
20
20
|
},
|
|
21
21
|
"icon": "./icon.svg",
|
|
22
22
|
"main": "lib/index.js",
|
|
23
|
-
"types": "lib/
|
|
23
|
+
"types": "./lib/index.d.ts",
|
|
24
24
|
"bin": {
|
|
25
25
|
"dsh-workbuddy-bridge": "lib/bin.js"
|
|
26
26
|
},
|
|
27
27
|
"exports": {
|
|
28
28
|
".": {
|
|
29
|
-
"types": "./lib/
|
|
29
|
+
"types": "./lib/index.d.ts",
|
|
30
30
|
"default": "./lib/index.js"
|
|
31
31
|
},
|
|
32
32
|
"./client": {
|
|
33
|
-
"types": "./lib/types/client/index.d.ts",
|
|
34
33
|
"default": "./lib/client.js"
|
|
35
34
|
},
|
|
36
35
|
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
@@ -68,7 +67,8 @@
|
|
|
68
67
|
"@deepseek-ai/dsh-client-ui-renderer",
|
|
69
68
|
"@deepseek-ai/dsh-client-ui-settings",
|
|
70
69
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
71
|
-
"@deepseek-ai/dsh-client-ui-model-selection"
|
|
70
|
+
"@deepseek-ai/dsh-client-ui-model-selection",
|
|
71
|
+
"@deepseek-ai/dsh-client-ui-chat"
|
|
72
72
|
],
|
|
73
73
|
"platform": "web"
|
|
74
74
|
}
|
|
@@ -80,6 +80,7 @@
|
|
|
80
80
|
"@deepseek-ai/dsh-attachment": ">=0.1.7-rc.2",
|
|
81
81
|
"@deepseek-ai/dsh-client-locale": ">=0.1.7-rc.2",
|
|
82
82
|
"@deepseek-ai/dsh-client-store": ">=0.1.7-rc.2",
|
|
83
|
+
"@deepseek-ai/dsh-client-ui-chat": ">=0.1.7-rc.2",
|
|
83
84
|
"@deepseek-ai/dsh-client-ui-plugin-manager": ">=0.1.7-rc.2",
|
|
84
85
|
"@deepseek-ai/dsh-client-ui-primitives": ">=0.1.7-rc.2",
|
|
85
86
|
"@deepseek-ai/dsh-client-ui-renderer": ">=0.1.7-rc.2",
|
|
@@ -97,36 +98,42 @@
|
|
|
97
98
|
},
|
|
98
99
|
"devDependencies": {
|
|
99
100
|
"@deepseek-ai/cordis": "4.0.4",
|
|
100
|
-
"@deepseek-ai/dsh-api-remotes": "0.
|
|
101
|
-
"@deepseek-ai/dsh-atomic-write": "0.
|
|
102
|
-
"@deepseek-ai/dsh-attachment": "0.
|
|
103
|
-
"@deepseek-ai/dsh-client-locale": "0.
|
|
104
|
-
"@deepseek-ai/dsh-client-store": "0.
|
|
105
|
-
"@deepseek-ai/dsh-client-ui-
|
|
106
|
-
"@deepseek-ai/dsh-client-ui-
|
|
107
|
-
"@deepseek-ai/dsh-client-ui-
|
|
108
|
-
"@deepseek-ai/dsh-client-ui-
|
|
109
|
-
"@deepseek-ai/dsh-client-ui-
|
|
110
|
-
"@deepseek-ai/dsh-client-ui-
|
|
111
|
-
"@deepseek-ai/dsh-client-ui-
|
|
112
|
-
"@deepseek-ai/dsh-client-ui-
|
|
113
|
-
"@deepseek-ai/dsh-
|
|
114
|
-
"@deepseek-ai/dsh-
|
|
115
|
-
"@deepseek-ai/dsh-
|
|
116
|
-
"@deepseek-ai/dsh-llm
|
|
117
|
-
"@deepseek-ai/dsh-
|
|
118
|
-
"@deepseek-ai/dsh-
|
|
119
|
-
"@deepseek-ai/dsh-util-
|
|
101
|
+
"@deepseek-ai/dsh-api-remotes": "0.2.0-rc.2",
|
|
102
|
+
"@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
|
|
103
|
+
"@deepseek-ai/dsh-attachment": "0.2.0-rc.2",
|
|
104
|
+
"@deepseek-ai/dsh-client-locale": "0.2.0-rc.2",
|
|
105
|
+
"@deepseek-ai/dsh-client-store": "0.2.0-rc.2",
|
|
106
|
+
"@deepseek-ai/dsh-client-ui-chat": "0.2.0-rc.2",
|
|
107
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.2",
|
|
108
|
+
"@deepseek-ai/dsh-client-ui-model-selection": "0.2.0-rc.2",
|
|
109
|
+
"@deepseek-ai/dsh-client-ui-plugin-manager": "0.2.0-rc.2",
|
|
110
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.2",
|
|
111
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.2",
|
|
112
|
+
"@deepseek-ai/dsh-client-ui-session": "0.2.0-rc.2",
|
|
113
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.2",
|
|
114
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.2",
|
|
115
|
+
"@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
|
|
116
|
+
"@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2",
|
|
117
|
+
"@deepseek-ai/dsh-llm": "0.2.0-rc.2",
|
|
118
|
+
"@deepseek-ai/dsh-llm-pi-ai": "0.2.0-rc.2",
|
|
119
|
+
"@deepseek-ai/dsh-settings": "0.2.0-rc.2",
|
|
120
|
+
"@deepseek-ai/dsh-util-code-language": "0.2.0-rc.2",
|
|
121
|
+
"@deepseek-ai/dsh-util-workspace-path": "0.2.0-rc.2",
|
|
120
122
|
"@deepseek-ai/schemastery": "3.18.4",
|
|
121
|
-
"@earendil-works/pi-ai": "0.
|
|
123
|
+
"@earendil-works/pi-ai": "^0.87.1",
|
|
124
|
+
"@eslint/js": "^10.0.1",
|
|
122
125
|
"@shikijs/langs": "^4.4.3",
|
|
123
126
|
"@types/node": "^22.20.0",
|
|
124
127
|
"@types/react": "~18.3.1",
|
|
125
128
|
"@types/react-dom": "^18.3.7",
|
|
126
129
|
"@types/react-test-renderer": "^18.3.1",
|
|
130
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
127
131
|
"anser": "^2.3.5",
|
|
128
132
|
"clsx": "^2.1.1",
|
|
129
133
|
"diff": "^9.0.0",
|
|
134
|
+
"eslint": "^10.11.0",
|
|
135
|
+
"eslint-config-prettier": "^10.1.8",
|
|
136
|
+
"globals": "^17.12.0",
|
|
130
137
|
"immer": "^11.1.18",
|
|
131
138
|
"katex": "^0.16.47",
|
|
132
139
|
"lightningcss": "^1.33.0",
|
|
@@ -141,6 +148,7 @@
|
|
|
141
148
|
"micromark-util-classify-character": "^2.0.1",
|
|
142
149
|
"micromark-util-sanitize-uri": "^2.0.1",
|
|
143
150
|
"micromark-util-symbol": "^2.0.1",
|
|
151
|
+
"prettier": "^3.9.9",
|
|
144
152
|
"react": "^18.2.0",
|
|
145
153
|
"react-dom": "^18.3.1",
|
|
146
154
|
"react-test-renderer": "18.3.1",
|
|
@@ -148,15 +156,19 @@
|
|
|
148
156
|
"simple-icons": "^16.32.0",
|
|
149
157
|
"tsdown": "^0.22.2",
|
|
150
158
|
"typescript": "^5.9.3",
|
|
159
|
+
"typescript-eslint": "^8.70.1",
|
|
151
160
|
"unrun": "^0.3.1",
|
|
152
|
-
"vitest": "^4.1.
|
|
161
|
+
"vitest": "^4.1.11",
|
|
153
162
|
"zustand": "^5.0.15"
|
|
154
163
|
},
|
|
155
164
|
"scripts": {
|
|
156
165
|
"build": "tsdown",
|
|
157
166
|
"test": "vitest run",
|
|
167
|
+
"lint": "eslint .",
|
|
168
|
+
"format": "prettier --write .",
|
|
169
|
+
"format:check": "prettier --check .",
|
|
158
170
|
"typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.client.json",
|
|
159
171
|
"check:release": "node scripts/check-release.mjs",
|
|
160
|
-
"check": "pnpm run typecheck && pnpm run
|
|
172
|
+
"check": "pnpm run typecheck && pnpm run build && pnpm run test"
|
|
161
173
|
}
|
|
162
174
|
}
|