dsh-skill-importer 0.2.2 → 0.2.4
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 +927 -86
- 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/atomicSkillDelete.d.ts +19 -0
- package/lib/types/client/composerFocus.d.ts +9 -0
- package/lib/types/client/effectiveSkills.d.ts +3 -0
- package/lib/types/client/index.d.ts +11 -3
- package/lib/types/client/locales.d.ts +90 -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 +8 -1
- package/src/server.ts +85 -37
- package/src/types.ts +25 -3
- package/tests/atomic-skill-delete.test.mjs +24 -0
- 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
|
@@ -5,8 +5,8 @@ window.__ModuleLoader__.load({
|
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
7
|
let react = require("react");
|
|
8
|
-
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
8
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
10
|
//#region src/frontmatter.ts
|
|
11
11
|
/** Kebab-case name rule shared with `dsh-skill` (`^[a-z0-9]+(?:-[a-z0-9]+)*$`). */
|
|
12
12
|
const KEBAB_CASE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
@@ -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)("");
|
|
@@ -261,7 +274,42 @@ window.__ModuleLoader__.load({
|
|
|
261
274
|
const [batchScan, setBatchScan] = (0, react.useState)();
|
|
262
275
|
const [batchResults, setBatchResults] = (0, react.useState)();
|
|
263
276
|
const [replaceNames, setReplaceNames] = (0, react.useState)(() => /* @__PURE__ */ new Set());
|
|
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);
|
|
286
|
+
const [batchConfirmation, setBatchConfirmation] = (0, react.useState)();
|
|
264
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
|
+
};
|
|
265
313
|
const onFilePicked = async (file) => {
|
|
266
314
|
setFileDraft(void 0);
|
|
267
315
|
setFileError(void 0);
|
|
@@ -302,8 +350,9 @@ window.__ModuleLoader__.load({
|
|
|
302
350
|
}, () => pollForSkill(name, attemptsLeft - 1));
|
|
303
351
|
}, 2e3);
|
|
304
352
|
};
|
|
305
|
-
const removeSkill = async (
|
|
306
|
-
if (
|
|
353
|
+
const removeSkill = async () => {
|
|
354
|
+
if (pendingDelete === void 0) return;
|
|
355
|
+
const skill = pendingDelete;
|
|
307
356
|
setBusy(true);
|
|
308
357
|
setMessage(void 0);
|
|
309
358
|
setMessageError(false);
|
|
@@ -311,8 +360,11 @@ window.__ModuleLoader__.load({
|
|
|
311
360
|
if (await actions.deleteSkill({
|
|
312
361
|
name: skill.name,
|
|
313
362
|
source: skill.source,
|
|
314
|
-
workspacePath:
|
|
315
|
-
}))
|
|
363
|
+
workspacePath: skill.workspacePath
|
|
364
|
+
})) {
|
|
365
|
+
setMessage(t("deleted"));
|
|
366
|
+
setPendingDelete(void 0);
|
|
367
|
+
}
|
|
316
368
|
setListEpoch((epoch) => epoch + 1);
|
|
317
369
|
} catch (error) {
|
|
318
370
|
setMessageError(true);
|
|
@@ -403,17 +455,20 @@ window.__ModuleLoader__.load({
|
|
|
403
455
|
setBusy(false);
|
|
404
456
|
}
|
|
405
457
|
};
|
|
406
|
-
const
|
|
458
|
+
const requestBatchCommit = () => {
|
|
407
459
|
if (batchScan === void 0) return;
|
|
408
460
|
const ready = batchScan.entries.filter((entry) => entry.status === "ready");
|
|
409
461
|
const replacing = ready.filter((entry) => replaceNames.has(entry.name)).length;
|
|
410
462
|
const importing = ready.filter((entry) => !entry.conflict).length;
|
|
411
463
|
const skipped = ready.filter((entry) => entry.conflict && !replaceNames.has(entry.name)).length;
|
|
412
|
-
|
|
464
|
+
setBatchConfirmation({
|
|
413
465
|
importing,
|
|
414
466
|
replacing,
|
|
415
467
|
skipped
|
|
416
|
-
})
|
|
468
|
+
});
|
|
469
|
+
};
|
|
470
|
+
const commitBatchDirectory = async () => {
|
|
471
|
+
if (batchScan === void 0 || batchConfirmation === void 0) return;
|
|
417
472
|
setBusy(true);
|
|
418
473
|
setMessage(void 0);
|
|
419
474
|
setMessageError(false);
|
|
@@ -425,6 +480,7 @@ window.__ModuleLoader__.load({
|
|
|
425
480
|
setBatchResults(result.results);
|
|
426
481
|
setBatchScan(void 0);
|
|
427
482
|
setReplaceNames(/* @__PURE__ */ new Set());
|
|
483
|
+
setBatchConfirmation(void 0);
|
|
428
484
|
setListEpoch((epoch) => epoch + 1);
|
|
429
485
|
} catch (error) {
|
|
430
486
|
setMessageError(true);
|
|
@@ -444,27 +500,57 @@ window.__ModuleLoader__.load({
|
|
|
444
500
|
setTarget(next);
|
|
445
501
|
if (mode === "batch") resetBatchPreflight();
|
|
446
502
|
};
|
|
447
|
-
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;
|
|
448
514
|
const runPrimaryAction = () => {
|
|
449
515
|
if (mode !== "batch") {
|
|
450
516
|
submit();
|
|
451
517
|
return;
|
|
452
518
|
}
|
|
453
519
|
if (batchScan === void 0) scanBatchDirectory();
|
|
454
|
-
else
|
|
520
|
+
else requestBatchCommit();
|
|
455
521
|
};
|
|
456
522
|
const primaryLabel = mode !== "batch" ? busy ? t("importing") : t("import") : busy ? t("batchWorking") : batchScan === void 0 ? t("batchScan") : t("batchCommit");
|
|
457
523
|
const flags = (skill) => {
|
|
458
524
|
if (!skill.modelInvocable && skill.userInvocable) return t("userOnly");
|
|
459
525
|
if (skill.modelInvocable && !skill.userInvocable) return t("modelOnly");
|
|
460
526
|
};
|
|
461
|
-
const
|
|
462
|
-
|
|
527
|
+
const toggleGroup = (groupKey) => {
|
|
528
|
+
setExpandedGroups((current) => {
|
|
463
529
|
const next = new Set(current);
|
|
464
|
-
if (!next.delete(
|
|
530
|
+
if (!next.delete(groupKey)) next.add(groupKey);
|
|
465
531
|
return next;
|
|
466
532
|
});
|
|
467
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
|
+
];
|
|
468
554
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
469
555
|
style: {
|
|
470
556
|
display: "flex",
|
|
@@ -519,23 +605,33 @@ window.__ModuleLoader__.load({
|
|
|
519
605
|
listError
|
|
520
606
|
]
|
|
521
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,
|
|
522
619
|
listState === "idle" && skills.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
523
620
|
style: descriptionStyle,
|
|
524
621
|
children: t("installedEmpty")
|
|
525
622
|
}) : null,
|
|
526
623
|
skills.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
527
624
|
style: skillGroupsStyle,
|
|
528
|
-
children:
|
|
529
|
-
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));
|
|
530
627
|
if (rows.length === 0) return null;
|
|
531
|
-
const
|
|
532
|
-
const open = !collapsedSources.has(source);
|
|
628
|
+
const open = expandedGroups.has(group.key);
|
|
533
629
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
534
630
|
style: skillGroupCardStyle,
|
|
535
631
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
536
632
|
type: "button",
|
|
537
633
|
"aria-expanded": open,
|
|
538
|
-
onClick: () =>
|
|
634
|
+
onClick: () => toggleGroup(group.key),
|
|
539
635
|
style: {
|
|
540
636
|
...skillGroupHeaderStyle,
|
|
541
637
|
borderBottom: open ? skillGroupHeaderStyle.borderBottom : "none"
|
|
@@ -549,7 +645,7 @@ window.__ModuleLoader__.load({
|
|
|
549
645
|
style: skillGroupIdentityStyle,
|
|
550
646
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
551
647
|
style: skillGroupNameStyle,
|
|
552
|
-
children:
|
|
648
|
+
children: group.name
|
|
553
649
|
})
|
|
554
650
|
}),
|
|
555
651
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -592,17 +688,15 @@ window.__ModuleLoader__.load({
|
|
|
592
688
|
type: "button",
|
|
593
689
|
"aria-label": `${t("delete")} ${skill.name}`,
|
|
594
690
|
title: t("delete"),
|
|
595
|
-
onClick: () =>
|
|
596
|
-
removeSkill(skill);
|
|
597
|
-
},
|
|
691
|
+
onClick: () => setPendingDelete(skill),
|
|
598
692
|
style: deleteIconButtonStyle,
|
|
599
693
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, {})
|
|
600
694
|
})
|
|
601
695
|
]
|
|
602
|
-
}, skill.source + ":" + skill.name);
|
|
696
|
+
}, skill.source + ":" + (skill.workspacePath ?? "") + ":" + skill.name);
|
|
603
697
|
})
|
|
604
698
|
}) : null]
|
|
605
|
-
},
|
|
699
|
+
}, group.key);
|
|
606
700
|
})
|
|
607
701
|
}) : null
|
|
608
702
|
]
|
|
@@ -1006,17 +1100,28 @@ window.__ModuleLoader__.load({
|
|
|
1006
1100
|
style: fieldLabelStyle,
|
|
1007
1101
|
children: t("targetLabel")
|
|
1008
1102
|
}),
|
|
1009
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
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")
|
|
1020
1125
|
})]
|
|
1021
1126
|
}),
|
|
1022
1127
|
workspace === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -1048,6 +1153,263 @@ window.__ModuleLoader__.load({
|
|
|
1048
1153
|
})
|
|
1049
1154
|
]
|
|
1050
1155
|
})
|
|
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
|
+
}),
|
|
1342
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
1343
|
+
open: pendingDelete !== void 0,
|
|
1344
|
+
onClose: () => {
|
|
1345
|
+
if (!busy) setPendingDelete(void 0);
|
|
1346
|
+
},
|
|
1347
|
+
title: t("deleteTitle"),
|
|
1348
|
+
closeLabel: t("close"),
|
|
1349
|
+
description: pendingDelete === void 0 ? void 0 : t("deleteConfirm", { name: pendingDelete.name }),
|
|
1350
|
+
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, {
|
|
1351
|
+
variant: "outline",
|
|
1352
|
+
disabled: busy,
|
|
1353
|
+
onClick: () => setPendingDelete(void 0),
|
|
1354
|
+
children: t("cancel")
|
|
1355
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1356
|
+
variant: "primary",
|
|
1357
|
+
disabled: busy,
|
|
1358
|
+
onClick: () => {
|
|
1359
|
+
removeSkill();
|
|
1360
|
+
},
|
|
1361
|
+
children: busy ? t("deleting") : t("delete")
|
|
1362
|
+
})] })
|
|
1363
|
+
}),
|
|
1364
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
1365
|
+
open: batchConfirmation !== void 0,
|
|
1366
|
+
onClose: () => {
|
|
1367
|
+
if (!busy) setBatchConfirmation(void 0);
|
|
1368
|
+
},
|
|
1369
|
+
title: t("batchConfirmTitle"),
|
|
1370
|
+
closeLabel: t("close"),
|
|
1371
|
+
description: batchConfirmation === void 0 ? void 0 : t("batchConfirm", batchConfirmation),
|
|
1372
|
+
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, {
|
|
1373
|
+
variant: "outline",
|
|
1374
|
+
disabled: busy,
|
|
1375
|
+
onClick: () => setBatchConfirmation(void 0),
|
|
1376
|
+
children: t("cancel")
|
|
1377
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1378
|
+
variant: "primary",
|
|
1379
|
+
disabled: busy,
|
|
1380
|
+
onClick: () => {
|
|
1381
|
+
commitBatchDirectory();
|
|
1382
|
+
},
|
|
1383
|
+
children: busy ? t("batchWorking") : t("batchCommit")
|
|
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
|
+
})
|
|
1051
1413
|
})
|
|
1052
1414
|
]
|
|
1053
1415
|
});
|
|
@@ -1076,6 +1438,58 @@ window.__ModuleLoader__.load({
|
|
|
1076
1438
|
lineHeight: "18px",
|
|
1077
1439
|
color: "var(--dsw-alias-label-caption)"
|
|
1078
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
|
+
};
|
|
1079
1493
|
const pillStyle = {
|
|
1080
1494
|
display: "inline-flex",
|
|
1081
1495
|
alignItems: "center",
|
|
@@ -1253,18 +1667,7 @@ window.__ModuleLoader__.load({
|
|
|
1253
1667
|
color: "var(--dsw-alias-label-primary)",
|
|
1254
1668
|
outline: "none"
|
|
1255
1669
|
};
|
|
1256
|
-
|
|
1257
|
-
* (same treatment as the composer chips / models page selects). */
|
|
1258
|
-
const selectStyle = {
|
|
1259
|
-
...controlStyle,
|
|
1260
|
-
appearance: "none",
|
|
1261
|
-
paddingRight: 32,
|
|
1262
|
-
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\")",
|
|
1263
|
-
backgroundRepeat: "no-repeat",
|
|
1264
|
-
backgroundPosition: "right 12px center",
|
|
1265
|
-
backgroundSize: "12px 12px",
|
|
1266
|
-
cursor: "pointer"
|
|
1267
|
-
};
|
|
1670
|
+
({ ...controlStyle });
|
|
1268
1671
|
const entryGridStyle = {
|
|
1269
1672
|
display: "grid",
|
|
1270
1673
|
gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
|
|
@@ -1365,6 +1768,127 @@ window.__ModuleLoader__.load({
|
|
|
1365
1768
|
fontSize: 12,
|
|
1366
1769
|
lineHeight: "18px"
|
|
1367
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
|
+
};
|
|
1368
1892
|
const previewStyle = {
|
|
1369
1893
|
display: "flex",
|
|
1370
1894
|
flexDirection: "column",
|
|
@@ -1516,6 +2040,58 @@ window.__ModuleLoader__.load({
|
|
|
1516
2040
|
cursor: "default"
|
|
1517
2041
|
};
|
|
1518
2042
|
//#endregion
|
|
2043
|
+
//#region src/client/atomicSkillDelete.ts
|
|
2044
|
+
function leadingSkillToken(draft, names) {
|
|
2045
|
+
const ordered = [...new Set(names)].sort((a, b) => b.length - a.length);
|
|
2046
|
+
for (const name of ordered) {
|
|
2047
|
+
if (name.length === 0) continue;
|
|
2048
|
+
const token = `/${name}`;
|
|
2049
|
+
if (!draft.startsWith(token)) continue;
|
|
2050
|
+
const following = draft[token.length];
|
|
2051
|
+
if (following !== void 0 && !/\s/u.test(following)) continue;
|
|
2052
|
+
return {
|
|
2053
|
+
tokenEnd: token.length,
|
|
2054
|
+
boundaryEnd: token.length + (following === " " ? 1 : 0)
|
|
2055
|
+
};
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* Delete one exact, leading, installed `/name` token as a single edit.
|
|
2060
|
+
*
|
|
2061
|
+
* This deliberately handles only the common boundary gesture. Selections,
|
|
2062
|
+
* token-internal edits, unknown names, leading whitespace, and non-boundary
|
|
2063
|
+
* carets fall through to the textarea's normal behavior.
|
|
2064
|
+
*/
|
|
2065
|
+
function atomicSkillBackspace(draft, caret, names) {
|
|
2066
|
+
if (!Number.isInteger(caret) || caret < 0 || caret > draft.length) return void 0;
|
|
2067
|
+
const token = leadingSkillToken(draft, names);
|
|
2068
|
+
if (token === void 0) return void 0;
|
|
2069
|
+
if (caret !== token.tokenEnd && caret !== token.boundaryEnd) return void 0;
|
|
2070
|
+
return {
|
|
2071
|
+
draft: draft.slice(token.boundaryEnd),
|
|
2072
|
+
caret: 0
|
|
2073
|
+
};
|
|
2074
|
+
}
|
|
2075
|
+
/**
|
|
2076
|
+
* Resolve one whole-token horizontal caret jump.
|
|
2077
|
+
* Left from anywhere inside/just after the leading skill goes before it;
|
|
2078
|
+
* right from before/inside it goes after its single separator.
|
|
2079
|
+
*/
|
|
2080
|
+
function atomicSkillArrow(draft, caret, direction, names) {
|
|
2081
|
+
if (!Number.isInteger(caret) || caret < 0 || caret > draft.length) return void 0;
|
|
2082
|
+
const token = leadingSkillToken(draft, names);
|
|
2083
|
+
if (token === void 0) return void 0;
|
|
2084
|
+
if (direction === "left" && caret > 0 && caret <= token.boundaryEnd) return 0;
|
|
2085
|
+
if (direction === "right" && caret >= 0 && caret < token.boundaryEnd) return token.boundaryEnd;
|
|
2086
|
+
}
|
|
2087
|
+
//#endregion
|
|
2088
|
+
//#region src/client/composerFocus.ts
|
|
2089
|
+
const COMPOSER_FOCUS_EVENT = "dsh-skill-importer/composer-focus";
|
|
2090
|
+
/** Ask the mounted picker in one session to restore its composer focus. */
|
|
2091
|
+
function requestComposerFocus(request) {
|
|
2092
|
+
window.dispatchEvent(new CustomEvent(COMPOSER_FOCUS_EVENT, { detail: request }));
|
|
2093
|
+
}
|
|
2094
|
+
//#endregion
|
|
1519
2095
|
//#region src/client/SkillsPicker.tsx
|
|
1520
2096
|
/**
|
|
1521
2097
|
* Composer skill picker: a compact pill trigger in the composer's tool row
|
|
@@ -1526,16 +2102,53 @@ window.__ModuleLoader__.load({
|
|
|
1526
2102
|
* with `/name ` — the native text gesture — highlighted via the plugin's
|
|
1527
2103
|
* lexicon contribution.
|
|
1528
2104
|
*/
|
|
2105
|
+
/** Find the one composer textarea owned by the picker nearest in the slot tree. */
|
|
2106
|
+
function composerTextareaFor(root) {
|
|
2107
|
+
let node = root?.parentElement;
|
|
2108
|
+
while (node !== null && node !== void 0) {
|
|
2109
|
+
const textareas = node.querySelectorAll("textarea");
|
|
2110
|
+
if (textareas.length > 0) return textareas.length === 1 ? textareas[0] : void 0;
|
|
2111
|
+
node = node.parentElement;
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
1529
2114
|
/** One row of the composer skill picker. */
|
|
1530
|
-
function SkillsPicker({ t,
|
|
1531
|
-
const skills = useSkills((value) => value);
|
|
2115
|
+
function SkillsPicker({ t, sessionId, useInput, inputActions, actions }) {
|
|
1532
2116
|
const input = useInput((value) => value.draft);
|
|
2117
|
+
const [skills, setSkills] = (0, react.useState)([]);
|
|
1533
2118
|
const [open, setOpen] = (0, react.useState)(false);
|
|
2119
|
+
const [loading, setLoading] = (0, react.useState)(true);
|
|
1534
2120
|
const [query, setQuery] = (0, react.useState)("");
|
|
1535
2121
|
const rootRef = (0, react.useRef)(null);
|
|
2122
|
+
const draftRef = (0, react.useRef)(input);
|
|
2123
|
+
const skillNamesRef = (0, react.useRef)([]);
|
|
2124
|
+
const caretFrameRef = (0, react.useRef)();
|
|
1536
2125
|
(0, react.useEffect)(() => {
|
|
1537
|
-
|
|
1538
|
-
|
|
2126
|
+
let cancelled = false;
|
|
2127
|
+
const refresh = (showLoading) => {
|
|
2128
|
+
if (showLoading) setLoading(true);
|
|
2129
|
+
actions.refreshSkillsForSession(sessionId).then((rows) => {
|
|
2130
|
+
if (!cancelled) {
|
|
2131
|
+
setSkills(rows);
|
|
2132
|
+
setLoading(false);
|
|
2133
|
+
}
|
|
2134
|
+
}, () => {
|
|
2135
|
+
if (!cancelled) {
|
|
2136
|
+
setSkills([]);
|
|
2137
|
+
setLoading(false);
|
|
2138
|
+
}
|
|
2139
|
+
});
|
|
2140
|
+
};
|
|
2141
|
+
refresh(true);
|
|
2142
|
+
const timer = open ? window.setInterval(() => refresh(false), 2e3) : void 0;
|
|
2143
|
+
return () => {
|
|
2144
|
+
cancelled = true;
|
|
2145
|
+
if (timer !== void 0) window.clearInterval(timer);
|
|
2146
|
+
};
|
|
2147
|
+
}, [
|
|
2148
|
+
actions,
|
|
2149
|
+
sessionId,
|
|
2150
|
+
open
|
|
2151
|
+
]);
|
|
1539
2152
|
(0, react.useEffect)(() => {
|
|
1540
2153
|
if (!open) return;
|
|
1541
2154
|
const onDown = (event) => {
|
|
@@ -1548,11 +2161,76 @@ window.__ModuleLoader__.load({
|
|
|
1548
2161
|
if (open) setQuery("");
|
|
1549
2162
|
}, [open]);
|
|
1550
2163
|
const usable = skills.filter((skill) => skill.userInvocable);
|
|
1551
|
-
|
|
2164
|
+
draftRef.current = input;
|
|
2165
|
+
skillNamesRef.current = usable.map((skill) => skill.name);
|
|
2166
|
+
const scheduleComposerFocus = (expectedDraft, caret) => {
|
|
2167
|
+
const textarea = composerTextareaFor(rootRef.current);
|
|
2168
|
+
if (caretFrameRef.current !== void 0) window.cancelAnimationFrame(caretFrameRef.current);
|
|
2169
|
+
caretFrameRef.current = window.requestAnimationFrame(() => {
|
|
2170
|
+
caretFrameRef.current = void 0;
|
|
2171
|
+
if (textarea === void 0 || !textarea.isConnected || textarea.value !== expectedDraft) return;
|
|
2172
|
+
textarea.focus({ preventScroll: true });
|
|
2173
|
+
textarea.setSelectionRange(caret, caret);
|
|
2174
|
+
});
|
|
2175
|
+
};
|
|
2176
|
+
(0, react.useEffect)(() => {
|
|
2177
|
+
const onFocusRequest = (event) => {
|
|
2178
|
+
const request = event.detail;
|
|
2179
|
+
if (request.sessionId !== sessionId) return;
|
|
2180
|
+
scheduleComposerFocus(request.expectedDraft, request.caret);
|
|
2181
|
+
};
|
|
2182
|
+
window.addEventListener(COMPOSER_FOCUS_EVENT, onFocusRequest);
|
|
2183
|
+
return () => window.removeEventListener(COMPOSER_FOCUS_EVENT, onFocusRequest);
|
|
2184
|
+
}, [sessionId]);
|
|
2185
|
+
(0, react.useEffect)(() => {
|
|
2186
|
+
const onKeyDown = (event) => {
|
|
2187
|
+
if (![
|
|
2188
|
+
"Backspace",
|
|
2189
|
+
"ArrowLeft",
|
|
2190
|
+
"ArrowRight"
|
|
2191
|
+
].includes(event.key)) return;
|
|
2192
|
+
if (event.defaultPrevented || event.isComposing || event.keyCode === 229) return;
|
|
2193
|
+
if (event.metaKey || event.ctrlKey || event.altKey) return;
|
|
2194
|
+
if (event.shiftKey && event.key !== "Backspace") return;
|
|
2195
|
+
const textarea = event.target;
|
|
2196
|
+
if (!(textarea instanceof HTMLTextAreaElement) || document.activeElement !== textarea) return;
|
|
2197
|
+
if (composerTextareaFor(rootRef.current) !== textarea || textarea.value !== draftRef.current) return;
|
|
2198
|
+
const start = textarea.selectionStart;
|
|
2199
|
+
const end = textarea.selectionEnd;
|
|
2200
|
+
if (start === null || end === null || start !== end) return;
|
|
2201
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
|
|
2202
|
+
const caret = atomicSkillArrow(draftRef.current, start, event.key === "ArrowLeft" ? "left" : "right", skillNamesRef.current);
|
|
2203
|
+
if (caret === void 0) return;
|
|
2204
|
+
event.preventDefault();
|
|
2205
|
+
event.stopPropagation();
|
|
2206
|
+
textarea.setSelectionRange(caret, caret);
|
|
2207
|
+
return;
|
|
2208
|
+
}
|
|
2209
|
+
const edit = atomicSkillBackspace(draftRef.current, start, skillNamesRef.current);
|
|
2210
|
+
if (edit === void 0) return;
|
|
2211
|
+
event.preventDefault();
|
|
2212
|
+
event.stopPropagation();
|
|
2213
|
+
inputActions.setDraft(edit.draft);
|
|
2214
|
+
if (caretFrameRef.current !== void 0) window.cancelAnimationFrame(caretFrameRef.current);
|
|
2215
|
+
caretFrameRef.current = window.requestAnimationFrame(() => {
|
|
2216
|
+
caretFrameRef.current = void 0;
|
|
2217
|
+
if (!textarea.isConnected || document.activeElement !== textarea || textarea.value !== edit.draft) return;
|
|
2218
|
+
textarea.setSelectionRange(edit.caret, edit.caret);
|
|
2219
|
+
});
|
|
2220
|
+
};
|
|
2221
|
+
document.addEventListener("keydown", onKeyDown, true);
|
|
2222
|
+
return () => {
|
|
2223
|
+
document.removeEventListener("keydown", onKeyDown, true);
|
|
2224
|
+
if (caretFrameRef.current !== void 0) window.cancelAnimationFrame(caretFrameRef.current);
|
|
2225
|
+
};
|
|
2226
|
+
}, [inputActions]);
|
|
1552
2227
|
const filtered = query.trim().length === 0 ? usable : usable.filter((skill) => skill.name.toLowerCase().includes(query.trim().toLowerCase()));
|
|
1553
2228
|
const onSelect = (name) => {
|
|
2229
|
+
const prefix = `/${name} `;
|
|
2230
|
+
const nextDraft = `${prefix}${input}`;
|
|
1554
2231
|
setOpen(false);
|
|
1555
|
-
inputActions.setDraft(
|
|
2232
|
+
inputActions.setDraft(nextDraft);
|
|
2233
|
+
scheduleComposerFocus(nextDraft, prefix.length);
|
|
1556
2234
|
};
|
|
1557
2235
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1558
2236
|
ref: rootRef,
|
|
@@ -1561,7 +2239,10 @@ window.__ModuleLoader__.load({
|
|
|
1561
2239
|
type: "button",
|
|
1562
2240
|
"aria-label": t("pickerLabel"),
|
|
1563
2241
|
"aria-expanded": open,
|
|
1564
|
-
onClick: () =>
|
|
2242
|
+
onClick: () => {
|
|
2243
|
+
if (!open) setLoading(true);
|
|
2244
|
+
setOpen((value) => !value);
|
|
2245
|
+
},
|
|
1565
2246
|
style: triggerStyle,
|
|
1566
2247
|
children: [
|
|
1567
2248
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -1593,7 +2274,10 @@ window.__ModuleLoader__.load({
|
|
|
1593
2274
|
placeholder: t("pickerSearchPlaceholder"),
|
|
1594
2275
|
style: searchStyle
|
|
1595
2276
|
}),
|
|
1596
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
2277
|
+
loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2278
|
+
style: emptyStyle,
|
|
2279
|
+
children: t("pickerLoading")
|
|
2280
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
1597
2281
|
style: listStyle,
|
|
1598
2282
|
children: filtered.map((skill) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1599
2283
|
type: "button",
|
|
@@ -1603,13 +2287,19 @@ window.__ModuleLoader__.load({
|
|
|
1603
2287
|
style: avatarStyle,
|
|
1604
2288
|
"aria-hidden": "true",
|
|
1605
2289
|
children: skill.name.charAt(0).toUpperCase()
|
|
1606
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
1607
|
-
style:
|
|
1608
|
-
children:
|
|
2290
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2291
|
+
style: rowCopyStyle,
|
|
2292
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2293
|
+
style: rowLabelStyle,
|
|
2294
|
+
children: skill.name
|
|
2295
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2296
|
+
style: rowDetailStyle,
|
|
2297
|
+
children: skill.source === "project-dsh" ? t("pickerSourceProjectDsh") : skill.source === "project-agents" ? t("pickerSourceProjectAgents") : skill.source === "user-dsh" ? t("pickerSourceUserDsh") : t("pickerSourceUserAgents")
|
|
2298
|
+
})]
|
|
1609
2299
|
})]
|
|
1610
2300
|
}) }, skill.name))
|
|
1611
2301
|
}),
|
|
1612
|
-
filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2302
|
+
!loading && filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1613
2303
|
style: emptyStyle,
|
|
1614
2304
|
children: t("pickerEmpty")
|
|
1615
2305
|
}) : null
|
|
@@ -1724,12 +2414,41 @@ window.__ModuleLoader__.load({
|
|
|
1724
2414
|
minWidth: 0,
|
|
1725
2415
|
overflow: "hidden"
|
|
1726
2416
|
};
|
|
2417
|
+
const rowCopyStyle = {
|
|
2418
|
+
display: "flex",
|
|
2419
|
+
flexDirection: "column",
|
|
2420
|
+
minWidth: 0,
|
|
2421
|
+
flex: 1,
|
|
2422
|
+
lineHeight: "18px"
|
|
2423
|
+
};
|
|
2424
|
+
const rowDetailStyle = {
|
|
2425
|
+
overflow: "hidden",
|
|
2426
|
+
textOverflow: "ellipsis",
|
|
2427
|
+
whiteSpace: "nowrap",
|
|
2428
|
+
color: "var(--dsw-alias-label-caption)",
|
|
2429
|
+
fontSize: 11,
|
|
2430
|
+
lineHeight: "16px"
|
|
2431
|
+
};
|
|
1727
2432
|
const emptyStyle = {
|
|
1728
2433
|
padding: "8px 10px",
|
|
1729
2434
|
fontSize: 12,
|
|
1730
2435
|
color: "var(--dsw-alias-label-caption)"
|
|
1731
2436
|
};
|
|
1732
2437
|
//#endregion
|
|
2438
|
+
//#region src/client/effectiveSkills.ts
|
|
2439
|
+
const SOURCE_RANK = {
|
|
2440
|
+
"project-dsh": 100,
|
|
2441
|
+
"project-agents": 200,
|
|
2442
|
+
"user-dsh": 400,
|
|
2443
|
+
"user-agents": 500
|
|
2444
|
+
};
|
|
2445
|
+
/** Mirror DSH's name-based winner selection for one session-scoped catalog. */
|
|
2446
|
+
function effectiveSkills(rows) {
|
|
2447
|
+
const winners = /* @__PURE__ */ new Map();
|
|
2448
|
+
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);
|
|
2449
|
+
return [...winners.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
2450
|
+
}
|
|
2451
|
+
//#endregion
|
|
1733
2452
|
//#region src/client/locales.ts
|
|
1734
2453
|
/**
|
|
1735
2454
|
* Locale dictionaries for the skill importer settings section.
|
|
@@ -1746,7 +2465,12 @@ window.__ModuleLoader__.load({
|
|
|
1746
2465
|
pickerLabel: "技能",
|
|
1747
2466
|
pickerPlaceholder: "技能",
|
|
1748
2467
|
pickerSearchPlaceholder: "筛选技能…",
|
|
2468
|
+
pickerLoading: "正在同步当前项目技能…",
|
|
1749
2469
|
pickerEmpty: "没有匹配的技能",
|
|
2470
|
+
pickerSourceProjectDsh: "当前项目 · .dsh",
|
|
2471
|
+
pickerSourceProjectAgents: "当前项目 · .agents",
|
|
2472
|
+
pickerSourceUserDsh: "全局 · .dsh",
|
|
2473
|
+
pickerSourceUserAgents: "全局 · .agents",
|
|
1750
2474
|
commandDescription: "选择技能:弹出技能列表,选中后填入 /<名称>",
|
|
1751
2475
|
entryTitle: "技能入口",
|
|
1752
2476
|
entryDescription: "通过输入框工具行的技能下拉或 /skills 命令选择技能;也可直接输入 /<名称>。选中的技能会高亮并注入指令。",
|
|
@@ -1754,10 +2478,15 @@ window.__ModuleLoader__.load({
|
|
|
1754
2478
|
refresh: "刷新",
|
|
1755
2479
|
installedEmpty: "暂无技能。导入新技能或手动放入技能目录后会自动出现。",
|
|
1756
2480
|
delete: "删除",
|
|
2481
|
+
deleting: "删除中…",
|
|
2482
|
+
deleteTitle: "删除技能",
|
|
1757
2483
|
deleteConfirm: "确定删除技能 {name} 吗?将删除对应目录下的 SKILL.md 及资源文件。",
|
|
2484
|
+
cancel: "取消",
|
|
2485
|
+
close: "关闭",
|
|
1758
2486
|
deleteFailed: "删除失败",
|
|
1759
2487
|
deleted: "已删除。",
|
|
1760
2488
|
installedFailed: "无法读取技能列表",
|
|
2489
|
+
installedPartial: "有 {count} 个技能目录暂时无法读取,其他技能已正常显示。",
|
|
1761
2490
|
userOnly: "仅斜杠可用",
|
|
1762
2491
|
modelOnly: "仅模型可用",
|
|
1763
2492
|
importTitle: "导入技能",
|
|
@@ -1800,6 +2529,7 @@ window.__ModuleLoader__.load({
|
|
|
1800
2529
|
batchConflict: "名称重复",
|
|
1801
2530
|
batchReplace: "替换",
|
|
1802
2531
|
batchConfirm: "将新增 {importing} 个、替换 {replacing} 个、跳过 {skipped} 个技能。确认继续吗?",
|
|
2532
|
+
batchConfirmTitle: "确认批量导入",
|
|
1803
2533
|
batchResultTitle: "本次导入结果",
|
|
1804
2534
|
batchResultSummary: "新增 {imported} · 替换 {replaced} · 跳过 {skipped} · 失败 {failed}",
|
|
1805
2535
|
batchStatusImported: "已导入",
|
|
@@ -1807,15 +2537,48 @@ window.__ModuleLoader__.load({
|
|
|
1807
2537
|
batchStatusSkipped: "已跳过",
|
|
1808
2538
|
batchStatusError: "失败",
|
|
1809
2539
|
targetLabel: "安装到",
|
|
1810
|
-
|
|
1811
|
-
targetProjectAgents: "
|
|
2540
|
+
targetProjectDsh: "DSH 项目技能({title})",
|
|
2541
|
+
targetProjectAgents: "通用项目技能({title})",
|
|
2542
|
+
targetUserDsh: "DSH 全局技能",
|
|
2543
|
+
targetUserAgents: "通用全局技能",
|
|
2544
|
+
locationChange: "更改",
|
|
2545
|
+
locationTitle: "选择安装位置",
|
|
2546
|
+
locationProject: "项目技能",
|
|
2547
|
+
locationGlobal: "全局技能",
|
|
2548
|
+
workspaceSearch: "搜索工作区…",
|
|
2549
|
+
workspaceNoMatch: "没有匹配的工作区",
|
|
2550
|
+
chooseRootHint: "选择技能目录",
|
|
2551
|
+
rootProjectDsh: "DSH 项目技能",
|
|
2552
|
+
rootProjectAgents: "通用项目技能",
|
|
2553
|
+
rootUserDsh: "DSH 全局技能",
|
|
2554
|
+
rootUserAgents: "通用全局技能",
|
|
2555
|
+
priorityHighest: "最高",
|
|
2556
|
+
priorityHigher: "较高",
|
|
2557
|
+
priorityLower: "较低",
|
|
2558
|
+
priorityLowest: "最低",
|
|
2559
|
+
locationSummaryProjectDsh: "项目技能 · {title} · .dsh/skills",
|
|
2560
|
+
locationSummaryProjectAgents: "项目技能 · {title} · .agents/skills",
|
|
2561
|
+
locationSummaryUserDsh: "全局技能 · ~/.dsh/skills",
|
|
2562
|
+
locationSummaryUserAgents: "全局技能 · ~/.agents/skills",
|
|
1812
2563
|
targetProjectNoWorkspace: "项目技能(需先添加工作区)",
|
|
1813
2564
|
noWorkspace: "未注册工作区:请先在会话页选择/创建工作区,或改用用户技能目录。",
|
|
1814
2565
|
import: "导入",
|
|
1815
2566
|
importing: "导入中…",
|
|
1816
2567
|
imported: "已写入:",
|
|
1817
2568
|
importFailed: "导入失败",
|
|
1818
|
-
hostUnreachable: "无法连接 dsh 服务(插件路由未生效)。请确认插件已安装,并重启 dsh web 后刷新页面。"
|
|
2569
|
+
hostUnreachable: "无法连接 dsh 服务(插件路由未生效)。请确认插件已安装,并重启 dsh web 后刷新页面。",
|
|
2570
|
+
versionChecking: "正在检查更新…",
|
|
2571
|
+
versionCurrent: "当前版本 v{version}",
|
|
2572
|
+
versionLatest: "已是最新版本",
|
|
2573
|
+
versionAvailable: "发现新版本 v{version}",
|
|
2574
|
+
versionCheckFailed: "暂时无法检查更新",
|
|
2575
|
+
versionRetry: "重试",
|
|
2576
|
+
versionUpdate: "更新",
|
|
2577
|
+
updateTitle: "更新 dsh-skill-importer",
|
|
2578
|
+
updateDescription: "复制下面的精确版本命令,在终端运行后重启 dsh web。",
|
|
2579
|
+
copyCommand: "复制更新命令",
|
|
2580
|
+
commandCopied: "已复制",
|
|
2581
|
+
restartHint: "更新完成后需要重启 dsh web 才会生效。"
|
|
1819
2582
|
};
|
|
1820
2583
|
/** English dictionary, checked complete against the zh key set. */
|
|
1821
2584
|
const en = {
|
|
@@ -1823,7 +2586,12 @@ window.__ModuleLoader__.load({
|
|
|
1823
2586
|
pickerLabel: "Skills",
|
|
1824
2587
|
pickerPlaceholder: "Skills",
|
|
1825
2588
|
pickerSearchPlaceholder: "Filter skills…",
|
|
2589
|
+
pickerLoading: "Syncing skills for the current project…",
|
|
1826
2590
|
pickerEmpty: "No matching skills",
|
|
2591
|
+
pickerSourceProjectDsh: "Current project · .dsh",
|
|
2592
|
+
pickerSourceProjectAgents: "Current project · .agents",
|
|
2593
|
+
pickerSourceUserDsh: "Global · .dsh",
|
|
2594
|
+
pickerSourceUserAgents: "Global · .agents",
|
|
1827
2595
|
commandDescription: "Pick a skill: opens a popup list; selecting fills /<name>",
|
|
1828
2596
|
entryTitle: "Skill entry points",
|
|
1829
2597
|
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.",
|
|
@@ -1831,10 +2599,15 @@ window.__ModuleLoader__.load({
|
|
|
1831
2599
|
refresh: "Refresh",
|
|
1832
2600
|
installedEmpty: "No skills yet. Import one or drop files into a skill directory and they will appear automatically.",
|
|
1833
2601
|
delete: "Delete",
|
|
2602
|
+
deleting: "Deleting…",
|
|
2603
|
+
deleteTitle: "Delete skill",
|
|
1834
2604
|
deleteConfirm: "Delete the skill {name}? This removes its SKILL.md and resources from that directory.",
|
|
2605
|
+
cancel: "Cancel",
|
|
2606
|
+
close: "Close",
|
|
1835
2607
|
deleteFailed: "Failed to delete",
|
|
1836
2608
|
deleted: "Deleted.",
|
|
1837
2609
|
installedFailed: "Unable to read the skill list",
|
|
2610
|
+
installedPartial: "{count} skill directories are temporarily unreadable; other skills are still shown.",
|
|
1838
2611
|
userOnly: "Slash only",
|
|
1839
2612
|
modelOnly: "Model only",
|
|
1840
2613
|
importTitle: "Import a skill",
|
|
@@ -1877,6 +2650,7 @@ window.__ModuleLoader__.load({
|
|
|
1877
2650
|
batchConflict: "Name conflict",
|
|
1878
2651
|
batchReplace: "Replace",
|
|
1879
2652
|
batchConfirm: "Add {importing}, replace {replacing}, and skip {skipped} skills. Continue?",
|
|
2653
|
+
batchConfirmTitle: "Confirm batch import",
|
|
1880
2654
|
batchResultTitle: "Import results",
|
|
1881
2655
|
batchResultSummary: "Added {imported} · Replaced {replaced} · Skipped {skipped} · Failed {failed}",
|
|
1882
2656
|
batchStatusImported: "Imported",
|
|
@@ -1884,15 +2658,48 @@ window.__ModuleLoader__.load({
|
|
|
1884
2658
|
batchStatusSkipped: "Skipped",
|
|
1885
2659
|
batchStatusError: "Failed",
|
|
1886
2660
|
targetLabel: "Install into",
|
|
1887
|
-
|
|
1888
|
-
targetProjectAgents: "
|
|
2661
|
+
targetProjectDsh: "DSH project skills ({title})",
|
|
2662
|
+
targetProjectAgents: "Shared project skills ({title})",
|
|
2663
|
+
targetUserDsh: "DSH global skills",
|
|
2664
|
+
targetUserAgents: "Shared global skills",
|
|
2665
|
+
locationChange: "Change",
|
|
2666
|
+
locationTitle: "Choose install location",
|
|
2667
|
+
locationProject: "Project skills",
|
|
2668
|
+
locationGlobal: "Global skills",
|
|
2669
|
+
workspaceSearch: "Search workspaces…",
|
|
2670
|
+
workspaceNoMatch: "No matching workspaces",
|
|
2671
|
+
chooseRootHint: "Choose a skill directory",
|
|
2672
|
+
rootProjectDsh: "DSH project skills",
|
|
2673
|
+
rootProjectAgents: "Shared project skills",
|
|
2674
|
+
rootUserDsh: "DSH global skills",
|
|
2675
|
+
rootUserAgents: "Shared global skills",
|
|
2676
|
+
priorityHighest: "Highest",
|
|
2677
|
+
priorityHigher: "Higher",
|
|
2678
|
+
priorityLower: "Lower",
|
|
2679
|
+
priorityLowest: "Lowest",
|
|
2680
|
+
locationSummaryProjectDsh: "Project · {title} · .dsh/skills",
|
|
2681
|
+
locationSummaryProjectAgents: "Project · {title} · .agents/skills",
|
|
2682
|
+
locationSummaryUserDsh: "Global · ~/.dsh/skills",
|
|
2683
|
+
locationSummaryUserAgents: "Global · ~/.agents/skills",
|
|
1889
2684
|
targetProjectNoWorkspace: "Project skills (add a workspace first)",
|
|
1890
2685
|
noWorkspace: "No registered workspace: create/select one in a session, or use the user skill directory.",
|
|
1891
2686
|
import: "Import",
|
|
1892
2687
|
importing: "Importing…",
|
|
1893
2688
|
imported: "Written to: ",
|
|
1894
2689
|
importFailed: "Import failed",
|
|
1895
|
-
hostUnreachable: "Cannot reach the dsh service (plugin routes are not active). Make sure the plugin is installed, restart dsh web, and refresh the page."
|
|
2690
|
+
hostUnreachable: "Cannot reach the dsh service (plugin routes are not active). Make sure the plugin is installed, restart dsh web, and refresh the page.",
|
|
2691
|
+
versionChecking: "Checking for updates…",
|
|
2692
|
+
versionCurrent: "Current version v{version}",
|
|
2693
|
+
versionLatest: "Up to date",
|
|
2694
|
+
versionAvailable: "Version v{version} is available",
|
|
2695
|
+
versionCheckFailed: "Unable to check for updates",
|
|
2696
|
+
versionRetry: "Retry",
|
|
2697
|
+
versionUpdate: "Update",
|
|
2698
|
+
updateTitle: "Update dsh-skill-importer",
|
|
2699
|
+
updateDescription: "Copy this exact-version command, run it in a terminal, then restart dsh web.",
|
|
2700
|
+
copyCommand: "Copy update command",
|
|
2701
|
+
commandCopied: "Copied",
|
|
2702
|
+
restartHint: "Restart dsh web after the update for it to take effect."
|
|
1896
2703
|
};
|
|
1897
2704
|
//#endregion
|
|
1898
2705
|
//#region src/client/index.ts
|
|
@@ -1909,7 +2716,8 @@ window.__ModuleLoader__.load({
|
|
|
1909
2716
|
importUrl: "/skill-importer/import-url",
|
|
1910
2717
|
delete: "/skill-importer/delete",
|
|
1911
2718
|
batchScan: "/skill-importer/batch/scan",
|
|
1912
|
-
batchCommit: "/skill-importer/batch/commit"
|
|
2719
|
+
batchCommit: "/skill-importer/batch/commit",
|
|
2720
|
+
updateStatus: "/skill-importer/update-status"
|
|
1913
2721
|
};
|
|
1914
2722
|
/** Fetch one route and unwrap the JSON envelope; throws on transport/HTTP errors. */
|
|
1915
2723
|
async function call(path, body) {
|
|
@@ -1942,7 +2750,10 @@ window.__ModuleLoader__.load({
|
|
|
1942
2750
|
en
|
|
1943
2751
|
}), "dsh-skill-importer: dictionaries");
|
|
1944
2752
|
const t = ctx.locale.bind(NS);
|
|
2753
|
+
const sourceLabel = (source) => source === "project-dsh" ? t("pickerSourceProjectDsh") : source === "project-agents" ? t("pickerSourceProjectAgents") : source === "user-dsh" ? t("pickerSourceUserDsh") : t("pickerSourceUserAgents");
|
|
1945
2754
|
let catalog = [];
|
|
2755
|
+
let issues = [];
|
|
2756
|
+
const sessionCatalogs = /* @__PURE__ */ new Map();
|
|
1946
2757
|
const listeners = /* @__PURE__ */ new Set();
|
|
1947
2758
|
const notify = () => {
|
|
1948
2759
|
for (const listener of [...listeners]) try {
|
|
@@ -1957,7 +2768,7 @@ window.__ModuleLoader__.load({
|
|
|
1957
2768
|
skillsApi.list = ((_request, _signal) => {
|
|
1958
2769
|
return Promise.reject(/* @__PURE__ */ new Error("skill group hidden: use the composer skill picker or /skills"));
|
|
1959
2770
|
});
|
|
1960
|
-
const usableNames = () =>
|
|
2771
|
+
const usableNames = () => [...new Set([...sessionCatalogs.values()].flat().filter((skill) => skill.userInvocable).map((skill) => skill.name))];
|
|
1961
2772
|
ctx.effect(() => {
|
|
1962
2773
|
return ctx.get("inputTriggers").registerSource({
|
|
1963
2774
|
trigger: "/",
|
|
@@ -1989,10 +2800,10 @@ window.__ModuleLoader__.load({
|
|
|
1989
2800
|
available: () => true,
|
|
1990
2801
|
ui: {
|
|
1991
2802
|
kind: "popupSelect",
|
|
1992
|
-
async options(
|
|
1993
|
-
return
|
|
2803
|
+
async options(session, _signal) {
|
|
2804
|
+
return (await refreshSkillsForSession(session.sessionId)).filter((skill) => skill.userInvocable).map((skill) => ({
|
|
1994
2805
|
id: skill.name,
|
|
1995
|
-
label: skill.name
|
|
2806
|
+
label: `${skill.name} · ${sourceLabel(skill.source)}`
|
|
1996
2807
|
}));
|
|
1997
2808
|
},
|
|
1998
2809
|
onSelect(option, session) {
|
|
@@ -2000,16 +2811,32 @@ window.__ModuleLoader__.load({
|
|
|
2000
2811
|
if (actx === void 0) return;
|
|
2001
2812
|
const input = conversation.input.for(actx);
|
|
2002
2813
|
const rest = input.state.getSnapshot().draft.replace(/^\s*\/[a-zA-Z][a-zA-Z0-9-]*\s*/, "");
|
|
2003
|
-
|
|
2814
|
+
const prefix = `/${option.id} `;
|
|
2815
|
+
const nextDraft = `${prefix}${rest}`;
|
|
2816
|
+
input.setDraft(nextDraft);
|
|
2817
|
+
requestComposerFocus({
|
|
2818
|
+
sessionId: session.sessionId,
|
|
2819
|
+
expectedDraft: nextDraft,
|
|
2820
|
+
caret: prefix.length
|
|
2821
|
+
});
|
|
2004
2822
|
}
|
|
2005
2823
|
}
|
|
2006
2824
|
});
|
|
2007
2825
|
}, "dsh-skill-importer: /skills popupSelect command");
|
|
2008
|
-
const refreshSkills = async () => {
|
|
2009
|
-
|
|
2826
|
+
const refreshSkills = async (workspacePath) => {
|
|
2827
|
+
const result = await call(workspacePath === void 0 ? ROUTES.list : `${ROUTES.list}?workspacePath=${encodeURIComponent(workspacePath)}`);
|
|
2828
|
+
catalog = result.skills;
|
|
2829
|
+
issues = result.issues;
|
|
2010
2830
|
notify();
|
|
2011
2831
|
return catalog;
|
|
2012
2832
|
};
|
|
2833
|
+
const refreshSkillsForSession = async (sessionId) => {
|
|
2834
|
+
const cwd = sessions.list.getSnapshot().byId[sessionId]?.cwd;
|
|
2835
|
+
const effective = effectiveSkills((await call(cwd === void 0 ? `${ROUTES.list}?scope=global` : `${ROUTES.list}?workspacePath=${encodeURIComponent(cwd)}`)).skills);
|
|
2836
|
+
sessionCatalogs.set(sessionId, effective);
|
|
2837
|
+
notify();
|
|
2838
|
+
return effective;
|
|
2839
|
+
};
|
|
2013
2840
|
const importSkill = async (request) => {
|
|
2014
2841
|
return (await call(ROUTES.import, request)).path;
|
|
2015
2842
|
};
|
|
@@ -2026,24 +2853,38 @@ window.__ModuleLoader__.load({
|
|
|
2026
2853
|
};
|
|
2027
2854
|
const scanBatch = (request) => call(ROUTES.batchScan, request);
|
|
2028
2855
|
const commitBatch = (request) => call(ROUTES.batchCommit, request);
|
|
2856
|
+
const checkForUpdates = () => call(ROUTES.updateStatus);
|
|
2029
2857
|
const face = () => ({
|
|
2030
|
-
hooks: {
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2858
|
+
hooks: {
|
|
2859
|
+
skills: {
|
|
2860
|
+
getSnapshot: () => catalog,
|
|
2861
|
+
subscribe: (listener) => {
|
|
2862
|
+
listeners.add(listener);
|
|
2863
|
+
return () => {
|
|
2864
|
+
listeners.delete(listener);
|
|
2865
|
+
};
|
|
2866
|
+
}
|
|
2867
|
+
},
|
|
2868
|
+
skillIssues: {
|
|
2869
|
+
getSnapshot: () => issues,
|
|
2870
|
+
subscribe: (listener) => {
|
|
2871
|
+
listeners.add(listener);
|
|
2872
|
+
return () => {
|
|
2873
|
+
listeners.delete(listener);
|
|
2874
|
+
};
|
|
2875
|
+
}
|
|
2037
2876
|
}
|
|
2038
|
-
}
|
|
2877
|
+
},
|
|
2039
2878
|
actions: {
|
|
2040
2879
|
refreshSkills,
|
|
2880
|
+
refreshSkillsForSession,
|
|
2041
2881
|
importSkill,
|
|
2042
2882
|
importUrl,
|
|
2043
2883
|
deleteSkill,
|
|
2044
2884
|
pickDirectory,
|
|
2045
2885
|
scanBatch,
|
|
2046
|
-
commitBatch
|
|
2886
|
+
commitBatch,
|
|
2887
|
+
checkForUpdates
|
|
2047
2888
|
}
|
|
2048
2889
|
});
|
|
2049
2890
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|