Back to home

sunshaobei

dsh-file-mention

支持dsh @引用文件及文件夹

Stars
0
Language
JavaScript
Created
Aug 16, 2026
Updated
Aug 16, 2026

Introduction

dsh-file-mention

Codex 式 @ 文件引用,DeepSeek Harness (DSH) Web 插件。

三个能力,全部挂在官方扩展点上,不改动 DSH 任何内置包。输入框的 ↑/↓ 输入历史 已拆分为独立插件 dsh-input-history(发送落库 localStorage 全局环、同步召回),本插件不再包含历史逻辑:

功能说明
@ 文件/文件夹提及输入框敲 @ 弹出工作区文件与文件夹菜单(git 索引优先、嵌套 git 仓库递归展开、fzf 风格模糊过滤);菜单行显示文件名/文件夹名主标题(文件夹带 /)+ 全路径小字副标题,宽度与输入框一致;选中插入纯文本 @token 相对路径 ——token 整体着色(无胶囊宽度上限),路径明文随行,模型零搜索直达文件;文件夹引用注入 kind="directory"
token/胶囊点击预览点击输入框内的着色 token 或会话气泡里的灰色胶囊,直接在右侧 better-sidebar 编辑器打开该文件预览(未安装时回退系统默认打开方式);pick 的 token 精确解析,手输 token 在 stem 唯一时也可解析
菜单样式覆盖注入一段 scoped CSS(:has([data-source="file"])),只影响文件组菜单:满宽 + 两行布局;其他 trigger 菜单(斜杠命令、子代理)保持内建尺寸

安装

dsh plugin --profile web add /path/to/dsh-file-mention

dsh.bundle.patch 声明会让 CLI 自动把本包追加进 profile 的 bundles(宿主半随之挂载)。然后重启 DSH 桌面应用并刷新页面。零运行时依赖,无 peer / 构建要求。

卸载:dsh plugin --profile web remove dsh-file-mention

开发迭代:改完代码运行 scripts/deploy.sh(同步 lib 到 profile 安装目录)后重启。

架构

┌ composer (ui-conversation, 不改) ─────────────────────────────┐
│ @ 触发 → inputTriggers 管线 → 本插件 source "file"            │
│   candidates: host files.index + dirs 合并模糊评分              │
│               行 = name(文件名/文件夹名,文件夹带 /)           │
│                    + description(全路径副标题)                 │
│   onPick    → insert-text → "@token rel/path "(无占位/无胶囊)│
│   lexicon   → 文件 + 文件夹全部可着色 token → 平台 scanTextRefs │
│   subscribeLexicon → 索引落定后通知管线重扫(着色及时生效)    │
│   发送      → 草稿即文本,chip-free 跳过序列化直落 sink       │
│ token/胶囊点击(捕获)→ pick 登记 / 唯一 stem 反解 → 绝对路径   │
│   → betterSidebar.openFile → 回退 workspaces.openPath          │
│ 菜单 CSS    → :has([data-source="file"]) 满宽 + 两行行布局    │
└──────────────────────────────────────────────────────────────┘
                       │ /file-mention/api (POST JSON, 浏览器信任围栏)
┌ host 半 ────────────┴────────────────────────────────────────┐
│ files.index  git ls-files --cached --others --exclude-standard │
│              嵌套 git 仓库条目(dir/)递归展开(同上限/深度界)  │
│              目录 roll = 文件祖先推导 + 嵌入式仓库 dir/ 条目    │
│              (失败/非 git → opendir walk 兜底,含空目录,     │
│                TTL 10s 缓存)                                  │
│ files.read   遗留接口(纯文本模式不再调用;保留供测试覆盖)    │
└──────────────────────────────────────────────────────────────┘
  • 客户端 bundle 以 window.__ModuleLoader__.load 约定注册,不 require 任何模块(纯逻辑,无 React),规避 externals 漂移,无需打包器。
  • 菜单渲染、键盘仲裁、IME 守卫、纯文本装饰(mark.textRef 着色)、气泡 refChip 投影全部由 DSH 内建管线承担。
  • @subagent@cordis 两个 @ 源共存(组名 file,order 2)。

引用格式(宿主侧注入,dsh-at-file 同款)

选中文件插入干净纯文本提及 @token (token = 去扩展名文件名);发送后的处理全部在宿主侧 agent/pre-step 边界完成:

  • 宿主扫描发出的用户消息里的 @token,按「pick 注册(精确)→ 索引唯一 stem」解析,stat 校验存在后,注入一条独立的引用消息给模型:
<workspace-reference path="lbk-flutter-common/modules/fiat/lib/screens/otc/home/otc_home_tab_page.dart" kind="file" />
  • 文件夹同样可引用:目录与文件共享同一索引与 token 语法(src/app/@app),选中或手输命中后注入 <workspace-reference path="lib/" kind="directory" />(目录 path 保留尾部 /);token/胶囊点击预览对目录走系统打开方式(跳过 better-sidebar 编辑器)

  • 输入框、草稿、用户气泡永远干净——只显示着色 token,路径不出现在任何用户可见文本里

  • 模型直接从引用消息拿精确路径,零搜索

  • 菜单 pick 时客户端通过 mentions.registertoken → 相对路径 精确映射登记到宿主(歧义 stem 也能精确解析);手输 token 靠全工作区唯一 stem 兜底

  • 注入消息的 source 为 at-file-mention(与 dsh-at-file 相同形状),不进入输入历史

  • token 语法 @[\w-]+:点文件(.gitignore)与多点名(archive.tar.gz)插入 @basename 但不着色、不注入引用

  • 手动键入 @token (token 命中 lexicon)同样着色;唯一 stem 的手输 token 发送时同样被注入引用

  • token/胶囊点击预览:pick 的 token 按 pick 时登记的绝对路径打开;手输/气泡 token 在 stem 唯一时反解打开;歧义 stem 点击不动作

已知限制

  • 非 git 目录靠默认忽略表兜底(node_modules/dist/build/隐藏目录等),不解析 .gitignore 本身;隐藏目录与忽略目录(node_modules 等)既不出现在文件也不出现在文件夹菜单
  • git 路径下目录由文件祖先推导:不含任何已跟踪文件的空目录不会出现(git 本身不跟踪空目录);walk 兜底路径下空目录可见
  • 索引上限 200000 文件(truncated 截断,目录 roll 同界);文件/文件夹新建后最长 10s + 重开菜单可见
  • 含空格的路径无法靠键入 query 命中(触发 token 遇空白终止,Codex 同款约束),仍可从菜单点选
  • 手输/气泡胶囊的点击解析依赖 stem 唯一:歧义 stem 不动作(pick 的 token 不受影响,pick 时已精确登记);文件夹与文件同名 stem 同样视为歧义
  • 菜单行 React key 含文件名:同名文件并列时开发构建会有 duplicate-key 告警(按索引 pick,功能不受影响)
  • 菜单 CSS 用结构选择器([role=option] span 顺序)而非平台哈希类:平台 MenuView 大改时覆盖规则失配,退回内建单行样式(无害降级)
  • 点击命中依赖 DOM 结构约定(data-composer-cardmark[data-decoration]span[data-ref-chip]),DSH 前端大版本变更时需适配

测试

node --test test/host.test.js test/client.test.js

27 个用例:目录遍历/深度/上限、嵌套仓库展开、目录 roll 推导、路径围栏、信任围栏(loopback/trusted/cross-site/origin)、读取(截断/二进制/越界)、路由分发、模糊评分(含目录行)、token/stem 派生(含目录尾部斜杠)、mention 扫描/引用形式(file + directory)/pre-step 注入/pick 注册校验、joinPath、命中测试、API 封包。(↑/↓ 输入历史相关用例已随拆分迁移至 dsh-input-history。)