dsh-vibegap 0.1.0 → 0.1.2
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 +24 -5
- package/lib/client.js +29 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,18 +3,36 @@
|
|
|
3
3
|
VibeGap 的 DeepSeek Harness 原生插件。Agent 持续运行 18 秒后,dsh web
|
|
4
4
|
右下角会出现拼写单词卡;会话完成或等待确认时,完成当前单词后自动收起或继续。
|
|
5
5
|
插件可独立运行,不要求安装 VibeGap Python 桌面端。
|
|
6
|
-
如果本机 VibeGap
|
|
7
|
-
|
|
6
|
+
如果本机 VibeGap Core 正在运行,插件会自动改用桌面端的当前词书和进度游标;
|
|
7
|
+
Core 在页面打开后才由另一个 Agent 拉起也能自动接入。连接失败或运行中断线时,
|
|
8
|
+
会回退到浏览器内的独立进度,远端游标会同步回本地作为断线续用位置。
|
|
8
9
|
|
|
9
10
|
## 安装
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
从 npm 安装:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
dsh plugin --profile web add dsh-vibegap
|
|
16
|
+
dsh web
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
也可以从发布镜像仓库
|
|
20
|
+
[`dsh-vibegap`](https://github.com/ktao732084-arch/dsh-vibegap) 安装:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
dsh plugin --profile web add "github:ktao732084-arch/dsh-vibegap#main"
|
|
24
|
+
dsh web
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
本地开发使用 link 安装:
|
|
12
28
|
|
|
13
29
|
```bash
|
|
14
30
|
dsh plugin --profile web add link:<仓库绝对路径>/vibegap/adapters/dsh/plugin
|
|
15
31
|
dsh web
|
|
16
32
|
```
|
|
17
33
|
|
|
34
|
+
> 本目录是开发主场;发布走 dsh-vibegap 镜像仓库(改动合入后同步拷贝过去打 tag)。
|
|
35
|
+
|
|
18
36
|
卸载:
|
|
19
37
|
|
|
20
38
|
```bash
|
|
@@ -25,8 +43,9 @@ dsh plugin --profile web remove dsh-vibegap
|
|
|
25
43
|
自动发音偏好通过 dsh 官方 snapshot store 保存在当前浏览器中。无痕模式或浏览器
|
|
26
44
|
拒绝持久化时,卡片仍可使用,但刷新后进度可能丢失。
|
|
27
45
|
|
|
28
|
-
本机
|
|
29
|
-
|
|
46
|
+
本机 Core 可用时,单词和进度改由 `http://127.0.0.1:8765/panel/*` 提供,
|
|
47
|
+
插件每 5 秒低频探测一次,且仅允许来自 `localhost` 或 `127.0.0.1` 的
|
|
48
|
+
HTTP(S) 浏览器 Origin。DSH 单独使用时不会因此启动 Python/Core 进程。
|
|
30
49
|
|
|
31
50
|
## 使用
|
|
32
51
|
|
package/lib/client.js
CHANGED
|
@@ -18,6 +18,7 @@ window.__ModuleLoader__.load({
|
|
|
18
18
|
var TRANSLATION_MAX_CHARS = 100;
|
|
19
19
|
var DAEMON_URL = "http://127.0.0.1:8765/panel";
|
|
20
20
|
var DAEMON_TIMEOUT_MS = 1000;
|
|
21
|
+
var DAEMON_PROBE_MS = 5000;
|
|
21
22
|
var DICT_URL = "https://raw.githubusercontent.com/RealKai42/qwerty-learner/master/public/dicts/CET6_T.json";
|
|
22
23
|
var STYLE_ID = "vg-card-styles";
|
|
23
24
|
var DONE_NOTICE = "会话已完成 · 拼完当前词后收起";
|
|
@@ -180,19 +181,39 @@ window.__ModuleLoader__.load({
|
|
|
180
181
|
if (payload.error) throw new Error(payload.error);
|
|
181
182
|
return payload;
|
|
182
183
|
}
|
|
184
|
+
function syncLocalProgress(remoteProgress) {
|
|
185
|
+
if (!remoteProgress || !Number.isFinite(Number(remoteProgress.cursor))) return;
|
|
186
|
+
progressStore.update(function (draft) {
|
|
187
|
+
if (!Array.isArray(draft.words) || draft.words.length === 0) return;
|
|
188
|
+
if (Number(remoteProgress.total) !== draft.words.length) return;
|
|
189
|
+
draft.cursor = Math.min(Math.max(Number(remoteProgress.cursor), 0), draft.words.length - 1);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
183
192
|
function useDaemonBackend() {
|
|
184
193
|
var backend = React.useState({ mode: "probing", word: null });
|
|
194
|
+
var current = useCell({ mode: "probing", word: null });
|
|
195
|
+
var setBackend = function (next) { current.current = next; backend[1](next); };
|
|
185
196
|
React.useEffect(function () {
|
|
186
197
|
var active = true;
|
|
187
|
-
|
|
198
|
+
var timer = null;
|
|
199
|
+
async function probe() {
|
|
188
200
|
try {
|
|
189
201
|
var state = await panelRequest("/state");
|
|
190
202
|
if (!state.ready) throw new Error("daemon has no wordbook");
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
203
|
+
syncLocalProgress(state.progress);
|
|
204
|
+
var cursor = state.progress && Number(state.progress.cursor);
|
|
205
|
+
var known = current.current.word && Number(current.current.word.position);
|
|
206
|
+
if (current.current.mode !== "daemon" || cursor !== known) {
|
|
207
|
+
var word = await panelRequest("/next-word");
|
|
208
|
+
if (active) setBackend({ mode: "daemon", word: word });
|
|
209
|
+
}
|
|
210
|
+
} catch (_) {
|
|
211
|
+
if (active && current.current.mode !== "local") setBackend({ mode: "local", word: null });
|
|
212
|
+
}
|
|
213
|
+
if (active) timer = setTimeout(probe, DAEMON_PROBE_MS);
|
|
214
|
+
}
|
|
215
|
+
probe();
|
|
216
|
+
return function () { active = false; if (timer) clearTimeout(timer); };
|
|
196
217
|
}, []);
|
|
197
218
|
return backend;
|
|
198
219
|
}
|
|
@@ -398,13 +419,14 @@ window.__ModuleLoader__.load({
|
|
|
398
419
|
advanceProgress(model.selection.ordered.length); return;
|
|
399
420
|
}
|
|
400
421
|
try {
|
|
401
|
-
await panelRequest("/commit", {
|
|
422
|
+
var result = await panelRequest("/commit", {
|
|
402
423
|
method: "POST", headers: { "Content-Type": "application/json" },
|
|
403
424
|
body: JSON.stringify({
|
|
404
425
|
result: model.states.peeked[0] ? "fail" : "pass",
|
|
405
426
|
typo_count: model.states.typos[0],
|
|
406
427
|
}),
|
|
407
428
|
});
|
|
429
|
+
syncLocalProgress(result);
|
|
408
430
|
var word = await panelRequest("/next-word");
|
|
409
431
|
model.backend[1]({ mode: "daemon", word: word });
|
|
410
432
|
} catch (_) { model.backend[1]({ mode: "local", word: null }); }
|