dsh-find-in-session 0.0.0-stage → 0.1.4

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,64 @@
1
+ # Changelog
2
+
3
+ ## 0.1.4 — 2026-11-01
4
+
5
+ - Replaced the single-glyph `当 / 全` scope button with a labelled segmented
6
+ control on its own row under the bar: `范围 [仅当前视图] [含已替换]`. The bar now
7
+ only carries fixed-size controls, so no text can be squeezed inside it, and the
8
+ wording explains itself instead of relying on a tooltip.
9
+ - Each segment carries its own tooltip that matches its label, and the control is
10
+ a `role="radiogroup"` with `aria-checked`, so the state is exposed to assistive
11
+ technology as well.
12
+ - Result header no longer repeats an empty state: with zero history hits the
13
+ header itself reads `全部历史中没有命中`; the count slot shows a short `无命中`
14
+ instead of a full sentence.
15
+ - Screenshot of the verified layout: [docs/panel.png](docs/panel.png).
16
+
17
+ ## 0.1.3 — 2026-11-01
18
+
19
+ - Scope toggle moved out of the text-button shape entirely: the bar now carries a
20
+ fixed `26x26` button with a single CJK glyph (`当` / `全`, English `C` / `A`), and
21
+ the readable wording (`仅当前视图` / `含已替换`) is a chip in the results header,
22
+ where the row has width to spare. A single character in a fixed box cannot wrap,
23
+ shrink, or clip regardless of host CSS.
24
+ - Measured in the real GUI at a 504px viewport: button `26x26`,
25
+ `scrollWidth == clientWidth`, bar has no overflow, header chip `66x17` unclipped;
26
+ toggling flips glyph and chip together.
27
+
28
+ ## 0.1.2 — 2026-11-01
29
+
30
+ - Fix the scope toggle label being clipped (`当前范围` / `含已替换` rendered
31
+ incomplete). The text button is now `flex: 0 0 auto` with
32
+ `min-width: max-content`, `white-space: nowrap`, `overflow: visible` and an
33
+ explicit `line-height`, so no host reset or tight bar can squeeze it; the count
34
+ label is `nowrap` too.
35
+ - Below a 330px viewport the scope button falls back to a two-character label
36
+ (`当前` / `全部`, tooltip keeps the full explanation), and a runtime box
37
+ measurement drops to that form if any host rule still squeezes the label.
38
+ Measured in the real GUI at 1264 / 380 / 320px: `scrollWidth == clientWidth`
39
+ and the bar never overflows.
40
+ - The panel re-renders on window resize so the label form tracks the width.
41
+
42
+ ## 0.1.1 — 2026-11-01
43
+
44
+ - Default search scope is `surface: current` (what the transcript renders); the
45
+ panel's scope button switches to `含已替换 / all events` for replaced or
46
+ compacted history. Measured on a 4.28 MB session: 143 hits / 108 ms instead of
47
+ 724 hits / 131 ms, with the first hit actually locatable in the view.
48
+ - `/ping` is now a self-diagnosis endpoint: `ready` plus
49
+ `client.{registered,path,bootListed,activated,hello,opens,lastOpen}`.
50
+ - The browser half beacons once on activation and once per find-bar open
51
+ (`POST /dsh-find-in-session/client-hello`), so "Ctrl+F does nothing" can be
52
+ narrowed to boot-graph / page-load / activation / shortcut without DevTools.
53
+ - `apply()` and both slot registrations are individually guarded: a failure can
54
+ no longer take down the client plugin group.
55
+ - Dropped `dsh.client.inject` (only baseline `react` is required, matching
56
+ `dsh-widgets` / `dsh-quick-ask`).
57
+ - Added `scripts/ui-probe/`: dependency-free CDP harness that verifies the find
58
+ bar, highlights and the full-history jump in a real Chromium.
59
+
60
+ ## 0.1.0 — 2026-11-01
61
+
62
+ - First cut: host `/dsh-find-in-session/{ping,search}` over
63
+ `ctx.sessionQuery.filterEvents`, Ctrl+F find bar with CSS Custom Highlight
64
+ painting, debounced full-history list, `loadThrough(seq)` paging jump.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Abraham
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,150 @@
1
- # Temporary Holding Version
1
+ # dsh-find-in-session
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
+ **DeepSeek Harness 会话内搜索插件 —— Ctrl+F 查找条 + 全历史检索 + 点击跳到那条消息。**
4
+
5
+ DSH 桌面端(Electron 外壳)没有接 `findInPage`,所以长会话里按 `Ctrl+F` 没有任何反应,只能靠肉眼滚。这个插件把「在会话中查找」补回来,两段式工作:
6
+
7
+ 1. **即时命中** —— 扫描已渲染的转写文本节点,用 CSS Custom Highlight API 高亮全部命中(不改 DOM,React 重渲染与流式输出都不受影响),`Enter` / `Shift+Enter` 逐条跳转。
8
+ 2. **全历史命中** —— 去抖后调用宿主路由 `/dsh-find-in-session/search`,由 `ctx.sessionQuery.filterEvents()` 扫描**整段事件日志**(含尚未翻页加载的早期历史),列出带时间与角色的命中片段;点一条就用会话自己的 `loadThrough(seq)` 翻页到那条事件,再滚动并闪一下对应正文。
9
+
10
+ ![查找条](docs/panel.png)
11
+
12
+ ## 安装
13
+
14
+ 从 npm:
15
+
16
+ ```sh
17
+ dsh plugin --profile desktop add dsh-find-in-session
18
+ # Web 端:dsh plugin --profile web add dsh-find-in-session
19
+ ```
20
+
21
+ 直接从仓库:
22
+
23
+ ```sh
24
+ dsh plugin --profile desktop add github:<owner>/dsh-find-in-session
25
+ ```
26
+
27
+ 装完**完全退出并重启** DSH Desktop —— 浏览器半需要重新载入模块清单。
28
+
29
+ <details>
30
+ <summary>从源码本地安装(插件开发用)</summary>
31
+
32
+ ```powershell
33
+ pwsh -File .\scripts\install.ps1 # 以 link: 方式装进 desktop profile;应用需先退出,或加 -Force
34
+ pwsh -File .\scripts\install.ps1 -Uninstall
35
+ ```
36
+
37
+ 脚本只做两件事:`pnpm add link:<插件目录>`,再把包名追加到 `<profile>/package.json` 的 `dsh.profile.bundles`。
38
+
39
+ </details>
40
+
41
+ ## 自检
42
+
43
+ ```powershell
44
+ # 端口取当前 GUI 地址(桌面端窗口 URL / 设置里可见)
45
+ curl http://127.0.0.1:<port>/dsh-find-in-session/ping
46
+ # {"ok":true,"plugin":"dsh-find-in-session","ready":true,
47
+ # "client":{"registered":true,"path":".../lib/client.js","bootListed":true,
48
+ # "activated":true,"hello":{...},"opens":1,"lastOpen":{...}}}
49
+ ```
50
+
51
+ | 字段 | 含义 |
52
+ |---|---|
53
+ | `ready` | 本 profile 的 `ctx.sessionQuery.filterEvents` 可用(出厂组合都可用;`openAt: never` 也能读,只是不做 FTS 排序) |
54
+ | `client.registered` | 模块系统解析到了本包的 `./client` 产物 |
55
+ | `client.bootListed` | 启动图(boot graph)里已列出本包 —— 页面重开/刷新即可执行 |
56
+ | `client.activated` | 浏览器半**真的执行了 `apply()`**:激活时 POST 一次 `/dsh-find-in-session/client-hello`,宿主记录时间、URL、UA、Highlight 支持情况;`client.hello` 就是那份报文 |
57
+ | `client.opens` / `client.lastOpen` | 查找条被打开的次数与最近一次的触发方式(`shortcut` / `button`) |
58
+ | `client.error` | 模块系统查询抛错时的信息 |
59
+
60
+ 这四个 `client.*` 字段合起来,能把「Ctrl+F 没反应」定位到唯一一段:启动图没收录 / 页面没加载 / 加载了但激活失败 / 激活了但快捷键被吞。
61
+
62
+ ## 使用
63
+
64
+ | 操作 | 效果 |
65
+ |---|---|
66
+ | `Ctrl+F`(macOS `Cmd+F`) | 打开/聚焦查找条(会话头部也有放大镜按钮) |
67
+ | 输入关键词 | 即时高亮当前视图全部命中,下方异步出现「全部历史命中」列表 |
68
+ | `Enter` / `Shift+Enter` | 下一处 / 上一处(无视图内命中时在全历史命中间跳) |
69
+ | 点击历史命中 | 翻页加载到该事件、滚动定位并闪烁 |
70
+ | `范围 [仅当前视图] [含已替换]` | `仅当前视图` = 只搜转写里显示的正文(`surface: current`,默认);`含已替换` = 连被改写、压缩掉的旧事件一起搜。两段各带匹配的 tooltip |
71
+ | `Esc` | 关闭查找条并清除高亮 |
72
+
73
+ 实测(4.28 MB 会话,查 `error`):默认范围 108 ms / 143 处,首条命中是可见的 `assistant/message`;改成「含已替换」则 131 ms / 724 处,首条是 `shadowed` 的 `tool/result`(视图里根本不显示,点了也定位不到)—— 这就是默认收窄范围的原因。
74
+
75
+ ## 兼容性
76
+
77
+ - `dsh.engines.dsh`:`>=0.1.7-rc.1`(宽区间,与生态里其它插件一致)
78
+ - 实测宿主:`0.2.1-rc.5`(桌面端 Electron 44 / Chrome 152)
79
+ - **降级行为**:若宿主没有 `ctx.sessionQuery.filterEvents`,`/search` 返回 `503 unavailable`,客户端自动退化为「只搜已渲染转写」,不会崩、不会拦启动。
80
+
81
+ ## 设计取舍
82
+
83
+ - **不改宿主、不加依赖**:全历史扫描走 `filterEvents()`,它是 provider-independent 的字面量扫描(`text` 子句大小写不敏感、空白弹性),所以**不需要**挂 `dsh-session-query-sqlite` 的 FTS、不需要建索引库,也不与官方 `dsh-experimental-session-search` 抢服务。
84
+ - **高亮用 CSS Custom Highlight API**:不给文本节点套 `<mark>`,避免与 React 重渲染、流式增量、代码块复制打架;宿主不支持该 API 时退化为「只滚动不染色」。
85
+ - **定位靠文本而不是事件键**:DSH 的 Chat 没有公开「按事件跳转」的 API,但 DOM 上有 `[data-chat-flow]` / `[data-chat-node-key]`。插件用命中片段里最长的词在 DOM 里二次匹配,配合 `loadThrough(seq)` 翻页;找不到时再点转写自己的「加载更早」,最多 14 轮。
86
+ - **只在本机可用**:宿主路由与其它 DSH 本机路由一致,做回环 socket + 回环 Host 头 + 同源三道校验,隧道/局域网客户端一律 403。
87
+ - **条栏里不放多字文本**:查找条只承载输入框、计数、`↑`/`↓`/`✕` 这类定尺寸控件;「范围」放在条下方独立一行,靠 flex-wrap 换行而不是挤压。
88
+
89
+ ## 验证记录
90
+
91
+ 在本机 `0.2.1-rc.5` 上实测(2026-11-01):
92
+
93
+ | 检查 | 结果 |
94
+ |---|---|
95
+ | 桌面端真机 | `activated=true`、`version=0.1.4`、`highlight=true`、`opens=2 via=button` |
96
+ | 宿主路由存活 | `GET /dsh-find-in-session/ping` → `{"ok":true,"ready":true}` |
97
+ | 真实会话检索 | 本会话搜 `findInPage` → `total=8`,命中带 `seq / type / surface / snippet`(`surface` 能区分 `current` 与 `log-only`) |
98
+ | 浏览器半被收录 | 另起 `dsh web`(临时挂载后已卸载):`client.registered=true`、`client.bootListed=true` |
99
+ | 浏览器半真的下发 | 页面启动图里出现预载行 `plugins/??...,dsh-find-in-session/client.js,...&rev=...`;抓该 combo 路由 → `200 text/javascript`,内容含 `dsh-find-in-session-anchor`、`conversation.input.overlay` 与中文文案 |
100
+ | 改文件后自动重算 | 改 `lib/client.js` → 图里的 `rev` 按 mtime 变化并推给页面 |
101
+ | 真实 Chromium 激活 | 无头 Chrome 156:`activated=true`、`hello.userAgent=HeadlessChrome/156`、`highlight=true`;合成 `ctrl+f` → 面板 `data-open=true`、焦点在输入框、宿主 `opens=1 via=shortcut` |
102
+ | 高亮与逐条跳转 | 注入 2 处关键词的转写:计数 `1/2`、`CSS.highlights` 里 2 个 Range、上下切换 `1/2 -> 2/2 -> 1/2` 回绕 |
103
+ | 全历史命中 + 翻页定位 | 打开真实会话(转写 2,282 字符)搜 `chrome`:视图内 `1/9`、宿主回报 19 处;点第 1 条 → 转写涨到 8,927 字符(`loadThrough` 生效)、滚动 `0 -> 5847`;点最后一条 → 该行 `data-active=true` |
104
+ | 面板布局 | 504px 视口下:面板 442×106,两段按钮 `75×21` / `64×21`,`scrollWidth == clientWidth`,面板无横向溢出 |
105
+ | 单元测试 | `node --test --test-isolation=none "test/*.test.js"` → 21 pass |
106
+
107
+ 浏览器侧验证可复现:起一个临时 `dsh web`(把本插件临时挂到某个 profile),用无头 Chrome 打开它,再跑:
108
+
109
+ ```powershell
110
+ pwsh -ExecutionPolicy Bypass -File .\scripts\ui-probe\run-fixture-check.ps1 -PageWs ws://127.0.0.1:<debug-port>/devtools/page/<id>
111
+ pwsh -ExecutionPolicy Bypass -File .\scripts\ui-probe\run-jump-check.ps1 -PageWs <同上> -PingUrl http://127.0.0.1:<port>/dsh-find-in-session/ping
112
+ ```
113
+
114
+ `scripts/ui-probe/` 是一个零依赖的最小 CDP 客户端(`cdp.ps1`)+ 若干被测页面片段(`step-search.js` 触发 `ctrl+f` 并输入、`step-read.js` 读回面板状态、`open-session.js` 打开真实会话),不引入 Playwright/Puppeteer。
115
+
116
+ ## 开发注意
117
+
118
+ 1. `lib/client.js` 刻意保持**纯 ASCII**(中文文案写成 `\uXXXX` 转义)。它曾被 PowerShell 5.1 的 `Get-Content -Raw` + `Set-Content`(按 ANSI 读 UTF-8)往返一次,中文与 `↑ ↓ ✕ …` 全部变乱码并导致 `SyntaxError`。纯 ASCII 源码对任何编辑路径免疫。
119
+ 2. **CSS 模板字符串里不能出现反引号**:在 CSS 注释里给 button 加反引号会截断模板串,插件随之激活失败(`/ping` 里会看到 `activated:false`)。这个坑踩过两次。
120
+ 3. 宿主插件代码**不热重载**:改 `lib/index.js` 必须重启应用;`lib/client.js` 也要重新载入页面。模块系统会按 mtime 重算 `rev` 并推给页面,但旧宿主进程里的路由仍是旧代码。
121
+
122
+ ## 已知限制
123
+
124
+ - 全历史检索是**字面量短语**匹配,不是 FTS5 排序检索;结果按事件顺序,不按相关度。
125
+ - 命中上限 50 条(路由接受 `limit` 至 200),超出时列表标「仅显示前若干条」。
126
+ - 折叠(fold)状态下的行仍可被命中并展开父级折叠,但不会自动展开每一层嵌套折叠。
127
+ - 侧边栏搜索的行为不受影响(本插件只服务会话内查找)。
128
+ - 依赖 `ctx.sessionQuery.filterEvents` 与客户端 `session.loadThrough`;缺失时的降级行为见「兼容性」。
129
+
130
+ ## 测试
131
+
132
+ ```powershell
133
+ node --test --test-isolation=none "test/*.test.js" # 21 pass(DSH 沙箱内必须带 --test-isolation=none)
134
+ node --test "test/*.test.js" # 普通环境
135
+ ```
136
+
137
+ 零依赖:覆盖字面量编译、片段窗口、上限与 surface 过滤,宿主路由的守卫/校验/错误码/正常返回,以及浏览器半在 stub DOM 下的 factory → exports → apply → 两处 slot 注册 + 激活探针。
138
+
139
+ ## 文件
140
+
141
+ | 路径 | 作用 |
142
+ |---|---|
143
+ | `lib/index.js` | 宿主半:`/dsh-find-in-session/{ping,search,client-hello}`,三道本机校验,调用 `ctx.sessionQuery.filterEvents()` 并拼装片段 |
144
+ | `lib/text.js` | 与宿主 session-query 语义一致的字面量编译与片段构造(纯函数) |
145
+ | `lib/client.js` | 浏览器半:Ctrl+F 查找条、Highlight 染色、全历史列表、`loadThrough` 翻页定位、自检探针 |
146
+ | `cordis.patch.yml` | 插入宿主插件行 |
147
+ | `scripts/install.ps1` | 以 `link:` 方式装进 profile(本地开发) |
148
+ | `scripts/ui-probe/` | 无头浏览器验证工具(CDP 客户端 + 页面片段) |
149
+
150
+ MIT
@@ -0,0 +1,8 @@
1
+ # dsh-find-in-session bundle layer.
2
+ #
3
+ # Inserts the host plugin row. The host half serves /dsh-find-in-session/* over
4
+ # the loopback web server; the browser half (exports "./client") mounts the
5
+ # Ctrl+F find bar. No configuration is required.
6
+ - insert:
7
+ - id: dsh-find-in-session
8
+ name: 'dsh-find-in-session'
package/docs/panel.png ADDED
Binary file