@michengai/dsh-skills-manager 1.1.18 → 1.1.21
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/CHANGELOG.md +17 -0
- package/CHANGELOG.zh-CN.md +17 -0
- package/README.md +29 -25
- package/README.zh-CN.md +28 -24
- package/assets/brands/agents.svg +1 -0
- package/assets/brands/cc-switch.png +0 -0
- package/assets/brands/claude.svg +1 -0
- package/assets/brands/codebuddy.svg +1 -0
- package/assets/brands/codex.svg +1 -0
- package/assets/brands/copilot.svg +1 -0
- package/assets/brands/cursor.svg +7 -0
- package/assets/brands/dsh.png +0 -0
- package/assets/brands/gemini.svg +1 -0
- package/assets/brands/openclaw.svg +1 -0
- package/assets/brands/opencode.svg +1 -0
- package/assets/brands/qoder.svg +1 -0
- package/assets/brands/roo.svg +1 -0
- package/assets/brands/trae.svg +1 -0
- package/assets/brands/windsurf.svg +1 -0
- package/assets/brands/workbuddy.png +0 -0
- package/assets/screenshots/project-skills.webp +0 -0
- package/assets/screenshots/skill-repositories.webp +0 -0
- package/assets/screenshots/skills-manager-v2-preview.webp +0 -0
- package/lib/catalog-skill.js +142 -0
- package/lib/clawhub-catalog.js +134 -0
- package/lib/client.js +97 -83
- package/lib/core.js +140 -37
- package/lib/index.js +51 -15
- package/lib/repositories.js +370 -57
- package/lib/repository-updates.js +8 -2
- package/lib/skills-sh-catalog.js +92 -0
- package/package.json +9 -9
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const SEARCH_URL = "https://skills.sh/api/search";
|
|
2
|
+
const MAX_QUERY_LENGTH = 100;
|
|
3
|
+
const MAX_RESPONSE_BYTES = 1 << 20;
|
|
4
|
+
const MAX_RESULTS = 100;
|
|
5
|
+
const IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
6
|
+
function catalogError(message, statusCode, code) {
|
|
7
|
+
return Object.assign(new Error(message), { statusCode, code });
|
|
8
|
+
}
|
|
9
|
+
function boundedString(value, maxLength) {
|
|
10
|
+
if (typeof value !== "string") return void 0;
|
|
11
|
+
const text = value.trim();
|
|
12
|
+
return text && text.length <= maxLength ? text : void 0;
|
|
13
|
+
}
|
|
14
|
+
async function searchSkillsSh(query) {
|
|
15
|
+
const normalized = typeof query === "string" ? query.trim() : "";
|
|
16
|
+
if (!normalized || normalized.length > MAX_QUERY_LENGTH) {
|
|
17
|
+
throw catalogError("\u641C\u7D22\u8BCD\u4E0D\u80FD\u4E3A\u7A7A\u4E14\u4E0D\u80FD\u8D85\u8FC7 100 \u4E2A\u5B57\u7B26", 400, "error.catalog.query");
|
|
18
|
+
}
|
|
19
|
+
const url = new URL(SEARCH_URL);
|
|
20
|
+
url.searchParams.set("q", normalized);
|
|
21
|
+
let response;
|
|
22
|
+
try {
|
|
23
|
+
response = await fetch(url, {
|
|
24
|
+
headers: { accept: "application/json" },
|
|
25
|
+
redirect: "error",
|
|
26
|
+
signal: AbortSignal.timeout(1e4)
|
|
27
|
+
});
|
|
28
|
+
} catch {
|
|
29
|
+
throw catalogError("skills.sh \u641C\u7D22\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528", 502, "error.catalog.upstream");
|
|
30
|
+
}
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
throw catalogError("skills.sh \u641C\u7D22\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528", 502, "error.catalog.upstream");
|
|
33
|
+
}
|
|
34
|
+
const contentLength = Number(response.headers.get("content-length"));
|
|
35
|
+
if (Number.isFinite(contentLength) && contentLength > MAX_RESPONSE_BYTES) {
|
|
36
|
+
await response.body?.cancel().catch(() => void 0);
|
|
37
|
+
throw catalogError("skills.sh \u641C\u7D22\u54CD\u5E94\u8FC7\u5927", 502, "error.catalog.response");
|
|
38
|
+
}
|
|
39
|
+
const chunks = [];
|
|
40
|
+
let size = 0;
|
|
41
|
+
const reader = response.body?.getReader();
|
|
42
|
+
if (reader) {
|
|
43
|
+
try {
|
|
44
|
+
while (true) {
|
|
45
|
+
const { done, value } = await reader.read();
|
|
46
|
+
if (done) break;
|
|
47
|
+
size += value.byteLength;
|
|
48
|
+
if (size > MAX_RESPONSE_BYTES) {
|
|
49
|
+
throw catalogError("skills.sh \u641C\u7D22\u54CD\u5E94\u8FC7\u5927", 502, "error.catalog.response");
|
|
50
|
+
}
|
|
51
|
+
chunks.push(value);
|
|
52
|
+
}
|
|
53
|
+
} catch (error) {
|
|
54
|
+
await reader.cancel().catch(() => void 0);
|
|
55
|
+
if (error instanceof Error && "code" in error && error.code === "error.catalog.response" && "statusCode" in error && error.statusCode === 502) throw error;
|
|
56
|
+
throw catalogError("skills.sh \u641C\u7D22\u54CD\u5E94\u65E0\u6548\u6216\u8BFB\u53D6\u4E2D\u65AD", 502, "error.catalog.response");
|
|
57
|
+
} finally {
|
|
58
|
+
reader.releaseLock();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const body = Buffer.concat(chunks, size).toString("utf8");
|
|
62
|
+
let payload;
|
|
63
|
+
try {
|
|
64
|
+
payload = JSON.parse(body);
|
|
65
|
+
} catch {
|
|
66
|
+
throw catalogError("skills.sh \u8FD4\u56DE\u4E86\u65E0\u6548\u7684\u641C\u7D22\u7ED3\u679C", 502, "error.catalog.response");
|
|
67
|
+
}
|
|
68
|
+
if (!payload || !Array.isArray(payload.skills)) {
|
|
69
|
+
throw catalogError("skills.sh \u8FD4\u56DE\u4E86\u65E0\u6548\u7684\u641C\u7D22\u7ED3\u679C", 502, "error.catalog.response");
|
|
70
|
+
}
|
|
71
|
+
const skills = [];
|
|
72
|
+
const seen = /* @__PURE__ */ new Set();
|
|
73
|
+
for (const candidate of payload.skills) {
|
|
74
|
+
if (!candidate || typeof candidate !== "object") continue;
|
|
75
|
+
const source = typeof candidate.source === "string" && candidate.source.split("/").length === 2 && candidate.source.split("/").every((part) => IDENTIFIER.test(part)) ? candidate.source : void 0;
|
|
76
|
+
const skillId = typeof candidate.skillId === "string" && IDENTIFIER.test(candidate.skillId) ? candidate.skillId : void 0;
|
|
77
|
+
const name = boundedString(candidate.name, 256);
|
|
78
|
+
const id = boundedString(candidate.id, 768) || (source && skillId ? `${source}/${skillId}` : void 0);
|
|
79
|
+
if (!id || !source || !skillId || !name || seen.has(id)) continue;
|
|
80
|
+
const item = { id, source, skillId, name };
|
|
81
|
+
if (typeof candidate.installs === "number" && Number.isSafeInteger(candidate.installs) && candidate.installs >= 0) {
|
|
82
|
+
item.installs = candidate.installs;
|
|
83
|
+
}
|
|
84
|
+
skills.push(item);
|
|
85
|
+
seen.add(id);
|
|
86
|
+
if (skills.length >= MAX_RESULTS) break;
|
|
87
|
+
}
|
|
88
|
+
return { skills };
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
searchSkillsSh
|
|
92
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@michengai/dsh-skills-manager",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.21",
|
|
4
4
|
"description": "DSH Skills Manager — 在 DeepSeek Harness 中统一加载并安全管理本机 Agent Skills · Load and safely manage local Agent Skills in DSH",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "node scripts/build.mjs",
|
|
45
|
-
"test": "npm run typecheck && npm run build && node test/build-test.mjs && node test/route-lifecycle.test.mjs && node test/repositories.test.mjs && node test/repository-install-targets.test.mjs && node test/workspace-target.test.mjs && node test/workspace-routes.test.mjs && node test/workspace-list.test.mjs && node test/destination-picker.test.mjs && node test/workspace-project-page.test.mjs && node test/repository-ui.test.mjs && node test/theme-select.test.mjs && node test/host-fallback.test.mjs && node test/repository-routes.test.mjs && node test/core-test.mjs && node test/disabled-external-native.test.mjs && node test/categories.test.mjs && node test/categories-ui.test.mjs && node test/readonly-discovery.test.mjs && node test/project-root-skills.test.mjs && node test/project-sources.test.mjs && node test/locale-test.mjs && node --test test/plugin-updater.test.mjs && node test/plugin-update-locale.test.mjs && node test/client-scope.test.mjs && node test/compatibility-options-test.mjs",
|
|
45
|
+
"test": "npm run typecheck && npm run build && node test/build-test.mjs && node test/route-lifecycle.test.mjs && node test/repositories.test.mjs && node test/repository-install-targets.test.mjs && node test/workspace-target.test.mjs && node test/workspace-routes.test.mjs && node test/workspace-list.test.mjs && node test/destination-picker.test.mjs && node test/workspace-project-page.test.mjs && node test/repository-ui.test.mjs && node test/catalog-skill.test.mjs && node test/skills-sh-catalog.test.mjs && node test/clawhub-catalog.test.mjs && node --test test/catalog-state.test.mjs test/catalog-lifecycle.test.mjs && node test/theme-select.test.mjs && node test/host-fallback.test.mjs && node test/repository-routes.test.mjs && node test/core-test.mjs && node test/disabled-external-native.test.mjs && node test/categories.test.mjs && node test/categories-ui.test.mjs && node test/readonly-discovery.test.mjs && node test/project-root-skills.test.mjs && node test/project-sources.test.mjs && node test/locale-test.mjs && node --test test/plugin-updater.test.mjs && node test/plugin-update-locale.test.mjs && node test/client-scope.test.mjs && node test/compatibility-options-test.mjs",
|
|
46
46
|
"verify": "node scripts/sync-hosts.mjs && npm test && npm run pack:check && node test/pack-test.mjs",
|
|
47
47
|
"pack:check": "npm pack --dry-run --json",
|
|
48
48
|
"prepack": "npm run typecheck && npm run build",
|
|
@@ -56,13 +56,13 @@
|
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"@deepseek-ai/cordis": ">=4.0.1 <5.0.0",
|
|
59
|
-
"@deepseek-ai/dsh-client-locale": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2",
|
|
60
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2",
|
|
61
|
-
"@deepseek-ai/dsh-host-webserver": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2",
|
|
62
|
-
"@deepseek-ai/dsh-session": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2",
|
|
63
|
-
"@deepseek-ai/dsh-skill": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2",
|
|
64
|
-
"@deepseek-ai/dsh-tools": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2",
|
|
65
|
-
"@deepseek-ai/dsh-web-app": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2",
|
|
59
|
+
"@deepseek-ai/dsh-client-locale": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
|
|
60
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
|
|
61
|
+
"@deepseek-ai/dsh-host-webserver": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
|
|
62
|
+
"@deepseek-ai/dsh-session": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
|
|
63
|
+
"@deepseek-ai/dsh-skill": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
|
|
64
|
+
"@deepseek-ai/dsh-tools": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
|
|
65
|
+
"@deepseek-ai/dsh-web-app": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
|
|
66
66
|
"react": "^18.2.0",
|
|
67
67
|
"react-dom": "^18.2.0"
|
|
68
68
|
},
|