dsh-skills-manager 0.1.5 → 0.1.7
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 +3 -2
- package/lib/client.js +328 -51
- package/lib/client.js.map +1 -1
- package/lib/index.js +144 -1
- package/lib/types/client/index.js +95 -17
- package/lib/types/index.d.ts +2 -1
- package/lib/types/index.js +146 -2
- package/lib/types/types.d.ts +8 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -33,8 +33,9 @@ After changing the bundle or installed dependencies, restart the Harness service
|
|
|
33
33
|
2. Choose **本机** to select a local skill folder, or **仓库** to enter a GitHub `owner/repo`, HTTPS URL, SSH URL, or other Git URL.
|
|
34
34
|
3. Enable **全局** or select a workspace and enable **项目**.
|
|
35
35
|
4. Use the refresh icon on a row to reinstall that skill from the source recorded in `skills-lock.json`.
|
|
36
|
-
5. Use
|
|
37
|
-
6.
|
|
36
|
+
5. Use **检测** to check every installed skill for upstream updates without applying them; rows show a badge (有更新 / 已是最新 / 上游已删除 / 无法检测). When updates are found, **全部更新 (N)** applies them one by one.
|
|
37
|
+
6. Use the wrench control beside the composer attachment button to toggle installed skills for the current session workspace only.
|
|
38
|
+
7. Remove an installed skill with **移除**. This deletes only the plugin's private library entry, not the local source or remote repository.
|
|
38
39
|
|
|
39
40
|
Repository imports and refreshes are delegated to the `skills` CLI. It supports GitHub `owner/repo`, HTTPS, SSH, Git and file URLs, and reuses the machine's existing Git credential helper or SSH configuration. Do not put credentials in repository URLs; the plugin rejects embedded credentials before invoking the CLI.
|
|
40
41
|
|
package/lib/client.js
CHANGED
|
@@ -135,26 +135,26 @@ const createLucideIcon = (iconName, iconNode) => {
|
|
|
135
135
|
|
|
136
136
|
//#endregion
|
|
137
137
|
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/wrench.mjs
|
|
138
|
-
const __iconNode$
|
|
138
|
+
const __iconNode$15 = [["path", {
|
|
139
139
|
d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z",
|
|
140
140
|
key: "1ngwbx"
|
|
141
141
|
}]];
|
|
142
|
-
const Wrench = createLucideIcon("wrench", __iconNode$
|
|
142
|
+
const Wrench = createLucideIcon("wrench", __iconNode$15);
|
|
143
143
|
|
|
144
144
|
//#endregion
|
|
145
145
|
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/plus.mjs
|
|
146
|
-
const __iconNode$
|
|
146
|
+
const __iconNode$14 = [["path", {
|
|
147
147
|
d: "M5 12h14",
|
|
148
148
|
key: "1ays0h"
|
|
149
149
|
}], ["path", {
|
|
150
150
|
d: "M12 5v14",
|
|
151
151
|
key: "s699le"
|
|
152
152
|
}]];
|
|
153
|
-
const Plus = createLucideIcon("plus", __iconNode$
|
|
153
|
+
const Plus = createLucideIcon("plus", __iconNode$14);
|
|
154
154
|
|
|
155
155
|
//#endregion
|
|
156
156
|
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/refresh-cw.mjs
|
|
157
|
-
const __iconNode$
|
|
157
|
+
const __iconNode$13 = [
|
|
158
158
|
["path", {
|
|
159
159
|
d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",
|
|
160
160
|
key: "v9h5vc"
|
|
@@ -172,11 +172,11 @@ const __iconNode$9 = [
|
|
|
172
172
|
key: "1cv678"
|
|
173
173
|
}]
|
|
174
174
|
];
|
|
175
|
-
const RefreshCw = createLucideIcon("refresh-cw", __iconNode$
|
|
175
|
+
const RefreshCw = createLucideIcon("refresh-cw", __iconNode$13);
|
|
176
176
|
|
|
177
177
|
//#endregion
|
|
178
178
|
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/search.mjs
|
|
179
|
-
const __iconNode$
|
|
179
|
+
const __iconNode$12 = [["path", {
|
|
180
180
|
d: "m21 21-4.34-4.34",
|
|
181
181
|
key: "14j7rj"
|
|
182
182
|
}], ["circle", {
|
|
@@ -185,22 +185,22 @@ const __iconNode$8 = [["path", {
|
|
|
185
185
|
r: "8",
|
|
186
186
|
key: "4ej97u"
|
|
187
187
|
}]];
|
|
188
|
-
const Search = createLucideIcon("search", __iconNode$
|
|
188
|
+
const Search = createLucideIcon("search", __iconNode$12);
|
|
189
189
|
|
|
190
190
|
//#endregion
|
|
191
191
|
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/x.mjs
|
|
192
|
-
const __iconNode$
|
|
192
|
+
const __iconNode$11 = [["path", {
|
|
193
193
|
d: "M18 6 6 18",
|
|
194
194
|
key: "1bl5f8"
|
|
195
195
|
}], ["path", {
|
|
196
196
|
d: "m6 6 12 12",
|
|
197
197
|
key: "d8bk6v"
|
|
198
198
|
}]];
|
|
199
|
-
const X = createLucideIcon("x", __iconNode$
|
|
199
|
+
const X = createLucideIcon("x", __iconNode$11);
|
|
200
200
|
|
|
201
201
|
//#endregion
|
|
202
202
|
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/trash-2.mjs
|
|
203
|
-
const __iconNode$
|
|
203
|
+
const __iconNode$10 = [
|
|
204
204
|
["path", {
|
|
205
205
|
d: "M10 11v6",
|
|
206
206
|
key: "nco0om"
|
|
@@ -222,11 +222,11 @@ const __iconNode$6 = [
|
|
|
222
222
|
key: "e791ji"
|
|
223
223
|
}]
|
|
224
224
|
];
|
|
225
|
-
const Trash2 = createLucideIcon("trash-2", __iconNode$
|
|
225
|
+
const Trash2 = createLucideIcon("trash-2", __iconNode$10);
|
|
226
226
|
|
|
227
227
|
//#endregion
|
|
228
228
|
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/globe.mjs
|
|
229
|
-
const __iconNode$
|
|
229
|
+
const __iconNode$9 = [
|
|
230
230
|
["circle", {
|
|
231
231
|
cx: "12",
|
|
232
232
|
cy: "12",
|
|
@@ -242,11 +242,11 @@ const __iconNode$5 = [
|
|
|
242
242
|
key: "9i4pu4"
|
|
243
243
|
}]
|
|
244
244
|
];
|
|
245
|
-
const Globe = createLucideIcon("globe", __iconNode$
|
|
245
|
+
const Globe = createLucideIcon("globe", __iconNode$9);
|
|
246
246
|
|
|
247
247
|
//#endregion
|
|
248
248
|
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/folder-git.mjs
|
|
249
|
-
const __iconNode$
|
|
249
|
+
const __iconNode$8 = [
|
|
250
250
|
["circle", {
|
|
251
251
|
cx: "12",
|
|
252
252
|
cy: "13",
|
|
@@ -266,11 +266,11 @@ const __iconNode$4 = [
|
|
|
266
266
|
key: "1pygq7"
|
|
267
267
|
}]
|
|
268
268
|
];
|
|
269
|
-
const FolderGit = createLucideIcon("folder-git", __iconNode$
|
|
269
|
+
const FolderGit = createLucideIcon("folder-git", __iconNode$8);
|
|
270
270
|
|
|
271
271
|
//#endregion
|
|
272
272
|
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/git-branch.mjs
|
|
273
|
-
const __iconNode$
|
|
273
|
+
const __iconNode$7 = [
|
|
274
274
|
["path", {
|
|
275
275
|
d: "M15 6a9 9 0 0 0-9 9V3",
|
|
276
276
|
key: "1cii5b"
|
|
@@ -288,11 +288,11 @@ const __iconNode$3 = [
|
|
|
288
288
|
key: "fqmcym"
|
|
289
289
|
}]
|
|
290
290
|
];
|
|
291
|
-
const GitBranch = createLucideIcon("git-branch", __iconNode$
|
|
291
|
+
const GitBranch = createLucideIcon("git-branch", __iconNode$7);
|
|
292
292
|
|
|
293
293
|
//#endregion
|
|
294
294
|
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/package-open.mjs
|
|
295
|
-
const __iconNode$
|
|
295
|
+
const __iconNode$6 = [
|
|
296
296
|
["path", {
|
|
297
297
|
d: "M12 22v-9",
|
|
298
298
|
key: "x3hkom"
|
|
@@ -310,19 +310,19 @@ const __iconNode$2 = [
|
|
|
310
310
|
key: "12ttoo"
|
|
311
311
|
}]
|
|
312
312
|
];
|
|
313
|
-
const PackageOpen = createLucideIcon("package-open", __iconNode$
|
|
313
|
+
const PackageOpen = createLucideIcon("package-open", __iconNode$6);
|
|
314
314
|
|
|
315
315
|
//#endregion
|
|
316
316
|
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/puzzle.mjs
|
|
317
|
-
const __iconNode$
|
|
317
|
+
const __iconNode$5 = [["path", {
|
|
318
318
|
d: "M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z",
|
|
319
319
|
key: "w46dr5"
|
|
320
320
|
}]];
|
|
321
|
-
const Puzzle = createLucideIcon("puzzle", __iconNode$
|
|
321
|
+
const Puzzle = createLucideIcon("puzzle", __iconNode$5);
|
|
322
322
|
|
|
323
323
|
//#endregion
|
|
324
324
|
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/circle-alert.mjs
|
|
325
|
-
const __iconNode = [
|
|
325
|
+
const __iconNode$4 = [
|
|
326
326
|
["circle", {
|
|
327
327
|
cx: "12",
|
|
328
328
|
cy: "12",
|
|
@@ -344,7 +344,61 @@ const __iconNode = [
|
|
|
344
344
|
key: "4dfq90"
|
|
345
345
|
}]
|
|
346
346
|
];
|
|
347
|
-
const CircleAlert = createLucideIcon("circle-alert", __iconNode);
|
|
347
|
+
const CircleAlert = createLucideIcon("circle-alert", __iconNode$4);
|
|
348
|
+
|
|
349
|
+
//#endregion
|
|
350
|
+
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/list.mjs
|
|
351
|
+
const __iconNode$3 = [
|
|
352
|
+
["path", {
|
|
353
|
+
d: "M3 5h.01",
|
|
354
|
+
key: "18ugdj"
|
|
355
|
+
}],
|
|
356
|
+
["path", {
|
|
357
|
+
d: "M3 12h.01",
|
|
358
|
+
key: "nlz23k"
|
|
359
|
+
}],
|
|
360
|
+
["path", {
|
|
361
|
+
d: "M3 19h.01",
|
|
362
|
+
key: "noohij"
|
|
363
|
+
}],
|
|
364
|
+
["path", {
|
|
365
|
+
d: "M8 5h13",
|
|
366
|
+
key: "1pao27"
|
|
367
|
+
}],
|
|
368
|
+
["path", {
|
|
369
|
+
d: "M8 12h13",
|
|
370
|
+
key: "1za7za"
|
|
371
|
+
}],
|
|
372
|
+
["path", {
|
|
373
|
+
d: "M8 19h13",
|
|
374
|
+
key: "m83p4d"
|
|
375
|
+
}]
|
|
376
|
+
];
|
|
377
|
+
const List = createLucideIcon("list", __iconNode$3);
|
|
378
|
+
|
|
379
|
+
//#endregion
|
|
380
|
+
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/folder.mjs
|
|
381
|
+
const __iconNode$2 = [["path", {
|
|
382
|
+
d: "M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z",
|
|
383
|
+
key: "1kt360"
|
|
384
|
+
}]];
|
|
385
|
+
const Folder = createLucideIcon("folder", __iconNode$2);
|
|
386
|
+
|
|
387
|
+
//#endregion
|
|
388
|
+
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/chevron-down.mjs
|
|
389
|
+
const __iconNode$1 = [["path", {
|
|
390
|
+
d: "m6 9 6 6 6-6",
|
|
391
|
+
key: "qrunsl"
|
|
392
|
+
}]];
|
|
393
|
+
const ChevronDown = createLucideIcon("chevron-down", __iconNode$1);
|
|
394
|
+
|
|
395
|
+
//#endregion
|
|
396
|
+
//#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/chevron-right.mjs
|
|
397
|
+
const __iconNode = [["path", {
|
|
398
|
+
d: "m9 18 6-6-6-6",
|
|
399
|
+
key: "mthhwq"
|
|
400
|
+
}]];
|
|
401
|
+
const ChevronRight = createLucideIcon("chevron-right", __iconNode);
|
|
348
402
|
|
|
349
403
|
//#endregion
|
|
350
404
|
//#region lib/types/client/popover.js
|
|
@@ -489,6 +543,11 @@ function apply(ctx) {
|
|
|
489
543
|
};
|
|
490
544
|
const list = (projectRoot) => request("list", projectRoot ? { projectRoot } : {});
|
|
491
545
|
const mutate = request;
|
|
546
|
+
const checkUpdates = async () => {
|
|
547
|
+
const result = await connection.rpc.call("/skill-manager", "check-updates", {});
|
|
548
|
+
if (!result.ok) throw new Error(result.error.message);
|
|
549
|
+
return result.value;
|
|
550
|
+
};
|
|
492
551
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
493
552
|
name: "settings.section",
|
|
494
553
|
id: "skills",
|
|
@@ -497,6 +556,7 @@ function apply(ctx) {
|
|
|
497
556
|
inject: () => ({
|
|
498
557
|
list,
|
|
499
558
|
mutate,
|
|
559
|
+
checkUpdates,
|
|
500
560
|
pickDirectory: () => ctx.workspaces.pickDirectory(),
|
|
501
561
|
loopback: connection.isLoopback
|
|
502
562
|
})
|
|
@@ -512,15 +572,19 @@ function apply(ctx) {
|
|
|
512
572
|
}, ComposerSkillButton));
|
|
513
573
|
}
|
|
514
574
|
function SkillManagerSection(props) {
|
|
515
|
-
const { list, mutate, pickDirectory, loopback, useWorkspaces } = props;
|
|
575
|
+
const { list, mutate, checkUpdates, pickDirectory, loopback, useWorkspaces } = props;
|
|
516
576
|
const workspaces = useWorkspaces((state) => state);
|
|
517
577
|
const [projectRoot, setProjectRoot] = (0, react.useState)(void 0);
|
|
518
578
|
const [catalog, setCatalog] = (0, react.useState)(null);
|
|
519
579
|
const [query, setQuery] = (0, react.useState)("");
|
|
520
580
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
581
|
+
const [checking, setChecking] = (0, react.useState)(false);
|
|
582
|
+
const [statuses, setStatuses] = (0, react.useState)({});
|
|
521
583
|
const [error, setError] = (0, react.useState)(null);
|
|
522
584
|
const [repositoryOpen, setRepositoryOpen] = (0, react.useState)(false);
|
|
523
585
|
const [repository, setRepository] = (0, react.useState)("");
|
|
586
|
+
const [view, setView] = (0, react.useState)("flat");
|
|
587
|
+
const [collapsed, setCollapsed] = (0, react.useState)({});
|
|
524
588
|
(0, react.useEffect)(() => {
|
|
525
589
|
ensureKeyframes();
|
|
526
590
|
}, []);
|
|
@@ -558,6 +622,7 @@ function SkillManagerSection(props) {
|
|
|
558
622
|
}, []);
|
|
559
623
|
const normalizedQuery = query.trim().toLocaleLowerCase();
|
|
560
624
|
const filtered = (catalog?.entries ?? []).filter((entry) => normalizedQuery.length === 0 || `${entry.name} ${entry.description}`.toLocaleLowerCase().includes(normalizedQuery));
|
|
625
|
+
const groups = groupBySource(filtered);
|
|
561
626
|
const importSkill = async () => {
|
|
562
627
|
const path = await pickDirectory();
|
|
563
628
|
if (path) await run(() => mutate("install", {
|
|
@@ -586,7 +651,60 @@ function SkillManagerSection(props) {
|
|
|
586
651
|
projectRoot
|
|
587
652
|
}));
|
|
588
653
|
};
|
|
654
|
+
const checkAll = async () => {
|
|
655
|
+
setChecking(true);
|
|
656
|
+
setError(null);
|
|
657
|
+
try {
|
|
658
|
+
const report = await checkUpdates();
|
|
659
|
+
setStatuses(Object.fromEntries(report.entries.map((entry) => [entry.name, entry.status])));
|
|
660
|
+
} catch (reason) {
|
|
661
|
+
setError(messageOf(reason));
|
|
662
|
+
} finally {
|
|
663
|
+
setChecking(false);
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
const updatable = (catalog?.entries ?? []).filter((entry) => statuses[entry.name] === "update-available" && entry.updateSupported);
|
|
667
|
+
const updateAll = async () => {
|
|
668
|
+
setBusy(true);
|
|
669
|
+
setError(null);
|
|
670
|
+
try {
|
|
671
|
+
for (const entry of updatable) setCatalog(await mutate("update", {
|
|
672
|
+
name: entry.name,
|
|
673
|
+
projectRoot
|
|
674
|
+
}));
|
|
675
|
+
setStatuses({});
|
|
676
|
+
} catch (reason) {
|
|
677
|
+
setError(messageOf(reason));
|
|
678
|
+
} finally {
|
|
679
|
+
setBusy(false);
|
|
680
|
+
}
|
|
681
|
+
};
|
|
589
682
|
const selectedWorkspace = workspaces.items.find((item) => item.path === projectRoot);
|
|
683
|
+
const rowProps = (entry) => ({
|
|
684
|
+
key: entry.name,
|
|
685
|
+
entry,
|
|
686
|
+
projectLabel: selectedWorkspace?.title ?? "当前项目",
|
|
687
|
+
projectAvailable: projectRoot !== void 0,
|
|
688
|
+
busy,
|
|
689
|
+
updateStatus: statuses[entry.name],
|
|
690
|
+
onGlobalChange: (enabled) => void run(() => mutate("set-enabled", {
|
|
691
|
+
name: entry.name,
|
|
692
|
+
scope: "global",
|
|
693
|
+
projectRoot,
|
|
694
|
+
enabled
|
|
695
|
+
})),
|
|
696
|
+
onProjectChange: (enabled) => void run(() => mutate("set-enabled", {
|
|
697
|
+
name: entry.name,
|
|
698
|
+
scope: "project",
|
|
699
|
+
projectRoot,
|
|
700
|
+
enabled
|
|
701
|
+
})),
|
|
702
|
+
onUpdate: () => void updateSkill(entry),
|
|
703
|
+
onRemove: () => void run(() => mutate("remove", {
|
|
704
|
+
name: entry.name,
|
|
705
|
+
projectRoot
|
|
706
|
+
}))
|
|
707
|
+
});
|
|
590
708
|
return (0, react.createElement)("div", {
|
|
591
709
|
style: panelStyle,
|
|
592
710
|
"aria-busy": busy
|
|
@@ -617,6 +735,25 @@ function SkillManagerSection(props) {
|
|
|
617
735
|
gap: 8,
|
|
618
736
|
flexWrap: "wrap"
|
|
619
737
|
} }, (0, react.createElement)("button", {
|
|
738
|
+
type: "button",
|
|
739
|
+
style: buttonStyle("ghost", busy || checking),
|
|
740
|
+
onClick: () => void checkAll(),
|
|
741
|
+
disabled: busy || checking,
|
|
742
|
+
title: "检测全部 skill 是否有更新(只检测,不更新)"
|
|
743
|
+
}, (0, react.createElement)(RefreshCw, {
|
|
744
|
+
size: 14,
|
|
745
|
+
"aria-hidden": true,
|
|
746
|
+
style: checking ? spinnerStyle : void 0
|
|
747
|
+
}), checking ? "检测中…" : "检测"), updatable.length > 0 ? (0, react.createElement)("button", {
|
|
748
|
+
type: "button",
|
|
749
|
+
style: buttonStyle("primary", busy || checking || !loopback),
|
|
750
|
+
onClick: () => void updateAll(),
|
|
751
|
+
disabled: busy || checking || !loopback,
|
|
752
|
+
title: loopback ? `更新全部 ${updatable.length} 个有更新的 skill` : "仅在本机连接时可更新"
|
|
753
|
+
}, (0, react.createElement)(RefreshCw, {
|
|
754
|
+
size: 14,
|
|
755
|
+
"aria-hidden": true
|
|
756
|
+
}), `全部更新 (${updatable.length})`) : null, (0, react.createElement)("button", {
|
|
620
757
|
type: "button",
|
|
621
758
|
style: buttonStyle("ghost", busy || !loopback),
|
|
622
759
|
onClick: () => setRepositoryOpen((value) => !value),
|
|
@@ -733,7 +870,49 @@ function SkillManagerSection(props) {
|
|
|
733
870
|
}, (0, react.createElement)("option", { value: "__global__" }, "只看全局"), ...workspaces.items.map((workspace) => (0, react.createElement)("option", {
|
|
734
871
|
key: workspace.workspaceId,
|
|
735
872
|
value: workspace.path
|
|
736
|
-
}, workspace.title))))
|
|
873
|
+
}, workspace.title)))), (0, react.createElement)("div", {
|
|
874
|
+
role: "group",
|
|
875
|
+
"aria-label": "视图切换",
|
|
876
|
+
style: {
|
|
877
|
+
display: "flex",
|
|
878
|
+
flex: "0 0 auto",
|
|
879
|
+
border: `1px solid ${tokens.border}`,
|
|
880
|
+
borderRadius: 8,
|
|
881
|
+
overflow: "hidden"
|
|
882
|
+
}
|
|
883
|
+
}, (0, react.createElement)("button", {
|
|
884
|
+
type: "button",
|
|
885
|
+
onClick: () => setView("flat"),
|
|
886
|
+
"aria-pressed": view === "flat",
|
|
887
|
+
title: "平铺列表",
|
|
888
|
+
style: {
|
|
889
|
+
...iconButtonStyle,
|
|
890
|
+
width: 32,
|
|
891
|
+
height: 32,
|
|
892
|
+
borderRadius: 0,
|
|
893
|
+
color: view === "flat" ? tokens.accent : tokens.secondary,
|
|
894
|
+
background: view === "flat" ? "rgba(99, 102, 241, .12)" : "transparent"
|
|
895
|
+
}
|
|
896
|
+
}, (0, react.createElement)(List, {
|
|
897
|
+
size: 15,
|
|
898
|
+
"aria-hidden": true
|
|
899
|
+
})), (0, react.createElement)("button", {
|
|
900
|
+
type: "button",
|
|
901
|
+
onClick: () => setView("grouped"),
|
|
902
|
+
"aria-pressed": view === "grouped",
|
|
903
|
+
title: "按来源仓库分组",
|
|
904
|
+
style: {
|
|
905
|
+
...iconButtonStyle,
|
|
906
|
+
width: 32,
|
|
907
|
+
height: 32,
|
|
908
|
+
borderRadius: 0,
|
|
909
|
+
color: view === "grouped" ? tokens.accent : tokens.secondary,
|
|
910
|
+
background: view === "grouped" ? "rgba(99, 102, 241, .12)" : "transparent"
|
|
911
|
+
}
|
|
912
|
+
}, (0, react.createElement)(Folder, {
|
|
913
|
+
size: 15,
|
|
914
|
+
"aria-hidden": true
|
|
915
|
+
})))), error ? (0, react.createElement)("div", {
|
|
737
916
|
role: "alert",
|
|
738
917
|
style: {
|
|
739
918
|
display: "flex",
|
|
@@ -764,30 +943,89 @@ function SkillManagerSection(props) {
|
|
|
764
943
|
textAlign: "center",
|
|
765
944
|
fontSize: 13,
|
|
766
945
|
color: tokens.secondary
|
|
767
|
-
} }, "正在读取…") : filtered.length === 0 ? (0, react.createElement)(EmptyState, { hasAny: (catalog.entries.length ?? 0) > 0 }) : filtered.map((entry) => (0, react.createElement)(SkillRow, {
|
|
768
|
-
key:
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
})),
|
|
779
|
-
onProjectChange: (enabled) => void run(() => mutate("set-enabled", {
|
|
780
|
-
name: entry.name,
|
|
781
|
-
scope: "project",
|
|
782
|
-
projectRoot,
|
|
783
|
-
enabled
|
|
946
|
+
} }, "正在读取…") : filtered.length === 0 ? (0, react.createElement)(EmptyState, { hasAny: (catalog.entries.length ?? 0) > 0 }) : view === "flat" ? filtered.map((entry) => (0, react.createElement)(SkillRow, rowProps(entry))) : groups.map((group) => (0, react.createElement)("div", {
|
|
947
|
+
key: group.key,
|
|
948
|
+
style: {
|
|
949
|
+
display: "grid",
|
|
950
|
+
gap: 8
|
|
951
|
+
}
|
|
952
|
+
}, (0, react.createElement)("button", {
|
|
953
|
+
type: "button",
|
|
954
|
+
onClick: () => setCollapsed((prev) => ({
|
|
955
|
+
...prev,
|
|
956
|
+
[group.key]: !prev[group.key]
|
|
784
957
|
})),
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
958
|
+
"aria-expanded": !collapsed[group.key],
|
|
959
|
+
style: {
|
|
960
|
+
display: "flex",
|
|
961
|
+
alignItems: "center",
|
|
962
|
+
gap: 8,
|
|
963
|
+
padding: "6px 4px",
|
|
964
|
+
border: "none",
|
|
965
|
+
background: "transparent",
|
|
966
|
+
color: "inherit",
|
|
967
|
+
cursor: "pointer",
|
|
968
|
+
fontSize: 13,
|
|
969
|
+
fontWeight: 600,
|
|
970
|
+
textAlign: "left"
|
|
971
|
+
}
|
|
972
|
+
}, collapsed[group.key] ? (0, react.createElement)(ChevronRight, {
|
|
973
|
+
size: 14,
|
|
974
|
+
"aria-hidden": true,
|
|
975
|
+
style: {
|
|
976
|
+
color: tokens.secondary,
|
|
977
|
+
flex: "0 0 auto"
|
|
978
|
+
}
|
|
979
|
+
}) : (0, react.createElement)(ChevronDown, {
|
|
980
|
+
size: 14,
|
|
981
|
+
"aria-hidden": true,
|
|
982
|
+
style: {
|
|
983
|
+
color: tokens.secondary,
|
|
984
|
+
flex: "0 0 auto"
|
|
985
|
+
}
|
|
986
|
+
}), (0, react.createElement)(GitBranch, {
|
|
987
|
+
size: 13,
|
|
988
|
+
"aria-hidden": true,
|
|
989
|
+
style: {
|
|
990
|
+
color: tokens.secondary,
|
|
991
|
+
flex: "0 0 auto"
|
|
992
|
+
}
|
|
993
|
+
}), (0, react.createElement)("span", {
|
|
994
|
+
title: group.key === "__local__" ? void 0 : group.key,
|
|
995
|
+
style: {
|
|
996
|
+
...monoStyle,
|
|
997
|
+
minWidth: 0,
|
|
998
|
+
overflow: "hidden",
|
|
999
|
+
textOverflow: "ellipsis",
|
|
1000
|
+
whiteSpace: "nowrap"
|
|
1001
|
+
}
|
|
1002
|
+
}, group.label), (0, react.createElement)("span", { style: {
|
|
1003
|
+
color: tokens.secondary,
|
|
1004
|
+
fontWeight: 400,
|
|
1005
|
+
flex: "0 0 auto"
|
|
1006
|
+
} }, `${group.entries.length} 个`)), collapsed[group.key] ? null : group.entries.map((entry) => (0, react.createElement)(SkillRow, rowProps(entry)))))));
|
|
1007
|
+
}
|
|
1008
|
+
function groupBySource(entries) {
|
|
1009
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1010
|
+
for (const entry of entries) {
|
|
1011
|
+
const key = entry.sourceType === "git" && entry.sourceUrl ? entry.sourceUrl : "__local__";
|
|
1012
|
+
const label = key === "__local__" ? "本机导入" : shortRepoLabel(key);
|
|
1013
|
+
const group = groups.get(key) ?? {
|
|
1014
|
+
label,
|
|
1015
|
+
entries: []
|
|
1016
|
+
};
|
|
1017
|
+
group.entries.push(entry);
|
|
1018
|
+
groups.set(key, group);
|
|
1019
|
+
}
|
|
1020
|
+
return [...groups.entries()].map(([key, group]) => ({
|
|
1021
|
+
key,
|
|
1022
|
+
label: group.label,
|
|
1023
|
+
entries: group.entries
|
|
1024
|
+
})).sort((a, b) => a.key === "__local__" ? 1 : b.key === "__local__" ? -1 : a.label.localeCompare(b.label));
|
|
1025
|
+
}
|
|
1026
|
+
function shortRepoLabel(url) {
|
|
1027
|
+
const match = /^(?:https?:\/\/|git@|ssh:\/\/git@)?([^/:]+)[:/]([^/]+\/[^/]+?)(?:\.git)?\/?$/.exec(url);
|
|
1028
|
+
return match ? `${match[2]} (${match[1]})` : url;
|
|
791
1029
|
}
|
|
792
1030
|
function EmptyState(props) {
|
|
793
1031
|
return (0, react.createElement)("div", { style: {
|
|
@@ -1043,8 +1281,35 @@ function ProjectSkillPopover(props) {
|
|
|
1043
1281
|
style: spinnerStyle
|
|
1044
1282
|
})) : null);
|
|
1045
1283
|
}
|
|
1284
|
+
const UPDATE_BADGE = {
|
|
1285
|
+
"update-available": {
|
|
1286
|
+
label: "有更新",
|
|
1287
|
+
color: tokens.accent,
|
|
1288
|
+
background: "rgba(99, 102, 241, .1)",
|
|
1289
|
+
border: "1px solid rgba(99, 102, 241, .35)"
|
|
1290
|
+
},
|
|
1291
|
+
"current": {
|
|
1292
|
+
label: "已是最新",
|
|
1293
|
+
color: tokens.success,
|
|
1294
|
+
background: "rgba(22, 163, 74, .1)",
|
|
1295
|
+
border: "1px solid rgba(22, 163, 74, .3)"
|
|
1296
|
+
},
|
|
1297
|
+
"deleted-upstream": {
|
|
1298
|
+
label: "上游已删除",
|
|
1299
|
+
color: tokens.danger,
|
|
1300
|
+
background: "rgba(220, 38, 38, .08)",
|
|
1301
|
+
border: "1px solid rgba(220, 38, 38, .3)"
|
|
1302
|
+
},
|
|
1303
|
+
"unknown": {
|
|
1304
|
+
label: "无法检测",
|
|
1305
|
+
color: tokens.secondary,
|
|
1306
|
+
background: "rgba(148, 163, 184, .09)",
|
|
1307
|
+
border: "1px solid transparent"
|
|
1308
|
+
}
|
|
1309
|
+
};
|
|
1046
1310
|
function SkillRow(props) {
|
|
1047
|
-
const { entry, projectLabel, projectAvailable, busy, onGlobalChange, onProjectChange, onUpdate, onRemove } = props;
|
|
1311
|
+
const { entry, projectLabel, projectAvailable, busy, updateStatus, onGlobalChange, onProjectChange, onUpdate, onRemove } = props;
|
|
1312
|
+
const badge = updateStatus ? UPDATE_BADGE[updateStatus] : void 0;
|
|
1048
1313
|
return (0, react.createElement)("article", {
|
|
1049
1314
|
className: "dsh-skill-manager-row",
|
|
1050
1315
|
style: {
|
|
@@ -1094,7 +1359,19 @@ function SkillRow(props) {
|
|
|
1094
1359
|
overflow: "hidden",
|
|
1095
1360
|
textOverflow: "ellipsis",
|
|
1096
1361
|
whiteSpace: "nowrap"
|
|
1097
|
-
} }, entry.name), (0, react.createElement)(
|
|
1362
|
+
} }, entry.name), badge ? (0, react.createElement)("span", { style: {
|
|
1363
|
+
display: "inline-flex",
|
|
1364
|
+
alignItems: "center",
|
|
1365
|
+
flex: "0 1 auto",
|
|
1366
|
+
padding: "2px 6px",
|
|
1367
|
+
borderRadius: 999,
|
|
1368
|
+
fontSize: 11,
|
|
1369
|
+
lineHeight: "16px",
|
|
1370
|
+
whiteSpace: "nowrap",
|
|
1371
|
+
color: badge.color,
|
|
1372
|
+
background: badge.background,
|
|
1373
|
+
border: badge.border
|
|
1374
|
+
} }, badge.label) : null, (0, react.createElement)(SourceBadge, { entry }), (0, react.createElement)(StatusBadge, {
|
|
1098
1375
|
active: entry.globalEnabled,
|
|
1099
1376
|
icon: Globe,
|
|
1100
1377
|
label: "全局"
|