dsh-quote-annotate-pro 0.0.0-stage → 0.2.1

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 ADDED
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ 本项目的所有重要变更都记在这里。版本号遵循 [SemVer](https://semver.org/lang/zh-CN/)。
4
+
5
+ ## 0.2.1 — 文档与自动发版
6
+
7
+ - README / README.en:新增 npm 版本、CI、License 徽章;安装章节补上 `dsh plugin add dsh-quote-annotate-pro`(npm)与 `github:` 两种方式
8
+ - 新增 `.github/workflows/release.yml`:推 `v*` 标签即由 **npm Trusted Publishing(OIDC)** 自动发布,仓库不存任何 token,并生成 provenance 签名
9
+ - `lib/client.js` 相对 0.2.0 **无变化**(本次发版只为验证 OIDC 发布链路并把文档同步到 npm)
10
+
11
+ ## 0.2.0 — 首个公开发布
12
+
13
+ Fork 自 [`dsh-quote-annotate`](https://github.com/wangwei-wade/dsh-quote-annotate) v0.1.1(MIT),
14
+ 在 **DSH 0.2.0-rc.2** 上真机验证。
15
+
16
+ ### 修复(上游在本版本上已无法工作)
17
+
18
+ 1. **缺 cordis 依赖声明导致静默失效**:`apply()` 中 `ctx.get('slots')` 未就绪即 `return`,插件加载成功却一个 UI 都不注册。
19
+ 补齐 `exports.name` / `exports.inject = ['slots']`,并给每一步注册加 `try/catch` 与上报。
20
+ 2. **`conversation.chat.turnTail` 由 chain 变 list**:上游仍按 `{ select, priority }` 注册会抛错,
21
+ 且该注册排在 4 个 overlay 注册之前,一崩全崩。改为 `{ name, id, order }`。
22
+ 3. **引用 chip 插入 API 变更**:`input.insertReference(...)` 在本版本不存在,引用永远退化为纯文本。
23
+ 改用官方会话事件 `slash/input-insert-reference`。
24
+ 4. **当前会话解析失效**:`useSessions(s => s.current)` 恒为 `undefined`(本版本会话列表快照无 `current` 字段),
25
+ 点「批注」只会关闭气泡。改用会话作用域槽位探针(`conversation.input.dock`)回填 `sessionId`。
26
+ 5. **回合尾部按钮不出现**:取文依赖 session 快照 + 数组 + 节点 `seq`;本版本为 Chat 快照(`useChat`)、
27
+ `nodes` 是 Map、身份字段 `anchorSeq`、assistant kind 为 `assistant-step`、文本在 `data.content` / `data.blocks`。
28
+ 6. **chip 无 DOM 标识**:本版本 chip 已无 `data-occurrence` 属性,上游"点 chip 跳回原文"不可能成立。
29
+
30
+ ### 新增
31
+
32
+ - **引用块带位置**:序列化首行为 `【引用 · 第N轮 · 角色】`,多轮对话中模型可精确定位引用来源。
33
+ - **引用导航条**:注册进 `conversation.input.dock`,读官方输入状态 `occurrences`,点击跳回原文并高亮,悬停预览原文。
34
+ - **锚点持久化**:`ref → 锚点` 写入 `localStorage`(按会话,60 条上限),刷新页面后引用仍可跳回。
35
+ - **输入框 chip 本体可点**:按 chip 的 `title`(= 插入时的 label)反查 ref,不依赖 CSS 类顺序。
36
+ - **诊断通道与自检工具**:`tools/diag-sink.mjs`(本地事件接收端)、`tools/check-manifest.mjs`(清单自检,已接入 CI)。
37
+ 插件的诊断上报在探测不到接收端时自动静默。
38
+
39
+ ### 已知限制
40
+
41
+ - chip 本体跳转按 `title` 反查,label 相同的多条引用只命中最早一条(导航条始终精确)。
42
+ - 目标消息行未加载时只给提示,不自动翻页。
43
+ - 回合尾部按钮在有交付文件的回合也会显示(上游会隐藏、让位给官方「已生成文件」chips)。
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wangwei-wade
4
+ Copyright (c) 2026 zhao-guang-ai and dsh-quote-annotate-pro contributors
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.en.md ADDED
@@ -0,0 +1,85 @@
1
+ # dsh-quote-annotate-pro
2
+
3
+ [![npm version](https://img.shields.io/npm/v/dsh-quote-annotate-pro?color=2ea44f&label=npm)](https://www.npmjs.com/package/dsh-quote-annotate-pro)
4
+ [![ci](https://github.com/zhao-guang-ai/dsh-quote-annotate-pro/actions/workflows/ci.yml/badge.svg)](https://github.com/zhao-guang-ai/dsh-quote-annotate-pro/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
6
+
7
+ **Select → annotate → quote, inside a DSH conversation.** The selected text enters the composer as an anchored quote reference; on send it serializes into a structured quote block, and a quote bar under the composer jumps back to the exact source message and highlights it. The model sees `【引用 · 第N轮 · DSH 回复】` — which turn, whose message — so it no longer has to guess what "that part above" means.
8
+
9
+ > An enhanced fork of [`dsh-quote-annotate`](https://github.com/wangwei-wade/dsh-quote-annotate) (MIT, by wangwei-wade).
10
+ > Upstream v0.1.1 **fails silently** on **DSH 0.2.0-rc.2** (loads without error, registers no UI at all). This fork fixes 4 compatibility
11
+ > problems, adapts 2 further interface changes, and adds 3 capabilities. Still MIT — see [LICENSE](./LICENSE).
12
+ > Full write-up: [SUMMARY.md](./SUMMARY.md) (Chinese).
13
+
14
+ ## Features
15
+
16
+ | Capability | Detail |
17
+ | --- | --- |
18
+ | Select & annotate | Select text in the transcript → a bubble appears above the selection → write a comment (optional) → `Enter` |
19
+ | Quote chip | An atomic `引用#1 · 第3轮 · DSH 回复` chip lands in the composer; it expands to the full quote block on send |
20
+ | **Quote bar** | A persistent bar under the composer (`引用 ❝ …`): click to jump back to the source and highlight it, hover to preview |
21
+ | **Turn-accurate context** | The quote block starts with `【引用 · 第3轮 · 你的消息】` followed by `> quoted text`, so the model knows exactly which turn and whose message |
22
+ | Turn-level quoting | Every finished turn gets `引用提问` / `引用回答` buttons that quote the whole question or answer |
23
+ | Anchors survive reload | The `ref → anchor` map is persisted in `localStorage` (per session, 60 entries max), so quotes still jump after a page refresh |
24
+
25
+ ## Install
26
+
27
+ ```sh
28
+ # from npm (recommended)
29
+ dsh plugin --profile <profile> add dsh-quote-annotate-pro
30
+
31
+ # from GitHub
32
+ dsh plugin --profile <profile> add github:zhao-guang-ai/dsh-quote-annotate-pro
33
+
34
+ # from a local clone (link install: edits apply instantly via HMR)
35
+ dsh plugin --profile <profile> add <absolute path to this repo>
36
+ ```
37
+
38
+ Verified on **DSH 0.2.0-rc.2**, desktop profile (Windows). A page reload (or an automatic client-HMR reload) is needed after installation.
39
+
40
+ ## How it works
41
+
42
+ ```
43
+ select text
44
+ │ bubble 「批注」→ editor → Enter
45
+ ▼
46
+ emit('slash/input-insert-reference', { reference, span }) ← official session-scoped event
47
+ │ the input machine mints one occurrence (source='quote-ref' / ref / label)
48
+ ▼
49
+ composer chip (an official Lexical decorator node)
50
+ │ on send, this plugin's codec serializes the ref
51
+ ▼
52
+ 【引用 · 第N轮 · 角色】
53
+ > quoted text
54
+ (comment)
55
+
56
+ jump back: quote bar / chip → [data-chat-anchor-key] row → scrollIntoView + highlight
57
+ ```
58
+
59
+ Official surfaces used: `slots` (`shell.overlay`, `conversation.chat.turnTail`, `conversation.input.dock`),
60
+ `conversation.input` (draft + occurrences), `sessions.binding` / `sessions.scope`,
61
+ `inputTriggers.registerSource` + codec, and the DOM anchors `data-chat-anchor-key` / `data-chat-turn` / `data-chat-flow-kind`.
62
+
63
+ ## Differences from upstream
64
+
65
+ **Compatibility fixes** (without these the plugin does nothing, silently):
66
+
67
+ 1. Missing `inject: ['slots']` — `apply()` returned early before the service was ready; now declares the dependency and reports each registration step.
68
+ 2. `conversation.chat.turnTail` became a **list** slot (was `chain`); the old `{ select, priority }` registration threw and aborted the 4 registrations after it.
69
+ 3. `input.insertReference(...)` no longer exists — quoting fell back to plain text; now uses the `slash/input-insert-reference` session event.
70
+ 4. `useSessions(s => s.current)` is always `undefined` in this version (the session-list snapshot has no `current` field) — clicking 「批注」 only closed the bubble. Now the session id comes from a session-scoped slot probe.
71
+
72
+ **Interface adaptations:** the turn-tail buttons read text from the **Chat snapshot** (`useChat`, `nodes` is a `Map`, identity is `anchorSeq`, assistant kind is `assistant-step`); composer chips have **no `data-*` attributes** any more, so the quote bar reads the official occurrence list instead.
73
+
74
+ ## Development
75
+
76
+ ```sh
77
+ npm run check # manifest self-check (package.json / patch / bundle registration id)
78
+ npm run diag # local diagnostics sink (http://127.0.0.1:47821)
79
+ ```
80
+
81
+ `lib/client.js` is a hand-written bundle (no build step) — edit and save; the client HMR reloads it. See [README.md](./README.md) (Chinese) for the diagnostics channel and known limitations.
82
+
83
+ ## License
84
+
85
+ MIT — see [LICENSE](./LICENSE). Upstream: [`wangwei-wade/dsh-quote-annotate`](https://github.com/wangwei-wade/dsh-quote-annotate) (MIT, © 2026 wangwei-wade).
package/README.md CHANGED
@@ -1,3 +1,159 @@
1
- # Temporary Holding Version
1
+ # dsh-quote-annotate-pro
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![npm version](https://img.shields.io/npm/v/dsh-quote-annotate-pro?color=2ea44f&label=npm)](https://www.npmjs.com/package/dsh-quote-annotate-pro)
4
+ [![ci](https://github.com/zhao-guang-ai/dsh-quote-annotate-pro/actions/workflows/ci.yml/badge.svg)](https://github.com/zhao-guang-ai/dsh-quote-annotate-pro/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
6
+
7
+ **在 DSH 会话里划词 → 批注 → 引用**:选中的文字变成带锚点的引用进入输入框,发送时序列化为结构化引用块;输入框下方常驻一条**引用导航条**,点一下就能跳回原文并高亮。多轮对话里,模型看到的是 `【引用 · 第N轮 · 你的消息】`,不再需要猜"你说的是哪一处"。
8
+
9
+ > 这是 [`dsh-quote-annotate`](https://github.com/wangwei-wade/dsh-quote-annotate)(MIT,作者 wangwei-wade)的增强 fork。
10
+ > 上游 v0.1.1 在 **DSH 0.2.0-rc.2** 上会**静默失效**(既不报错也不注册任何 UI),本 fork 修掉了 4 个兼容性问题,
11
+ > 并补上了 3 项能力;另有 2 个接口变化(当前会话、chip DOM 定位)一并适配。许可仍为 MIT,见 [LICENSE](./LICENSE)。
12
+ > 完整汇总见 [SUMMARY.md](./SUMMARY.md)。
13
+
14
+ ## 功能
15
+
16
+ | 能力 | 说明 |
17
+ |---|---|
18
+ | 划词批注 | 会话里选中任意文字 → 选区上方浮出气泡(预览 + 「批注」)→ 编辑框里写评语(可留空)→ `Enter` 插入 |
19
+ | 引用 chip | 输入框里出现 `引用#1 · 第5轮 · DSH 回复` 的原子 chip;发送时展开为完整引用块 |
20
+ | **引用导航条** | 输入框下方常驻 `引用 ❝ 引用#1 …`,**点击跳回原文并高亮**,悬停预览原文 |
21
+ | **模型侧精确定位** | 引用块首行是 `【引用 · 第5轮 · 你的消息】`,后接 `> 原文`,让模型明确知道**哪一轮、谁说的** |
22
+ | 回合级引用 | 每条已完成回合尾部有「引用提问 / 引用回答」,整段引用该轮 |
23
+ | 锚点持久化 | `ref → 锚点` 映射写入 `localStorage`(按会话,最多 60 条),**刷新页面后引用条仍能跳回原文** |
24
+ | 中英自适应 | 按钮文案跟随界面语言(沿用上游) |
25
+
26
+ ## 与上游的差异
27
+
28
+ ### 兼容性修复(否则整插件静默失效)
29
+
30
+ 1. **缺 cordis 依赖声明** —— 上游 `apply(ctx)` 里 `const slots = ctx.get('slots')`,拿不到就 `return`。
31
+ 没有声明 `inject: ['slots']` 时 `apply` 可能早于 slots 服务就绪执行,于是**无声退出,一个 UI 都不注册**。
32
+ → 本 fork 声明 `exports.name` + `exports.inject = ['slots']`,并给每一步注册加 `try/catch` + 上报。
33
+
34
+ 2. **`conversation.chat.turnTail` 已从 chain 变 list**(DSH 0.1.6-alpha.2 起)—— 上游仍用 `{ select, priority }` 注册,
35
+ 会抛错;而它排在 4 个 overlay 注册**之前**,一崩全崩。→ 改为 `{ name, id, order }`。
36
+
37
+ 3. **chip 插入 API 变了** —— 上游调用 `input.insertReference(...)`,该对象在本版本没有此方法,永远退化为纯文本。
38
+ → 改走官方会话事件 `slash/input-insert-reference`(与 `dsh-better-sidebar` 同一条在本版本已验证的通路)。
39
+
40
+ 4. **回合尾部按钮不出现(快照形状变了)** —— 上游用 `useSession` 的快照 + `Array.isArray(snapshot.nodes)` + 节点 `seq`
41
+ 来取该轮文本;本版本真实形状是 **Chat 快照(`useChat`)**、**`nodes` 是 Map**、**节点身份是 `anchorSeq`**、
42
+ 文本在 `user.data.content[{type:'text'}]` / `assistant-step.data.blocks[{kind:'text'}]`,
43
+ assistant 节点 kind 也不是 `assistant` 而是 `assistant-step`。→ 全部按本版本形状重写取文与锚点解析。
44
+
45
+ ### 能力增强
46
+
47
+ 5. **当前会话解析** —— 上游读 `useSessions(s => s.current)`,而**本版本会话列表快照没有 `current` 字段**(恒为 `undefined`),
48
+ 导致点「批注」只关掉气泡、什么都不发生。→ 改为由**会话作用域槽位**(`conversation.input.dock` 探针)回填 `sessionId`,
49
+ 并去掉"必须先解析到会话才开编辑框"的门槛(解析失败也照常进入编辑,插入时再解析)。
50
+
51
+ 6. **引用块带轮次/角色** —— 上游只发 `> 原文`。→ 首行加 `【引用 · 第N轮 · 角色】`(轮次取自 `data-chat-turn`,角色取自 `data-chat-flow-kind`)。
52
+
53
+ 7. **引用导航条 + 锚点持久化** —— 本版本输入框 chip **没有 `data-*` 属性**(只有 CSS 类),上游"点 chip 跳转"不可能成立。
54
+ → 改为读官方输入状态 `occurrences`(`source === 'quote-ref'`)渲染导航条;`ref → 锚点` 落 `localStorage`,刷新后仍可跳。
55
+ (输入框 chip 本体也支持点击跳转:按 `title` = label 反查 ref,不依赖 CSS 类顺序。)
56
+
57
+ ## 安装
58
+
59
+ ```sh
60
+ # 从 npm 安装(推荐,一步到位)
61
+ dsh plugin --profile <profile> add dsh-quote-annotate-pro
62
+
63
+ # 或直接从 GitHub 安装
64
+ dsh plugin --profile <profile> add github:zhao-guang-ai/dsh-quote-annotate-pro
65
+
66
+ # 本地开发:
67
+ # <本仓库绝对路径> 为克隆后的目录;link 安装后改文件即刻热更,无需重启
68
+ dsh plugin --profile <profile> add <本仓库绝对路径>
69
+ ```
70
+
71
+ 装好后 profile 的 `package.json` 会出现:
72
+
73
+ ```
74
+ "dsh-quote-annotate-pro": "link:<本仓库绝对路径>"
75
+ ```
76
+
77
+ ## 工作原理
78
+
79
+ ```
80
+ 选中文字
81
+ │ 气泡「批注」→ 编辑框 → Enter
82
+ ▼
83
+ emit('slash/input-insert-reference', { reference, span }) ← 官方会话事件,会话作用域
84
+ │ 输入机 mint 一条 occurrence(source='quote-ref' / ref / label)
85
+ ▼
86
+ 输入框 chip(官方 Lexical 装饰节点)
87
+ │ 发送
88
+ ▼
89
+ 本插件 codec.serialize(ref) → 完整引用块
90
+ 【引用 · 第5轮 · DSH 回复】
91
+ > 原文……
92
+ (你的评语)
93
+ ▼
94
+ 模型收到"哪一轮 + 谁说的 + 原文"
95
+
96
+ 跳回原文:导航条/锚点 → [data-chat-anchor-key] 行 → scrollIntoView + 高亮
97
+ ```
98
+
99
+ 用到的官方接口:`slots`(`shell.overlay` / `conversation.chat.turnTail` / `conversation.input.dock`)、
100
+ `conversation.input`(草稿 + occurrences)、`sessions.binding/scope`、`inputTriggers.registerSource` + codec、
101
+ DOM 锚点 `data-chat-anchor-key` / `data-chat-turn`。
102
+
103
+ ## 开发
104
+
105
+ ```
106
+ lib/client.js 全部功能(手写 bundle,无构建步骤 —— 改完保存即生效)
107
+ tools/diag-sink.mjs 本地诊断接收端(可选)
108
+ tools/check-manifest.mjs 清单一致性自检(CI 同款)
109
+ ```
110
+
111
+ ```sh
112
+ npm run check # 校验 package.json / patch / bundle 注册 id 是否一致
113
+ npm run diag # 起诊断接收端(默认 http://127.0.0.1:47821)
114
+ ```
115
+
116
+ 改完 `lib/client.js` **无需重启 DSH**:宿主按磁盘内容提供 bundle,客户端 HMR 检测到内容变化会自动热更该插件。
117
+
118
+ ### 诊断通道(开发期)
119
+
120
+ `lib/client.js` 顶部有:
121
+
122
+ ```js
123
+ const DIAG_ENABLED = true
124
+ const DIAG_URL = 'http://127.0.0.1:47821/dsh-quote-pro'
125
+ ```
126
+
127
+ 插件启动时 POST 一次 `/ping`;**探测不到接收端就本次运行静默**(不会产生网络噪音)。
128
+ 配合 `npm run diag`,终端会实时打出全链路事件:
129
+
130
+ ```
131
+ module:materialized / apply:start / register:ok … 插件加载与槽位注册
132
+ selection:show / selection:stage 划词与「批注」
133
+ insert:chip / insert:fallback-plaintext 引用插入(chip 或纯文本回退)
134
+ dock:rows / dock:click / jump:ok / toast 导航条与跳回原文
135
+ turnTail:render 回合尾部按钮取文
136
+ ```
137
+
138
+ 不需要时把 `DIAG_ENABLED` 改成 `false` 即可(`console.log('[quote-pro]', …)` 会保留)。
139
+
140
+ ## 已知限制
141
+
142
+ - **输入框 chip 本体跳转依赖 `title`**:本版本 chip 无 `data-*` 属性,是按渲染出的 `title`(= 插入时写入的 label)反查 ref;
143
+ label 相同的多条引用只会命中最早的一条(导航条则始终精确)。
144
+ - **跳转要求原文行在当前页面**:目标消息未加载(历史未翻到)时只能给出提示,不做自动翻页加载。
145
+ - **导航条在会话切换后重建**:锚点按会话存储;切到别的会话不会串。
146
+ - **回合尾部按钮在有交付文件的回合也会显示**:上游会隐藏、让位给官方「已生成文件」chips。
147
+ - **评语以纯文本追加在 chip 之后**:编辑 chip 文本请用 Backspace 删除。
148
+
149
+ ## 贡献
150
+
151
+ 欢迎 Issue / PR。提 PR 前请跑一遍 `npm run check`,并说明验证时使用的 DSH 版本(本仓库在 **0.2.0-rc.2** 上真机验证)。
152
+ 由于 DSH 仍处于 rc 阶段,内部契约可能随版本变化,改动请附上验证方式。
153
+
154
+ ## 许可与来源
155
+
156
+ MIT,见 [LICENSE](./LICENSE)。
157
+
158
+ - 上游:[`wangwei-wade/dsh-quote-annotate`](https://github.com/wangwei-wade/dsh-quote-annotate) v0.1.1(MIT,© 2026 wangwei-wade)
159
+ - 本 fork:修复其在 **DSH 0.2.0-rc.2** 上的 6 个兼容性问题,并补充引用定位相关能力,同样以 MIT 发布
package/SUMMARY.md ADDED
@@ -0,0 +1,143 @@
1
+ # dsh-quote-annotate-pro · 汇总
2
+
3
+ > 一份把"调研 → 选型 → 排障 → 改造 → 验证"全部收拢的文档。
4
+ > 环境:Windows 桌面版 **DSH 0.2.0-rc.2**,profile = `desktop`,GUI `http://127.0.0.1:19387`(`DSH_HOME` 视安装而定)。
5
+
6
+ ---
7
+
8
+ ## 1. 一句话
9
+
10
+ 在 DSH 会话里**划词 → 批注 → 引用**:选中的文字带锚点进入输入框,发送时序列化成结构化引用块;输入框下方常驻**引用导航条**,点一下跳回原文并高亮。多轮对话里模型看到的是 `【引用 · 第N轮 · 你的消息】`,精确知道"你说的是哪一处"。
11
+
12
+ ## 2. 现状速览
13
+
14
+ | 能力 | 状态 |
15
+ |---|---|
16
+ | 划词 → 浮出气泡 → 「批注」→ 编辑框 | ✅ 已验证 |
17
+ | 输入框内引用 chip(`引用#1 · 第N轮 · 角色`) | ✅ 已验证 |
18
+ | 输入框下方引用导航条:点击跳回原文 + 高亮 | ✅ 已验证(日志 `jump:ok`) |
19
+ | 悬停引用预览原文 | ✅ |
20
+ | 回合尾部「引用提问 / 引用回答」 | ✅ 已验证(4 个回合均取到文本) |
21
+ | 引用块带轮次/角色,模型侧精确定位 | ✅ 用户实际发送的引用消息为证 |
22
+ | 锚点刷新后仍可跳(localStorage) | ✅ 已实现(按会话,60 条上限) |
23
+ | 输入框 chip 本体点击跳转 | ✅ 按 `title` 反查 ref 实现 |
24
+
25
+ **上手 3 步**:① 消息里划词 → ② 点「批注」写评语(可留空)→ `Enter`;③ 点输入框下方引用条或回合尾部按钮跳回原文。
26
+
27
+ ## 3. 背景与调研
28
+
29
+ 需求:划词引用 + 多轮对话精准定位。先查市场,再查 GitHub:
30
+
31
+ | 候选 | 来源 | 能力 | 结论 |
32
+ |---|---|---|---|
33
+ | **dsh-quote-annotate** ★6 | [GitHub](https://github.com/wangwei-wade/dsh-quote-annotate) · npm `0.1.1` · MIT | 划词批注 + 锚点 chip + 点击跳回 + 回合级引用 | **选它做基础**(最贴合),但在本机静默失效 → fork |
34
+ | dsh-ui-quote-selection | [nekogpt](https://github.com/nekogpt/dsh-ui-quote-selection) · npm `0.1.0` · MIT | 选中即引用,走官方 codec,发送时展开全文 | 无回跳/批注,多轮定位弱 |
35
+ | dsh-selection-ask ★5 | npm `0.1.1` · MIT | 选中弹「Ask …」(ChatGPT 式) | 轻量,无锚点回跳 |
36
+ | dsh-sidenote ★10 | npm `0.4.5` | Codex 式侧聊 + 选区批注 | `engines: <0.2.0` → **不兼容本机** |
37
+ | dsh-plugin-quote-reply | npm `0.1.0` | 划词引用 / 新窗口回复 | peer 停在 `0.1.0-rc.6`,偏旧 |
38
+ | dsh-selection-quote | [cfyofjackie](https://github.com/cfyofjackie/dsh-selection-quote) · MIT | 选中即插入原子引用 | 未发 npm,0★ |
39
+
40
+ 市场侧:`deepseek1024.com` 目录(13,769 个插件)检索 `quote / 引用 / 选区` 命中上述多个;本机另装有 `dshmarket` 市场插件(其数据源 `awesome-dsh-plugin.com` 在本网络不可达)。
41
+
42
+ ## 4. 上游为什么在本机失效(6 个兼容性问题)
43
+
44
+ > 前两个会让插件**完全不报错地什么都不做**,这是"有气泡但点批注没用 / 没有按钮"的根源。
45
+
46
+ | # | 症状 | 真因 | 证据 | 修法 |
47
+ |---|---|---|---|---|
48
+ | 1 | 一个 UI 都不注册,且无报错 | `apply()` 里 `ctx.get('slots')` 拿不到就 `return`,但**未声明** `inject: ['slots']`,可能早于服务就绪执行 | 加 `exports.name`/`exports.inject=['slots']` 后立刻 `register:ok …` | 声明 cordis 依赖 + 每步 `try/catch` + 上报 |
49
+ | 2 | 后续 4 个 overlay 注册全不执行 | `conversation.chat.turnTail` 自 0.1.6-alpha.2 **由 chain 变 list**,上游仍用 `{select, priority}` 注册 → 抛错,而它排在 overlay 之前 | Inspect 显示该槽 `kind: "list"`,注册参数为 `id/order/label` | 改 `{name, id, order}` |
50
+ | 3 | 引用永远退化成纯文本、chip 不生成 | 调用 `input.insertReference(...)`,该对象在本版本**没有**此方法 | `probe:emit-ok {"viaScope":true,"draftRev":34}` | 改走会话事件 `slash/input-insert-reference`(`dsh-better-sidebar` 同款已验证通路) |
51
+ | 4 | 点「批注」只关掉气泡,什么都不发生 | 读 `useSessions(s => s.current)`,而**本版本会话列表快照没有 `current` 字段**(恒 `undefined`)→ `if (current)` 不成立 | `env:overlay-props {"keys":[…],"hasSessionId":false}`;社区插件 `dsh-better-sidebar` 源码注释明确记载该字段不存在 | 用**会话作用域探针**(`conversation.input.dock`)回填 `sessionId`;去掉"必须先有会话才开编辑框"的门槛 |
52
+ | 5 | 回合尾部「引用提问/回答」不出现 | 用 `useSession` 快照 + `Array.isArray(nodes)` + 节点 `seq` 取文本;本版本真实形状是 **Chat 快照(`useChat`)**、**`nodes` 是 Map**、身份字段 **`anchorSeq`**、assistant 节点 kind 是 **`assistant-step`**、文本在 `data.content[{type:'text'}]` / `data.blocks[{kind:'text'}]` | `turnTail:render {"turn":6,"userChars":48,"assistantChars":1734,…}` | 按本版本形状重写取文与锚点解析 |
53
+ | 6 | 「点输入框里的 chip 跳回」不可能成立 | 本版本 chip 的 DOM **没有 `data-occurrence`**(只有 CSS 类,`title` 是 label) | 在 conversation 客户端 bundle 中检索 `data-occurrence` 无匹配 | 主入口改为**引用导航条**;chip 本体按 `title` 反查 ref |
54
+
55
+ ## 5. 本 fork 的增强
56
+
57
+ 1. **引用块带位置**:首行 `【引用 · 第N轮 · 角色】`(轮次 ← `data-chat-turn`,角色 ← `data-chat-flow-kind`),解决"多轮里模型不知道指哪一处"。
58
+ 2. **当前会话解析**:会话作用域探针(dock 槽位)→ 右侧栏 `sidebarRight.mounted` 兜底。
59
+ 3. **引用导航条**:注册进 `conversation.input.dock`,读官方输入状态 `occurrences`(`source === 'quote-ref'`),点击跳回 + 高亮 + 悬停预览。
60
+ 4. **锚点持久化**:`ref → {anchorKey, body, label}` 写入 `localStorage`(`dsh-quote-pro:ref:<sessionId>`,60 条上限),刷新后仍可跳。
61
+ 5. **输入框 chip 本体可点**:按 `title`(= 插入时的 label)反查 ref,不依赖 CSS 类顺序。
62
+ 6. **诊断通道**:启动 `POST /ping`,探测不到接收端则本次运行静默(避免网络噪音);`DIAG_ENABLED=false` 可彻底关闭。
63
+
64
+ ## 6. 实现要点
65
+
66
+ ```
67
+ 划词 → 气泡「批注」→ 编辑框 → Enter
68
+ ▼
69
+ emit('slash/input-insert-reference', { reference, span }) ← 会话作用域事件
70
+ ▼ 输入机 mint 一条 occurrence(source='quote-ref' / ref / label)
71
+ 输入框 chip(官方 Lexical 装饰节点)
72
+ ▼ 发送时本插件 codec.serialize(ref)
73
+ 【引用 · 第N轮 · 角色】
74
+ > 原文……
75
+ (你的评语)
76
+
77
+ 跳回:导航条/chip → [data-chat-anchor-key] 行 → scrollIntoView + .dshq-flash 高亮
78
+ ```
79
+
80
+ 用到的官方接口:`slots`(`shell.overlay` / `conversation.chat.turnTail` / `conversation.input.dock`)、
81
+ `conversation.input`(草稿 + occurrences)、`sessions.binding` / `sessions.scope`、
82
+ `inputTriggers.registerSource` + codec、DOM 锚点 `data-chat-anchor-key` / `data-chat-turn` / `data-chat-flow-kind`。
83
+
84
+ 槽位占用(`Slots` Inspect 实测均为 `active: true`):
85
+ `shell.overlay`:`quote-pro-selection-toolbar` / `quote-pro-annotation-editor` / `quote-pro-feedback-toast` / `quote-pro-tooltip`;
86
+ `conversation.chat.turnTail`:`quote-turn-actions`;`conversation.input.dock`:`quote-pro-session-probe` / `quote-pro-quote-dock`。
87
+
88
+ ## 7. 验证记录(诊断日志实测)
89
+
90
+ ```
91
+ session:resolved {"via":"dock-probe"} ← 会话解析成功
92
+ probe:emit-ok {"viaScope":true,"draftRev":34} ← chip 插入通路(零副作用探针)
93
+ insert:chip {"header":"【引用 · 第6轮 · DSH 回复】","chars":26} ← 引用块带位置
94
+ dock:rows {"count":1} → dock:click → jump:ok → toast ok | 已跳转到原文 ✓ ← 跳回全链路
95
+ turnTail:render {"turn":4..7,"userChars":11/2/48/7,"assistantChars":844/1219/1734/94} ← 回合按钮取文
96
+ ```
97
+ 用户实际发送的引用消息(模型侧可见):
98
+ `【引用 · 第2轮 · DSH 回复】` / `【引用 · 第6轮 · DSH 回复】`。
99
+
100
+ ## 8. 文件与安装
101
+
102
+ ```
103
+ dsh-quote-annotate-pro/
104
+ ├── lib/client.js 全部功能(手写 bundle:window.__ModuleLoader__.load 工厂式 CJS,无构建步骤)
105
+ ├── lib/index.js Host 半区空占位
106
+ ├── cordis.patch.yml 插入 Loader 行 quote-annotate-pro
107
+ ├── package.json dsh.bundle.patch + dsh.client{platform:'web'}
108
+ ├── tools/diag-sink.mjs 本地诊断接收端(开发期可选)
109
+ ├── README.md 功能 / 与上游差异 / 原理 / 诊断开关 / 已知限制
110
+ ├── SUMMARY.md 本文档
111
+ └── LICENSE MIT(保留上游 wangwei-wade 署名)
112
+ ```
113
+
114
+ 安装(本机开发时为 `link:` 方式 → **改文件即热更,无需重启**):
115
+
116
+ ```
117
+ <profile>/package.json
118
+ "dsh-quote-annotate-pro": "link:<本仓库绝对路径>"
119
+ ```
120
+
121
+ 卸载:`插件管理器 remove_bundle dsh-quote-annotate-pro`。上游 `dsh-quote-annotate` 已从 profile 卸载。
122
+
123
+ ## 9. 已知限制
124
+
125
+ - 输入框 chip 跳转按 `title` 反查,label 相同只会命中最早一条(导航条始终精确)。
126
+ - 跳转要求目标消息行在当前页面;未加载的历史只给提示,不自动翻页。
127
+ - 回合尾部按钮现在**总是显示**(上游在有交付文件的回合会隐藏,让位给官方「已生成文件」chips)。
128
+ - 评语以纯文本追加在 chip 之后;删 chip 用 Backspace。
129
+
130
+ ## 10. 可继续做
131
+
132
+ 1. **发送后的引用也能点**:在 transcript 里识别 `【引用 · 第N轮 · …】` 块,点击跳回该轮。
133
+ 2. **跨会话跳转**:锚点已按会话存储,可扩展到"切到目标会话并定位"。
134
+ 3. **自动翻页加载**:目标轮次未加载时调用 `loadThrough` / `loadOlder` 后再定位。
135
+ 4. 回合尾部按钮恢复"有交付文件时隐藏"的上游语义。
136
+
137
+ ## 附:时间线(本次会话)
138
+
139
+ 1. 调研市场 + GitHub,确认已有同类插件 → 选 `dsh-quote-annotate` 装进 desktop profile。
140
+ 2. 发现"装了但毫无反应" → 用本地诊断接收端 + 自研上报确认插件**加载了却没注册任何 UI**。
141
+ 3. fork 出 `dsh-quote-annotate-pro`,逐个修复 6 个兼容性问题(上表)。
142
+ 4. 补齐 6 项增强,并把诊断从"临时排查"固化为"探测不到即静默"的通道。
143
+ 5. 用户实测:划词→批注→chip→导航条跳回→发送后引用块 全链路通过;回合尾部按钮修复后取文正常。
@@ -0,0 +1,4 @@
1
+ # dsh-quote-annotate-pro:插入插件行(跟随 bundle 安装到任意 profile)
2
+ - insert:
3
+ - id: quote-annotate-pro
4
+ name: dsh-quote-annotate-pro