Repository navigation
Releases: Nethur-auro/dsh-multi-root-explorer
Release list
0.1.8 — 资源树自动刷新 · 新会话交给 DSH 命名 · 修复重命名输入被全选
0.1.8
- 资源树自动跟上磁盘。 已加载的目录层每隔几秒用 Host 的目录版本号探测一次,只有真的变了才重新取那一层,并且在已翻到的深度内重取,手工翻出来的分页不会被收回。
- 新会话交给 DSH 命名。 在文件夹里新建会话时不再预先写死标题,标题留给 DSH 自己的标题器,按你发的第一条消息命名。
- 修复重命名输入框。 之前每敲一个字都会被全选替换,最后只剩最后一个字;现在打开时全选一次,输入过程中不再打断。
0.1.7 — 修复右上角控件贴边(皮肤描边会压住)
修复
面板右上角那三个控件(眼睛 / 刷新 / 设置)贴着面板右边缘,装了描边类主题插件时会被压住。
那行的样式只有左内边距、右边是 0,而控件靠 margin-left:auto 顶到最右侧,所以正好落在边缘上。现在这行的右内边距和下面那行选项卡一致(8px),控件随之左移 8px,与选项卡的右边缘对齐,同时也给主题插件的边距让出了位置。
只有装了描边/边框类皮肤才看得出来;不装皮肤时几乎无感(只是控件与下方选项卡对齐了)。
如果还差一点,说一句"再多一点/少一点"即可 —— 这是一行的改动。
0.1.6 — 修复在文字后拖拽不生成引用块
修复
在文字后面拖拽不会变成引用块(报 no-menu,只留下一段 @路径 文本)
拖拽写进编辑器的文本是原样插入的。当落点紧贴前一个词(变成 文字@路径)时,DSH 补全管线的 token 边界规则不认为这是 token —— 菜单根本不会打开,也就无从提升成引用块。表现就是那句「拖拽引用未自动转换,原因:no-menu」;而只要前面加一个空格就正常。
现在拖拽载荷里的纯文本自带一个前导分隔空格,所以无论在什么位置落下,这段 mention 都是可识别的 token,能正常提升为引用块。
词表里登记的仍是不带空格的干净 mention(管线读的是它自己跟踪到的 token,不含分隔符),所以已有的补全与着色行为不受影响 —— 有一条既有测试正好在守这一点。
唯一的代价:如果把文件拖到一个空草稿的最前面,会留下一个前导空格。它无害,在 Markdown 里也不影响渲染。
升级建议
建议升级 —— 这是可见的功能缺陷。GitHub 的安装链接永远指向最新发布版,无需改任何东西。
0.1.5 — 修复 Windows 隐藏目标 · 截图打码 · 安装说明重写
修复
Windows 上隐藏目标被判 outside-root(CI 在 Windows runner 上一直红)
addRoot 会把根路径经 realpath 解析后存储,而请求里的隐藏目标保持调用者拼写的原样。两者一旦拼写不同,包含关系判断就会失败:
- GitHub 的 Windows runner 上,
os.tmpdir()返回 8.3 短名(C:\Users\RUNNER~1\…),而realpath给出长名(C:\Users\runneradmin\…) - 同一类问题还有符号链接的临时目录:macOS 上
/var与/private/var是同一处
现在目标会先经文件系统解析成与根一致的拼写(目标存在就解析目标;不存在就解析其父目录并接回最后一段),再做包含判断,存储的也是解析后的拼写。带一条回归测试:通过链接登记根、再从链接那一侧隐藏路径。把修复移出后该测试会精确复现 CI 的报错(path is outside registered roots)。
同一次修复还包含一处兼容性处理:本版起「隐藏」存的是解析后的拼写,而此前版本存的是调用者拼写,所以「取消隐藏」会同时匹配两种拼写——否则被旧版本隐藏过的目录将永远无法恢复显示。(这条由 5 个"用原始拼写预置记录"的测试抓出来,另加一条本机可复现的兼容用例。)
变更
截图打码(隐私)
assets/sidebar.png 会同时出现在两个 README 和插件市场详情页。原图里有真实的目录名(工作区根、备课、配置、catalog-entry、default-workspace)以及七个真实会话标题。文字列现已打码——目录图标、会话计数、相对时间、选项卡和各控件都保留,所以「展开成带计数的会话文件夹」这个说明依然成立。
安装说明重写
原来的段落把 dsh plugin add … 当主推,但桌面应用版用户机器上不一定有 dsh 命令。现在分为四条路线,并明确标出哪些不需要命令行:
- 应用内插件市场(不依赖命令行)
- npm 包——写包名,永远取最新已发布版本
- 从 GitHub 装:
- 3a 预构建包:
releases/latest/download/dsh-multi-root-explorer.tgz。latest在请求时解析,而资产名刻意不带版本号,所以它永远指向最新发布版、且不会随发版失效。 - 3b 源码:跟踪
main。本项目每次发布都把main停在发布提交上,所以mainHEAD 与最新 tag 始终同一点。
- 3a 预构建包:
- 手动改 profile(不依赖命令行)
另加 docs/RELEASING.md,把这两条保证写成可执行的自查步骤;其中最关键的一条是资产名不能带版本号——一旦带了,安装链接会在下次发版当天 404 而无人察觉。
建议升级
Windows 用户建议升级(隐藏目标可能报 outside-root)。其余平台功能无变化。
0.1.4 — 工作目录内的拖拽现在能匹配上候选
修复:工作目录内的拖拽永远匹配不上候选(no-candidate)
拖拽插入的 mention 是相对会话工作目录拼写的(这是 DSH 自带引用源的写法),而 Host 侧的候选索引是相对已登记根拼写的。两套基准不一致:
- 拖拽工作目录之外的路径 → mention 是绝对路径 → 匹配得上 ✓(所以之前那些测试都成功)
- 拖拽工作目录之内的路径 → mention 形如
.dsh/skills/,索引里却是配置/.dsh/skills→ 永远匹配不上 ✗ → 每次都被判no-candidate
现在索引同时接受三种拼法:根相对 / 会话工作目录相对 / 绝对,客户端把当前会话的工作目录随查询一起传给 Host。
修复前在你机器上实测(运行中的 Host):
| 查询 | 候选数 |
|---|---|
.dsh/skills/ — 拖拽实际插入的写法 |
0 ✗ |
配置/.dsh/skills/ — 相对根的写法 |
5 ✓ |
顺带修掉同类问题:带空格的文件夹引用现在会把引号闭合。官方语法为了"边输入边下钻"保留开放引号,但那样整段文本不构成可识别的 token,拖进去也永远提升不了。
新增 5 条断言,其中一条专门钉住这次的回退:同一种拼法在只知道根的时候匹配不到。
测试
Host 166 + 客户端 139 + 原生桥接 15,全绿。
0.1.3 — 修复索引重建翻倍与首次查询候选窗口
修复
1. 候选索引在每次重建时条目翻倍(0.1.2 引入)
重建索引时,上一份候选列表被"沿用为"新遍历的目标数组——本意是让重建期间继续用旧列表作答,实际效果是同一批条目被反复推进同一个数组:entries 2 → 4 → 8……而 TTL 是 20 秒,跑几分钟后同一份文件会在候选里重复出现四次、八次,既浪费结果名额也拖慢响应。
现在遍历写进自己的列表,完成时才整体替换旧列表。新增 4 条回归断言(首次一次、重建不翻倍、再次重建仍不翻倍、重建后仍能作答)。
2. 首次查询的候选窗口太短(导致"拖拽引用未自动转换,原因:no-candidate")
Host 侧索引的首次查询只给新遍历 40ms 抢先时间。对一个只有 99 个目录的根,逐个目录读取也需要更久——于是刚重启就拖拽时,补全菜单拿到的是还没索引完的部分列表,里面没有那个文件;而输入管线对一个 token 只会取一次候选,不会重取,所以这一次拖拽注定失败,而稍后再拖就正常。
现在首次查询最多等 1200ms 让遍历跑完。代价只出现在"索引冷的第一次查询"(插件加载时已经预热一次,所以通常连这一次都不会遇到);换来的是不再有"重启后第一次拖拽失败"这种偶发现象。
拖拽提升的等待窗口也从 2s 放宽到 3s,与上面配合。
升级建议
- 0.1.2 用户请升级(第 1 条是 0.1.2 引入的回归)
- 0.1.1 或更早的用户直接跳到本版
已知代价(不变)
把拖拽提升成引用块用到了未公开的接口:编辑器只把 text/plain 当纯文本插入,引用块只能由输入管线在"选中一个补全候选"时生成。每一环都做了能力探测,对不上就退化成一条可读的引用文本并说明原因;DSH 升级若改了这些内部字段,提升会失效,lib/client.js 里的 ADAPTATION POINT 注释写明了依赖的确切字段。
0.1.2 — 修复 @ 补全源注册竞态(0.1.1 的回归)
修复
@ 补全源的注册竞态(0.1.1 里引入的回归)
0.1.1 里 inputTriggers 服务只在插件应用时读取一次。客户端插件之间的加载顺序没有保证——那一读一旦跑在 dsh-input-trigger 之前就是 undefined,于是:
- 我们的
@源从此不再注册(且永不重试) - 所有补全查询只由 DSH 自带的源作答
- 每次拖拽都报「拖拽引用未自动转换,原因:no-menu」
表现是时好时坏:开发链接模式侥幸赢过这个竞态,重启后就输了——典型的 flaky,而它被带进了 0.1.1。
现在改为等待服务出现并重试(每 250ms 一次,上限 15 秒),并把这一类失败从 no-menu 里单独命名为 no-source,所以以后再遇到同类问题,提示会直接指出"是 source 没注册",而不是含糊的"菜单没开"。
升级建议
从 0.1.1 升级到 0.1.2 即可;0.1.0 用户直接跳到 0.1.2。
0.1.1 的内容(若你从 0.1.0 上来)
见 0.1.1 的发布说明:原生引用块、全工作区 @ 补全、诚实的会话工作状态,以及隐藏选择、Host 路径与上限、资源树缓存键等一批修复。
0.1.1 — 原生引用块 · 全工作区 @ 补全 · 诚实的工作状态
新增
- 拖进输入框就是原生引用。 把资源行拖进对话输入框会生成 DSH 原生的原子引用块——文件图标 + 文件名 + 业务色,和从
@菜单里选中一个候选完全一样。提升失败时(落点紧邻文字、补全菜单没有为这段文本打开等)会退化成一条可读的引用文本并说明原因,不会把草稿弄乱。 @补全覆盖全部已登记工作区。 DSH 自带的文件补全只索引会话的工作目录,所以其他盘上的根永远搜不到。插件另外注册了一个@源覆盖所有根,Host 侧维护一份有界索引:沿用官方排除目录策略(node_modules等)、切片后台遍历、查询永不阻塞。- 工作状态诚实。 会话状态卡与行首圆点不再只看会话自己的 agent:子 agent 仍在工作(即使主 agent 已经停下)、goal 仍在逐轮推进(两轮之间的空档)都显示「工作中」。
修复
隐藏选择(两个选项卡现已共用同一套语义)
- 对话选项卡完全没有"父覆盖 → 展开为子项"的逻辑,导致子项取消不掉、点已选中的父目录会连子一起清空
- 展开只作用一层,点击被覆盖的孙级目录取消不掉(中间层继续覆盖它)
- 展开时只保留子目录、丢掉文件,导致「空文件夹」对文件不成立
- 只看已加载的层级,未展开过的子文件夹被静默漏掉——现在按需向 Host 读该目录自身的层级
工作状态
running只反映会话自己的 agent,子 agent 在工作时判定为「空闲」- goal 逐项推进期间(两轮之间)判定为「空闲」
资源树
- 层级缓存键写错(用裸路径查一个键为
root.id:折叠路径的表),导致每次展开都重复加载同一层
Host 侧加固
joinCanonical对盘根产出D://x,而fold('D://x') ≠ fold('D:/x')—— 破坏"拼出来的路径就是规范路径"这个不变量,并影响盘根工作区的引用候选匹配- 无
scope的兼容请求完全跳过隐藏目标的边界校验(可写入任意绝对路径、绕过"已登记根不可隐藏") - 展开集满 2000 条后保留最旧(隐藏列表保留最新),新展开的节点永远存不进去
- 注册上限在落盘路径失效:手改或半写入的
config.json可塞进任意多根 - Windows 上把 POSIX 拼写交给平台解析器(
canonical('/home/x')变成当前盘的D:/home/x),与外来自述意图相反,会静默改写其他平台写的配置
新建会话
- 补上被漏掉的命名结果校验:命名失败现在会明确报错,而不是静默打开一个用文件夹名当标题的会话(命名本身一直由 Host 侧完成并记入持久 ledger 重试)
性能
@索引从"首次查询同步等整棵树走完"改为切片后台遍历 + 查询永不阻塞(大树不再卡住输入)
其他
- 删除 193 行经审计证明不可达的死代码(客户端重命名簇、
pickStrings、driveKeyOf、pickAnchor、splitAnchorPaths等) - 测试:Host 158 + 客户端 138 + 原生桥接 15,全绿
- 一个已知代价:把拖拽提升成引用用到了未公开的接口(编辑器只把
text/plain当纯文本插入,引用块只能由输入管线在选中候选时生成)。每一环都做了能力探测,对不上就退化成引用文本;但 DSH 升级若改了这些内部字段,自动提升会失效——lib/client.js里标了ADAPTATION POINT注释,写明了依赖的确切字段。