dsh-skill-importer 0.2.3 → 0.2.5
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 +20 -8
- package/README.zh.md +19 -7
- package/lib/client.js +874 -110
- package/lib/index.js +199 -41
- package/lib/types/client/SkillImporterSection.d.ts +1 -1
- package/lib/types/client/SkillsPicker.d.ts +1 -1
- package/lib/types/client/effectiveSkills.d.ts +3 -0
- package/lib/types/client/index.d.ts +12 -4
- package/lib/types/client/locales.d.ts +80 -2
- package/lib/types/index.d.ts +1 -0
- package/lib/types/server.d.ts +6 -2
- package/lib/types/types.d.ts +23 -3
- package/lib/types/update.d.ts +6 -0
- package/package.json +4 -1
- package/src/server.ts +85 -37
- package/src/types.ts +25 -3
- package/tests/batch-import.test.mjs +5 -5
- package/tests/effective-skills.test.mjs +25 -0
- package/tests/skill-list.test.mjs +50 -0
- package/tests/update.test.mjs +22 -0
package/lib/client.js
CHANGED
|
@@ -225,14 +225,24 @@ window.__ModuleLoader__.load({
|
|
|
225
225
|
});
|
|
226
226
|
}
|
|
227
227
|
/** The settings section's page body. */
|
|
228
|
-
function SkillImporterSection({ t, useSkills, useWorkspaces, actions }) {
|
|
228
|
+
function SkillImporterSection({ t, useSkills, useSkillIssues, useWorkspaces, actions }) {
|
|
229
229
|
const skills = useSkills((value) => value);
|
|
230
|
+
const skillIssues = useSkillIssues((value) => value);
|
|
230
231
|
const workspaces = useWorkspaces((value) => value);
|
|
231
|
-
const
|
|
232
|
+
const [selectedWorkspaceId, setSelectedWorkspaceId] = (0, react.useState)(() => workspaces.recentWorkspaceId ?? workspaces.items[0]?.workspaceId);
|
|
233
|
+
(0, react.useEffect)(() => {
|
|
234
|
+
if (selectedWorkspaceId !== void 0 && workspaces.items.some((item) => item.workspaceId === selectedWorkspaceId)) return;
|
|
235
|
+
setSelectedWorkspaceId(workspaces.recentWorkspaceId ?? workspaces.items[0]?.workspaceId);
|
|
236
|
+
}, [
|
|
237
|
+
selectedWorkspaceId,
|
|
238
|
+
workspaces.items,
|
|
239
|
+
workspaces.recentWorkspaceId
|
|
240
|
+
]);
|
|
241
|
+
const workspace = (0, react.useMemo)(() => workspaces.items.find((item) => item.workspaceId === selectedWorkspaceId), [selectedWorkspaceId, workspaces.items]);
|
|
232
242
|
const [listState, setListState] = (0, react.useState)("idle");
|
|
233
243
|
const [listError, setListError] = (0, react.useState)();
|
|
234
244
|
const [listEpoch, setListEpoch] = (0, react.useState)(0);
|
|
235
|
-
const [
|
|
245
|
+
const [expandedGroups, setExpandedGroups] = (0, react.useState)(() => /* @__PURE__ */ new Set());
|
|
236
246
|
(0, react.useEffect)(() => {
|
|
237
247
|
let cancelled = false;
|
|
238
248
|
setListState("loading");
|
|
@@ -249,7 +259,10 @@ window.__ModuleLoader__.load({
|
|
|
249
259
|
};
|
|
250
260
|
}, [listEpoch, actions]);
|
|
251
261
|
const [mode, setMode] = (0, react.useState)("file");
|
|
252
|
-
const [target, setTarget] = (0, react.useState)("project-
|
|
262
|
+
const [target, setTarget] = (0, react.useState)("project-dsh");
|
|
263
|
+
(0, react.useEffect)(() => {
|
|
264
|
+
if (workspaces.items.length === 0 && target.startsWith("project-")) setTarget("user-dsh");
|
|
265
|
+
}, [target, workspaces.items.length]);
|
|
253
266
|
const [fileDraft, setFileDraft] = (0, react.useState)();
|
|
254
267
|
const [fileError, setFileError] = (0, react.useState)();
|
|
255
268
|
const [url, setUrl] = (0, react.useState)("");
|
|
@@ -262,8 +275,41 @@ window.__ModuleLoader__.load({
|
|
|
262
275
|
const [batchResults, setBatchResults] = (0, react.useState)();
|
|
263
276
|
const [replaceNames, setReplaceNames] = (0, react.useState)(() => /* @__PURE__ */ new Set());
|
|
264
277
|
const [pendingDelete, setPendingDelete] = (0, react.useState)();
|
|
278
|
+
const [locationOpen, setLocationOpen] = (0, react.useState)(false);
|
|
279
|
+
const [workspaceQuery, setWorkspaceQuery] = (0, react.useState)("");
|
|
280
|
+
const [draftTarget, setDraftTarget] = (0, react.useState)("project-dsh");
|
|
281
|
+
const [draftWorkspaceId, setDraftWorkspaceId] = (0, react.useState)();
|
|
282
|
+
const [updateState, setUpdateState] = (0, react.useState)("checking");
|
|
283
|
+
const [updateStatus, setUpdateStatus] = (0, react.useState)();
|
|
284
|
+
const [updateDialogOpen, setUpdateDialogOpen] = (0, react.useState)(false);
|
|
285
|
+
const [commandCopied, setCommandCopied] = (0, react.useState)(false);
|
|
265
286
|
const [batchConfirmation, setBatchConfirmation] = (0, react.useState)();
|
|
266
287
|
const fileInput = (0, react.useRef)(null);
|
|
288
|
+
const checkForUpdates = () => {
|
|
289
|
+
setUpdateState("checking");
|
|
290
|
+
actions.checkForUpdates().then((status) => {
|
|
291
|
+
setUpdateStatus(status);
|
|
292
|
+
setUpdateState(status.error === void 0 ? "ready" : "error");
|
|
293
|
+
}, () => setUpdateState("error"));
|
|
294
|
+
};
|
|
295
|
+
(0, react.useEffect)(() => {
|
|
296
|
+
let cancelled = false;
|
|
297
|
+
actions.checkForUpdates().then((status) => {
|
|
298
|
+
if (cancelled) return;
|
|
299
|
+
setUpdateStatus(status);
|
|
300
|
+
setUpdateState(status.error === void 0 ? "ready" : "error");
|
|
301
|
+
}, () => {
|
|
302
|
+
if (!cancelled) setUpdateState("error");
|
|
303
|
+
});
|
|
304
|
+
return () => {
|
|
305
|
+
cancelled = true;
|
|
306
|
+
};
|
|
307
|
+
}, [actions]);
|
|
308
|
+
const copyUpdateCommand = async () => {
|
|
309
|
+
if (updateStatus?.command === void 0) return;
|
|
310
|
+
await navigator.clipboard.writeText(updateStatus.command);
|
|
311
|
+
setCommandCopied(true);
|
|
312
|
+
};
|
|
267
313
|
const onFilePicked = async (file) => {
|
|
268
314
|
setFileDraft(void 0);
|
|
269
315
|
setFileError(void 0);
|
|
@@ -314,7 +360,7 @@ window.__ModuleLoader__.load({
|
|
|
314
360
|
if (await actions.deleteSkill({
|
|
315
361
|
name: skill.name,
|
|
316
362
|
source: skill.source,
|
|
317
|
-
workspacePath:
|
|
363
|
+
workspacePath: skill.workspacePath
|
|
318
364
|
})) {
|
|
319
365
|
setMessage(t("deleted"));
|
|
320
366
|
setPendingDelete(void 0);
|
|
@@ -454,7 +500,17 @@ window.__ModuleLoader__.load({
|
|
|
454
500
|
setTarget(next);
|
|
455
501
|
if (mode === "batch") resetBatchPreflight();
|
|
456
502
|
};
|
|
457
|
-
const
|
|
503
|
+
const chooseDestination = (nextTarget, nextWorkspaceId) => {
|
|
504
|
+
if (nextWorkspaceId !== void 0) setSelectedWorkspaceId(nextWorkspaceId);
|
|
505
|
+
changeTarget(nextTarget);
|
|
506
|
+
setLocationOpen(false);
|
|
507
|
+
};
|
|
508
|
+
const locationSummary = target === "project-dsh" ? t("locationSummaryProjectDsh", { title: workspace?.title ?? "" }) : target === "project-agents" ? t("locationSummaryProjectAgents", { title: workspace?.title ?? "" }) : target === "user-dsh" ? t("locationSummaryUserDsh") : t("locationSummaryUserAgents");
|
|
509
|
+
const filteredWorkspaces = workspaces.items.filter((item) => {
|
|
510
|
+
const query = workspaceQuery.trim().toLowerCase();
|
|
511
|
+
return query.length === 0 || item.title.toLowerCase().includes(query) || item.path.toLowerCase().includes(query);
|
|
512
|
+
});
|
|
513
|
+
const canSubmit = busy || mode === "file" && fileDraft === void 0 || mode === "url" && (url.trim().length === 0 || !/^https?:\/\//i.test(url.trim())) || mode === "batch" && batchPath === void 0 || target.startsWith("project-") && workspace === void 0;
|
|
458
514
|
const runPrimaryAction = () => {
|
|
459
515
|
if (mode !== "batch") {
|
|
460
516
|
submit();
|
|
@@ -468,13 +524,33 @@ window.__ModuleLoader__.load({
|
|
|
468
524
|
if (!skill.modelInvocable && skill.userInvocable) return t("userOnly");
|
|
469
525
|
if (skill.modelInvocable && !skill.userInvocable) return t("modelOnly");
|
|
470
526
|
};
|
|
471
|
-
const
|
|
472
|
-
|
|
527
|
+
const toggleGroup = (groupKey) => {
|
|
528
|
+
setExpandedGroups((current) => {
|
|
473
529
|
const next = new Set(current);
|
|
474
|
-
if (!next.delete(
|
|
530
|
+
if (!next.delete(groupKey)) next.add(groupKey);
|
|
475
531
|
return next;
|
|
476
532
|
});
|
|
477
533
|
};
|
|
534
|
+
const skillGroups = [
|
|
535
|
+
...workspaces.items.flatMap((item) => ["project-dsh", "project-agents"].map((source) => ({
|
|
536
|
+
key: `${item.workspaceId}:${source}`,
|
|
537
|
+
source,
|
|
538
|
+
workspacePath: item.path,
|
|
539
|
+
name: source === "project-dsh" ? t("targetProjectDsh", { title: item.title }) : t("targetProjectAgents", { title: item.title })
|
|
540
|
+
}))),
|
|
541
|
+
{
|
|
542
|
+
key: "user-dsh",
|
|
543
|
+
source: "user-dsh",
|
|
544
|
+
workspacePath: void 0,
|
|
545
|
+
name: t("targetUserDsh")
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
key: "user-agents",
|
|
549
|
+
source: "user-agents",
|
|
550
|
+
workspacePath: void 0,
|
|
551
|
+
name: t("targetUserAgents")
|
|
552
|
+
}
|
|
553
|
+
];
|
|
478
554
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
479
555
|
style: {
|
|
480
556
|
display: "flex",
|
|
@@ -529,23 +605,33 @@ window.__ModuleLoader__.load({
|
|
|
529
605
|
listError
|
|
530
606
|
]
|
|
531
607
|
}) : null,
|
|
608
|
+
listState !== "error" && skillIssues.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
609
|
+
style: {
|
|
610
|
+
...descriptionStyle,
|
|
611
|
+
color: "var(--dsw-alias-state-warn-label)"
|
|
612
|
+
},
|
|
613
|
+
children: [
|
|
614
|
+
t("installedPartial", { count: skillIssues.length }),
|
|
615
|
+
" ",
|
|
616
|
+
skillIssues[0]?.message
|
|
617
|
+
]
|
|
618
|
+
}) : null,
|
|
532
619
|
listState === "idle" && skills.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
533
620
|
style: descriptionStyle,
|
|
534
621
|
children: t("installedEmpty")
|
|
535
622
|
}) : null,
|
|
536
623
|
skills.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
537
624
|
style: skillGroupsStyle,
|
|
538
|
-
children:
|
|
539
|
-
const rows = skills.filter((skill) => skill.source === source);
|
|
625
|
+
children: skillGroups.map((group) => {
|
|
626
|
+
const rows = skills.filter((skill) => skill.source === group.source && (!group.source.startsWith("project-") || skill.workspacePath === group.workspacePath));
|
|
540
627
|
if (rows.length === 0) return null;
|
|
541
|
-
const
|
|
542
|
-
const open = !collapsedSources.has(source);
|
|
628
|
+
const open = expandedGroups.has(group.key);
|
|
543
629
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
544
630
|
style: skillGroupCardStyle,
|
|
545
631
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
546
632
|
type: "button",
|
|
547
633
|
"aria-expanded": open,
|
|
548
|
-
onClick: () =>
|
|
634
|
+
onClick: () => toggleGroup(group.key),
|
|
549
635
|
style: {
|
|
550
636
|
...skillGroupHeaderStyle,
|
|
551
637
|
borderBottom: open ? skillGroupHeaderStyle.borderBottom : "none"
|
|
@@ -559,7 +645,7 @@ window.__ModuleLoader__.load({
|
|
|
559
645
|
style: skillGroupIdentityStyle,
|
|
560
646
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
561
647
|
style: skillGroupNameStyle,
|
|
562
|
-
children:
|
|
648
|
+
children: group.name
|
|
563
649
|
})
|
|
564
650
|
}),
|
|
565
651
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -607,10 +693,10 @@ window.__ModuleLoader__.load({
|
|
|
607
693
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, {})
|
|
608
694
|
})
|
|
609
695
|
]
|
|
610
|
-
}, skill.source + ":" + skill.name);
|
|
696
|
+
}, skill.source + ":" + (skill.workspacePath ?? "") + ":" + skill.name);
|
|
611
697
|
})
|
|
612
698
|
}) : null]
|
|
613
|
-
},
|
|
699
|
+
}, group.key);
|
|
614
700
|
})
|
|
615
701
|
}) : null
|
|
616
702
|
]
|
|
@@ -1014,17 +1100,28 @@ window.__ModuleLoader__.load({
|
|
|
1014
1100
|
style: fieldLabelStyle,
|
|
1015
1101
|
children: t("targetLabel")
|
|
1016
1102
|
}),
|
|
1017
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1103
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1104
|
+
type: "button",
|
|
1105
|
+
onClick: () => {
|
|
1106
|
+
setWorkspaceQuery("");
|
|
1107
|
+
setDraftTarget(target);
|
|
1108
|
+
setDraftWorkspaceId(selectedWorkspaceId);
|
|
1109
|
+
setLocationOpen(true);
|
|
1110
|
+
},
|
|
1111
|
+
style: locationSummaryStyle,
|
|
1112
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1113
|
+
style: {
|
|
1114
|
+
minWidth: 0,
|
|
1115
|
+
flex: 1,
|
|
1116
|
+
overflow: "hidden",
|
|
1117
|
+
textOverflow: "ellipsis",
|
|
1118
|
+
whiteSpace: "nowrap",
|
|
1119
|
+
textAlign: "left"
|
|
1120
|
+
},
|
|
1121
|
+
children: locationSummary
|
|
1122
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1123
|
+
style: secondaryButtonStyle,
|
|
1124
|
+
children: t("locationChange")
|
|
1028
1125
|
})]
|
|
1029
1126
|
}),
|
|
1030
1127
|
workspace === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -1057,6 +1154,191 @@ window.__ModuleLoader__.load({
|
|
|
1057
1154
|
]
|
|
1058
1155
|
})
|
|
1059
1156
|
}),
|
|
1157
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1158
|
+
style: versionFooterStyle,
|
|
1159
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1160
|
+
style: versionCopyStyle,
|
|
1161
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1162
|
+
style: versionLabelStyle,
|
|
1163
|
+
children: updateStatus === void 0 ? t("versionChecking") : t("versionCurrent", { version: updateStatus.currentVersion })
|
|
1164
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1165
|
+
style: descriptionStyle,
|
|
1166
|
+
children: updateState === "checking" ? t("versionChecking") : updateState === "error" ? t("versionCheckFailed") : updateStatus?.updateAvailable === true ? t("versionAvailable", { version: updateStatus.latestVersion ?? "" }) : t("versionLatest")
|
|
1167
|
+
})]
|
|
1168
|
+
}), updateState === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1169
|
+
type: "button",
|
|
1170
|
+
onClick: checkForUpdates,
|
|
1171
|
+
style: pillStyle,
|
|
1172
|
+
children: t("versionRetry")
|
|
1173
|
+
}) : updateStatus?.updateAvailable === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1174
|
+
type: "button",
|
|
1175
|
+
onClick: () => {
|
|
1176
|
+
setCommandCopied(false);
|
|
1177
|
+
setUpdateDialogOpen(true);
|
|
1178
|
+
},
|
|
1179
|
+
style: updateButtonStyle,
|
|
1180
|
+
children: t("versionUpdate")
|
|
1181
|
+
}) : null]
|
|
1182
|
+
}),
|
|
1183
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
1184
|
+
open: locationOpen,
|
|
1185
|
+
onClose: () => setLocationOpen(false),
|
|
1186
|
+
title: t("locationTitle"),
|
|
1187
|
+
closeLabel: t("close"),
|
|
1188
|
+
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1189
|
+
variant: "outline",
|
|
1190
|
+
onClick: () => setLocationOpen(false),
|
|
1191
|
+
children: t("cancel")
|
|
1192
|
+
}),
|
|
1193
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1194
|
+
style: locationPanelStyle,
|
|
1195
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1196
|
+
style: locationScopeStyle,
|
|
1197
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1198
|
+
type: "button",
|
|
1199
|
+
onClick: () => {
|
|
1200
|
+
if (!draftTarget.startsWith("project-")) setDraftTarget("project-dsh");
|
|
1201
|
+
},
|
|
1202
|
+
style: {
|
|
1203
|
+
...locationScopeButtonStyle,
|
|
1204
|
+
...draftTarget.startsWith("project-") ? locationScopeButtonActiveStyle : {}
|
|
1205
|
+
},
|
|
1206
|
+
children: t("locationProject")
|
|
1207
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1208
|
+
type: "button",
|
|
1209
|
+
onClick: () => {
|
|
1210
|
+
if (draftTarget.startsWith("project-")) setDraftTarget("user-dsh");
|
|
1211
|
+
},
|
|
1212
|
+
style: {
|
|
1213
|
+
...locationScopeButtonStyle,
|
|
1214
|
+
...!draftTarget.startsWith("project-") ? locationScopeButtonActiveStyle : {}
|
|
1215
|
+
},
|
|
1216
|
+
children: t("locationGlobal")
|
|
1217
|
+
})]
|
|
1218
|
+
}), draftTarget.startsWith("project-") ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1219
|
+
type: "search",
|
|
1220
|
+
value: workspaceQuery,
|
|
1221
|
+
onChange: (event) => setWorkspaceQuery(event.target.value),
|
|
1222
|
+
placeholder: t("workspaceSearch"),
|
|
1223
|
+
style: controlStyle
|
|
1224
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1225
|
+
style: locationWorkspaceListStyle,
|
|
1226
|
+
children: [filteredWorkspaces.map((item) => {
|
|
1227
|
+
const selected = item.workspaceId === draftWorkspaceId;
|
|
1228
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1229
|
+
style: {
|
|
1230
|
+
...locationWorkspaceGroupStyle,
|
|
1231
|
+
...selected ? locationWorkspaceActiveStyle : {}
|
|
1232
|
+
},
|
|
1233
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1234
|
+
type: "button",
|
|
1235
|
+
onClick: (event) => {
|
|
1236
|
+
const group = event.currentTarget.parentElement;
|
|
1237
|
+
setDraftWorkspaceId(selected ? void 0 : item.workspaceId);
|
|
1238
|
+
if (!selected) window.requestAnimationFrame(() => group?.scrollIntoView({
|
|
1239
|
+
block: "nearest",
|
|
1240
|
+
behavior: "smooth"
|
|
1241
|
+
}));
|
|
1242
|
+
},
|
|
1243
|
+
style: locationWorkspaceStyle,
|
|
1244
|
+
"aria-expanded": selected,
|
|
1245
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1246
|
+
style: {
|
|
1247
|
+
minWidth: 0,
|
|
1248
|
+
flex: 1,
|
|
1249
|
+
display: "flex",
|
|
1250
|
+
flexDirection: "column",
|
|
1251
|
+
gap: 2
|
|
1252
|
+
},
|
|
1253
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1254
|
+
style: skillNameStyle,
|
|
1255
|
+
children: item.title
|
|
1256
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1257
|
+
style: skillDescriptionStyle,
|
|
1258
|
+
children: item.path
|
|
1259
|
+
})]
|
|
1260
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1261
|
+
style: skillGroupChevronStyle,
|
|
1262
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronIcon, { open: selected })
|
|
1263
|
+
})]
|
|
1264
|
+
}), selected ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1265
|
+
style: locationExpandedRootsStyle,
|
|
1266
|
+
children: [
|
|
1267
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1268
|
+
style: locationRootHintStyle,
|
|
1269
|
+
children: t("chooseRootHint")
|
|
1270
|
+
}),
|
|
1271
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1272
|
+
type: "button",
|
|
1273
|
+
onClick: () => chooseDestination("project-dsh", item.workspaceId),
|
|
1274
|
+
style: locationOptionStyle,
|
|
1275
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1276
|
+
style: locationOptionCopyStyle,
|
|
1277
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("rootProjectDsh") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
|
|
1278
|
+
style: descriptionStyle,
|
|
1279
|
+
children: ".dsh/skills"
|
|
1280
|
+
})]
|
|
1281
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1282
|
+
style: priorityHighStyle,
|
|
1283
|
+
children: t("priorityHighest")
|
|
1284
|
+
})]
|
|
1285
|
+
}),
|
|
1286
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1287
|
+
type: "button",
|
|
1288
|
+
onClick: () => chooseDestination("project-agents", item.workspaceId),
|
|
1289
|
+
style: locationOptionStyle,
|
|
1290
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1291
|
+
style: locationOptionCopyStyle,
|
|
1292
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("rootProjectAgents") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
|
|
1293
|
+
style: descriptionStyle,
|
|
1294
|
+
children: ".agents/skills"
|
|
1295
|
+
})]
|
|
1296
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1297
|
+
style: priorityMediumStyle,
|
|
1298
|
+
children: t("priorityHigher")
|
|
1299
|
+
})]
|
|
1300
|
+
})
|
|
1301
|
+
]
|
|
1302
|
+
}) : null]
|
|
1303
|
+
}, item.workspaceId);
|
|
1304
|
+
}), filteredWorkspaces.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1305
|
+
style: descriptionStyle,
|
|
1306
|
+
children: t("workspaceNoMatch")
|
|
1307
|
+
}) : null]
|
|
1308
|
+
})] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1309
|
+
style: locationRootsStyle,
|
|
1310
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1311
|
+
type: "button",
|
|
1312
|
+
onClick: () => chooseDestination("user-dsh"),
|
|
1313
|
+
style: locationOptionStyle,
|
|
1314
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1315
|
+
style: locationOptionCopyStyle,
|
|
1316
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("rootUserDsh") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
|
|
1317
|
+
style: descriptionStyle,
|
|
1318
|
+
children: "~/.dsh/skills"
|
|
1319
|
+
})]
|
|
1320
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1321
|
+
style: priorityLowStyle,
|
|
1322
|
+
children: t("priorityLower")
|
|
1323
|
+
})]
|
|
1324
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1325
|
+
type: "button",
|
|
1326
|
+
onClick: () => chooseDestination("user-agents"),
|
|
1327
|
+
style: locationOptionStyle,
|
|
1328
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1329
|
+
style: locationOptionCopyStyle,
|
|
1330
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("rootUserAgents") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
|
|
1331
|
+
style: descriptionStyle,
|
|
1332
|
+
children: "~/.agents/skills"
|
|
1333
|
+
})]
|
|
1334
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1335
|
+
style: priorityLowStyle,
|
|
1336
|
+
children: t("priorityLowest")
|
|
1337
|
+
})]
|
|
1338
|
+
})]
|
|
1339
|
+
})]
|
|
1340
|
+
})
|
|
1341
|
+
}),
|
|
1060
1342
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
1061
1343
|
open: pendingDelete !== void 0,
|
|
1062
1344
|
onClose: () => {
|
|
@@ -1100,6 +1382,34 @@ window.__ModuleLoader__.load({
|
|
|
1100
1382
|
},
|
|
1101
1383
|
children: busy ? t("batchWorking") : t("batchCommit")
|
|
1102
1384
|
})] })
|
|
1385
|
+
}),
|
|
1386
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
1387
|
+
open: updateDialogOpen,
|
|
1388
|
+
onClose: () => setUpdateDialogOpen(false),
|
|
1389
|
+
title: t("updateTitle"),
|
|
1390
|
+
closeLabel: t("close"),
|
|
1391
|
+
description: t("updateDescription"),
|
|
1392
|
+
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1393
|
+
variant: "outline",
|
|
1394
|
+
onClick: () => setUpdateDialogOpen(false),
|
|
1395
|
+
children: t("cancel")
|
|
1396
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1397
|
+
variant: "primary",
|
|
1398
|
+
onClick: () => {
|
|
1399
|
+
copyUpdateCommand();
|
|
1400
|
+
},
|
|
1401
|
+
children: commandCopied ? t("commandCopied") : t("copyCommand")
|
|
1402
|
+
})] }),
|
|
1403
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1404
|
+
style: updateDialogBodyStyle,
|
|
1405
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
1406
|
+
style: updateCommandStyle,
|
|
1407
|
+
children: updateStatus?.command
|
|
1408
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1409
|
+
style: descriptionStyle,
|
|
1410
|
+
children: t("restartHint")
|
|
1411
|
+
})]
|
|
1412
|
+
})
|
|
1103
1413
|
})
|
|
1104
1414
|
]
|
|
1105
1415
|
});
|
|
@@ -1128,6 +1438,58 @@ window.__ModuleLoader__.load({
|
|
|
1128
1438
|
lineHeight: "18px",
|
|
1129
1439
|
color: "var(--dsw-alias-label-caption)"
|
|
1130
1440
|
};
|
|
1441
|
+
const versionFooterStyle = {
|
|
1442
|
+
minHeight: 58,
|
|
1443
|
+
padding: "12px 0",
|
|
1444
|
+
display: "flex",
|
|
1445
|
+
alignItems: "center",
|
|
1446
|
+
gap: 12,
|
|
1447
|
+
borderTop: "1px solid var(--dsw-alias-border-l2)"
|
|
1448
|
+
};
|
|
1449
|
+
const versionCopyStyle = {
|
|
1450
|
+
flex: 1,
|
|
1451
|
+
minWidth: 0,
|
|
1452
|
+
display: "flex",
|
|
1453
|
+
flexDirection: "column",
|
|
1454
|
+
gap: 2
|
|
1455
|
+
};
|
|
1456
|
+
const versionLabelStyle = {
|
|
1457
|
+
fontSize: 12,
|
|
1458
|
+
lineHeight: "18px",
|
|
1459
|
+
fontWeight: 500,
|
|
1460
|
+
color: "var(--dsw-alias-label-secondary)"
|
|
1461
|
+
};
|
|
1462
|
+
const updateButtonStyle = {
|
|
1463
|
+
display: "inline-flex",
|
|
1464
|
+
alignItems: "center",
|
|
1465
|
+
height: 28,
|
|
1466
|
+
padding: "0 12px",
|
|
1467
|
+
border: "1px solid var(--dsw-alias-interactive-border-primary)",
|
|
1468
|
+
borderRadius: 14,
|
|
1469
|
+
background: "transparent",
|
|
1470
|
+
font: "inherit",
|
|
1471
|
+
fontSize: 13,
|
|
1472
|
+
borderColor: "var(--dsw-alias-interactive-border-primary)",
|
|
1473
|
+
color: "var(--dsw-alias-interactive-label-primary)",
|
|
1474
|
+
cursor: "pointer"
|
|
1475
|
+
};
|
|
1476
|
+
const updateDialogBodyStyle = {
|
|
1477
|
+
display: "flex",
|
|
1478
|
+
flexDirection: "column",
|
|
1479
|
+
gap: 10
|
|
1480
|
+
};
|
|
1481
|
+
const updateCommandStyle = {
|
|
1482
|
+
display: "block",
|
|
1483
|
+
padding: "10px 12px",
|
|
1484
|
+
border: "1px solid var(--dsw-alias-border-l2)",
|
|
1485
|
+
borderRadius: 8,
|
|
1486
|
+
background: "var(--dsw-alias-bg-module-platform)",
|
|
1487
|
+
color: "var(--dsw-alias-label-primary)",
|
|
1488
|
+
fontSize: 12,
|
|
1489
|
+
lineHeight: "18px",
|
|
1490
|
+
whiteSpace: "pre-wrap",
|
|
1491
|
+
wordBreak: "break-all"
|
|
1492
|
+
};
|
|
1131
1493
|
const pillStyle = {
|
|
1132
1494
|
display: "inline-flex",
|
|
1133
1495
|
alignItems: "center",
|
|
@@ -1305,18 +1667,7 @@ window.__ModuleLoader__.load({
|
|
|
1305
1667
|
color: "var(--dsw-alias-label-primary)",
|
|
1306
1668
|
outline: "none"
|
|
1307
1669
|
};
|
|
1308
|
-
|
|
1309
|
-
* (same treatment as the composer chips / models page selects). */
|
|
1310
|
-
const selectStyle = {
|
|
1311
|
-
...controlStyle,
|
|
1312
|
-
appearance: "none",
|
|
1313
|
-
paddingRight: 32,
|
|
1314
|
-
backgroundImage: "url(\"data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2712%27 height=%2712%27 viewBox=%270 0 12 12%27 fill=%27none%27%3E%3Cpath d=%27M3 4.5L6 7.5L9 4.5%27 stroke=%27%2381858C%27 stroke-width=%271.5%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27/%3E%3C/svg%3E\")",
|
|
1315
|
-
backgroundRepeat: "no-repeat",
|
|
1316
|
-
backgroundPosition: "right 12px center",
|
|
1317
|
-
backgroundSize: "12px 12px",
|
|
1318
|
-
cursor: "pointer"
|
|
1319
|
-
};
|
|
1670
|
+
({ ...controlStyle });
|
|
1320
1671
|
const entryGridStyle = {
|
|
1321
1672
|
display: "grid",
|
|
1322
1673
|
gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
|
|
@@ -1417,6 +1768,127 @@ window.__ModuleLoader__.load({
|
|
|
1417
1768
|
fontSize: 12,
|
|
1418
1769
|
lineHeight: "18px"
|
|
1419
1770
|
};
|
|
1771
|
+
const locationSummaryStyle = {
|
|
1772
|
+
...controlStyle,
|
|
1773
|
+
display: "flex",
|
|
1774
|
+
alignItems: "center",
|
|
1775
|
+
gap: 10,
|
|
1776
|
+
cursor: "pointer"
|
|
1777
|
+
};
|
|
1778
|
+
const locationPanelStyle = {
|
|
1779
|
+
display: "flex",
|
|
1780
|
+
flexDirection: "column",
|
|
1781
|
+
gap: 14,
|
|
1782
|
+
minWidth: 0
|
|
1783
|
+
};
|
|
1784
|
+
const locationScopeStyle = {
|
|
1785
|
+
display: "grid",
|
|
1786
|
+
gridTemplateColumns: "1fr 1fr",
|
|
1787
|
+
gap: 4,
|
|
1788
|
+
padding: 4,
|
|
1789
|
+
borderRadius: 10,
|
|
1790
|
+
background: "var(--dsw-alias-bg-module-platform)"
|
|
1791
|
+
};
|
|
1792
|
+
const locationScopeButtonStyle = {
|
|
1793
|
+
border: "none",
|
|
1794
|
+
borderRadius: 7,
|
|
1795
|
+
padding: "8px 12px",
|
|
1796
|
+
background: "transparent",
|
|
1797
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
1798
|
+
cursor: "pointer",
|
|
1799
|
+
fontWeight: 500
|
|
1800
|
+
};
|
|
1801
|
+
const locationScopeButtonActiveStyle = {
|
|
1802
|
+
background: "var(--dsw-alias-bg-layer-1)",
|
|
1803
|
+
color: "var(--dsw-alias-label-primary)",
|
|
1804
|
+
boxShadow: "0 1px 3px rgba(0,0,0,.08)"
|
|
1805
|
+
};
|
|
1806
|
+
const locationWorkspaceListStyle = {
|
|
1807
|
+
display: "flex",
|
|
1808
|
+
flexDirection: "column",
|
|
1809
|
+
gap: 4,
|
|
1810
|
+
maxHeight: "min(440px, 52vh)",
|
|
1811
|
+
overflowY: "auto",
|
|
1812
|
+
scrollPadding: "8px 0"
|
|
1813
|
+
};
|
|
1814
|
+
const locationWorkspaceGroupStyle = {
|
|
1815
|
+
overflow: "hidden",
|
|
1816
|
+
borderRadius: 10,
|
|
1817
|
+
transition: "background 140ms ease"
|
|
1818
|
+
};
|
|
1819
|
+
const locationWorkspaceStyle = {
|
|
1820
|
+
width: "100%",
|
|
1821
|
+
display: "flex",
|
|
1822
|
+
alignItems: "center",
|
|
1823
|
+
gap: 8,
|
|
1824
|
+
border: "none",
|
|
1825
|
+
borderRadius: 8,
|
|
1826
|
+
padding: "9px 10px",
|
|
1827
|
+
background: "transparent",
|
|
1828
|
+
cursor: "pointer",
|
|
1829
|
+
textAlign: "left"
|
|
1830
|
+
};
|
|
1831
|
+
const locationWorkspaceActiveStyle = { background: "var(--dsw-alias-bg-module-platform)" };
|
|
1832
|
+
const locationExpandedRootsStyle = {
|
|
1833
|
+
display: "flex",
|
|
1834
|
+
flexDirection: "column",
|
|
1835
|
+
gap: 8,
|
|
1836
|
+
padding: "2px 10px 10px 18px"
|
|
1837
|
+
};
|
|
1838
|
+
const locationRootHintStyle = {
|
|
1839
|
+
fontSize: 11,
|
|
1840
|
+
lineHeight: "16px",
|
|
1841
|
+
fontWeight: 500,
|
|
1842
|
+
color: "var(--dsw-alias-label-tertiary)"
|
|
1843
|
+
};
|
|
1844
|
+
const locationRootsStyle = {
|
|
1845
|
+
display: "flex",
|
|
1846
|
+
flexDirection: "column",
|
|
1847
|
+
gap: 8
|
|
1848
|
+
};
|
|
1849
|
+
const locationOptionStyle = {
|
|
1850
|
+
display: "flex",
|
|
1851
|
+
alignItems: "center",
|
|
1852
|
+
gap: 12,
|
|
1853
|
+
width: "100%",
|
|
1854
|
+
border: "1px solid var(--dsw-alias-border-l2)",
|
|
1855
|
+
borderRadius: 10,
|
|
1856
|
+
padding: "10px 12px",
|
|
1857
|
+
background: "var(--dsw-alias-bg-layer-1)",
|
|
1858
|
+
color: "var(--dsw-alias-label-primary)",
|
|
1859
|
+
cursor: "pointer",
|
|
1860
|
+
textAlign: "left"
|
|
1861
|
+
};
|
|
1862
|
+
const locationOptionCopyStyle = {
|
|
1863
|
+
minWidth: 0,
|
|
1864
|
+
flex: 1,
|
|
1865
|
+
display: "flex",
|
|
1866
|
+
flexDirection: "column",
|
|
1867
|
+
gap: 2
|
|
1868
|
+
};
|
|
1869
|
+
const priorityBaseStyle = {
|
|
1870
|
+
flex: "none",
|
|
1871
|
+
borderRadius: 999,
|
|
1872
|
+
padding: "2px 7px",
|
|
1873
|
+
fontSize: 11,
|
|
1874
|
+
lineHeight: "16px",
|
|
1875
|
+
fontWeight: 600
|
|
1876
|
+
};
|
|
1877
|
+
const priorityHighStyle = {
|
|
1878
|
+
...priorityBaseStyle,
|
|
1879
|
+
color: "var(--dsw-alias-state-success-primary)",
|
|
1880
|
+
background: "var(--dsw-alias-bg-module-platform)"
|
|
1881
|
+
};
|
|
1882
|
+
const priorityMediumStyle = {
|
|
1883
|
+
...priorityBaseStyle,
|
|
1884
|
+
color: "var(--dsw-alias-label-primary)",
|
|
1885
|
+
background: "var(--dsw-alias-bg-module-platform)"
|
|
1886
|
+
};
|
|
1887
|
+
const priorityLowStyle = {
|
|
1888
|
+
...priorityBaseStyle,
|
|
1889
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
1890
|
+
background: "var(--dsw-alias-bg-module-platform)"
|
|
1891
|
+
};
|
|
1420
1892
|
const previewStyle = {
|
|
1421
1893
|
display: "flex",
|
|
1422
1894
|
flexDirection: "column",
|
|
@@ -1630,28 +2102,108 @@ window.__ModuleLoader__.load({
|
|
|
1630
2102
|
* with `/name ` — the native text gesture — highlighted via the plugin's
|
|
1631
2103
|
* lexicon contribution.
|
|
1632
2104
|
*/
|
|
1633
|
-
/** Find the one
|
|
1634
|
-
function
|
|
2105
|
+
/** Find the one legacy textarea or Lexical contenteditable owned by this picker. */
|
|
2106
|
+
function composerInputFor(root) {
|
|
1635
2107
|
let node = root?.parentElement;
|
|
1636
2108
|
while (node !== null && node !== void 0) {
|
|
1637
|
-
const
|
|
1638
|
-
if (
|
|
2109
|
+
const inputs = node.querySelectorAll("textarea, [data-composer-input]");
|
|
2110
|
+
if (inputs.length > 0) return inputs.length === 1 ? inputs[0] : void 0;
|
|
1639
2111
|
node = node.parentElement;
|
|
1640
2112
|
}
|
|
1641
2113
|
}
|
|
2114
|
+
function composerText(input) {
|
|
2115
|
+
return input instanceof HTMLTextAreaElement ? input.value : input.textContent ?? "";
|
|
2116
|
+
}
|
|
2117
|
+
function composerCaret(input) {
|
|
2118
|
+
if (input instanceof HTMLTextAreaElement) {
|
|
2119
|
+
if (input.selectionStart === null || input.selectionEnd === null) return void 0;
|
|
2120
|
+
return {
|
|
2121
|
+
start: input.selectionStart,
|
|
2122
|
+
end: input.selectionEnd
|
|
2123
|
+
};
|
|
2124
|
+
}
|
|
2125
|
+
const selection = window.getSelection();
|
|
2126
|
+
if (selection === null || selection.rangeCount !== 1) return void 0;
|
|
2127
|
+
const range = selection.getRangeAt(0);
|
|
2128
|
+
if (!input.contains(range.startContainer) || !input.contains(range.endContainer)) return void 0;
|
|
2129
|
+
const offsetOf = (container, offset) => {
|
|
2130
|
+
const prefix = range.cloneRange();
|
|
2131
|
+
prefix.selectNodeContents(input);
|
|
2132
|
+
prefix.setEnd(container, offset);
|
|
2133
|
+
return prefix.toString().length;
|
|
2134
|
+
};
|
|
2135
|
+
return {
|
|
2136
|
+
start: offsetOf(range.startContainer, range.startOffset),
|
|
2137
|
+
end: offsetOf(range.endContainer, range.endOffset)
|
|
2138
|
+
};
|
|
2139
|
+
}
|
|
2140
|
+
function setComposerCaret(input, caret) {
|
|
2141
|
+
input.focus({ preventScroll: true });
|
|
2142
|
+
if (input instanceof HTMLTextAreaElement) {
|
|
2143
|
+
input.setSelectionRange(caret, caret);
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
const range = document.createRange();
|
|
2147
|
+
let remaining = caret;
|
|
2148
|
+
const walker = document.createTreeWalker(input, NodeFilter.SHOW_TEXT);
|
|
2149
|
+
let text = walker.nextNode();
|
|
2150
|
+
while (text !== null) {
|
|
2151
|
+
const length = text.textContent?.length ?? 0;
|
|
2152
|
+
if (remaining <= length) {
|
|
2153
|
+
range.setStart(text, remaining);
|
|
2154
|
+
range.collapse(true);
|
|
2155
|
+
const selection = window.getSelection();
|
|
2156
|
+
selection?.removeAllRanges();
|
|
2157
|
+
selection?.addRange(range);
|
|
2158
|
+
return;
|
|
2159
|
+
}
|
|
2160
|
+
remaining -= length;
|
|
2161
|
+
text = walker.nextNode();
|
|
2162
|
+
}
|
|
2163
|
+
range.selectNodeContents(input);
|
|
2164
|
+
range.collapse(false);
|
|
2165
|
+
const selection = window.getSelection();
|
|
2166
|
+
selection?.removeAllRanges();
|
|
2167
|
+
selection?.addRange(range);
|
|
2168
|
+
}
|
|
1642
2169
|
/** One row of the composer skill picker. */
|
|
1643
|
-
function SkillsPicker({ t, sessionId,
|
|
1644
|
-
const skills = useSkills((value) => value);
|
|
2170
|
+
function SkillsPicker({ t, sessionId, useInput, inputActions, actions }) {
|
|
1645
2171
|
const input = useInput((value) => value.draft);
|
|
2172
|
+
const [skills, setSkills] = (0, react.useState)([]);
|
|
1646
2173
|
const [open, setOpen] = (0, react.useState)(false);
|
|
2174
|
+
const [loading, setLoading] = (0, react.useState)(true);
|
|
1647
2175
|
const [query, setQuery] = (0, react.useState)("");
|
|
1648
2176
|
const rootRef = (0, react.useRef)(null);
|
|
1649
2177
|
const draftRef = (0, react.useRef)(input);
|
|
1650
2178
|
const skillNamesRef = (0, react.useRef)([]);
|
|
1651
2179
|
const caretFrameRef = (0, react.useRef)();
|
|
1652
2180
|
(0, react.useEffect)(() => {
|
|
1653
|
-
|
|
1654
|
-
|
|
2181
|
+
let cancelled = false;
|
|
2182
|
+
const refresh = (showLoading) => {
|
|
2183
|
+
if (showLoading) setLoading(true);
|
|
2184
|
+
actions.refreshSkillsForSession(sessionId).then((rows) => {
|
|
2185
|
+
if (!cancelled) {
|
|
2186
|
+
setSkills(rows);
|
|
2187
|
+
setLoading(false);
|
|
2188
|
+
}
|
|
2189
|
+
}, () => {
|
|
2190
|
+
if (!cancelled) {
|
|
2191
|
+
setSkills([]);
|
|
2192
|
+
setLoading(false);
|
|
2193
|
+
}
|
|
2194
|
+
});
|
|
2195
|
+
};
|
|
2196
|
+
refresh(true);
|
|
2197
|
+
const timer = open ? window.setInterval(() => refresh(false), 2e3) : void 0;
|
|
2198
|
+
return () => {
|
|
2199
|
+
cancelled = true;
|
|
2200
|
+
if (timer !== void 0) window.clearInterval(timer);
|
|
2201
|
+
};
|
|
2202
|
+
}, [
|
|
2203
|
+
actions,
|
|
2204
|
+
sessionId,
|
|
2205
|
+
open
|
|
2206
|
+
]);
|
|
1655
2207
|
(0, react.useEffect)(() => {
|
|
1656
2208
|
if (!open) return;
|
|
1657
2209
|
const onDown = (event) => {
|
|
@@ -1667,13 +2219,12 @@ window.__ModuleLoader__.load({
|
|
|
1667
2219
|
draftRef.current = input;
|
|
1668
2220
|
skillNamesRef.current = usable.map((skill) => skill.name);
|
|
1669
2221
|
const scheduleComposerFocus = (expectedDraft, caret) => {
|
|
1670
|
-
const
|
|
2222
|
+
const input = composerInputFor(rootRef.current);
|
|
1671
2223
|
if (caretFrameRef.current !== void 0) window.cancelAnimationFrame(caretFrameRef.current);
|
|
1672
2224
|
caretFrameRef.current = window.requestAnimationFrame(() => {
|
|
1673
2225
|
caretFrameRef.current = void 0;
|
|
1674
|
-
if (
|
|
1675
|
-
|
|
1676
|
-
textarea.setSelectionRange(caret, caret);
|
|
2226
|
+
if (input === void 0 || !input.isConnected || composerText(input) !== expectedDraft) return;
|
|
2227
|
+
setComposerCaret(input, caret);
|
|
1677
2228
|
});
|
|
1678
2229
|
};
|
|
1679
2230
|
(0, react.useEffect)(() => {
|
|
@@ -1695,18 +2246,20 @@ window.__ModuleLoader__.load({
|
|
|
1695
2246
|
if (event.defaultPrevented || event.isComposing || event.keyCode === 229) return;
|
|
1696
2247
|
if (event.metaKey || event.ctrlKey || event.altKey) return;
|
|
1697
2248
|
if (event.shiftKey && event.key !== "Backspace") return;
|
|
1698
|
-
const
|
|
1699
|
-
if (!(
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
2249
|
+
const target = event.target;
|
|
2250
|
+
if (!(target instanceof Node)) return;
|
|
2251
|
+
const input = composerInputFor(rootRef.current);
|
|
2252
|
+
if (input === void 0 || document.activeElement !== input || !input.contains(target)) return;
|
|
2253
|
+
if (composerText(input) !== draftRef.current) return;
|
|
2254
|
+
const selection = composerCaret(input);
|
|
2255
|
+
if (selection === void 0 || selection.start !== selection.end) return;
|
|
2256
|
+
const start = selection.start;
|
|
1704
2257
|
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
|
|
1705
2258
|
const caret = atomicSkillArrow(draftRef.current, start, event.key === "ArrowLeft" ? "left" : "right", skillNamesRef.current);
|
|
1706
2259
|
if (caret === void 0) return;
|
|
1707
2260
|
event.preventDefault();
|
|
1708
2261
|
event.stopPropagation();
|
|
1709
|
-
|
|
2262
|
+
setComposerCaret(input, caret);
|
|
1710
2263
|
return;
|
|
1711
2264
|
}
|
|
1712
2265
|
const edit = atomicSkillBackspace(draftRef.current, start, skillNamesRef.current);
|
|
@@ -1717,8 +2270,8 @@ window.__ModuleLoader__.load({
|
|
|
1717
2270
|
if (caretFrameRef.current !== void 0) window.cancelAnimationFrame(caretFrameRef.current);
|
|
1718
2271
|
caretFrameRef.current = window.requestAnimationFrame(() => {
|
|
1719
2272
|
caretFrameRef.current = void 0;
|
|
1720
|
-
if (!
|
|
1721
|
-
|
|
2273
|
+
if (!input.isConnected || document.activeElement !== input || composerText(input) !== edit.draft) return;
|
|
2274
|
+
setComposerCaret(input, edit.caret);
|
|
1722
2275
|
});
|
|
1723
2276
|
};
|
|
1724
2277
|
document.addEventListener("keydown", onKeyDown, true);
|
|
@@ -1727,7 +2280,6 @@ window.__ModuleLoader__.load({
|
|
|
1727
2280
|
if (caretFrameRef.current !== void 0) window.cancelAnimationFrame(caretFrameRef.current);
|
|
1728
2281
|
};
|
|
1729
2282
|
}, [inputActions]);
|
|
1730
|
-
if (usable.length === 0) return null;
|
|
1731
2283
|
const filtered = query.trim().length === 0 ? usable : usable.filter((skill) => skill.name.toLowerCase().includes(query.trim().toLowerCase()));
|
|
1732
2284
|
const onSelect = (name) => {
|
|
1733
2285
|
const prefix = `/${name} `;
|
|
@@ -1743,7 +2295,10 @@ window.__ModuleLoader__.load({
|
|
|
1743
2295
|
type: "button",
|
|
1744
2296
|
"aria-label": t("pickerLabel"),
|
|
1745
2297
|
"aria-expanded": open,
|
|
1746
|
-
onClick: () =>
|
|
2298
|
+
onClick: () => {
|
|
2299
|
+
if (!open) setLoading(true);
|
|
2300
|
+
setOpen((value) => !value);
|
|
2301
|
+
},
|
|
1747
2302
|
style: triggerStyle,
|
|
1748
2303
|
children: [
|
|
1749
2304
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -1775,7 +2330,10 @@ window.__ModuleLoader__.load({
|
|
|
1775
2330
|
placeholder: t("pickerSearchPlaceholder"),
|
|
1776
2331
|
style: searchStyle
|
|
1777
2332
|
}),
|
|
1778
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
2333
|
+
loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2334
|
+
style: emptyStyle,
|
|
2335
|
+
children: t("pickerLoading")
|
|
2336
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
1779
2337
|
style: listStyle,
|
|
1780
2338
|
children: filtered.map((skill) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1781
2339
|
type: "button",
|
|
@@ -1785,13 +2343,19 @@ window.__ModuleLoader__.load({
|
|
|
1785
2343
|
style: avatarStyle,
|
|
1786
2344
|
"aria-hidden": "true",
|
|
1787
2345
|
children: skill.name.charAt(0).toUpperCase()
|
|
1788
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
1789
|
-
style:
|
|
1790
|
-
children:
|
|
2346
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2347
|
+
style: rowCopyStyle,
|
|
2348
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2349
|
+
style: rowLabelStyle,
|
|
2350
|
+
children: skill.name
|
|
2351
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2352
|
+
style: rowDetailStyle,
|
|
2353
|
+
children: skill.source === "project-dsh" ? t("pickerSourceProjectDsh") : skill.source === "project-agents" ? t("pickerSourceProjectAgents") : skill.source === "user-dsh" ? t("pickerSourceUserDsh") : t("pickerSourceUserAgents")
|
|
2354
|
+
})]
|
|
1791
2355
|
})]
|
|
1792
2356
|
}) }, skill.name))
|
|
1793
2357
|
}),
|
|
1794
|
-
filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2358
|
+
!loading && filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1795
2359
|
style: emptyStyle,
|
|
1796
2360
|
children: t("pickerEmpty")
|
|
1797
2361
|
}) : null
|
|
@@ -1906,12 +2470,41 @@ window.__ModuleLoader__.load({
|
|
|
1906
2470
|
minWidth: 0,
|
|
1907
2471
|
overflow: "hidden"
|
|
1908
2472
|
};
|
|
2473
|
+
const rowCopyStyle = {
|
|
2474
|
+
display: "flex",
|
|
2475
|
+
flexDirection: "column",
|
|
2476
|
+
minWidth: 0,
|
|
2477
|
+
flex: 1,
|
|
2478
|
+
lineHeight: "18px"
|
|
2479
|
+
};
|
|
2480
|
+
const rowDetailStyle = {
|
|
2481
|
+
overflow: "hidden",
|
|
2482
|
+
textOverflow: "ellipsis",
|
|
2483
|
+
whiteSpace: "nowrap",
|
|
2484
|
+
color: "var(--dsw-alias-label-caption)",
|
|
2485
|
+
fontSize: 11,
|
|
2486
|
+
lineHeight: "16px"
|
|
2487
|
+
};
|
|
1909
2488
|
const emptyStyle = {
|
|
1910
2489
|
padding: "8px 10px",
|
|
1911
2490
|
fontSize: 12,
|
|
1912
2491
|
color: "var(--dsw-alias-label-caption)"
|
|
1913
2492
|
};
|
|
1914
2493
|
//#endregion
|
|
2494
|
+
//#region src/client/effectiveSkills.ts
|
|
2495
|
+
const SOURCE_RANK = {
|
|
2496
|
+
"project-dsh": 100,
|
|
2497
|
+
"project-agents": 200,
|
|
2498
|
+
"user-dsh": 400,
|
|
2499
|
+
"user-agents": 500
|
|
2500
|
+
};
|
|
2501
|
+
/** Mirror DSH's name-based winner selection for one session-scoped catalog. */
|
|
2502
|
+
function effectiveSkills(rows) {
|
|
2503
|
+
const winners = /* @__PURE__ */ new Map();
|
|
2504
|
+
for (const row of [...rows].sort((a, b) => SOURCE_RANK[a.source] - SOURCE_RANK[b.source])) if (!winners.has(row.name)) winners.set(row.name, row);
|
|
2505
|
+
return [...winners.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
2506
|
+
}
|
|
2507
|
+
//#endregion
|
|
1915
2508
|
//#region src/client/locales.ts
|
|
1916
2509
|
/**
|
|
1917
2510
|
* Locale dictionaries for the skill importer settings section.
|
|
@@ -1928,7 +2521,12 @@ window.__ModuleLoader__.load({
|
|
|
1928
2521
|
pickerLabel: "技能",
|
|
1929
2522
|
pickerPlaceholder: "技能",
|
|
1930
2523
|
pickerSearchPlaceholder: "筛选技能…",
|
|
2524
|
+
pickerLoading: "正在同步当前项目技能…",
|
|
1931
2525
|
pickerEmpty: "没有匹配的技能",
|
|
2526
|
+
pickerSourceProjectDsh: "当前项目 · .dsh",
|
|
2527
|
+
pickerSourceProjectAgents: "当前项目 · .agents",
|
|
2528
|
+
pickerSourceUserDsh: "全局 · .dsh",
|
|
2529
|
+
pickerSourceUserAgents: "全局 · .agents",
|
|
1932
2530
|
commandDescription: "选择技能:弹出技能列表,选中后填入 /<名称>",
|
|
1933
2531
|
entryTitle: "技能入口",
|
|
1934
2532
|
entryDescription: "通过输入框工具行的技能下拉或 /skills 命令选择技能;也可直接输入 /<名称>。选中的技能会高亮并注入指令。",
|
|
@@ -1944,6 +2542,7 @@ window.__ModuleLoader__.load({
|
|
|
1944
2542
|
deleteFailed: "删除失败",
|
|
1945
2543
|
deleted: "已删除。",
|
|
1946
2544
|
installedFailed: "无法读取技能列表",
|
|
2545
|
+
installedPartial: "有 {count} 个技能目录暂时无法读取,其他技能已正常显示。",
|
|
1947
2546
|
userOnly: "仅斜杠可用",
|
|
1948
2547
|
modelOnly: "仅模型可用",
|
|
1949
2548
|
importTitle: "导入技能",
|
|
@@ -1994,15 +2593,48 @@ window.__ModuleLoader__.load({
|
|
|
1994
2593
|
batchStatusSkipped: "已跳过",
|
|
1995
2594
|
batchStatusError: "失败",
|
|
1996
2595
|
targetLabel: "安装到",
|
|
1997
|
-
|
|
1998
|
-
targetProjectAgents: "
|
|
2596
|
+
targetProjectDsh: "DSH 项目技能({title})",
|
|
2597
|
+
targetProjectAgents: "通用项目技能({title})",
|
|
2598
|
+
targetUserDsh: "DSH 全局技能",
|
|
2599
|
+
targetUserAgents: "通用全局技能",
|
|
2600
|
+
locationChange: "更改",
|
|
2601
|
+
locationTitle: "选择安装位置",
|
|
2602
|
+
locationProject: "项目技能",
|
|
2603
|
+
locationGlobal: "全局技能",
|
|
2604
|
+
workspaceSearch: "搜索工作区…",
|
|
2605
|
+
workspaceNoMatch: "没有匹配的工作区",
|
|
2606
|
+
chooseRootHint: "选择技能目录",
|
|
2607
|
+
rootProjectDsh: "DSH 项目技能",
|
|
2608
|
+
rootProjectAgents: "通用项目技能",
|
|
2609
|
+
rootUserDsh: "DSH 全局技能",
|
|
2610
|
+
rootUserAgents: "通用全局技能",
|
|
2611
|
+
priorityHighest: "最高",
|
|
2612
|
+
priorityHigher: "较高",
|
|
2613
|
+
priorityLower: "较低",
|
|
2614
|
+
priorityLowest: "最低",
|
|
2615
|
+
locationSummaryProjectDsh: "项目技能 · {title} · .dsh/skills",
|
|
2616
|
+
locationSummaryProjectAgents: "项目技能 · {title} · .agents/skills",
|
|
2617
|
+
locationSummaryUserDsh: "全局技能 · ~/.dsh/skills",
|
|
2618
|
+
locationSummaryUserAgents: "全局技能 · ~/.agents/skills",
|
|
1999
2619
|
targetProjectNoWorkspace: "项目技能(需先添加工作区)",
|
|
2000
2620
|
noWorkspace: "未注册工作区:请先在会话页选择/创建工作区,或改用用户技能目录。",
|
|
2001
2621
|
import: "导入",
|
|
2002
2622
|
importing: "导入中…",
|
|
2003
2623
|
imported: "已写入:",
|
|
2004
2624
|
importFailed: "导入失败",
|
|
2005
|
-
hostUnreachable: "无法连接 dsh 服务(插件路由未生效)。请确认插件已安装,并重启 dsh web 后刷新页面。"
|
|
2625
|
+
hostUnreachable: "无法连接 dsh 服务(插件路由未生效)。请确认插件已安装,并重启 dsh web 后刷新页面。",
|
|
2626
|
+
versionChecking: "正在检查更新…",
|
|
2627
|
+
versionCurrent: "当前版本 v{version}",
|
|
2628
|
+
versionLatest: "已是最新版本",
|
|
2629
|
+
versionAvailable: "发现新版本 v{version}",
|
|
2630
|
+
versionCheckFailed: "暂时无法检查更新",
|
|
2631
|
+
versionRetry: "重试",
|
|
2632
|
+
versionUpdate: "更新",
|
|
2633
|
+
updateTitle: "更新 dsh-skill-importer",
|
|
2634
|
+
updateDescription: "复制下面的精确版本命令,在终端运行后重启 dsh web。",
|
|
2635
|
+
copyCommand: "复制更新命令",
|
|
2636
|
+
commandCopied: "已复制",
|
|
2637
|
+
restartHint: "更新完成后需要重启 dsh web 才会生效。"
|
|
2006
2638
|
};
|
|
2007
2639
|
/** English dictionary, checked complete against the zh key set. */
|
|
2008
2640
|
const en = {
|
|
@@ -2010,7 +2642,12 @@ window.__ModuleLoader__.load({
|
|
|
2010
2642
|
pickerLabel: "Skills",
|
|
2011
2643
|
pickerPlaceholder: "Skills",
|
|
2012
2644
|
pickerSearchPlaceholder: "Filter skills…",
|
|
2645
|
+
pickerLoading: "Syncing skills for the current project…",
|
|
2013
2646
|
pickerEmpty: "No matching skills",
|
|
2647
|
+
pickerSourceProjectDsh: "Current project · .dsh",
|
|
2648
|
+
pickerSourceProjectAgents: "Current project · .agents",
|
|
2649
|
+
pickerSourceUserDsh: "Global · .dsh",
|
|
2650
|
+
pickerSourceUserAgents: "Global · .agents",
|
|
2014
2651
|
commandDescription: "Pick a skill: opens a popup list; selecting fills /<name>",
|
|
2015
2652
|
entryTitle: "Skill entry points",
|
|
2016
2653
|
entryDescription: "Pick a skill from the composer tool-row dropdown or the /skills command; or type /<name> directly. The picked skill is highlighted and its instructions are injected.",
|
|
@@ -2026,6 +2663,7 @@ window.__ModuleLoader__.load({
|
|
|
2026
2663
|
deleteFailed: "Failed to delete",
|
|
2027
2664
|
deleted: "Deleted.",
|
|
2028
2665
|
installedFailed: "Unable to read the skill list",
|
|
2666
|
+
installedPartial: "{count} skill directories are temporarily unreadable; other skills are still shown.",
|
|
2029
2667
|
userOnly: "Slash only",
|
|
2030
2668
|
modelOnly: "Model only",
|
|
2031
2669
|
importTitle: "Import a skill",
|
|
@@ -2076,24 +2714,91 @@ window.__ModuleLoader__.load({
|
|
|
2076
2714
|
batchStatusSkipped: "Skipped",
|
|
2077
2715
|
batchStatusError: "Failed",
|
|
2078
2716
|
targetLabel: "Install into",
|
|
2079
|
-
|
|
2080
|
-
targetProjectAgents: "
|
|
2717
|
+
targetProjectDsh: "DSH project skills ({title})",
|
|
2718
|
+
targetProjectAgents: "Shared project skills ({title})",
|
|
2719
|
+
targetUserDsh: "DSH global skills",
|
|
2720
|
+
targetUserAgents: "Shared global skills",
|
|
2721
|
+
locationChange: "Change",
|
|
2722
|
+
locationTitle: "Choose install location",
|
|
2723
|
+
locationProject: "Project skills",
|
|
2724
|
+
locationGlobal: "Global skills",
|
|
2725
|
+
workspaceSearch: "Search workspaces…",
|
|
2726
|
+
workspaceNoMatch: "No matching workspaces",
|
|
2727
|
+
chooseRootHint: "Choose a skill directory",
|
|
2728
|
+
rootProjectDsh: "DSH project skills",
|
|
2729
|
+
rootProjectAgents: "Shared project skills",
|
|
2730
|
+
rootUserDsh: "DSH global skills",
|
|
2731
|
+
rootUserAgents: "Shared global skills",
|
|
2732
|
+
priorityHighest: "Highest",
|
|
2733
|
+
priorityHigher: "Higher",
|
|
2734
|
+
priorityLower: "Lower",
|
|
2735
|
+
priorityLowest: "Lowest",
|
|
2736
|
+
locationSummaryProjectDsh: "Project · {title} · .dsh/skills",
|
|
2737
|
+
locationSummaryProjectAgents: "Project · {title} · .agents/skills",
|
|
2738
|
+
locationSummaryUserDsh: "Global · ~/.dsh/skills",
|
|
2739
|
+
locationSummaryUserAgents: "Global · ~/.agents/skills",
|
|
2081
2740
|
targetProjectNoWorkspace: "Project skills (add a workspace first)",
|
|
2082
2741
|
noWorkspace: "No registered workspace: create/select one in a session, or use the user skill directory.",
|
|
2083
2742
|
import: "Import",
|
|
2084
2743
|
importing: "Importing…",
|
|
2085
2744
|
imported: "Written to: ",
|
|
2086
2745
|
importFailed: "Import failed",
|
|
2087
|
-
hostUnreachable: "Cannot reach the dsh service (plugin routes are not active). Make sure the plugin is installed, restart dsh web, and refresh the page."
|
|
2746
|
+
hostUnreachable: "Cannot reach the dsh service (plugin routes are not active). Make sure the plugin is installed, restart dsh web, and refresh the page.",
|
|
2747
|
+
versionChecking: "Checking for updates…",
|
|
2748
|
+
versionCurrent: "Current version v{version}",
|
|
2749
|
+
versionLatest: "Up to date",
|
|
2750
|
+
versionAvailable: "Version v{version} is available",
|
|
2751
|
+
versionCheckFailed: "Unable to check for updates",
|
|
2752
|
+
versionRetry: "Retry",
|
|
2753
|
+
versionUpdate: "Update",
|
|
2754
|
+
updateTitle: "Update dsh-skill-importer",
|
|
2755
|
+
updateDescription: "Copy this exact-version command, run it in a terminal, then restart dsh web.",
|
|
2756
|
+
copyCommand: "Copy update command",
|
|
2757
|
+
commandCopied: "Copied",
|
|
2758
|
+
restartHint: "Restart dsh web after the update for it to take effect."
|
|
2088
2759
|
};
|
|
2089
2760
|
//#endregion
|
|
2090
2761
|
//#region src/client/index.ts
|
|
2091
|
-
/**
|
|
2762
|
+
/** Every client service used during apply is explicit; alpha DSH no longer tolerates load-order access. */
|
|
2092
2763
|
const inject = [
|
|
2093
2764
|
"slots",
|
|
2094
2765
|
"locale",
|
|
2095
|
-
"connection"
|
|
2766
|
+
"connection",
|
|
2767
|
+
"remote",
|
|
2768
|
+
"remote.skills",
|
|
2769
|
+
"remote.directoryPicker",
|
|
2770
|
+
"inputTriggers",
|
|
2771
|
+
"commandUi",
|
|
2772
|
+
"sessions",
|
|
2773
|
+
"conversation"
|
|
2096
2774
|
];
|
|
2775
|
+
const popupEscapeHandlers = /* @__PURE__ */ new WeakMap();
|
|
2776
|
+
/** Restore keyboard ownership when DSH opens this plugin's popup from the composer. */
|
|
2777
|
+
function focusSkillsPopupSearch(options) {
|
|
2778
|
+
const focus = () => {
|
|
2779
|
+
for (const input of document.querySelectorAll("input[type=\"text\"]")) {
|
|
2780
|
+
let node = input;
|
|
2781
|
+
while (node !== null) {
|
|
2782
|
+
if ((node.getAttribute("aria-label") ?? "").toLowerCase().includes("skills")) {
|
|
2783
|
+
const previous = popupEscapeHandlers.get(input);
|
|
2784
|
+
if (previous !== void 0) input.removeEventListener("keydown", previous);
|
|
2785
|
+
const onKeyDown = (event) => {
|
|
2786
|
+
if (event.key !== "Escape") return;
|
|
2787
|
+
window.setTimeout(options.onEscape, 0);
|
|
2788
|
+
};
|
|
2789
|
+
popupEscapeHandlers.set(input, onKeyDown);
|
|
2790
|
+
input.addEventListener("keydown", onKeyDown);
|
|
2791
|
+
input.focus({ preventScroll: true });
|
|
2792
|
+
options.resetActive();
|
|
2793
|
+
return;
|
|
2794
|
+
}
|
|
2795
|
+
node = node.parentElement;
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
};
|
|
2799
|
+
window.requestAnimationFrame(focus);
|
|
2800
|
+
window.setTimeout(focus, 0);
|
|
2801
|
+
}
|
|
2097
2802
|
/** Same-origin route literals (mirrors the host half's ROUTES). */
|
|
2098
2803
|
const ROUTES = {
|
|
2099
2804
|
list: "/skill-importer/list",
|
|
@@ -2101,7 +2806,8 @@ window.__ModuleLoader__.load({
|
|
|
2101
2806
|
importUrl: "/skill-importer/import-url",
|
|
2102
2807
|
delete: "/skill-importer/delete",
|
|
2103
2808
|
batchScan: "/skill-importer/batch/scan",
|
|
2104
|
-
batchCommit: "/skill-importer/batch/commit"
|
|
2809
|
+
batchCommit: "/skill-importer/batch/commit",
|
|
2810
|
+
updateStatus: "/skill-importer/update-status"
|
|
2105
2811
|
};
|
|
2106
2812
|
/** Fetch one route and unwrap the JSON envelope; throws on transport/HTTP errors. */
|
|
2107
2813
|
async function call(path, body) {
|
|
@@ -2134,7 +2840,10 @@ window.__ModuleLoader__.load({
|
|
|
2134
2840
|
en
|
|
2135
2841
|
}), "dsh-skill-importer: dictionaries");
|
|
2136
2842
|
const t = ctx.locale.bind(NS);
|
|
2843
|
+
const sourceLabel = (source) => source === "project-dsh" ? t("pickerSourceProjectDsh") : source === "project-agents" ? t("pickerSourceProjectAgents") : source === "user-dsh" ? t("pickerSourceUserDsh") : t("pickerSourceUserAgents");
|
|
2137
2844
|
let catalog = [];
|
|
2845
|
+
let issues = [];
|
|
2846
|
+
const sessionCatalogs = /* @__PURE__ */ new Map();
|
|
2138
2847
|
const listeners = /* @__PURE__ */ new Set();
|
|
2139
2848
|
const notify = () => {
|
|
2140
2849
|
for (const listener of [...listeners]) try {
|
|
@@ -2143,13 +2852,11 @@ window.__ModuleLoader__.load({
|
|
|
2143
2852
|
console.error("[dsh-skill-importer] listener failed:", error);
|
|
2144
2853
|
}
|
|
2145
2854
|
};
|
|
2146
|
-
const
|
|
2147
|
-
const
|
|
2148
|
-
skillsApi
|
|
2149
|
-
skillsApi.list = (
|
|
2150
|
-
|
|
2151
|
-
});
|
|
2152
|
-
const usableNames = () => catalog.filter((skill) => skill.userInvocable).map((skill) => skill.name);
|
|
2855
|
+
const legacyApi = ctx.get("connection").api;
|
|
2856
|
+
const remote = ctx.remote ?? ctx.get("remote");
|
|
2857
|
+
const skillsApi = remote?.skills ?? legacyApi?.skills;
|
|
2858
|
+
if (skillsApi !== void 0) skillsApi.list = () => Promise.reject(/* @__PURE__ */ new Error("skill group hidden: use the composer skill picker or /skills"));
|
|
2859
|
+
const usableNames = () => [...new Set([...sessionCatalogs.values()].flat().filter((skill) => skill.userInvocable).map((skill) => skill.name))];
|
|
2153
2860
|
ctx.effect(() => {
|
|
2154
2861
|
return ctx.get("inputTriggers").registerSource({
|
|
2155
2862
|
trigger: "/",
|
|
@@ -2173,42 +2880,79 @@ window.__ModuleLoader__.load({
|
|
|
2173
2880
|
}, "dsh-skill-importer: lexicon source");
|
|
2174
2881
|
const commandUi = ctx.get("commandUi");
|
|
2175
2882
|
const sessions = ctx.get("sessions");
|
|
2176
|
-
|
|
2177
|
-
if (commandUi !== void 0 && sessions !== void 0 && conversation !== void 0) ctx.effect(() => {
|
|
2883
|
+
if (commandUi !== void 0 && sessions !== void 0) ctx.effect(() => {
|
|
2178
2884
|
return commandUi.register({
|
|
2179
2885
|
name: "skills",
|
|
2180
2886
|
description: t("commandDescription"),
|
|
2181
2887
|
available: () => true,
|
|
2182
2888
|
ui: {
|
|
2183
2889
|
kind: "popupSelect",
|
|
2184
|
-
async options(
|
|
2185
|
-
|
|
2890
|
+
async options(session, _signal) {
|
|
2891
|
+
const rows = await refreshSkillsForSession(session.sessionId);
|
|
2892
|
+
const restoreComposerFocus = () => {
|
|
2893
|
+
const actx = sessions.scope(session.sessionId);
|
|
2894
|
+
if (actx === void 0) return;
|
|
2895
|
+
const conversation = actx.get("conversation");
|
|
2896
|
+
if (conversation === void 0) return;
|
|
2897
|
+
const draft = conversation.input.for(actx).state.getSnapshot().draft;
|
|
2898
|
+
requestComposerFocus({
|
|
2899
|
+
sessionId: session.sessionId,
|
|
2900
|
+
expectedDraft: draft,
|
|
2901
|
+
caret: draft.length
|
|
2902
|
+
});
|
|
2903
|
+
};
|
|
2904
|
+
const resetActive = () => {
|
|
2905
|
+
const actx = sessions.scope(session.sessionId);
|
|
2906
|
+
if (actx === void 0) return;
|
|
2907
|
+
commandUi.popupFor(actx).highlight?.(0);
|
|
2908
|
+
};
|
|
2909
|
+
focusSkillsPopupSearch({
|
|
2910
|
+
onEscape: restoreComposerFocus,
|
|
2911
|
+
resetActive
|
|
2912
|
+
});
|
|
2913
|
+
return rows.filter((skill) => skill.userInvocable).map((skill) => ({
|
|
2186
2914
|
id: skill.name,
|
|
2187
|
-
label: skill.name
|
|
2915
|
+
label: `${skill.name} · ${sourceLabel(skill.source)}`
|
|
2188
2916
|
}));
|
|
2189
2917
|
},
|
|
2190
2918
|
onSelect(option, session) {
|
|
2191
2919
|
const actx = sessions.scope(session.sessionId);
|
|
2192
|
-
if (actx === void 0)
|
|
2193
|
-
const
|
|
2194
|
-
|
|
2920
|
+
if (actx === void 0) throw new Error("this session is no longer available");
|
|
2921
|
+
const conversation = actx.get("conversation");
|
|
2922
|
+
if (conversation === void 0) throw new Error("conversation input is unavailable");
|
|
2923
|
+
const rest = conversation.input.for(actx).state.getSnapshot().draft.replace(/^\s*\/[a-zA-Z][a-zA-Z0-9-]*\s*/, "");
|
|
2195
2924
|
const prefix = `/${option.id} `;
|
|
2196
2925
|
const nextDraft = `${prefix}${rest}`;
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2926
|
+
window.setTimeout(() => {
|
|
2927
|
+
const liveScope = sessions.scope(session.sessionId);
|
|
2928
|
+
if (liveScope === void 0) return;
|
|
2929
|
+
const liveConversation = liveScope.get("conversation");
|
|
2930
|
+
if (liveConversation === void 0) return;
|
|
2931
|
+
liveConversation.input.for(liveScope).setDraft(nextDraft);
|
|
2932
|
+
requestComposerFocus({
|
|
2933
|
+
sessionId: session.sessionId,
|
|
2934
|
+
expectedDraft: nextDraft,
|
|
2935
|
+
caret: prefix.length
|
|
2936
|
+
});
|
|
2937
|
+
}, 0);
|
|
2203
2938
|
}
|
|
2204
2939
|
}
|
|
2205
2940
|
});
|
|
2206
2941
|
}, "dsh-skill-importer: /skills popupSelect command");
|
|
2207
|
-
const refreshSkills = async () => {
|
|
2208
|
-
|
|
2942
|
+
const refreshSkills = async (workspacePath) => {
|
|
2943
|
+
const result = await call(workspacePath === void 0 ? ROUTES.list : `${ROUTES.list}?workspacePath=${encodeURIComponent(workspacePath)}`);
|
|
2944
|
+
catalog = result.skills;
|
|
2945
|
+
issues = result.issues;
|
|
2209
2946
|
notify();
|
|
2210
2947
|
return catalog;
|
|
2211
2948
|
};
|
|
2949
|
+
const refreshSkillsForSession = async (sessionId) => {
|
|
2950
|
+
const cwd = sessions.list.getSnapshot().byId[sessionId]?.cwd;
|
|
2951
|
+
const effective = effectiveSkills((await call(cwd === void 0 ? `${ROUTES.list}?scope=global` : `${ROUTES.list}?workspacePath=${encodeURIComponent(cwd)}`)).skills);
|
|
2952
|
+
sessionCatalogs.set(sessionId, effective);
|
|
2953
|
+
notify();
|
|
2954
|
+
return effective;
|
|
2955
|
+
};
|
|
2212
2956
|
const importSkill = async (request) => {
|
|
2213
2957
|
return (await call(ROUTES.import, request)).path;
|
|
2214
2958
|
};
|
|
@@ -2219,30 +2963,50 @@ window.__ModuleLoader__.load({
|
|
|
2219
2963
|
return (await call(ROUTES.delete, request)).removed;
|
|
2220
2964
|
};
|
|
2221
2965
|
const pickDirectory = async () => {
|
|
2222
|
-
|
|
2966
|
+
if (remote?.directoryPicker !== void 0) {
|
|
2967
|
+
const result = await remote.directoryPicker.pick();
|
|
2968
|
+
if (!result.ok) throw new Error(result.error.message);
|
|
2969
|
+
return result.value;
|
|
2970
|
+
}
|
|
2971
|
+
if (legacyApi?.host === void 0) throw new Error("当前 DSH 未提供目录选择能力");
|
|
2972
|
+
const response = await legacyApi.host.pickDirectory({});
|
|
2223
2973
|
if (!response.result.ok) throw new Error(response.result.error.message);
|
|
2224
2974
|
return response.result.value.path;
|
|
2225
2975
|
};
|
|
2226
2976
|
const scanBatch = (request) => call(ROUTES.batchScan, request);
|
|
2227
2977
|
const commitBatch = (request) => call(ROUTES.batchCommit, request);
|
|
2978
|
+
const checkForUpdates = () => call(ROUTES.updateStatus);
|
|
2228
2979
|
const face = () => ({
|
|
2229
|
-
hooks: {
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2980
|
+
hooks: {
|
|
2981
|
+
skills: {
|
|
2982
|
+
getSnapshot: () => catalog,
|
|
2983
|
+
subscribe: (listener) => {
|
|
2984
|
+
listeners.add(listener);
|
|
2985
|
+
return () => {
|
|
2986
|
+
listeners.delete(listener);
|
|
2987
|
+
};
|
|
2988
|
+
}
|
|
2989
|
+
},
|
|
2990
|
+
skillIssues: {
|
|
2991
|
+
getSnapshot: () => issues,
|
|
2992
|
+
subscribe: (listener) => {
|
|
2993
|
+
listeners.add(listener);
|
|
2994
|
+
return () => {
|
|
2995
|
+
listeners.delete(listener);
|
|
2996
|
+
};
|
|
2997
|
+
}
|
|
2236
2998
|
}
|
|
2237
|
-
}
|
|
2999
|
+
},
|
|
2238
3000
|
actions: {
|
|
2239
3001
|
refreshSkills,
|
|
3002
|
+
refreshSkillsForSession,
|
|
2240
3003
|
importSkill,
|
|
2241
3004
|
importUrl,
|
|
2242
3005
|
deleteSkill,
|
|
2243
3006
|
pickDirectory,
|
|
2244
3007
|
scanBatch,
|
|
2245
|
-
commitBatch
|
|
3008
|
+
commitBatch,
|
|
3009
|
+
checkForUpdates
|
|
2246
3010
|
}
|
|
2247
3011
|
});
|
|
2248
3012
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|