dsh-skill-picker 0.5.19 → 0.5.21
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/README.md +4 -1
- package/lib/client.js +1 -2
- package/lib/client.js.map +2 -2
- package/lib/index.js +43 -3
- package/lib/index.js.map +2 -2
- package/package.json +1 -1
- package/src/client/slash-source.js +5 -2
- package/src/index.js +25 -10
- package/src/patch-ui-skill.js +47 -0
package/README.md
CHANGED
|
@@ -141,7 +141,10 @@ source.onPick = (args) => { track(args?.candidate?.name); return onPick.call(sou
|
|
|
141
141
|
|
|
142
142
|
## 更新日志
|
|
143
143
|
|
|
144
|
-
- **v0.5.
|
|
144
|
+
- **v0.5.21**:**文件补丁正式退休:默认不再改官方文件,并自动把改过的还原回去**——起因是国豪发现**同一件事桌面端对、网页端不对**,并直接怀疑到"之前魔改过"。**查证结果:他猜对了。** 两端加载的官方 `@deepseek-ai/dsh-client-ui-skill` 根本不是同一份:**桌面端从 `app.asar` 取**(打包只读,永远是原版),**网页端从 `~/.dsh/profiles/node_modules/` 取共享那份 —— 而那份被本插件的老文件补丁改过**(实测:`__dshSkillPickerFuzzy`×2、`order: -1`,旁边躺着 `.bak`)。**这个差异为什么会让排序看起来不一样**:补丁把官方 `candidates` 改成走 `window.__dshSkillPickerFuzzy`,而它返回的**已经是「置顶+使用热度」排好序**的列表;我的包装层再做一次排序时,`groupByPinned` 把「🗂️ 全部」分组的**输入顺序**保留下来(同热度时的稳定排序)——于是网页端的「全部」是**使用热度序**、桌面端是**字母序**。**根因级别的问题**:文件补丁自 v0.5.15 起**已是纯冗余** —— 它只做三件事(技能组置顶 `order: -1`、模糊+拼音匹配、`onPick` 记使用),而**运行时接管三件全都自己做了**。它却仍在改用户的官方包,还让两个 profile 对同一个文件产生分歧。**修法**:① 新增 `revertUiSkillPatches()`,启动时**只针对"仍带我们标记"的文件**从 `.bak` 还原(用 temp+rename,绝不动 pnpm 硬链接的共享 inode;幂等);② 文件补丁改为**默认关闭**,只有显式设 `DSH_SKILL_PICKER_FILE_PATCH=1` 才走旧的自愈路径(给"触发源注册表里没有 live sources 可接管"的老内核兜底)。**本机已实测还原**:共享那份 `lib/client.js` 现在 `__dshSkillPickerFuzzy`=0、`order: 2`、**hash 与 `.bak` 完全一致**。全量 `npm test`:**65 tests / 64 pass / 0 fail**
|
|
145
|
+
- **v0.5.20**:**`/` 菜单的空查询也走排序,「置顶」技能排到最前面(与 ⚡ 面板一致)**——国豪指出:按 ⚡ 按钮时列表是「📌 置顶(3)」在前、再「📁 全部(57)」,但直接打 `/` 出来的却**是纯字母序、置顶不在前面**,两边排序不一样。**根因**:包装层对**空查询**做了短路 —— `if (query === '') return cached` / `if (query === '' || ...) return everything`,即"空查询把官方列表原封不动返回"。而 ⚡ 面板走的是 `rankPickerItems(items, '')`,它会先 `groupByPinned(...)` 把置顶提到最前。**于是同一个数据源、两套排序。** **修法**:去掉空查询短路,**空查询也交给 `rank()`** —— `rankPickerItems(items, '')` 本就设计为"空查询 = 全部条目、按面板顺序(置顶优先)",所以两边从此同源同序。**顺带发现一条假通过的测试**:旧的 `an empty query returns the official result untouched` 里 `rank` 是**故意抛错**的,而 `rank` 一抛错就被包装层的 try/catch 兜住、仍然返回官方列表 —— 也就是说那条测试**测的是兜底路径,不是它声称的语义**,所以它在新行为下照样"通过"。已改写为正面断言:空查询**必须**调用 `rank`,且置顶技能排第一。全量 `npm test`:**65 tests / 64 pass / 0 fail**
|
|
146
|
+
- **v0.5.19**:**修掉 v0.5.17 里"预热走错了路"的 bug**(0.5.18 因 npm 发布延迟被误判为"卡住",实际已发布;两者代码逐字节相同)—— 上一版已经把胜负手找对了(技能组要 **0 个 `await`** 才抢得到高亮),但它预热时调的是**官方 `source.warm()`**:`warm()` 只预热**官方模块自己的**缓存,**插件自己的 `itemCache` 依然是空的** → 菜单打开那次**仍然未命中**、仍然 `await` 官方、仍然比命令组多一跳、**仍然输**。这一条是从运行诊断里确认的:`{"mode":"runtime","installed":true,"took":"candidates+order+onPick"}` 与 `{"servedFromCache":false,"sessionId":"session-de1f2494-…","primed":true,"count":71}` —— 即"接管装上了、缓存也被填过,但菜单那次仍是 `servedFromCache:false`"。**修法**:预热改为**走插件自己的包装路径**(一次空查询 `candidates`),**一次调用同时填满两层**(包装层写快照 + 官方层自然预热)。另:缓存**热重载后不再被清空**,所以重载后的第一次打开也是命中。**桌面端已实测确认修好**。**回归测试**:新增一条直击要害的用例 —— 官方取数故意慢 60ms,预热后菜单调用**必须在 30ms 内返回**;另把"预热走官方 `warm()`"这条反例锁死(断言**不会**只调 `warm()`)。全量 `npm test`:**65 tests / 64 pass / 0 fail**
|
|
147
|
+
- **v0.5.18**(**从未发布到 npm**):修复内容与 0.5.19 完全相同,但版本号因 npm 暂存槽位冲突(`E409 Cannot publish over previously staged version`)无法发布,改用 0.5.19。**教训:npm 上"已 staging"的版本号会被占住且 `npm stage list` 看不到,直接换号最快。**
|
|
145
148
|
- **v0.5.17**:**修复「打 `/` 时菜单开到下面去、高亮不在第一条技能」**——症状是输入一个 `/`,菜单**滚到底部**、高亮停在命令组(`添加 / 文件` 或 `指令 / compact`)上,而不是停在最上面第一条技能。**根因**:官方斜杠菜单的高亮是一条「**谁先就绪谁拿高亮、拿到就粘住**」的规则 —— `highlight = validHighlight(旧高亮, groups) ?? firstHighlight(groups)`,`firstHighlight` 取的是**第一个「已就绪」分组**的第一条;随后 `scrollIntoView({ block: "nearest" })` 把高亮滚进视野。本插件为了让技能组排在最上面把它的 `order` 从 2 改成 `-1`,于是**命令组一旦先就绪,高亮就落在它身上、而它现在被压在技能组下面** → 菜单往下滚去够高亮。**关键:这是 microtask 跳数的比赛,不是网络快慢** —— 「已就绪的 promise」`await` 一次就是一个 microtask;实测三种写法的胜负(技能组在 roster 里排第一,命令源至少一层 `await`):| 写法 | 先就绪 |
|
|
146
149
|
|---|---|
|
|
147
150
|
| 包装层 `await` 官方 candidates(2 跳) | 命令组 ❌ |
|
package/lib/client.js
CHANGED
|
@@ -25890,7 +25890,6 @@ function wrapSkillSource(source, hooks = {}) {
|
|
|
25890
25890
|
if (cached !== void 0) {
|
|
25891
25891
|
noteDiag({ mode: "runtime", servedFromCache: true, sessionId: cacheKey, query });
|
|
25892
25892
|
refreshCache(cacheKey, original.candidates, this, projection, options);
|
|
25893
|
-
if (query === "") return cached;
|
|
25894
25893
|
try {
|
|
25895
25894
|
return rank(cached, query);
|
|
25896
25895
|
} catch {
|
|
@@ -25902,7 +25901,7 @@ function wrapSkillSource(source, hooks = {}) {
|
|
|
25902
25901
|
itemCache.set(cacheKey, everything.slice());
|
|
25903
25902
|
noteDiag({ mode: "runtime", servedFromCache: false, sessionId: cacheKey, primed: true, count: everything.length });
|
|
25904
25903
|
}
|
|
25905
|
-
if (
|
|
25904
|
+
if (!Array.isArray(everything)) return everything;
|
|
25906
25905
|
try {
|
|
25907
25906
|
return rank(everything, query);
|
|
25908
25907
|
} catch {
|