dsh-llm-workbuddy 0.1.4 → 0.1.6
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/LICENSE +21 -0
- package/README.md +34 -9
- package/lib/client.js +61 -0
- package/lib/index.js +109 -5
- package/package.json +6 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dengkun Zhang
|
|
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.md
CHANGED
|
@@ -92,33 +92,53 @@ CLI 会把依赖写进 profile 并把 `dsh-llm-workbuddy` 追加到 `dsh.profile
|
|
|
92
92
|
|
|
93
93
|
## 安装代理(先决条件,第三方)
|
|
94
94
|
|
|
95
|
-
插件只提供模型路由与登录;真正的协议转换由 **workbuddy2api
|
|
96
|
-
|
|
95
|
+
插件只提供模型路由与登录;真正的协议转换由 **workbuddy2api**(第三方开源项目)完成。
|
|
96
|
+
它**不在本插件包里**,需要单独安装并启动在 `127.0.0.1:8787`。分两种情况:
|
|
97
|
+
|
|
98
|
+
### 全新机器 / 标准安装(任何能跑 Python 的机器)
|
|
99
|
+
|
|
100
|
+
别人或你自己在**新机器**上用 npm 版插件时,按以下 3 步装代理:
|
|
97
101
|
|
|
98
102
|
```sh
|
|
99
|
-
# 1. 安装 uv(本机 Python
|
|
103
|
+
# 1. 安装 uv(本机 Python 工具,若已装可跳过)
|
|
100
104
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
101
105
|
|
|
102
106
|
# 2. 拉取 workbuddy2api 主分支源码
|
|
103
107
|
git clone https://github.com/hawklithm/workbuddy2api.git
|
|
104
108
|
cd workbuddy2api
|
|
105
109
|
|
|
106
|
-
# 3.
|
|
110
|
+
# 3. 启动代理(监听 127.0.0.1:8787;先完成下方「登录」后再真正调用模型)
|
|
107
111
|
uv run python -u -m codebuddy_proxy --desensitize \
|
|
108
112
|
--session-file ~/.codebuddy-session.json \
|
|
109
113
|
--log-file ~/.codebuddy-proxy.jsonl
|
|
110
|
-
# 监听 http://127.0.0.1:8787
|
|
111
114
|
```
|
|
112
115
|
|
|
113
|
-
>
|
|
116
|
+
> 之后任何时候想重启代理,就在 `workbuddy2api` 目录里重跑上面第 3 条命令。
|
|
117
|
+
> 若提示 `address already in use`,先停掉旧代理:
|
|
118
|
+
> `lsof -tiTCP:8787 -sTCP:LISTEN | xargs kill`,再重跑。
|
|
119
|
+
|
|
120
|
+
### 本仓库本地开发(可选快捷方式)
|
|
121
|
+
|
|
122
|
+
仓库根目录提供 `start-workbuddy.sh`,它会用仓库固定的 `main` 分支源码 + 本地
|
|
123
|
+
`.tools/uv` 工具链 + 仓库内的 `.workbuddy/session.json` 启动代理。它**不随 npm
|
|
124
|
+
包发布**,仅面向本仓库开发时方便:
|
|
114
125
|
|
|
115
|
-
|
|
126
|
+
```sh
|
|
127
|
+
cd /path/to/dsh-workbuddy
|
|
128
|
+
./start-workbuddy.sh
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 验证代理是否真的能用
|
|
116
132
|
|
|
117
133
|
```sh
|
|
118
134
|
curl http://127.0.0.1:8787/health # {"status":"ok","authenticated":true,...}
|
|
119
135
|
curl http://127.0.0.1:8787/v1/models # 模型列表(含 glm-5.2 / deepseek-v4-pro ...)
|
|
120
136
|
```
|
|
121
137
|
|
|
138
|
+
> ⚠️ `/health` 只证明**代理进程活着**,不能证明模型能真正出字(代理进程指向旧
|
|
139
|
+
> 路径/文件缺失时 `/health` 仍返回 `authenticated: true`,但所有模型请求 500)。
|
|
140
|
+
> 想确认"模型真能用",用右下角胶囊的 **🔍 诊断** 按钮,它会真实发一次模型请求。
|
|
141
|
+
|
|
122
142
|
> 登录态过期时 `authenticated` 变回 `false`,重跑登录即可,代理无需重启
|
|
123
143
|
> (会话按请求读取)。
|
|
124
144
|
|
|
@@ -174,6 +194,7 @@ Web 登录后终端脚本也读得到同一份会话。
|
|
|
174
194
|
|---|---|
|
|
175
195
|
| `GET /api/workbuddy/status` | 读取会话文件(默认 `~/.codebuddy-session.json`,或配置的 `sessionFile`)的 `auth.expiresAt` 判断会话是否有效,并 `fetch` 代理 `/health` 判断 `proxyUp`;返回 JSON:`{ sessionFile, authenticated, expiresAt, account, proxyUp, tokenValid, loginScriptAvailable }`;非 GET 返回 405 |
|
|
176
196
|
| `POST /api/workbuddy/login` | 若已有有效会话则直接返回 `alreadyLoggedIn`;否则用系统 `python3` `spawn` 包内 `login_workbuddy.py --session-file <sessionFile>`,从子进程 stdout 解析出 `authUrl` 立即返回 `{ authUrl, pending:true }`(设备流在后台继续,前端轮询 status 感知完成);非 POST 返回 405 |
|
|
197
|
+
| `POST /api/workbuddy/diagnose` | **一键诊断**:真实探测健康状态,返回 `{ ok, session, health, chat, loginScriptAvailable, restartCommand }`。与 `/status` 不同,它除了探 `/health`,还会**真实发一次最小模型请求**(`chat.chatWorking`),能戳穿"胶囊显示成功但模型全 500"的假象;`ok:false` 时附带 `restartCommand`(自动区分本地 monorepo 布局与标准安装);非 POST 返回 405 |
|
|
177
198
|
|
|
178
199
|
> 会话文件与登录脚本路径的解析顺序:
|
|
179
200
|
> 1. 配置里显式指定的 `sessionFile` / `loginScript`;
|
|
@@ -186,6 +207,9 @@ Web 登录后终端脚本也读得到同一份会话。
|
|
|
186
207
|
- 启动时在 `document.body` 末尾挂一个 `position:fixed` 的胶囊(右下角)。
|
|
187
208
|
- 每 **5 秒** `GET /api/workbuddy/status`;点「登录」后加快到每 **2 秒**轮询、
|
|
188
209
|
最多 30 次,直到 `authenticated:true`。
|
|
210
|
+
- 胶囊里有个 **🔍 诊断** 按钮:点它 `POST /api/workbuddy/diagnose`,弹出一个面板
|
|
211
|
+
显示**真实健康状态**(登录、会话文件、代理进程、登录令牌、模型能否出字),
|
|
212
|
+
发现问题时附带**可复制的重启命令**(一键复制到终端执行)。
|
|
189
213
|
- 状态映射:
|
|
190
214
|
- `authenticated && proxyUp` → 🟢 绿,显示 `WorkBuddy · <昵称>`
|
|
191
215
|
- 否则 → 🔴 红,显示「登录」按钮;`proxyUp` 为 false 时额外提示 `代理未运行`
|
|
@@ -262,6 +286,7 @@ DSH 的 `dsh.client` 机制只要求 `package.json` 里:
|
|
|
262
286
|
| 右下角没有胶囊 | `dsh web` 没重启加载新 bundle → 重启 `dsh web`;或 `curl /plugins/dsh-llm-workbuddy/client.js` 应返回 200 |
|
|
263
287
|
| 胶囊一直 `…`(加载中) | `GET /api/workbuddy/status` 失败 → 确认 `dsh web` 在跑、端口正确 |
|
|
264
288
|
| 胶囊红 + `代理未运行` | workbuddy2api 代理没起或挂了 → 按「安装代理」章节启动 |
|
|
289
|
+
| 胶囊显示登录成功但模型用不了 | 典型的"代理进程活着但指向旧路径/文件缺失"假象(`/health` 仍显示 ok)。点胶囊 **🔍 诊断**,看 `模型出字` 是否失败;按面板给出的重启命令重启代理 |
|
|
265
290
|
| 点「登录」没反应 / 按钮灰 | `loginScriptAvailable:false` → 包内 `login_workbuddy.py` 缺失或系统无 `python3`;检查安装 |
|
|
266
291
|
| 新标签页打开后登录完成,胶囊仍是红 | 会话文件(默认 `~/.codebuddy-session.json`)未刷新或 `expiresAt` 已过期 → 刷新页面或重跑登录 |
|
|
267
292
|
| 启动 `dsh web` 报 `EPERM ... cordis.yml` | `.dsh` 所在系统卷受保护(`/System/Volumes/Data` 带 `protect`)。解决:`sudo chown -R $(whoami) /Users/jiyunyang/.dsh`,或 `export DSH_HOME=$HOME/dsh-home` 后重新 `dsh plugin --profile web add` 并把插件链接进新 home |
|
|
@@ -284,8 +309,8 @@ DSH 的 `dsh.client` 机制只要求 `package.json` 里:
|
|
|
284
309
|
|
|
285
310
|
| 路径 | 作用 |
|
|
286
311
|
|---|---|
|
|
287
|
-
| `lib/index.js` | Cordis 插件主体:LLM 适配器 `WorkBuddyAdapter` + `/api/workbuddy/*`
|
|
288
|
-
| `lib/client.js` | 零依赖浏览器小部件(状态胶囊 +
|
|
312
|
+
| `lib/index.js` | Cordis 插件主体:LLM 适配器 `WorkBuddyAdapter` + `/api/workbuddy/*` 路由(status / login / **diagnose**) |
|
|
313
|
+
| `lib/client.js` | 零依赖浏览器小部件(状态胶囊 + 登录流程 + **🔍 诊断**),被 `dsh.client` 注入 |
|
|
289
314
|
| `login_workbuddy.py` | 设备流登录脚本(随包发布,被后端路由用系统 `python3` spawn) |
|
|
290
315
|
| `cordis.patch.yml` | 本包的 Cordis bundle 挂载声明(`id: llm-workbuddy`) |
|
|
291
316
|
| `package.json` | 包元数据、`dsh.client` 浏览器入口声明、`llm-workbuddy` peer 依赖 |
|
package/lib/client.js
CHANGED
|
@@ -105,11 +105,15 @@ function runWidget() {
|
|
|
105
105
|
html += '<button class="wb-btn" id="wb-login"' + disabled + ">" +
|
|
106
106
|
(busy ? "登录中…" : "登录") + "</button>";
|
|
107
107
|
}
|
|
108
|
+
// 诊断按钮始终显示,便于随时自查真实健康状态。
|
|
109
|
+
html += '<button class="wb-btn wb-diagnose" id="wb-diagnose" title="一键诊断">🔍</button>';
|
|
108
110
|
if (!status.proxyUp) html += '<span class="wb-warn">代理未运行</span>';
|
|
109
111
|
html += "</div>";
|
|
110
112
|
host.innerHTML = html;
|
|
111
113
|
var btn = host.querySelector("#wb-login");
|
|
112
114
|
if (btn) btn.addEventListener("click", onLogin);
|
|
115
|
+
var dg = host.querySelector("#wb-diagnose");
|
|
116
|
+
if (dg) dg.addEventListener("click", onDiagnose);
|
|
113
117
|
}
|
|
114
118
|
|
|
115
119
|
function refresh() {
|
|
@@ -151,6 +155,63 @@ function runWidget() {
|
|
|
151
155
|
});
|
|
152
156
|
}
|
|
153
157
|
|
|
158
|
+
/** 一键诊断:真实探测代理健康,必要时给出可复制的重启命令。 */
|
|
159
|
+
function onDiagnose() {
|
|
160
|
+
var panel = document.getElementById("wb-diagnose-panel");
|
|
161
|
+
if (panel) { panel.remove(); return; }
|
|
162
|
+
var el = document.createElement("div");
|
|
163
|
+
el.id = "wb-diagnose-panel";
|
|
164
|
+
el.style.cssText =
|
|
165
|
+
"position:fixed;right:12px;bottom:44px;z-index:2147483647;width:340px;max-height:340px;overflow:auto;" +
|
|
166
|
+
"background:#0f172a;color:#e2e8f0;border:1px solid #334155;border-radius:8px;" +
|
|
167
|
+
"padding:10px;font:12px/1.5 system-ui,sans-serif;box-shadow:0 6px 20px rgba(0,0,0,.5);";
|
|
168
|
+
el.innerHTML = '<div class="wb-dg-title" style="font-weight:700;margin-bottom:6px">WorkBuddy 诊断中…</div>' +
|
|
169
|
+
'<div class="wb-dg-body" style="white-space:pre-wrap;word-break:break-word;color:#94a3b8">正在探测…</div>';
|
|
170
|
+
document.body.appendChild(el);
|
|
171
|
+
|
|
172
|
+
fetch("/api/workbuddy/diagnose", { method: "POST" })
|
|
173
|
+
.then(function (r) { return r.json(); })
|
|
174
|
+
.then(function (d) {
|
|
175
|
+
if (!d) throw new Error("空响应");
|
|
176
|
+
var title = d.ok ? "✅ 一切正常" : "⚠️ 发现问题";
|
|
177
|
+
var lines = [];
|
|
178
|
+
lines.push("登录状态: " + (d.session && d.session.authenticated ? "有效" : "无效"));
|
|
179
|
+
lines.push("会话文件: " + (d.session && d.session.file ? "存在" : "缺失"));
|
|
180
|
+
lines.push("代理进程: " + (d.health && d.health.proxyUp ? "在运行" : "未运行"));
|
|
181
|
+
lines.push("登录令牌: " + (d.health && d.health.tokenValid ? "有效" : "无效"));
|
|
182
|
+
lines.push("模型出字: " + (d.chat && d.chat.chatWorking ? "正常" : "失败"));
|
|
183
|
+
if (d.chat && d.chat.chatError) lines.push("出字错误: " + d.chat.chatError);
|
|
184
|
+
var html = '<div class="wb-dg-title" style="font-weight:700;margin-bottom:6px">' + title + '</div>' +
|
|
185
|
+
'<div class="wb-dg-body" style="white-space:pre-wrap;word-break:break-word">' + lines.map(esc).join("\n") + "</div>";
|
|
186
|
+
if (!d.ok && d.restartCommand) {
|
|
187
|
+
html += '<div style="margin-top:8px;font-weight:700">重启命令(复制到终端执行):</div>' +
|
|
188
|
+
'<pre style="background:#1e293b;border-radius:6px;padding:8px;font-size:11px;overflow:auto;white-space:pre-wrap">' +
|
|
189
|
+
esc(d.restartCommand) + "</pre>" +
|
|
190
|
+
'<button class="wb-btn" id="wb-copy-cmd">复制重启命令</button>';
|
|
191
|
+
}
|
|
192
|
+
el.innerHTML = html;
|
|
193
|
+
var copy = document.getElementById("wb-copy-cmd");
|
|
194
|
+
if (copy) {
|
|
195
|
+
copy.addEventListener("click", function () {
|
|
196
|
+
navigator.clipboard.writeText(d.restartCommand).then(function () {
|
|
197
|
+
copy.textContent = "已复制 ✓";
|
|
198
|
+
setTimeout(function () { copy.textContent = "复制重启命令"; }, 1500);
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
})
|
|
203
|
+
.catch(function (err) {
|
|
204
|
+
el.innerHTML = '<div class="wb-dg-title" style="font-weight:700;color:#f87171">诊断失败</div>' +
|
|
205
|
+
'<div class="wb-dg-body">' + esc(String(err && err.message || err)) + "</div>";
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function esc(s) {
|
|
210
|
+
return String(s == null ? "" : s).replace(/[&<>"']/g, function (c) {
|
|
211
|
+
return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c];
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
154
215
|
refresh();
|
|
155
216
|
timer = setInterval(refresh, POLL_MS);
|
|
156
217
|
}
|
package/lib/index.js
CHANGED
|
@@ -762,11 +762,87 @@ async function probeProxy(baseURL) {
|
|
|
762
762
|
}
|
|
763
763
|
|
|
764
764
|
/**
|
|
765
|
-
*
|
|
766
|
-
*
|
|
767
|
-
*
|
|
768
|
-
*
|
|
769
|
-
*
|
|
765
|
+
* Probe whether the proxy can actually complete a chat completion, not just
|
|
766
|
+
* answer `/health`. `/health` reflects the proxy process alone — it stays
|
|
767
|
+
* `authenticated: true` even when the process points at a deleted/old path
|
|
768
|
+
* and every model request fails with `[Errno 2] No such file or directory`.
|
|
769
|
+
* Sending one minimal request is the only probe that catches that class of
|
|
770
|
+
* "capsule shows green but models are all down" false positive.
|
|
771
|
+
* @returns `{ chatWorking, chatError? }` where `chatWorking` is true only
|
|
772
|
+
* when the proxy returned a non-streamed completion.
|
|
773
|
+
*/
|
|
774
|
+
async function probeChatWorking(baseURL) {
|
|
775
|
+
const controller = new AbortController();
|
|
776
|
+
const timer = setTimeout(() => controller.abort(), 15000);
|
|
777
|
+
try {
|
|
778
|
+
const endpoint = `${baseURL.replace(/\/v1\/?$/, "")}/v1/chat/completions`;
|
|
779
|
+
const response = await fetch(endpoint, {
|
|
780
|
+
method: "POST",
|
|
781
|
+
headers: { "content-type": "application/json" },
|
|
782
|
+
body: JSON.stringify({
|
|
783
|
+
model: "hy3",
|
|
784
|
+
messages: [{ role: "user", content: "ping" }],
|
|
785
|
+
max_tokens: 4,
|
|
786
|
+
stream: false,
|
|
787
|
+
}),
|
|
788
|
+
signal: controller.signal,
|
|
789
|
+
});
|
|
790
|
+
if (!response.ok) {
|
|
791
|
+
const text = await response.text().catch(() => "");
|
|
792
|
+
return { chatWorking: false, chatError: `HTTP ${response.status}${text ? `: ${text.slice(0, 200)}` : ""}` };
|
|
793
|
+
}
|
|
794
|
+
const body = await response.json().catch(() => null);
|
|
795
|
+
const content = body?.choices?.[0]?.message?.content;
|
|
796
|
+
if (typeof content === "string" && content.length > 0) {
|
|
797
|
+
return { chatWorking: true };
|
|
798
|
+
}
|
|
799
|
+
return { chatWorking: false, chatError: "代理返回了空响应" };
|
|
800
|
+
} catch (error) {
|
|
801
|
+
return { chatWorking: false, chatError: String(error?.message ?? error) };
|
|
802
|
+
} finally {
|
|
803
|
+
clearTimeout(timer);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* The restart command shown by the diagnose route. It adapts to two layouts:
|
|
809
|
+
* - Local monorepo dev: the plugin sits inside a `dsh-workbuddy/` checkout with
|
|
810
|
+
* `start-workbuddy.sh` two levels up — use the workspace-local script.
|
|
811
|
+
* - Standard install (any other machine): no `start-workbuddy.sh`, so show the
|
|
812
|
+
* upstream README command for running the workbuddy2api proxy via uv.
|
|
813
|
+
*/
|
|
814
|
+
function diagnoseRestartCommand() {
|
|
815
|
+
const workspaceRoot = resolve(PLUGIN_DIR, "..", "..");
|
|
816
|
+
const localScript = resolve(workspaceRoot, "start-workbuddy.sh");
|
|
817
|
+
if (existsSync(localScript)) {
|
|
818
|
+
return [
|
|
819
|
+
"# 检测到本机 monorepo 布局(dsh-workbuddy/),用仓库脚本重启代理",
|
|
820
|
+
"# 停掉旧代理(若 8787 被占用)",
|
|
821
|
+
"lsof -tiTCP:8787 -sTCP:LISTEN | xargs kill",
|
|
822
|
+
"",
|
|
823
|
+
"# 重启代理(脚本路径自动定位到本仓库)",
|
|
824
|
+
`cd ${workspaceRoot} && ./start-workbuddy.sh`,
|
|
825
|
+
].join("\n");
|
|
826
|
+
}
|
|
827
|
+
return [
|
|
828
|
+
"# 用 workbuddy2api 代理(标准安装)重启:",
|
|
829
|
+
"# 停掉旧代理(若 8787 被占用)",
|
|
830
|
+
"lsof -tiTCP:8787 -sTCP:LISTEN | xargs kill",
|
|
831
|
+
"",
|
|
832
|
+
"# 拉取并运行代理(详见 README「安装代理」)",
|
|
833
|
+
"git clone https://github.com/hawklithm/workbuddy2api.git && cd workbuddy2api",
|
|
834
|
+
"uv run python -u -m codebuddy_proxy --desensitize \\",
|
|
835
|
+
" --session-file ~/.codebuddy-session.json --log-file ~/.codebuddy-proxy.jsonl",
|
|
836
|
+
].join("\n");
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* Register `GET /api/workbuddy/status`, `POST /api/workbuddy/login`, and
|
|
841
|
+
* `POST /api/workbuddy/diagnose` on the DSH web server. The login route spawns
|
|
842
|
+
* `login_workbuddy.py`, parses the device-flow `authUrl` it prints to stdout,
|
|
843
|
+
* and returns it so the browser can open it in a new tab. The widget then
|
|
844
|
+
* polls `/status` until the session file appears and reports
|
|
845
|
+
* `authenticated: true`.
|
|
770
846
|
*/
|
|
771
847
|
function registerWorkbuddyRoutes(ctx, config) {
|
|
772
848
|
// Delay registration until the webServer service exists. The plugin keeps
|
|
@@ -843,6 +919,34 @@ function registerWorkbuddyRoutes(ctx, config) {
|
|
|
843
919
|
res.end(JSON.stringify({ authUrl, pending: true }));
|
|
844
920
|
},
|
|
845
921
|
}));
|
|
922
|
+
webCtx.effect(() => webServer.register({
|
|
923
|
+
kind: "exact",
|
|
924
|
+
path: "/api/workbuddy/diagnose",
|
|
925
|
+
async handler(req, res) {
|
|
926
|
+
if (req.method !== "POST") {
|
|
927
|
+
res.writeHead(405, { "content-type": "application/json" });
|
|
928
|
+
res.end(JSON.stringify({ error: "method not allowed" }));
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
// Real health: probe /health AND actually complete a chat. /health
|
|
932
|
+
// alone stays green even when the proxy points at a deleted path and
|
|
933
|
+
// every model request 500s — the exact "capsule green but models dead"
|
|
934
|
+
// false positive the diagnose button exists to surface.
|
|
935
|
+
const session = readSessionStatus(sessionFile);
|
|
936
|
+
const health = await probeProxy(baseURL);
|
|
937
|
+
const chat = await probeChatWorking(baseURL);
|
|
938
|
+
const ok = Boolean(health.proxyUp && health.tokenValid && session.authenticated && chat.chatWorking);
|
|
939
|
+
res.writeHead(200, { "content-type": "application/json" });
|
|
940
|
+
res.end(JSON.stringify({
|
|
941
|
+
ok,
|
|
942
|
+
session: { file: session.sessionFile, authenticated: session.authenticated, expiresAt: session.expiresAt },
|
|
943
|
+
health,
|
|
944
|
+
chat,
|
|
945
|
+
loginScriptAvailable: existsSync(loginScript),
|
|
946
|
+
restartCommand: ok ? null : diagnoseRestartCommand(),
|
|
947
|
+
}));
|
|
948
|
+
},
|
|
949
|
+
}));
|
|
846
950
|
});
|
|
847
951
|
}
|
|
848
952
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-llm-workbuddy",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "WorkBuddy (via the local workbuddy2api proxy) LLM provider adapter for DeepSeek Harness, with a Web login-status widget",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -17,7 +17,11 @@
|
|
|
17
17
|
],
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
20
|
-
"url": ""
|
|
20
|
+
"url": "git+https://github.com/zdk119746/dsh-llm-workbuddy.git"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/zdk119746/dsh-llm-workbuddy#readme",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/zdk119746/dsh-llm-workbuddy/issues"
|
|
21
25
|
},
|
|
22
26
|
"dsh": {
|
|
23
27
|
"bundle": {
|