dsh-skills-manager 0.1.6 → 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 +98 -3
- package/lib/client.js.map +1 -1
- package/lib/index.js +144 -1
- package/lib/types/client/index.js +51 -5
- 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 +1 -1
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
|
@@ -543,6 +543,11 @@ function apply(ctx) {
|
|
|
543
543
|
};
|
|
544
544
|
const list = (projectRoot) => request("list", projectRoot ? { projectRoot } : {});
|
|
545
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
|
+
};
|
|
546
551
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
547
552
|
name: "settings.section",
|
|
548
553
|
id: "skills",
|
|
@@ -551,6 +556,7 @@ function apply(ctx) {
|
|
|
551
556
|
inject: () => ({
|
|
552
557
|
list,
|
|
553
558
|
mutate,
|
|
559
|
+
checkUpdates,
|
|
554
560
|
pickDirectory: () => ctx.workspaces.pickDirectory(),
|
|
555
561
|
loopback: connection.isLoopback
|
|
556
562
|
})
|
|
@@ -566,12 +572,14 @@ function apply(ctx) {
|
|
|
566
572
|
}, ComposerSkillButton));
|
|
567
573
|
}
|
|
568
574
|
function SkillManagerSection(props) {
|
|
569
|
-
const { list, mutate, pickDirectory, loopback, useWorkspaces } = props;
|
|
575
|
+
const { list, mutate, checkUpdates, pickDirectory, loopback, useWorkspaces } = props;
|
|
570
576
|
const workspaces = useWorkspaces((state) => state);
|
|
571
577
|
const [projectRoot, setProjectRoot] = (0, react.useState)(void 0);
|
|
572
578
|
const [catalog, setCatalog] = (0, react.useState)(null);
|
|
573
579
|
const [query, setQuery] = (0, react.useState)("");
|
|
574
580
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
581
|
+
const [checking, setChecking] = (0, react.useState)(false);
|
|
582
|
+
const [statuses, setStatuses] = (0, react.useState)({});
|
|
575
583
|
const [error, setError] = (0, react.useState)(null);
|
|
576
584
|
const [repositoryOpen, setRepositoryOpen] = (0, react.useState)(false);
|
|
577
585
|
const [repository, setRepository] = (0, react.useState)("");
|
|
@@ -643,6 +651,34 @@ function SkillManagerSection(props) {
|
|
|
643
651
|
projectRoot
|
|
644
652
|
}));
|
|
645
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
|
+
};
|
|
646
682
|
const selectedWorkspace = workspaces.items.find((item) => item.path === projectRoot);
|
|
647
683
|
const rowProps = (entry) => ({
|
|
648
684
|
key: entry.name,
|
|
@@ -650,6 +686,7 @@ function SkillManagerSection(props) {
|
|
|
650
686
|
projectLabel: selectedWorkspace?.title ?? "当前项目",
|
|
651
687
|
projectAvailable: projectRoot !== void 0,
|
|
652
688
|
busy,
|
|
689
|
+
updateStatus: statuses[entry.name],
|
|
653
690
|
onGlobalChange: (enabled) => void run(() => mutate("set-enabled", {
|
|
654
691
|
name: entry.name,
|
|
655
692
|
scope: "global",
|
|
@@ -698,6 +735,25 @@ function SkillManagerSection(props) {
|
|
|
698
735
|
gap: 8,
|
|
699
736
|
flexWrap: "wrap"
|
|
700
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", {
|
|
701
757
|
type: "button",
|
|
702
758
|
style: buttonStyle("ghost", busy || !loopback),
|
|
703
759
|
onClick: () => setRepositoryOpen((value) => !value),
|
|
@@ -1225,8 +1281,35 @@ function ProjectSkillPopover(props) {
|
|
|
1225
1281
|
style: spinnerStyle
|
|
1226
1282
|
})) : null);
|
|
1227
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
|
+
};
|
|
1228
1310
|
function SkillRow(props) {
|
|
1229
|
-
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;
|
|
1230
1313
|
return (0, react.createElement)("article", {
|
|
1231
1314
|
className: "dsh-skill-manager-row",
|
|
1232
1315
|
style: {
|
|
@@ -1276,7 +1359,19 @@ function SkillRow(props) {
|
|
|
1276
1359
|
overflow: "hidden",
|
|
1277
1360
|
textOverflow: "ellipsis",
|
|
1278
1361
|
whiteSpace: "nowrap"
|
|
1279
|
-
} }, 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, {
|
|
1280
1375
|
active: entry.globalEnabled,
|
|
1281
1376
|
icon: Globe,
|
|
1282
1377
|
label: "全局"
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","AlertCircle","Icon"],"sources":["../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toKebabCase.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toCamelCase.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toPascalCase.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/defaultAttributes.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/hasA11yProp.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/context.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/Icon.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/createLucideIcon.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/wrench.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/plus.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/refresh-cw.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/search.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/x.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/trash-2.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/globe.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/folder-git.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/git-branch.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/package-open.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/puzzle.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/circle-alert.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/list.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/folder.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/chevron-down.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/chevron-right.mjs","types/client/popover.js","types/client/session.js","types/client/index.js"],"sourcesContent":["/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst mergeClasses = (...classes) => classes.filter((className, index, array) => {\n return Boolean(className) && className.trim() !== \"\" && array.indexOf(className) === index;\n}).join(\" \").trim();\n\nexport { mergeClasses };\n//# sourceMappingURL=mergeClasses.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\n\nexport { toKebabCase };\n//# sourceMappingURL=toKebabCase.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toCamelCase = (string) => string.replace(\n /^([A-Z])|[\\s-_]+(\\w)/g,\n (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()\n);\n\nexport { toCamelCase };\n//# sourceMappingURL=toCamelCase.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { toCamelCase } from './toCamelCase.mjs';\n\nconst toPascalCase = (string) => {\n const camelCase = toCamelCase(string);\n return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);\n};\n\nexport { toPascalCase };\n//# sourceMappingURL=toPascalCase.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nvar defaultAttributes = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 24,\n height: 24,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\"\n};\n\nexport { defaultAttributes as default };\n//# sourceMappingURL=defaultAttributes.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst hasA11yProp = (props) => {\n for (const prop in props) {\n if (prop.startsWith(\"aria-\") || prop === \"role\" || prop === \"title\") {\n return true;\n }\n }\n return false;\n};\n\nexport { hasA11yProp };\n//# sourceMappingURL=hasA11yProp.mjs.map\n","\"use strict\";\n\"use client\";\n/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { createContext, useContext, useMemo, createElement } from 'react';\n\nconst LucideContext = createContext({});\nfunction LucideProvider({\n children,\n size,\n color,\n strokeWidth,\n absoluteStrokeWidth,\n className\n}) {\n const value = useMemo(\n () => ({\n size,\n color,\n strokeWidth,\n absoluteStrokeWidth,\n className\n }),\n [size, color, strokeWidth, absoluteStrokeWidth, className]\n );\n return createElement(LucideContext.Provider, { value }, children);\n}\nconst useLucideContext = () => useContext(LucideContext);\n\nexport { LucideProvider, useLucideContext };\n//# sourceMappingURL=context.mjs.map\n","\"use strict\";\n\"use client\";\n/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport defaultAttributes from './defaultAttributes.mjs';\nimport { hasA11yProp } from './shared/src/utils/hasA11yProp.mjs';\nimport { mergeClasses } from './shared/src/utils/mergeClasses.mjs';\nimport { useLucideContext } from './context.mjs';\n\nconst Icon = forwardRef(\n ({ color, size, strokeWidth, absoluteStrokeWidth, className = \"\", children, iconNode, ...rest }, ref) => {\n const {\n size: contextSize = 24,\n strokeWidth: contextStrokeWidth = 2,\n absoluteStrokeWidth: contextAbsoluteStrokeWidth = false,\n color: contextColor = \"currentColor\",\n className: contextClass = \"\"\n } = useLucideContext() ?? {};\n const calculatedStrokeWidth = absoluteStrokeWidth ?? contextAbsoluteStrokeWidth ? Number(strokeWidth ?? contextStrokeWidth) * 24 / Number(size ?? contextSize) : strokeWidth ?? contextStrokeWidth;\n return createElement(\n \"svg\",\n {\n ref,\n ...defaultAttributes,\n width: size ?? contextSize ?? defaultAttributes.width,\n height: size ?? contextSize ?? defaultAttributes.height,\n stroke: color ?? contextColor,\n strokeWidth: calculatedStrokeWidth,\n className: mergeClasses(\"lucide\", contextClass, className),\n ...!children && !hasA11yProp(rest) && { \"aria-hidden\": \"true\" },\n ...rest\n },\n [\n ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),\n ...Array.isArray(children) ? children : [children]\n ]\n );\n }\n);\n\nexport { Icon as default };\n//# sourceMappingURL=Icon.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport { mergeClasses } from './shared/src/utils/mergeClasses.mjs';\nimport { toKebabCase } from './shared/src/utils/toKebabCase.mjs';\nimport { toPascalCase } from './shared/src/utils/toPascalCase.mjs';\nimport Icon from './Icon.mjs';\n\nconst createLucideIcon = (iconName, iconNode) => {\n const Component = forwardRef(\n ({ className, ...props }, ref) => createElement(Icon, {\n ref,\n iconNode,\n className: mergeClasses(\n `lucide-${toKebabCase(toPascalCase(iconName))}`,\n `lucide-${iconName}`,\n className\n ),\n ...props\n })\n );\n Component.displayName = toPascalCase(iconName);\n return Component;\n};\n\nexport { createLucideIcon as default };\n//# sourceMappingURL=createLucideIcon.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n 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\",\n key: \"1ngwbx\"\n }\n ]\n];\nconst Wrench = createLucideIcon(\"wrench\", __iconNode);\n\nexport { __iconNode, Wrench as default };\n//# sourceMappingURL=wrench.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M5 12h14\", key: \"1ays0h\" }],\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }]\n];\nconst Plus = createLucideIcon(\"plus\", __iconNode);\n\nexport { __iconNode, Plus as default };\n//# sourceMappingURL=plus.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\", key: \"v9h5vc\" }],\n [\"path\", { d: \"M21 3v5h-5\", key: \"1q7to0\" }],\n [\"path\", { d: \"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\", key: \"3uifl3\" }],\n [\"path\", { d: \"M8 16H3v5\", key: \"1cv678\" }]\n];\nconst RefreshCw = createLucideIcon(\"refresh-cw\", __iconNode);\n\nexport { __iconNode, RefreshCw as default };\n//# sourceMappingURL=refresh-cw.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"m21 21-4.34-4.34\", key: \"14j7rj\" }],\n [\"circle\", { cx: \"11\", cy: \"11\", r: \"8\", key: \"4ej97u\" }]\n];\nconst Search = createLucideIcon(\"search\", __iconNode);\n\nexport { __iconNode, Search as default };\n//# sourceMappingURL=search.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M18 6 6 18\", key: \"1bl5f8\" }],\n [\"path\", { d: \"m6 6 12 12\", key: \"d8bk6v\" }]\n];\nconst X = createLucideIcon(\"x\", __iconNode);\n\nexport { __iconNode, X as default };\n//# sourceMappingURL=x.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M10 11v6\", key: \"nco0om\" }],\n [\"path\", { d: \"M14 11v6\", key: \"outv1u\" }],\n [\"path\", { d: \"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\", key: \"miytrc\" }],\n [\"path\", { d: \"M3 6h18\", key: \"d0wm0j\" }],\n [\"path\", { d: \"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\", key: \"e791ji\" }]\n];\nconst Trash2 = createLucideIcon(\"trash-2\", __iconNode);\n\nexport { __iconNode, Trash2 as default };\n//# sourceMappingURL=trash-2.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20\", key: \"13o1zl\" }],\n [\"path\", { d: \"M2 12h20\", key: \"9i4pu4\" }]\n];\nconst Globe = createLucideIcon(\"globe\", __iconNode);\n\nexport { __iconNode, Globe as default };\n//# sourceMappingURL=globe.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"13\", r: \"2\", key: \"1c1ljs\" }],\n [\n \"path\",\n {\n 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\",\n key: \"1kt360\"\n }\n ],\n [\"path\", { d: \"M14 13h3\", key: \"1dgedf\" }],\n [\"path\", { d: \"M7 13h3\", key: \"1pygq7\" }]\n];\nconst FolderGit = createLucideIcon(\"folder-git\", __iconNode);\n\nexport { __iconNode, FolderGit as default };\n//# sourceMappingURL=folder-git.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M15 6a9 9 0 0 0-9 9V3\", key: \"1cii5b\" }],\n [\"circle\", { cx: \"18\", cy: \"6\", r: \"3\", key: \"1h7g24\" }],\n [\"circle\", { cx: \"6\", cy: \"18\", r: \"3\", key: \"fqmcym\" }]\n];\nconst GitBranch = createLucideIcon(\"git-branch\", __iconNode);\n\nexport { __iconNode, GitBranch as default };\n//# sourceMappingURL=git-branch.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 22v-9\", key: \"x3hkom\" }],\n [\n \"path\",\n {\n 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\",\n key: \"2ntwy6\"\n }\n ],\n [\n \"path\",\n {\n 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\",\n key: \"1pmm1c\"\n }\n ],\n [\n \"path\",\n {\n 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\",\n key: \"12ttoo\"\n }\n ]\n];\nconst PackageOpen = createLucideIcon(\"package-open\", __iconNode);\n\nexport { __iconNode, PackageOpen as default };\n//# sourceMappingURL=package-open.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n 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\",\n key: \"w46dr5\"\n }\n ]\n];\nconst Puzzle = createLucideIcon(\"puzzle\", __iconNode);\n\nexport { __iconNode, Puzzle as default };\n//# sourceMappingURL=puzzle.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"8\", y2: \"12\", key: \"1pkeuh\" }],\n [\"line\", { x1: \"12\", x2: \"12.01\", y1: \"16\", y2: \"16\", key: \"4dfq90\" }]\n];\nconst CircleAlert = createLucideIcon(\"circle-alert\", __iconNode);\n\nexport { __iconNode, CircleAlert as default };\n//# sourceMappingURL=circle-alert.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M3 5h.01\", key: \"18ugdj\" }],\n [\"path\", { d: \"M3 12h.01\", key: \"nlz23k\" }],\n [\"path\", { d: \"M3 19h.01\", key: \"noohij\" }],\n [\"path\", { d: \"M8 5h13\", key: \"1pao27\" }],\n [\"path\", { d: \"M8 12h13\", key: \"1za7za\" }],\n [\"path\", { d: \"M8 19h13\", key: \"m83p4d\" }]\n];\nconst List = createLucideIcon(\"list\", __iconNode);\n\nexport { __iconNode, List as default };\n//# sourceMappingURL=list.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n 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\",\n key: \"1kt360\"\n }\n ]\n];\nconst Folder = createLucideIcon(\"folder\", __iconNode);\n\nexport { __iconNode, Folder as default };\n//# sourceMappingURL=folder.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [[\"path\", { d: \"m6 9 6 6 6-6\", key: \"qrunsl\" }]];\nconst ChevronDown = createLucideIcon(\"chevron-down\", __iconNode);\n\nexport { __iconNode, ChevronDown as default };\n//# sourceMappingURL=chevron-down.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [[\"path\", { d: \"m9 18 6-6-6-6\", key: \"mthhwq\" }]];\nconst ChevronRight = createLucideIcon(\"chevron-right\", __iconNode);\n\nexport { __iconNode, ChevronRight as default };\n//# sourceMappingURL=chevron-right.mjs.map\n","export const projectPopoverEnabledCount = (entries) => entries.filter(entry => entry.effectiveEnabled).length;\nexport const projectPopoverRow = (entry, busy = false) => ({\n checked: entry.effectiveEnabled,\n disabled: busy || entry.globalEnabled,\n badge: entry.globalEnabled ? '全局' : null,\n checkboxTitle: entry.globalEnabled ? '全局已启用,请到 Skill 管理关闭' : '项目启用',\n});\n","export const projectRootForSession = (state, sessionId) => state.byId[sessionId]?.cwd;\n","import { createElement as h, useCallback, useEffect, useRef, useState } from 'react';\nimport Wrench from 'lucide-react/dist/esm/icons/wrench.mjs';\nimport Plus from 'lucide-react/dist/esm/icons/plus.mjs';\nimport RefreshCw from 'lucide-react/dist/esm/icons/refresh-cw.mjs';\nimport Search from 'lucide-react/dist/esm/icons/search.mjs';\nimport X from 'lucide-react/dist/esm/icons/x.mjs';\nimport Trash2 from 'lucide-react/dist/esm/icons/trash-2.mjs';\nimport Globe from 'lucide-react/dist/esm/icons/globe.mjs';\nimport FolderGit from 'lucide-react/dist/esm/icons/folder-git.mjs';\nimport GitBranch from 'lucide-react/dist/esm/icons/git-branch.mjs';\nimport PackageOpen from 'lucide-react/dist/esm/icons/package-open.mjs';\nimport Puzzle from 'lucide-react/dist/esm/icons/puzzle.mjs';\nimport AlertCircle from 'lucide-react/dist/esm/icons/alert-circle.mjs';\nimport List from 'lucide-react/dist/esm/icons/list.mjs';\nimport Folder from 'lucide-react/dist/esm/icons/folder.mjs';\nimport ChevronDown from 'lucide-react/dist/esm/icons/chevron-down.mjs';\nimport ChevronRight from 'lucide-react/dist/esm/icons/chevron-right.mjs';\nimport { projectPopoverEnabledCount, projectPopoverRow } from './popover.js';\nimport { projectRootForSession } from './session.js';\nexport const inject = ['connection', 'slots', 'workspaces'];\nconst ICON_SPIN = ['dsh-skill-manager-spin', 'to { transform: rotate(360deg); }'];\nfunction ensureKeyframes() {\n if (typeof document === 'undefined')\n return;\n if (document.getElementById(ICON_SPIN[0]))\n return;\n const style = document.createElement('style');\n style.id = ICON_SPIN[0];\n style.textContent = `\n @keyframes ${ICON_SPIN[0]} { ${ICON_SPIN[1]} }\n .dsh-skill-manager-row:hover {\n border-color: ${tokens.borderStrong} !important;\n background: ${tokens.surfaceHover} !important;\n }\n @container (max-width: 360px) {\n .dsh-skill-manager-row { grid-template-columns: minmax(0, 1fr) !important; }\n .dsh-skill-manager-row-icon { display: none !important; }\n .dsh-skill-manager-row-actions { grid-column: 1 !important; justify-content: flex-start !important; }\n }\n `;\n document.head.appendChild(style);\n}\nconst spinnerStyle = { animation: `${ICON_SPIN[0]} 1s linear infinite`, flex: '0 0 auto' };\nconst monoStyle = { fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace' };\nconst tokens = {\n border: 'var(--border-subtle, rgba(148, 163, 184, .22))',\n borderStrong: 'var(--border-strong, rgba(148, 163, 184, .38))',\n accent: 'var(--fg-accent, #6366f1)',\n success: 'var(--fg-success, #16a34a)',\n danger: 'var(--fg-danger, #dc2626)',\n secondary: 'var(--fg-secondary, #64748b)',\n surfaceHover: 'var(--bg-hover, rgba(148, 163, 184, .08))',\n};\nconst panelStyle = { containerType: 'inline-size', display: 'grid', gap: 18, width: '100%', minWidth: 0, maxWidth: 760, padding: '6px 0 36px' };\nfunction buttonStyle(tone, disabled) {\n const base = {\n display: 'inline-flex', alignItems: 'center', gap: 6, minHeight: 32, padding: '0 12px',\n borderRadius: 8, border: `1px solid transparent`, fontSize: 13, fontWeight: 500,\n cursor: disabled ? 'default' : 'pointer', opacity: disabled ? 0.55 : 1, whiteSpace: 'nowrap',\n transition: 'background .15s ease, border-color .15s ease',\n };\n if (tone === 'primary')\n return { ...base, background: tokens.accent, color: 'var(--fg-on-accent, #fff)', border: 'none' };\n return { ...base, background: 'transparent', color: 'inherit', border: `1px solid ${tokens.border}` };\n}\nconst iconButtonStyle = {\n display: 'grid', placeItems: 'center', width: 28, height: 28, padding: 0,\n border: 'none', borderRadius: 7, background: 'transparent', color: tokens.secondary, cursor: 'pointer',\n};\nconst inputStyle = {\n width: '100%', minHeight: 34, padding: '0 10px 0 30px', borderRadius: 8,\n border: `1px solid ${tokens.border}`, background: 'var(--bg-primary, transparent)', color: 'inherit',\n fontSize: 13, outline: 'none', boxSizing: 'border-box',\n};\nconst selectStyle = {\n minHeight: 34, maxWidth: 300, padding: '0 8px', borderRadius: 8,\n border: `1px solid ${tokens.border}`, background: 'var(--bg-primary, transparent)', color: 'inherit', fontSize: 13,\n};\nconst checkboxStyle = { width: 16, height: 16, margin: 0, accentColor: tokens.accent, flex: '0 0 auto' };\nexport function apply(ctx) {\n const connection = ctx.connection;\n const request = async (endpoint, payload = {}) => {\n const result = await connection.rpc.call('/skill-manager', endpoint, payload);\n if (!result.ok)\n throw new Error(result.error.message);\n return result.value;\n };\n const list = (projectRoot) => request('list', projectRoot ? { projectRoot } : {});\n const mutate = request;\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'skills',\n order: 35,\n label: 'Skill 管理',\n inject: () => ({ list, mutate, pickDirectory: () => ctx.workspaces.pickDirectory(), loopback: connection.isLoopback }),\n }, SkillManagerSection));\n ctx.slots.inject('conversation.input.left', () => ctx.slots.register({\n name: 'conversation.input.left',\n id: 'skill-manager',\n order: 10,\n inject: () => ({ list, mutate }),\n }, ComposerSkillButton));\n}\nfunction SkillManagerSection(props) {\n const { list, mutate, pickDirectory, loopback, useWorkspaces } = props;\n const workspaces = useWorkspaces(state => state);\n const [projectRoot, setProjectRoot] = useState(undefined);\n const [catalog, setCatalog] = useState(null);\n const [query, setQuery] = useState('');\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState(null);\n const [repositoryOpen, setRepositoryOpen] = useState(false);\n const [repository, setRepository] = useState('');\n const [view, setView] = useState('flat');\n const [collapsed, setCollapsed] = useState({});\n useEffect(() => { ensureKeyframes(); }, []);\n // 追踪用户是否主动选过「只看全局」,避免 useEffect 把它重置回第一个工作区\n const userChoseGlobal = useRef(false);\n useEffect(() => {\n // 仅当用户未主动选择「只看全局」时,才自动选中第一个工作区\n if (projectRoot === undefined && !userChoseGlobal.current && workspaces.items.length > 0)\n setProjectRoot(workspaces.items[0].path);\n // 当前选中的工作区被移除时,回退到第一个工作区\n if (projectRoot !== undefined && !workspaces.items.some(item => item.path === projectRoot))\n setProjectRoot(workspaces.items[0]?.path);\n }, [projectRoot, workspaces.items]);\n const refresh = useCallback(async () => {\n setBusy(true);\n setError(null);\n try {\n setCatalog(await list(projectRoot));\n }\n catch (reason) {\n setError(messageOf(reason));\n }\n finally {\n setBusy(false);\n }\n }, [list, projectRoot]);\n useEffect(() => { void refresh(); }, [refresh]);\n const run = useCallback(async (action) => {\n setBusy(true);\n setError(null);\n try {\n setCatalog(await action());\n return true;\n }\n catch (reason) {\n setError(messageOf(reason));\n return false;\n }\n finally {\n setBusy(false);\n }\n }, []);\n const normalizedQuery = query.trim().toLocaleLowerCase();\n const filtered = (catalog?.entries ?? []).filter(entry => normalizedQuery.length === 0 || `${entry.name} ${entry.description}`.toLocaleLowerCase().includes(normalizedQuery));\n const groups = groupBySource(filtered);\n const importSkill = async () => {\n const path = await pickDirectory();\n if (path)\n await run(() => mutate('install', { path, projectRoot }));\n };\n const importRepository = async (event) => {\n event.preventDefault();\n const source = repository.trim();\n if (!source)\n return;\n if (await run(() => mutate('install-remote', { repository: source, projectRoot }))) {\n setRepository('');\n setRepositoryOpen(false);\n }\n };\n const updateSkill = async (entry) => {\n const path = entry.updateSupported ? undefined : await pickDirectory() ?? undefined;\n if (!entry.updateSupported && !path)\n return;\n await run(() => mutate('update', { name: entry.name, path, projectRoot }));\n };\n const selectedWorkspace = workspaces.items.find(item => item.path === projectRoot);\n const rowProps = (entry) => ({\n key: entry.name,\n entry,\n projectLabel: selectedWorkspace?.title ?? '当前项目',\n projectAvailable: projectRoot !== undefined,\n busy,\n onGlobalChange: (enabled) => void run(() => mutate('set-enabled', { name: entry.name, scope: 'global', projectRoot, enabled })),\n onProjectChange: (enabled) => void run(() => mutate('set-enabled', { name: entry.name, scope: 'project', projectRoot, enabled })),\n onUpdate: () => void updateSkill(entry),\n onRemove: () => void run(() => mutate('remove', { name: entry.name, projectRoot })),\n });\n return h('div', { style: panelStyle, 'aria-busy': busy }, h('header', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 16, flexWrap: 'wrap' } }, h('div', { style: { display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 } }, h(Puzzle, { size: 20, 'aria-hidden': true }), h('h2', { style: { margin: 0, fontSize: 18, fontWeight: 600 } }, 'Skill 管理'), busy ? h(RefreshCw, { size: 14, 'aria-hidden': true, style: spinnerStyle }) : null), h('div', { style: { display: 'flex', gap: 8, flexWrap: 'wrap' } }, h('button', { type: 'button', style: buttonStyle('ghost', busy || !loopback), onClick: () => setRepositoryOpen(value => !value), disabled: busy || !loopback, title: loopback ? '从 Git 仓库导入 skill' : '仅在本机连接时可导入' }, h(GitBranch, { size: 14, 'aria-hidden': true }), '仓库'), h('button', { type: 'button', style: buttonStyle('primary', busy || !loopback), onClick: importSkill, disabled: busy || !loopback, title: loopback ? '从本机目录导入 skill' : '仅在本机连接时可导入' }, h(Plus, { size: 14, 'aria-hidden': true }), '本机'))), h('p', { style: { margin: '-8px 0 0', fontSize: 13, color: tokens.secondary, lineHeight: 1.5 } }, '从本机目录或 Git 仓库导入 skill,并按「全局」或「项目」范围启用。'), repositoryOpen ? h('form', { onSubmit: importRepository, style: { display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center' } }, h('input', {\n type: 'text',\n value: repository,\n onChange: (event) => setRepository(event.currentTarget.value),\n placeholder: 'owner/repo 或 Git URL',\n 'aria-label': 'Git 仓库地址',\n autoFocus: true,\n disabled: busy,\n style: { ...inputStyle, flex: '1 1 260px', minWidth: 0, paddingLeft: 10 },\n }), h('button', { type: 'submit', style: buttonStyle('primary', busy || !repository.trim()), disabled: busy || !repository.trim() }, h(GitBranch, { size: 14, 'aria-hidden': true }), '导入'), h('button', { type: 'button', style: iconButtonStyle, onClick: () => setRepositoryOpen(false), disabled: busy, title: '关闭仓库导入', 'aria-label': '关闭仓库导入' }, h(X, { size: 15, 'aria-hidden': true }))) : null, h('div', { style: { display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'center' } }, h('div', { style: { position: 'relative', flex: '1 1 220px', display: 'flex', alignItems: 'center' } }, h(Search, { size: 14, 'aria-hidden': true, style: { position: 'absolute', left: 9, color: tokens.secondary, pointerEvents: 'none' } }), h('input', { type: 'search', value: query, placeholder: '搜索 skill…', 'aria-label': '搜索 skill', onChange: (event) => setQuery(event.currentTarget.value), style: inputStyle })), h('label', { style: { display: 'flex', flex: '1 1 220px', minWidth: 0, alignItems: 'center', gap: 8, fontSize: 13, color: tokens.secondary } }, h('span', { style: { flex: '0 0 auto' } }, '项目范围'), h('select', { value: projectRoot ?? '__global__', onChange: (event) => { const value = event.currentTarget.value; if (value === '__global__') {\n userChoseGlobal.current = true;\n setProjectRoot(undefined);\n }\n else {\n userChoseGlobal.current = false;\n setProjectRoot(value);\n } }, style: { ...selectStyle, flex: '1 1 auto', minWidth: 0, maxWidth: 'none' } }, h('option', { value: '__global__' }, '只看全局'), ...workspaces.items.map(workspace => h('option', { key: workspace.workspaceId, value: workspace.path }, workspace.title)))), h('div', { role: 'group', 'aria-label': '视图切换', style: { display: 'flex', flex: '0 0 auto', border: `1px solid ${tokens.border}`, borderRadius: 8, overflow: 'hidden' } }, h('button', { type: 'button', onClick: () => setView('flat'), 'aria-pressed': view === 'flat', title: '平铺列表', style: { ...iconButtonStyle, width: 32, height: 32, borderRadius: 0, color: view === 'flat' ? tokens.accent : tokens.secondary, background: view === 'flat' ? 'rgba(99, 102, 241, .12)' : 'transparent' } }, h(List, { size: 15, 'aria-hidden': true })), h('button', { type: 'button', onClick: () => setView('grouped'), 'aria-pressed': view === 'grouped', title: '按来源仓库分组', style: { ...iconButtonStyle, width: 32, height: 32, borderRadius: 0, color: view === 'grouped' ? tokens.accent : tokens.secondary, background: view === 'grouped' ? 'rgba(99, 102, 241, .12)' : 'transparent' } }, h(Folder, { size: 15, 'aria-hidden': true })))), error ? h('div', { role: 'alert', style: { display: 'flex', gap: 8, alignItems: 'center', margin: 0, padding: '9px 12px', borderRadius: 8, fontSize: 13, color: tokens.danger, background: 'rgba(220, 38, 38, .08)', border: '1px solid rgba(220, 38, 38, .28)' } }, h(AlertCircle, { size: 15, 'aria-hidden': true }), error) : null, h('section', { style: { display: 'grid', width: '100%', minWidth: 0, gap: 8 }, 'aria-label': '已安装 skill' }, catalog === null\n ? h('p', { style: { margin: 0, padding: '24px 0', textAlign: 'center', fontSize: 13, color: tokens.secondary } }, '正在读取…')\n : filtered.length === 0\n ? h(EmptyState, { hasAny: (catalog.entries.length ?? 0) > 0 })\n : view === 'flat'\n ? filtered.map(entry => h(SkillRow, rowProps(entry)))\n : groups.map(group => h('div', { key: group.key, style: { display: 'grid', gap: 8 } }, h('button', {\n type: 'button',\n onClick: () => setCollapsed(prev => ({ ...prev, [group.key]: !prev[group.key] })),\n 'aria-expanded': !collapsed[group.key],\n style: { display: 'flex', alignItems: 'center', gap: 8, padding: '6px 4px', border: 'none', background: 'transparent', color: 'inherit', cursor: 'pointer', fontSize: 13, fontWeight: 600, textAlign: 'left' },\n }, collapsed[group.key] ? h(ChevronRight, { size: 14, 'aria-hidden': true, style: { color: tokens.secondary, flex: '0 0 auto' } }) : h(ChevronDown, { size: 14, 'aria-hidden': true, style: { color: tokens.secondary, flex: '0 0 auto' } }), h(GitBranch, { size: 13, 'aria-hidden': true, style: { color: tokens.secondary, flex: '0 0 auto' } }), h('span', { title: group.key === '__local__' ? undefined : group.key, style: { ...monoStyle, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, group.label), h('span', { style: { color: tokens.secondary, fontWeight: 400, flex: '0 0 auto' } }, `${group.entries.length} 个`)), collapsed[group.key] ? null : group.entries.map(entry => h(SkillRow, rowProps(entry)))))));\n}\nfunction groupBySource(entries) {\n const groups = new Map();\n for (const entry of entries) {\n const key = entry.sourceType === 'git' && entry.sourceUrl ? entry.sourceUrl : '__local__';\n const label = key === '__local__' ? '本机导入' : shortRepoLabel(key);\n const group = groups.get(key) ?? { label, entries: [] };\n group.entries.push(entry);\n groups.set(key, group);\n }\n return [...groups.entries()]\n .map(([key, group]) => ({ key, label: group.label, entries: group.entries }))\n .sort((a, b) => (a.key === '__local__' ? 1 : b.key === '__local__' ? -1 : a.label.localeCompare(b.label)));\n}\nfunction shortRepoLabel(url) {\n const match = /^(?:https?:\\/\\/|git@|ssh:\\/\\/git@)?([^/:]+)[:/]([^/]+\\/[^/]+?)(?:\\.git)?\\/?$/.exec(url);\n return match ? `${match[2]} (${match[1]})` : url;\n}\nfunction EmptyState(props) {\n return h('div', { style: { display: 'grid', justifyItems: 'center', gap: 8, padding: '36px 16px', borderRadius: 10, border: `1px dashed ${tokens.borderStrong}`, color: tokens.secondary, textAlign: 'center' } }, h(PackageOpen, { size: 26, 'aria-hidden': true }), h('p', { style: { margin: 0, fontSize: 13, lineHeight: 1.5 } }, props.hasAny ? '没有匹配的 skill,试试调整搜索词。' : '还没有导入任何 skill。点击右上角「导入」,从本机目录开始。'));\n}\nfunction ComposerSkillButton(props) {\n const { session, useSessions, list, mutate } = props;\n const projectRoot = useSessions(state => projectRootForSession(state, session.sessionId));\n const [open, setOpen] = useState(false);\n const containerRef = useRef(null);\n useEffect(() => {\n if (!open)\n return;\n const onPointerDown = (event) => {\n if (containerRef.current && event.target instanceof Node && !containerRef.current.contains(event.target))\n setOpen(false);\n };\n const onKeyDown = (event) => { if (event.key === 'Escape')\n setOpen(false); };\n document.addEventListener('pointerdown', onPointerDown);\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('pointerdown', onPointerDown);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [open]);\n return h('div', { ref: containerRef, style: { position: 'relative', display: 'inline-flex', marginLeft: -25 } }, h('button', {\n type: 'button',\n title: projectRoot ? '配置当前项目的 Skill' : '当前会话没有工作区',\n 'aria-label': '配置当前项目的 Skill',\n 'aria-expanded': open,\n disabled: !projectRoot,\n onClick: () => setOpen(value => !value),\n style: {\n display: 'grid',\n placeItems: 'center',\n flex: '0 0 auto',\n width: 28,\n height: 28,\n padding: 0,\n border: 'none',\n borderRadius: 999,\n background: open ? 'var(--dsw-alias-bg-active, rgba(255, 255, 255, .16))' : 'var(--dsw-specific-selector, rgba(255, 255, 255, .08))',\n color: 'var(--dsw-alias-label-primary, inherit)',\n cursor: projectRoot ? 'pointer' : 'default',\n opacity: projectRoot ? 1 : 0.5,\n },\n }, h(Wrench, { size: 16, 'aria-hidden': true })), open && projectRoot ? h(ProjectSkillPopover, { projectRoot, list, mutate, onClose: () => setOpen(false) }) : null);\n}\nfunction ProjectSkillPopover(props) {\n const { projectRoot, list, mutate, onClose } = props;\n const theme = currentThemeColors();\n const [catalog, setCatalog] = useState(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState(null);\n useEffect(() => { ensureKeyframes(); }, []);\n const refresh = useCallback(async () => {\n setBusy(true);\n setError(null);\n try {\n setCatalog(await list(projectRoot));\n }\n catch (reason) {\n setError(messageOf(reason));\n }\n finally {\n setBusy(false);\n }\n }, [list, projectRoot]);\n useEffect(() => { void refresh(); }, [refresh]);\n const toggle = async (entry, enabled) => {\n setBusy(true);\n setError(null);\n try {\n setCatalog(await mutate('set-enabled', { name: entry.name, scope: 'project', projectRoot, enabled }));\n }\n catch (reason) {\n setError(messageOf(reason));\n }\n finally {\n setBusy(false);\n }\n };\n const enabledCount = projectPopoverEnabledCount(catalog?.entries ?? []);\n return h('section', { style: { position: 'absolute', zIndex: 50, left: 0, bottom: 40, width: 320, display: 'grid', gap: 6, padding: 12, border: `1px solid ${tokens.borderStrong}`, borderRadius: 12, background: theme.background, color: theme.color, boxShadow: '0 16px 40px rgba(0, 0, 0, .4)' }, 'aria-label': '当前项目 Skill' }, h('header', { style: { display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'center', paddingBottom: 4 } }, h('div', { style: { display: 'flex', alignItems: 'center', gap: 7, minWidth: 0 } }, h(FolderGit, { size: 14, 'aria-hidden': true, style: { color: tokens.secondary, flex: '0 0 auto' } }), h('strong', { style: { fontSize: 13, fontWeight: 600 } }, '项目 Skill'), h('span', { style: { fontSize: 12, color: tokens.secondary } }, `${enabledCount}/${catalog?.entries.length ?? 0} 已启用`)), h('button', { type: 'button', onClick: onClose, style: iconButtonStyle, 'aria-label': '关闭项目 Skill', title: '关闭' }, h(X, { size: 14, 'aria-hidden': true }))), error ? h('div', { role: 'alert', style: { display: 'flex', gap: 6, alignItems: 'center', margin: 0, padding: '7px 9px', borderRadius: 7, fontSize: 12, color: tokens.danger, background: 'rgba(220, 38, 38, .08)' } }, h(AlertCircle, { size: 13, 'aria-hidden': true }), error) : null, h('div', { style: { display: 'grid', gap: 1, maxHeight: 280, overflowY: 'auto', margin: '0 -4px', padding: '0 4px' } }, catalog === null\n ? h('p', { style: { margin: 0, padding: '18px 0', textAlign: 'center', fontSize: 12, color: tokens.secondary } }, '正在读取…')\n : catalog.entries.length === 0\n ? h('p', { style: { margin: 0, padding: '18px 0', textAlign: 'center', fontSize: 12, color: tokens.secondary } }, '未导入 skill。请到「设置 → Skill 管理」导入。')\n : catalog.entries.map(entry => {\n const row = projectPopoverRow(entry, busy);\n return h('label', { key: entry.name, style: { display: 'grid', gridTemplateColumns: '14px minmax(0, 1fr) 30px', gap: 8, alignItems: 'center', padding: '7px 6px', borderRadius: 7, fontSize: 13, cursor: row.disabled ? 'default' : 'pointer' }, title: entry.description || entry.name }, h(Puzzle, { size: 13, 'aria-hidden': true, style: { color: entry.effectiveEnabled ? tokens.accent : tokens.secondary } }), h('div', { style: { display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 } }, h('span', { style: { minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, entry.name), row.badge ? h(StatusBadge, { active: true, icon: Globe, label: row.badge }) : null), h('input', { type: 'checkbox', checked: row.checked, disabled: row.disabled, onChange: (event) => void toggle(entry, event.currentTarget.checked), 'aria-label': `${entry.name} 项目开关`, title: row.checkboxTitle, style: checkboxStyle }));\n })), busy ? h('div', { style: { display: 'flex', justifyContent: 'flex-end', paddingTop: 2 } }, h(RefreshCw, { size: 12, 'aria-hidden': true, style: spinnerStyle })) : null);\n}\nfunction SkillRow(props) {\n const { entry, projectLabel, projectAvailable, busy, onGlobalChange, onProjectChange, onUpdate, onRemove } = props;\n return h('article', {\n className: 'dsh-skill-manager-row',\n style: {\n display: 'grid', gridTemplateColumns: '32px minmax(0, 1fr)', gap: 12, alignItems: 'center',\n width: '100%', minWidth: 0, maxWidth: '100%', overflow: 'hidden', boxSizing: 'border-box',\n padding: '12px 14px', borderRadius: 10, border: `1px solid ${tokens.border}`,\n background: 'transparent', transition: 'border-color .15s ease, background .15s ease',\n },\n }, h('div', { className: 'dsh-skill-manager-row-icon', style: { display: 'grid', placeItems: 'center', width: 32, height: 32, borderRadius: 8, color: entry.effectiveEnabled ? tokens.accent : tokens.secondary, background: entry.effectiveEnabled ? 'rgba(99, 102, 241, .1)' : 'rgba(148, 163, 184, .1)' } }, h(Puzzle, { size: 16, 'aria-hidden': true })), h('div', { style: { minWidth: 0, display: 'grid', gap: 4 } }, h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, minWidth: 0, flexWrap: 'wrap' } }, h('strong', { style: { ...monoStyle, fontSize: 13, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, entry.name), h(SourceBadge, { entry }), h(StatusBadge, { active: entry.globalEnabled, icon: Globe, label: '全局' }), projectAvailable ? h(StatusBadge, { active: entry.projectEnabled, icon: FolderGit, label: projectLabel }) : null), entry.description ? h('p', { style: { margin: 0, color: tokens.secondary, lineHeight: 1.45, fontSize: 12.5, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' } }, entry.description) : null), h('div', { className: 'dsh-skill-manager-row-actions', style: { gridColumn: '1 / -1', display: 'flex', width: '100%', minWidth: 0, justifyContent: 'flex-end', alignItems: 'center', gap: 10, flexWrap: 'wrap' } }, h('input', { type: 'checkbox', checked: entry.globalEnabled, disabled: busy, onChange: (event) => onGlobalChange(event.currentTarget.checked), 'aria-label': `${entry.name} 全局开关`, title: '全局启用', style: checkboxStyle }), projectAvailable ? h('input', { type: 'checkbox', checked: entry.projectEnabled, disabled: busy, onChange: (event) => onProjectChange(event.currentTarget.checked), 'aria-label': `${entry.name} 项目开关`, title: `${projectLabel} 启用`, style: checkboxStyle }) : null, h('button', { type: 'button', style: { ...iconButtonStyle, color: tokens.secondary }, disabled: busy, onClick: onUpdate, title: entry.updateSupported ? (entry.sourceType === 'git' ? '从远程仓库更新' : '从原始目录更新') : '选择来源目录并更新', 'aria-label': `更新 ${entry.name}` }, h(RefreshCw, { size: 15, 'aria-hidden': true })), h('button', { type: 'button', style: { ...iconButtonStyle, color: tokens.danger }, disabled: busy, onClick: onRemove, title: '从库中移除', 'aria-label': `移除 ${entry.name}` }, h(Trash2, { size: 15, 'aria-hidden': true }))));\n}\nfunction SourceBadge(props) {\n const remote = props.entry.sourceType === 'git';\n const local = props.entry.sourceType === 'local';\n const Icon = remote ? GitBranch : local ? FolderGit : AlertCircle;\n const label = remote ? 'Git' : local ? '本机' : '未知';\n const title = remote ? props.entry.sourceUrl : local ? props.entry.sourcePath : '来源未知,更新时需选择本机来源目录';\n return h('span', {\n title,\n style: {\n display: 'inline-flex', alignItems: 'center', gap: 4, flex: '0 1 auto', maxWidth: '100%', overflow: 'hidden',\n padding: '2px 6px', borderRadius: 999, fontSize: 11, lineHeight: '16px', whiteSpace: 'nowrap',\n color: tokens.secondary, background: 'rgba(148, 163, 184, .09)',\n },\n }, h(Icon, { size: 11, 'aria-hidden': true }), label);\n}\nfunction StatusBadge(props) {\n const Icon = props.icon;\n return h('span', {\n title: props.active ? `${props.label}已启用` : `${props.label}未启用`,\n style: {\n display: 'inline-flex', alignItems: 'center', gap: 4, flex: '0 1 auto', maxWidth: '100%', overflow: 'hidden',\n padding: '2px 6px', borderRadius: 999, fontSize: 11, lineHeight: '16px', whiteSpace: 'nowrap',\n color: props.active ? tokens.success : tokens.secondary,\n background: props.active ? 'rgba(22, 163, 74, .1)' : 'rgba(148, 163, 184, .09)',\n border: `1px solid ${props.active ? 'rgba(22, 163, 74, .3)' : 'transparent'}`,\n },\n }, h(Icon, { size: 11, 'aria-hidden': true }), props.active ? `${props.label}开` : `${props.label}关`);\n}\nfunction currentThemeColors() {\n if (typeof document === 'undefined')\n return { background: '#151517', color: '#f9fafb' };\n const style = getComputedStyle(document.body);\n return {\n background: style.backgroundColor || '#151517',\n color: style.color || '#f9fafb',\n };\n}\nfunction messageOf(reason) {\n return reason instanceof Error ? reason.message : String(reason);\n}\n"],"x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","AlertCircle","Icon"],"sources":["../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toKebabCase.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toCamelCase.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/toPascalCase.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/defaultAttributes.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/hasA11yProp.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/context.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/Icon.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/createLucideIcon.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/wrench.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/plus.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/refresh-cw.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/search.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/x.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/trash-2.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/globe.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/folder-git.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/git-branch.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/package-open.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/puzzle.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/circle-alert.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/list.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/folder.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/chevron-down.mjs","../node_modules/.pnpm/lucide-react@1.31.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/chevron-right.mjs","types/client/popover.js","types/client/session.js","types/client/index.js"],"sourcesContent":["/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst mergeClasses = (...classes) => classes.filter((className, index, array) => {\n return Boolean(className) && className.trim() !== \"\" && array.indexOf(className) === index;\n}).join(\" \").trim();\n\nexport { mergeClasses };\n//# sourceMappingURL=mergeClasses.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\n\nexport { toKebabCase };\n//# sourceMappingURL=toKebabCase.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toCamelCase = (string) => string.replace(\n /^([A-Z])|[\\s-_]+(\\w)/g,\n (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()\n);\n\nexport { toCamelCase };\n//# sourceMappingURL=toCamelCase.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { toCamelCase } from './toCamelCase.mjs';\n\nconst toPascalCase = (string) => {\n const camelCase = toCamelCase(string);\n return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);\n};\n\nexport { toPascalCase };\n//# sourceMappingURL=toPascalCase.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nvar defaultAttributes = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 24,\n height: 24,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\"\n};\n\nexport { defaultAttributes as default };\n//# sourceMappingURL=defaultAttributes.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst hasA11yProp = (props) => {\n for (const prop in props) {\n if (prop.startsWith(\"aria-\") || prop === \"role\" || prop === \"title\") {\n return true;\n }\n }\n return false;\n};\n\nexport { hasA11yProp };\n//# sourceMappingURL=hasA11yProp.mjs.map\n","\"use strict\";\n\"use client\";\n/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { createContext, useContext, useMemo, createElement } from 'react';\n\nconst LucideContext = createContext({});\nfunction LucideProvider({\n children,\n size,\n color,\n strokeWidth,\n absoluteStrokeWidth,\n className\n}) {\n const value = useMemo(\n () => ({\n size,\n color,\n strokeWidth,\n absoluteStrokeWidth,\n className\n }),\n [size, color, strokeWidth, absoluteStrokeWidth, className]\n );\n return createElement(LucideContext.Provider, { value }, children);\n}\nconst useLucideContext = () => useContext(LucideContext);\n\nexport { LucideProvider, useLucideContext };\n//# sourceMappingURL=context.mjs.map\n","\"use strict\";\n\"use client\";\n/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport defaultAttributes from './defaultAttributes.mjs';\nimport { hasA11yProp } from './shared/src/utils/hasA11yProp.mjs';\nimport { mergeClasses } from './shared/src/utils/mergeClasses.mjs';\nimport { useLucideContext } from './context.mjs';\n\nconst Icon = forwardRef(\n ({ color, size, strokeWidth, absoluteStrokeWidth, className = \"\", children, iconNode, ...rest }, ref) => {\n const {\n size: contextSize = 24,\n strokeWidth: contextStrokeWidth = 2,\n absoluteStrokeWidth: contextAbsoluteStrokeWidth = false,\n color: contextColor = \"currentColor\",\n className: contextClass = \"\"\n } = useLucideContext() ?? {};\n const calculatedStrokeWidth = absoluteStrokeWidth ?? contextAbsoluteStrokeWidth ? Number(strokeWidth ?? contextStrokeWidth) * 24 / Number(size ?? contextSize) : strokeWidth ?? contextStrokeWidth;\n return createElement(\n \"svg\",\n {\n ref,\n ...defaultAttributes,\n width: size ?? contextSize ?? defaultAttributes.width,\n height: size ?? contextSize ?? defaultAttributes.height,\n stroke: color ?? contextColor,\n strokeWidth: calculatedStrokeWidth,\n className: mergeClasses(\"lucide\", contextClass, className),\n ...!children && !hasA11yProp(rest) && { \"aria-hidden\": \"true\" },\n ...rest\n },\n [\n ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),\n ...Array.isArray(children) ? children : [children]\n ]\n );\n }\n);\n\nexport { Icon as default };\n//# sourceMappingURL=Icon.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport { mergeClasses } from './shared/src/utils/mergeClasses.mjs';\nimport { toKebabCase } from './shared/src/utils/toKebabCase.mjs';\nimport { toPascalCase } from './shared/src/utils/toPascalCase.mjs';\nimport Icon from './Icon.mjs';\n\nconst createLucideIcon = (iconName, iconNode) => {\n const Component = forwardRef(\n ({ className, ...props }, ref) => createElement(Icon, {\n ref,\n iconNode,\n className: mergeClasses(\n `lucide-${toKebabCase(toPascalCase(iconName))}`,\n `lucide-${iconName}`,\n className\n ),\n ...props\n })\n );\n Component.displayName = toPascalCase(iconName);\n return Component;\n};\n\nexport { createLucideIcon as default };\n//# sourceMappingURL=createLucideIcon.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n 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\",\n key: \"1ngwbx\"\n }\n ]\n];\nconst Wrench = createLucideIcon(\"wrench\", __iconNode);\n\nexport { __iconNode, Wrench as default };\n//# sourceMappingURL=wrench.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M5 12h14\", key: \"1ays0h\" }],\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }]\n];\nconst Plus = createLucideIcon(\"plus\", __iconNode);\n\nexport { __iconNode, Plus as default };\n//# sourceMappingURL=plus.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\", key: \"v9h5vc\" }],\n [\"path\", { d: \"M21 3v5h-5\", key: \"1q7to0\" }],\n [\"path\", { d: \"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\", key: \"3uifl3\" }],\n [\"path\", { d: \"M8 16H3v5\", key: \"1cv678\" }]\n];\nconst RefreshCw = createLucideIcon(\"refresh-cw\", __iconNode);\n\nexport { __iconNode, RefreshCw as default };\n//# sourceMappingURL=refresh-cw.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"m21 21-4.34-4.34\", key: \"14j7rj\" }],\n [\"circle\", { cx: \"11\", cy: \"11\", r: \"8\", key: \"4ej97u\" }]\n];\nconst Search = createLucideIcon(\"search\", __iconNode);\n\nexport { __iconNode, Search as default };\n//# sourceMappingURL=search.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M18 6 6 18\", key: \"1bl5f8\" }],\n [\"path\", { d: \"m6 6 12 12\", key: \"d8bk6v\" }]\n];\nconst X = createLucideIcon(\"x\", __iconNode);\n\nexport { __iconNode, X as default };\n//# sourceMappingURL=x.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M10 11v6\", key: \"nco0om\" }],\n [\"path\", { d: \"M14 11v6\", key: \"outv1u\" }],\n [\"path\", { d: \"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\", key: \"miytrc\" }],\n [\"path\", { d: \"M3 6h18\", key: \"d0wm0j\" }],\n [\"path\", { d: \"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\", key: \"e791ji\" }]\n];\nconst Trash2 = createLucideIcon(\"trash-2\", __iconNode);\n\nexport { __iconNode, Trash2 as default };\n//# sourceMappingURL=trash-2.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20\", key: \"13o1zl\" }],\n [\"path\", { d: \"M2 12h20\", key: \"9i4pu4\" }]\n];\nconst Globe = createLucideIcon(\"globe\", __iconNode);\n\nexport { __iconNode, Globe as default };\n//# sourceMappingURL=globe.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"13\", r: \"2\", key: \"1c1ljs\" }],\n [\n \"path\",\n {\n 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\",\n key: \"1kt360\"\n }\n ],\n [\"path\", { d: \"M14 13h3\", key: \"1dgedf\" }],\n [\"path\", { d: \"M7 13h3\", key: \"1pygq7\" }]\n];\nconst FolderGit = createLucideIcon(\"folder-git\", __iconNode);\n\nexport { __iconNode, FolderGit as default };\n//# sourceMappingURL=folder-git.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M15 6a9 9 0 0 0-9 9V3\", key: \"1cii5b\" }],\n [\"circle\", { cx: \"18\", cy: \"6\", r: \"3\", key: \"1h7g24\" }],\n [\"circle\", { cx: \"6\", cy: \"18\", r: \"3\", key: \"fqmcym\" }]\n];\nconst GitBranch = createLucideIcon(\"git-branch\", __iconNode);\n\nexport { __iconNode, GitBranch as default };\n//# sourceMappingURL=git-branch.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 22v-9\", key: \"x3hkom\" }],\n [\n \"path\",\n {\n 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\",\n key: \"2ntwy6\"\n }\n ],\n [\n \"path\",\n {\n 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\",\n key: \"1pmm1c\"\n }\n ],\n [\n \"path\",\n {\n 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\",\n key: \"12ttoo\"\n }\n ]\n];\nconst PackageOpen = createLucideIcon(\"package-open\", __iconNode);\n\nexport { __iconNode, PackageOpen as default };\n//# sourceMappingURL=package-open.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n 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\",\n key: \"w46dr5\"\n }\n ]\n];\nconst Puzzle = createLucideIcon(\"puzzle\", __iconNode);\n\nexport { __iconNode, Puzzle as default };\n//# sourceMappingURL=puzzle.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"8\", y2: \"12\", key: \"1pkeuh\" }],\n [\"line\", { x1: \"12\", x2: \"12.01\", y1: \"16\", y2: \"16\", key: \"4dfq90\" }]\n];\nconst CircleAlert = createLucideIcon(\"circle-alert\", __iconNode);\n\nexport { __iconNode, CircleAlert as default };\n//# sourceMappingURL=circle-alert.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M3 5h.01\", key: \"18ugdj\" }],\n [\"path\", { d: \"M3 12h.01\", key: \"nlz23k\" }],\n [\"path\", { d: \"M3 19h.01\", key: \"noohij\" }],\n [\"path\", { d: \"M8 5h13\", key: \"1pao27\" }],\n [\"path\", { d: \"M8 12h13\", key: \"1za7za\" }],\n [\"path\", { d: \"M8 19h13\", key: \"m83p4d\" }]\n];\nconst List = createLucideIcon(\"list\", __iconNode);\n\nexport { __iconNode, List as default };\n//# sourceMappingURL=list.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n 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\",\n key: \"1kt360\"\n }\n ]\n];\nconst Folder = createLucideIcon(\"folder\", __iconNode);\n\nexport { __iconNode, Folder as default };\n//# sourceMappingURL=folder.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [[\"path\", { d: \"m6 9 6 6 6-6\", key: \"qrunsl\" }]];\nconst ChevronDown = createLucideIcon(\"chevron-down\", __iconNode);\n\nexport { __iconNode, ChevronDown as default };\n//# sourceMappingURL=chevron-down.mjs.map\n","/**\n * @license lucide-react v1.31.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [[\"path\", { d: \"m9 18 6-6-6-6\", key: \"mthhwq\" }]];\nconst ChevronRight = createLucideIcon(\"chevron-right\", __iconNode);\n\nexport { __iconNode, ChevronRight as default };\n//# sourceMappingURL=chevron-right.mjs.map\n","export const projectPopoverEnabledCount = (entries) => entries.filter(entry => entry.effectiveEnabled).length;\nexport const projectPopoverRow = (entry, busy = false) => ({\n checked: entry.effectiveEnabled,\n disabled: busy || entry.globalEnabled,\n badge: entry.globalEnabled ? '全局' : null,\n checkboxTitle: entry.globalEnabled ? '全局已启用,请到 Skill 管理关闭' : '项目启用',\n});\n","export const projectRootForSession = (state, sessionId) => state.byId[sessionId]?.cwd;\n","import { createElement as h, useCallback, useEffect, useRef, useState } from 'react';\nimport Wrench from 'lucide-react/dist/esm/icons/wrench.mjs';\nimport Plus from 'lucide-react/dist/esm/icons/plus.mjs';\nimport RefreshCw from 'lucide-react/dist/esm/icons/refresh-cw.mjs';\nimport Search from 'lucide-react/dist/esm/icons/search.mjs';\nimport X from 'lucide-react/dist/esm/icons/x.mjs';\nimport Trash2 from 'lucide-react/dist/esm/icons/trash-2.mjs';\nimport Globe from 'lucide-react/dist/esm/icons/globe.mjs';\nimport FolderGit from 'lucide-react/dist/esm/icons/folder-git.mjs';\nimport GitBranch from 'lucide-react/dist/esm/icons/git-branch.mjs';\nimport PackageOpen from 'lucide-react/dist/esm/icons/package-open.mjs';\nimport Puzzle from 'lucide-react/dist/esm/icons/puzzle.mjs';\nimport AlertCircle from 'lucide-react/dist/esm/icons/alert-circle.mjs';\nimport List from 'lucide-react/dist/esm/icons/list.mjs';\nimport Folder from 'lucide-react/dist/esm/icons/folder.mjs';\nimport ChevronDown from 'lucide-react/dist/esm/icons/chevron-down.mjs';\nimport ChevronRight from 'lucide-react/dist/esm/icons/chevron-right.mjs';\nimport { projectPopoverEnabledCount, projectPopoverRow } from './popover.js';\nimport { projectRootForSession } from './session.js';\nexport const inject = ['connection', 'slots', 'workspaces'];\nconst ICON_SPIN = ['dsh-skill-manager-spin', 'to { transform: rotate(360deg); }'];\nfunction ensureKeyframes() {\n if (typeof document === 'undefined')\n return;\n if (document.getElementById(ICON_SPIN[0]))\n return;\n const style = document.createElement('style');\n style.id = ICON_SPIN[0];\n style.textContent = `\n @keyframes ${ICON_SPIN[0]} { ${ICON_SPIN[1]} }\n .dsh-skill-manager-row:hover {\n border-color: ${tokens.borderStrong} !important;\n background: ${tokens.surfaceHover} !important;\n }\n @container (max-width: 360px) {\n .dsh-skill-manager-row { grid-template-columns: minmax(0, 1fr) !important; }\n .dsh-skill-manager-row-icon { display: none !important; }\n .dsh-skill-manager-row-actions { grid-column: 1 !important; justify-content: flex-start !important; }\n }\n `;\n document.head.appendChild(style);\n}\nconst spinnerStyle = { animation: `${ICON_SPIN[0]} 1s linear infinite`, flex: '0 0 auto' };\nconst monoStyle = { fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace' };\nconst tokens = {\n border: 'var(--border-subtle, rgba(148, 163, 184, .22))',\n borderStrong: 'var(--border-strong, rgba(148, 163, 184, .38))',\n accent: 'var(--fg-accent, #6366f1)',\n success: 'var(--fg-success, #16a34a)',\n danger: 'var(--fg-danger, #dc2626)',\n secondary: 'var(--fg-secondary, #64748b)',\n surfaceHover: 'var(--bg-hover, rgba(148, 163, 184, .08))',\n};\nconst panelStyle = { containerType: 'inline-size', display: 'grid', gap: 18, width: '100%', minWidth: 0, maxWidth: 760, padding: '6px 0 36px' };\nfunction buttonStyle(tone, disabled) {\n const base = {\n display: 'inline-flex', alignItems: 'center', gap: 6, minHeight: 32, padding: '0 12px',\n borderRadius: 8, border: `1px solid transparent`, fontSize: 13, fontWeight: 500,\n cursor: disabled ? 'default' : 'pointer', opacity: disabled ? 0.55 : 1, whiteSpace: 'nowrap',\n transition: 'background .15s ease, border-color .15s ease',\n };\n if (tone === 'primary')\n return { ...base, background: tokens.accent, color: 'var(--fg-on-accent, #fff)', border: 'none' };\n return { ...base, background: 'transparent', color: 'inherit', border: `1px solid ${tokens.border}` };\n}\nconst iconButtonStyle = {\n display: 'grid', placeItems: 'center', width: 28, height: 28, padding: 0,\n border: 'none', borderRadius: 7, background: 'transparent', color: tokens.secondary, cursor: 'pointer',\n};\nconst inputStyle = {\n width: '100%', minHeight: 34, padding: '0 10px 0 30px', borderRadius: 8,\n border: `1px solid ${tokens.border}`, background: 'var(--bg-primary, transparent)', color: 'inherit',\n fontSize: 13, outline: 'none', boxSizing: 'border-box',\n};\nconst selectStyle = {\n minHeight: 34, maxWidth: 300, padding: '0 8px', borderRadius: 8,\n border: `1px solid ${tokens.border}`, background: 'var(--bg-primary, transparent)', color: 'inherit', fontSize: 13,\n};\nconst checkboxStyle = { width: 16, height: 16, margin: 0, accentColor: tokens.accent, flex: '0 0 auto' };\nexport function apply(ctx) {\n const connection = ctx.connection;\n const request = async (endpoint, payload = {}) => {\n const result = await connection.rpc.call('/skill-manager', endpoint, payload);\n if (!result.ok)\n throw new Error(result.error.message);\n return result.value;\n };\n const list = (projectRoot) => request('list', projectRoot ? { projectRoot } : {});\n const mutate = request;\n const checkUpdates = async () => {\n const result = await connection.rpc.call('/skill-manager', 'check-updates', {});\n if (!result.ok)\n throw new Error(result.error.message);\n return result.value;\n };\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'skills',\n order: 35,\n label: 'Skill 管理',\n inject: () => ({ list, mutate, checkUpdates, pickDirectory: () => ctx.workspaces.pickDirectory(), loopback: connection.isLoopback }),\n }, SkillManagerSection));\n ctx.slots.inject('conversation.input.left', () => ctx.slots.register({\n name: 'conversation.input.left',\n id: 'skill-manager',\n order: 10,\n inject: () => ({ list, mutate }),\n }, ComposerSkillButton));\n}\nfunction SkillManagerSection(props) {\n const { list, mutate, checkUpdates, pickDirectory, loopback, useWorkspaces } = props;\n const workspaces = useWorkspaces(state => state);\n const [projectRoot, setProjectRoot] = useState(undefined);\n const [catalog, setCatalog] = useState(null);\n const [query, setQuery] = useState('');\n const [busy, setBusy] = useState(false);\n const [checking, setChecking] = useState(false);\n const [statuses, setStatuses] = useState({});\n const [error, setError] = useState(null);\n const [repositoryOpen, setRepositoryOpen] = useState(false);\n const [repository, setRepository] = useState('');\n const [view, setView] = useState('flat');\n const [collapsed, setCollapsed] = useState({});\n useEffect(() => { ensureKeyframes(); }, []);\n // 追踪用户是否主动选过「只看全局」,避免 useEffect 把它重置回第一个工作区\n const userChoseGlobal = useRef(false);\n useEffect(() => {\n // 仅当用户未主动选择「只看全局」时,才自动选中第一个工作区\n if (projectRoot === undefined && !userChoseGlobal.current && workspaces.items.length > 0)\n setProjectRoot(workspaces.items[0].path);\n // 当前选中的工作区被移除时,回退到第一个工作区\n if (projectRoot !== undefined && !workspaces.items.some(item => item.path === projectRoot))\n setProjectRoot(workspaces.items[0]?.path);\n }, [projectRoot, workspaces.items]);\n const refresh = useCallback(async () => {\n setBusy(true);\n setError(null);\n try {\n setCatalog(await list(projectRoot));\n }\n catch (reason) {\n setError(messageOf(reason));\n }\n finally {\n setBusy(false);\n }\n }, [list, projectRoot]);\n useEffect(() => { void refresh(); }, [refresh]);\n const run = useCallback(async (action) => {\n setBusy(true);\n setError(null);\n try {\n setCatalog(await action());\n return true;\n }\n catch (reason) {\n setError(messageOf(reason));\n return false;\n }\n finally {\n setBusy(false);\n }\n }, []);\n const normalizedQuery = query.trim().toLocaleLowerCase();\n const filtered = (catalog?.entries ?? []).filter(entry => normalizedQuery.length === 0 || `${entry.name} ${entry.description}`.toLocaleLowerCase().includes(normalizedQuery));\n const groups = groupBySource(filtered);\n const importSkill = async () => {\n const path = await pickDirectory();\n if (path)\n await run(() => mutate('install', { path, projectRoot }));\n };\n const importRepository = async (event) => {\n event.preventDefault();\n const source = repository.trim();\n if (!source)\n return;\n if (await run(() => mutate('install-remote', { repository: source, projectRoot }))) {\n setRepository('');\n setRepositoryOpen(false);\n }\n };\n const updateSkill = async (entry) => {\n const path = entry.updateSupported ? undefined : await pickDirectory() ?? undefined;\n if (!entry.updateSupported && !path)\n return;\n await run(() => mutate('update', { name: entry.name, path, projectRoot }));\n };\n const checkAll = async () => {\n setChecking(true);\n setError(null);\n try {\n const report = await checkUpdates();\n setStatuses(Object.fromEntries(report.entries.map(entry => [entry.name, entry.status])));\n }\n catch (reason) {\n setError(messageOf(reason));\n }\n finally {\n setChecking(false);\n }\n };\n const updatable = (catalog?.entries ?? []).filter(entry => statuses[entry.name] === 'update-available' && entry.updateSupported);\n const updateAll = async () => {\n setBusy(true);\n setError(null);\n try {\n for (const entry of updatable)\n setCatalog(await mutate('update', { name: entry.name, projectRoot }));\n setStatuses({});\n }\n catch (reason) {\n setError(messageOf(reason));\n }\n finally {\n setBusy(false);\n }\n };\n const selectedWorkspace = workspaces.items.find(item => item.path === projectRoot);\n const rowProps = (entry) => ({\n key: entry.name,\n entry,\n projectLabel: selectedWorkspace?.title ?? '当前项目',\n projectAvailable: projectRoot !== undefined,\n busy,\n updateStatus: statuses[entry.name],\n onGlobalChange: (enabled) => void run(() => mutate('set-enabled', { name: entry.name, scope: 'global', projectRoot, enabled })),\n onProjectChange: (enabled) => void run(() => mutate('set-enabled', { name: entry.name, scope: 'project', projectRoot, enabled })),\n onUpdate: () => void updateSkill(entry),\n onRemove: () => void run(() => mutate('remove', { name: entry.name, projectRoot })),\n });\n return h('div', { style: panelStyle, 'aria-busy': busy }, h('header', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 16, flexWrap: 'wrap' } }, h('div', { style: { display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 } }, h(Puzzle, { size: 20, 'aria-hidden': true }), h('h2', { style: { margin: 0, fontSize: 18, fontWeight: 600 } }, 'Skill 管理'), busy ? h(RefreshCw, { size: 14, 'aria-hidden': true, style: spinnerStyle }) : null), h('div', { style: { display: 'flex', gap: 8, flexWrap: 'wrap' } }, h('button', { type: 'button', style: buttonStyle('ghost', busy || checking), onClick: () => void checkAll(), disabled: busy || checking, title: '检测全部 skill 是否有更新(只检测,不更新)' }, h(RefreshCw, { size: 14, 'aria-hidden': true, style: checking ? spinnerStyle : undefined }), checking ? '检测中…' : '检测'), updatable.length > 0 ? h('button', { type: 'button', style: buttonStyle('primary', busy || checking || !loopback), onClick: () => void updateAll(), disabled: busy || checking || !loopback, title: loopback ? `更新全部 ${updatable.length} 个有更新的 skill` : '仅在本机连接时可更新' }, h(RefreshCw, { size: 14, 'aria-hidden': true }), `全部更新 (${updatable.length})`) : null, h('button', { type: 'button', style: buttonStyle('ghost', busy || !loopback), onClick: () => setRepositoryOpen(value => !value), disabled: busy || !loopback, title: loopback ? '从 Git 仓库导入 skill' : '仅在本机连接时可导入' }, h(GitBranch, { size: 14, 'aria-hidden': true }), '仓库'), h('button', { type: 'button', style: buttonStyle('primary', busy || !loopback), onClick: importSkill, disabled: busy || !loopback, title: loopback ? '从本机目录导入 skill' : '仅在本机连接时可导入' }, h(Plus, { size: 14, 'aria-hidden': true }), '本机'))), h('p', { style: { margin: '-8px 0 0', fontSize: 13, color: tokens.secondary, lineHeight: 1.5 } }, '从本机目录或 Git 仓库导入 skill,并按「全局」或「项目」范围启用。'), repositoryOpen ? h('form', { onSubmit: importRepository, style: { display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center' } }, h('input', {\n type: 'text',\n value: repository,\n onChange: (event) => setRepository(event.currentTarget.value),\n placeholder: 'owner/repo 或 Git URL',\n 'aria-label': 'Git 仓库地址',\n autoFocus: true,\n disabled: busy,\n style: { ...inputStyle, flex: '1 1 260px', minWidth: 0, paddingLeft: 10 },\n }), h('button', { type: 'submit', style: buttonStyle('primary', busy || !repository.trim()), disabled: busy || !repository.trim() }, h(GitBranch, { size: 14, 'aria-hidden': true }), '导入'), h('button', { type: 'button', style: iconButtonStyle, onClick: () => setRepositoryOpen(false), disabled: busy, title: '关闭仓库导入', 'aria-label': '关闭仓库导入' }, h(X, { size: 15, 'aria-hidden': true }))) : null, h('div', { style: { display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'center' } }, h('div', { style: { position: 'relative', flex: '1 1 220px', display: 'flex', alignItems: 'center' } }, h(Search, { size: 14, 'aria-hidden': true, style: { position: 'absolute', left: 9, color: tokens.secondary, pointerEvents: 'none' } }), h('input', { type: 'search', value: query, placeholder: '搜索 skill…', 'aria-label': '搜索 skill', onChange: (event) => setQuery(event.currentTarget.value), style: inputStyle })), h('label', { style: { display: 'flex', flex: '1 1 220px', minWidth: 0, alignItems: 'center', gap: 8, fontSize: 13, color: tokens.secondary } }, h('span', { style: { flex: '0 0 auto' } }, '项目范围'), h('select', { value: projectRoot ?? '__global__', onChange: (event) => { const value = event.currentTarget.value; if (value === '__global__') {\n userChoseGlobal.current = true;\n setProjectRoot(undefined);\n }\n else {\n userChoseGlobal.current = false;\n setProjectRoot(value);\n } }, style: { ...selectStyle, flex: '1 1 auto', minWidth: 0, maxWidth: 'none' } }, h('option', { value: '__global__' }, '只看全局'), ...workspaces.items.map(workspace => h('option', { key: workspace.workspaceId, value: workspace.path }, workspace.title)))), h('div', { role: 'group', 'aria-label': '视图切换', style: { display: 'flex', flex: '0 0 auto', border: `1px solid ${tokens.border}`, borderRadius: 8, overflow: 'hidden' } }, h('button', { type: 'button', onClick: () => setView('flat'), 'aria-pressed': view === 'flat', title: '平铺列表', style: { ...iconButtonStyle, width: 32, height: 32, borderRadius: 0, color: view === 'flat' ? tokens.accent : tokens.secondary, background: view === 'flat' ? 'rgba(99, 102, 241, .12)' : 'transparent' } }, h(List, { size: 15, 'aria-hidden': true })), h('button', { type: 'button', onClick: () => setView('grouped'), 'aria-pressed': view === 'grouped', title: '按来源仓库分组', style: { ...iconButtonStyle, width: 32, height: 32, borderRadius: 0, color: view === 'grouped' ? tokens.accent : tokens.secondary, background: view === 'grouped' ? 'rgba(99, 102, 241, .12)' : 'transparent' } }, h(Folder, { size: 15, 'aria-hidden': true })))), error ? h('div', { role: 'alert', style: { display: 'flex', gap: 8, alignItems: 'center', margin: 0, padding: '9px 12px', borderRadius: 8, fontSize: 13, color: tokens.danger, background: 'rgba(220, 38, 38, .08)', border: '1px solid rgba(220, 38, 38, .28)' } }, h(AlertCircle, { size: 15, 'aria-hidden': true }), error) : null, h('section', { style: { display: 'grid', width: '100%', minWidth: 0, gap: 8 }, 'aria-label': '已安装 skill' }, catalog === null\n ? h('p', { style: { margin: 0, padding: '24px 0', textAlign: 'center', fontSize: 13, color: tokens.secondary } }, '正在读取…')\n : filtered.length === 0\n ? h(EmptyState, { hasAny: (catalog.entries.length ?? 0) > 0 })\n : view === 'flat'\n ? filtered.map(entry => h(SkillRow, rowProps(entry)))\n : groups.map(group => h('div', { key: group.key, style: { display: 'grid', gap: 8 } }, h('button', {\n type: 'button',\n onClick: () => setCollapsed(prev => ({ ...prev, [group.key]: !prev[group.key] })),\n 'aria-expanded': !collapsed[group.key],\n style: { display: 'flex', alignItems: 'center', gap: 8, padding: '6px 4px', border: 'none', background: 'transparent', color: 'inherit', cursor: 'pointer', fontSize: 13, fontWeight: 600, textAlign: 'left' },\n }, collapsed[group.key] ? h(ChevronRight, { size: 14, 'aria-hidden': true, style: { color: tokens.secondary, flex: '0 0 auto' } }) : h(ChevronDown, { size: 14, 'aria-hidden': true, style: { color: tokens.secondary, flex: '0 0 auto' } }), h(GitBranch, { size: 13, 'aria-hidden': true, style: { color: tokens.secondary, flex: '0 0 auto' } }), h('span', { title: group.key === '__local__' ? undefined : group.key, style: { ...monoStyle, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, group.label), h('span', { style: { color: tokens.secondary, fontWeight: 400, flex: '0 0 auto' } }, `${group.entries.length} 个`)), collapsed[group.key] ? null : group.entries.map(entry => h(SkillRow, rowProps(entry)))))));\n}\nfunction groupBySource(entries) {\n const groups = new Map();\n for (const entry of entries) {\n const key = entry.sourceType === 'git' && entry.sourceUrl ? entry.sourceUrl : '__local__';\n const label = key === '__local__' ? '本机导入' : shortRepoLabel(key);\n const group = groups.get(key) ?? { label, entries: [] };\n group.entries.push(entry);\n groups.set(key, group);\n }\n return [...groups.entries()]\n .map(([key, group]) => ({ key, label: group.label, entries: group.entries }))\n .sort((a, b) => (a.key === '__local__' ? 1 : b.key === '__local__' ? -1 : a.label.localeCompare(b.label)));\n}\nfunction shortRepoLabel(url) {\n const match = /^(?:https?:\\/\\/|git@|ssh:\\/\\/git@)?([^/:]+)[:/]([^/]+\\/[^/]+?)(?:\\.git)?\\/?$/.exec(url);\n return match ? `${match[2]} (${match[1]})` : url;\n}\nfunction EmptyState(props) {\n return h('div', { style: { display: 'grid', justifyItems: 'center', gap: 8, padding: '36px 16px', borderRadius: 10, border: `1px dashed ${tokens.borderStrong}`, color: tokens.secondary, textAlign: 'center' } }, h(PackageOpen, { size: 26, 'aria-hidden': true }), h('p', { style: { margin: 0, fontSize: 13, lineHeight: 1.5 } }, props.hasAny ? '没有匹配的 skill,试试调整搜索词。' : '还没有导入任何 skill。点击右上角「导入」,从本机目录开始。'));\n}\nfunction ComposerSkillButton(props) {\n const { session, useSessions, list, mutate } = props;\n const projectRoot = useSessions(state => projectRootForSession(state, session.sessionId));\n const [open, setOpen] = useState(false);\n const containerRef = useRef(null);\n useEffect(() => {\n if (!open)\n return;\n const onPointerDown = (event) => {\n if (containerRef.current && event.target instanceof Node && !containerRef.current.contains(event.target))\n setOpen(false);\n };\n const onKeyDown = (event) => { if (event.key === 'Escape')\n setOpen(false); };\n document.addEventListener('pointerdown', onPointerDown);\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('pointerdown', onPointerDown);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [open]);\n return h('div', { ref: containerRef, style: { position: 'relative', display: 'inline-flex', marginLeft: -25 } }, h('button', {\n type: 'button',\n title: projectRoot ? '配置当前项目的 Skill' : '当前会话没有工作区',\n 'aria-label': '配置当前项目的 Skill',\n 'aria-expanded': open,\n disabled: !projectRoot,\n onClick: () => setOpen(value => !value),\n style: {\n display: 'grid',\n placeItems: 'center',\n flex: '0 0 auto',\n width: 28,\n height: 28,\n padding: 0,\n border: 'none',\n borderRadius: 999,\n background: open ? 'var(--dsw-alias-bg-active, rgba(255, 255, 255, .16))' : 'var(--dsw-specific-selector, rgba(255, 255, 255, .08))',\n color: 'var(--dsw-alias-label-primary, inherit)',\n cursor: projectRoot ? 'pointer' : 'default',\n opacity: projectRoot ? 1 : 0.5,\n },\n }, h(Wrench, { size: 16, 'aria-hidden': true })), open && projectRoot ? h(ProjectSkillPopover, { projectRoot, list, mutate, onClose: () => setOpen(false) }) : null);\n}\nfunction ProjectSkillPopover(props) {\n const { projectRoot, list, mutate, onClose } = props;\n const theme = currentThemeColors();\n const [catalog, setCatalog] = useState(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState(null);\n useEffect(() => { ensureKeyframes(); }, []);\n const refresh = useCallback(async () => {\n setBusy(true);\n setError(null);\n try {\n setCatalog(await list(projectRoot));\n }\n catch (reason) {\n setError(messageOf(reason));\n }\n finally {\n setBusy(false);\n }\n }, [list, projectRoot]);\n useEffect(() => { void refresh(); }, [refresh]);\n const toggle = async (entry, enabled) => {\n setBusy(true);\n setError(null);\n try {\n setCatalog(await mutate('set-enabled', { name: entry.name, scope: 'project', projectRoot, enabled }));\n }\n catch (reason) {\n setError(messageOf(reason));\n }\n finally {\n setBusy(false);\n }\n };\n const enabledCount = projectPopoverEnabledCount(catalog?.entries ?? []);\n return h('section', { style: { position: 'absolute', zIndex: 50, left: 0, bottom: 40, width: 320, display: 'grid', gap: 6, padding: 12, border: `1px solid ${tokens.borderStrong}`, borderRadius: 12, background: theme.background, color: theme.color, boxShadow: '0 16px 40px rgba(0, 0, 0, .4)' }, 'aria-label': '当前项目 Skill' }, h('header', { style: { display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'center', paddingBottom: 4 } }, h('div', { style: { display: 'flex', alignItems: 'center', gap: 7, minWidth: 0 } }, h(FolderGit, { size: 14, 'aria-hidden': true, style: { color: tokens.secondary, flex: '0 0 auto' } }), h('strong', { style: { fontSize: 13, fontWeight: 600 } }, '项目 Skill'), h('span', { style: { fontSize: 12, color: tokens.secondary } }, `${enabledCount}/${catalog?.entries.length ?? 0} 已启用`)), h('button', { type: 'button', onClick: onClose, style: iconButtonStyle, 'aria-label': '关闭项目 Skill', title: '关闭' }, h(X, { size: 14, 'aria-hidden': true }))), error ? h('div', { role: 'alert', style: { display: 'flex', gap: 6, alignItems: 'center', margin: 0, padding: '7px 9px', borderRadius: 7, fontSize: 12, color: tokens.danger, background: 'rgba(220, 38, 38, .08)' } }, h(AlertCircle, { size: 13, 'aria-hidden': true }), error) : null, h('div', { style: { display: 'grid', gap: 1, maxHeight: 280, overflowY: 'auto', margin: '0 -4px', padding: '0 4px' } }, catalog === null\n ? h('p', { style: { margin: 0, padding: '18px 0', textAlign: 'center', fontSize: 12, color: tokens.secondary } }, '正在读取…')\n : catalog.entries.length === 0\n ? h('p', { style: { margin: 0, padding: '18px 0', textAlign: 'center', fontSize: 12, color: tokens.secondary } }, '未导入 skill。请到「设置 → Skill 管理」导入。')\n : catalog.entries.map(entry => {\n const row = projectPopoverRow(entry, busy);\n return h('label', { key: entry.name, style: { display: 'grid', gridTemplateColumns: '14px minmax(0, 1fr) 30px', gap: 8, alignItems: 'center', padding: '7px 6px', borderRadius: 7, fontSize: 13, cursor: row.disabled ? 'default' : 'pointer' }, title: entry.description || entry.name }, h(Puzzle, { size: 13, 'aria-hidden': true, style: { color: entry.effectiveEnabled ? tokens.accent : tokens.secondary } }), h('div', { style: { display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 } }, h('span', { style: { minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, entry.name), row.badge ? h(StatusBadge, { active: true, icon: Globe, label: row.badge }) : null), h('input', { type: 'checkbox', checked: row.checked, disabled: row.disabled, onChange: (event) => void toggle(entry, event.currentTarget.checked), 'aria-label': `${entry.name} 项目开关`, title: row.checkboxTitle, style: checkboxStyle }));\n })), busy ? h('div', { style: { display: 'flex', justifyContent: 'flex-end', paddingTop: 2 } }, h(RefreshCw, { size: 12, 'aria-hidden': true, style: spinnerStyle })) : null);\n}\nconst UPDATE_BADGE = {\n 'update-available': { label: '有更新', color: tokens.accent, background: 'rgba(99, 102, 241, .1)', border: '1px solid rgba(99, 102, 241, .35)' },\n 'current': { label: '已是最新', color: tokens.success, background: 'rgba(22, 163, 74, .1)', border: '1px solid rgba(22, 163, 74, .3)' },\n 'deleted-upstream': { label: '上游已删除', color: tokens.danger, background: 'rgba(220, 38, 38, .08)', border: '1px solid rgba(220, 38, 38, .3)' },\n 'unknown': { label: '无法检测', color: tokens.secondary, background: 'rgba(148, 163, 184, .09)', border: '1px solid transparent' },\n};\nfunction SkillRow(props) {\n const { entry, projectLabel, projectAvailable, busy, updateStatus, onGlobalChange, onProjectChange, onUpdate, onRemove } = props;\n const badge = updateStatus ? UPDATE_BADGE[updateStatus] : undefined;\n return h('article', {\n className: 'dsh-skill-manager-row',\n style: {\n display: 'grid', gridTemplateColumns: '32px minmax(0, 1fr)', gap: 12, alignItems: 'center',\n width: '100%', minWidth: 0, maxWidth: '100%', overflow: 'hidden', boxSizing: 'border-box',\n padding: '12px 14px', borderRadius: 10, border: `1px solid ${tokens.border}`,\n background: 'transparent', transition: 'border-color .15s ease, background .15s ease',\n },\n }, h('div', { className: 'dsh-skill-manager-row-icon', style: { display: 'grid', placeItems: 'center', width: 32, height: 32, borderRadius: 8, color: entry.effectiveEnabled ? tokens.accent : tokens.secondary, background: entry.effectiveEnabled ? 'rgba(99, 102, 241, .1)' : 'rgba(148, 163, 184, .1)' } }, h(Puzzle, { size: 16, 'aria-hidden': true })), h('div', { style: { minWidth: 0, display: 'grid', gap: 4 } }, h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, minWidth: 0, flexWrap: 'wrap' } }, h('strong', { style: { ...monoStyle, fontSize: 13, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, entry.name), badge ? h('span', { style: { display: 'inline-flex', alignItems: 'center', flex: '0 1 auto', padding: '2px 6px', borderRadius: 999, fontSize: 11, lineHeight: '16px', whiteSpace: 'nowrap', color: badge.color, background: badge.background, border: badge.border } }, badge.label) : null, h(SourceBadge, { entry }), h(StatusBadge, { active: entry.globalEnabled, icon: Globe, label: '全局' }), projectAvailable ? h(StatusBadge, { active: entry.projectEnabled, icon: FolderGit, label: projectLabel }) : null), entry.description ? h('p', { style: { margin: 0, color: tokens.secondary, lineHeight: 1.45, fontSize: 12.5, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' } }, entry.description) : null), h('div', { className: 'dsh-skill-manager-row-actions', style: { gridColumn: '1 / -1', display: 'flex', width: '100%', minWidth: 0, justifyContent: 'flex-end', alignItems: 'center', gap: 10, flexWrap: 'wrap' } }, h('input', { type: 'checkbox', checked: entry.globalEnabled, disabled: busy, onChange: (event) => onGlobalChange(event.currentTarget.checked), 'aria-label': `${entry.name} 全局开关`, title: '全局启用', style: checkboxStyle }), projectAvailable ? h('input', { type: 'checkbox', checked: entry.projectEnabled, disabled: busy, onChange: (event) => onProjectChange(event.currentTarget.checked), 'aria-label': `${entry.name} 项目开关`, title: `${projectLabel} 启用`, style: checkboxStyle }) : null, h('button', { type: 'button', style: { ...iconButtonStyle, color: tokens.secondary }, disabled: busy, onClick: onUpdate, title: entry.updateSupported ? (entry.sourceType === 'git' ? '从远程仓库更新' : '从原始目录更新') : '选择来源目录并更新', 'aria-label': `更新 ${entry.name}` }, h(RefreshCw, { size: 15, 'aria-hidden': true })), h('button', { type: 'button', style: { ...iconButtonStyle, color: tokens.danger }, disabled: busy, onClick: onRemove, title: '从库中移除', 'aria-label': `移除 ${entry.name}` }, h(Trash2, { size: 15, 'aria-hidden': true }))));\n}\nfunction SourceBadge(props) {\n const remote = props.entry.sourceType === 'git';\n const local = props.entry.sourceType === 'local';\n const Icon = remote ? GitBranch : local ? FolderGit : AlertCircle;\n const label = remote ? 'Git' : local ? '本机' : '未知';\n const title = remote ? props.entry.sourceUrl : local ? props.entry.sourcePath : '来源未知,更新时需选择本机来源目录';\n return h('span', {\n title,\n style: {\n display: 'inline-flex', alignItems: 'center', gap: 4, flex: '0 1 auto', maxWidth: '100%', overflow: 'hidden',\n padding: '2px 6px', borderRadius: 999, fontSize: 11, lineHeight: '16px', whiteSpace: 'nowrap',\n color: tokens.secondary, background: 'rgba(148, 163, 184, .09)',\n },\n }, h(Icon, { size: 11, 'aria-hidden': true }), label);\n}\nfunction StatusBadge(props) {\n const Icon = props.icon;\n return h('span', {\n title: props.active ? `${props.label}已启用` : `${props.label}未启用`,\n style: {\n display: 'inline-flex', alignItems: 'center', gap: 4, flex: '0 1 auto', maxWidth: '100%', overflow: 'hidden',\n padding: '2px 6px', borderRadius: 999, fontSize: 11, lineHeight: '16px', whiteSpace: 'nowrap',\n color: props.active ? tokens.success : tokens.secondary,\n background: props.active ? 'rgba(22, 163, 74, .1)' : 'rgba(148, 163, 184, .09)',\n border: `1px solid ${props.active ? 'rgba(22, 163, 74, .3)' : 'transparent'}`,\n },\n }, h(Icon, { size: 11, 'aria-hidden': true }), props.active ? `${props.label}开` : `${props.label}关`);\n}\nfunction currentThemeColors() {\n if (typeof document === 'undefined')\n return { background: '#151517', color: '#f9fafb' };\n const style = getComputedStyle(document.body);\n return {\n background: style.backgroundColor || '#151517',\n color: style.color || '#f9fafb',\n };\n}\nfunction messageOf(reason) {\n return reason instanceof Error ? reason.message : String(reason);\n}\n"],"x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24],"mappings":"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"}
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
3
3
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
|
-
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { execFile } from "node:child_process";
|
|
7
7
|
import { promisify } from "node:util";
|
|
@@ -198,6 +198,74 @@ var SkillManager = class {
|
|
|
198
198
|
this.providerControl?.invalidate();
|
|
199
199
|
return this.catalog(projectRoot);
|
|
200
200
|
}
|
|
201
|
+
async checkUpdates() {
|
|
202
|
+
await this.loaded;
|
|
203
|
+
let lockSkills;
|
|
204
|
+
try {
|
|
205
|
+
lockSkills = JSON.parse(await readFile(join(this.root, "skills-lock.json"), "utf8")).skills ?? {};
|
|
206
|
+
} catch {
|
|
207
|
+
return { entries: [] };
|
|
208
|
+
}
|
|
209
|
+
const installed = new Set((await this.libraryCandidates({})).map((candidate) => candidate.name));
|
|
210
|
+
const entries = Object.entries(lockSkills).filter(([name$1]) => installed.has(name$1));
|
|
211
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
212
|
+
for (const item of entries) {
|
|
213
|
+
const source = item[1].source ?? "";
|
|
214
|
+
bySource.set(source, [...bySource.get(source) ?? [], item]);
|
|
215
|
+
}
|
|
216
|
+
const report = [];
|
|
217
|
+
for (const [source, items] of bySource) {
|
|
218
|
+
const first = items[0][1];
|
|
219
|
+
const apply$1 = (statuses) => {
|
|
220
|
+
for (const [name$1] of items) report.push({
|
|
221
|
+
name: name$1,
|
|
222
|
+
status: statuses[name$1] ?? "unknown"
|
|
223
|
+
});
|
|
224
|
+
};
|
|
225
|
+
if (first.sourceType === "local") {
|
|
226
|
+
const sourceRoot = isAbsolute(source) ? source : resolve(this.root, source);
|
|
227
|
+
const statuses = {};
|
|
228
|
+
for (const [name$1] of items) {
|
|
229
|
+
const [sourceHash, installedHash] = await Promise.all([computeSkillFolderHash(join(sourceRoot, name$1)).catch(() => void 0), computeSkillFolderHash(join(this.library, name$1)).catch(() => void 0)]);
|
|
230
|
+
statuses[name$1] = sourceHash === void 0 ? "unknown" : sourceHash === installedHash ? "current" : "update-available";
|
|
231
|
+
}
|
|
232
|
+
apply$1(statuses);
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (first.sourceType === "github" || first.sourceType === "git" || first.sourceType === "gitlab") {
|
|
236
|
+
if (!first.skillPath) {
|
|
237
|
+
apply$1({});
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
const url = first.sourceUrl || source;
|
|
241
|
+
let latest;
|
|
242
|
+
try {
|
|
243
|
+
latest = await computeLatestHashesFromGit(url, first.ref, items.map(([, entry]) => entry.skillPath));
|
|
244
|
+
} catch {
|
|
245
|
+
apply$1({});
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
const statuses = {};
|
|
249
|
+
for (const [name$1, entry] of items) {
|
|
250
|
+
if (!latest.paths.has(entry.skillPath)) {
|
|
251
|
+
statuses[name$1] = "deleted-upstream";
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
const remote = latest.hashes.get(entry.skillPath);
|
|
255
|
+
if (!remote) {
|
|
256
|
+
statuses[name$1] = "unknown";
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
const installed$1 = await computeSkillFolderHash(join(this.library, name$1)).catch(() => void 0);
|
|
260
|
+
statuses[name$1] = installed$1 === void 0 ? "unknown" : installed$1 === remote ? "current" : "update-available";
|
|
261
|
+
}
|
|
262
|
+
apply$1(statuses);
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
apply$1({});
|
|
266
|
+
}
|
|
267
|
+
return { entries: report.sort((a, b) => a.name.localeCompare(b.name)) };
|
|
268
|
+
}
|
|
201
269
|
async setEnabled(name$1, scope, projectRoot, enabled) {
|
|
202
270
|
await this.loaded;
|
|
203
271
|
await this.assertInstalled(name$1);
|
|
@@ -326,6 +394,10 @@ async function handleRpc(manager, endpoint, payload) {
|
|
|
326
394
|
ok: true,
|
|
327
395
|
value: await manager.remove(requiredString(args.name, "name"), asOptionalString(args.projectRoot))
|
|
328
396
|
};
|
|
397
|
+
case "check-updates": return {
|
|
398
|
+
ok: true,
|
|
399
|
+
value: await manager.checkUpdates()
|
|
400
|
+
};
|
|
329
401
|
default: throw new Error(`unknown skill-manager endpoint: ${endpoint}`);
|
|
330
402
|
}
|
|
331
403
|
}
|
|
@@ -455,6 +527,77 @@ function isRecord(value) {
|
|
|
455
527
|
function isNodeError(value) {
|
|
456
528
|
return value instanceof Error && "code" in value;
|
|
457
529
|
}
|
|
530
|
+
async function computeSkillFolderHash(skillDir) {
|
|
531
|
+
const files = [];
|
|
532
|
+
const collect = async (directory) => {
|
|
533
|
+
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
534
|
+
if (entry.name === ".git" || entry.name === "node_modules") continue;
|
|
535
|
+
const fullPath = join(directory, entry.name);
|
|
536
|
+
if (entry.isDirectory()) await collect(fullPath);
|
|
537
|
+
else if (entry.isFile()) files.push({
|
|
538
|
+
relativePath: relative(skillDir, fullPath).split(sep).join("/"),
|
|
539
|
+
content: await readFile(fullPath)
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
await collect(skillDir);
|
|
544
|
+
files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
545
|
+
const hash = createHash("sha256");
|
|
546
|
+
for (const file of files) {
|
|
547
|
+
hash.update(file.relativePath);
|
|
548
|
+
hash.update(file.content);
|
|
549
|
+
}
|
|
550
|
+
return hash.digest("hex");
|
|
551
|
+
}
|
|
552
|
+
function skillFolderFromPath(skillPath) {
|
|
553
|
+
let folder = skillPath.replace(/\\/g, "/");
|
|
554
|
+
if (folder.toLowerCase().endsWith("/skill.md")) folder = folder.slice(0, -9);
|
|
555
|
+
else if (folder.toLowerCase().endsWith("skill.md")) folder = folder.slice(0, -8);
|
|
556
|
+
return folder.endsWith("/") ? folder.slice(0, -1) : folder;
|
|
557
|
+
}
|
|
558
|
+
async function computeLatestHashesFromGit(url, ref, skillPaths) {
|
|
559
|
+
const temporaryRoot = await mkdtemp(join(tmpdir(), "dsh-skill-manager-check-"));
|
|
560
|
+
try {
|
|
561
|
+
await execFileAsync("git", [
|
|
562
|
+
"clone",
|
|
563
|
+
"--depth",
|
|
564
|
+
"1",
|
|
565
|
+
"--no-recurse-submodules",
|
|
566
|
+
...ref ? ["--branch", ref] : [],
|
|
567
|
+
preflightRepositorySource(url),
|
|
568
|
+
join(temporaryRoot, "repo")
|
|
569
|
+
], {
|
|
570
|
+
timeout: 12e4,
|
|
571
|
+
maxBuffer: 4 * 1024 * 1024
|
|
572
|
+
});
|
|
573
|
+
const repo = join(temporaryRoot, "repo");
|
|
574
|
+
const paths = /* @__PURE__ */ new Set();
|
|
575
|
+
const walk = async (directory) => {
|
|
576
|
+
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
577
|
+
if (entry.name === ".git") continue;
|
|
578
|
+
const fullPath = join(directory, entry.name);
|
|
579
|
+
if (entry.isDirectory()) await walk(fullPath);
|
|
580
|
+
else if (entry.isFile()) paths.add(relative(repo, fullPath).split(sep).join("/"));
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
await walk(repo);
|
|
584
|
+
const hashes = /* @__PURE__ */ new Map();
|
|
585
|
+
for (const skillPath of skillPaths) {
|
|
586
|
+
if (!paths.has(skillPath)) continue;
|
|
587
|
+
const folder = join(repo, skillFolderFromPath(skillPath));
|
|
588
|
+
hashes.set(skillPath, await computeSkillFolderHash(folder).catch(() => ""));
|
|
589
|
+
}
|
|
590
|
+
return {
|
|
591
|
+
paths,
|
|
592
|
+
hashes
|
|
593
|
+
};
|
|
594
|
+
} finally {
|
|
595
|
+
await rm(temporaryRoot, {
|
|
596
|
+
recursive: true,
|
|
597
|
+
force: true
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
}
|
|
458
601
|
|
|
459
602
|
//#endregion
|
|
460
603
|
export { Config, SkillManager, apply, inject, name };
|
|
@@ -87,12 +87,18 @@ export function apply(ctx) {
|
|
|
87
87
|
};
|
|
88
88
|
const list = (projectRoot) => request('list', projectRoot ? { projectRoot } : {});
|
|
89
89
|
const mutate = request;
|
|
90
|
+
const checkUpdates = async () => {
|
|
91
|
+
const result = await connection.rpc.call('/skill-manager', 'check-updates', {});
|
|
92
|
+
if (!result.ok)
|
|
93
|
+
throw new Error(result.error.message);
|
|
94
|
+
return result.value;
|
|
95
|
+
};
|
|
90
96
|
ctx.slots.inject('settings.section', () => ctx.slots.register({
|
|
91
97
|
name: 'settings.section',
|
|
92
98
|
id: 'skills',
|
|
93
99
|
order: 35,
|
|
94
100
|
label: 'Skill 管理',
|
|
95
|
-
inject: () => ({ list, mutate, pickDirectory: () => ctx.workspaces.pickDirectory(), loopback: connection.isLoopback }),
|
|
101
|
+
inject: () => ({ list, mutate, checkUpdates, pickDirectory: () => ctx.workspaces.pickDirectory(), loopback: connection.isLoopback }),
|
|
96
102
|
}, SkillManagerSection));
|
|
97
103
|
ctx.slots.inject('conversation.input.left', () => ctx.slots.register({
|
|
98
104
|
name: 'conversation.input.left',
|
|
@@ -102,12 +108,14 @@ export function apply(ctx) {
|
|
|
102
108
|
}, ComposerSkillButton));
|
|
103
109
|
}
|
|
104
110
|
function SkillManagerSection(props) {
|
|
105
|
-
const { list, mutate, pickDirectory, loopback, useWorkspaces } = props;
|
|
111
|
+
const { list, mutate, checkUpdates, pickDirectory, loopback, useWorkspaces } = props;
|
|
106
112
|
const workspaces = useWorkspaces(state => state);
|
|
107
113
|
const [projectRoot, setProjectRoot] = useState(undefined);
|
|
108
114
|
const [catalog, setCatalog] = useState(null);
|
|
109
115
|
const [query, setQuery] = useState('');
|
|
110
116
|
const [busy, setBusy] = useState(false);
|
|
117
|
+
const [checking, setChecking] = useState(false);
|
|
118
|
+
const [statuses, setStatuses] = useState({});
|
|
111
119
|
const [error, setError] = useState(null);
|
|
112
120
|
const [repositoryOpen, setRepositoryOpen] = useState(false);
|
|
113
121
|
const [repository, setRepository] = useState('');
|
|
@@ -177,6 +185,36 @@ function SkillManagerSection(props) {
|
|
|
177
185
|
return;
|
|
178
186
|
await run(() => mutate('update', { name: entry.name, path, projectRoot }));
|
|
179
187
|
};
|
|
188
|
+
const checkAll = async () => {
|
|
189
|
+
setChecking(true);
|
|
190
|
+
setError(null);
|
|
191
|
+
try {
|
|
192
|
+
const report = await checkUpdates();
|
|
193
|
+
setStatuses(Object.fromEntries(report.entries.map(entry => [entry.name, entry.status])));
|
|
194
|
+
}
|
|
195
|
+
catch (reason) {
|
|
196
|
+
setError(messageOf(reason));
|
|
197
|
+
}
|
|
198
|
+
finally {
|
|
199
|
+
setChecking(false);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
const updatable = (catalog?.entries ?? []).filter(entry => statuses[entry.name] === 'update-available' && entry.updateSupported);
|
|
203
|
+
const updateAll = async () => {
|
|
204
|
+
setBusy(true);
|
|
205
|
+
setError(null);
|
|
206
|
+
try {
|
|
207
|
+
for (const entry of updatable)
|
|
208
|
+
setCatalog(await mutate('update', { name: entry.name, projectRoot }));
|
|
209
|
+
setStatuses({});
|
|
210
|
+
}
|
|
211
|
+
catch (reason) {
|
|
212
|
+
setError(messageOf(reason));
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
setBusy(false);
|
|
216
|
+
}
|
|
217
|
+
};
|
|
180
218
|
const selectedWorkspace = workspaces.items.find(item => item.path === projectRoot);
|
|
181
219
|
const rowProps = (entry) => ({
|
|
182
220
|
key: entry.name,
|
|
@@ -184,12 +222,13 @@ function SkillManagerSection(props) {
|
|
|
184
222
|
projectLabel: selectedWorkspace?.title ?? '当前项目',
|
|
185
223
|
projectAvailable: projectRoot !== undefined,
|
|
186
224
|
busy,
|
|
225
|
+
updateStatus: statuses[entry.name],
|
|
187
226
|
onGlobalChange: (enabled) => void run(() => mutate('set-enabled', { name: entry.name, scope: 'global', projectRoot, enabled })),
|
|
188
227
|
onProjectChange: (enabled) => void run(() => mutate('set-enabled', { name: entry.name, scope: 'project', projectRoot, enabled })),
|
|
189
228
|
onUpdate: () => void updateSkill(entry),
|
|
190
229
|
onRemove: () => void run(() => mutate('remove', { name: entry.name, projectRoot })),
|
|
191
230
|
});
|
|
192
|
-
return h('div', { style: panelStyle, 'aria-busy': busy }, h('header', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 16, flexWrap: 'wrap' } }, h('div', { style: { display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 } }, h(Puzzle, { size: 20, 'aria-hidden': true }), h('h2', { style: { margin: 0, fontSize: 18, fontWeight: 600 } }, 'Skill 管理'), busy ? h(RefreshCw, { size: 14, 'aria-hidden': true, style: spinnerStyle }) : null), h('div', { style: { display: 'flex', gap: 8, flexWrap: 'wrap' } }, h('button', { type: 'button', style: buttonStyle('ghost', busy || !loopback), onClick: () => setRepositoryOpen(value => !value), disabled: busy || !loopback, title: loopback ? '从 Git 仓库导入 skill' : '仅在本机连接时可导入' }, h(GitBranch, { size: 14, 'aria-hidden': true }), '仓库'), h('button', { type: 'button', style: buttonStyle('primary', busy || !loopback), onClick: importSkill, disabled: busy || !loopback, title: loopback ? '从本机目录导入 skill' : '仅在本机连接时可导入' }, h(Plus, { size: 14, 'aria-hidden': true }), '本机'))), h('p', { style: { margin: '-8px 0 0', fontSize: 13, color: tokens.secondary, lineHeight: 1.5 } }, '从本机目录或 Git 仓库导入 skill,并按「全局」或「项目」范围启用。'), repositoryOpen ? h('form', { onSubmit: importRepository, style: { display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center' } }, h('input', {
|
|
231
|
+
return h('div', { style: panelStyle, 'aria-busy': busy }, h('header', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 16, flexWrap: 'wrap' } }, h('div', { style: { display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 } }, h(Puzzle, { size: 20, 'aria-hidden': true }), h('h2', { style: { margin: 0, fontSize: 18, fontWeight: 600 } }, 'Skill 管理'), busy ? h(RefreshCw, { size: 14, 'aria-hidden': true, style: spinnerStyle }) : null), h('div', { style: { display: 'flex', gap: 8, flexWrap: 'wrap' } }, h('button', { type: 'button', style: buttonStyle('ghost', busy || checking), onClick: () => void checkAll(), disabled: busy || checking, title: '检测全部 skill 是否有更新(只检测,不更新)' }, h(RefreshCw, { size: 14, 'aria-hidden': true, style: checking ? spinnerStyle : undefined }), checking ? '检测中…' : '检测'), updatable.length > 0 ? h('button', { type: 'button', style: buttonStyle('primary', busy || checking || !loopback), onClick: () => void updateAll(), disabled: busy || checking || !loopback, title: loopback ? `更新全部 ${updatable.length} 个有更新的 skill` : '仅在本机连接时可更新' }, h(RefreshCw, { size: 14, 'aria-hidden': true }), `全部更新 (${updatable.length})`) : null, h('button', { type: 'button', style: buttonStyle('ghost', busy || !loopback), onClick: () => setRepositoryOpen(value => !value), disabled: busy || !loopback, title: loopback ? '从 Git 仓库导入 skill' : '仅在本机连接时可导入' }, h(GitBranch, { size: 14, 'aria-hidden': true }), '仓库'), h('button', { type: 'button', style: buttonStyle('primary', busy || !loopback), onClick: importSkill, disabled: busy || !loopback, title: loopback ? '从本机目录导入 skill' : '仅在本机连接时可导入' }, h(Plus, { size: 14, 'aria-hidden': true }), '本机'))), h('p', { style: { margin: '-8px 0 0', fontSize: 13, color: tokens.secondary, lineHeight: 1.5 } }, '从本机目录或 Git 仓库导入 skill,并按「全局」或「项目」范围启用。'), repositoryOpen ? h('form', { onSubmit: importRepository, style: { display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center' } }, h('input', {
|
|
193
232
|
type: 'text',
|
|
194
233
|
value: repository,
|
|
195
234
|
onChange: (event) => setRepository(event.currentTarget.value),
|
|
@@ -326,8 +365,15 @@ function ProjectSkillPopover(props) {
|
|
|
326
365
|
return h('label', { key: entry.name, style: { display: 'grid', gridTemplateColumns: '14px minmax(0, 1fr) 30px', gap: 8, alignItems: 'center', padding: '7px 6px', borderRadius: 7, fontSize: 13, cursor: row.disabled ? 'default' : 'pointer' }, title: entry.description || entry.name }, h(Puzzle, { size: 13, 'aria-hidden': true, style: { color: entry.effectiveEnabled ? tokens.accent : tokens.secondary } }), h('div', { style: { display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 } }, h('span', { style: { minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, entry.name), row.badge ? h(StatusBadge, { active: true, icon: Globe, label: row.badge }) : null), h('input', { type: 'checkbox', checked: row.checked, disabled: row.disabled, onChange: (event) => void toggle(entry, event.currentTarget.checked), 'aria-label': `${entry.name} 项目开关`, title: row.checkboxTitle, style: checkboxStyle }));
|
|
327
366
|
})), busy ? h('div', { style: { display: 'flex', justifyContent: 'flex-end', paddingTop: 2 } }, h(RefreshCw, { size: 12, 'aria-hidden': true, style: spinnerStyle })) : null);
|
|
328
367
|
}
|
|
368
|
+
const UPDATE_BADGE = {
|
|
369
|
+
'update-available': { label: '有更新', color: tokens.accent, background: 'rgba(99, 102, 241, .1)', border: '1px solid rgba(99, 102, 241, .35)' },
|
|
370
|
+
'current': { label: '已是最新', color: tokens.success, background: 'rgba(22, 163, 74, .1)', border: '1px solid rgba(22, 163, 74, .3)' },
|
|
371
|
+
'deleted-upstream': { label: '上游已删除', color: tokens.danger, background: 'rgba(220, 38, 38, .08)', border: '1px solid rgba(220, 38, 38, .3)' },
|
|
372
|
+
'unknown': { label: '无法检测', color: tokens.secondary, background: 'rgba(148, 163, 184, .09)', border: '1px solid transparent' },
|
|
373
|
+
};
|
|
329
374
|
function SkillRow(props) {
|
|
330
|
-
const { entry, projectLabel, projectAvailable, busy, onGlobalChange, onProjectChange, onUpdate, onRemove } = props;
|
|
375
|
+
const { entry, projectLabel, projectAvailable, busy, updateStatus, onGlobalChange, onProjectChange, onUpdate, onRemove } = props;
|
|
376
|
+
const badge = updateStatus ? UPDATE_BADGE[updateStatus] : undefined;
|
|
331
377
|
return h('article', {
|
|
332
378
|
className: 'dsh-skill-manager-row',
|
|
333
379
|
style: {
|
|
@@ -336,7 +382,7 @@ function SkillRow(props) {
|
|
|
336
382
|
padding: '12px 14px', borderRadius: 10, border: `1px solid ${tokens.border}`,
|
|
337
383
|
background: 'transparent', transition: 'border-color .15s ease, background .15s ease',
|
|
338
384
|
},
|
|
339
|
-
}, h('div', { className: 'dsh-skill-manager-row-icon', style: { display: 'grid', placeItems: 'center', width: 32, height: 32, borderRadius: 8, color: entry.effectiveEnabled ? tokens.accent : tokens.secondary, background: entry.effectiveEnabled ? 'rgba(99, 102, 241, .1)' : 'rgba(148, 163, 184, .1)' } }, h(Puzzle, { size: 16, 'aria-hidden': true })), h('div', { style: { minWidth: 0, display: 'grid', gap: 4 } }, h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, minWidth: 0, flexWrap: 'wrap' } }, h('strong', { style: { ...monoStyle, fontSize: 13, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, entry.name), h(SourceBadge, { entry }), h(StatusBadge, { active: entry.globalEnabled, icon: Globe, label: '全局' }), projectAvailable ? h(StatusBadge, { active: entry.projectEnabled, icon: FolderGit, label: projectLabel }) : null), entry.description ? h('p', { style: { margin: 0, color: tokens.secondary, lineHeight: 1.45, fontSize: 12.5, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' } }, entry.description) : null), h('div', { className: 'dsh-skill-manager-row-actions', style: { gridColumn: '1 / -1', display: 'flex', width: '100%', minWidth: 0, justifyContent: 'flex-end', alignItems: 'center', gap: 10, flexWrap: 'wrap' } }, h('input', { type: 'checkbox', checked: entry.globalEnabled, disabled: busy, onChange: (event) => onGlobalChange(event.currentTarget.checked), 'aria-label': `${entry.name} 全局开关`, title: '全局启用', style: checkboxStyle }), projectAvailable ? h('input', { type: 'checkbox', checked: entry.projectEnabled, disabled: busy, onChange: (event) => onProjectChange(event.currentTarget.checked), 'aria-label': `${entry.name} 项目开关`, title: `${projectLabel} 启用`, style: checkboxStyle }) : null, h('button', { type: 'button', style: { ...iconButtonStyle, color: tokens.secondary }, disabled: busy, onClick: onUpdate, title: entry.updateSupported ? (entry.sourceType === 'git' ? '从远程仓库更新' : '从原始目录更新') : '选择来源目录并更新', 'aria-label': `更新 ${entry.name}` }, h(RefreshCw, { size: 15, 'aria-hidden': true })), h('button', { type: 'button', style: { ...iconButtonStyle, color: tokens.danger }, disabled: busy, onClick: onRemove, title: '从库中移除', 'aria-label': `移除 ${entry.name}` }, h(Trash2, { size: 15, 'aria-hidden': true }))));
|
|
385
|
+
}, h('div', { className: 'dsh-skill-manager-row-icon', style: { display: 'grid', placeItems: 'center', width: 32, height: 32, borderRadius: 8, color: entry.effectiveEnabled ? tokens.accent : tokens.secondary, background: entry.effectiveEnabled ? 'rgba(99, 102, 241, .1)' : 'rgba(148, 163, 184, .1)' } }, h(Puzzle, { size: 16, 'aria-hidden': true })), h('div', { style: { minWidth: 0, display: 'grid', gap: 4 } }, h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, minWidth: 0, flexWrap: 'wrap' } }, h('strong', { style: { ...monoStyle, fontSize: 13, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, entry.name), badge ? h('span', { style: { display: 'inline-flex', alignItems: 'center', flex: '0 1 auto', padding: '2px 6px', borderRadius: 999, fontSize: 11, lineHeight: '16px', whiteSpace: 'nowrap', color: badge.color, background: badge.background, border: badge.border } }, badge.label) : null, h(SourceBadge, { entry }), h(StatusBadge, { active: entry.globalEnabled, icon: Globe, label: '全局' }), projectAvailable ? h(StatusBadge, { active: entry.projectEnabled, icon: FolderGit, label: projectLabel }) : null), entry.description ? h('p', { style: { margin: 0, color: tokens.secondary, lineHeight: 1.45, fontSize: 12.5, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' } }, entry.description) : null), h('div', { className: 'dsh-skill-manager-row-actions', style: { gridColumn: '1 / -1', display: 'flex', width: '100%', minWidth: 0, justifyContent: 'flex-end', alignItems: 'center', gap: 10, flexWrap: 'wrap' } }, h('input', { type: 'checkbox', checked: entry.globalEnabled, disabled: busy, onChange: (event) => onGlobalChange(event.currentTarget.checked), 'aria-label': `${entry.name} 全局开关`, title: '全局启用', style: checkboxStyle }), projectAvailable ? h('input', { type: 'checkbox', checked: entry.projectEnabled, disabled: busy, onChange: (event) => onProjectChange(event.currentTarget.checked), 'aria-label': `${entry.name} 项目开关`, title: `${projectLabel} 启用`, style: checkboxStyle }) : null, h('button', { type: 'button', style: { ...iconButtonStyle, color: tokens.secondary }, disabled: busy, onClick: onUpdate, title: entry.updateSupported ? (entry.sourceType === 'git' ? '从远程仓库更新' : '从原始目录更新') : '选择来源目录并更新', 'aria-label': `更新 ${entry.name}` }, h(RefreshCw, { size: 15, 'aria-hidden': true })), h('button', { type: 'button', style: { ...iconButtonStyle, color: tokens.danger }, disabled: busy, onClick: onRemove, title: '从库中移除', 'aria-label': `移除 ${entry.name}` }, h(Trash2, { size: 15, 'aria-hidden': true }))));
|
|
340
386
|
}
|
|
341
387
|
function SourceBadge(props) {
|
|
342
388
|
const remote = props.entry.sourceType === 'git';
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis';
|
|
2
2
|
import Schema from '@deepseek-ai/schemastery';
|
|
3
3
|
import type { SkillProvider, SkillProviderControl } from '@deepseek-ai/dsh-skill';
|
|
4
|
-
import type { SkillCatalog, SkillScope } from './types.js';
|
|
4
|
+
import type { SkillCatalog, SkillScope, SkillUpdateReport } from './types.js';
|
|
5
5
|
export declare const name = "dsh-skills-manager";
|
|
6
6
|
export declare const inject: string[];
|
|
7
7
|
export interface Config {
|
|
@@ -25,6 +25,7 @@ export declare class SkillManager {
|
|
|
25
25
|
installRemote(input: string, projectRoot?: string): Promise<SkillCatalog>;
|
|
26
26
|
private installSource;
|
|
27
27
|
update(name: string, sourcePath: string | undefined, projectRoot?: string): Promise<SkillCatalog>;
|
|
28
|
+
checkUpdates(): Promise<SkillUpdateReport>;
|
|
28
29
|
setEnabled(name: string, scope: SkillScope, projectRoot: string | undefined, enabled: boolean): Promise<SkillCatalog>;
|
|
29
30
|
remove(name: string, projectRoot?: string): Promise<SkillCatalog>;
|
|
30
31
|
private createFilesystemProvider;
|
package/lib/types/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
2
|
-
import { basename, dirname, isAbsolute, join, resolve } from 'node:path';
|
|
3
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
3
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
5
|
import { execFile } from 'node:child_process';
|
|
6
6
|
import { createRequire } from 'node:module';
|
|
@@ -120,6 +120,82 @@ export class SkillManager {
|
|
|
120
120
|
this.providerControl?.invalidate();
|
|
121
121
|
return this.catalog(projectRoot);
|
|
122
122
|
}
|
|
123
|
+
// ponytail: sources are checked sequentially to keep git/fetch usage trivial; parallelize per-source if checks feel slow
|
|
124
|
+
async checkUpdates() {
|
|
125
|
+
await this.loaded;
|
|
126
|
+
let lockSkills;
|
|
127
|
+
try {
|
|
128
|
+
lockSkills = JSON.parse(await readFile(join(this.root, 'skills-lock.json'), 'utf8')).skills ?? {};
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return { entries: [] };
|
|
132
|
+
}
|
|
133
|
+
const installed = new Set((await this.libraryCandidates({})).map(candidate => candidate.name));
|
|
134
|
+
const entries = Object.entries(lockSkills).filter(([name]) => installed.has(name));
|
|
135
|
+
const bySource = new Map();
|
|
136
|
+
for (const item of entries) {
|
|
137
|
+
const source = item[1].source ?? '';
|
|
138
|
+
bySource.set(source, [...bySource.get(source) ?? [], item]);
|
|
139
|
+
}
|
|
140
|
+
const report = [];
|
|
141
|
+
for (const [source, items] of bySource) {
|
|
142
|
+
const first = items[0][1];
|
|
143
|
+
const apply = (statuses) => {
|
|
144
|
+
for (const [name] of items)
|
|
145
|
+
report.push({ name, status: statuses[name] ?? 'unknown' });
|
|
146
|
+
};
|
|
147
|
+
if (first.sourceType === 'local') {
|
|
148
|
+
// The CLI stores portable relative sources; they resolve against the lock file's directory.
|
|
149
|
+
const sourceRoot = isAbsolute(source) ? source : resolve(this.root, source);
|
|
150
|
+
const statuses = {};
|
|
151
|
+
for (const [name] of items) {
|
|
152
|
+
const [sourceHash, installedHash] = await Promise.all([
|
|
153
|
+
computeSkillFolderHash(join(sourceRoot, name)).catch(() => undefined),
|
|
154
|
+
computeSkillFolderHash(join(this.library, name)).catch(() => undefined),
|
|
155
|
+
]);
|
|
156
|
+
statuses[name] = sourceHash === undefined ? 'unknown' : sourceHash === installedHash ? 'current' : 'update-available';
|
|
157
|
+
}
|
|
158
|
+
apply(statuses);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (first.sourceType === 'github' || first.sourceType === 'git' || first.sourceType === 'gitlab') {
|
|
162
|
+
if (!first.skillPath) {
|
|
163
|
+
apply({});
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
// ponytail: always shallow-clone and compare content hashes. The CLI's project lock stores content
|
|
167
|
+
// hashes even for github sources, so the GitHub tree API (tree SHAs) is not comparable to it.
|
|
168
|
+
const url = first.sourceUrl || source;
|
|
169
|
+
let latest;
|
|
170
|
+
try {
|
|
171
|
+
latest = await computeLatestHashesFromGit(url, first.ref, items.map(([, entry]) => entry.skillPath));
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
apply({});
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const statuses = {};
|
|
178
|
+
for (const [name, entry] of items) {
|
|
179
|
+
if (!latest.paths.has(entry.skillPath)) {
|
|
180
|
+
statuses[name] = 'deleted-upstream';
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const remote = latest.hashes.get(entry.skillPath);
|
|
184
|
+
if (!remote) {
|
|
185
|
+
statuses[name] = 'unknown';
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
// Compare against the installed copy so locally-diverged installs show as updatable.
|
|
189
|
+
const installed = await computeSkillFolderHash(join(this.library, name)).catch(() => undefined);
|
|
190
|
+
statuses[name] = installed === undefined ? 'unknown' : installed === remote ? 'current' : 'update-available';
|
|
191
|
+
}
|
|
192
|
+
apply(statuses);
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
apply({});
|
|
196
|
+
}
|
|
197
|
+
return { entries: report.sort((a, b) => a.name.localeCompare(b.name)) };
|
|
198
|
+
}
|
|
123
199
|
async setEnabled(name, scope, projectRoot, enabled) {
|
|
124
200
|
await this.loaded;
|
|
125
201
|
await this.assertInstalled(name);
|
|
@@ -235,6 +311,8 @@ async function handleRpc(manager, endpoint, payload) {
|
|
|
235
311
|
};
|
|
236
312
|
case 'remove':
|
|
237
313
|
return { ok: true, value: await manager.remove(requiredString(args.name, 'name'), asOptionalString(args.projectRoot)) };
|
|
314
|
+
case 'check-updates':
|
|
315
|
+
return { ok: true, value: await manager.checkUpdates() };
|
|
238
316
|
default:
|
|
239
317
|
throw new Error(`unknown skill-manager endpoint: ${endpoint}`);
|
|
240
318
|
}
|
|
@@ -379,3 +457,69 @@ function isRecord(value) {
|
|
|
379
457
|
function isNodeError(value) {
|
|
380
458
|
return value instanceof Error && 'code' in value;
|
|
381
459
|
}
|
|
460
|
+
// Same algorithm as the skills CLI: sha256 over sorted "relativePath + content" of every file below the skill folder.
|
|
461
|
+
async function computeSkillFolderHash(skillDir) {
|
|
462
|
+
const files = [];
|
|
463
|
+
const collect = async (directory) => {
|
|
464
|
+
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
465
|
+
if (entry.name === '.git' || entry.name === 'node_modules')
|
|
466
|
+
continue;
|
|
467
|
+
const fullPath = join(directory, entry.name);
|
|
468
|
+
if (entry.isDirectory())
|
|
469
|
+
await collect(fullPath);
|
|
470
|
+
else if (entry.isFile())
|
|
471
|
+
files.push({ relativePath: relative(skillDir, fullPath).split(sep).join('/'), content: await readFile(fullPath) });
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
await collect(skillDir);
|
|
475
|
+
files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
476
|
+
const hash = createHash('sha256');
|
|
477
|
+
for (const file of files) {
|
|
478
|
+
hash.update(file.relativePath);
|
|
479
|
+
hash.update(file.content);
|
|
480
|
+
}
|
|
481
|
+
return hash.digest('hex');
|
|
482
|
+
}
|
|
483
|
+
function skillFolderFromPath(skillPath) {
|
|
484
|
+
let folder = skillPath.replace(/\\/g, '/');
|
|
485
|
+
if (folder.toLowerCase().endsWith('/skill.md'))
|
|
486
|
+
folder = folder.slice(0, -'/skill.md'.length);
|
|
487
|
+
else if (folder.toLowerCase().endsWith('skill.md'))
|
|
488
|
+
folder = folder.slice(0, -'skill.md'.length);
|
|
489
|
+
return folder.endsWith('/') ? folder.slice(0, -1) : folder;
|
|
490
|
+
}
|
|
491
|
+
// Mirror the CLI's update check: shallow clone the source and hash the skill folders.
|
|
492
|
+
async function computeLatestHashesFromGit(url, ref, skillPaths) {
|
|
493
|
+
const temporaryRoot = await mkdtemp(join(tmpdir(), 'dsh-skill-manager-check-'));
|
|
494
|
+
try {
|
|
495
|
+
await execFileAsync('git', ['clone', '--depth', '1', '--no-recurse-submodules', ...ref ? ['--branch', ref] : [], preflightRepositorySource(url), join(temporaryRoot, 'repo')], {
|
|
496
|
+
timeout: 120_000,
|
|
497
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
498
|
+
});
|
|
499
|
+
const repo = join(temporaryRoot, 'repo');
|
|
500
|
+
const paths = new Set();
|
|
501
|
+
const walk = async (directory) => {
|
|
502
|
+
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
503
|
+
if (entry.name === '.git')
|
|
504
|
+
continue;
|
|
505
|
+
const fullPath = join(directory, entry.name);
|
|
506
|
+
if (entry.isDirectory())
|
|
507
|
+
await walk(fullPath);
|
|
508
|
+
else if (entry.isFile())
|
|
509
|
+
paths.add(relative(repo, fullPath).split(sep).join('/'));
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
await walk(repo);
|
|
513
|
+
const hashes = new Map();
|
|
514
|
+
for (const skillPath of skillPaths) {
|
|
515
|
+
if (!paths.has(skillPath))
|
|
516
|
+
continue;
|
|
517
|
+
const folder = join(repo, skillFolderFromPath(skillPath));
|
|
518
|
+
hashes.set(skillPath, await computeSkillFolderHash(folder).catch(() => ''));
|
|
519
|
+
}
|
|
520
|
+
return { paths, hashes };
|
|
521
|
+
}
|
|
522
|
+
finally {
|
|
523
|
+
await rm(temporaryRoot, { recursive: true, force: true });
|
|
524
|
+
}
|
|
525
|
+
}
|
package/lib/types/types.d.ts
CHANGED
|
@@ -23,3 +23,11 @@ export interface SkillCatalogEntry {
|
|
|
23
23
|
export interface SkillCatalog {
|
|
24
24
|
readonly entries: readonly SkillCatalogEntry[];
|
|
25
25
|
}
|
|
26
|
+
export type SkillUpdateStatus = 'update-available' | 'current' | 'deleted-upstream' | 'unknown';
|
|
27
|
+
export interface SkillUpdateReportEntry {
|
|
28
|
+
readonly name: string;
|
|
29
|
+
readonly status: SkillUpdateStatus;
|
|
30
|
+
}
|
|
31
|
+
export interface SkillUpdateReport {
|
|
32
|
+
readonly entries: readonly SkillUpdateReportEntry[];
|
|
33
|
+
}
|