dsh-prompt-predict 0.2.1 → 0.2.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/CHANGELOG.md +9 -0
- package/CHANGELOG_zh.md +8 -0
- package/README.md +27 -7
- package/README_zh.md +25 -7
- package/client/client.js +44 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,15 @@ All notable changes to this project are documented here. The format follows
|
|
|
6
6
|
|
|
7
7
|
[中文](CHANGELOG_zh.md)
|
|
8
8
|
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **The suggestion is now an in-dock row instead of a fixed overlay.** DSH `0.2.1-rc.2` stopped
|
|
12
|
+
exposing the composer draft through the slot's `useInput`, so the overlay kept showing while
|
|
13
|
+
typing; and because it was positioned from `getBoundingClientRect` it vanished whenever that
|
|
14
|
+
measurement failed. The row lives in `conversation.composer.dock` — space the host allocates —
|
|
15
|
+
and hides on the first printable keypress, which needs no draft state.
|
|
16
|
+
- Verified on DSH `0.2.1-rc.2`.
|
|
17
|
+
|
|
9
18
|
## [0.2.1] — 2026-10-17
|
|
10
19
|
|
|
11
20
|
### Fixed
|
package/CHANGELOG_zh.md
CHANGED
|
@@ -5,6 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
[English](CHANGELOG.md)
|
|
7
7
|
|
|
8
|
+
### 修复
|
|
9
|
+
|
|
10
|
+
- **建议改为在 composer dock 内的一行,不再用 fixed 覆盖层。** DSH `0.2.1-rc.2` 不再通过 slot 的
|
|
11
|
+
`useInput` 暴露草稿,覆盖层会在打字时继续显示;而它靠 `getBoundingClientRect` 定位,一旦算不出
|
|
12
|
+
坐标就整个消失。新实现放在 `conversation.composer.dock`(宿主分配好的空间),并在第一个可打印
|
|
13
|
+
按键时隐藏——不依赖草稿状态。
|
|
14
|
+
- 已在 DSH `0.2.1-rc.2` 上验证。
|
|
15
|
+
|
|
8
16
|
## [0.2.1] — 2026-10-17
|
|
9
17
|
|
|
10
18
|
### 修复
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<a href="https://www.npmjs.com/package/dsh-prompt-predict"><img alt="npm version" src="https://img.shields.io/npm/v/dsh-prompt-predict" /></a>
|
|
7
7
|
<a href="https://www.npmjs.com/package/dsh-prompt-predict"><img alt="npm downloads" src="https://img.shields.io/npm/dm/dsh-prompt-predict" /></a>
|
|
8
8
|
<a href="https://github.com/ferrisching/dsh-prompt-predict/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/ferrisching/dsh-prompt-predict" /></a>
|
|
9
|
-
<img alt="Verified on DSH 0.2.
|
|
9
|
+
<img alt="Verified on DSH 0.2.1-rc.2" src="https://img.shields.io/badge/DSH-0.2.1--rc.2-4d6bfe" />
|
|
10
10
|
<img alt="Zero runtime dependencies" src="https://img.shields.io/badge/dependencies-zero%20runtime-41ba41" />
|
|
11
11
|
<img alt="Host + client plugin" src="https://img.shields.io/badge/shape-host%20%2B%20client-8250df" />
|
|
12
12
|
<a href="./LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-yellow.svg" /></a>
|
|
@@ -54,15 +54,35 @@ The plugin is published on npm. Options are ordered by convenience.
|
|
|
54
54
|
|
|
55
55
|
**GUI**: open the plugins page → **Add plugin** → enter the package name `dsh-prompt-predict` → install.
|
|
56
56
|
|
|
57
|
-
**Or the dsh CLI
|
|
57
|
+
**Or the dsh CLI** — pin any published version with pnpm's `@version` syntax:
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
dsh plugin --profile desktop add dsh-prompt-predict
|
|
60
|
+
dsh plugin --profile desktop add dsh-prompt-predict@0.2.1
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
Replace `--profile` with your own profile (usually `desktop` on the desktop app, `web` for the web build)
|
|
63
|
+
Replace `--profile` with your own profile (usually `desktop` on the desktop app, `web` for the web build), then **restart DSH**.
|
|
64
64
|
|
|
65
|
-
>
|
|
65
|
+
> ⚠️ **The CLI only installs the package.** DSH loads a plugin only when it is also listed in
|
|
66
|
+
> `dsh.profile.bundles` inside `~/.dsh/profiles/<profile>/package.json`. Verified: with the package
|
|
67
|
+
> installed but not in that list, the plugin's routes answer `404` and nothing loads. The GUI route
|
|
68
|
+
> above handles it for you; with the CLI add `"dsh-prompt-predict"` to that array yourself, or just
|
|
69
|
+
> run `scripts/install.sh` below, which does both steps.
|
|
70
|
+
|
|
71
|
+
> You'll find the switch and all parameters under **Settings → Prompt Suggestions**.
|
|
72
|
+
|
|
73
|
+
### Install from a release tarball
|
|
74
|
+
|
|
75
|
+
Every [release](https://github.com/ferrisching/dsh-prompt-predict/releases) carries the exact
|
|
76
|
+
tarball that is on npm (`shasum` matches the registry), which is handy for offline machines or for
|
|
77
|
+
pinning an artifact you can verify:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
gh release download v0.2.1 --repo ferrisching/dsh-prompt-predict --pattern '*.tgz'
|
|
81
|
+
dsh plugin --profile desktop add ./dsh-prompt-predict-0.2.1.tgz
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Same caveat as the CLI route above: add `"dsh-prompt-predict"` to `dsh.profile.bundles` yourself,
|
|
85
|
+
or run `scripts/install.sh` instead.
|
|
66
86
|
|
|
67
87
|
### Install from source
|
|
68
88
|
|
|
@@ -93,7 +113,7 @@ Then open that profile's `package.json` and add `"dsh-prompt-predict"` to the `d
|
|
|
93
113
|
|
|
94
114
|
### Requirements
|
|
95
115
|
|
|
96
|
-
- Verified on **DSH `0.2.
|
|
116
|
+
- Verified on **DSH `0.2.1-rc.2`** (web build; the desktop app runs the same host and client code)
|
|
97
117
|
- `node` / `pnpm`: the install script prefers DSH's own runtime under `~/.dsh/dsh-runtimes/*/dependencies` and only falls back to `PATH`
|
|
98
118
|
- macOS / Linux; Windows untested
|
|
99
119
|
|
|
@@ -203,7 +223,7 @@ The tests need no DSH runtime: a fake ctx plus a local HTTP server cover route r
|
|
|
203
223
|
|
|
204
224
|
## ⚠️ Known limitations
|
|
205
225
|
|
|
206
|
-
- Verified only on DSH `0.2.
|
|
226
|
+
- Verified only on DSH `0.2.1-rc.2`; other versions untested
|
|
207
227
|
- Depends on the host's `conversation.composer.dock` and `settings.section` slot names — a major DSH update may require adapting
|
|
208
228
|
- Predictions consume quota on the selected model; pinning a fast small model is cheaper than following a reasoning model
|
|
209
229
|
|
package/README_zh.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<a href="https://www.npmjs.com/package/dsh-prompt-predict"><img alt="npm version" src="https://img.shields.io/npm/v/dsh-prompt-predict" /></a>
|
|
7
7
|
<a href="https://www.npmjs.com/package/dsh-prompt-predict"><img alt="npm downloads" src="https://img.shields.io/npm/dm/dsh-prompt-predict" /></a>
|
|
8
8
|
<a href="https://github.com/ferrisching/dsh-prompt-predict/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/ferrisching/dsh-prompt-predict" /></a>
|
|
9
|
-
<img alt="已验证 DSH 0.2.
|
|
9
|
+
<img alt="已验证 DSH 0.2.1-rc.2" src="https://img.shields.io/badge/DSH-0.2.1--rc.2-4d6bfe" />
|
|
10
10
|
<img alt="零运行时依赖" src="https://img.shields.io/badge/%E4%BE%9D%E8%B5%96-%E9%9B%B6%E8%BF%90%E8%A1%8C%E6%97%B6%E4%BE%9D%E8%B5%96-41ba41" />
|
|
11
11
|
<img alt="客户端 + Host 双端插件" src="https://img.shields.io/badge/%E5%BD%A2%E6%80%81-Host%20%2B%20%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%8F%92%E4%BB%B6-8250df" />
|
|
12
12
|
<a href="./LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-yellow.svg" /></a>
|
|
@@ -54,15 +54,33 @@
|
|
|
54
54
|
|
|
55
55
|
**图形界面**:打开插件页 →「添加插件」→ 填入包名 `dsh-prompt-predict` → 安装。
|
|
56
56
|
|
|
57
|
-
**或者用 dsh CLI
|
|
57
|
+
**或者用 dsh CLI**——想装某个已发布版本就用 pnpm 的 `@版本` 语法:
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
dsh plugin --profile desktop add dsh-prompt-predict
|
|
60
|
+
dsh plugin --profile desktop add dsh-prompt-predict@0.2.1
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
`--profile` 换成你自己的 profile(桌面端一般是 `desktop`,Web 端是 `web
|
|
63
|
+
`--profile` 换成你自己的 profile(桌面端一般是 `desktop`,Web 端是 `web`),**装完重启 DSH 生效**。
|
|
64
64
|
|
|
65
|
-
>
|
|
65
|
+
> ⚠️ **CLI 只负责装包。** DSH 只有在 `~/.dsh/profiles/<profile>/package.json` 的
|
|
66
|
+
> `dsh.profile.bundles` 里也列出该插件时才会加载它。实测:包装了但不在该列表里,插件路由返回 `404`,
|
|
67
|
+
> 什么都不会加载。上面的图形界面路径会替你处理;用 CLI 的话请自己把 `"dsh-prompt-predict"` 加进该数组,
|
|
68
|
+
> 或直接跑下面的 `scripts/install.sh`——它两步都做。
|
|
69
|
+
|
|
70
|
+
> 装完在 **设置 → 提示词联想** 里能看到开关与各项参数。
|
|
71
|
+
|
|
72
|
+
### 从 release 的 tarball 安装
|
|
73
|
+
|
|
74
|
+
每个 [release](https://github.com/ferrisching/dsh-prompt-predict/releases) 都附了与 npm 上
|
|
75
|
+
**完全一致**的 tarball(`shasum` 与 registry 相同),适合离线机器或需要自行校验产物的场景:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
gh release download v0.2.1 --repo ferrisching/dsh-prompt-predict --pattern '*.tgz'
|
|
79
|
+
dsh plugin --profile desktop add ./dsh-prompt-predict-0.2.1.tgz
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
与上面 CLI 路径同样的注意点:请自己把 `"dsh-prompt-predict"` 加进 `dsh.profile.bundles`,
|
|
83
|
+
或改用 `scripts/install.sh`。
|
|
66
84
|
|
|
67
85
|
### 从源码安装
|
|
68
86
|
|
|
@@ -93,7 +111,7 @@ pnpm add /path/to/dsh-prompt-predict
|
|
|
93
111
|
|
|
94
112
|
### 安装要求
|
|
95
113
|
|
|
96
|
-
- 已在 **DSH `0.2.
|
|
114
|
+
- 已在 **DSH `0.2.1-rc.2`** 上验证(Web 构建;桌面端跑的是同一套 host 与 client 代码)
|
|
97
115
|
- `node` / `pnpm`:安装脚本优先使用 `~/.dsh/dsh-runtimes/*/dependencies` 下 DSH 自带的运行时,找不到才回退 `PATH`
|
|
98
116
|
- macOS / Linux;Windows 未验证
|
|
99
117
|
|
|
@@ -203,7 +221,7 @@ npm test # 66 项:51 项 Host 端 + 15 项客户端渲染冒烟
|
|
|
203
221
|
|
|
204
222
|
## ⚠️ 已知限制
|
|
205
223
|
|
|
206
|
-
- 仅在 DSH `0.2.
|
|
224
|
+
- 仅在 DSH `0.2.1-rc.2` 上验证过,其它版本未测
|
|
207
225
|
- 依赖宿主的 `conversation.composer.dock` 与 `settings.section` 两个 slot 名称,DSH 大版本调整后可能需要适配
|
|
208
226
|
- 联想会消耗所选模型的额度;固定到快速小模型比跟随推理模型更省
|
|
209
227
|
|
package/client/client.js
CHANGED
|
@@ -361,6 +361,10 @@ window.__ModuleLoader__.load({
|
|
|
361
361
|
var abortRef = useRef(null);
|
|
362
362
|
var sessionRef = useRef(sessionId);
|
|
363
363
|
var dismissedByDraft = useRef(false);
|
|
364
|
+
// rc.2 不再把 draft 暴露给 slot,拿不到「输入框是否为空」。
|
|
365
|
+
// 用等价信号:建议可见时按下任何可打印键 = 用户开始输入 → 立即隐藏。
|
|
366
|
+
var _tk = useState(0), typedTick = _tk[0], setTypedTick = _tk[1];
|
|
367
|
+
var typedSince = useRef(false);
|
|
364
368
|
// 逐段采纳的前缀,只有「输入框里确实还留着它」时才算数:
|
|
365
369
|
// 用户把它删掉后必须重新完整展示整条建议,否则会出现从中间截断的鬼影。
|
|
366
370
|
var prefixKept = accepted !== "" && suggestion.indexOf(accepted) === 0 && draft === accepted;
|
|
@@ -368,7 +372,7 @@ window.__ModuleLoader__.load({
|
|
|
368
372
|
// 打字即隐藏,两种例外:
|
|
369
373
|
// (a) 草稿又被删空 —— 用户回到了「需要建议」的状态,让它重新浮现(只有 Esc 才是永久忽略)
|
|
370
374
|
// (b) 草稿正是我们逐段写进去、且没有改动的前缀 —— 不能把自己插的内容误判成用户打字
|
|
371
|
-
dismissedByDraft.current = draft.trim() !== "" && !prefixKept;
|
|
375
|
+
dismissedByDraft.current = (draft.trim() !== "" || typedSince.current) && !prefixKept;
|
|
372
376
|
var visibleSuggestion = dismissedByDraft.current ? "" : remaining;
|
|
373
377
|
|
|
374
378
|
// 首次读取启用状态;设置页保存后通过事件让当前会话立即生效。
|
|
@@ -395,6 +399,7 @@ window.__ModuleLoader__.load({
|
|
|
395
399
|
dismissedByDraft.current = false;
|
|
396
400
|
setSuggestion("");
|
|
397
401
|
setAccepted("");
|
|
402
|
+
typedSince.current = false;
|
|
398
403
|
if (abortRef.current) abortRef.current.abort();
|
|
399
404
|
}, [sessionId]);
|
|
400
405
|
|
|
@@ -405,6 +410,7 @@ window.__ModuleLoader__.load({
|
|
|
405
410
|
dismissedByDraft.current = false;
|
|
406
411
|
setSuggestion("");
|
|
407
412
|
setAccepted("");
|
|
413
|
+
typedSince.current = false;
|
|
408
414
|
if (abortRef.current) abortRef.current.abort();
|
|
409
415
|
return;
|
|
410
416
|
}
|
|
@@ -418,6 +424,7 @@ window.__ModuleLoader__.load({
|
|
|
418
424
|
.then(function (result) {
|
|
419
425
|
if (controller.signal.aborted || sessionRef.current !== sessionId) return;
|
|
420
426
|
if (result && result.ok && typeof result.suggestion === "string") {
|
|
427
|
+
typedSince.current = false;
|
|
421
428
|
setSuggestion(result.suggestion.trim());
|
|
422
429
|
recordRun(result, null);
|
|
423
430
|
} else {
|
|
@@ -483,6 +490,11 @@ window.__ModuleLoader__.load({
|
|
|
483
490
|
var onKey = function (event) {
|
|
484
491
|
if (event.isComposing) return;
|
|
485
492
|
if (event.key === "Escape") { event.preventDefault(); setSuggestion(""); setAccepted(""); return; }
|
|
493
|
+
// 任何可打印字符 → 认定用户开始输入,隐藏建议(与「开始输入自动消失」一致)
|
|
494
|
+
if (!typedSince.current && typeof event.key === "string" && event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
495
|
+
typedSince.current = true;
|
|
496
|
+
setTypedTick(function (n) { return n + 1; });
|
|
497
|
+
}
|
|
486
498
|
// Option/Alt + → :逐段采纳(对齐 Codex 的手感)
|
|
487
499
|
if (event.key === "ArrowRight" && event.altKey) {
|
|
488
500
|
if (!acceptChunk()) return;
|
|
@@ -501,7 +513,37 @@ window.__ModuleLoader__.load({
|
|
|
501
513
|
|
|
502
514
|
// 建议直接以灰色 ghost text 覆盖在 Lexical 输入框首字符处。
|
|
503
515
|
if (!enabled || dismissedByDraft.current || !visibleSuggestion) return null;
|
|
504
|
-
|
|
516
|
+
// 在 composer dock 的流内渲染一行建议(不再用 fixed 覆盖层):
|
|
517
|
+
// dock 是宿主分配了空间的位置,不依赖 findElement 算坐标,也不会压在草稿文字上。
|
|
518
|
+
return h("div", {
|
|
519
|
+
"data-prompt-predict-row": "true",
|
|
520
|
+
role: "status",
|
|
521
|
+
"aria-live": "polite",
|
|
522
|
+
style: {
|
|
523
|
+
display: "flex", alignItems: "center", gap: 8, minWidth: 0,
|
|
524
|
+
padding: "2px 4px", fontSize: 12, lineHeight: "18px", color: "#9aa3b2",
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
h("span", {
|
|
528
|
+
style: { flex: 1, minWidth: 0, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" },
|
|
529
|
+
}, visibleSuggestion),
|
|
530
|
+
h("button", {
|
|
531
|
+
type: "button", onClick: accept, title: tt(t, "ghost.acceptHint"),
|
|
532
|
+
style: {
|
|
533
|
+
flex: "none", padding: "0 7px", height: 19, borderRadius: 5,
|
|
534
|
+
border: "1px solid var(--dsw-alias-border-l1, #d1d5db)", background: "var(--dsw-alias-bg-secondary, #f8fafc)",
|
|
535
|
+
color: "#9aa3b2", fontSize: 10, fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", cursor: "pointer",
|
|
536
|
+
},
|
|
537
|
+
}, "Tab"),
|
|
538
|
+
h("button", {
|
|
539
|
+
type: "button", onClick: reroll, title: tt(t, "ghost.reroll"),
|
|
540
|
+
style: {
|
|
541
|
+
flex: "none", width: 19, height: 19, padding: 0, borderRadius: 5,
|
|
542
|
+
border: "1px solid var(--dsw-alias-border-l1, #d1d5db)", background: "var(--dsw-alias-bg-secondary, #f8fafc)",
|
|
543
|
+
color: "#9aa3b2", fontSize: 11, lineHeight: 1, cursor: "pointer",
|
|
544
|
+
},
|
|
545
|
+
}, "↻"),
|
|
546
|
+
h("span", { style: { flex: "none", fontSize: 10, whiteSpace: "nowrap" } }, tt(t, "ghost.dismiss")));
|
|
505
547
|
}
|
|
506
548
|
|
|
507
549
|
// ================= 设置页 =================
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-prompt-predict",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "输入框提示词联想插件:助手回复结束后预测你的下一句话,以灰色 ghost text 浮在输入框里,Tab 采纳、Esc 忽略 | Codex-style composer prompt predictions for DeepSeek Harness: your next message ghosted into the composer, accepted with Tab.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|