dsh-newbe-response-window 0.3.0 → 0.3.2-alpha
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 +16 -10
- package/lib/client.js +30 -13
- package/lib/index.js +24 -13
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
DeepSeek Harness (DSH) Web 插件:把一轮里的 think(推理)和工具调用放进**有限高度的可滚动窗口**(默认 10 行),以**阶段性文字回复为界分段**,每个分段一个 **slide**;文字回复保持原生完整显示、不做限高。中间过程**始终可见**(只是不撑爆页面)——Grok Build 风格。
|
|
4
4
|
|
|
5
|
-
> 已验证 DSH 版本:**0.1.
|
|
5
|
+
> 已验证 DSH 版本:**0.1.7-alpha.1**(2026-09)。
|
|
6
6
|
> 与「全部折叠成 summary」类插件(如 `dsh-tool-summary`)不同:本插件**不隐藏**任何内容。think 与工具调用一条条列在 slide 里,每段都能展开翻到底;文字回复完全原生展示。
|
|
7
7
|
> 只包 bash + think:阶段性/最终文字 response **不**加限高、**不**加「展开全部/收起」按钮。
|
|
8
|
+
> **0.1.7 起的一轮折叠**:DSH 0.1.7 原生把「已完成的一轮」的中间过程折叠成一行「已完成工作 N 个工具调用」(简洁/详细/完全展开三种「工作过程展示」模式都折叠)。进行中的一轮 slide 照常常显;已完成的一轮点开这一行后,看到的就是本插件的 slide。
|
|
8
9
|
|
|
9
10
|
## 效果
|
|
10
11
|
|
|
@@ -30,16 +31,16 @@ DeepSeek Harness (DSH) Web 插件:把一轮里的 think(推理)和工具
|
|
|
30
31
|
|
|
31
32
|
## 安装
|
|
32
33
|
|
|
33
|
-
从 npm
|
|
34
|
+
从 npm 安装(跟 `latest`,即最近一次稳定发布):
|
|
34
35
|
|
|
35
36
|
```bash
|
|
36
37
|
dsh plugin --profile web add dsh-newbe-response-window
|
|
37
38
|
```
|
|
38
39
|
|
|
39
|
-
或从合集仓库 GitHub
|
|
40
|
+
或从合集仓库 GitHub 子目录安装(`alpha` 通道;换 `#rc` 装 rc 通道,换 `#<commit-sha>` 锁死某次发布):
|
|
40
41
|
|
|
41
42
|
```bash
|
|
42
|
-
dsh plugin --profile web add github:qiqiangvae/dsh-newbe-plugins#path:packages/dsh-newbe-response-window
|
|
43
|
+
dsh plugin --profile web add 'github:qiqiangvae/dsh-newbe-plugins#alpha&path:packages/dsh-newbe-response-window'
|
|
43
44
|
```
|
|
44
45
|
|
|
45
46
|
或本地 link 方式(开发调试):
|
|
@@ -63,7 +64,7 @@ dsh plugin --profile web add "link:$(pwd)/packages/dsh-newbe-response-window"
|
|
|
63
64
|
| 键 | 默认 | 说明 |
|
|
64
65
|
| --- | --- | --- |
|
|
65
66
|
| `lines` | `10` | 窗口高度(行)。`0` = 不限高(等价于关闭窗口) |
|
|
66
|
-
| `collapsed` | `false` |
|
|
67
|
+
| `collapsed` | `false` | slide 本身是否默认收起成一行 bar。默认 `false`:展开、内容可见(已完成轮次的外层折叠由 DSH 原生「已完成工作」那行控制) |
|
|
67
68
|
| `showReadOnly` | `true` | 是否在 slide 里列出 read/grep/web_search 等只读调用(默认全列出,不藏) |
|
|
68
69
|
| `minCollapseRows` | `3` | 仅 `collapsed: true` 时生效:少于该数量的轮次不收起 |
|
|
69
70
|
| `liveStreamThink` | `'out'` | 流式 think 的显示模式:`'out'` 盒外流式结束后进盒折叠 / `'in'` 盒内自动展开 / `'off'` 全程折叠 |
|
|
@@ -80,9 +81,11 @@ dsh plugin --profile web add "link:$(pwd)/packages/dsh-newbe-response-window"
|
|
|
80
81
|
|
|
81
82
|
- 工具调用 slide 通过 `conversation.chat.node`(`tool-call` key,`priority: -100`)的 **slot shadow** 在 React 层实现:每轮第一个 tool-call 节点渲染整个 slide,同轮其余 tool-call 节点渲染空,任何渲染异常由 slot 运行时的 entry boundary **自动 abdicate** 回内置渲染。
|
|
82
83
|
- **绝不移走 React 拥有的 `[data-chat-anchor-key]` 行节点**。实测:把行移进自定义容器后,一旦 DSH 后续移除该行(会话切换/编辑/压缩),React 会调用 `parent.removeChild(row)` 抛 `NotFoundError`,整个会话树被卸载——因此本插件只用「slot shadow + 类/CSS」两种方式,对 React 行结构零改动。
|
|
83
|
-
- 原生 Think 行隐藏与 slide 内的 think 同步:只对「该段内有 slide」的原生 `data-variant="think"` 行加 `display:none`(DOM 类/CSS,无重挂、无删除),其余(无工具调用的纯 Think 段)保持原生显示。
|
|
84
|
+
- 原生 Think 行隐藏与 slide 内的 think 同步:只对「该段内有 slide」的原生 `data-variant="think"` 行加 `display:none`(DOM 类/CSS,无重挂、无删除),其余(无工具调用的纯 Think 段)保持原生显示。0.1.7 把消息流行套进了 process-group 容器(`[data-chat-flow] > group root > content > 行`),行不再是 flow 的直接子节点,所以这段判定改成按文档顺序读全部 `[data-chat-flow-kind]` 行。(改动前 `flow.children` 只看到组外壳,永远匹配不到 Think,导致 slide 与原生 Think 双份显示。)
|
|
84
85
|
- 插件只读会话快照,不写快照、不调宿主 API。0.1.2-alpha 起快照从 slot 标准 prop **`useChat`** 读取(`{ locations.getTurn(turn), nodes.get(key) }` 形状),不再走 `useSession` 的 `chat` 字段;「幽灵行」判定通过 DOM 行上的 `data-chat-flow-key` 与该快照对号,不再嗅探 markdown CSS 类名(新版 CSS Module 类名已不含 `_markdown`)。
|
|
85
86
|
- 浏览器半依赖 `@deepseek-ai/dsh-client-store`(`createSnapshotStore`,shell 内置 seed module),替代旧版的 `@deepseek-ai/dsh-client-runtime`(该包在新 alpha 已移除)。旧版 `dsh.plugin.json` 清单在新 alpha 不再被读取,已删除。
|
|
87
|
+
- **设置持久化走 `configForms`**:0.1.7 移除了 `settingsScope` 服务,改为每个 profile 条目一个 controller(`ctx.configForms.get(条目 id)`,id 即 settings namespace)。宿主半的 `Config` 必须把用户可改字段标 `.volatile()`(settings 文档只投影 volatile 字段),并 `settings.configure({ auto: false }, ctx.fiber)` 退出自动生成的配置页。旧写法(`settingsScope` + `settings.register()`)会让 `inject` 永远等不到服务、整个插件静默不挂载——这正是 0.1.7 升级后 slide 全消失的原因。
|
|
88
|
+
- 宿主半因此要求 `@deepseek-ai/schemastery` **≥ 3.18.3**(`.volatile()` 的引入版本;随 DSH 0.1.7-alpha.1 发布)。
|
|
86
89
|
|
|
87
90
|
## 开发 / 测试
|
|
88
91
|
|
|
@@ -92,15 +95,18 @@ dsh plugin --profile web add "link:$(pwd)/packages/dsh-newbe-response-window"
|
|
|
92
95
|
npm run check # node --check lib/index.js && node --check lib/client.js
|
|
93
96
|
```
|
|
94
97
|
|
|
95
|
-
E2E(需要已启动的 `dsh web
|
|
98
|
+
E2E(需要已启动的 `dsh web`;用 uv 起 python playwright):
|
|
96
99
|
|
|
97
100
|
```bash
|
|
98
101
|
dsh --profile web --no-open --port 3639 &
|
|
99
|
-
|
|
102
|
+
uv run --with playwright playwright install chromium # 首次
|
|
103
|
+
uv run --with playwright python3 test/e2e.py --url http://127.0.0.1:3639 --session "修复 dsh 升级后的插件不兼容"
|
|
100
104
|
```
|
|
101
105
|
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
断言含:客户端半确实挂载(slide ≥ 1,服务缺失时这里会先失败)、窗口限高且内部真能滚动、think 单行且点击展开、有 slide 的段落里原生 Think 不重复显示、Settings → General 两行挂载并读到持久值、会话切换不崩。
|
|
107
|
+
|
|
108
|
+
- 宿主半:`lib/index.js`(声明 volatile 设置字段并退出自动配置页,依赖 `@deepseek-ai/schemastery` ≥ 3.18.3)
|
|
109
|
+
- 浏览器半:`lib/client.js`(`window.__ModuleLoader__.load`,require `react` 与 shell seed 的 `@deepseek-ai/dsh-client-store`,设置走 `configForms`)
|
|
104
110
|
|
|
105
111
|
## License
|
|
106
112
|
|
package/lib/client.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
// dsh-newbe-response-window — browser half.
|
|
2
2
|
//
|
|
3
|
-
// Adapted for DSH 0.1.
|
|
4
|
-
// generation). Breaking changes vs. the
|
|
3
|
+
// Adapted for DSH 0.1.7-alpha.1 (the current client-module / slot-runtime
|
|
4
|
+
// generation). Breaking changes vs. the alpha this plugin last shipped for:
|
|
5
5
|
//
|
|
6
|
-
// -
|
|
6
|
+
// - The `settingsScope` client service is gone. Durable preferences now go
|
|
7
|
+
// through the `configForms` service, keyed by profile entry id, and the host
|
|
8
|
+
// half has to mark its user-editable fields `volatile()` and call
|
|
9
|
+
// `settings.configure({ auto: false }, ctx.fiber)`. Declaring the old
|
|
10
|
+
// service in `inject` parks the plugin forever ("waiting for service:
|
|
11
|
+
// settingsScope") — that, and only that, is what upgrading DSH broke.
|
|
12
|
+
// - `@deepseek-ai/dsh-client-runtime` is gone. The browser shell seeds
|
|
7
13
|
// `@deepseek-ai/dsh-client-store` (createSnapshotStore) as a static module,
|
|
8
14
|
// so the bundle requires that instead — no dsh.client.inject needed.
|
|
9
15
|
// - `conversation.chat.node` moved from dsh-client-ui-conversation to
|
|
@@ -706,10 +712,15 @@ window.__ModuleLoader__.load({
|
|
|
706
712
|
// reasoning does not appear both inside the slide and inline in the flow.
|
|
707
713
|
// Only DOM class toggling — never reparents React-owned rows.
|
|
708
714
|
function hideNativeThink(root, textIndex) {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
715
|
+
// 0.1.7-alpha.1 nests flow rows inside process-group containers
|
|
716
|
+
// (`[data-chat-flow] > group root > content > rows`) instead of keeping
|
|
717
|
+
// every row a direct child of one flow element, so walking
|
|
718
|
+
// `flow.children` only ever saw the group wrappers and never matched a
|
|
719
|
+
// Think against the slide that sits beside it in the same group. Read the
|
|
720
|
+
// flow rows in document order instead — that is still reading order —
|
|
721
|
+
// while keeping the segment-boundary walk unchanged.
|
|
722
|
+
var rows = root.querySelectorAll('[data-chat-flow-kind]')
|
|
723
|
+
if (rows.length === 0) return
|
|
713
724
|
// Segment boundary in the DOM: a user/steering row, a turn-level row
|
|
714
725
|
// (turn-process / turn-tail), or an assistant-step row that carries
|
|
715
726
|
// visible staged text (a response shown to the user mid-turn).
|
|
@@ -866,20 +877,26 @@ window.__ModuleLoader__.load({
|
|
|
866
877
|
// ---- plugin entry -------------------------------------------------------
|
|
867
878
|
var currentConfig = readConfig(null)
|
|
868
879
|
|
|
869
|
-
|
|
880
|
+
// 0.1.7-alpha.1 replaced the `settingsScope` service with `configForms`:
|
|
881
|
+
// one controller per profile entry id, exposing getSnapshot/subscribe/set
|
|
882
|
+
// over the host settings document. Same shape we already used, so the bind
|
|
883
|
+
// is a rename — but the service is a hard inject dependency, and a missing
|
|
884
|
+
// one silently parks the whole plugin (no slides at all).
|
|
885
|
+
var INJECT = ['slots', 'configForms']
|
|
870
886
|
function apply(ctx, config) {
|
|
871
887
|
currentConfig = readConfig(config)
|
|
872
888
|
injectStyles()
|
|
873
889
|
|
|
874
|
-
// Durable settings binding: the host half
|
|
875
|
-
//
|
|
890
|
+
// Durable settings binding: the host half declares the volatile fields of
|
|
891
|
+
// the `dsh-newbe-response-window` entry; this controller mirrors them and
|
|
892
|
+
// persists user overrides.
|
|
876
893
|
linesStore = createSnapshotStore(currentConfig.lines)
|
|
877
894
|
liveStreamThinkStore = createSnapshotStore(currentConfig.liveStreamThink)
|
|
878
895
|
var scopeService = null
|
|
879
|
-
try { scopeService = ctx.get('
|
|
880
|
-
if (scopeService && typeof scopeService.
|
|
896
|
+
try { scopeService = ctx.get('configForms') } catch (e) { scopeService = null }
|
|
897
|
+
if (scopeService && typeof scopeService.get === 'function') {
|
|
881
898
|
try {
|
|
882
|
-
settingsScope = scopeService.
|
|
899
|
+
settingsScope = scopeService.get(NS)
|
|
883
900
|
} catch (e) {
|
|
884
901
|
settingsScope = null
|
|
885
902
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
// dsh-newbe-response-window — host half.
|
|
2
2
|
//
|
|
3
|
-
// Verified against DSH 0.1.
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// "./client").
|
|
3
|
+
// Verified against DSH 0.1.7-alpha.1. Owns the durable settings namespace so the
|
|
4
|
+
// browser Settings UI can persist the window size etc. in the user settings
|
|
5
|
+
// document. The heavy lifting lives in the browser half (exports "./client").
|
|
7
6
|
//
|
|
8
|
-
//
|
|
7
|
+
// The host settings contract is the 0.1.7 one: the settings document is keyed
|
|
8
|
+
// by the profile entry id, a namespace only shows up in it when its Config
|
|
9
|
+
// schema projects at least one `volatile()` field, and a plugin opts out of the
|
|
10
|
+
// auto-generated page with `settings.configure({ auto: false }, ctx.fiber)`.
|
|
11
|
+
//
|
|
12
|
+
// Namespace + schema (browser `configForms.get(SETTINGS_NS)` mirrors it):
|
|
9
13
|
// lines window height in lines (default 10; 0 = uncapped)
|
|
10
14
|
// collapsed start slides collapsed instead of always-expanded
|
|
11
15
|
// showReadOnly include read-only tools in the slide list
|
|
@@ -16,9 +20,9 @@
|
|
|
16
20
|
// 'out' — stream outside the slide (native row), then
|
|
17
21
|
// fold into the slide once settled (default 'out')
|
|
18
22
|
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
23
|
+
// The namespace must equal the profile entry id (the `id:` of the row this
|
|
24
|
+
// bundle patch inserts), because that is what the host settings document and
|
|
25
|
+
// `configForms.get()` are keyed by.
|
|
22
26
|
|
|
23
27
|
import z from '@deepseek-ai/schemastery'
|
|
24
28
|
|
|
@@ -28,21 +32,28 @@ export const name = 'dsh-newbe-response-window'
|
|
|
28
32
|
/** Durable settings namespace for this plugin (lowercase kebab-case). */
|
|
29
33
|
export const SETTINGS_NS = 'dsh-newbe-response-window'
|
|
30
34
|
|
|
31
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Settings schema. Only the two user-editable preferences are `volatile()`:
|
|
37
|
+
* the browser settings document is projected from volatile fields alone, and
|
|
38
|
+
* the rest stay patch-time configuration that the client reads from row config.
|
|
39
|
+
*/
|
|
32
40
|
export const Config = z.object({
|
|
33
|
-
lines: z.natural().min(0).max(200).default(10),
|
|
41
|
+
lines: z.natural().min(0).max(200).default(10).volatile(),
|
|
34
42
|
collapsed: z.boolean().default(false),
|
|
35
43
|
showReadOnly: z.boolean().default(true),
|
|
36
44
|
minCollapseRows: z.natural().min(1).max(50).default(3),
|
|
37
|
-
liveStreamThink: z.string().default('out'),
|
|
45
|
+
liveStreamThink: z.string().default('out').volatile(),
|
|
38
46
|
})
|
|
39
47
|
|
|
40
48
|
/**
|
|
41
|
-
*
|
|
49
|
+
* Opt this plugin's entry out of the auto-generated settings page. Its
|
|
50
|
+
* namespace is the profile entry id (`dsh-newbe-response-window`), which is
|
|
51
|
+
* exactly {@link SETTINGS_NS}, so the browser half can bind the durable scope
|
|
52
|
+
* through `configForms.get(SETTINGS_NS)`.
|
|
42
53
|
* @param ctx - host plugin context.
|
|
43
54
|
*/
|
|
44
55
|
export function apply(ctx) {
|
|
45
56
|
ctx.inject(['settings'], (settingsCtx) => {
|
|
46
|
-
settingsCtx.settings.
|
|
57
|
+
settingsCtx.effect(() => settingsCtx.settings.configure({ auto: false }, ctx.fiber))
|
|
47
58
|
})
|
|
48
59
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-newbe-response-window",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2-alpha",
|
|
4
4
|
"description": "DeepSeek Harness (DSH) web plugin: per-turn response window. Each turn's tool calls collapse into ONE always-expanded bounded slide (configurable N-line window, inner scroll, nothing hidden), and long assistant markdown gets a bounded scroll window too — Grok-build style, keeps every intermediate response visible inside a finite window. Streaming think blocks can live-stream outside the slide and fold in when settled (or auto-expand inside), switchable via Settings.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"check": "node --check lib/index.js && node --check lib/client.js"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@deepseek-ai/schemastery": "^3.
|
|
31
|
+
"@deepseek-ai/schemastery": "^3.18.3"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"react": "^18.0.0 || ^19.0.0"
|