dsh-skills-manager 0.1.0

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/lib/client.js ADDED
@@ -0,0 +1,1317 @@
1
+ window.__ModuleLoader__.load({ id: "dsh-skills-manager", factory: (require) => {
2
+ var module = { exports: {} }; var exports = module.exports;
3
+ //#region rolldown:runtime
4
+ var __create = Object.create;
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getProtoOf = Object.getPrototypeOf;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
21
+ value: mod,
22
+ enumerable: true
23
+ }) : target, mod));
24
+
25
+ //#endregion
26
+ let react = require("react");
27
+ react = __toESM(react);
28
+
29
+ //#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.mjs
30
+ /**
31
+ * @license lucide-react v1.31.0 - ISC
32
+ *
33
+ * This source code is licensed under the ISC license.
34
+ * See the LICENSE file in the root directory of this source tree.
35
+ */
36
+ const mergeClasses = (...classes) => classes.filter((className, index, array) => {
37
+ return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
38
+ }).join(" ").trim();
39
+
40
+ //#endregion
41
+ //#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toKebabCase.mjs
42
+ /**
43
+ * @license lucide-react v1.31.0 - ISC
44
+ *
45
+ * This source code is licensed under the ISC license.
46
+ * See the LICENSE file in the root directory of this source tree.
47
+ */
48
+ const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
49
+
50
+ //#endregion
51
+ //#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toCamelCase.mjs
52
+ /**
53
+ * @license lucide-react v1.31.0 - ISC
54
+ *
55
+ * This source code is licensed under the ISC license.
56
+ * See the LICENSE file in the root directory of this source tree.
57
+ */
58
+ const toCamelCase = (string) => string.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase());
59
+
60
+ //#endregion
61
+ //#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toPascalCase.mjs
62
+ const toPascalCase = (string) => {
63
+ const camelCase = toCamelCase(string);
64
+ return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
65
+ };
66
+
67
+ //#endregion
68
+ //#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/defaultAttributes.mjs
69
+ /**
70
+ * @license lucide-react v1.31.0 - ISC
71
+ *
72
+ * This source code is licensed under the ISC license.
73
+ * See the LICENSE file in the root directory of this source tree.
74
+ */
75
+ var defaultAttributes = {
76
+ xmlns: "http://www.w3.org/2000/svg",
77
+ width: 24,
78
+ height: 24,
79
+ viewBox: "0 0 24 24",
80
+ fill: "none",
81
+ stroke: "currentColor",
82
+ strokeWidth: 2,
83
+ strokeLinecap: "round",
84
+ strokeLinejoin: "round"
85
+ };
86
+
87
+ //#endregion
88
+ //#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/hasA11yProp.mjs
89
+ /**
90
+ * @license lucide-react v1.31.0 - ISC
91
+ *
92
+ * This source code is licensed under the ISC license.
93
+ * See the LICENSE file in the root directory of this source tree.
94
+ */
95
+ const hasA11yProp = (props) => {
96
+ for (const prop in props) if (prop.startsWith("aria-") || prop === "role" || prop === "title") return true;
97
+ return false;
98
+ };
99
+
100
+ //#endregion
101
+ //#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/context.mjs
102
+ const LucideContext = (0, react.createContext)({});
103
+ const useLucideContext = () => (0, react.useContext)(LucideContext);
104
+
105
+ //#endregion
106
+ //#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/Icon.mjs
107
+ const Icon = (0, react.forwardRef)(({ color, size, strokeWidth, absoluteStrokeWidth, className = "", children, iconNode,...rest }, ref) => {
108
+ const { size: contextSize = 24, strokeWidth: contextStrokeWidth = 2, absoluteStrokeWidth: contextAbsoluteStrokeWidth = false, color: contextColor = "currentColor", className: contextClass = "" } = useLucideContext() ?? {};
109
+ const calculatedStrokeWidth = absoluteStrokeWidth ?? contextAbsoluteStrokeWidth ? Number(strokeWidth ?? contextStrokeWidth) * 24 / Number(size ?? contextSize) : strokeWidth ?? contextStrokeWidth;
110
+ return (0, react.createElement)("svg", {
111
+ ref,
112
+ ...defaultAttributes,
113
+ width: size ?? contextSize ?? defaultAttributes.width,
114
+ height: size ?? contextSize ?? defaultAttributes.height,
115
+ stroke: color ?? contextColor,
116
+ strokeWidth: calculatedStrokeWidth,
117
+ className: mergeClasses("lucide", contextClass, className),
118
+ ...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
119
+ ...rest
120
+ }, [...iconNode.map(([tag, attrs]) => (0, react.createElement)(tag, attrs)), ...Array.isArray(children) ? children : [children]]);
121
+ });
122
+
123
+ //#endregion
124
+ //#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/createLucideIcon.mjs
125
+ const createLucideIcon = (iconName, iconNode) => {
126
+ const Component = (0, react.forwardRef)(({ className,...props }, ref) => (0, react.createElement)(Icon, {
127
+ ref,
128
+ iconNode,
129
+ className: mergeClasses(`lucide-${toKebabCase(toPascalCase(iconName))}`, `lucide-${iconName}`, className),
130
+ ...props
131
+ }));
132
+ Component.displayName = toPascalCase(iconName);
133
+ return Component;
134
+ };
135
+
136
+ //#endregion
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$12 = [["path", {
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
+ key: "1ngwbx"
141
+ }]];
142
+ const Wrench = createLucideIcon("wrench", __iconNode$12);
143
+
144
+ //#endregion
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$11 = [["path", {
147
+ d: "M5 12h14",
148
+ key: "1ays0h"
149
+ }], ["path", {
150
+ d: "M12 5v14",
151
+ key: "s699le"
152
+ }]];
153
+ const Plus = createLucideIcon("plus", __iconNode$11);
154
+
155
+ //#endregion
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$10 = [
158
+ ["path", {
159
+ d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",
160
+ key: "v9h5vc"
161
+ }],
162
+ ["path", {
163
+ d: "M21 3v5h-5",
164
+ key: "1q7to0"
165
+ }],
166
+ ["path", {
167
+ d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",
168
+ key: "3uifl3"
169
+ }],
170
+ ["path", {
171
+ d: "M8 16H3v5",
172
+ key: "1cv678"
173
+ }]
174
+ ];
175
+ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$10);
176
+
177
+ //#endregion
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$9 = [["path", {
180
+ d: "m21 21-4.34-4.34",
181
+ key: "14j7rj"
182
+ }], ["circle", {
183
+ cx: "11",
184
+ cy: "11",
185
+ r: "8",
186
+ key: "4ej97u"
187
+ }]];
188
+ const Search = createLucideIcon("search", __iconNode$9);
189
+
190
+ //#endregion
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$8 = [["path", {
193
+ d: "M18 6 6 18",
194
+ key: "1bl5f8"
195
+ }], ["path", {
196
+ d: "m6 6 12 12",
197
+ key: "d8bk6v"
198
+ }]];
199
+ const X = createLucideIcon("x", __iconNode$8);
200
+
201
+ //#endregion
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$7 = [
204
+ ["path", {
205
+ d: "M10 11v6",
206
+ key: "nco0om"
207
+ }],
208
+ ["path", {
209
+ d: "M14 11v6",
210
+ key: "outv1u"
211
+ }],
212
+ ["path", {
213
+ d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",
214
+ key: "miytrc"
215
+ }],
216
+ ["path", {
217
+ d: "M3 6h18",
218
+ key: "d0wm0j"
219
+ }],
220
+ ["path", {
221
+ d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",
222
+ key: "e791ji"
223
+ }]
224
+ ];
225
+ const Trash2 = createLucideIcon("trash-2", __iconNode$7);
226
+
227
+ //#endregion
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$6 = [
230
+ ["circle", {
231
+ cx: "12",
232
+ cy: "12",
233
+ r: "10",
234
+ key: "1mglay"
235
+ }],
236
+ ["path", {
237
+ d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",
238
+ key: "13o1zl"
239
+ }],
240
+ ["path", {
241
+ d: "M2 12h20",
242
+ key: "9i4pu4"
243
+ }]
244
+ ];
245
+ const Globe = createLucideIcon("globe", __iconNode$6);
246
+
247
+ //#endregion
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$5 = [
250
+ ["circle", {
251
+ cx: "12",
252
+ cy: "13",
253
+ r: "2",
254
+ key: "1c1ljs"
255
+ }],
256
+ ["path", {
257
+ 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",
258
+ key: "1kt360"
259
+ }],
260
+ ["path", {
261
+ d: "M14 13h3",
262
+ key: "1dgedf"
263
+ }],
264
+ ["path", {
265
+ d: "M7 13h3",
266
+ key: "1pygq7"
267
+ }]
268
+ ];
269
+ const FolderGit = createLucideIcon("folder-git", __iconNode$5);
270
+
271
+ //#endregion
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$4 = [
274
+ ["path", {
275
+ d: "M15 6a9 9 0 0 0-9 9V3",
276
+ key: "1cii5b"
277
+ }],
278
+ ["circle", {
279
+ cx: "18",
280
+ cy: "6",
281
+ r: "3",
282
+ key: "1h7g24"
283
+ }],
284
+ ["circle", {
285
+ cx: "6",
286
+ cy: "18",
287
+ r: "3",
288
+ key: "fqmcym"
289
+ }]
290
+ ];
291
+ const GitBranch = createLucideIcon("git-branch", __iconNode$4);
292
+
293
+ //#endregion
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$3 = [
296
+ ["path", {
297
+ d: "M12 22v-9",
298
+ key: "x3hkom"
299
+ }],
300
+ ["path", {
301
+ d: "M15.17 2.21a1.67 1.67 0 0 1 1.63 0L21 4.57a1.93 1.93 0 0 1 0 3.36L8.82 14.79a1.655 1.655 0 0 1-1.64 0L3 12.43a1.93 1.93 0 0 1 0-3.36z",
302
+ key: "2ntwy6"
303
+ }],
304
+ ["path", {
305
+ d: "M20 13v3.87a2.06 2.06 0 0 1-1.11 1.83l-6 3.08a1.93 1.93 0 0 1-1.78 0l-6-3.08A2.06 2.06 0 0 1 4 16.87V13",
306
+ key: "1pmm1c"
307
+ }],
308
+ ["path", {
309
+ d: "M21 12.43a1.93 1.93 0 0 0 0-3.36L8.83 2.2a1.64 1.64 0 0 0-1.63 0L3 4.57a1.93 1.93 0 0 0 0 3.36l12.18 6.86a1.636 1.636 0 0 0 1.63 0z",
310
+ key: "12ttoo"
311
+ }]
312
+ ];
313
+ const PackageOpen = createLucideIcon("package-open", __iconNode$3);
314
+
315
+ //#endregion
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$2 = [["path", {
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
+ key: "w46dr5"
320
+ }]];
321
+ const Puzzle = createLucideIcon("puzzle", __iconNode$2);
322
+
323
+ //#endregion
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$1 = [
326
+ ["circle", {
327
+ cx: "12",
328
+ cy: "12",
329
+ r: "10",
330
+ key: "1mglay"
331
+ }],
332
+ ["line", {
333
+ x1: "12",
334
+ x2: "12",
335
+ y1: "8",
336
+ y2: "12",
337
+ key: "1pkeuh"
338
+ }],
339
+ ["line", {
340
+ x1: "12",
341
+ x2: "12.01",
342
+ y1: "16",
343
+ y2: "16",
344
+ key: "4dfq90"
345
+ }]
346
+ ];
347
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$1);
348
+
349
+ //#endregion
350
+ //#region node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/check.mjs
351
+ const __iconNode = [["path", {
352
+ d: "M20 6 9 17l-5-5",
353
+ key: "1gmf2c"
354
+ }]];
355
+ const Check = createLucideIcon("check", __iconNode);
356
+
357
+ //#endregion
358
+ //#region lib/types/client/index.js
359
+ const inject = [
360
+ "connection",
361
+ "slots",
362
+ "workspaces",
363
+ "sessions"
364
+ ];
365
+ const ICON_SPIN = ["dsh-skill-manager-spin", "to { transform: rotate(360deg); }"];
366
+ function ensureKeyframes() {
367
+ if (typeof document === "undefined") return;
368
+ if (document.getElementById(ICON_SPIN[0])) return;
369
+ const style = document.createElement("style");
370
+ style.id = ICON_SPIN[0];
371
+ style.textContent = `
372
+ @keyframes ${ICON_SPIN[0]} { ${ICON_SPIN[1]} }
373
+ @container (max-width: 360px) {
374
+ .dsh-skill-manager-row { grid-template-columns: minmax(0, 1fr) !important; }
375
+ .dsh-skill-manager-row-icon { display: none !important; }
376
+ .dsh-skill-manager-row-actions { grid-column: 1 !important; justify-content: flex-start !important; }
377
+ }
378
+ `;
379
+ document.head.appendChild(style);
380
+ }
381
+ const spinnerStyle = {
382
+ animation: `${ICON_SPIN[0]} 1s linear infinite`,
383
+ flex: "0 0 auto"
384
+ };
385
+ const monoStyle = { fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" };
386
+ const tokens = {
387
+ border: "var(--border-subtle, rgba(148, 163, 184, .22))",
388
+ borderStrong: "var(--border-strong, rgba(148, 163, 184, .38))",
389
+ accent: "var(--fg-accent, #6366f1)",
390
+ success: "var(--fg-success, #16a34a)",
391
+ danger: "var(--fg-danger, #dc2626)",
392
+ secondary: "var(--fg-secondary, #64748b)",
393
+ surfaceHover: "var(--bg-hover, rgba(148, 163, 184, .08))",
394
+ surfaceActive: "var(--bg-active, rgba(99, 102, 241, .12))"
395
+ };
396
+ const panelStyle = {
397
+ containerType: "inline-size",
398
+ display: "grid",
399
+ gap: 18,
400
+ width: "100%",
401
+ minWidth: 0,
402
+ maxWidth: 760,
403
+ padding: "6px 0 36px"
404
+ };
405
+ function buttonStyle(tone, disabled) {
406
+ const base = {
407
+ display: "inline-flex",
408
+ alignItems: "center",
409
+ gap: 6,
410
+ minHeight: 32,
411
+ padding: "0 12px",
412
+ borderRadius: 8,
413
+ border: `1px solid transparent`,
414
+ fontSize: 13,
415
+ fontWeight: 500,
416
+ cursor: disabled ? "default" : "pointer",
417
+ opacity: disabled ? .55 : 1,
418
+ whiteSpace: "nowrap",
419
+ transition: "background .15s ease, border-color .15s ease"
420
+ };
421
+ if (tone === "primary") return {
422
+ ...base,
423
+ background: tokens.accent,
424
+ color: "var(--fg-on-accent, #fff)",
425
+ border: "none"
426
+ };
427
+ if (tone === "danger") return {
428
+ ...base,
429
+ background: "transparent",
430
+ color: tokens.danger,
431
+ border: `1px solid ${tokens.border}`
432
+ };
433
+ return {
434
+ ...base,
435
+ background: "transparent",
436
+ color: "inherit",
437
+ border: `1px solid ${tokens.border}`
438
+ };
439
+ }
440
+ const iconButtonStyle = {
441
+ display: "grid",
442
+ placeItems: "center",
443
+ width: 28,
444
+ height: 28,
445
+ padding: 0,
446
+ border: "none",
447
+ borderRadius: 7,
448
+ background: "transparent",
449
+ color: tokens.secondary,
450
+ cursor: "pointer"
451
+ };
452
+ const inputStyle = {
453
+ width: "100%",
454
+ minHeight: 34,
455
+ padding: "0 10px 0 30px",
456
+ borderRadius: 8,
457
+ border: `1px solid ${tokens.border}`,
458
+ background: "var(--bg-primary, transparent)",
459
+ color: "inherit",
460
+ fontSize: 13,
461
+ outline: "none",
462
+ boxSizing: "border-box"
463
+ };
464
+ const selectStyle = {
465
+ minHeight: 34,
466
+ maxWidth: 300,
467
+ padding: "0 8px",
468
+ borderRadius: 8,
469
+ border: `1px solid ${tokens.border}`,
470
+ background: "var(--bg-primary, transparent)",
471
+ color: "inherit",
472
+ fontSize: 13
473
+ };
474
+ function apply(ctx) {
475
+ const client = ctx;
476
+ const list = async (projectRoot) => {
477
+ const result = await client.connection.rpc.call("/skill-manager", "list", projectRoot ? { projectRoot } : {});
478
+ if (!result.ok) throw new Error(result.error.message);
479
+ return result.value;
480
+ };
481
+ const mutate = async (endpoint, payload) => {
482
+ const result = await client.connection.rpc.call("/skill-manager", endpoint, payload);
483
+ if (!result.ok) throw new Error(result.error.message);
484
+ return result.value;
485
+ };
486
+ ctx.slots.inject("settings.section", () => ctx.slots.register({
487
+ name: "settings.section",
488
+ id: "skills",
489
+ order: 35,
490
+ label: "Skill 管理",
491
+ inject: () => ({
492
+ list,
493
+ mutate,
494
+ pickDirectory: () => ctx.workspaces.pickDirectory(),
495
+ loopback: client.connection.isLoopback
496
+ })
497
+ }, SkillManagerSection));
498
+ ctx.slots.inject("conversation.input.left", () => ctx.slots.register({
499
+ name: "conversation.input.left",
500
+ id: "skill-manager",
501
+ order: 10,
502
+ inject: () => ({
503
+ list,
504
+ mutate,
505
+ sessions: ctx.sessions.list
506
+ })
507
+ }, ComposerSkillButton));
508
+ }
509
+ function SkillManagerSection(props) {
510
+ const { list, mutate, pickDirectory, loopback, useWorkspaces } = props;
511
+ const workspaces = useWorkspaces((state) => state);
512
+ const [projectRoot, setProjectRoot] = (0, react.useState)(void 0);
513
+ const [catalog, setCatalog] = (0, react.useState)(null);
514
+ const [query, setQuery] = (0, react.useState)("");
515
+ const [busy, setBusy] = (0, react.useState)(false);
516
+ const [error, setError] = (0, react.useState)(null);
517
+ const [repositoryOpen, setRepositoryOpen] = (0, react.useState)(false);
518
+ const [repository, setRepository] = (0, react.useState)("");
519
+ (0, react.useEffect)(() => {
520
+ ensureKeyframes();
521
+ }, []);
522
+ (0, react.useEffect)(() => {
523
+ if (projectRoot === void 0 && workspaces.items.length > 0) setProjectRoot(workspaces.items[0].path);
524
+ if (projectRoot !== void 0 && !workspaces.items.some((item) => item.path === projectRoot)) setProjectRoot(workspaces.items[0]?.path);
525
+ }, [projectRoot, workspaces.items]);
526
+ const refresh = (0, react.useCallback)(async () => {
527
+ setBusy(true);
528
+ setError(null);
529
+ try {
530
+ setCatalog(await list(projectRoot));
531
+ } catch (reason) {
532
+ setError(messageOf(reason));
533
+ } finally {
534
+ setBusy(false);
535
+ }
536
+ }, [list, projectRoot]);
537
+ (0, react.useEffect)(() => {
538
+ refresh();
539
+ }, [refresh]);
540
+ const run = (0, react.useCallback)(async (action) => {
541
+ setBusy(true);
542
+ setError(null);
543
+ try {
544
+ setCatalog(await action());
545
+ return true;
546
+ } catch (reason) {
547
+ setError(messageOf(reason));
548
+ return false;
549
+ } finally {
550
+ setBusy(false);
551
+ }
552
+ }, []);
553
+ const filtered = (0, react.useMemo)(() => {
554
+ const normalized = query.trim().toLocaleLowerCase();
555
+ return (catalog?.entries ?? []).filter((entry) => normalized.length === 0 || `${entry.name} ${entry.description}`.toLocaleLowerCase().includes(normalized));
556
+ }, [catalog, query]);
557
+ const stats = (0, react.useMemo)(() => {
558
+ const entries = catalog?.entries ?? [];
559
+ return {
560
+ total: entries.length,
561
+ global: entries.filter((entry) => entry.globalEnabled).length,
562
+ project: entries.filter((entry) => entry.projectEnabled).length
563
+ };
564
+ }, [catalog]);
565
+ const importSkill = async () => {
566
+ const path = await pickDirectory();
567
+ if (path) await run(() => mutate("install", {
568
+ path,
569
+ projectRoot
570
+ }));
571
+ };
572
+ const importRepository = async (event) => {
573
+ event.preventDefault();
574
+ const source = repository.trim();
575
+ if (!source) return;
576
+ if (await run(() => mutate("install-remote", {
577
+ repository: source,
578
+ projectRoot
579
+ }))) {
580
+ setRepository("");
581
+ setRepositoryOpen(false);
582
+ }
583
+ };
584
+ const updateSkill = async (entry) => {
585
+ let path;
586
+ const remote = entry.sourceType === "git" || Boolean(entry.sourceUrl);
587
+ if (!entry.updateSupported || entry.updateError && !remote) {
588
+ path = await pickDirectory() ?? void 0;
589
+ if (!path) return;
590
+ }
591
+ await run(() => mutate("update", {
592
+ name: entry.name,
593
+ path,
594
+ projectRoot
595
+ }));
596
+ };
597
+ const selectedWorkspace = workspaces.items.find((item) => item.path === projectRoot);
598
+ return (0, react.createElement)("div", {
599
+ style: panelStyle,
600
+ "aria-busy": busy
601
+ }, (0, react.createElement)("header", { style: {
602
+ display: "flex",
603
+ justifyContent: "space-between",
604
+ alignItems: "center",
605
+ gap: 16,
606
+ flexWrap: "wrap"
607
+ } }, (0, react.createElement)("div", { style: {
608
+ display: "flex",
609
+ alignItems: "center",
610
+ gap: 10,
611
+ minWidth: 0
612
+ } }, (0, react.createElement)(Puzzle, {
613
+ size: 20,
614
+ "aria-hidden": true
615
+ }), (0, react.createElement)("h2", { style: {
616
+ margin: 0,
617
+ fontSize: 18,
618
+ fontWeight: 600
619
+ } }, "Skill 管理"), busy ? (0, react.createElement)(RefreshCw, {
620
+ size: 14,
621
+ "aria-hidden": true,
622
+ style: spinnerStyle
623
+ }) : null), (0, react.createElement)("div", { style: {
624
+ display: "flex",
625
+ gap: 8,
626
+ flexWrap: "wrap"
627
+ } }, (0, react.createElement)("button", {
628
+ type: "button",
629
+ style: buttonStyle("ghost", busy),
630
+ onClick: () => void run(() => mutate("check-updates", { projectRoot })),
631
+ disabled: busy,
632
+ title: "检查已记录来源是否有变化"
633
+ }, (0, react.createElement)(RefreshCw, {
634
+ size: 14,
635
+ "aria-hidden": true
636
+ }), "检查更新"), (0, react.createElement)("button", {
637
+ type: "button",
638
+ style: buttonStyle("ghost", busy || !loopback),
639
+ onClick: () => setRepositoryOpen((value) => !value),
640
+ disabled: busy || !loopback,
641
+ title: loopback ? "从 Git 仓库导入 skill" : "仅在本机连接时可导入"
642
+ }, (0, react.createElement)(GitBranch, {
643
+ size: 14,
644
+ "aria-hidden": true
645
+ }), "仓库"), (0, react.createElement)("button", {
646
+ type: "button",
647
+ style: buttonStyle("primary", busy || !loopback),
648
+ onClick: importSkill,
649
+ disabled: busy || !loopback,
650
+ title: loopback ? "从本机目录导入 skill" : "仅在本机连接时可导入"
651
+ }, (0, react.createElement)(Plus, {
652
+ size: 14,
653
+ "aria-hidden": true
654
+ }), "本机"))), (0, react.createElement)("p", { style: {
655
+ margin: "-8px 0 0",
656
+ fontSize: 13,
657
+ color: tokens.secondary,
658
+ lineHeight: 1.5
659
+ } }, "从本机目录或 Git 仓库导入 skill,并按「全局」或「项目」范围启用。"), repositoryOpen ? (0, react.createElement)("form", {
660
+ onSubmit: importRepository,
661
+ style: {
662
+ display: "flex",
663
+ flexWrap: "wrap",
664
+ gap: 8,
665
+ alignItems: "center"
666
+ }
667
+ }, (0, react.createElement)("input", {
668
+ type: "text",
669
+ value: repository,
670
+ onChange: (event) => setRepository(event.currentTarget.value),
671
+ placeholder: "owner/repo 或 Git URL",
672
+ "aria-label": "Git 仓库地址",
673
+ autoFocus: true,
674
+ disabled: busy,
675
+ style: {
676
+ ...inputStyle,
677
+ flex: "1 1 260px",
678
+ minWidth: 0,
679
+ paddingLeft: 10
680
+ }
681
+ }), (0, react.createElement)("button", {
682
+ type: "submit",
683
+ style: buttonStyle("primary", busy || !repository.trim()),
684
+ disabled: busy || !repository.trim()
685
+ }, (0, react.createElement)(GitBranch, {
686
+ size: 14,
687
+ "aria-hidden": true
688
+ }), "导入"), (0, react.createElement)("button", {
689
+ type: "button",
690
+ style: iconButtonStyle,
691
+ onClick: () => setRepositoryOpen(false),
692
+ disabled: busy,
693
+ title: "关闭仓库导入",
694
+ "aria-label": "关闭仓库导入"
695
+ }, (0, react.createElement)(X, {
696
+ size: 15,
697
+ "aria-hidden": true
698
+ }))) : null, (0, react.createElement)("div", { style: {
699
+ display: "flex",
700
+ gap: 10,
701
+ flexWrap: "wrap",
702
+ alignItems: "center"
703
+ } }, (0, react.createElement)("div", { style: {
704
+ position: "relative",
705
+ flex: "1 1 220px",
706
+ display: "flex",
707
+ alignItems: "center"
708
+ } }, (0, react.createElement)(Search, {
709
+ size: 14,
710
+ "aria-hidden": true,
711
+ style: {
712
+ position: "absolute",
713
+ left: 9,
714
+ color: tokens.secondary,
715
+ pointerEvents: "none"
716
+ }
717
+ }), (0, react.createElement)("input", {
718
+ type: "search",
719
+ value: query,
720
+ placeholder: "搜索 skill…",
721
+ "aria-label": "搜索 skill",
722
+ onChange: (event) => setQuery(event.currentTarget.value),
723
+ style: inputStyle
724
+ })), (0, react.createElement)("label", { style: {
725
+ display: "flex",
726
+ flex: "1 1 220px",
727
+ minWidth: 0,
728
+ alignItems: "center",
729
+ gap: 8,
730
+ flexWrap: "wrap",
731
+ fontSize: 13,
732
+ color: tokens.secondary
733
+ } }, "项目范围", (0, react.createElement)("select", {
734
+ value: projectRoot ?? "",
735
+ onChange: (event) => setProjectRoot(event.currentTarget.value || void 0),
736
+ style: {
737
+ ...selectStyle,
738
+ width: "100%"
739
+ }
740
+ }, (0, react.createElement)("option", { value: "" }, "只看全局"), ...workspaces.items.map((workspace) => (0, react.createElement)("option", {
741
+ key: workspace.workspaceId,
742
+ value: workspace.path
743
+ }, workspace.title))))), (0, react.createElement)("div", { style: {
744
+ display: "flex",
745
+ gap: 8,
746
+ flexWrap: "wrap"
747
+ } }, (0, react.createElement)(StatChip, {
748
+ label: "已安装",
749
+ value: stats.total
750
+ }), (0, react.createElement)(StatChip, {
751
+ label: "全局启用",
752
+ value: stats.global,
753
+ tone: "accent"
754
+ }), projectRoot !== void 0 ? (0, react.createElement)(StatChip, {
755
+ label: "项目启用",
756
+ value: stats.project,
757
+ tone: "accent"
758
+ }) : null), error ? (0, react.createElement)("div", {
759
+ role: "alert",
760
+ style: {
761
+ display: "flex",
762
+ gap: 8,
763
+ alignItems: "center",
764
+ margin: 0,
765
+ padding: "9px 12px",
766
+ borderRadius: 8,
767
+ fontSize: 13,
768
+ color: tokens.danger,
769
+ background: "rgba(220, 38, 38, .08)",
770
+ border: "1px solid rgba(220, 38, 38, .28)"
771
+ }
772
+ }, (0, react.createElement)(CircleAlert, {
773
+ size: 15,
774
+ "aria-hidden": true
775
+ }), error) : null, (0, react.createElement)("section", {
776
+ style: {
777
+ display: "grid",
778
+ width: "100%",
779
+ minWidth: 0,
780
+ gap: 8
781
+ },
782
+ "aria-label": "已安装 skill"
783
+ }, catalog === null ? (0, react.createElement)("p", { style: {
784
+ margin: 0,
785
+ padding: "24px 0",
786
+ textAlign: "center",
787
+ fontSize: 13,
788
+ color: tokens.secondary
789
+ } }, "正在读取…") : filtered.length === 0 ? (0, react.createElement)(EmptyState, { hasAny: (catalog.entries.length ?? 0) > 0 }) : filtered.map((entry) => (0, react.createElement)(SkillRow, {
790
+ key: entry.name,
791
+ entry,
792
+ projectLabel: selectedWorkspace?.title ?? "当前项目",
793
+ projectAvailable: projectRoot !== void 0,
794
+ busy,
795
+ onGlobalChange: (enabled) => void run(() => mutate("set-enabled", {
796
+ name: entry.name,
797
+ scope: "global",
798
+ projectRoot,
799
+ enabled
800
+ })),
801
+ onProjectChange: (enabled) => void run(() => mutate("set-enabled", {
802
+ name: entry.name,
803
+ scope: "project",
804
+ projectRoot,
805
+ enabled
806
+ })),
807
+ onUpdate: () => void updateSkill(entry),
808
+ onRemove: () => void run(() => mutate("remove", {
809
+ name: entry.name,
810
+ projectRoot
811
+ }))
812
+ }))));
813
+ }
814
+ function StatChip(props) {
815
+ const active = props.tone === "accent" && props.value > 0;
816
+ return (0, react.createElement)("span", { style: {
817
+ display: "inline-flex",
818
+ alignItems: "baseline",
819
+ gap: 6,
820
+ padding: "4px 10px",
821
+ borderRadius: 999,
822
+ fontSize: 12,
823
+ border: `1px solid ${active ? "rgba(99, 102, 241, .4)" : tokens.border}`,
824
+ color: active ? tokens.accent : tokens.secondary,
825
+ background: active ? "rgba(99, 102, 241, .08)" : "transparent"
826
+ } }, (0, react.createElement)("span", null, props.label), (0, react.createElement)("strong", { style: {
827
+ fontSize: 13,
828
+ fontWeight: 600
829
+ } }, String(props.value)));
830
+ }
831
+ function EmptyState(props) {
832
+ return (0, react.createElement)("div", { style: {
833
+ display: "grid",
834
+ justifyItems: "center",
835
+ gap: 8,
836
+ padding: "36px 16px",
837
+ borderRadius: 10,
838
+ border: `1px dashed ${tokens.borderStrong}`,
839
+ color: tokens.secondary,
840
+ textAlign: "center"
841
+ } }, (0, react.createElement)(PackageOpen, {
842
+ size: 26,
843
+ "aria-hidden": true
844
+ }), (0, react.createElement)("p", { style: {
845
+ margin: 0,
846
+ fontSize: 13,
847
+ lineHeight: 1.5
848
+ } }, props.hasAny ? "没有匹配的 skill,试试调整搜索词。" : "还没有导入任何 skill。点击右上角「导入」,从本机目录开始。"));
849
+ }
850
+ function ComposerSkillButton(props) {
851
+ const { session, sessions, list, mutate } = props;
852
+ const projectRoot = (0, react.useSyncExternalStore)(sessions.subscribe, sessions.getSnapshot, sessions.getSnapshot).byId[session.sessionId]?.cwd;
853
+ const [open, setOpen] = (0, react.useState)(false);
854
+ const containerRef = (0, react.useRef)(null);
855
+ (0, react.useEffect)(() => {
856
+ if (!open) return;
857
+ const onPointerDown = (event) => {
858
+ if (containerRef.current && event.target instanceof Node && !containerRef.current.contains(event.target)) setOpen(false);
859
+ };
860
+ const onKeyDown = (event) => {
861
+ if (event.key === "Escape") setOpen(false);
862
+ };
863
+ document.addEventListener("pointerdown", onPointerDown);
864
+ document.addEventListener("keydown", onKeyDown);
865
+ return () => {
866
+ document.removeEventListener("pointerdown", onPointerDown);
867
+ document.removeEventListener("keydown", onKeyDown);
868
+ };
869
+ }, [open]);
870
+ return (0, react.createElement)("div", {
871
+ ref: containerRef,
872
+ style: {
873
+ position: "relative",
874
+ display: "inline-flex",
875
+ marginLeft: -25
876
+ }
877
+ }, (0, react.createElement)("button", {
878
+ type: "button",
879
+ title: projectRoot ? "配置当前项目的 Skill" : "当前会话没有工作区",
880
+ "aria-label": "配置当前项目的 Skill",
881
+ "aria-expanded": open,
882
+ disabled: !projectRoot,
883
+ onClick: () => setOpen((value) => !value),
884
+ style: {
885
+ display: "grid",
886
+ placeItems: "center",
887
+ flex: "0 0 auto",
888
+ width: 28,
889
+ height: 28,
890
+ padding: 0,
891
+ border: "none",
892
+ borderRadius: 999,
893
+ background: open ? "var(--dsw-alias-bg-active, rgba(255, 255, 255, .16))" : "var(--dsw-specific-selector, rgba(255, 255, 255, .08))",
894
+ color: "var(--dsw-alias-label-primary, inherit)",
895
+ cursor: projectRoot ? "pointer" : "default",
896
+ opacity: projectRoot ? 1 : .5
897
+ }
898
+ }, (0, react.createElement)(Wrench, {
899
+ size: 16,
900
+ "aria-hidden": true
901
+ })), open && projectRoot ? (0, react.createElement)(ProjectSkillPopover, {
902
+ projectRoot,
903
+ list,
904
+ mutate,
905
+ onClose: () => setOpen(false)
906
+ }) : null);
907
+ }
908
+ function ProjectSkillPopover(props) {
909
+ const { projectRoot, list, mutate, onClose } = props;
910
+ const theme = currentThemeColors();
911
+ const [catalog, setCatalog] = (0, react.useState)(null);
912
+ const [busy, setBusy] = (0, react.useState)(false);
913
+ const [error, setError] = (0, react.useState)(null);
914
+ (0, react.useEffect)(() => {
915
+ ensureKeyframes();
916
+ }, []);
917
+ const refresh = (0, react.useCallback)(async () => {
918
+ setBusy(true);
919
+ setError(null);
920
+ try {
921
+ setCatalog(await list(projectRoot));
922
+ } catch (reason) {
923
+ setError(messageOf(reason));
924
+ } finally {
925
+ setBusy(false);
926
+ }
927
+ }, [list, projectRoot]);
928
+ (0, react.useEffect)(() => {
929
+ refresh();
930
+ }, [refresh]);
931
+ const toggle = async (entry, enabled) => {
932
+ setBusy(true);
933
+ setError(null);
934
+ try {
935
+ setCatalog(await mutate("set-enabled", {
936
+ name: entry.name,
937
+ scope: "project",
938
+ projectRoot,
939
+ enabled
940
+ }));
941
+ } catch (reason) {
942
+ setError(messageOf(reason));
943
+ } finally {
944
+ setBusy(false);
945
+ }
946
+ };
947
+ const enabledCount = (catalog?.entries ?? []).filter((entry) => entry.projectEnabled).length;
948
+ return (0, react.createElement)("section", {
949
+ style: {
950
+ position: "absolute",
951
+ zIndex: 50,
952
+ left: 0,
953
+ bottom: 40,
954
+ width: 320,
955
+ display: "grid",
956
+ gap: 6,
957
+ padding: 12,
958
+ border: `1px solid ${tokens.borderStrong}`,
959
+ borderRadius: 12,
960
+ background: theme.background,
961
+ color: theme.color,
962
+ boxShadow: "0 16px 40px rgba(0, 0, 0, .4)"
963
+ },
964
+ "aria-label": "当前项目 Skill"
965
+ }, (0, react.createElement)("header", { style: {
966
+ display: "flex",
967
+ justifyContent: "space-between",
968
+ gap: 8,
969
+ alignItems: "center",
970
+ paddingBottom: 4
971
+ } }, (0, react.createElement)("div", { style: {
972
+ display: "flex",
973
+ alignItems: "center",
974
+ gap: 7,
975
+ minWidth: 0
976
+ } }, (0, react.createElement)(FolderGit, {
977
+ size: 14,
978
+ "aria-hidden": true,
979
+ style: {
980
+ color: tokens.secondary,
981
+ flex: "0 0 auto"
982
+ }
983
+ }), (0, react.createElement)("strong", { style: {
984
+ fontSize: 13,
985
+ fontWeight: 600
986
+ } }, "项目 Skill"), (0, react.createElement)("span", { style: {
987
+ fontSize: 12,
988
+ color: tokens.secondary
989
+ } }, `${enabledCount}/${catalog?.entries.length ?? 0} 已启用`)), (0, react.createElement)("button", {
990
+ type: "button",
991
+ onClick: onClose,
992
+ style: iconButtonStyle,
993
+ "aria-label": "关闭项目 Skill",
994
+ title: "关闭"
995
+ }, (0, react.createElement)(X, {
996
+ size: 14,
997
+ "aria-hidden": true
998
+ }))), error ? (0, react.createElement)("div", {
999
+ role: "alert",
1000
+ style: {
1001
+ display: "flex",
1002
+ gap: 6,
1003
+ alignItems: "center",
1004
+ margin: 0,
1005
+ padding: "7px 9px",
1006
+ borderRadius: 7,
1007
+ fontSize: 12,
1008
+ color: tokens.danger,
1009
+ background: "rgba(220, 38, 38, .08)"
1010
+ }
1011
+ }, (0, react.createElement)(CircleAlert, {
1012
+ size: 13,
1013
+ "aria-hidden": true
1014
+ }), error) : null, (0, react.createElement)("div", { style: {
1015
+ display: "grid",
1016
+ gap: 1,
1017
+ maxHeight: 280,
1018
+ overflowY: "auto",
1019
+ margin: "0 -4px",
1020
+ padding: "0 4px"
1021
+ } }, catalog === null ? (0, react.createElement)("p", { style: {
1022
+ margin: 0,
1023
+ padding: "18px 0",
1024
+ textAlign: "center",
1025
+ fontSize: 12,
1026
+ color: tokens.secondary
1027
+ } }, "正在读取…") : catalog.entries.length === 0 ? (0, react.createElement)("p", { style: {
1028
+ margin: 0,
1029
+ padding: "18px 0",
1030
+ textAlign: "center",
1031
+ fontSize: 12,
1032
+ color: tokens.secondary
1033
+ } }, "未导入 skill。请到「设置 → Skill 管理」导入。") : catalog.entries.map((entry) => (0, react.createElement)("label", {
1034
+ key: entry.name,
1035
+ style: {
1036
+ display: "grid",
1037
+ gridTemplateColumns: "14px minmax(0, 1fr) 30px",
1038
+ gap: 8,
1039
+ alignItems: "center",
1040
+ padding: "7px 6px",
1041
+ borderRadius: 7,
1042
+ fontSize: 13,
1043
+ cursor: busy ? "default" : "pointer"
1044
+ },
1045
+ title: entry.description || entry.name
1046
+ }, (0, react.createElement)(Puzzle, {
1047
+ size: 13,
1048
+ "aria-hidden": true,
1049
+ style: { color: entry.projectEnabled ? tokens.accent : tokens.secondary }
1050
+ }), (0, react.createElement)("span", { style: {
1051
+ overflow: "hidden",
1052
+ textOverflow: "ellipsis",
1053
+ whiteSpace: "nowrap"
1054
+ } }, entry.name), (0, react.createElement)(Toggle, {
1055
+ checked: entry.projectEnabled,
1056
+ disabled: busy,
1057
+ onChange: (enabled) => void toggle(entry, enabled),
1058
+ label: entry.name
1059
+ })))), busy ? (0, react.createElement)("div", { style: {
1060
+ display: "flex",
1061
+ justifyContent: "flex-end",
1062
+ paddingTop: 2
1063
+ } }, (0, react.createElement)(RefreshCw, {
1064
+ size: 12,
1065
+ "aria-hidden": true,
1066
+ style: spinnerStyle
1067
+ })) : null);
1068
+ }
1069
+ function SkillRow(props) {
1070
+ const { entry, projectLabel, projectAvailable, busy, onGlobalChange, onProjectChange, onUpdate, onRemove } = props;
1071
+ const [hover, setHover] = (0, react.useState)(false);
1072
+ return (0, react.createElement)("article", {
1073
+ className: "dsh-skill-manager-row",
1074
+ style: {
1075
+ display: "grid",
1076
+ gridTemplateColumns: "32px minmax(0, 1fr)",
1077
+ gap: 12,
1078
+ alignItems: "center",
1079
+ width: "100%",
1080
+ minWidth: 0,
1081
+ maxWidth: "100%",
1082
+ overflow: "hidden",
1083
+ boxSizing: "border-box",
1084
+ padding: "12px 14px",
1085
+ borderRadius: 10,
1086
+ border: `1px solid ${hover ? tokens.borderStrong : tokens.border}`,
1087
+ background: hover ? tokens.surfaceHover : "transparent",
1088
+ transition: "border-color .15s ease, background .15s ease"
1089
+ },
1090
+ onMouseEnter: () => setHover(true),
1091
+ onMouseLeave: () => setHover(false)
1092
+ }, (0, react.createElement)("div", {
1093
+ className: "dsh-skill-manager-row-icon",
1094
+ style: {
1095
+ display: "grid",
1096
+ placeItems: "center",
1097
+ width: 32,
1098
+ height: 32,
1099
+ borderRadius: 8,
1100
+ color: entry.effectiveEnabled ? tokens.accent : tokens.secondary,
1101
+ background: entry.effectiveEnabled ? "rgba(99, 102, 241, .1)" : "rgba(148, 163, 184, .1)"
1102
+ }
1103
+ }, (0, react.createElement)(Puzzle, {
1104
+ size: 16,
1105
+ "aria-hidden": true
1106
+ })), (0, react.createElement)("div", { style: {
1107
+ minWidth: 0,
1108
+ display: "grid",
1109
+ gap: 4
1110
+ } }, (0, react.createElement)("div", { style: {
1111
+ display: "flex",
1112
+ alignItems: "center",
1113
+ gap: 8,
1114
+ minWidth: 0,
1115
+ flexWrap: "wrap"
1116
+ } }, (0, react.createElement)("strong", { style: {
1117
+ ...monoStyle,
1118
+ fontSize: 13,
1119
+ fontWeight: 600,
1120
+ overflow: "hidden",
1121
+ textOverflow: "ellipsis",
1122
+ whiteSpace: "nowrap"
1123
+ } }, entry.name), (0, react.createElement)(SourceBadge, { entry }), (0, react.createElement)(StatusBadge, {
1124
+ active: entry.globalEnabled,
1125
+ icon: Globe,
1126
+ label: "全局"
1127
+ }), projectAvailable ? (0, react.createElement)(StatusBadge, {
1128
+ active: entry.projectEnabled,
1129
+ icon: FolderGit,
1130
+ label: projectLabel
1131
+ }) : null, entry.updateAvailable ? (0, react.createElement)("span", { style: {
1132
+ flex: "0 0 auto",
1133
+ fontSize: 11,
1134
+ color: tokens.accent
1135
+ } }, "有更新") : null, entry.updateError ? (0, react.createElement)("span", {
1136
+ style: {
1137
+ flex: "0 0 auto",
1138
+ fontSize: 11,
1139
+ color: tokens.danger
1140
+ },
1141
+ title: entry.updateError
1142
+ }, "来源异常") : null), entry.description ? (0, react.createElement)("p", { style: {
1143
+ margin: 0,
1144
+ color: tokens.secondary,
1145
+ lineHeight: 1.45,
1146
+ fontSize: 12.5,
1147
+ display: "-webkit-box",
1148
+ WebkitLineClamp: 2,
1149
+ WebkitBoxOrient: "vertical",
1150
+ overflow: "hidden"
1151
+ } }, entry.description) : null), (0, react.createElement)("div", {
1152
+ className: "dsh-skill-manager-row-actions",
1153
+ style: {
1154
+ gridColumn: "1 / -1",
1155
+ display: "flex",
1156
+ width: "100%",
1157
+ minWidth: 0,
1158
+ justifyContent: "flex-end",
1159
+ alignItems: "center",
1160
+ gap: 10,
1161
+ flexWrap: "wrap"
1162
+ }
1163
+ }, (0, react.createElement)(Toggle, {
1164
+ checked: entry.globalEnabled,
1165
+ disabled: busy,
1166
+ onChange: onGlobalChange,
1167
+ label: `${entry.name} 全局开关`,
1168
+ title: "全局启用"
1169
+ }), projectAvailable ? (0, react.createElement)(Toggle, {
1170
+ checked: entry.projectEnabled,
1171
+ disabled: busy,
1172
+ onChange: onProjectChange,
1173
+ label: `${entry.name} 项目开关`,
1174
+ title: `${projectLabel} 启用`
1175
+ }) : null, (0, react.createElement)("button", {
1176
+ type: "button",
1177
+ style: {
1178
+ ...iconButtonStyle,
1179
+ color: entry.updateAvailable ? tokens.accent : tokens.secondary
1180
+ },
1181
+ disabled: busy,
1182
+ onClick: onUpdate,
1183
+ title: entry.updateSupported && !entry.updateError ? entry.sourceType === "git" ? "从远程仓库更新" : "从原始目录更新" : "选择来源目录并更新",
1184
+ "aria-label": `更新 ${entry.name}`
1185
+ }, (0, react.createElement)(RefreshCw, {
1186
+ size: 15,
1187
+ "aria-hidden": true
1188
+ })), (0, react.createElement)("button", {
1189
+ type: "button",
1190
+ style: {
1191
+ ...iconButtonStyle,
1192
+ color: tokens.danger
1193
+ },
1194
+ disabled: busy,
1195
+ onClick: onRemove,
1196
+ title: "从库中移除",
1197
+ "aria-label": `移除 ${entry.name}`
1198
+ }, (0, react.createElement)(Trash2, {
1199
+ size: 15,
1200
+ "aria-hidden": true
1201
+ }))));
1202
+ }
1203
+ function SourceBadge(props) {
1204
+ const remote = props.entry.sourceType === "git" || Boolean(props.entry.sourceUrl);
1205
+ const local = props.entry.sourceType === "local" || Boolean(props.entry.sourcePath);
1206
+ const Icon$1 = remote ? GitBranch : local ? FolderGit : CircleAlert;
1207
+ const label = remote ? "Git" : local ? "本机" : "未知";
1208
+ return (0, react.createElement)("span", {
1209
+ title: remote ? props.entry.sourceUrl : local ? props.entry.sourcePath : "旧版本导入,首次更新需重新选择来源",
1210
+ style: {
1211
+ display: "inline-flex",
1212
+ alignItems: "center",
1213
+ gap: 4,
1214
+ flex: "0 1 auto",
1215
+ maxWidth: "100%",
1216
+ overflow: "hidden",
1217
+ padding: "2px 6px",
1218
+ borderRadius: 999,
1219
+ fontSize: 11,
1220
+ lineHeight: "16px",
1221
+ whiteSpace: "nowrap",
1222
+ color: tokens.secondary,
1223
+ background: "rgba(148, 163, 184, .09)"
1224
+ }
1225
+ }, (0, react.createElement)(Icon$1, {
1226
+ size: 11,
1227
+ "aria-hidden": true
1228
+ }), label);
1229
+ }
1230
+ function StatusBadge(props) {
1231
+ const Icon$1 = props.icon;
1232
+ return (0, react.createElement)("span", {
1233
+ title: props.active ? `${props.label}已启用` : `${props.label}未启用`,
1234
+ style: {
1235
+ display: "inline-flex",
1236
+ alignItems: "center",
1237
+ gap: 4,
1238
+ flex: "0 1 auto",
1239
+ maxWidth: "100%",
1240
+ overflow: "hidden",
1241
+ padding: "2px 6px",
1242
+ borderRadius: 999,
1243
+ fontSize: 11,
1244
+ lineHeight: "16px",
1245
+ whiteSpace: "nowrap",
1246
+ color: props.active ? tokens.success : tokens.secondary,
1247
+ background: props.active ? "rgba(22, 163, 74, .1)" : "rgba(148, 163, 184, .09)",
1248
+ border: `1px solid ${props.active ? "rgba(22, 163, 74, .3)" : "transparent"}`
1249
+ }
1250
+ }, (0, react.createElement)(Icon$1, {
1251
+ size: 11,
1252
+ "aria-hidden": true
1253
+ }), props.active ? `${props.label}开` : `${props.label}关`);
1254
+ }
1255
+ function Toggle(props) {
1256
+ const { checked, disabled, onChange, label, title } = props;
1257
+ return (0, react.createElement)("button", {
1258
+ type: "button",
1259
+ role: "switch",
1260
+ "aria-checked": checked,
1261
+ "aria-label": label,
1262
+ title,
1263
+ disabled,
1264
+ onClick: () => onChange(!checked),
1265
+ style: {
1266
+ position: "relative",
1267
+ flex: "0 0 auto",
1268
+ width: 30,
1269
+ height: 18,
1270
+ padding: 0,
1271
+ border: "none",
1272
+ borderRadius: 999,
1273
+ background: checked ? tokens.accent : "rgba(148, 163, 184, .35)",
1274
+ cursor: disabled ? "default" : "pointer",
1275
+ opacity: disabled ? .55 : 1,
1276
+ transition: "background .15s ease"
1277
+ }
1278
+ }, (0, react.createElement)("span", {
1279
+ "aria-hidden": true,
1280
+ style: {
1281
+ position: "absolute",
1282
+ top: 2,
1283
+ left: checked ? 14 : 2,
1284
+ width: 14,
1285
+ height: 14,
1286
+ borderRadius: 999,
1287
+ background: "#fff",
1288
+ boxShadow: "0 1px 2px rgba(0, 0, 0, .3)",
1289
+ transition: "left .15s ease",
1290
+ display: "grid",
1291
+ placeItems: "center"
1292
+ }
1293
+ }, checked ? (0, react.createElement)(Check, {
1294
+ size: 10,
1295
+ "aria-hidden": true
1296
+ }) : null));
1297
+ }
1298
+ function currentThemeColors() {
1299
+ if (typeof document === "undefined") return {
1300
+ background: "#151517",
1301
+ color: "#f9fafb"
1302
+ };
1303
+ const style = getComputedStyle(document.body);
1304
+ return {
1305
+ background: style.backgroundColor || "#151517",
1306
+ color: style.color || "#f9fafb"
1307
+ };
1308
+ }
1309
+ function messageOf(reason) {
1310
+ return reason instanceof Error ? reason.message : String(reason);
1311
+ }
1312
+
1313
+ //#endregion
1314
+ exports.apply = apply;
1315
+ exports.inject = inject;
1316
+ return module.exports; } });
1317
+ //# sourceMappingURL=client.js.map