dsh-workbuddy-connect 0.2.3 → 0.2.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
@@ -10,6 +10,8 @@ Brings every model in the WorkBuddy desktop app (GLM-5.3, GLM-5.2, DeepSeek-V4-P
10
10
 
11
11
  ![WorkBuddy models in the DSH model picker](assets/1.png)
12
12
 
13
+ - **Image input**: image messages are admitted per the upstream's per-model capability flag — most models (GLM-5.3-Flash, GLM-5.2, the DeepSeek-V4 series, etc.) accept pasted or dragged-in images, while text-only models (e.g. GLM-5.1) keep a clear refusal.
14
+
13
15
  - **Info at a glance**: Settings → Plugins → DSH WorkBuddy Connect card
14
16
 
15
17
  ![Settings card showing the plugin](assets/2.png)
@@ -56,7 +58,7 @@ After installing, switch to a WorkBuddy model in the model picker of the interfa
56
58
 
57
59
  ## Known limitations
58
60
 
59
- - Verified on macOS with the DSH Web / Desktop / TUI profile (`0.1.1-rc.2`+, Node 22+). The default credential paths on Windows / Linux are unverified — point the `WORKBUDDY_AUTH_FILE` environment variable at the actual location if needed.
61
+ - Verified on macOS with the DSH Web / Desktop / TUI profile (`0.1.1-rc.2`+, Node 22+). 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` at the actual file.
60
62
  - Relies on WorkBuddy client interfaces (not a public API); the plugin may need updates as WorkBuddy changes.
61
63
 
62
64
  ## Disclaimer
package/README.md CHANGED
@@ -15,6 +15,9 @@
15
15
  ![WorkBuddy 模型出现在 DSH 模型选择器中](assets/1.png)
16
16
 
17
17
 
18
+ - **图片输入**:按上游逐模型声明的能力放行图片——绝大多数模型(含 GLM-5.3-Flash、GLM-5.2、DeepSeek-V4 系列等)可直接粘贴或拖入图片;个别纯文本模型(如 GLM-5.1)按上游声明仍会明确提示不支持。
19
+
20
+
18
21
  - **信息查看**:设置 → 插件 → DSH WorkBuddy Connect 卡片
19
22
 
20
23
 
@@ -62,7 +65,7 @@ dsh --profile dsh-tui
62
65
 
63
66
  ## 已知限制
64
67
 
65
- - 在 macOS 的 DSH Web / Desktop / TUI profile(`0.1.1-rc.2`+、Node 22+)下验证通过;Windows / Linux 的凭据默认路径未经验证,必要时可通过环境变量 `WORKBUDDY_AUTH_FILE` 指定实际位置。
68
+ - 在 macOS 的 DSH Web / Desktop / TUI profile(`0.1.1-rc.2`+、Node 22+)下验证通过。Windows 会依次探测 Local 与 Roaming AppData;WSL 会优先从挂载的 Windows 用户目录读取登录凭据。若 Windows 与 Linux 用户名不同且 Windows 环境变量未传入 WSL,请通过 `WORKBUDDY_AUTH_FILE` 指定实际位置。
66
69
  - 依赖 WorkBuddy 客户端接口(非官方开放 API),WorkBuddy 更新后插件可能需要随之调整。
67
70
 
68
71
  ## 免责声明
package/lib/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { _ as WorkBuddyCredentialStore, a as readHostHeartbeat, c as WORKBUDDY_CONNECT_VERSION, l as WorkBuddyUpstreamClient, o as workbuddyHostHeartbeatPath, p as FALLBACK_WORKBUDDY_MODELS, r as isHeartbeatProcessAlive, x as workbuddyOwnAuthPath } from "./host-heartbeat-C80jXKyk.js";
2
+ import { _ as WorkBuddyCredentialStore, a as readHostHeartbeat, c as WORKBUDDY_CONNECT_VERSION, l as WorkBuddyUpstreamClient, o as workbuddyHostHeartbeatPath, p as FALLBACK_WORKBUDDY_MODELS, r as isHeartbeatProcessAlive, x as workbuddyOwnAuthPath } from "./host-heartbeat-1MO2dZrM.js";
3
3
  import { realpathSync } from "node:fs";
4
4
  import { fileURLToPath } from "node:url";
5
5
  //#region src/bin.ts
@@ -1,6 +1,6 @@
1
1
  import { readFile, rm, stat, writeFile } from "node:fs/promises";
2
- import { homedir } from "node:os";
3
- import { join } from "node:path";
2
+ import { homedir, release } from "node:os";
3
+ import { basename, join } from "node:path";
4
4
  import { withFileLock, writeFileAtomic } from "@deepseek-ai/dsh-atomic-write";
5
5
  import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
6
6
  import { execFileSync } from "node:child_process";
@@ -24,17 +24,50 @@ const OWN_FORMAT_VERSION = 1;
24
24
  function workbuddyOwnAuthPath() {
25
25
  return join(resolveDshHome(), WORKBUDDY_AUTH_FILENAME);
26
26
  }
27
+ const DESKTOP_AUTH_RELATIVE_PATH = [
28
+ "CodeBuddyExtension",
29
+ "Data",
30
+ "Public",
31
+ "auth",
32
+ "workbuddy-desktop.info"
33
+ ];
34
+ /** Whether this Linux process is running inside Windows Subsystem for Linux. */
35
+ function isWsl() {
36
+ if (process.platform !== "linux") return false;
37
+ if (process.env["WSL_DISTRO_NAME"] !== void 0 || process.env["WSL_INTEROP"] !== void 0) return true;
38
+ return release().toLowerCase().includes("microsoft");
39
+ }
40
+ /** Convert a Windows drive path to WSL's conventional `/mnt/<drive>` form. */
41
+ function windowsPathForWsl(value) {
42
+ const path = value?.trim();
43
+ if (!path) return void 0;
44
+ if (path.startsWith("/")) return path;
45
+ const drivePath = /^([a-z]):[\\/](.*)$/iu.exec(path);
46
+ if (drivePath === null) return void 0;
47
+ return join("/mnt", drivePath[1].toLowerCase(), ...drivePath[2].split(/[\\/]+/u));
48
+ }
49
+ /** Windows desktop credential candidates visible from a WSL process. */
50
+ function wslDesktopAuthCandidates(home) {
51
+ const profile = windowsPathForWsl(process.env["USERPROFILE"]) ?? join("/mnt/c/Users", basename(home));
52
+ const localAppData = windowsPathForWsl(process.env["LOCALAPPDATA"]) ?? join(profile, "AppData", "Local");
53
+ const roamingAppData = windowsPathForWsl(process.env["APPDATA"]) ?? join(profile, "AppData", "Roaming");
54
+ return [join(localAppData, ...DESKTOP_AUTH_RELATIVE_PATH), join(roamingAppData, ...DESKTOP_AUTH_RELATIVE_PATH)];
55
+ }
27
56
  /**
28
57
  * Platform-default candidates for the WorkBuddy desktop app's auth file, in
29
58
  * probe order. Windows probes both AppData roots: current builds write under
30
- * `%LOCALAPPDATA%` (Local), older ones under `%APPDATA%` (Roaming). macOS and
31
- * Linux have a single well-known location.
59
+ * `%LOCALAPPDATA%` (Local), older ones under `%APPDATA%` (Roaming). WSL probes
60
+ * those same Windows locations through its mounted Windows profile before the
61
+ * native Linux location.
32
62
  */
33
63
  function defaultDesktopAuthCandidates() {
34
64
  const home = homedir();
35
65
  if (process.platform === "darwin") return [join(home, "Library", "Application Support", "CodeBuddyExtension", "Data", "Public", "auth", "workbuddy-desktop.info")];
36
66
  if (process.platform === "win32") return [join(home, "AppData", "Local", "CodeBuddyExtension", "Data", "Public", "auth", "workbuddy-desktop.info"), join(home, "AppData", "Roaming", "CodeBuddyExtension", "Data", "Public", "auth", "workbuddy-desktop.info")];
37
- if (process.platform === "linux") return [join(home, ".config", "CodeBuddyExtension", "Data", "Public", "auth", "workbuddy-desktop.info")];
67
+ if (process.platform === "linux") {
68
+ const linux = join(home, ".config", ...DESKTOP_AUTH_RELATIVE_PATH);
69
+ return isWsl() ? [...wslDesktopAuthCandidates(home), linux] : [linux];
70
+ }
38
71
  return [];
39
72
  }
40
73
  /** First platform-default candidate; see {@link defaultDesktopAuthCandidates}. */
@@ -281,76 +314,88 @@ var WorkBuddyCredentialStore = class {
281
314
  //#endregion
282
315
  //#region src/catalog.ts
283
316
  /**
284
- * Static CLI models observed on the CN endpoint (2026-08-17). The upstream
285
- * refresh replaces this list at startup; it exists so the provider registers
286
- * with a usable catalog even while the first fetch is in flight or offline.
317
+ * Static CLI models observed on the CN endpoint (2026-08-17; image flags
318
+ * re-verified against the live catalog 2026-08-29). The upstream refresh
319
+ * replaces this list at startup; it exists so the provider registers with a
320
+ * usable catalog even while the first fetch is in flight or offline.
287
321
  */
288
322
  const FALLBACK_WORKBUDDY_MODELS = [
289
323
  {
290
324
  id: "auto",
291
325
  name: "Auto",
292
326
  contextWindow: 168e3,
293
- maxTokens: 32e3
327
+ maxTokens: 32e3,
328
+ supportsImages: true
294
329
  },
295
330
  {
296
331
  id: "hy3",
297
332
  name: "Hy3",
298
333
  contextWindow: 192e3,
299
- maxTokens: 64e3
334
+ maxTokens: 64e3,
335
+ supportsImages: true
300
336
  },
301
337
  {
302
338
  id: "glm-5v-turbo",
303
339
  name: "GLM-5v-Turbo",
304
340
  contextWindow: 2e5,
305
- maxTokens: 64e3
341
+ maxTokens: 64e3,
342
+ supportsImages: true
306
343
  },
307
344
  {
308
345
  id: "glm-5.2",
309
346
  name: "GLM-5.2",
310
347
  contextWindow: 1e6,
311
- maxTokens: 48e3
348
+ maxTokens: 48e3,
349
+ supportsImages: true
312
350
  },
313
351
  {
314
352
  id: "glm-5.1",
315
353
  name: "GLM-5.1",
316
354
  contextWindow: 2e5,
317
- maxTokens: 48e3
355
+ maxTokens: 48e3,
356
+ supportsImages: false
318
357
  },
319
358
  {
320
359
  id: "minimax-m3",
321
360
  name: "MiniMax-M3",
322
361
  contextWindow: 512e3,
323
- maxTokens: 128e3
362
+ maxTokens: 128e3,
363
+ supportsImages: true
324
364
  },
325
365
  {
326
366
  id: "kimi-k3-1",
327
367
  name: "Kimi-K3",
328
368
  contextWindow: 1e6,
329
- maxTokens: 32e3
369
+ maxTokens: 32e3,
370
+ supportsImages: true
330
371
  },
331
372
  {
332
373
  id: "kimi-k2.7",
333
374
  name: "Kimi-K2.7-Code",
334
375
  contextWindow: 256e3,
335
- maxTokens: 32e3
376
+ maxTokens: 32e3,
377
+ supportsImages: true
336
378
  },
337
379
  {
338
380
  id: "kimi-k2.6",
339
381
  name: "Kimi-K2.6",
340
382
  contextWindow: 256e3,
341
- maxTokens: 32e3
383
+ maxTokens: 32e3,
384
+ supportsImages: true
342
385
  },
343
386
  {
344
387
  id: "deepseek-v4-flash",
345
388
  name: "Deepseek-V4-Flash",
346
389
  contextWindow: 1e6,
347
- maxTokens: 5e4
390
+ maxTokens: 5e4,
391
+ supportsImages: true
348
392
  },
349
393
  {
350
394
  id: "deepseek-v4-pro",
351
395
  name: "Deepseek-V4-Pro",
352
396
  contextWindow: 1e6,
353
- maxTokens: 5e4
397
+ maxTokens: 5e4,
398
+ supportsImages: true
354
399
  }
355
400
  ];
356
401
  /** Mutable catalog shared by the shim's `/v1/models` and the adapter. */
@@ -633,7 +678,8 @@ var WorkBuddyUpstreamClient = class {
633
678
  id,
634
679
  name: typeof wrapped["name"] === "string" && wrapped["name"] !== "" ? wrapped["name"] : id,
635
680
  contextWindow: input,
636
- maxTokens: output
681
+ maxTokens: output,
682
+ supportsImages: wrapped["supportsImages"] === true && wrapped["disabledMultimodal"] !== true
637
683
  });
638
684
  }
639
685
  const models = cliIds.map((id) => byId.get(id)).filter((model) => model !== void 0);
@@ -701,7 +747,7 @@ var WorkBuddyUpstreamClient = class {
701
747
  };
702
748
  //#endregion
703
749
  //#region src/version.ts
704
- const WORKBUDDY_CONNECT_VERSION = "0.2.3";
750
+ const WORKBUDDY_CONNECT_VERSION = "0.2.5";
705
751
  //#endregion
706
752
  //#region src/host-heartbeat.ts
707
753
  /**
package/lib/index.d.ts CHANGED
@@ -13,6 +13,12 @@ interface WorkBuddyUpstreamModel {
13
13
  name: string;
14
14
  contextWindow: number;
15
15
  maxTokens: number;
16
+ /**
17
+ * Upstream-declared image input capability. Missing or false upstream data
18
+ * resolves to false, so an unknown model stays text-only: over-claiming
19
+ * admits an image the provider then rejects after the message is durable.
20
+ */
21
+ supportsImages: boolean;
16
22
  }
17
23
  /** One billing package and its remaining credit. */
18
24
  interface WorkBuddyCreditAccount {
@@ -110,8 +116,9 @@ declare function workbuddyOwnAuthPath(): string;
110
116
  /**
111
117
  * Platform-default candidates for the WorkBuddy desktop app's auth file, in
112
118
  * probe order. Windows probes both AppData roots: current builds write under
113
- * `%LOCALAPPDATA%` (Local), older ones under `%APPDATA%` (Roaming). macOS and
114
- * Linux have a single well-known location.
119
+ * `%LOCALAPPDATA%` (Local), older ones under `%APPDATA%` (Roaming). WSL probes
120
+ * those same Windows locations through its mounted Windows profile before the
121
+ * native Linux location.
115
122
  */
116
123
  declare function defaultDesktopAuthCandidates(): string[];
117
124
  /** First platform-default candidate; see {@link defaultDesktopAuthCandidates}. */
@@ -183,9 +190,10 @@ declare class WorkBuddyCredentialStore {
183
190
  /** One model entry the adapter exposes. */
184
191
  type WorkBuddyModelInfo = WorkBuddyUpstreamModel;
185
192
  /**
186
- * Static CLI models observed on the CN endpoint (2026-08-17). The upstream
187
- * refresh replaces this list at startup; it exists so the provider registers
188
- * with a usable catalog even while the first fetch is in flight or offline.
193
+ * Static CLI models observed on the CN endpoint (2026-08-17; image flags
194
+ * re-verified against the live catalog 2026-08-29). The upstream refresh
195
+ * replaces this list at startup; it exists so the provider registers with a
196
+ * usable catalog even while the first fetch is in flight or offline.
189
197
  */
190
198
  declare const FALLBACK_WORKBUDDY_MODELS: readonly WorkBuddyModelInfo[];
191
199
  /** Mutable catalog shared by the shim's `/v1/models` and the adapter. */
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as WorkBuddyCredentialStore, a as readHostHeartbeat, b as parseWorkBuddyAuth, d as prepareChatBody, f as regionOf, g as WORKBUDDY_AUTH_FILE_ENV, h as WORKBUDDY_AUTH_FILENAME, i as processStartTimeMs, l as WorkBuddyUpstreamClient, m as WorkBuddyCatalog, n as clearHostHeartbeat, o as workbuddyHostHeartbeatPath, p as FALLBACK_WORKBUDDY_MODELS, r as isHeartbeatProcessAlive, s as writeHostHeartbeat, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, u as classifyUpstreamError, v as defaultDesktopAuthCandidates, x as workbuddyOwnAuthPath, y as defaultDesktopAuthPath } from "./host-heartbeat-C80jXKyk.js";
1
+ import { _ as WorkBuddyCredentialStore, a as readHostHeartbeat, b as parseWorkBuddyAuth, d as prepareChatBody, f as regionOf, g as WORKBUDDY_AUTH_FILE_ENV, h as WORKBUDDY_AUTH_FILENAME, i as processStartTimeMs, l as WorkBuddyUpstreamClient, m as WorkBuddyCatalog, n as clearHostHeartbeat, o as workbuddyHostHeartbeatPath, p as FALLBACK_WORKBUDDY_MODELS, r as isHeartbeatProcessAlive, s as writeHostHeartbeat, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, u as classifyUpstreamError, v as defaultDesktopAuthCandidates, x as workbuddyOwnAuthPath, y as defaultDesktopAuthPath } from "./host-heartbeat-1MO2dZrM.js";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
4
4
  import { createProvider } from "@earendil-works/pi-ai";
@@ -22,8 +22,8 @@ const WORKBUDDY_PROVIDER = "workbuddy";
22
22
  const WORKBUDDY_STREAM_IDLE_TIMEOUT_MS = 3e5;
23
23
  /**
24
24
  * Image-request budgets at the dsh-llm-pi-ai defaults; the profile type made
25
- * them required in 0.1.1-rc.2. WorkBuddy routes are text-only today, so these
26
- * bounds never bite unless image input is added to the catalog.
25
+ * them required in 0.1.1-rc.2. They bound requests to models whose catalog
26
+ * entry declares `supportsImages`; text-only models never receive images.
27
27
  */
28
28
  const REQUEST_IMAGE_BUDGETS = {
29
29
  maxRequestImageBytes: 20971520,
@@ -70,7 +70,7 @@ function toPiModel(info, baseUrl) {
70
70
  api: "openai-completions",
71
71
  provider: WORKBUDDY_PROVIDER,
72
72
  baseUrl,
73
- input: ["text"],
73
+ input: info.supportsImages === true ? ["text", "image"] : ["text"],
74
74
  cost: NO_COST,
75
75
  contextWindow: info.contextWindow,
76
76
  maxTokens: info.maxTokens
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.2.3",
5
+ "version": "0.2.5",
6
6
  "author": "corrinehu",
7
7
  "keywords": [
8
8
  "dsh-plugin",