@wingman-ai/gateway 0.4.1 → 0.4.3
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 +14 -0
- package/dist/agent/config/mcpClientManager.cjs +104 -1
- package/dist/agent/config/mcpClientManager.d.ts +30 -0
- package/dist/agent/config/mcpClientManager.js +104 -1
- package/dist/agent/config/modelFactory.cjs +10 -0
- package/dist/agent/config/modelFactory.js +10 -0
- package/dist/agent/config/xaiImageModel.cjs +242 -0
- package/dist/agent/config/xaiImageModel.d.ts +33 -0
- package/dist/agent/config/xaiImageModel.js +202 -0
- package/dist/agent/tests/mcpClientManager.test.cjs +116 -0
- package/dist/agent/tests/mcpClientManager.test.js +117 -1
- package/dist/agent/tests/mcpResourceTools.test.cjs +101 -0
- package/dist/agent/tests/mcpResourceTools.test.d.ts +1 -0
- package/dist/agent/tests/mcpResourceTools.test.js +95 -0
- package/dist/agent/tests/modelFactory.test.cjs +16 -2
- package/dist/agent/tests/modelFactory.test.js +16 -2
- package/dist/agent/tests/xaiImageModel.test.cjs +194 -0
- package/dist/agent/tests/xaiImageModel.test.d.ts +1 -0
- package/dist/agent/tests/xaiImageModel.test.js +188 -0
- package/dist/agent/tools/mcp_resources.cjs +111 -0
- package/dist/agent/tools/mcp_resources.d.ts +3 -0
- package/dist/agent/tools/mcp_resources.js +77 -0
- package/dist/bench/adapters/commandAdapter.cjs +93 -0
- package/dist/bench/adapters/commandAdapter.d.ts +6 -0
- package/dist/bench/adapters/commandAdapter.js +59 -0
- package/dist/bench/adapters/helpers.cjs +170 -0
- package/dist/bench/adapters/helpers.d.ts +7 -0
- package/dist/bench/adapters/helpers.js +133 -0
- package/dist/bench/adapters/index.cjs +41 -0
- package/dist/bench/adapters/index.d.ts +2 -0
- package/dist/bench/adapters/index.js +7 -0
- package/dist/bench/adapters/wingmanCliAdapter.cjs +100 -0
- package/dist/bench/adapters/wingmanCliAdapter.d.ts +6 -0
- package/dist/bench/adapters/wingmanCliAdapter.js +66 -0
- package/dist/bench/cleanup.cjs +122 -0
- package/dist/bench/cleanup.d.ts +9 -0
- package/dist/bench/cleanup.js +85 -0
- package/dist/bench/config.cjs +190 -0
- package/dist/bench/config.d.ts +2 -0
- package/dist/bench/config.js +156 -0
- package/dist/bench/index.cjs +43 -0
- package/dist/bench/index.d.ts +3 -0
- package/dist/bench/index.js +3 -0
- package/dist/bench/official.cjs +616 -0
- package/dist/bench/official.d.ts +80 -0
- package/dist/bench/official.js +546 -0
- package/dist/bench/officialCli.cjs +204 -0
- package/dist/bench/officialCli.d.ts +5 -0
- package/dist/bench/officialCli.js +170 -0
- package/dist/bench/process.cjs +78 -0
- package/dist/bench/process.d.ts +14 -0
- package/dist/bench/process.js +44 -0
- package/dist/bench/runner.cjs +237 -0
- package/dist/bench/runner.d.ts +7 -0
- package/dist/bench/runner.js +197 -0
- package/dist/bench/scoring.cjs +171 -0
- package/dist/bench/scoring.d.ts +9 -0
- package/dist/bench/scoring.js +137 -0
- package/dist/bench/types.cjs +18 -0
- package/dist/bench/types.d.ts +200 -0
- package/dist/bench/types.js +0 -0
- package/dist/bench/validator.cjs +92 -0
- package/dist/bench/validator.d.ts +2 -0
- package/dist/bench/validator.js +58 -0
- package/dist/cli/commands/init.cjs +135 -1
- package/dist/cli/commands/init.js +136 -2
- package/dist/cli/commands/skill.cjs +7 -3
- package/dist/cli/commands/skill.js +7 -3
- package/dist/cli/config/loader.cjs +7 -3
- package/dist/cli/config/loader.js +7 -3
- package/dist/cli/config/schema.cjs +63 -10
- package/dist/cli/config/schema.d.ts +64 -4
- package/dist/cli/config/schema.js +59 -9
- package/dist/cli/config/warnings.cjs +119 -51
- package/dist/cli/config/warnings.js +119 -51
- package/dist/cli/core/agentInvoker.cjs +58 -13
- package/dist/cli/core/agentInvoker.d.ts +1 -0
- package/dist/cli/core/agentInvoker.js +58 -13
- package/dist/cli/core/imagePersistence.cjs +17 -1
- package/dist/cli/core/imagePersistence.d.ts +2 -0
- package/dist/cli/core/imagePersistence.js +13 -3
- package/dist/cli/core/sessionManager.cjs +2 -0
- package/dist/cli/core/sessionManager.js +3 -1
- package/dist/cli/services/skillRepository.cjs +155 -69
- package/dist/cli/services/skillRepository.d.ts +7 -2
- package/dist/cli/services/skillRepository.js +155 -69
- package/dist/cli/services/skillService.cjs +93 -26
- package/dist/cli/services/skillService.d.ts +7 -0
- package/dist/cli/services/skillService.js +96 -29
- package/dist/cli/types/skill.d.ts +8 -3
- package/dist/cli/types.d.ts +18 -0
- package/dist/gateway/adapters/teams.cjs +419 -0
- package/dist/gateway/adapters/teams.d.ts +47 -0
- package/dist/gateway/adapters/teams.js +361 -0
- package/dist/gateway/http/sms.cjs +286 -0
- package/dist/gateway/http/sms.d.ts +4 -0
- package/dist/gateway/http/sms.js +249 -0
- package/dist/gateway/server.cjs +54 -3
- package/dist/gateway/server.d.ts +2 -0
- package/dist/gateway/server.js +54 -3
- package/dist/gateway/sms/commands.cjs +116 -0
- package/dist/gateway/sms/commands.d.ts +15 -0
- package/dist/gateway/sms/commands.js +79 -0
- package/dist/gateway/sms/control.cjs +118 -0
- package/dist/gateway/sms/control.d.ts +18 -0
- package/dist/gateway/sms/control.js +84 -0
- package/dist/gateway/sms/policyStore.cjs +198 -0
- package/dist/gateway/sms/policyStore.d.ts +37 -0
- package/dist/gateway/sms/policyStore.js +161 -0
- package/dist/providers/registry.cjs +1 -0
- package/dist/providers/registry.js +1 -0
- package/dist/skills/activation.cjs +92 -0
- package/dist/skills/activation.d.ts +12 -0
- package/dist/skills/activation.js +58 -0
- package/dist/skills/bin-requirements.cjs +63 -0
- package/dist/skills/bin-requirements.d.ts +3 -0
- package/dist/skills/bin-requirements.js +26 -0
- package/dist/skills/metadata.cjs +141 -0
- package/dist/skills/metadata.d.ts +29 -0
- package/dist/skills/metadata.js +104 -0
- package/dist/skills/overlay.cjs +75 -0
- package/dist/skills/overlay.d.ts +2 -0
- package/dist/skills/overlay.js +38 -0
- package/dist/tests/cli-config-loader.test.cjs +7 -3
- package/dist/tests/cli-config-loader.test.js +7 -3
- package/dist/tests/cli-config-warnings.test.cjs +41 -0
- package/dist/tests/cli-config-warnings.test.js +41 -0
- package/dist/tests/cli-init.test.cjs +86 -26
- package/dist/tests/cli-init.test.js +86 -26
- package/dist/tests/config-json-schema.test.cjs +12 -0
- package/dist/tests/config-json-schema.test.js +12 -0
- package/dist/tests/gateway-http-security.test.cjs +21 -0
- package/dist/tests/gateway-http-security.test.js +21 -0
- package/dist/tests/gateway-origin-policy.test.cjs +22 -0
- package/dist/tests/gateway-origin-policy.test.js +22 -0
- package/dist/tests/gateway.test.cjs +57 -0
- package/dist/tests/gateway.test.js +57 -0
- package/dist/tests/imagePersistence.test.cjs +26 -0
- package/dist/tests/imagePersistence.test.js +27 -1
- package/dist/tests/run-terminal-bench-official-script.test.cjs +61 -0
- package/dist/tests/run-terminal-bench-official-script.test.d.ts +1 -0
- package/dist/tests/run-terminal-bench-official-script.test.js +55 -0
- package/dist/tests/sessions-api.test.cjs +69 -1
- package/dist/tests/sessions-api.test.js +70 -2
- package/dist/tests/skill-activation.test.cjs +86 -0
- package/dist/tests/skill-activation.test.d.ts +1 -0
- package/dist/tests/skill-activation.test.js +80 -0
- package/dist/tests/skill-metadata.test.cjs +119 -0
- package/dist/tests/skill-metadata.test.d.ts +1 -0
- package/dist/tests/skill-metadata.test.js +113 -0
- package/dist/tests/skill-repository.test.cjs +363 -0
- package/dist/tests/skill-repository.test.js +363 -0
- package/dist/tests/sms-api.test.cjs +183 -0
- package/dist/tests/sms-api.test.d.ts +1 -0
- package/dist/tests/sms-api.test.js +177 -0
- package/dist/tests/sms-commands.test.cjs +90 -0
- package/dist/tests/sms-commands.test.d.ts +1 -0
- package/dist/tests/sms-commands.test.js +84 -0
- package/dist/tests/sms-policy-store.test.cjs +69 -0
- package/dist/tests/sms-policy-store.test.d.ts +1 -0
- package/dist/tests/sms-policy-store.test.js +63 -0
- package/dist/tests/teams-adapter.test.cjs +58 -0
- package/dist/tests/teams-adapter.test.d.ts +1 -0
- package/dist/tests/teams-adapter.test.js +52 -0
- package/dist/tests/terminal-bench-adapters-helpers.test.cjs +64 -0
- package/dist/tests/terminal-bench-adapters-helpers.test.d.ts +1 -0
- package/dist/tests/terminal-bench-adapters-helpers.test.js +58 -0
- package/dist/tests/terminal-bench-cleanup.test.cjs +93 -0
- package/dist/tests/terminal-bench-cleanup.test.d.ts +1 -0
- package/dist/tests/terminal-bench-cleanup.test.js +87 -0
- package/dist/tests/terminal-bench-config.test.cjs +62 -0
- package/dist/tests/terminal-bench-config.test.d.ts +1 -0
- package/dist/tests/terminal-bench-config.test.js +56 -0
- package/dist/tests/terminal-bench-official.test.cjs +194 -0
- package/dist/tests/terminal-bench-official.test.d.ts +1 -0
- package/dist/tests/terminal-bench-official.test.js +188 -0
- package/dist/tests/terminal-bench-runner.test.cjs +82 -0
- package/dist/tests/terminal-bench-runner.test.d.ts +1 -0
- package/dist/tests/terminal-bench-runner.test.js +76 -0
- package/dist/tests/terminal-bench-scoring.test.cjs +128 -0
- package/dist/tests/terminal-bench-scoring.test.d.ts +1 -0
- package/dist/tests/terminal-bench-scoring.test.js +122 -0
- package/dist/tools/mcp-fal-ai.cjs +1 -1
- package/dist/tools/mcp-fal-ai.js +1 -1
- package/dist/webui/assets/index-Cyg_Hs57.css +11 -0
- package/dist/webui/assets/{index-BMekSELC.js → index-DZXLLjaA.js} +109 -109
- package/dist/webui/index.html +2 -2
- package/package.json +14 -5
- package/skills/gog/SKILL.md +1 -1
- package/skills/weather/SKILL.md +1 -1
- package/templates/agents/game-dev/agent.md +122 -63
- package/templates/agents/game-dev/art-director.md +106 -0
- package/templates/agents/game-dev/game-designer.md +87 -0
- package/templates/agents/game-dev/scene-engineer.md +474 -0
- package/dist/webui/assets/index-Cwkg4DKj.css +0 -11
- package/skills/ui-registry/SKILL.md +0 -35
- package/templates/agents/game-dev/art-generation.md +0 -38
- package/templates/agents/game-dev/asset-refinement.md +0 -17
- package/templates/agents/game-dev/planning-idea.md +0 -17
- package/templates/agents/game-dev/ui-specialist.md +0 -17
|
@@ -24,6 +24,8 @@ var __webpack_require__ = {};
|
|
|
24
24
|
var __webpack_exports__ = {};
|
|
25
25
|
__webpack_require__.r(__webpack_exports__);
|
|
26
26
|
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
removeSessionMediaDirectory: ()=>removeSessionMediaDirectory,
|
|
28
|
+
getSessionMediaDirectory: ()=>getSessionMediaDirectory,
|
|
27
29
|
persistAssistantImagesToDisk: ()=>persistAssistantImagesToDisk,
|
|
28
30
|
parseBase64DataUrl: ()=>parseBase64DataUrl,
|
|
29
31
|
resolveImageExtension: ()=>resolveImageExtension
|
|
@@ -34,7 +36,7 @@ const external_node_path_namespaceObject = require("node:path");
|
|
|
34
36
|
const DATA_URL_BASE64_PATTERN = /^data:([^;,]+);base64,(.+)$/i;
|
|
35
37
|
function persistAssistantImagesToDisk(input) {
|
|
36
38
|
if (!input.messages.length) return;
|
|
37
|
-
const mediaRoot = (
|
|
39
|
+
const mediaRoot = getSessionMediaDirectory(input.dbPath, input.sessionId);
|
|
38
40
|
for (const message of input.messages)if ("assistant" === message.role) {
|
|
39
41
|
if (Array.isArray(message.attachments) && 0 !== message.attachments.length) for (const attachment of message.attachments){
|
|
40
42
|
if (!attachment || "image" !== attachment.kind) continue;
|
|
@@ -66,6 +68,16 @@ function persistAssistantImagesToDisk(input) {
|
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
70
|
}
|
|
71
|
+
function getSessionMediaDirectory(dbPath, sessionId) {
|
|
72
|
+
return (0, external_node_path_namespaceObject.join)((0, external_node_path_namespaceObject.dirname)(dbPath), "media", sanitizePathSegment(sessionId));
|
|
73
|
+
}
|
|
74
|
+
function removeSessionMediaDirectory(dbPath, sessionId) {
|
|
75
|
+
const mediaDir = getSessionMediaDirectory(dbPath, sessionId);
|
|
76
|
+
(0, external_node_fs_namespaceObject.rmSync)(mediaDir, {
|
|
77
|
+
recursive: true,
|
|
78
|
+
force: true
|
|
79
|
+
});
|
|
80
|
+
}
|
|
69
81
|
function parseBase64DataUrl(dataUrl) {
|
|
70
82
|
if ("string" != typeof dataUrl) return null;
|
|
71
83
|
const match = dataUrl.match(DATA_URL_BASE64_PATTERN);
|
|
@@ -112,12 +124,16 @@ function sanitizePathSegment(value) {
|
|
|
112
124
|
const sanitized = normalized.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
113
125
|
return sanitized.slice(0, 120) || "default-session";
|
|
114
126
|
}
|
|
127
|
+
exports.getSessionMediaDirectory = __webpack_exports__.getSessionMediaDirectory;
|
|
115
128
|
exports.parseBase64DataUrl = __webpack_exports__.parseBase64DataUrl;
|
|
116
129
|
exports.persistAssistantImagesToDisk = __webpack_exports__.persistAssistantImagesToDisk;
|
|
130
|
+
exports.removeSessionMediaDirectory = __webpack_exports__.removeSessionMediaDirectory;
|
|
117
131
|
exports.resolveImageExtension = __webpack_exports__.resolveImageExtension;
|
|
118
132
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
133
|
+
"getSessionMediaDirectory",
|
|
119
134
|
"parseBase64DataUrl",
|
|
120
135
|
"persistAssistantImagesToDisk",
|
|
136
|
+
"removeSessionMediaDirectory",
|
|
121
137
|
"resolveImageExtension"
|
|
122
138
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
123
139
|
Object.defineProperty(exports, '__esModule', {
|
|
@@ -19,6 +19,8 @@ export declare function persistAssistantImagesToDisk(input: {
|
|
|
19
19
|
sessionId: string;
|
|
20
20
|
messages: PersistableMessage[];
|
|
21
21
|
}): void;
|
|
22
|
+
export declare function getSessionMediaDirectory(dbPath: string, sessionId: string): string;
|
|
23
|
+
export declare function removeSessionMediaDirectory(dbPath: string, sessionId: string): void;
|
|
22
24
|
export declare function parseBase64DataUrl(dataUrl: string): ParsedDataUrl | null;
|
|
23
25
|
export declare function resolveImageExtension(mimeType: string): string;
|
|
24
26
|
export {};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
const DATA_URL_BASE64_PATTERN = /^data:([^;,]+);base64,(.+)$/i;
|
|
5
5
|
function persistAssistantImagesToDisk(input) {
|
|
6
6
|
if (!input.messages.length) return;
|
|
7
|
-
const mediaRoot =
|
|
7
|
+
const mediaRoot = getSessionMediaDirectory(input.dbPath, input.sessionId);
|
|
8
8
|
for (const message of input.messages)if ("assistant" === message.role) {
|
|
9
9
|
if (Array.isArray(message.attachments) && 0 !== message.attachments.length) for (const attachment of message.attachments){
|
|
10
10
|
if (!attachment || "image" !== attachment.kind) continue;
|
|
@@ -36,6 +36,16 @@ function persistAssistantImagesToDisk(input) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
+
function getSessionMediaDirectory(dbPath, sessionId) {
|
|
40
|
+
return join(dirname(dbPath), "media", sanitizePathSegment(sessionId));
|
|
41
|
+
}
|
|
42
|
+
function removeSessionMediaDirectory(dbPath, sessionId) {
|
|
43
|
+
const mediaDir = getSessionMediaDirectory(dbPath, sessionId);
|
|
44
|
+
rmSync(mediaDir, {
|
|
45
|
+
recursive: true,
|
|
46
|
+
force: true
|
|
47
|
+
});
|
|
48
|
+
}
|
|
39
49
|
function parseBase64DataUrl(dataUrl) {
|
|
40
50
|
if ("string" != typeof dataUrl) return null;
|
|
41
51
|
const match = dataUrl.match(DATA_URL_BASE64_PATTERN);
|
|
@@ -82,4 +92,4 @@ function sanitizePathSegment(value) {
|
|
|
82
92
|
const sanitized = normalized.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
83
93
|
return sanitized.slice(0, 120) || "default-session";
|
|
84
94
|
}
|
|
85
|
-
export { parseBase64DataUrl, persistAssistantImagesToDisk, resolveImageExtension };
|
|
95
|
+
export { getSessionMediaDirectory, parseBase64DataUrl, persistAssistantImagesToDisk, removeSessionMediaDirectory, resolveImageExtension };
|
|
@@ -227,6 +227,7 @@ class SessionManager {
|
|
|
227
227
|
writesStmt.run(sessionId);
|
|
228
228
|
const pendingStmt = this.db.prepare("DELETE FROM session_pending_messages WHERE session_id = ?");
|
|
229
229
|
pendingStmt.run(sessionId);
|
|
230
|
+
(0, external_imagePersistence_cjs_namespaceObject.removeSessionMediaDirectory)(this.dbPath, sessionId);
|
|
230
231
|
}
|
|
231
232
|
clearSessionMessages(sessionId) {
|
|
232
233
|
if (!this.db || !this.checkpointer) throw new Error("SessionManager not initialized");
|
|
@@ -242,6 +243,7 @@ class SessionManager {
|
|
|
242
243
|
WHERE id = ?
|
|
243
244
|
`);
|
|
244
245
|
sessionStmt.run(Date.now(), sessionId);
|
|
246
|
+
(0, external_imagePersistence_cjs_namespaceObject.removeSessionMediaDirectory)(this.dbPath, sessionId);
|
|
245
247
|
}
|
|
246
248
|
persistPendingMessage(input) {
|
|
247
249
|
if (!this.db) throw new Error("SessionManager not initialized");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SqliteSaver } from "@langchain/langgraph-checkpoint-sqlite";
|
|
2
2
|
import { createDeepAgent } from "deepagents";
|
|
3
3
|
import { v4 } from "uuid";
|
|
4
|
-
import { persistAssistantImagesToDisk } from "./imagePersistence.js";
|
|
4
|
+
import { persistAssistantImagesToDisk, removeSessionMediaDirectory } from "./imagePersistence.js";
|
|
5
5
|
function _define_property(obj, key, value) {
|
|
6
6
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
7
7
|
value: value,
|
|
@@ -194,6 +194,7 @@ class SessionManager {
|
|
|
194
194
|
writesStmt.run(sessionId);
|
|
195
195
|
const pendingStmt = this.db.prepare("DELETE FROM session_pending_messages WHERE session_id = ?");
|
|
196
196
|
pendingStmt.run(sessionId);
|
|
197
|
+
removeSessionMediaDirectory(this.dbPath, sessionId);
|
|
197
198
|
}
|
|
198
199
|
clearSessionMessages(sessionId) {
|
|
199
200
|
if (!this.db || !this.checkpointer) throw new Error("SessionManager not initialized");
|
|
@@ -209,6 +210,7 @@ class SessionManager {
|
|
|
209
210
|
WHERE id = ?
|
|
210
211
|
`);
|
|
211
212
|
sessionStmt.run(Date.now(), sessionId);
|
|
213
|
+
removeSessionMediaDirectory(this.dbPath, sessionId);
|
|
212
214
|
}
|
|
213
215
|
persistPendingMessage(input) {
|
|
214
216
|
if (!this.db) throw new Error("SessionManager not initialized");
|
|
@@ -27,6 +27,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
27
27
|
SkillRepository: ()=>SkillRepository
|
|
28
28
|
});
|
|
29
29
|
const external_logger_cjs_namespaceObject = require("../../logger.cjs");
|
|
30
|
+
const metadata_cjs_namespaceObject = require("../../skills/metadata.cjs");
|
|
30
31
|
function _define_property(obj, key, value) {
|
|
31
32
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
32
33
|
value: value,
|
|
@@ -63,7 +64,8 @@ class SkillRepository {
|
|
|
63
64
|
async listAvailableSkills() {
|
|
64
65
|
try {
|
|
65
66
|
if ("clawhub" === this.provider) return await this.listSkillsFromClawhub();
|
|
66
|
-
return await this.listSkillsFromGitHub();
|
|
67
|
+
if ("github" === this.provider) return await this.listSkillsFromGitHub();
|
|
68
|
+
return await this.listSkillsFromHybrid();
|
|
67
69
|
} catch (error) {
|
|
68
70
|
if (error instanceof Error) throw new Error(`Failed to list skills: ${error.message}`);
|
|
69
71
|
throw error;
|
|
@@ -85,19 +87,39 @@ class SkillRepository {
|
|
|
85
87
|
return Buffer.from(arrayBuffer);
|
|
86
88
|
}
|
|
87
89
|
async getSkillMetadata(skillName) {
|
|
88
|
-
if ("clawhub" === this.provider) return await this.getClawhubSkillMetadata(skillName);
|
|
89
90
|
try {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return
|
|
91
|
+
if ("clawhub" === this.provider) return await this.getClawhubSkillMetadata(skillName);
|
|
92
|
+
if ("github" === this.provider) {
|
|
93
|
+
const repository = await this.resolveGitHubRepositoryForSkill(skillName);
|
|
94
|
+
return await this.getGitHubSkillMetadata(skillName, repository);
|
|
95
|
+
}
|
|
96
|
+
return await this.getHybridSkillMetadata(skillName);
|
|
96
97
|
} catch (error) {
|
|
97
98
|
if (error instanceof Error) throw new Error(`Failed to fetch skill metadata for ${skillName}: ${error.message}`);
|
|
98
99
|
throw error;
|
|
99
100
|
}
|
|
100
101
|
}
|
|
102
|
+
async getGitHubSkillMetadata(skillName, repository) {
|
|
103
|
+
const skillMdPath = `/repos/${repository.owner}/${repository.name}/contents/skills/${skillName}/SKILL.md`;
|
|
104
|
+
const skillMd = await this.fetchGitHub(skillMdPath);
|
|
105
|
+
if ("file" !== skillMd.type || !skillMd.content) throw new Error(`SKILL.md not found or invalid in ${repository.owner}/${repository.name}`);
|
|
106
|
+
const content = Buffer.from(skillMd.content, "base64").toString("utf-8");
|
|
107
|
+
return this.parseSkillMetadata(content);
|
|
108
|
+
}
|
|
109
|
+
async resolveGitHubRepositoryForSkill(skillName) {
|
|
110
|
+
const repositories = this.getGitHubRepositories();
|
|
111
|
+
for(let index = repositories.length - 1; index >= 0; index -= 1){
|
|
112
|
+
const repository = repositories[index];
|
|
113
|
+
try {
|
|
114
|
+
await this.fetchGitHub(`/repos/${repository.owner}/${repository.name}/contents/skills/${skillName}/SKILL.md`);
|
|
115
|
+
return repository;
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (error instanceof Error && error.message.includes("Resource not found")) continue;
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
throw new Error(`Skill '${skillName}' not found in configured GitHub repositories: ${repositories.map((repository)=>`${repository.owner}/${repository.name}`).join(", ")}`);
|
|
122
|
+
}
|
|
101
123
|
async getClawhubSkillMetadata(skillName) {
|
|
102
124
|
try {
|
|
103
125
|
const detail = await this.fetchJson(`${this.clawhubBaseUrl}/api/v1/skills/${encodeURIComponent(skillName)}`, {
|
|
@@ -127,51 +149,50 @@ class SkillRepository {
|
|
|
127
149
|
throw error;
|
|
128
150
|
}
|
|
129
151
|
}
|
|
152
|
+
async getHybridSkillMetadata(skillName) {
|
|
153
|
+
let githubError;
|
|
154
|
+
try {
|
|
155
|
+
const repository = await this.resolveGitHubRepositoryForSkill(skillName);
|
|
156
|
+
return await this.getGitHubSkillMetadata(skillName, repository);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
githubError = error;
|
|
159
|
+
logger.debug(`Falling back to ClawHub metadata lookup for '${skillName}' after GitHub error: ${error instanceof Error ? error.message : String(error)}`);
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
return await this.getClawhubSkillMetadata(skillName);
|
|
163
|
+
} catch (clawhubError) {
|
|
164
|
+
throw new Error(`GitHub error: ${githubError instanceof Error ? githubError.message : String(githubError)}; ClawHub error: ${clawhubError instanceof Error ? clawhubError.message : String(clawhubError)}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
130
167
|
parseSkillMetadata(content) {
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
168
|
+
const parsed = (0, metadata_cjs_namespaceObject.parseSkillFrontmatter)(content);
|
|
169
|
+
return {
|
|
170
|
+
name: parsed.name,
|
|
171
|
+
description: parsed.description,
|
|
172
|
+
...parsed.license ? {
|
|
173
|
+
license: parsed.license
|
|
174
|
+
} : {},
|
|
175
|
+
...parsed.compatibility ? {
|
|
176
|
+
compatibility: parsed.compatibility
|
|
177
|
+
} : {},
|
|
178
|
+
...parsed.allowedTools.length > 0 ? {
|
|
179
|
+
allowedTools: parsed.allowedTools
|
|
180
|
+
} : {},
|
|
181
|
+
...parsed.metadata ? {
|
|
182
|
+
metadata: parsed.metadata
|
|
183
|
+
} : {}
|
|
138
184
|
};
|
|
139
|
-
const lines = frontmatter.split("\n");
|
|
140
|
-
for (const line of lines){
|
|
141
|
-
const colonIndex = line.indexOf(":");
|
|
142
|
-
if (-1 === colonIndex) continue;
|
|
143
|
-
const key = line.substring(0, colonIndex).trim();
|
|
144
|
-
const value = line.substring(colonIndex + 1).trim();
|
|
145
|
-
switch(key){
|
|
146
|
-
case "name":
|
|
147
|
-
metadata.name = value;
|
|
148
|
-
break;
|
|
149
|
-
case "description":
|
|
150
|
-
metadata.description = value;
|
|
151
|
-
break;
|
|
152
|
-
case "license":
|
|
153
|
-
metadata.license = value;
|
|
154
|
-
break;
|
|
155
|
-
case "compatibility":
|
|
156
|
-
metadata.compatibility = value;
|
|
157
|
-
break;
|
|
158
|
-
case "allowed-tools":
|
|
159
|
-
metadata.allowedTools = value;
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
if (!metadata.name) throw new Error("Invalid SKILL.md: missing required field 'name'");
|
|
164
|
-
if (!metadata.description) throw new Error("Invalid SKILL.md: missing required field 'description'");
|
|
165
|
-
const nameRegex = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
166
|
-
if (!nameRegex.test(metadata.name)) throw new Error(`Invalid skill name '${metadata.name}': must be lowercase alphanumeric with hyphens only`);
|
|
167
|
-
return metadata;
|
|
168
185
|
}
|
|
169
186
|
async downloadSkill(skillName) {
|
|
170
|
-
if ("clawhub" === this.provider) return await this.downloadSkillFromClawhub(skillName);
|
|
171
187
|
try {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
188
|
+
if ("clawhub" === this.provider) return await this.downloadSkillFromClawhub(skillName);
|
|
189
|
+
if ("github" === this.provider) {
|
|
190
|
+
const repository = await this.resolveGitHubRepositoryForSkill(skillName);
|
|
191
|
+
const files = new Map();
|
|
192
|
+
await this.downloadDirectory(`skills/${skillName}`, files, skillName, repository);
|
|
193
|
+
return files;
|
|
194
|
+
}
|
|
195
|
+
return await this.downloadHybridSkill(skillName);
|
|
175
196
|
} catch (error) {
|
|
176
197
|
if (error instanceof Error) throw new Error(`Failed to download skill ${skillName}: ${error.message}`);
|
|
177
198
|
throw error;
|
|
@@ -214,8 +235,25 @@ class SkillRepository {
|
|
|
214
235
|
throw error;
|
|
215
236
|
}
|
|
216
237
|
}
|
|
217
|
-
async
|
|
218
|
-
|
|
238
|
+
async downloadHybridSkill(skillName) {
|
|
239
|
+
let githubError;
|
|
240
|
+
try {
|
|
241
|
+
const repository = await this.resolveGitHubRepositoryForSkill(skillName);
|
|
242
|
+
const files = new Map();
|
|
243
|
+
await this.downloadDirectory(`skills/${skillName}`, files, skillName, repository);
|
|
244
|
+
return files;
|
|
245
|
+
} catch (error) {
|
|
246
|
+
githubError = error;
|
|
247
|
+
logger.debug(`Falling back to ClawHub download for '${skillName}' after GitHub error: ${error instanceof Error ? error.message : String(error)}`);
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
return await this.downloadSkillFromClawhub(skillName);
|
|
251
|
+
} catch (clawhubError) {
|
|
252
|
+
throw new Error(`GitHub error: ${githubError instanceof Error ? githubError.message : String(githubError)}; ClawHub error: ${clawhubError instanceof Error ? clawhubError.message : String(clawhubError)}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
async downloadDirectory(path, files, skillName, repository) {
|
|
256
|
+
const contents = await this.fetchGitHub(`/repos/${repository.owner}/${repository.name}/contents/${path}`);
|
|
219
257
|
for (const item of contents)if ("file" === item.type) if (item.content) {
|
|
220
258
|
const content = Buffer.from(item.content, "base64");
|
|
221
259
|
const relativePath = item.path.replace(`skills/${skillName}/`, "");
|
|
@@ -228,7 +266,7 @@ class SkillRepository {
|
|
|
228
266
|
files.set(relativePath, content);
|
|
229
267
|
}
|
|
230
268
|
}
|
|
231
|
-
else if ("dir" === item.type) await this.downloadDirectory(item.path, files, skillName);
|
|
269
|
+
else if ("dir" === item.type) await this.downloadDirectory(item.path, files, skillName, repository);
|
|
232
270
|
}
|
|
233
271
|
async listSkillsFromClawhub() {
|
|
234
272
|
const allSkills = [];
|
|
@@ -257,32 +295,80 @@ class SkillRepository {
|
|
|
257
295
|
}while (cursor);
|
|
258
296
|
return allSkills;
|
|
259
297
|
}
|
|
260
|
-
async
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
description: metadata.description || "No description",
|
|
268
|
-
path: item.path,
|
|
269
|
-
metadata
|
|
270
|
-
});
|
|
298
|
+
async listSkillsFromHybrid() {
|
|
299
|
+
let clawhubSkills = [];
|
|
300
|
+
let githubSkills = [];
|
|
301
|
+
let clawhubError;
|
|
302
|
+
let githubError;
|
|
303
|
+
try {
|
|
304
|
+
clawhubSkills = await this.listSkillsFromClawhub();
|
|
271
305
|
} catch (error) {
|
|
272
|
-
|
|
306
|
+
clawhubError = error;
|
|
307
|
+
logger.warn(`Failed to list ClawHub skills in hybrid mode: ${error instanceof Error ? error.message : String(error)}`);
|
|
273
308
|
}
|
|
274
|
-
|
|
309
|
+
try {
|
|
310
|
+
githubSkills = await this.listSkillsFromGitHub();
|
|
311
|
+
} catch (error) {
|
|
312
|
+
githubError = error;
|
|
313
|
+
logger.warn(`Failed to list GitHub skills in hybrid mode: ${error instanceof Error ? error.message : String(error)}`);
|
|
314
|
+
}
|
|
315
|
+
if (0 === clawhubSkills.length && 0 === githubSkills.length) throw new Error(`No skill sources available. ClawHub error: ${clawhubError instanceof Error ? clawhubError.message : "none"}; GitHub error: ${githubError instanceof Error ? githubError.message : "none"}`);
|
|
316
|
+
const mergedSkills = new Map();
|
|
317
|
+
for (const skill of clawhubSkills)mergedSkills.set(skill.name, skill);
|
|
318
|
+
for (const skill of githubSkills){
|
|
319
|
+
if (mergedSkills.has(skill.name)) mergedSkills.delete(skill.name);
|
|
320
|
+
mergedSkills.set(skill.name, skill);
|
|
321
|
+
}
|
|
322
|
+
return [
|
|
323
|
+
...mergedSkills.values()
|
|
324
|
+
];
|
|
325
|
+
}
|
|
326
|
+
async listSkillsFromGitHub() {
|
|
327
|
+
const mergedSkills = new Map();
|
|
328
|
+
for (const repository of this.getGitHubRepositories()){
|
|
329
|
+
const contents = await this.fetchGitHub(`/repos/${repository.owner}/${repository.name}/contents/skills`);
|
|
330
|
+
for (const item of contents)if ("dir" === item.type) try {
|
|
331
|
+
const metadata = await this.getGitHubSkillMetadata(item.name, repository);
|
|
332
|
+
if (mergedSkills.has(item.name)) mergedSkills.delete(item.name);
|
|
333
|
+
mergedSkills.set(item.name, {
|
|
334
|
+
name: item.name,
|
|
335
|
+
description: metadata.description || "No description",
|
|
336
|
+
path: item.path,
|
|
337
|
+
metadata
|
|
338
|
+
});
|
|
339
|
+
} catch (error) {
|
|
340
|
+
logger.warn(`Could not read skill ${item.name} from ${repository.owner}/${repository.name}`, error instanceof Error ? error.message : String(error));
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return [
|
|
344
|
+
...mergedSkills.values()
|
|
345
|
+
];
|
|
346
|
+
}
|
|
347
|
+
getGitHubRepositories() {
|
|
348
|
+
if (this.repositories.length > 0) return this.repositories;
|
|
349
|
+
throw new Error("No GitHub skill repositories configured. Set skills.repositories or the legacy skills.repositoryOwner + skills.repositoryName fields.");
|
|
275
350
|
}
|
|
276
351
|
constructor(options = {}){
|
|
277
352
|
_define_property(this, "githubBaseUrl", "https://api.github.com");
|
|
278
|
-
_define_property(this, "
|
|
279
|
-
_define_property(this, "repo", void 0);
|
|
353
|
+
_define_property(this, "repositories", void 0);
|
|
280
354
|
_define_property(this, "token", void 0);
|
|
281
355
|
_define_property(this, "provider", void 0);
|
|
282
356
|
_define_property(this, "clawhubBaseUrl", void 0);
|
|
283
|
-
this.provider = options.provider || "
|
|
284
|
-
|
|
285
|
-
|
|
357
|
+
this.provider = options.provider || "hybrid";
|
|
358
|
+
const normalizedRepositories = (options.repositories || []).map((repository)=>({
|
|
359
|
+
owner: repository.owner.trim(),
|
|
360
|
+
name: repository.name.trim()
|
|
361
|
+
})).filter((repository)=>repository.owner && repository.name);
|
|
362
|
+
const legacyOwner = options.repositoryOwner?.trim();
|
|
363
|
+
const legacyName = options.repositoryName?.trim();
|
|
364
|
+
if (normalizedRepositories.length > 0) this.repositories = normalizedRepositories;
|
|
365
|
+
else if (legacyOwner && legacyName) this.repositories = [
|
|
366
|
+
{
|
|
367
|
+
owner: legacyOwner,
|
|
368
|
+
name: legacyName
|
|
369
|
+
}
|
|
370
|
+
];
|
|
371
|
+
else this.repositories = [];
|
|
286
372
|
this.token = options.githubToken || process.env.GITHUB_TOKEN || void 0;
|
|
287
373
|
this.clawhubBaseUrl = (options.clawhubBaseUrl || "https://clawhub.ai").replace(/\/+$/, "");
|
|
288
374
|
}
|
|
@@ -4,8 +4,7 @@ import type { SkillInfo, SkillMetadata, SkillRepositoryOptions } from "../types/
|
|
|
4
4
|
*/
|
|
5
5
|
export declare class SkillRepository {
|
|
6
6
|
private readonly githubBaseUrl;
|
|
7
|
-
private readonly
|
|
8
|
-
private readonly repo;
|
|
7
|
+
private readonly repositories;
|
|
9
8
|
private readonly token?;
|
|
10
9
|
private readonly provider;
|
|
11
10
|
private readonly clawhubBaseUrl;
|
|
@@ -24,7 +23,10 @@ export declare class SkillRepository {
|
|
|
24
23
|
* Get skill metadata by fetching and parsing SKILL.md
|
|
25
24
|
*/
|
|
26
25
|
getSkillMetadata(skillName: string): Promise<SkillMetadata>;
|
|
26
|
+
private getGitHubSkillMetadata;
|
|
27
|
+
private resolveGitHubRepositoryForSkill;
|
|
27
28
|
private getClawhubSkillMetadata;
|
|
29
|
+
private getHybridSkillMetadata;
|
|
28
30
|
/**
|
|
29
31
|
* Parse SKILL.md content to extract YAML frontmatter
|
|
30
32
|
*/
|
|
@@ -34,10 +36,13 @@ export declare class SkillRepository {
|
|
|
34
36
|
*/
|
|
35
37
|
downloadSkill(skillName: string): Promise<Map<string, string | Buffer>>;
|
|
36
38
|
private downloadSkillFromClawhub;
|
|
39
|
+
private downloadHybridSkill;
|
|
37
40
|
/**
|
|
38
41
|
* Recursively download all files in a directory
|
|
39
42
|
*/
|
|
40
43
|
private downloadDirectory;
|
|
41
44
|
private listSkillsFromClawhub;
|
|
45
|
+
private listSkillsFromHybrid;
|
|
42
46
|
private listSkillsFromGitHub;
|
|
47
|
+
private getGitHubRepositories;
|
|
43
48
|
}
|