dsh-skill-picker 0.5.13 → 0.5.18
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 +242 -214
- package/lib/client.js +285 -24
- package/lib/client.js.map +3 -3
- package/lib/index.js +1 -1
- package/lib/index.js.map +2 -2
- package/package.json +76 -76
- package/src/client/index.jsx +109 -46
- package/src/client/slash-source.js +440 -0
- package/src/patch-ui-skill.js +1 -1
package/lib/client.js
CHANGED
|
@@ -25778,6 +25778,236 @@ function useWorkspaceCwd(props) {
|
|
|
25778
25778
|
return typeof cwd === "string" ? cwd : "";
|
|
25779
25779
|
}
|
|
25780
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
|
+
var takenOverSource;
|
|
25789
|
+
var pendingSessionId;
|
|
25790
|
+
var itemCache = /* @__PURE__ */ new Map();
|
|
25791
|
+
function noteDiag(patch) {
|
|
25792
|
+
try {
|
|
25793
|
+
const key = "dsh-skill-picker:diag";
|
|
25794
|
+
const previous = JSON.parse(localStorage.getItem(key) ?? "{}");
|
|
25795
|
+
localStorage.setItem(key, JSON.stringify({ ...previous, ...patch, at: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
25796
|
+
} catch {
|
|
25797
|
+
}
|
|
25798
|
+
}
|
|
25799
|
+
function refreshCache(cacheKey, originalCandidates, self, projection, options) {
|
|
25800
|
+
try {
|
|
25801
|
+
const signal = typeof AbortController === "function" ? new AbortController().signal : void 0;
|
|
25802
|
+
Promise.resolve().then(() => originalCandidates.call(self, projection, { ...options, query: "", signal })).then((items) => {
|
|
25803
|
+
if (Array.isArray(items)) itemCache.set(cacheKey, items.slice());
|
|
25804
|
+
}).catch(() => {
|
|
25805
|
+
});
|
|
25806
|
+
} catch {
|
|
25807
|
+
}
|
|
25808
|
+
}
|
|
25809
|
+
function slashEnhancementMode() {
|
|
25810
|
+
return enhancementMode;
|
|
25811
|
+
}
|
|
25812
|
+
function warmSlashSkill(sessionId) {
|
|
25813
|
+
if (typeof sessionId !== "string" || sessionId === "") return;
|
|
25814
|
+
if (primeNow(sessionId)) pendingSessionId = void 0;
|
|
25815
|
+
else pendingSessionId = sessionId;
|
|
25816
|
+
}
|
|
25817
|
+
function primeNow(sessionId) {
|
|
25818
|
+
const source = takenOverSource;
|
|
25819
|
+
if (source === null || source === void 0) return false;
|
|
25820
|
+
if (itemCache.has(sessionId)) return true;
|
|
25821
|
+
try {
|
|
25822
|
+
const signal = typeof AbortController === "function" ? new AbortController().signal : void 0;
|
|
25823
|
+
Promise.resolve(source.candidates({ sessionId }, { query: "", signal })).catch(() => {
|
|
25824
|
+
});
|
|
25825
|
+
} catch {
|
|
25826
|
+
}
|
|
25827
|
+
return true;
|
|
25828
|
+
}
|
|
25829
|
+
function isSkillSource(source) {
|
|
25830
|
+
return source !== null && typeof source === "object" && source.trigger === SKILL_SOURCE.trigger && source.name === SKILL_SOURCE.name;
|
|
25831
|
+
}
|
|
25832
|
+
function registryCandidates(service) {
|
|
25833
|
+
const lists = [];
|
|
25834
|
+
const push = (value) => {
|
|
25835
|
+
if (Array.isArray(value) && value.length > 0) lists.push(value);
|
|
25836
|
+
};
|
|
25837
|
+
try {
|
|
25838
|
+
push(service.live?.sources);
|
|
25839
|
+
} catch {
|
|
25840
|
+
}
|
|
25841
|
+
try {
|
|
25842
|
+
if (typeof service.sources === "function") push(service.sources(SKILL_SOURCE.trigger));
|
|
25843
|
+
} catch {
|
|
25844
|
+
}
|
|
25845
|
+
try {
|
|
25846
|
+
if (typeof service.all === "function") push(service.all());
|
|
25847
|
+
} catch {
|
|
25848
|
+
}
|
|
25849
|
+
try {
|
|
25850
|
+
push(service.sources);
|
|
25851
|
+
} catch {
|
|
25852
|
+
}
|
|
25853
|
+
try {
|
|
25854
|
+
if (typeof service.roster?.sources === "function") push(service.roster.sources(SKILL_SOURCE.trigger));
|
|
25855
|
+
} catch {
|
|
25856
|
+
}
|
|
25857
|
+
try {
|
|
25858
|
+
if (typeof service.roster?.all === "function") push(service.roster.all());
|
|
25859
|
+
} catch {
|
|
25860
|
+
}
|
|
25861
|
+
return lists;
|
|
25862
|
+
}
|
|
25863
|
+
function findSkillSource(service) {
|
|
25864
|
+
if (service === null || service === void 0) return void 0;
|
|
25865
|
+
for (const list of registryCandidates(service)) {
|
|
25866
|
+
const found = list.find(isSkillSource);
|
|
25867
|
+
if (found !== void 0) return found;
|
|
25868
|
+
}
|
|
25869
|
+
return void 0;
|
|
25870
|
+
}
|
|
25871
|
+
function wrapSkillSource(source, hooks = {}) {
|
|
25872
|
+
const { rank, order, onPick } = hooks;
|
|
25873
|
+
if (source === null || typeof source !== "object") return void 0;
|
|
25874
|
+
if (isSkillSourceWrapped(source)) return void 0;
|
|
25875
|
+
if (Object.isFrozen(source)) return void 0;
|
|
25876
|
+
const original = {
|
|
25877
|
+
candidates: source.candidates,
|
|
25878
|
+
order: source.order,
|
|
25879
|
+
hadOrder: Object.hasOwn(source, "order"),
|
|
25880
|
+
onPick: source.onPick,
|
|
25881
|
+
hadOnPick: Object.hasOwn(source, "onPick")
|
|
25882
|
+
};
|
|
25883
|
+
const taken = [];
|
|
25884
|
+
const wrappedCandidates = typeof rank === "function" && typeof original.candidates === "function" ? async function candidates(projection, args) {
|
|
25885
|
+
const options = args ?? {};
|
|
25886
|
+
const query = String(options.query ?? "").trim();
|
|
25887
|
+
const sessionId = projection?.sessionId;
|
|
25888
|
+
const cacheKey = typeof sessionId === "string" ? sessionId : void 0;
|
|
25889
|
+
const cached = cacheKey === void 0 ? void 0 : itemCache.get(cacheKey);
|
|
25890
|
+
if (cached !== void 0) {
|
|
25891
|
+
noteDiag({ mode: "runtime", servedFromCache: true, sessionId: cacheKey, query });
|
|
25892
|
+
refreshCache(cacheKey, original.candidates, this, projection, options);
|
|
25893
|
+
if (query === "") return cached;
|
|
25894
|
+
try {
|
|
25895
|
+
return rank(cached, query);
|
|
25896
|
+
} catch {
|
|
25897
|
+
return cached;
|
|
25898
|
+
}
|
|
25899
|
+
}
|
|
25900
|
+
const everything = await original.candidates.call(this, projection, { ...options, query: "" });
|
|
25901
|
+
if (cacheKey !== void 0 && Array.isArray(everything)) {
|
|
25902
|
+
itemCache.set(cacheKey, everything.slice());
|
|
25903
|
+
noteDiag({ mode: "runtime", servedFromCache: false, sessionId: cacheKey, primed: true, count: everything.length });
|
|
25904
|
+
}
|
|
25905
|
+
if (query === "" || !Array.isArray(everything)) return everything;
|
|
25906
|
+
try {
|
|
25907
|
+
return rank(everything, query);
|
|
25908
|
+
} catch {
|
|
25909
|
+
return everything;
|
|
25910
|
+
}
|
|
25911
|
+
} : void 0;
|
|
25912
|
+
const wrappedPick = typeof onPick === "function" && typeof original.onPick === "function" ? function onPickWrapped(args) {
|
|
25913
|
+
try {
|
|
25914
|
+
const name = args?.candidate?.name;
|
|
25915
|
+
if (typeof name === "string") onPick(name);
|
|
25916
|
+
} catch {
|
|
25917
|
+
}
|
|
25918
|
+
return original.onPick.call(this, args);
|
|
25919
|
+
} : void 0;
|
|
25920
|
+
try {
|
|
25921
|
+
Object.defineProperty(source, WRAPPED, { value: true, enumerable: false, configurable: true });
|
|
25922
|
+
if (wrappedCandidates !== void 0) {
|
|
25923
|
+
source.candidates = wrappedCandidates;
|
|
25924
|
+
taken.push("candidates");
|
|
25925
|
+
}
|
|
25926
|
+
if (typeof order === "number" && source.order !== order) {
|
|
25927
|
+
source.order = order;
|
|
25928
|
+
taken.push("order");
|
|
25929
|
+
}
|
|
25930
|
+
if (wrappedPick !== void 0) {
|
|
25931
|
+
source.onPick = wrappedPick;
|
|
25932
|
+
taken.push("onPick");
|
|
25933
|
+
}
|
|
25934
|
+
} catch {
|
|
25935
|
+
try {
|
|
25936
|
+
delete source[WRAPPED];
|
|
25937
|
+
} catch {
|
|
25938
|
+
}
|
|
25939
|
+
return void 0;
|
|
25940
|
+
}
|
|
25941
|
+
if (taken.length === 0) {
|
|
25942
|
+
try {
|
|
25943
|
+
delete source[WRAPPED];
|
|
25944
|
+
} catch {
|
|
25945
|
+
}
|
|
25946
|
+
return void 0;
|
|
25947
|
+
}
|
|
25948
|
+
enhancementMode = "runtime";
|
|
25949
|
+
takenOverSource = source;
|
|
25950
|
+
noteDiag({ mode: "runtime", installed: true, took: taken.join("+") });
|
|
25951
|
+
if (pendingSessionId !== void 0) {
|
|
25952
|
+
const sessionId = pendingSessionId;
|
|
25953
|
+
pendingSessionId = void 0;
|
|
25954
|
+
primeNow(sessionId);
|
|
25955
|
+
}
|
|
25956
|
+
return () => {
|
|
25957
|
+
try {
|
|
25958
|
+
if (taken.includes("candidates")) source.candidates = original.candidates;
|
|
25959
|
+
if (taken.includes("order")) {
|
|
25960
|
+
if (original.hadOrder) source.order = original.order;
|
|
25961
|
+
else delete source.order;
|
|
25962
|
+
}
|
|
25963
|
+
if (taken.includes("onPick")) {
|
|
25964
|
+
if (original.hadOnPick) source.onPick = original.onPick;
|
|
25965
|
+
else delete source.onPick;
|
|
25966
|
+
}
|
|
25967
|
+
delete source[WRAPPED];
|
|
25968
|
+
enhancementMode = void 0;
|
|
25969
|
+
if (takenOverSource === source) takenOverSource = void 0;
|
|
25970
|
+
pendingSessionId = void 0;
|
|
25971
|
+
} catch {
|
|
25972
|
+
}
|
|
25973
|
+
};
|
|
25974
|
+
}
|
|
25975
|
+
function installSlashFuzzy(inputTriggers, hooks = {}, options = {}) {
|
|
25976
|
+
const maxAttempts = options.attempts ?? 40;
|
|
25977
|
+
const intervalMs = options.intervalMs ?? 250;
|
|
25978
|
+
let restore;
|
|
25979
|
+
let timer;
|
|
25980
|
+
let attempts = 0;
|
|
25981
|
+
let stopped = false;
|
|
25982
|
+
const attempt = () => {
|
|
25983
|
+
if (stopped || restore !== void 0) return;
|
|
25984
|
+
try {
|
|
25985
|
+
const source = findSkillSource(inputTriggers);
|
|
25986
|
+
if (source === void 0) {
|
|
25987
|
+
if (attempts++ < maxAttempts) {
|
|
25988
|
+
timer = setTimeout(attempt, intervalMs);
|
|
25989
|
+
} else {
|
|
25990
|
+
noteDiag({ mode: "none", gaveUp: true, attempts: maxAttempts });
|
|
25991
|
+
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`);
|
|
25992
|
+
}
|
|
25993
|
+
return;
|
|
25994
|
+
}
|
|
25995
|
+
restore = wrapSkillSource(source, hooks) ?? (() => {
|
|
25996
|
+
});
|
|
25997
|
+
} catch {
|
|
25998
|
+
restore = () => {
|
|
25999
|
+
};
|
|
26000
|
+
}
|
|
26001
|
+
};
|
|
26002
|
+
attempt();
|
|
26003
|
+
return () => {
|
|
26004
|
+
stopped = true;
|
|
26005
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
26006
|
+
restore?.();
|
|
26007
|
+
restore = void 0;
|
|
26008
|
+
};
|
|
26009
|
+
}
|
|
26010
|
+
|
|
25781
26011
|
// src/client/index.jsx
|
|
25782
26012
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25783
26013
|
var inject = ["slots", "connection", "sessions", "inputTriggers"];
|
|
@@ -25882,6 +26112,25 @@ function matchRank(skill, q) {
|
|
|
25882
26112
|
if (py.includes(q)) return 3;
|
|
25883
26113
|
return 4;
|
|
25884
26114
|
}
|
|
26115
|
+
function rankPickerItems(items, query) {
|
|
26116
|
+
const ordered = groupByPinned(
|
|
26117
|
+
Array.isArray(items) ? items : [],
|
|
26118
|
+
loadUsage(),
|
|
26119
|
+
loadPinned()
|
|
26120
|
+
).flatMap((group) => group.items);
|
|
26121
|
+
const q = String(query ?? "").trim().toLowerCase();
|
|
26122
|
+
if (q === "") return ordered;
|
|
26123
|
+
const order = new Map(ordered.map((skill, index) => [skill.name, index]));
|
|
26124
|
+
const targets = ordered.map((s) => ({
|
|
26125
|
+
s,
|
|
26126
|
+
search: `${s.name} ${s.description ?? ""} ${skillPinyinText(s.name, s.description ?? "")}`
|
|
26127
|
+
}));
|
|
26128
|
+
return fuzzysort_default.go(q, targets, {
|
|
26129
|
+
key: "search",
|
|
26130
|
+
limit: 30,
|
|
26131
|
+
threshold: -1e4
|
|
26132
|
+
}).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));
|
|
26133
|
+
}
|
|
25885
26134
|
var buttonStyle = {
|
|
25886
26135
|
display: "inline-flex",
|
|
25887
26136
|
alignItems: "center",
|
|
@@ -26015,6 +26264,10 @@ function SkillPickerButton(props) {
|
|
|
26015
26264
|
window.addEventListener("dsh-skill-picker:usage-updated", onUsageUpdated);
|
|
26016
26265
|
return () => window.removeEventListener("dsh-skill-picker:usage-updated", onUsageUpdated);
|
|
26017
26266
|
}, []);
|
|
26267
|
+
const activeSessionId = sessionIdOf(props);
|
|
26268
|
+
(0, import_react.useEffect)(() => {
|
|
26269
|
+
if (activeSessionId !== void 0) warmSlashSkill(activeSessionId);
|
|
26270
|
+
}, [activeSessionId]);
|
|
26018
26271
|
const draftRef = (0, import_react.useRef)("");
|
|
26019
26272
|
if (typeof props.useInput === "function") {
|
|
26020
26273
|
try {
|
|
@@ -26238,7 +26491,15 @@ function SkillPickerButton(props) {
|
|
|
26238
26491
|
] }, group.title);
|
|
26239
26492
|
});
|
|
26240
26493
|
})() }),
|
|
26241
|
-
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" }) })
|
|
26494
|
+
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" }) }),
|
|
26495
|
+
slashEnhancementMode() === "runtime" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
26496
|
+
"div",
|
|
26497
|
+
{
|
|
26498
|
+
style: sourceBadgeStyle,
|
|
26499
|
+
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",
|
|
26500
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: sourceBadgeTextStyle, children: "/ \u589E\u5F3A\uFF1A\u8FD0\u884C\u65F6\u63A5\u7BA1" })
|
|
26501
|
+
}
|
|
26502
|
+
)
|
|
26242
26503
|
] })
|
|
26243
26504
|
] })
|
|
26244
26505
|
] });
|
|
@@ -26291,40 +26552,40 @@ function apply(ctx) {
|
|
|
26291
26552
|
unsubscribeLegacyCwd();
|
|
26292
26553
|
};
|
|
26293
26554
|
}, "dsh-skill-picker: composer input slot");
|
|
26555
|
+
const trackPick = (name) => {
|
|
26556
|
+
const usage = loadUsage();
|
|
26557
|
+
const nextUsage = { ...usage, [name]: { count: (usage[name]?.count ?? 0) + 1, lastUsed: Date.now() } };
|
|
26558
|
+
saveUsage(nextUsage);
|
|
26559
|
+
try {
|
|
26560
|
+
window.dispatchEvent(new CustomEvent("dsh-skill-picker:usage-updated"));
|
|
26561
|
+
} catch {
|
|
26562
|
+
}
|
|
26563
|
+
};
|
|
26294
26564
|
ctx.effect(() => {
|
|
26295
26565
|
const fuzzyMatch = (skills, query = "") => {
|
|
26296
26566
|
const visible = (Array.isArray(skills) ? skills : []).filter(isUserFacingSkill);
|
|
26297
|
-
|
|
26298
|
-
const q = String(query).trim().toLowerCase();
|
|
26299
|
-
if (q === "") return ordered;
|
|
26300
|
-
const rankByName = new Map(ordered.map((skill, index) => [skill.name, index]));
|
|
26301
|
-
const targets = ordered.map((s) => ({
|
|
26302
|
-
s,
|
|
26303
|
-
search: `${s.name} ${s.description ?? ""} ${skillPinyinText(s.name, s.description ?? "")}`
|
|
26304
|
-
}));
|
|
26305
|
-
const results = fuzzysort_default.go(q, targets, {
|
|
26306
|
-
key: "search",
|
|
26307
|
-
limit: 30,
|
|
26308
|
-
threshold: -1e4
|
|
26309
|
-
});
|
|
26310
|
-
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));
|
|
26567
|
+
return rankPickerItems(visible, query);
|
|
26311
26568
|
};
|
|
26312
26569
|
window.__dshSkillPickerFuzzy = fuzzyMatch;
|
|
26313
|
-
const trackPick = (name) => {
|
|
26314
|
-
const usage = loadUsage();
|
|
26315
|
-
const nextUsage = { ...usage, [name]: { count: (usage[name]?.count ?? 0) + 1, lastUsed: Date.now() } };
|
|
26316
|
-
saveUsage(nextUsage);
|
|
26317
|
-
try {
|
|
26318
|
-
window.dispatchEvent(new CustomEvent("dsh-skill-picker:usage-updated"));
|
|
26319
|
-
} catch {
|
|
26320
|
-
}
|
|
26321
|
-
};
|
|
26322
26570
|
window.__dshSkillPickerTrack = trackPick;
|
|
26323
26571
|
return () => {
|
|
26324
26572
|
if (window.__dshSkillPickerFuzzy === fuzzyMatch) delete window.__dshSkillPickerFuzzy;
|
|
26325
26573
|
if (window.__dshSkillPickerTrack === trackPick) delete window.__dshSkillPickerTrack;
|
|
26326
26574
|
};
|
|
26327
26575
|
}, "dsh-skill-picker: fuzzy matcher for official / source");
|
|
26576
|
+
ctx.effect(() => {
|
|
26577
|
+
const inputTriggers = ctx.inputTriggers ?? ctx.get?.("inputTriggers");
|
|
26578
|
+
if (inputTriggers === void 0) return () => {
|
|
26579
|
+
};
|
|
26580
|
+
return installSlashFuzzy(inputTriggers, {
|
|
26581
|
+
// Rank the official display items ({name, description}) by the same rule
|
|
26582
|
+
// the bolt panel uses, so the two lists agree on order as well as match.
|
|
26583
|
+
rank: (items, query) => rankPickerItems(items, query),
|
|
26584
|
+
// `order: 2` (official) → `-1`: the skill group sorts above commands.
|
|
26585
|
+
order: -1,
|
|
26586
|
+
onPick: trackPick
|
|
26587
|
+
});
|
|
26588
|
+
}, "dsh-skill-picker: runtime takeover of the official / skill source");
|
|
26328
26589
|
}
|
|
26329
26590
|
return module.exports; } });
|
|
26330
26591
|
//# sourceMappingURL=client.js.map
|