dsh-skill-picker 0.3.4 → 0.4.0
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 +17 -1
- package/lib/client.js +17 -101
- package/lib/client.js.map +2 -2
- package/package.json +2 -3
- package/src/client/index.jsx +26 -127
package/README.md
CHANGED
|
@@ -98,10 +98,26 @@ DSH 的 [dsh-tool-skill](https://github.com/deepseek-ai/deepseek-harness) 在 `a
|
|
|
98
98
|
[DSH] agent/pre-step 识别手势 → 自动加载技能 → 执行
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
- client 半:注册到官方 `conversation.input.right` 插槽(composer 工具行、发送按钮左侧的控件位),**技能列表优先走官方宿主 skills API**(`
|
|
101
|
+
- client 半:注册到官方 `conversation.input.right` 插槽(composer 工具行、发送按钮左侧的控件位),**技能列表优先走官方宿主 skills API**(`remote.skills.list`——与 DSH 内置 `/` 补全同源,会话作用域,自动含用户级/项目级技能),失败时回退到 host 扫描路由;插入文本走框架输入机的 `inputActions.setDraft`(单一路径,撤销/草稿持久化自动处理);最近/常用排序 + 拼音索引(`pinyin-pro`)在 client 侧生成,按技能缓存
|
|
102
|
+
|
|
103
|
+
## 与官方 `/` 补全的关系(v0.4.0 起:增强,而非并列)
|
|
104
|
+
|
|
105
|
+
**v0.2.0–0.3.4**:插件注册了一个独立的 `/` 候选源(`skill-fuzzy`),与官方 ui-skill 源**并列**——菜单里出现两个技能分组,搜索行为相互独立(冲突风险、视觉重复)。
|
|
106
|
+
|
|
107
|
+
**v0.4.0 起**:**不再注册平行源**。改为给官方 `@deepseek-ai/dsh-client-ui-skill` 包的 candidates **打补丁**——其候选逻辑从 `skill.name.startsWith(query)`(前缀匹配)换成调用插件注入的全局函数 `window.__dshSkillPickerFuzzy`(fuzzysort 模糊 + pinyin-pro 拼音 + 最近/常用排行,与 ⚡ 面板同一套规则)。
|
|
108
|
+
|
|
109
|
+
**效果**:官方「技能」分组**仍是唯一一个 `/` 技能列表**(官方规则全部保留:`userInvocable` 区分、菜单文案、排序基础),只是匹配行为被升级;插件不再产生第二列表。
|
|
110
|
+
|
|
111
|
+
**Patch 部署姿势**(本机 `profiles/web/local/`,与其它 patch 插件同款):
|
|
112
|
+
1. 把官方包拷到 `profiles/web/local/dsh-client-ui-skill/`(`lib/client.js` 改 candidates 为 `window.__dshSkillPickerFuzzy` 优先,`startsWith` 兜底)
|
|
113
|
+
2. profile package.json 加依赖 `"@deepseek-ai/dsh-client-ui-skill": "link:C:/Users/<user>/.dsh/profiles/web/local/dsh-client-ui-skill"`
|
|
114
|
+
3. `pnpm install` 后重启 DSH
|
|
115
|
+
|
|
116
|
+
> 官方 DSH 升级后(如 alpha.6),若 ui-skill 包变动:重拷新包覆盖 local 副本、重打补丁即可;插件本身逻辑不变。
|
|
102
117
|
|
|
103
118
|
## 更新日志
|
|
104
119
|
|
|
120
|
+
- **v0.4.0**:**单列表模糊搜索**——不再注册独立 `/` 候选源,改为 patch 官方 ui-skill 的 candidates(模糊+拼音注入,官方列表是唯一来源,无并列列表、无搜索冲突);实测 `/jiyi` → 官方「技能」组 backup-memory 排第一
|
|
105
121
|
- **v0.3.4**:适配 DSH 0.1.2-alpha.5 —— 技能列表改用官方 `remote.skills` RPC(alpha.5 将 rc.x 的 `connection.api.skills` 改名),`/` 补全与 ⚡ 面板统一「官方 RPC → host 扫描兜底」;`dsh.client.inject` 声明 `dsh-client-ui-input-trigger`(alpha.5 装载器只给声明了提供者的插件暴露 `inputTriggers` 服务)。修复 alpha.5 下 `/` 模糊/拼音搜索失效(实测 `/jiyi` → backup-memory)
|
|
106
122
|
- **v0.3.3**:兜底扫描对齐官方全部技能根——补扫 user-agents 层(`~/.agents/skills`,含 `DSH_AGENTS_HOME`),扫描顺序与官方 rank 一致(项目级优先于用户级);走兜底时 ⚡ 面板显示「本地扫描」来源徽标便于排障(对应 issue #5)
|
|
107
123
|
- **v0.3.2**:安装文档修正——实测三种安装方式并补网络特例(HTTPS 受限改 SSH、npm 新版本 24h 内被 minimumReleaseAge 门禁挡旧版的规避方法)
|
package/lib/client.js
CHANGED
|
@@ -26100,7 +26100,6 @@ function SkillPickerButton(props) {
|
|
|
26100
26100
|
] });
|
|
26101
26101
|
}
|
|
26102
26102
|
function apply(ctx) {
|
|
26103
|
-
const inputTriggers = typeof ctx.get === "function" ? ctx.get("inputTriggers") : ctx.inputTriggers;
|
|
26104
26103
|
const listSkills = async (sessionId) => {
|
|
26105
26104
|
const remoteSkills = ctx.remote?.skills;
|
|
26106
26105
|
const connectionSkills = ctx.connection?.api?.skills;
|
|
@@ -26125,24 +26124,6 @@ function apply(ctx) {
|
|
|
26125
26124
|
currentCwd = "";
|
|
26126
26125
|
}
|
|
26127
26126
|
};
|
|
26128
|
-
const fetchHostSkills = async () => {
|
|
26129
|
-
const cwd = typeof currentCwd === "string" && currentCwd !== "" ? `?cwd=${encodeURIComponent(currentCwd)}` : "";
|
|
26130
|
-
const res = await fetch(`/dsh-skill-picker/skills${cwd}`, { headers: { accept: "application/json" } });
|
|
26131
|
-
const json = await res.json();
|
|
26132
|
-
if (!json.ok) throw new Error(json.error || "bad response");
|
|
26133
|
-
return Array.isArray(json.skills) ? json.skills : [];
|
|
26134
|
-
};
|
|
26135
|
-
const resolveSkills = async (sessionId) => {
|
|
26136
|
-
try {
|
|
26137
|
-
return await listSkills(sessionId);
|
|
26138
|
-
} catch {
|
|
26139
|
-
try {
|
|
26140
|
-
return await fetchHostSkills();
|
|
26141
|
-
} catch {
|
|
26142
|
-
return [];
|
|
26143
|
-
}
|
|
26144
|
-
}
|
|
26145
|
-
};
|
|
26146
26127
|
syncCwd();
|
|
26147
26128
|
const unsubscribe = ctx.sessions.list.subscribe(syncCwd);
|
|
26148
26129
|
ctx.effect(() => {
|
|
@@ -26160,91 +26141,26 @@ function apply(ctx) {
|
|
|
26160
26141
|
};
|
|
26161
26142
|
}, "dsh-skill-picker: composer input slot");
|
|
26162
26143
|
ctx.effect(() => {
|
|
26163
|
-
const
|
|
26164
|
-
|
|
26165
|
-
|
|
26166
|
-
|
|
26167
|
-
|
|
26168
|
-
|
|
26169
|
-
}
|
|
26170
|
-
|
|
26171
|
-
|
|
26172
|
-
|
|
26173
|
-
|
|
26174
|
-
|
|
26175
|
-
|
|
26176
|
-
|
|
26177
|
-
namesCache.set(sessionId, (Array.isArray(skills) ? skills : []).map((s) => s.name));
|
|
26178
|
-
notifyLexicon(sessionId);
|
|
26179
|
-
} catch {
|
|
26180
|
-
}
|
|
26181
|
-
};
|
|
26182
|
-
const source = {
|
|
26183
|
-
trigger: "/",
|
|
26184
|
-
name: "skill-fuzzy",
|
|
26185
|
-
order: -10,
|
|
26186
|
-
async candidates(session, { query, signal }) {
|
|
26187
|
-
const skills = await resolveSkills(session.sessionId);
|
|
26188
|
-
if (signal.aborted) return [];
|
|
26189
|
-
namesCache.set(session.sessionId, skills.map((s) => s.name));
|
|
26190
|
-
notifyLexicon(session.sessionId);
|
|
26191
|
-
const ordered = rankByUsage(skills, loadUsage());
|
|
26192
|
-
const q = String(query ?? "").trim().toLowerCase();
|
|
26193
|
-
if (q === "") {
|
|
26194
|
-
return ordered.map((s) => ({ name: s.name, description: s.description }));
|
|
26195
|
-
}
|
|
26196
|
-
const targets = ordered.map((s) => ({
|
|
26197
|
-
s,
|
|
26198
|
-
search: `${s.name} ${s.description ?? ""} ${skillPinyinText(s.name, s.description ?? "")}`
|
|
26199
|
-
}));
|
|
26200
|
-
const results = fuzzysort_default.go(q, targets, {
|
|
26201
|
-
key: "search",
|
|
26202
|
-
limit: 12,
|
|
26203
|
-
threshold: -1e4
|
|
26204
|
-
});
|
|
26205
|
-
return results.filter((r) => r.score > 0).map((r) => ({ name: r.obj.s.name, description: r.obj.s.description }));
|
|
26206
|
-
},
|
|
26207
|
-
warm(session) {
|
|
26208
|
-
refreshNames(session.sessionId);
|
|
26209
|
-
},
|
|
26210
|
-
lexicon(session) {
|
|
26211
|
-
return namesCache.get(session.sessionId);
|
|
26212
|
-
},
|
|
26213
|
-
subscribeLexicon(session, listener) {
|
|
26214
|
-
const key = session.sessionId;
|
|
26215
|
-
const set = lexiconListeners.get(key) ?? /* @__PURE__ */ new Set();
|
|
26216
|
-
set.add(listener);
|
|
26217
|
-
lexiconListeners.set(key, set);
|
|
26218
|
-
return () => {
|
|
26219
|
-
const cur = lexiconListeners.get(key);
|
|
26220
|
-
if (cur !== void 0) {
|
|
26221
|
-
cur.delete(listener);
|
|
26222
|
-
if (cur.size === 0) lexiconListeners.delete(key);
|
|
26223
|
-
}
|
|
26224
|
-
};
|
|
26225
|
-
},
|
|
26226
|
-
onPick({ candidate }) {
|
|
26227
|
-
try {
|
|
26228
|
-
const usage = loadUsage();
|
|
26229
|
-
const name = candidate.name;
|
|
26230
|
-
const next = { ...usage, [name]: { count: (usage[name]?.count ?? 0) + 1, lastUsed: Date.now() } };
|
|
26231
|
-
saveUsage(next);
|
|
26232
|
-
} catch {
|
|
26233
|
-
}
|
|
26234
|
-
return { text: `/${candidate.name} ` };
|
|
26235
|
-
}
|
|
26144
|
+
const fuzzyMatch = (skills, query = "") => {
|
|
26145
|
+
const ordered = rankByUsage(skills, loadUsage());
|
|
26146
|
+
const q = String(query).trim().toLowerCase();
|
|
26147
|
+
if (q === "") return ordered;
|
|
26148
|
+
const targets = ordered.map((s) => ({
|
|
26149
|
+
s,
|
|
26150
|
+
search: `${s.name} ${s.description ?? ""} ${skillPinyinText(s.name, s.description ?? "")}`
|
|
26151
|
+
}));
|
|
26152
|
+
const results = fuzzysort_default.go(q, targets, {
|
|
26153
|
+
key: "search",
|
|
26154
|
+
limit: 12,
|
|
26155
|
+
threshold: -1e4
|
|
26156
|
+
});
|
|
26157
|
+
return results.filter((r) => r.score > 0).map((r) => r.obj.s);
|
|
26236
26158
|
};
|
|
26237
|
-
|
|
26238
|
-
console.warn("[dsh-skill-picker] inputTriggers service unavailable; fuzzy / completion disabled (\u26A1 panel still works)");
|
|
26239
|
-
return;
|
|
26240
|
-
}
|
|
26241
|
-
const unregister = inputTriggers.registerSource(source);
|
|
26159
|
+
window.__dshSkillPickerFuzzy = fuzzyMatch;
|
|
26242
26160
|
return () => {
|
|
26243
|
-
|
|
26244
|
-
namesCache.clear();
|
|
26245
|
-
lexiconListeners.clear();
|
|
26161
|
+
if (window.__dshSkillPickerFuzzy === fuzzyMatch) delete window.__dshSkillPickerFuzzy;
|
|
26246
26162
|
};
|
|
26247
|
-
}, "dsh-skill-picker: fuzzy / source");
|
|
26163
|
+
}, "dsh-skill-picker: fuzzy matcher for official / source");
|
|
26248
26164
|
}
|
|
26249
26165
|
return module.exports; } });
|
|
26250
26166
|
//# sourceMappingURL=client.js.map
|