dsh-connect-workbuddy 1.0.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/CHANGELOG.md +33 -0
- package/LICENSE +21 -0
- package/README.en.md +141 -0
- package/README.md +143 -0
- package/THIRD_PARTY_NOTICES.md +57 -0
- package/cordis.patch.yml +6 -0
- package/docs/assets/dsh-connect-workbuddy-usage-card.png +0 -0
- package/lib/bin.d.ts +19 -0
- package/lib/bin.js +202 -0
- package/lib/client.js +872 -0
- package/lib/host-heartbeat-DHfQtrSf.js +1118 -0
- package/lib/index.d.ts +651 -0
- package/lib/index.js +792 -0
- package/package.json +114 -0
- package/screenshots.json +3 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 1.0.0 (2026-08-30)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- **WorkBuddy 模型接入**:将本机登录的 WorkBuddy 模型注册为 DSH 的 `workbuddy` provider,通过安全 loopback shim 提供模型调用,DSH 本地执行工具循环。
|
|
10
|
+
- **模型管理**:从上游刷新完整模型目录后可逐项勾选启用;刷新为草稿操作,需显式保存。上游同时给出积分倍率、上下文/输出上限与推理档位(实测 16 个 cli 模型全部带出这些字段,原实现仅保留 id/name/token 上限)。
|
|
11
|
+
- **图片输入手动开关**:图片支持由用户在模型列表手动勾选「图片」复选框决定(默认不勾选),不再依赖上游 `supportsImages`/`disabledMultimodal` 自动推断;勾选保存后该模型声明 image 输入,未勾选仅 text。
|
|
12
|
+
- **本机账号切换**:扫描 WorkBuddy auth 目录(活跃文件 + 时间戳备份),按 uin 去重为多个可选账号,默认跟随 App 当前登录。
|
|
13
|
+
- **凭据路径多候选**:macOS / Windows(Local+Roaming) / Linux(XDG) 逐一探测,支持环境变量与配置覆盖。
|
|
14
|
+
- **只读积分概览**:按套餐聚合展示剩余积分,区分「月度周期套餐」与「一次性礼包」;查询不消耗积分。
|
|
15
|
+
- **每日签到**:卡片下方提供一键签到按钮,查询状态与领取均走 `/plugins/dsh-connect-workbuddy/checkin`(POST),回环来源校验 + 领取前二次确认,不会重复领取。
|
|
16
|
+
- **只读路由 trio**:`/plugins/dsh-connect-workbuddy/{usage,models/refresh,accounts/refresh}`,回环来源校验 + token 脱敏,积分查询失败降级为 `creditsError`。
|
|
17
|
+
- **CLI 诊断**:`status` / `doctor` / `logout`(`--json` 支持),doctor 列出每个发现的账号及其文件来源。
|
|
18
|
+
|
|
19
|
+
### Fixes
|
|
20
|
+
|
|
21
|
+
- **凭据选择优先活跃文件**:实测所有备份文件都声称 2027 年到期,但只有 `workbuddy-desktop.info` 的 token 被上游接受。改为活跃文件优先,到期时间仅作备份间排序。
|
|
22
|
+
- **无头 profile 下不再崩溃**:`ctx.effect()` 的回调同步执行,无 `webServer` 服务时(TUI)会同步抛错。现改为先 `ctx.get('webServer')` 判空再注册。
|
|
23
|
+
- **刷新保留用户选择**:从 WorkBuddy 刷新目录后,已启用的模型、已勾选的图片与上下文预算均按模型 id 重新映射保留,不再丢失。
|
|
24
|
+
- 测试不再污染真实 `$DSH_HOME`:vitest 配置隔离 DSH_HOME,避免写心跳与凭据副本到开发者真实 profile。
|
|
25
|
+
|
|
26
|
+
### Docs
|
|
27
|
+
|
|
28
|
+
- README 与 README.en.md 顶部新增插件使用界面截图,并新增 `screenshots.json` 登记截图路径。
|
|
29
|
+
- 确立溯源与致谢规范:`THIRD_PARTY_NOTICES.md` 完整记录参考项目及其许可证;README 与 README.en.md 的致谢章节按「连接内核的参照 / 插件外观与结构的基准」两类如实标注来源。
|
|
30
|
+
- `dsh-codex-connect`(Apache-2.0)作为唯一非 MIT 参考项,其第 4 条声明义务在 `THIRD_PARTY_NOTICES.md` 中单独履行。
|
|
31
|
+
- `docs/DESIGN.md` 第 5.3 节确立源文件头标注规范:每个借鉴自参考项目的文件必须写明「参考了谁 / 参考了什么 / 改动了什么」。
|
|
32
|
+
- `RELEASING.md` 将「核对溯源与致谢」列为发布前强制步骤。
|
|
33
|
+
- 新增 `awesome-dsh-plugin-submission/` 市场注册草稿(与 `dsh-connect-trae`、`dsh-subagent-default-model` 对齐),README 补充「市场收录与展示」章节。
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LaoDing
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/dsh-connect-workbuddy-usage-card.png" width="640" alt="dsh-connect-workbuddy settings panel" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">dsh-connect-workbuddy</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center"><b>Connect locally signed-in WorkBuddy models to DeepSeek Harness, with a read-only credits overview and model management.</b></p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/dsh-connect-workbuddy"><img src="https://img.shields.io/npm/v/dsh-connect-workbuddy?style=flat-square&label=npm&color=cb3837" alt="npm version"></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/dsh-connect-workbuddy"><img src="https://img.shields.io/npm/dm/dsh-connect-workbuddy?style=flat-square&label=downloads" alt="npm downloads"></a>
|
|
12
|
+
<a href="https://github.com/dingminhua/dsh-connect-workbuddy/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/dingminhua/dsh-connect-workbuddy/ci.yml?branch=main&style=flat-square&label=tests" alt="test status"></a>
|
|
13
|
+
<a href="LICENSE"><img src="https://img.shields.io/github/license/dingminhua/dsh-connect-workbuddy?style=flat-square" alt="MIT license"></a>
|
|
14
|
+
<a href="https://github.com/dingminhua/dsh-connect-workbuddy/stargazers"><img src="https://img.shields.io/github/stars/dingminhua/dsh-connect-workbuddy?style=flat-square" alt="GitHub stars"></a>
|
|
15
|
+
<a href="https://dshfind.com/plugins/dingminhua/dsh-connect-workbuddy"><img src="https://dshfind.com/api/badge/dingminhua/dsh-connect-workbuddy" alt="dshfind plugin"></a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
[English](README.en.md) | 中文
|
|
19
|
+
|
|
20
|
+
A [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) bundle plugin that connects locally signed-in WorkBuddy CN models to the DSH model picker, with a read-only credits overview and selectable model management.
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- **WorkBuddy model provider** — registers locally signed-in WorkBuddy models as the `workbuddy` provider (e.g. `GLM-5.3`, `DeepSeek-V4-Pro`, `Kimi-K3`, `MiniMax-M3`, `Hy3`).
|
|
25
|
+
- **Model management** — refresh the full catalog from upstream and enable or disable each model individually; refresh is a draft operation that only takes effect on save. Upstream also reports credit multiplier, context/output limits, reasoning efforts, and multimodal capability.
|
|
26
|
+
- **Local account switching** — discovers the multiple sign-in credentials WorkBuddy's desktop app leaves behind and lets you switch between them. Tokens are never written to DSH settings.
|
|
27
|
+
- **Read-only credits overview** — remaining credit aggregated per package, plus each model's credit multiplier. Queries consume no credits.
|
|
28
|
+
- **Multi-candidate credential paths** — probes the platform defaults for macOS / Windows / Linux in turn, overridable by environment variable or directly in the card.
|
|
29
|
+
- **Secure loopback shim** — random port + in-process random secret; the real WorkBuddy token is never handed to pi-ai.
|
|
30
|
+
- **Command-line diagnostics** — `status` / `doctor` / `logout`, so sign-in, credits, and host health can be checked without a browser.
|
|
31
|
+
|
|
32
|
+
## How it works
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
DSH PiAiAdapter
|
|
36
|
+
-> secure loopback shim (random port + in-process random secret)
|
|
37
|
+
-> WorkBuddyUpstreamClient
|
|
38
|
+
-> https://copilot.tencent.com/v2/chat/completions
|
|
39
|
+
-> WorkBuddy SSE
|
|
40
|
+
-> DSH executes local tools and returns their results
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The model catalog comes from `/console/enterprises/personal/models` and the credits overview from `https://www.codebuddy.cn/v2/billing/meter/get-user-resource`; both are read-only.
|
|
44
|
+
|
|
45
|
+
Credentials are read (read-only) from the WorkBuddy desktop app's own auth file. Refreshed tokens are kept separately in `$DSH_HOME/.workbuddy-auth.json`; the desktop app's file is never written.
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
Prerequisite: the WorkBuddy desktop app is installed and signed in (the plugin reuses the app's sign-in state).
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
dsh plugin --profile desktop add dsh-connect-workbuddy
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or directly via npm:
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
npm install dsh-connect-workbuddy
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Restart the DSH process after install/update/uninstall.
|
|
62
|
+
|
|
63
|
+
The plugin also runs under **Web** and **TUI**; pick the command matching your profile:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
dsh plugin --profile web add dsh-connect-workbuddy # Web
|
|
67
|
+
dsh plugin --profile dsh-tui add dsh-connect-workbuddy # TUI
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Command line
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
dsh plugin --profile <web|desktop|dsh-tui> exec dsh-connect-workbuddy status # sign-in state and remaining credit
|
|
74
|
+
dsh plugin --profile <web|desktop|dsh-tui> exec dsh-connect-workbuddy doctor # credential paths and host diagnostics
|
|
75
|
+
dsh plugin --profile <web|desktop|dsh-tui> exec dsh-connect-workbuddy logout # clear the plugin-held credential copy
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`status` and `doctor` accept `--json` for machine-readable output.
|
|
79
|
+
|
|
80
|
+
## Development
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
pnpm install
|
|
84
|
+
pnpm run check # typecheck + test + build
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Local dev via a `link:` install to the desktop profile (restart DSH Desktop after editing):
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
dsh plugin --profile desktop add /Users/dmh2002/DshProject/dsh-connect-workbuddy
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Marketplace listing
|
|
94
|
+
|
|
95
|
+
The plugin ships an installable `dsh.bundle` manifest and is published to npm. Community marketplaces generally sync entries from the [Awesome DSH Plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin) registry; the submission draft lives at [`awesome-dsh-plugin-submission/dingminhua__dsh-connect-workbuddy.yml`](awesome-dsh-plugin-submission/dingminhua__dsh-connect-workbuddy.yml).
|
|
96
|
+
|
|
97
|
+
Marketplace screenshots and GitHub README badges are two separate mechanisms:
|
|
98
|
+
|
|
99
|
+
- **GitHub badges** are produced by the Shields/dshfind image links at the top of this README.
|
|
100
|
+
- **Marketplace screenshots** are controlled by the registry's `data/screenshots.json`; when unset, the marketplace falls back to extracting images from the README.
|
|
101
|
+
- **Marketplace icons/placeholders** follow each marketplace's own display rules; they are not a generic npm `package.json` field nor a README badge.
|
|
102
|
+
|
|
103
|
+
## Known limitations
|
|
104
|
+
|
|
105
|
+
- The plugin depends on WorkBuddy client endpoints (not an official public API), so a WorkBuddy update may require adjustments.
|
|
106
|
+
- **Account switching** relies on the historical auth files the WorkBuddy desktop app leaves behind (the app's own backups), not an official multi-account API. Following the app's current sign-in remains the default; switching is an explicit opt-in, and historical credentials can be invalidated by the app's cleanup or sign-out.
|
|
107
|
+
- Windows and Linux credential paths are derived from platform conventions and are not verified on real hardware; set `WORKBUDDY_AUTH_FILE` if yours lives elsewhere.
|
|
108
|
+
|
|
109
|
+
## Disclaimer
|
|
110
|
+
|
|
111
|
+
- This project is **for personal study and research only**. It drives only your own WorkBuddy account locally; do not use it commercially or beyond reasonable personal use.
|
|
112
|
+
- You must comply with WorkBuddy's terms of service. Any consequence of using this project (including account restriction, quota depletion, or service interruption) is your own responsibility.
|
|
113
|
+
- The author is not liable for any direct or indirect loss arising from the use or misuse of this project.
|
|
114
|
+
- This project is unaffiliated with and unendorsed by Tencent, WorkBuddy, or DeepSeek. Names appear solely to describe compatibility; their trademarks belong to their respective owners.
|
|
115
|
+
|
|
116
|
+
## Acknowledgements
|
|
117
|
+
|
|
118
|
+
This project builds on work others have published. Sources and licenses are credited honestly below; we hold that in genuine respect.
|
|
119
|
+
|
|
120
|
+
### Reference for the connection core
|
|
121
|
+
|
|
122
|
+
- [corrinehu/dsh-workbuddy-connect](https://github.com/corrinehu/dsh-workbuddy-connect) (MIT, Copyright (c) 2026 Corrine Hu) — **the principal reference for this project.** That project first validated a working WorkBuddy-to-DSH integration: desktop credential discovery and refresh, the upstream protocol and header conventions, loopback shim hardening, pi-ai provider assembly, and the status CLI were all studied from it. This project reimplements those proven capabilities while focusing on improving the experience.
|
|
123
|
+
- [Sliverkiss/workbuddy2api](https://github.com/Sliverkiss/workbuddy2api) (MIT) — reference implementation of the WorkBuddy upstream protocol (the `copilot.tencent.com` wire behavior), referenced via `dsh-workbuddy-connect`.
|
|
124
|
+
|
|
125
|
+
### Baseline for the plugin presentation and structure
|
|
126
|
+
|
|
127
|
+
- [dingminhua/dsh-connect-trae](https://github.com/dingminhua/dsh-connect-trae) (MIT, Copyright (c) 2026 LaoDing) — the plugin's presentation is kept consistent with it: the settings-card structure and interaction, the model-management (refresh → select → save) and account-selection model, the read-only host↔client route shape, and the npm release engineering.
|
|
128
|
+
- [dingminhua/dsh-subagent-default-model](https://github.com/dingminhua/dsh-subagent-default-model) (MIT, Copyright (c) 2026 LaoDing) — source of the `dsm-*` card style system, the `row.*` bilingual copy-key convention, and the brand icon, referenced via `dsh-connect-trae`.
|
|
129
|
+
- [franksong2702/dsh-codex-connect](https://github.com/franksong2702/dsh-codex-connect) (Apache-2.0) — reference for the DSH plugin structure and provider registration, referenced via `dsh-workbuddy-connect`. Its Apache-2.0 obligations are discharged separately in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
|
|
130
|
+
|
|
131
|
+
### Note
|
|
132
|
+
|
|
133
|
+
Copyright in each project above belongs to its respective author. This project follows a **learn-the-design, write-our-own-code** approach and does not copy any reference project's source wholesale; key modules are written independently and each file's header comment names the specific project and pattern it draws on. If you find an attribution missing or incorrect, please open an issue and we will correct it promptly.
|
|
134
|
+
|
|
135
|
+
## Third-party open-source dependencies
|
|
136
|
+
|
|
137
|
+
The open-source projects referenced here, together with their licenses and compliance notes, are recorded in full in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md). When introducing new WorkBuddy-related external dependencies or reusing code from other projects, update that file and honor the upstream licenses.
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
This project is licensed under the [MIT License](LICENSE). Copyright: **Copyright (c) 2026 LaoDing**.
|
package/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/dsh-connect-workbuddy-usage-card.png" width="640" alt="dsh-connect-workbuddy settings panel" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">dsh-connect-workbuddy</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center"><b>把本机登录的 WorkBuddy 模型接入 DeepSeek Harness,并提供只读的积分概览与模型管理。</b></p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="README.en.md">English</a> ·
|
|
11
|
+
<a href="#安装">安装</a> ·
|
|
12
|
+
<a href="#工作原理">工作原理</a> ·
|
|
13
|
+
<a href="CHANGELOG.md">更新日志</a> ·
|
|
14
|
+
<a href="https://github.com/dingminhua/dsh-connect-workbuddy/issues">问题反馈</a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<p align="center">
|
|
18
|
+
<a href="https://www.npmjs.com/package/dsh-connect-workbuddy"><img src="https://img.shields.io/npm/v/dsh-connect-workbuddy?style=flat-square&label=npm&color=cb3837" alt="npm version"></a>
|
|
19
|
+
<a href="https://www.npmjs.com/package/dsh-connect-workbuddy"><img src="https://img.shields.io/npm/dm/dsh-connect-workbuddy?style=flat-square&label=downloads" alt="npm downloads"></a>
|
|
20
|
+
<a href="https://github.com/dingminhua/dsh-connect-workbuddy/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/dingminhua/dsh-connect-workbuddy/ci.yml?branch=main&style=flat-square&label=tests" alt="test status"></a>
|
|
21
|
+
<a href="LICENSE"><img src="https://img.shields.io/github/license/dingminhua/dsh-connect-workbuddy?style=flat-square" alt="MIT license"></a>
|
|
22
|
+
<a href="https://github.com/dingminhua/dsh-connect-workbuddy/stargazers"><img src="https://img.shields.io/github/stars/dingminhua/dsh-connect-workbuddy?style=flat-square" alt="GitHub stars"></a>
|
|
23
|
+
<a href="https://dshfind.com/plugins/dingminhua/dsh-connect-workbuddy"><img src="https://dshfind.com/api/badge/dingminhua/dsh-connect-workbuddy" alt="dshfind plugin"></a>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
一个独立的 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) bundle 插件。它把本机已登录的 WorkBuddy 中国区账号接到 DSH 的模型选择器,同时提供**只读**的积分概览与可勾选的模型管理界面。
|
|
27
|
+
|
|
28
|
+
## 功能特性
|
|
29
|
+
|
|
30
|
+
- **WorkBuddy 模型接入** —— 把本机登录的 WorkBuddy 模型注册为 DSH 的 `workbuddy` provider,模型选择器出现 `GLM-5.3`、`DeepSeek-V4-Pro`、`Kimi-K3`、`MiniMax-M3`、`Hy3` 等。
|
|
31
|
+
- **模型管理** —— 从上游刷新完整模型目录,逐项勾选启用或禁用;刷新是草稿操作,点保存才生效。上游同时给出积分倍率、上下文/输出上限、推理档位与多模态能力。
|
|
32
|
+
- **本机账号切换** —— 自动发现 WorkBuddy 桌面端留下的多个登录凭据,可切换账号;Token 不写入 DSH 设置。
|
|
33
|
+
- **只读积分概览** —— 按套餐聚合展示剩余积分,并列出每个模型的积分倍率。查询不消耗积分。
|
|
34
|
+
- **凭据路径多候选** —— macOS / Windows / Linux 逐一探测默认位置,也支持环境变量与卡片内直接指定。
|
|
35
|
+
- **安全 loopback shim** —— 随机端口 + 进程内随机 secret,真实 WorkBuddy token 不交给 pi-ai。
|
|
36
|
+
- **命令行诊断** —— `status` / `doctor` / `logout`,无需浏览器即可确认登录、积分与宿主状态。
|
|
37
|
+
|
|
38
|
+
## 工作原理
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
DSH PiAiAdapter
|
|
42
|
+
-> 安全 loopback shim(随机端口 + 进程内随机 secret)
|
|
43
|
+
-> WorkBuddyUpstreamClient
|
|
44
|
+
-> https://copilot.tencent.com/v2/chat/completions
|
|
45
|
+
-> WorkBuddy SSE
|
|
46
|
+
-> DSH 本地执行工具并回传结果
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
模型目录走 `/console/enterprises/personal/models`,积分概览走 `https://www.codebuddy.cn/v2/billing/meter/get-user-resource`,两者均为只读接口。
|
|
50
|
+
|
|
51
|
+
凭据读取自 WorkBuddy 桌面 App 自身的 auth 文件(只读);刷新得到的 token 单独存放在 `$DSH_HOME/.workbuddy-auth.json`,桌面端文件永不被写入。
|
|
52
|
+
|
|
53
|
+
## 安装
|
|
54
|
+
|
|
55
|
+
前置:已安装并登录 WorkBuddy 桌面 App(插件复用 App 的登录状态)。
|
|
56
|
+
|
|
57
|
+
推荐使用 DSH 插件命令安装 npm 已发布版本:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
dsh plugin --profile desktop add dsh-connect-workbuddy
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
或直接通过 npm 安装:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
npm install dsh-connect-workbuddy
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
安装、更新或卸载 bundle 后,需要重启对应的 DSH 进程。
|
|
70
|
+
|
|
71
|
+
插件在 **Web**、**Desktop**、**TUI** 三种界面下均可运行,按你使用的 profile 选择对应命令:
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
dsh plugin --profile web add dsh-connect-workbuddy # Web
|
|
75
|
+
dsh plugin --profile dsh-tui add dsh-connect-workbuddy # TUI
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 命令行
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
dsh plugin --profile <web|desktop|dsh-tui> exec dsh-connect-workbuddy status # 登录状态与剩余积分
|
|
82
|
+
dsh plugin --profile <web|desktop|dsh-tui> exec dsh-connect-workbuddy doctor # 凭据路径与宿主诊断
|
|
83
|
+
dsh plugin --profile <web|desktop|dsh-tui> exec dsh-connect-workbuddy logout # 清理插件持有的凭据副本
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`status` 与 `doctor` 支持 `--json` 输出机器可读格式。
|
|
87
|
+
|
|
88
|
+
## 开发
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
pnpm install
|
|
92
|
+
pnpm run check # typecheck + test + build
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
本地开发用 `link:` 安装到 desktop profile(改码后重启 DSH Desktop 生效):
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
dsh plugin --profile desktop add /Users/dmh2002/DshProject/dsh-connect-workbuddy
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## 市场收录与展示
|
|
102
|
+
|
|
103
|
+
插件已包含可安装的 `dsh.bundle` manifest,并发布到 npm。社区市场通常从 [Awesome DSH Plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin) 注册表同步条目;仓库内的提交草稿位于 [`awesome-dsh-plugin-submission/dingminhua__dsh-connect-workbuddy.yml`](awesome-dsh-plugin-submission/dingminhua__dsh-connect-workbuddy.yml)。
|
|
104
|
+
|
|
105
|
+
市场卡片中的截图与 GitHub README 徽章是两套机制:
|
|
106
|
+
|
|
107
|
+
- **GitHub 徽章**由本 README 顶部的 Shields/dshfind 图片链接生成。
|
|
108
|
+
- **市场截图**由注册表 `data/screenshots.json` 控制;未配置时,市场会尝试从 README 提取图片。
|
|
109
|
+
- **市场图标/占位图**由具体市场的展示规则决定,并不是 npm `package.json` 的通用字段,也不是 README 徽章。
|
|
110
|
+
|
|
111
|
+
## 已知限制
|
|
112
|
+
|
|
113
|
+
- 依赖 WorkBuddy 客户端接口(非官方开放 API),WorkBuddy 更新后插件可能需要随之调整。
|
|
114
|
+
- **账号切换**基于 WorkBuddy 桌面端留下的历史 auth 文件(App 自身的备份产物),并非官方多账号 API。默认行为仍是跟随 App 当前登录;切换账号是显式选项,且历史凭据可能因 App 清理或退出登录而失效。
|
|
115
|
+
- Windows / Linux 的凭据默认路径为按平台约定推导,未经真机验证;必要时可通过环境变量 `WORKBUDDY_AUTH_FILE` 指定实际位置。
|
|
116
|
+
|
|
117
|
+
## 免责声明
|
|
118
|
+
|
|
119
|
+
- 本项目**仅供个人学习和研究使用**,仅驱动使用者自己的 WorkBuddy 账号在本机调用,请勿用于商业用途或超出个人合理使用的场景。
|
|
120
|
+
- 使用者需遵守 WorkBuddy 的服务条款;因使用本项目产生的任何后果(包括但不限于账号被限制、额度被清空、服务中断),由使用者自行承担。
|
|
121
|
+
- 本项目作者不对任何因使用或滥用本项目产生的直接或间接损失负责。
|
|
122
|
+
- 本项目与腾讯、WorkBuddy、DeepSeek 均无关联,未获其授权或认可;文中出现的名称仅用于描述兼容关系,其商标权利归各自所有。
|
|
123
|
+
|
|
124
|
+
## 致谢
|
|
125
|
+
|
|
126
|
+
本项目的实现建立在他人已公开的工作之上。以下内容如实标注来源与许可证,我们对此保持充分尊重:
|
|
127
|
+
|
|
128
|
+
### 连接内核的参照
|
|
129
|
+
|
|
130
|
+
- [corrinehu/dsh-workbuddy-connect](https://github.com/corrinehu/dsh-workbuddy-connect)(MIT,Copyright (c) 2026 Corrine Hu)— **本项目的主要参照**。WorkBuddy 接入 DeepSeek Harness 的完整可行方案由该项目首先验证:桌面端凭据的发现与刷新机制、上游协议与请求头约定、loopback shim 的入站加固、pi-ai provider 的装配方式、以及状态诊断 CLI,均以其为参照。本项目在保留这些已验证能力的基础上重写,着重改善使用体验。
|
|
131
|
+
- [Sliverkiss/workbuddy2api](https://github.com/Sliverkiss/workbuddy2api)(MIT)— WorkBuddy 上游协议(`copilot.tencent.com` 的 wire behavior)的参照实现,经 `dsh-workbuddy-connect` 转引。
|
|
132
|
+
|
|
133
|
+
### 说明
|
|
134
|
+
|
|
135
|
+
以上项目的版权归各自作者所有。本项目采用**借鉴设计思路 + 独立实现**的方式,未整体复制任何参考项目的源码;关键模块均为独立编写,并在源文件头部注释中标注了所参考的具体项目与模式。若你发现本项目的标注有遗漏或不当之处,请提交 issue,我们会立即更正。
|
|
136
|
+
|
|
137
|
+
## 第三方开源依赖
|
|
138
|
+
|
|
139
|
+
本项目参考的开源项目、其许可证与合规说明,完整记录见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。引入新的与 WorkBuddy 接入相关的外部依赖或复用其他项目代码时,请同步更新该文件并遵守对应许可证要求。
|
|
140
|
+
|
|
141
|
+
## 许可证
|
|
142
|
+
|
|
143
|
+
本项目采用 [MIT](LICENSE) 许可证,版权归属:**Copyright (c) 2026 LaoDing**。
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# 第三方开源声明(Third-Party Notices)
|
|
2
|
+
|
|
3
|
+
> 本文件记录本项目在设计、实现与外观上参考或借鉴的开源项目,以及各自的许可证与合规要求。
|
|
4
|
+
>
|
|
5
|
+
> 通用平台与构建依赖(`@deepseek-ai/*`、`react`、`typescript`、`tsdown`、`vitest` 等)的许可证随各自 npm 包自动携带,不属于本文档范围。
|
|
6
|
+
>
|
|
7
|
+
> 若你对本文件的完整性有疑问或发现遗漏,请提交 issue 或 PR。
|
|
8
|
+
|
|
9
|
+
## 一、项目缘起
|
|
10
|
+
|
|
11
|
+
本项目是 **WorkBuddy 接入 DeepSeek Harness(DSH)** 的重新实现,目标是在保留已验证连接能力的同时,改善使用体验。它的两个来源必须被明确承认:
|
|
12
|
+
|
|
13
|
+
| 角色 | 项目 | 提供了什么 |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| 连接内核的参照 | [`dsh-workbuddy-connect`](https://github.com/corrinehu/dsh-workbuddy-connect) | 已验证可用的 WorkBuddy 接入方案:桌面端凭据发现与刷新、上游协议、SSE 直通、loopback shim 加固、pi-ai provider 装配、状态 CLI |
|
|
16
|
+
| 插件外观的基准 | [`dsh-connect-trae`](https://github.com/dingminhua/dsh-connect-trae) | 插件卡片的结构与 CSS、模型管理与账号选择的交互模型、host↔client 路由形态、npm 发布工程 |
|
|
17
|
+
|
|
18
|
+
> `dsh-connect-trae` 的外观本身又派生自 [`dsh-subagent-default-model`](https://github.com/dingminhua/dsh-subagent-default-model)(同一作者的插件家族基准),其 `dsm-*` 卡片样式与 `row.*` 文案键约定来自那里。
|
|
19
|
+
|
|
20
|
+
## 二、参考项目清单
|
|
21
|
+
|
|
22
|
+
### 与 WorkBuddy 接入直接相关
|
|
23
|
+
|
|
24
|
+
| 项目 | 仓库 | 参考内容 | 许可证 |
|
|
25
|
+
| --- | --- | --- | --- |
|
|
26
|
+
| `dsh-workbuddy-connect` | <https://github.com/corrinehu/dsh-workbuddy-connect> | WorkBuddy 接入的完整参照:凭据发现、上游协议、shim、适配器、CLI | **MIT**(Copyright (c) 2026 Corrine Hu) |
|
|
27
|
+
| `workbuddy2api` | <https://github.com/Sliverkiss/workbuddy2api> | WorkBuddy 上游协议(`copilot.tencent.com` 的 wire behavior)的参照实现 | **MIT** |
|
|
28
|
+
|
|
29
|
+
### 与 DSH 插件结构 / 外观相关
|
|
30
|
+
|
|
31
|
+
| 项目 | 仓库 | 参考内容 | 许可证 |
|
|
32
|
+
| --- | --- | --- | --- |
|
|
33
|
+
| `dsh-connect-trae` | <https://github.com/dingminhua/dsh-connect-trae> | 插件卡片外观、模型管理与账号选择交互、路由与发布工程 | **MIT**(Copyright (c) 2026 LaoDing) |
|
|
34
|
+
| `dsh-subagent-default-model` | <https://github.com/dingminhua/dsh-subagent-default-model> | `dsm-*` 卡片 CSS、`row.*` 文案键约定、品牌图标 | **MIT**(Copyright (c) 2026 LaoDing) |
|
|
35
|
+
| `dsh-codex-connect` | <https://github.com/franksong2702/dsh-codex-connect> | DSH 插件结构与 pi-ai provider 注册的参照(经 `dsh-workbuddy-connect` 转引) | **Apache-2.0** |
|
|
36
|
+
|
|
37
|
+
## 三、Apache-2.0 特别说明
|
|
38
|
+
|
|
39
|
+
`dsh-codex-connect` 采用 **Apache License 2.0**,其义务重于 MIT。本项目对它的参考是**间接的**:经由 `dsh-workbuddy-connect` 转引其 DSH 插件结构与 provider 注册思路。即便如此,本项目仍遵守 Apache-2.0 第 4 条的要求:
|
|
40
|
+
|
|
41
|
+
- **保留声明**:在该项目条目中标注其许可证为 Apache-2.0,并注明「经 `dsh-workbuddy-connect` 转引」的事实路径。
|
|
42
|
+
- **NOTICE 文件**:`dsh-codex-connect` 未随其仓库提供独立的 `NOTICE` 文本文件;若上游后续补充,本项目将同步将其内容纳入本文件或随包的 `NOTICE`。
|
|
43
|
+
- **改动声明**:本项目**未修改** `dsh-codex-connect` 的源码;相关模块(适配器装配、插件注册)为独立实现。
|
|
44
|
+
- **专利与商标**:本项目不主张 `dsh-codex-connect` 作者的任何专利许可或商标权利。
|
|
45
|
+
|
|
46
|
+
> 附:Apache-2.0 与本项目自身的 MIT 许可证在**再分发**层面兼容(Apache-2.0 允许以 MIT 条款再分发衍生作品,前提是满足其第 4 条的声明义务)。本项目通过本文件满足该义务。
|
|
47
|
+
|
|
48
|
+
## 四、本项目的使用方式
|
|
49
|
+
|
|
50
|
+
- **借鉴设计思路 + 独立实现**:关键模块均为本项目独立编写,并在各源文件头部注释中标注所参考的具体项目与模式。
|
|
51
|
+
- **不整体复制源码**:未复制、修改或再分发上述任何参考项目的源文件。
|
|
52
|
+
- **版权声明保留**:所有参考项目的版权归各自作者所有;本项目代码不构成对它们的再分发。
|
|
53
|
+
- **后续引入依赖时**:引入任何新的 WorkBuddy 相关外部依赖、或复用其他项目代码时,必须同步更新本文件,并遵守对应许可证的署名与声明要求。
|
|
54
|
+
|
|
55
|
+
## 五、随包分发
|
|
56
|
+
|
|
57
|
+
本文件已列入 `package.json` 的 `files` 白名单,随 npm 包一同分发,确保最终用户在安装包内即可看到完整的第三方声明。README(中英双语)中的「致谢」章节与本文件互为索引。
|
package/cordis.patch.yml
ADDED
|
Binary file
|
package/lib/bin.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/bin.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Standalone status/diagnostics CLI for the dsh-connect-workbuddy bundle.
|
|
4
|
+
*
|
|
5
|
+
* 参考:corrinehu/dsh-workbuddy-connect(MIT,Copyright (c) 2026 Corrine Hu)
|
|
6
|
+
* — 三个子命令(`doctor` / `status` / `logout`)、`--json` 输出、
|
|
7
|
+
* `safeMessage` 脱敏、schemaVersion 字段、以及
|
|
8
|
+
* 「宿主心跳 + 桌面端凭据文件 + 登录态」三项联合诊断的结构,
|
|
9
|
+
* 均由该项目设计。
|
|
10
|
+
* 改动:凭据诊断由单文件扩展为「目录扫描 + 按账号分组」,
|
|
11
|
+
* doctor 会列出发现的每个账号及其文件来源,便于确认多账号是否可用;
|
|
12
|
+
* 另补 desktopAuthDir 字段。
|
|
13
|
+
*
|
|
14
|
+
* @module dsh-connect-workbuddy/bin
|
|
15
|
+
*/
|
|
16
|
+
/** Execute one boot-free command. */
|
|
17
|
+
declare function run(argv: readonly string[]): Promise<number>;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { run };
|
package/lib/bin.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { C as defaultDesktopAuthCandidates, O as workbuddyOwnAuthPath, a as readHostHeartbeat, b as WORKBUDDY_AUTH_FILE_ENV, c as WORKBUDDY_CONNECT_VERSION, g as FALLBACK_WORKBUDDY_MODELS, l as WorkBuddyUpstreamClient, o as workbuddyHostHeartbeatPath, r as isHeartbeatProcessAlive, w as defaultDesktopAuthDirs, x as WorkBuddyCredentialStore } from "./host-heartbeat-DHfQtrSf.js";
|
|
3
|
+
import { realpathSync } from "node:fs";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
//#region src/bin.ts
|
|
6
|
+
/**
|
|
7
|
+
* Standalone status/diagnostics CLI for the dsh-connect-workbuddy bundle.
|
|
8
|
+
*
|
|
9
|
+
* 参考:corrinehu/dsh-workbuddy-connect(MIT,Copyright (c) 2026 Corrine Hu)
|
|
10
|
+
* — 三个子命令(`doctor` / `status` / `logout`)、`--json` 输出、
|
|
11
|
+
* `safeMessage` 脱敏、schemaVersion 字段、以及
|
|
12
|
+
* 「宿主心跳 + 桌面端凭据文件 + 登录态」三项联合诊断的结构,
|
|
13
|
+
* 均由该项目设计。
|
|
14
|
+
* 改动:凭据诊断由单文件扩展为「目录扫描 + 按账号分组」,
|
|
15
|
+
* doctor 会列出发现的每个账号及其文件来源,便于确认多账号是否可用;
|
|
16
|
+
* 另补 desktopAuthDir 字段。
|
|
17
|
+
*
|
|
18
|
+
* @module dsh-connect-workbuddy/bin
|
|
19
|
+
*/
|
|
20
|
+
const JSON_SCHEMA_VERSION = 1;
|
|
21
|
+
/** Remove token-like strings from an unexpected diagnostic message. */
|
|
22
|
+
function safeMessage(error) {
|
|
23
|
+
return (error instanceof Error ? error.message : String(error)).replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu, "[redacted token]").replace(/(\b(?:code|token|refresh_token|access_token)=)[^&\s]+/giu, "$1[redacted]");
|
|
24
|
+
}
|
|
25
|
+
function printHelp() {
|
|
26
|
+
process.stdout.write([
|
|
27
|
+
"Usage: dsh-connect-workbuddy <doctor|status|logout> [--json]",
|
|
28
|
+
"",
|
|
29
|
+
" doctor secret-free sign-in and environment diagnostics",
|
|
30
|
+
" status sign-in state, remaining WorkBuddy credit, and host-bundle health",
|
|
31
|
+
" logout remove the plugin-owned credential copy (the desktop app keeps its sign-in)",
|
|
32
|
+
" --json emit one secret-free JSON document (doctor/status only)",
|
|
33
|
+
""
|
|
34
|
+
].join("\n"));
|
|
35
|
+
}
|
|
36
|
+
function printJson(value) {
|
|
37
|
+
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
38
|
+
}
|
|
39
|
+
function makeStore() {
|
|
40
|
+
const client = new WorkBuddyUpstreamClient();
|
|
41
|
+
return new WorkBuddyCredentialStore({ refresh: (credential) => client.refreshToken(credential) });
|
|
42
|
+
}
|
|
43
|
+
async function doctor(jsonOutput) {
|
|
44
|
+
const store = makeStore();
|
|
45
|
+
const status = await store.status();
|
|
46
|
+
const desktopPresent = await store.desktopFilePresent();
|
|
47
|
+
const heartbeat = await readHostHeartbeat();
|
|
48
|
+
const hostAlive = heartbeat !== void 0 && isHeartbeatProcessAlive(heartbeat);
|
|
49
|
+
const accounts = await store.accounts();
|
|
50
|
+
const report = {
|
|
51
|
+
schemaVersion: JSON_SCHEMA_VERSION,
|
|
52
|
+
package: "dsh-connect-workbuddy",
|
|
53
|
+
version: WORKBUDDY_CONNECT_VERSION,
|
|
54
|
+
node: process.version,
|
|
55
|
+
desktopAuthFile: {
|
|
56
|
+
path: store.desktopAuthPath() ?? "(no platform default; set WORKBUDDY_AUTH_FILE)",
|
|
57
|
+
dir: defaultDesktopAuthDirs()[0] ?? "(no platform default)",
|
|
58
|
+
candidates: defaultDesktopAuthCandidates(),
|
|
59
|
+
present: desktopPresent
|
|
60
|
+
},
|
|
61
|
+
ownAuthFile: workbuddyOwnAuthPath(),
|
|
62
|
+
hostHeartbeat: {
|
|
63
|
+
path: workbuddyHostHeartbeatPath(),
|
|
64
|
+
present: heartbeat !== void 0,
|
|
65
|
+
...heartbeat === void 0 ? {} : {
|
|
66
|
+
registeredAt: heartbeat.registeredAt,
|
|
67
|
+
pid: heartbeat.pid
|
|
68
|
+
},
|
|
69
|
+
processAlive: hostAlive
|
|
70
|
+
},
|
|
71
|
+
signIn: status.state,
|
|
72
|
+
accounts: accounts.map((account) => ({
|
|
73
|
+
id: account.id,
|
|
74
|
+
accountName: account.accountName,
|
|
75
|
+
domain: account.domain === "" ? void 0 : account.domain,
|
|
76
|
+
source: account.source,
|
|
77
|
+
selected: account.selected,
|
|
78
|
+
tokenExpiresAt: new Date(account.tokenExpiresAtMs).toISOString()
|
|
79
|
+
})),
|
|
80
|
+
fallbackModels: FALLBACK_WORKBUDDY_MODELS.length,
|
|
81
|
+
hints: [
|
|
82
|
+
...status.state === "signed-in" ? [] : ["Sign in once in the WorkBuddy desktop app, then run status again."],
|
|
83
|
+
...desktopPresent ? [] : [`No WorkBuddy desktop auth file at the expected path; set ${WORKBUDDY_AUTH_FILE_ENV} if it lives elsewhere.`],
|
|
84
|
+
...hostAlive ? [] : ["Host bundle not running in this DSH profile (or the process exited). The browser card and provider are unavailable until DSH starts the plugin."],
|
|
85
|
+
...accounts.length > 1 ? [] : ["Only one local WorkBuddy credential was found; account switching needs the app to have left backups of earlier sign-ins."]
|
|
86
|
+
]
|
|
87
|
+
};
|
|
88
|
+
if (jsonOutput) printJson(report);
|
|
89
|
+
else process.stdout.write([
|
|
90
|
+
`WorkBuddy Connect ${WORKBUDDY_CONNECT_VERSION} on ${process.version}`,
|
|
91
|
+
`Desktop auth file: ${report.desktopAuthFile.present ? "present" : "missing"} (${report.desktopAuthFile.path})`,
|
|
92
|
+
`Host bundle: ${hostAlive ? `running (pid ${heartbeat.pid})` : heartbeat !== void 0 ? "stale heartbeat (process exited)" : "not started"}`,
|
|
93
|
+
`Sign-in state: ${report.signIn}`,
|
|
94
|
+
`Local accounts: ${accounts.length}`,
|
|
95
|
+
...accounts.map((account) => ` - ${account.accountName} (${account.id})${account.selected ? " [selected]" : ""} expires ${new Date(account.tokenExpiresAtMs).toISOString()}`),
|
|
96
|
+
`Static fallback models: ${report.fallbackModels}`,
|
|
97
|
+
...report.hints.map((hint) => `Hint: ${hint}`),
|
|
98
|
+
""
|
|
99
|
+
].join("\n"));
|
|
100
|
+
return status.state === "signed-in" && desktopPresent ? 0 : 1;
|
|
101
|
+
}
|
|
102
|
+
async function status(jsonOutput) {
|
|
103
|
+
const store = makeStore();
|
|
104
|
+
const client = new WorkBuddyUpstreamClient();
|
|
105
|
+
const authStatus = await store.status();
|
|
106
|
+
const heartbeat = await readHostHeartbeat();
|
|
107
|
+
const hostAlive = heartbeat !== void 0 && isHeartbeatProcessAlive(heartbeat);
|
|
108
|
+
const hostState = hostAlive ? "running" : heartbeat !== void 0 ? "stale" : "not-started";
|
|
109
|
+
if (authStatus.state !== "signed-in") {
|
|
110
|
+
if (jsonOutput) printJson({
|
|
111
|
+
schemaVersion: JSON_SCHEMA_VERSION,
|
|
112
|
+
package: "dsh-connect-workbuddy",
|
|
113
|
+
version: WORKBUDDY_CONNECT_VERSION,
|
|
114
|
+
status: "signed-out",
|
|
115
|
+
hostBundle: hostState
|
|
116
|
+
});
|
|
117
|
+
else process.stdout.write(`WorkBuddy Connect: signed out\nHost bundle: ${hostState}\n`);
|
|
118
|
+
return 1;
|
|
119
|
+
}
|
|
120
|
+
let credits;
|
|
121
|
+
try {
|
|
122
|
+
const credential = await store.resolve();
|
|
123
|
+
credits = { total: (await client.fetchCredits(credential)).total };
|
|
124
|
+
} catch (error) {
|
|
125
|
+
credits = {
|
|
126
|
+
total: 0,
|
|
127
|
+
error: safeMessage(error)
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const accounts = await store.accounts();
|
|
131
|
+
const selected = accounts.find((account) => account.selected);
|
|
132
|
+
const expiresAt = authStatus.expiresAtMs !== void 0 ? new Date(authStatus.expiresAtMs).toISOString() : void 0;
|
|
133
|
+
if (jsonOutput) {
|
|
134
|
+
printJson({
|
|
135
|
+
schemaVersion: JSON_SCHEMA_VERSION,
|
|
136
|
+
package: "dsh-connect-workbuddy",
|
|
137
|
+
version: WORKBUDDY_CONNECT_VERSION,
|
|
138
|
+
status: "signed-in",
|
|
139
|
+
...expiresAt === void 0 ? {} : { accessTokenExpires: expiresAt },
|
|
140
|
+
...authStatus.nickname === void 0 ? {} : { nickname: authStatus.nickname },
|
|
141
|
+
...authStatus.domain === void 0 || authStatus.domain === "" ? {} : { domain: authStatus.domain },
|
|
142
|
+
source: authStatus.source,
|
|
143
|
+
...selected === void 0 ? {} : {
|
|
144
|
+
accountId: selected.id,
|
|
145
|
+
accountName: selected.accountName
|
|
146
|
+
},
|
|
147
|
+
accountCount: accounts.length,
|
|
148
|
+
credits: credits?.total,
|
|
149
|
+
...credits?.error === void 0 ? {} : { creditsError: credits.error },
|
|
150
|
+
hostBundle: hostState
|
|
151
|
+
});
|
|
152
|
+
return 0;
|
|
153
|
+
}
|
|
154
|
+
process.stdout.write([
|
|
155
|
+
`WorkBuddy Connect: signed in${authStatus.nickname === void 0 ? "" : ` as ${authStatus.nickname}`}`,
|
|
156
|
+
...expiresAt === void 0 ? [] : [`Access token expires ${expiresAt} (refresh is automatic)`],
|
|
157
|
+
`Local accounts: ${accounts.length}${selected === void 0 ? "" : ` (using ${selected.accountName})`}`,
|
|
158
|
+
credits?.error === void 0 ? `Remaining credit: ${credits?.total ?? "unknown"}` : `Remaining credit: unavailable (${credits.error})`,
|
|
159
|
+
`Host bundle: ${hostAlive ? `running (pid ${heartbeat.pid})` : hostState === "stale" ? "stale heartbeat (DSH process exited)" : "not started in this profile"}`,
|
|
160
|
+
"Client card: load failures are logged to the browser console only; the host provider is unaffected.",
|
|
161
|
+
""
|
|
162
|
+
].join("\n"));
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
/** Execute one boot-free command. */
|
|
166
|
+
async function run(argv) {
|
|
167
|
+
if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h") {
|
|
168
|
+
printHelp();
|
|
169
|
+
return 0;
|
|
170
|
+
}
|
|
171
|
+
const [rawAction, ...flags] = argv;
|
|
172
|
+
if (![
|
|
173
|
+
"doctor",
|
|
174
|
+
"logout",
|
|
175
|
+
"status"
|
|
176
|
+
].includes(rawAction)) {
|
|
177
|
+
process.stderr.write(`dsh-connect-workbuddy: expected doctor, logout, or status; got ${JSON.stringify(rawAction)}\n`);
|
|
178
|
+
return 1;
|
|
179
|
+
}
|
|
180
|
+
const action = rawAction;
|
|
181
|
+
const jsonOutput = flags.includes("--json");
|
|
182
|
+
if (flags.filter((flag) => flag !== "--json").length > 0 || jsonOutput && action === "logout") {
|
|
183
|
+
process.stderr.write(`dsh-connect-workbuddy: invalid options for ${action}: ${flags.join(" ")}\n`);
|
|
184
|
+
return 1;
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
switch (action) {
|
|
188
|
+
case "doctor": return await doctor(jsonOutput);
|
|
189
|
+
case "status": return await status(jsonOutput);
|
|
190
|
+
case "logout":
|
|
191
|
+
await makeStore().logout();
|
|
192
|
+
process.stdout.write(`WorkBuddy Connect: removed ${workbuddyOwnAuthPath()}; the desktop app's sign-in is untouched\n`);
|
|
193
|
+
return 0;
|
|
194
|
+
}
|
|
195
|
+
} catch (error) {
|
|
196
|
+
process.stderr.write(`dsh-connect-workbuddy: ${action} failed: ${safeMessage(error)}\n`);
|
|
197
|
+
return 1;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (process.argv[1] !== void 0 && fileURLToPath(import.meta.url) === realpathSync(process.argv[1])) process.exitCode = await run(process.argv.slice(2));
|
|
201
|
+
//#endregion
|
|
202
|
+
export { run };
|