dsh-skill-picker 0.5.12 → 0.5.15
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 +234 -208
- package/lib/client.js +251 -35
- package/lib/client.js.map +3 -3
- package/lib/index.js +50 -2
- package/lib/index.js.map +2 -2
- package/package.json +76 -73
- package/src/client/index.jsx +806 -736
- package/src/client/session-view.js +68 -0
- package/src/client/slash-source.js +278 -0
- package/src/patch-ui-skill.js +110 -5
package/lib/client.js
CHANGED
|
@@ -25762,6 +25762,187 @@ function pinyin(word, options) {
|
|
|
25762
25762
|
return middlewareType(list, options, word);
|
|
25763
25763
|
}
|
|
25764
25764
|
|
|
25765
|
+
// src/client/session-view.js
|
|
25766
|
+
function sessionIdOf(props) {
|
|
25767
|
+
return props?.sessionId ?? props?.session?.sessionId;
|
|
25768
|
+
}
|
|
25769
|
+
function selectWorkspaceCwd(sessionId) {
|
|
25770
|
+
return (state) => {
|
|
25771
|
+
const cwd = sessionId === void 0 ? void 0 : state?.byId?.[sessionId]?.cwd;
|
|
25772
|
+
return typeof cwd === "string" ? cwd : "";
|
|
25773
|
+
};
|
|
25774
|
+
}
|
|
25775
|
+
function useWorkspaceCwd(props) {
|
|
25776
|
+
const useSessions = props?.useSessions;
|
|
25777
|
+
const cwd = typeof useSessions === "function" ? useSessions(selectWorkspaceCwd(sessionIdOf(props))) : void 0;
|
|
25778
|
+
return typeof cwd === "string" ? cwd : "";
|
|
25779
|
+
}
|
|
25780
|
+
|
|
25781
|
+
// src/client/slash-source.js
|
|
25782
|
+
var WRAPPED = "__dshSkillPickerWrappedCandidates";
|
|
25783
|
+
var SKILL_SOURCE = { trigger: "/", name: "skill" };
|
|
25784
|
+
function isSkillSourceWrapped(source) {
|
|
25785
|
+
return source !== null && typeof source === "object" && source[WRAPPED] === true;
|
|
25786
|
+
}
|
|
25787
|
+
var enhancementMode;
|
|
25788
|
+
function slashEnhancementMode() {
|
|
25789
|
+
return enhancementMode;
|
|
25790
|
+
}
|
|
25791
|
+
function isSkillSource(source) {
|
|
25792
|
+
return source !== null && typeof source === "object" && source.trigger === SKILL_SOURCE.trigger && source.name === SKILL_SOURCE.name;
|
|
25793
|
+
}
|
|
25794
|
+
function registryCandidates(service) {
|
|
25795
|
+
const lists = [];
|
|
25796
|
+
const push = (value) => {
|
|
25797
|
+
if (Array.isArray(value) && value.length > 0) lists.push(value);
|
|
25798
|
+
};
|
|
25799
|
+
try {
|
|
25800
|
+
push(service.live?.sources);
|
|
25801
|
+
} catch {
|
|
25802
|
+
}
|
|
25803
|
+
try {
|
|
25804
|
+
if (typeof service.sources === "function") push(service.sources(SKILL_SOURCE.trigger));
|
|
25805
|
+
} catch {
|
|
25806
|
+
}
|
|
25807
|
+
try {
|
|
25808
|
+
if (typeof service.all === "function") push(service.all());
|
|
25809
|
+
} catch {
|
|
25810
|
+
}
|
|
25811
|
+
try {
|
|
25812
|
+
push(service.sources);
|
|
25813
|
+
} catch {
|
|
25814
|
+
}
|
|
25815
|
+
try {
|
|
25816
|
+
if (typeof service.roster?.sources === "function") push(service.roster.sources(SKILL_SOURCE.trigger));
|
|
25817
|
+
} catch {
|
|
25818
|
+
}
|
|
25819
|
+
try {
|
|
25820
|
+
if (typeof service.roster?.all === "function") push(service.roster.all());
|
|
25821
|
+
} catch {
|
|
25822
|
+
}
|
|
25823
|
+
return lists;
|
|
25824
|
+
}
|
|
25825
|
+
function findSkillSource(service) {
|
|
25826
|
+
if (service === null || service === void 0) return void 0;
|
|
25827
|
+
for (const list of registryCandidates(service)) {
|
|
25828
|
+
const found = list.find(isSkillSource);
|
|
25829
|
+
if (found !== void 0) return found;
|
|
25830
|
+
}
|
|
25831
|
+
return void 0;
|
|
25832
|
+
}
|
|
25833
|
+
function wrapSkillSource(source, hooks = {}) {
|
|
25834
|
+
const { rank, order, onPick } = hooks;
|
|
25835
|
+
if (source === null || typeof source !== "object") return void 0;
|
|
25836
|
+
if (isSkillSourceWrapped(source)) return void 0;
|
|
25837
|
+
if (Object.isFrozen(source)) return void 0;
|
|
25838
|
+
const original = {
|
|
25839
|
+
candidates: source.candidates,
|
|
25840
|
+
order: source.order,
|
|
25841
|
+
hadOrder: Object.hasOwn(source, "order"),
|
|
25842
|
+
onPick: source.onPick,
|
|
25843
|
+
hadOnPick: Object.hasOwn(source, "onPick")
|
|
25844
|
+
};
|
|
25845
|
+
const taken = [];
|
|
25846
|
+
const wrappedCandidates = typeof rank === "function" && typeof original.candidates === "function" ? async function candidates(projection, args) {
|
|
25847
|
+
const options = args ?? {};
|
|
25848
|
+
const everything = await original.candidates.call(this, projection, { ...options, query: "" });
|
|
25849
|
+
const query = String(options.query ?? "").trim();
|
|
25850
|
+
if (query === "" || !Array.isArray(everything)) return everything;
|
|
25851
|
+
try {
|
|
25852
|
+
return rank(everything, query);
|
|
25853
|
+
} catch {
|
|
25854
|
+
return everything;
|
|
25855
|
+
}
|
|
25856
|
+
} : void 0;
|
|
25857
|
+
const wrappedPick = typeof onPick === "function" && typeof original.onPick === "function" ? function onPickWrapped(args) {
|
|
25858
|
+
try {
|
|
25859
|
+
const name = args?.candidate?.name;
|
|
25860
|
+
if (typeof name === "string") onPick(name);
|
|
25861
|
+
} catch {
|
|
25862
|
+
}
|
|
25863
|
+
return original.onPick.call(this, args);
|
|
25864
|
+
} : void 0;
|
|
25865
|
+
try {
|
|
25866
|
+
Object.defineProperty(source, WRAPPED, { value: true, enumerable: false, configurable: true });
|
|
25867
|
+
if (wrappedCandidates !== void 0) {
|
|
25868
|
+
source.candidates = wrappedCandidates;
|
|
25869
|
+
taken.push("candidates");
|
|
25870
|
+
}
|
|
25871
|
+
if (typeof order === "number" && source.order !== order) {
|
|
25872
|
+
source.order = order;
|
|
25873
|
+
taken.push("order");
|
|
25874
|
+
}
|
|
25875
|
+
if (wrappedPick !== void 0) {
|
|
25876
|
+
source.onPick = wrappedPick;
|
|
25877
|
+
taken.push("onPick");
|
|
25878
|
+
}
|
|
25879
|
+
} catch {
|
|
25880
|
+
try {
|
|
25881
|
+
delete source[WRAPPED];
|
|
25882
|
+
} catch {
|
|
25883
|
+
}
|
|
25884
|
+
return void 0;
|
|
25885
|
+
}
|
|
25886
|
+
if (taken.length === 0) {
|
|
25887
|
+
try {
|
|
25888
|
+
delete source[WRAPPED];
|
|
25889
|
+
} catch {
|
|
25890
|
+
}
|
|
25891
|
+
return void 0;
|
|
25892
|
+
}
|
|
25893
|
+
enhancementMode = "runtime";
|
|
25894
|
+
return () => {
|
|
25895
|
+
try {
|
|
25896
|
+
if (taken.includes("candidates")) source.candidates = original.candidates;
|
|
25897
|
+
if (taken.includes("order")) {
|
|
25898
|
+
if (original.hadOrder) source.order = original.order;
|
|
25899
|
+
else delete source.order;
|
|
25900
|
+
}
|
|
25901
|
+
if (taken.includes("onPick")) {
|
|
25902
|
+
if (original.hadOnPick) source.onPick = original.onPick;
|
|
25903
|
+
else delete source.onPick;
|
|
25904
|
+
}
|
|
25905
|
+
delete source[WRAPPED];
|
|
25906
|
+
enhancementMode = void 0;
|
|
25907
|
+
} catch {
|
|
25908
|
+
}
|
|
25909
|
+
};
|
|
25910
|
+
}
|
|
25911
|
+
function installSlashFuzzy(inputTriggers, hooks = {}, options = {}) {
|
|
25912
|
+
const maxAttempts = options.attempts ?? 40;
|
|
25913
|
+
const intervalMs = options.intervalMs ?? 250;
|
|
25914
|
+
let restore;
|
|
25915
|
+
let timer;
|
|
25916
|
+
let attempts = 0;
|
|
25917
|
+
let stopped = false;
|
|
25918
|
+
const attempt = () => {
|
|
25919
|
+
if (stopped || restore !== void 0) return;
|
|
25920
|
+
try {
|
|
25921
|
+
const source = findSkillSource(inputTriggers);
|
|
25922
|
+
if (source === void 0) {
|
|
25923
|
+
if (attempts++ < maxAttempts) {
|
|
25924
|
+
timer = setTimeout(attempt, intervalMs);
|
|
25925
|
+
} else {
|
|
25926
|
+
console.warn(`[dsh-skill-picker] / takeover: the official "skill" trigger source was not found after ${maxAttempts} attempts \u2014 the / menu keeps the official matcher. See https://github.com/a735624258/dsh-skill-picker/issues/14`);
|
|
25927
|
+
}
|
|
25928
|
+
return;
|
|
25929
|
+
}
|
|
25930
|
+
restore = wrapSkillSource(source, hooks) ?? (() => {
|
|
25931
|
+
});
|
|
25932
|
+
} catch {
|
|
25933
|
+
restore = () => {
|
|
25934
|
+
};
|
|
25935
|
+
}
|
|
25936
|
+
};
|
|
25937
|
+
attempt();
|
|
25938
|
+
return () => {
|
|
25939
|
+
stopped = true;
|
|
25940
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
25941
|
+
restore?.();
|
|
25942
|
+
restore = void 0;
|
|
25943
|
+
};
|
|
25944
|
+
}
|
|
25945
|
+
|
|
25765
25946
|
// src/client/index.jsx
|
|
25766
25947
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25767
25948
|
var inject = ["slots", "connection", "sessions", "inputTriggers"];
|
|
@@ -25866,6 +26047,25 @@ function matchRank(skill, q) {
|
|
|
25866
26047
|
if (py.includes(q)) return 3;
|
|
25867
26048
|
return 4;
|
|
25868
26049
|
}
|
|
26050
|
+
function rankPickerItems(items, query) {
|
|
26051
|
+
const ordered = groupByPinned(
|
|
26052
|
+
Array.isArray(items) ? items : [],
|
|
26053
|
+
loadUsage(),
|
|
26054
|
+
loadPinned()
|
|
26055
|
+
).flatMap((group) => group.items);
|
|
26056
|
+
const q = String(query ?? "").trim().toLowerCase();
|
|
26057
|
+
if (q === "") return ordered;
|
|
26058
|
+
const order = new Map(ordered.map((skill, index) => [skill.name, index]));
|
|
26059
|
+
const targets = ordered.map((s) => ({
|
|
26060
|
+
s,
|
|
26061
|
+
search: `${s.name} ${s.description ?? ""} ${skillPinyinText(s.name, s.description ?? "")}`
|
|
26062
|
+
}));
|
|
26063
|
+
return fuzzysort_default.go(q, targets, {
|
|
26064
|
+
key: "search",
|
|
26065
|
+
limit: 30,
|
|
26066
|
+
threshold: -1e4
|
|
26067
|
+
}).filter((r) => r.score > 0).map((r) => r.obj.s).filter((s) => matchRank(s, q) < 4).sort((a, b) => matchRank(a, q) - matchRank(b, q) || (order.get(a.name) ?? 0) - (order.get(b.name) ?? 0));
|
|
26068
|
+
}
|
|
25869
26069
|
var buttonStyle = {
|
|
25870
26070
|
display: "inline-flex",
|
|
25871
26071
|
alignItems: "center",
|
|
@@ -26011,9 +26211,10 @@ function SkillPickerButton(props) {
|
|
|
26011
26211
|
}
|
|
26012
26212
|
const load = (0, import_react.useCallback)(async () => {
|
|
26013
26213
|
if (skills !== void 0 || error !== void 0) return;
|
|
26214
|
+
const sessionId = sessionIdOf(props);
|
|
26014
26215
|
try {
|
|
26015
|
-
if (typeof props.listSkills === "function" &&
|
|
26016
|
-
const listed = await props.listSkills(
|
|
26216
|
+
if (typeof props.listSkills === "function" && sessionId !== void 0) {
|
|
26217
|
+
const listed = await props.listSkills(sessionId);
|
|
26017
26218
|
setSkills(Array.isArray(listed) ? listed : []);
|
|
26018
26219
|
setSource("official");
|
|
26019
26220
|
return;
|
|
@@ -26031,7 +26232,7 @@ function SkillPickerButton(props) {
|
|
|
26031
26232
|
} catch (cause) {
|
|
26032
26233
|
setError(String(cause?.message ?? cause));
|
|
26033
26234
|
}
|
|
26034
|
-
}, [skills, error, props.listSkills, props.session, props.cwd]);
|
|
26235
|
+
}, [skills, error, props.listSkills, props.sessionId, props.session, props.cwd]);
|
|
26035
26236
|
const toggle = () => {
|
|
26036
26237
|
if (!open) {
|
|
26037
26238
|
setUsage(loadUsage());
|
|
@@ -26221,7 +26422,15 @@ function SkillPickerButton(props) {
|
|
|
26221
26422
|
] }, group.title);
|
|
26222
26423
|
});
|
|
26223
26424
|
})() }),
|
|
26224
|
-
source === "host" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: sourceBadgeStyle, title: "\u5B98\u65B9\u6280\u80FD API \u4E0D\u53EF\u7528\uFF0C\u5217\u8868\u6765\u81EA\u672C\u5730\u76EE\u5F55\u626B\u63CF\uFF08\u4E0E\u5B98\u65B9 / \u8865\u5168\u540C\u6E90\uFF09", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: sourceBadgeTextStyle, children: "\u672C\u5730\u626B\u63CF" }) })
|
|
26425
|
+
source === "host" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: sourceBadgeStyle, title: "\u5B98\u65B9\u6280\u80FD API \u4E0D\u53EF\u7528\uFF0C\u5217\u8868\u6765\u81EA\u672C\u5730\u76EE\u5F55\u626B\u63CF\uFF08\u4E0E\u5B98\u65B9 / \u8865\u5168\u540C\u6E90\uFF09", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: sourceBadgeTextStyle, children: "\u672C\u5730\u626B\u63CF" }) }),
|
|
26426
|
+
slashEnhancementMode() === "runtime" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
26427
|
+
"div",
|
|
26428
|
+
{
|
|
26429
|
+
style: sourceBadgeStyle,
|
|
26430
|
+
title: "`/` \u83DC\u5355\u7684\u6A21\u7CCA+\u62FC\u97F3\u641C\u7D22\u7531\u672C\u63D2\u4EF6\u5728\u8FD0\u884C\u65F6\u63A5\u7BA1\u5B98\u65B9\u6280\u80FD\u6E90\uFF08\u4E0D\u4F9D\u8D56\u6539\u5199\u4EFB\u4F55\u6587\u4EF6\uFF0Cissue #14\uFF09",
|
|
26431
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: sourceBadgeTextStyle, children: "/ \u589E\u5F3A\uFF1A\u8FD0\u884C\u65F6\u63A5\u7BA1" })
|
|
26432
|
+
}
|
|
26433
|
+
)
|
|
26225
26434
|
] })
|
|
26226
26435
|
] })
|
|
26227
26436
|
] });
|
|
@@ -26240,21 +26449,28 @@ function apply(ctx) {
|
|
|
26240
26449
|
const raw = result.value?.skills ?? [];
|
|
26241
26450
|
return raw.filter(isUserFacingSkill).map((skill) => ({ name: skill.name, description: skill.description ?? "" }));
|
|
26242
26451
|
};
|
|
26243
|
-
let
|
|
26244
|
-
const
|
|
26452
|
+
let legacyCwd = "";
|
|
26453
|
+
const syncLegacyCwd = () => {
|
|
26245
26454
|
try {
|
|
26246
26455
|
const snapshot2 = ctx.sessions.list.getSnapshot();
|
|
26247
26456
|
const sessionId = snapshot2.current;
|
|
26248
26457
|
const cwd = sessionId === void 0 ? void 0 : snapshot2.byId[sessionId]?.cwd;
|
|
26249
|
-
|
|
26458
|
+
legacyCwd = typeof cwd === "string" ? cwd : "";
|
|
26250
26459
|
} catch {
|
|
26251
|
-
|
|
26460
|
+
legacyCwd = "";
|
|
26252
26461
|
}
|
|
26253
26462
|
};
|
|
26254
|
-
|
|
26255
|
-
const
|
|
26463
|
+
syncLegacyCwd();
|
|
26464
|
+
const unsubscribeLegacyCwd = ctx.sessions.list.subscribe(syncLegacyCwd);
|
|
26256
26465
|
ctx.effect(() => {
|
|
26257
|
-
const PickerWithCwd = (props) =>
|
|
26466
|
+
const PickerWithCwd = (props) => {
|
|
26467
|
+
const cwd = useWorkspaceCwd(props);
|
|
26468
|
+
return import_react.default.createElement(SkillPickerButton, {
|
|
26469
|
+
...props,
|
|
26470
|
+
cwd: cwd === "" ? legacyCwd : cwd,
|
|
26471
|
+
listSkills
|
|
26472
|
+
});
|
|
26473
|
+
};
|
|
26258
26474
|
const dispose = ctx.slots.inject(
|
|
26259
26475
|
"conversation.input.right",
|
|
26260
26476
|
() => ctx.slots.register(
|
|
@@ -26264,43 +26480,43 @@ function apply(ctx) {
|
|
|
26264
26480
|
);
|
|
26265
26481
|
return () => {
|
|
26266
26482
|
dispose();
|
|
26267
|
-
|
|
26483
|
+
unsubscribeLegacyCwd();
|
|
26268
26484
|
};
|
|
26269
26485
|
}, "dsh-skill-picker: composer input slot");
|
|
26486
|
+
const trackPick = (name) => {
|
|
26487
|
+
const usage = loadUsage();
|
|
26488
|
+
const nextUsage = { ...usage, [name]: { count: (usage[name]?.count ?? 0) + 1, lastUsed: Date.now() } };
|
|
26489
|
+
saveUsage(nextUsage);
|
|
26490
|
+
try {
|
|
26491
|
+
window.dispatchEvent(new CustomEvent("dsh-skill-picker:usage-updated"));
|
|
26492
|
+
} catch {
|
|
26493
|
+
}
|
|
26494
|
+
};
|
|
26270
26495
|
ctx.effect(() => {
|
|
26271
26496
|
const fuzzyMatch = (skills, query = "") => {
|
|
26272
26497
|
const visible = (Array.isArray(skills) ? skills : []).filter(isUserFacingSkill);
|
|
26273
|
-
|
|
26274
|
-
const q = String(query).trim().toLowerCase();
|
|
26275
|
-
if (q === "") return ordered;
|
|
26276
|
-
const rankByName = new Map(ordered.map((skill, index) => [skill.name, index]));
|
|
26277
|
-
const targets = ordered.map((s) => ({
|
|
26278
|
-
s,
|
|
26279
|
-
search: `${s.name} ${s.description ?? ""} ${skillPinyinText(s.name, s.description ?? "")}`
|
|
26280
|
-
}));
|
|
26281
|
-
const results = fuzzysort_default.go(q, targets, {
|
|
26282
|
-
key: "search",
|
|
26283
|
-
limit: 30,
|
|
26284
|
-
threshold: -1e4
|
|
26285
|
-
});
|
|
26286
|
-
return results.filter((r) => r.score > 0).map((r) => r.obj.s).filter((s) => matchRank(s, q) < 4).sort((a, b) => matchRank(a, q) - matchRank(b, q) || (rankByName.get(a.name) ?? 0) - (rankByName.get(b.name) ?? 0));
|
|
26498
|
+
return rankPickerItems(visible, query);
|
|
26287
26499
|
};
|
|
26288
26500
|
window.__dshSkillPickerFuzzy = fuzzyMatch;
|
|
26289
|
-
const trackPick = (name) => {
|
|
26290
|
-
const usage = loadUsage();
|
|
26291
|
-
const nextUsage = { ...usage, [name]: { count: (usage[name]?.count ?? 0) + 1, lastUsed: Date.now() } };
|
|
26292
|
-
saveUsage(nextUsage);
|
|
26293
|
-
try {
|
|
26294
|
-
window.dispatchEvent(new CustomEvent("dsh-skill-picker:usage-updated"));
|
|
26295
|
-
} catch {
|
|
26296
|
-
}
|
|
26297
|
-
};
|
|
26298
26501
|
window.__dshSkillPickerTrack = trackPick;
|
|
26299
26502
|
return () => {
|
|
26300
26503
|
if (window.__dshSkillPickerFuzzy === fuzzyMatch) delete window.__dshSkillPickerFuzzy;
|
|
26301
26504
|
if (window.__dshSkillPickerTrack === trackPick) delete window.__dshSkillPickerTrack;
|
|
26302
26505
|
};
|
|
26303
26506
|
}, "dsh-skill-picker: fuzzy matcher for official / source");
|
|
26507
|
+
ctx.effect(() => {
|
|
26508
|
+
const inputTriggers = ctx.inputTriggers ?? ctx.get?.("inputTriggers");
|
|
26509
|
+
if (inputTriggers === void 0) return () => {
|
|
26510
|
+
};
|
|
26511
|
+
return installSlashFuzzy(inputTriggers, {
|
|
26512
|
+
// Rank the official display items ({name, description}) by the same rule
|
|
26513
|
+
// the bolt panel uses, so the two lists agree on order as well as match.
|
|
26514
|
+
rank: (items, query) => rankPickerItems(items, query),
|
|
26515
|
+
// `order: 2` (official) → `-1`: the skill group sorts above commands.
|
|
26516
|
+
order: -1,
|
|
26517
|
+
onPick: trackPick
|
|
26518
|
+
});
|
|
26519
|
+
}, "dsh-skill-picker: runtime takeover of the official / skill source");
|
|
26304
26520
|
}
|
|
26305
26521
|
return module.exports; } });
|
|
26306
26522
|
//# sourceMappingURL=client.js.map
|