dsh-select-quote 0.1.0 → 0.3.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/README.md +55 -115
- package/lib/client.js +2611 -620
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
# dsh-select-quote
|
|
2
2
|
|
|
3
|
-
[DeepSeek Harness](https://deepseek-harness.github.io/deepseek-harness/guide/quickstart) 的 Web
|
|
3
|
+
[DeepSeek Harness](https://deepseek-harness.github.io/deepseek-harness/guide/quickstart) 的 Web 客户端插件:在对话里**划词加批注**——把选中的原文连同你的评论一起交给模型,并让它在回答里明确指出说的是哪一段。
|
|
4
4
|
|
|
5
|
-
- **划词工具条**:选中对话区任意文本,浮出「复制 /
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
5
|
+
- **划词工具条**:选中对话区任意文本,浮出「复制 / 添加到任务」;拖拽结束才出现,不挡操作
|
|
6
|
+
- **批注卡片**:添加后输入框内出现一张摘要卡片(可多条),**草稿里不会出现任何协议文本**
|
|
7
|
+
- **正文标记**:被划中的文字在原消息里留下虚线下划线 + 序号角标;点卡片里的条目会滚回那段文字
|
|
8
|
+
- **模型回指**:模型回答时以内联指令标出它处理的每一条批注,插件把这些指令渲染成可点击的 chip
|
|
9
|
+
- **对话记录**:已发送消息里的批注渲染为卡片,用户气泡只剩你打的问题
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
<sub>示意图(按产品真实设计 token 渲染,源文件 `assets/screenshot-1.mock.html`)</sub>
|
|
9
14
|
|
|
10
15
|
---
|
|
11
16
|
|
|
@@ -13,149 +18,84 @@
|
|
|
13
18
|
|
|
14
19
|
| 项 | 值 |
|
|
15
20
|
|---|---|
|
|
16
|
-
| dsh | `0.1.
|
|
17
|
-
| profile | web(`dsh web
|
|
21
|
+
| dsh | `0.1.7-rc.1`(2026-09-24 实测:划词、批注卡片、正文标记、对话记录渲染全通) |
|
|
22
|
+
| profile | web(`dsh web`)与桌面端(desktop)都可用;桌面端在 0.2.0 及更早版本会楔死渲染进程,本仓库已修复,详见下节 |
|
|
18
23
|
| 运行时 | 只有浏览器半有业务;Node 半仅用于让包被 Loader 挂载 |
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
实现依赖若干产品内部约定(槽位名、composer DOM、深色主题属性等),升级 dsh 后请先跑 `npm run check`,再照 [`docs/internals.md`](docs/internals.md) 末尾的复核清单人工回归一遍。
|
|
21
26
|
|
|
22
|
-
|
|
27
|
+
### 桌面端(desktop profile)
|
|
23
28
|
|
|
24
|
-
|
|
29
|
+
桌面端是 Electron 外壳 + 同一个 Web 客户端,插件声明的 `dsh.client.platform: "web"` 在桌面端同样加载,槽位与 DOM 契约都在,功能本身可用(实测批注随消息送达模型、模型回指渲染为 chip 均正常)。
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
git clone <repo> && cd dsh-select-quote
|
|
28
|
-
npm install
|
|
29
|
-
npm run build
|
|
31
|
+
> ⚠️ **0.2.0 及更早版本在桌面端会楔死渲染进程**,见 [#1](https://github.com/latte03/dsh-select-quote/issues/1):App 能启动、界面完整渲染,但整个输入区无法点击,renderer 子进程单核 100% 持续旋转。根因在插件自己的装饰器里——协议头部逐字写出了 `:dsh-annotation{index="N"}`,当文本含有这个字面量而严格正则一条都没匹配上时,装饰器仍然替换了一次内容完全相同的 Text 节点,于是被自己的 `MutationObserver` 反复触发,微任务队列永远排不空,宏任务和定时器再也得不到执行。触发条件是文本内容,与 Electron 或 `dsh-app://` 无关,桌面端只是恰好把那段文本送进了 Text 节点。完整机制与两道防线记录在 [`docs/internals.md`](docs/internals.md) 关键机制 8。
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
打开 `http://127.0.0.1:3080`,在对话消息里划词即可看到工具条。
|
|
33
|
+
> **现在的状态**:修复已进主干,Windows 桌面端 0.2.0-rc.2 实测重新启用插件后批注正常送达、Turn 正常结束、输入框可点击、没有新的崩溃日志。npm 上可安装的仍是 `0.2.0`,也就是带缺陷的那一版,因此桌面端用户在修复版发布之前请在 `dsh.profile.bundles` 中摘除本插件,或改用浏览器访问同一个端口。[#1](https://github.com/latte03/dsh-select-quote/issues/1) 保持 open,等报告人复验后关闭。
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
## 安装
|
|
37
36
|
|
|
38
|
-
###
|
|
37
|
+
### 方式一:从 npm 安装(bundle)
|
|
39
38
|
|
|
40
39
|
```bash
|
|
41
|
-
dsh plugin --profile web add dsh-select-quote
|
|
40
|
+
dsh plugin --profile web add dsh-select-quote
|
|
42
41
|
dsh --profile web
|
|
43
42
|
```
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
npm run typecheck # tsc --noEmit,应无输出
|
|
49
|
-
npm run build # 产出 lib/index.js 与 lib/client.js
|
|
50
|
-
npm run watch # 增量重建
|
|
51
|
-
npm run verify # 无头执行 lib/client.js,断言 5 项贡献都注册上了
|
|
52
|
-
npm run check # typecheck + build + verify(提交前跑这个)
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
**为什么有 `verify`**:`tsdown` 不做类型检查,一个语法坏掉的 bundle 也能构建"成功"。最典型的一次事故是 CSS 模板字符串里出现了反引号(`` `.nyYjTG_file` ``),字符串被提前截断,产出的 JS 无法执行,但 build 输出一切正常。`verify` 把 `lib/client.js` 放进假的 `window.__ModuleLoader__` 里跑一遍,用 mock ctx 调 `apply()`,逐项核对注册结果——这是唯一能在浏览器之外发现这类错误的手段。改动 `src/client/index.tsx` 的注册项时,记得同步 `scripts/verify-bundle.mjs` 里的 `EXPECTED`。
|
|
56
|
-
|
|
57
|
-
## 工作原理
|
|
58
|
-
|
|
59
|
-
### 数据契约:消息里的引用块
|
|
44
|
+
> npm 上目前最新是 `0.2.0`(2026-09-24 发布):带批注卡片、正文标记与模型回指,但界面只有简体中文,桌面端还会楔死渲染进程(见兼容性一节)。本仓库的 `0.3.0` 修掉了楔死、加了简体中文 / English / Русский 三语,并把对话记录里的批注卡片改到用户气泡内,**还没发布到 npm**。要用 `0.3.0` 的行为,先按方式二从本地 checkout 加载;发布完成后这一节需要更新。仓库里另有 `0.1.0`,那是旧版「引用块」,不要装错。
|
|
60
45
|
|
|
61
|
-
|
|
46
|
+
### 方式二:本地 checkout 加载(`--patch`)
|
|
62
47
|
|
|
48
|
+
```bash
|
|
49
|
+
git clone <repo> && cd dsh-select-quote
|
|
50
|
+
npm install && npm run build
|
|
51
|
+
dsh web --patch "$PWD/dev.patch.yml"
|
|
63
52
|
```
|
|
64
|
-
> [选中文本]
|
|
65
|
-
> 用户选中的第一段
|
|
66
|
-
|
|
67
|
-
> [选中文本]
|
|
68
|
-
> 用户选中的第二段
|
|
69
|
-
|
|
70
|
-
用户自己输入的问题
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
`> [选中文本]` 这个标记是插件的识别依据:客户端据此把这段从用户气泡里剥掉、改渲染成卡片。**改动这个标记要同时改三处**:`formatQuoteBlock()`(写)、`parseQuoteMessage()`(读)、`displayTextWithoutQuote()`(剥离)。
|
|
74
|
-
|
|
75
|
-
### 客户端贡献
|
|
76
|
-
|
|
77
|
-
| 位置 | 类型 | 说明 |
|
|
78
|
-
|---|---|---|
|
|
79
|
-
| `conversation.input.overlay` | list slot | `select-quote-toolbar`(划词工具条)、`select-quote-card`(引用卡片堆) |
|
|
80
|
-
| `conversation.chat.node` | keyed slot | `select-quote`(引用卡片)、`user`(替换用户气泡) |
|
|
81
|
-
| Conversation Definition | `uiConversation.events.register` | `select-quote`:把带引用的 `user/message` 变成一个 Chat 节点 |
|
|
82
53
|
|
|
83
|
-
|
|
54
|
+
打开 `http://127.0.0.1:3080`,在对话消息里划词即可看到工具条。`dev.patch.yml` 里的插件路径按本机写死(必须是绝对路径),换机器或换目录时改那一行;该文件不随 npm 包发布。
|
|
84
55
|
|
|
85
|
-
|
|
56
|
+
## 用法
|
|
86
57
|
|
|
87
|
-
|
|
58
|
+
1. 在对话区选中一段文本 → 点「添加到任务」
|
|
59
|
+
2. 弹出评论框,写一句想说的话(可留空,只划不评)→ `⌘/Ctrl + Enter` 确认
|
|
60
|
+
3. 输入框上方出现批注卡片,悬停可展开列表:逐条编辑、删除,或一键清空;点条目会跳到正文里对应的那段文字
|
|
61
|
+
4. 正常打字、按 Enter 发送。批注随消息一起交给模型,卡片随之消失
|
|
62
|
+
5. 模型回答里指向某条批注的位置,会显示成可点的 chip
|
|
88
63
|
|
|
89
|
-
|
|
64
|
+
## 语言 / Localization
|
|
90
65
|
|
|
91
|
-
|
|
66
|
+
界面文案支持 **简体中文 / English / Русский**,默认跟随浏览器语言:
|
|
92
67
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
68
|
+
| 语言 | 默认值 |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `zh` | 原文案,同时作为缺失键的兜底词典 |
|
|
71
|
+
| `en` | 非中文环境 |
|
|
72
|
+
| `ru` | `ru` / `ru-RU` 等标签 |
|
|
96
73
|
|
|
97
|
-
|
|
74
|
+
想固定语言,在 Web GUI 控制台里设置后刷新页面:
|
|
98
75
|
|
|
99
|
-
```
|
|
100
|
-
.
|
|
76
|
+
```js
|
|
77
|
+
localStorage.setItem('dsq-locale', 'ru') // 'ru' | 'en' | 'zh'
|
|
78
|
+
localStorage.removeItem('dsq-locale') // 恢复跟随浏览器
|
|
101
79
|
```
|
|
102
80
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
**4. 对话记录:Definition + 节点 + 气泡替换**
|
|
106
|
-
|
|
107
|
-
- Definition(`transcript-node.ts`)匹配 `type === "user/message"` 且文本含引用块的消息,产出一个 `select-quote` 节点;
|
|
108
|
-
- `TranscriptQuoteCard.tsx` 渲染该节点(每段引用一张卡片,纵向堆叠、与气泡同侧);
|
|
109
|
-
- `UserMessageDisplay.tsx` 以 `priority: -10` 替换内置的 `user` 节点,把引用块从气泡里剥掉,**同时自己渲染消息携带的图片**——只引用、没有正文的消息,气泡文本为空,若不接管图片渲染,整条消息(含图片)会消失。
|
|
81
|
+
**刻意不翻译的部分**:`> [选中文本]`、`<response-annotations>`、`:dsh-annotation{index="N"}` 这些是模型与解析器约定的传输格式;`# Response annotations:` 那段是给模型的指令正文,不是界面文案。只有面向人的 chrome 走 `t()`。
|
|
110
82
|
|
|
111
|
-
|
|
83
|
+
新增文案:在 `src/client/i18n.ts` 的三份词典里各加一条,再在组件里 `t('key', { ... })` 调用。带 `{count}` 的键可以写成复数形式对象(中文用 `other`,俄语用 `one` / `few` / `many`)。
|
|
112
84
|
|
|
113
|
-
|
|
85
|
+
## 已知限制
|
|
114
86
|
|
|
115
|
-
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
87
|
+
- **待发批注只在内存里**:刷新页面或切换会话后会丢,卡片不持久化(已发送消息里的批注不受影响)。
|
|
88
|
+
- **占用了用户气泡的渲染**:本插件以最低优先级替换内置 `user` 节点。若其它插件也替换同一个键(例如 `dsh-easyrewrite` 用 `-1`),会被本插件屏蔽。
|
|
89
|
+
- **卡片宽度有限**:输入框内每条摘要最宽约为输入框的 1/4,超长标题走省略号。
|
|
90
|
+
- 划词只在对话区生效,不介入编辑器、终端等面板。
|
|
118
91
|
|
|
119
|
-
##
|
|
92
|
+
## 开发
|
|
120
93
|
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
src/client/index.tsx # Client 半入口:注册 Slot 与 Conversation Definition
|
|
124
|
-
src/client/SelectionToolbar.tsx # 划词浮动条(复制 / 添加到任务)
|
|
125
|
-
src/client/selection.ts # 选区快照、工具条定位、复制、聚焦输入框
|
|
126
|
-
src/client/QuoteCard.tsx # 输入框内引用卡片堆 + 发送动作拦截
|
|
127
|
-
src/client/quote-store.ts # 每会话引用状态、消息块拼装、U+200B 标记
|
|
128
|
-
src/client/TranscriptQuoteCard.tsx # 对话记录里的引用卡片
|
|
129
|
-
src/client/UserMessageDisplay.tsx # 替换用户气泡(隐藏引用块、保留图片)
|
|
130
|
-
src/client/transcript-node.ts # select-quote Conversation Definition
|
|
131
|
-
src/client/transcript-parse.ts # 引用块解析 / 气泡文本剥离
|
|
132
|
-
src/client/styles.ts # 全部 CSS(模板字符串注入)
|
|
133
|
-
src/client/context.d.ts # 客户端 Context 服务的类型补充
|
|
134
|
-
scripts/build.mjs # tsdown 构建 + ModuleLoader 包装
|
|
135
|
-
scripts/verify-bundle.mjs # 无头 bundle 校验
|
|
136
|
-
cordis.patch.yml # bundle 加载层(按包名,随 npm 包发布)
|
|
137
|
-
dev.patch.yml # 本地 --patch 开发层(绝对路径,不发布)
|
|
138
|
-
lib/ # 构建产物(已提交,运行时直接读它)
|
|
94
|
+
```bash
|
|
95
|
+
npm run check # typecheck + build + verify,提交前跑这个
|
|
139
96
|
```
|
|
140
97
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
- **引用状态在内存里**:刷新页面或换会话后待发引用会丢,卡片不会持久化。
|
|
144
|
-
- **输入框卡片最宽为输入框的 1/4**(`max-width: calc(25% - 5px)`),超长标题走省略号;同一行可放 4 张,多了换行。正因为窄,输入框内的图标是 36px,而对话记录里是 40px。
|
|
145
|
-
- **替换了 `user` 节点**(`priority: -10`,最低优先级胜出)。若其它插件也替换同一个键(例如 `dsh-easyrewrite` 用 `-1`),本插件会把对方屏蔽掉。
|
|
146
|
-
- **只注入一个会话一份待发引用**,按 `sessionId` 在内存 Map 里存。
|
|
147
|
-
- 依赖的产品内部约定:`[data-composer-card]` 属性、主发送按钮是卡片内 DOM 顺序上最后一个 `button`、停止按钮渲染 `svg rect`、`user/message` 事件的内容在 `data.content`(不是 `data.message.content`)、深色属性 `data-ds-dark-theme`。产品升级后这些都需要复核。
|
|
148
|
-
|
|
149
|
-
## 排错
|
|
150
|
-
|
|
151
|
-
| 现象 | 先查 |
|
|
152
|
-
|---|---|
|
|
153
|
-
| 划词没有工具条 / 卡片不出现 | 跑 `npm run check`;确认页面已刷新;Host 的 boot 图里应包含 `dsh-select-quote`(`/plugins` 路由由 `ctx.clientModules` 提供) |
|
|
154
|
-
| 输入框里出现 `> [选中文本]` 原文 | 说明发送前的注入没生效:确认草稿里存在 U+200B(发送按钮应是可用的),以及 composer 结构未变(`[data-composer-card]`) |
|
|
155
|
-
| 对话记录里没有卡片 | 该 `user/message` 事件的 `data.content` 是否含引用块;`conversation.chat.node` 的 `select-quote` 单元是否被注册 |
|
|
156
|
-
| 带图片的消息在记录里只剩卡片、图片没了 | `UserMessageDisplay` 是否拿到了 `renderMessageImages` |
|
|
157
|
-
| 改了 CSS 不生效 | `<style>` 只注入一次,刷新页面 |
|
|
158
|
-
| 按 Backspace 删不掉 / 中文输入被打断 | 检查是否有代码在响应草稿变化时调用 `setDraft()`(见[关键机制 2](#关键机制)) |
|
|
98
|
+
改 CSS 后要刷新页面(样式只注入一次)。协议格式、槽位注册、以及几处非显而易见的坑(U+200B 草稿标记、portal 到 body 的浮层、`--dsq-quote-pad` 高度补偿)记录在 **[docs/internals.md](docs/internals.md)**。
|
|
159
99
|
|
|
160
100
|
## License
|
|
161
101
|
|