dsh-session-search
只想要“照着做一遍”的封装版本(含安装、配置与排错表),见同名技能包 dsh-session-search;本仓库是代码本体。
让 DSH Web 左侧边栏的搜索框搜索范围由你自己定:时间范围(全部 / 最近 N 天)与搜索内容(我说的话 / DSH 的回复 / 项目名)都在搜索结果上方可改;选择存进官方设置文档,重开浏览器、重启 DSH 之后仍然是上次的选择。命中片段显示两行原文。
- 宿主半边
lib/index.js:按「范围对象」改写侧边栏搜索的过滤条件(时间范围 + 内容来源),并把范围接到官方设置服务ctx.settings上。 - 客户端半边
lib/client.js:在搜索结果上方给一个「范围」控件;命中片段从单行省略改成两行;把官方那条归因不准的提示换成带当前范围的说明。 - 组合行
cordis.patch.yml:挂载本插件,并把官方全文索引打开(见下)。
为什么原来搜不到内容
DSH 的侧边栏搜索链路是:
搜索框 → 客户端 sessions.search → 远程 session.search → 宿主 SessionController.search
→ ctx.sessionQuery.searchSessions(...) → 官方 SQLite FTS5 全文索引
官方全文索引(@deepseek-ai/dsh-session-query-sqlite)在 web 组合里是可选能力,
@deepseek-ai/dsh-web-app 把它那一行固定成 path: ':memory:' + openAt: never:
openAt: never… while search calls fail withSESSION_QUERY_SEARCH_DISABLEDand SQLite is never opened; the Web sidebar search matches titles and workspace names only.
所以搜索框只能匹配名称;输关键词时页面还会在结果下方提示「内容搜索暂不可用,仅显示名称匹配」——
这句话把原因归到「只能按名称匹配」,但真实原因通常是索引还没建好。本插件随后会把它换成说真话的提示。
要开内容搜索,官方给的做法就是在更靠后的补丁层(profile 的 cordis.patch.yml)覆盖这一行的 openAt。
本插件做了什么
开索引(profile 的
cordis.patch.yml,本插件的安装步骤之一):- id: session-query-sqlite config: path: '<DSH_HOME>\profiles\web\session-search.db' openAt: first-searchopenAt: first-search= 不在启动时开库,第一次搜索才建索引(Node 22 启动保持安静)。 索引是独立的派生库,只读会话日志、绝不写回;删掉这个文件即完全重建。按范围改写过滤器(
lib/index.js):在ctx.sessionQuery上包一层searchSessions。 官方调用方原本发的是「user/message+assistant/message+current表层」, 本插件丢掉它的type与time两条,换成当前范围给出的:过滤器 值 作用 surfacecurrent只看当前模型表层,忽略被替换的历史 typeuser/message/assistant/message(按勾选,可同时)决定搜「我说的话」「DSH 的回复」还是两者 timefrom= 当地今天 00:00 往前 N-1 天只看最近 N 天;范围为「全部」时不注入这条 三种内容来源一个都不勾(例如「只看项目名」)时,正文检索没有意义:宿主直接回一个空页, 不调用官方索引,侧边栏于是只展示它自己的名称匹配结果。
窗口取「整天边界」而不取
now - N×24h:语义上就是「最近 N 天(含今天)」, 且同一天内取值恒定 ——searchSessions的分页游标绑定的是规范化后的确切请求, 逐次漂移会让翻页被判成SESSION_QUERY_STALE_CURSOR。query/limit/cursor原样透传,返回值不变,命中片段由官方索引给出。范围可改、选择可留存(
lib/client.js+lib/index.js):范围对象有默认值和用户选择两层。 默认值来自上面的组合行 config;用户在下拉面板里改的选择走官方设置服务ctx.settings(命名空间session-search),存进settings.yaml:session-search: days: 7 user: true assistant: true project: true所以改完立即生效(不需要重启),重开浏览器、重启 DSH 之后仍然是这份选择。 设置服务不在时自动退回浏览器
localStorage,面板底部会如实说明。两行片段(
lib/client.js):官方结果行把片段渲染成单行省略 (white-space:nowrap; text-overflow:ellipsis),这里补一条样式改成两行。 选择器用[class*="searchResultSnippet"](class 哈希前缀随构建变化、局部名稳定), 写成双属性选择器是为了抬特异性,避免依赖样式插入顺序。移除本文件里的css数组即恢复单行。索引预热(可选,默认开):索引是「首次搜索才建」, 会话日志积累得多时,第一次搜索要一次性为全部历史建索引(之后只增量对账)。 预热把这段时间挪到后台:启动后延迟
prewarmDelayMs(默认 45 秒)跑一次不可能命中的搜索, 失败静默忽略。不想要就设prewarm: false。
搜索范围怎么改
搜索框在侧边栏展开、并且输入了关键词时,搜索结果上方会出现一条「范围」控件,右边实时显示当前范围与命中情况:
- 点搜索图标展开侧边栏搜索框,随便输一个关键词;
- 点结果上方的「范围」,面板里两组开关:时间范围(全部 / 1 天 / 3 天 / 7 天 / 30 天 / 自定义天数) 与搜索内容(我说的话 / DSH 的回复 / 项目名);
- 点一下立即生效,不用回车、不用重启;面板右下角会说明设置写到哪里;
- 「项目名」这一项管的是会话名 / 工作区名的名称匹配(由官方侧边栏自己完成): 勾上=名称命中照常出现;取消=只保留正文命中的结果行。它是名称匹配开关,不是工作目录过滤。
- 结果为空时提示会带上当前范围(例如「当前范围(最近 3 天 · 我说的话)内没有命中」), 索引还没建好时的提示会说明真实原因,而不是让你以为只能搜名称。
配置项(组合行 config)
| 字段 | 默认 | 含义 |
|---|---|---|
days |
3 |
时间范围天数(含今天);0 = 不限时间(全部历史) |
user |
true |
搜我说的话 |
assistant |
false |
搜 DSH 的回复 |
project |
true |
名称匹配开关(会话名 / 工作区名) |
userOnly |
无 | 1.0.0 的旧写法:true ≈ user: true, assistant: false;false ≈ 两者都 true |
prewarm |
true |
启动后在后台预热一次全文索引 |
prewarmDelayMs |
45000 |
预热延迟毫秒 |
安装
下文把 DSH 的配置目录记作 <DSH_HOME>:设过环境变量 DSH_HOME 就用它,
否则是 %USERPROFILE%\.dsh;profile 名以 web 为例。本仓库的检出目录记作 <REPO>。
安装三步,改完重启 dsh web 生效:
让插件出现在 profile 的
node_modules里:<DSH_HOME>\profiles\web\node_modules\dsh-session-search。 Windows 上可以用 junction(不占额外空间,改仓库里的文件即刻生效):$home = if ($env:DSH_HOME) { $env:DSH_HOME } else { Join-Path $env:USERPROFILE '.dsh' } $modules = Join-Path $home 'profiles\web\node_modules' New-Item -ItemType Directory -Force -Path $modules | Out-Null New-Item -ItemType Junction -Path (Join-Path $modules 'dsh-session-search') -Target '<REPO>'换成普通的目录副本同样可以:只要上面那个路径下能看到本仓库的内容即可。
profile 的
package.json:dsh.profile.bundles加dsh-session-search,dependencies加"dsh-session-search": "link:<REPO>"(<REPO>写成正斜杠路径)。profile 的
cordis.patch.yml:加开索引那一行(上面「本插件做了什么」第 1 点)。
回滚
删掉上面三处即可(插件行随 bundle 一起消失;开索引那行删掉后搜索回到「只匹配名称」)。
已有的选择存在 settings.yaml 的 session-search: 分节里,不需要了连同这个分节一起删;
索引文件 <DSH_HOME>\profiles\web\session-search.db 可直接删除,下次搜索自动重建。
测试
零依赖,不需要 DSH 在运行、不需要联网:
node test.mjs # 汇总入口:语法检查 + 两个验证台 + 文档一致性 + 仓库卫生
node tools/verify-host.cjs # 宿主半边离线验证台
node tools/verify-client.cjs # 客户端半边离线验证台
node test.mjs 会跑 node --check、上面两个验证台,再核对 README 的配置表字段与
lib/index.js 一致、README 与 README.en.md 结构对齐、package.json / LICENSE /
CHANGELOG.md 的字段与列出的文件齐备。
两个验证台各自造桩:不连真实会话库、不读 profile、不写任何文件。
tools/verify-host.cjs(78 项):过滤器改写、字段透传、时间范围边界(含「全部」)、 内容来源组合、只看项目名的短路、旧配置兼容、范围归一化边界、设置 schema 与接线、卸载精确还原、 无服务时静默跳过、预热定时器登记与清理。tools/verify-client.cjs(62 项):bundle 注册与inject声明、零require、样式标记与去重键、 四条关键样式规则、范围控件落位与文案、改范围三处落地(本地 /localStorage/ 设置服务)、 两种 body 类开关、设置就绪与不可用两条路径、DOM 变化降频与卸载还原。
这三条命令就是 CI 里跑的全部内容。
许可
MIT。插件本身可自由取用。
DSH 本体与官方全文索引(@deepseek-ai/dsh-session-query-sqlite、@deepseek-ai/dsh-web-app 等)
属上游项目,遵循各自的许可。
No comments yet. Be the first to write one.