@wingman-ai/gateway 0.4.0 → 0.4.2
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 +29 -111
- package/dist/agent/config/agentConfig.cjs +2 -0
- package/dist/agent/config/agentConfig.d.ts +6 -0
- package/dist/agent/config/agentConfig.js +2 -0
- package/dist/agent/config/agentLoader.cjs +21 -18
- package/dist/agent/config/agentLoader.js +22 -19
- package/dist/agent/config/toolRegistry.cjs +19 -0
- package/dist/agent/config/toolRegistry.d.ts +4 -0
- package/dist/agent/config/toolRegistry.js +17 -1
- package/dist/agent/middleware/additional-messages.cjs +115 -11
- package/dist/agent/middleware/additional-messages.d.ts +9 -0
- package/dist/agent/middleware/additional-messages.js +115 -11
- package/dist/agent/tests/agentLoader.test.cjs +45 -0
- package/dist/agent/tests/agentLoader.test.js +45 -0
- package/dist/agent/tests/toolRegistry.test.cjs +2 -0
- package/dist/agent/tests/toolRegistry.test.js +2 -0
- package/dist/agent/tools/node_invoke.cjs +146 -0
- package/dist/agent/tools/node_invoke.d.ts +86 -0
- package/dist/agent/tools/node_invoke.js +109 -0
- package/dist/cli/commands/gateway.cjs +1 -1
- package/dist/cli/commands/gateway.js +1 -1
- 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 +27 -9
- package/dist/cli/config/schema.d.ts +18 -4
- package/dist/cli/config/schema.js +23 -8
- package/dist/cli/core/agentInvoker.cjs +70 -14
- package/dist/cli/core/agentInvoker.d.ts +10 -0
- package/dist/cli/core/agentInvoker.js +70 -14
- 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/gateway/http/nodes.cjs +247 -0
- package/dist/gateway/http/nodes.d.ts +20 -0
- package/dist/gateway/http/nodes.js +210 -0
- package/dist/gateway/node.cjs +10 -1
- package/dist/gateway/node.d.ts +10 -1
- package/dist/gateway/node.js +10 -1
- package/dist/gateway/server.cjs +414 -27
- package/dist/gateway/server.d.ts +34 -0
- package/dist/gateway/server.js +408 -27
- package/dist/gateway/types.d.ts +6 -1
- package/dist/gateway/validation.cjs +2 -0
- package/dist/gateway/validation.d.ts +4 -0
- package/dist/gateway/validation.js +2 -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/additionalMessageMiddleware.test.cjs +92 -0
- package/dist/tests/additionalMessageMiddleware.test.js +92 -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-init.test.cjs +54 -0
- package/dist/tests/cli-init.test.js +54 -0
- 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 +277 -0
- package/dist/tests/gateway-http-security.test.d.ts +1 -0
- package/dist/tests/gateway-http-security.test.js +271 -0
- package/dist/tests/gateway-node-mode.test.cjs +174 -0
- package/dist/tests/gateway-node-mode.test.d.ts +1 -0
- package/dist/tests/gateway-node-mode.test.js +168 -0
- package/dist/tests/gateway-origin-policy.test.cjs +60 -0
- package/dist/tests/gateway-origin-policy.test.d.ts +1 -0
- package/dist/tests/gateway-origin-policy.test.js +54 -0
- package/dist/tests/gateway.test.cjs +1 -0
- package/dist/tests/gateway.test.js +1 -0
- package/dist/tests/node-tools.test.cjs +77 -0
- package/dist/tests/node-tools.test.d.ts +1 -0
- package/dist/tests/node-tools.test.js +71 -0
- package/dist/tests/nodes-api.test.cjs +86 -0
- package/dist/tests/nodes-api.test.d.ts +1 -0
- package/dist/tests/nodes-api.test.js +80 -0
- 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/webui/assets/{index-DHbfLOUR.js → index-BMekSELC.js} +106 -106
- package/dist/webui/index.html +1 -1
- package/package.json +4 -4
- package/skills/gog/SKILL.md +1 -1
- package/skills/weather/SKILL.md +1 -1
- package/skills/ui-registry/SKILL.md +0 -35
package/dist/gateway/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { ServerWebSocket } from "bun";
|
|
|
2
2
|
/**
|
|
3
3
|
* Message types for gateway communication
|
|
4
4
|
*/
|
|
5
|
-
export type MessageType = "connect" | "res" | "req:agent" | "req:agent:cancel" | "event:agent" | "session_subscribe" | "session_unsubscribe" | "register" | "registered" | "unregister" | "join_group" | "leave_group" | "broadcast" | "direct" | "ping" | "pong" | "error" | "ack" | "upgrade";
|
|
5
|
+
export type MessageType = "connect" | "res" | "req:agent" | "req:agent:cancel" | "event:agent" | "req:node" | "event:node" | "session_subscribe" | "session_unsubscribe" | "register" | "registered" | "unregister" | "join_group" | "leave_group" | "broadcast" | "direct" | "ping" | "pong" | "error" | "ack" | "upgrade";
|
|
6
6
|
/**
|
|
7
7
|
* Gateway message structure
|
|
8
8
|
*/
|
|
@@ -87,6 +87,7 @@ export interface RoutingInfo {
|
|
|
87
87
|
export interface NodeMetadata {
|
|
88
88
|
id: string;
|
|
89
89
|
name: string;
|
|
90
|
+
clientId?: string;
|
|
90
91
|
capabilities?: string[];
|
|
91
92
|
groups: Set<string>;
|
|
92
93
|
connectedAt: number;
|
|
@@ -102,6 +103,10 @@ export interface NodeMetadata {
|
|
|
102
103
|
export interface Node extends NodeMetadata {
|
|
103
104
|
ws: ServerWebSocket<{
|
|
104
105
|
nodeId: string;
|
|
106
|
+
clientId?: string;
|
|
107
|
+
clientType?: string;
|
|
108
|
+
authenticated?: boolean;
|
|
109
|
+
tailscaleUser?: string;
|
|
105
110
|
}>;
|
|
106
111
|
}
|
|
107
112
|
/**
|
|
@@ -10,6 +10,8 @@ export declare const MessageTypeSchema: z.ZodEnum<{
|
|
|
10
10
|
"req:agent": "req:agent";
|
|
11
11
|
"req:agent:cancel": "req:agent:cancel";
|
|
12
12
|
"event:agent": "event:agent";
|
|
13
|
+
"req:node": "req:node";
|
|
14
|
+
"event:node": "event:node";
|
|
13
15
|
session_subscribe: "session_subscribe";
|
|
14
16
|
session_unsubscribe: "session_unsubscribe";
|
|
15
17
|
register: "register";
|
|
@@ -34,6 +36,8 @@ export declare const GatewayMessageSchema: z.ZodObject<{
|
|
|
34
36
|
"req:agent": "req:agent";
|
|
35
37
|
"req:agent:cancel": "req:agent:cancel";
|
|
36
38
|
"event:agent": "event:agent";
|
|
39
|
+
"req:node": "req:node";
|
|
40
|
+
"event:node": "event:node";
|
|
37
41
|
session_subscribe: "session_subscribe";
|
|
38
42
|
session_unsubscribe: "session_unsubscribe";
|
|
39
43
|
register: "register";
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
resolveSkillActivation: ()=>resolveSkillActivation
|
|
28
|
+
});
|
|
29
|
+
const promises_namespaceObject = require("node:fs/promises");
|
|
30
|
+
const external_node_path_namespaceObject = require("node:path");
|
|
31
|
+
const external_bin_requirements_cjs_namespaceObject = require("./bin-requirements.cjs");
|
|
32
|
+
const external_metadata_cjs_namespaceObject = require("./metadata.cjs");
|
|
33
|
+
const resolveSkillActivation = async (skillsRoot, checkBin = external_bin_requirements_cjs_namespaceObject.isBinAvailable)=>{
|
|
34
|
+
const activeSkillNames = [];
|
|
35
|
+
const inactiveSkills = [];
|
|
36
|
+
let entries = [];
|
|
37
|
+
try {
|
|
38
|
+
entries = await promises_namespaceObject.readdir(skillsRoot, {
|
|
39
|
+
withFileTypes: true,
|
|
40
|
+
encoding: "utf8"
|
|
41
|
+
});
|
|
42
|
+
} catch {
|
|
43
|
+
return {
|
|
44
|
+
activeSkillNames,
|
|
45
|
+
inactiveSkills
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
for (const entry of entries){
|
|
49
|
+
if (!entry.isDirectory()) continue;
|
|
50
|
+
const skillName = entry.name;
|
|
51
|
+
const skillMdPath = (0, external_node_path_namespaceObject.join)(skillsRoot, skillName, "SKILL.md");
|
|
52
|
+
let content;
|
|
53
|
+
try {
|
|
54
|
+
content = await promises_namespaceObject.readFile(skillMdPath, "utf-8");
|
|
55
|
+
} catch {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const parsed = (0, external_metadata_cjs_namespaceObject.parseSkillFrontmatter)(content);
|
|
60
|
+
const runtime = parsed.runtimeMetadata;
|
|
61
|
+
const requiredBins = runtime?.requires.bins || [];
|
|
62
|
+
if (!runtime || 0 === requiredBins.length) {
|
|
63
|
+
activeSkillNames.push(skillName);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const missingBins = (0, external_bin_requirements_cjs_namespaceObject.findMissingBins)(requiredBins, checkBin);
|
|
67
|
+
if (0 === missingBins.length) {
|
|
68
|
+
activeSkillNames.push(skillName);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
inactiveSkills.push({
|
|
72
|
+
name: skillName,
|
|
73
|
+
namespace: runtime.namespace,
|
|
74
|
+
requiredBins,
|
|
75
|
+
missingBins
|
|
76
|
+
});
|
|
77
|
+
} catch {
|
|
78
|
+
activeSkillNames.push(skillName);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
activeSkillNames,
|
|
83
|
+
inactiveSkills
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
exports.resolveSkillActivation = __webpack_exports__.resolveSkillActivation;
|
|
87
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
88
|
+
"resolveSkillActivation"
|
|
89
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
90
|
+
Object.defineProperty(exports, '__esModule', {
|
|
91
|
+
value: true
|
|
92
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type BinAvailabilityChecker } from "./bin-requirements.js";
|
|
2
|
+
export interface InactiveSkill {
|
|
3
|
+
name: string;
|
|
4
|
+
namespace: "wingman" | "openclaw";
|
|
5
|
+
requiredBins: string[];
|
|
6
|
+
missingBins: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface SkillActivationResult {
|
|
9
|
+
activeSkillNames: string[];
|
|
10
|
+
inactiveSkills: InactiveSkill[];
|
|
11
|
+
}
|
|
12
|
+
export declare const resolveSkillActivation: (skillsRoot: string, checkBin?: BinAvailabilityChecker) => Promise<SkillActivationResult>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { findMissingBins, isBinAvailable } from "./bin-requirements.js";
|
|
4
|
+
import { parseSkillFrontmatter } from "./metadata.js";
|
|
5
|
+
const resolveSkillActivation = async (skillsRoot, checkBin = isBinAvailable)=>{
|
|
6
|
+
const activeSkillNames = [];
|
|
7
|
+
const inactiveSkills = [];
|
|
8
|
+
let entries = [];
|
|
9
|
+
try {
|
|
10
|
+
entries = await readdir(skillsRoot, {
|
|
11
|
+
withFileTypes: true,
|
|
12
|
+
encoding: "utf8"
|
|
13
|
+
});
|
|
14
|
+
} catch {
|
|
15
|
+
return {
|
|
16
|
+
activeSkillNames,
|
|
17
|
+
inactiveSkills
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
for (const entry of entries){
|
|
21
|
+
if (!entry.isDirectory()) continue;
|
|
22
|
+
const skillName = entry.name;
|
|
23
|
+
const skillMdPath = join(skillsRoot, skillName, "SKILL.md");
|
|
24
|
+
let content;
|
|
25
|
+
try {
|
|
26
|
+
content = await readFile(skillMdPath, "utf-8");
|
|
27
|
+
} catch {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const parsed = parseSkillFrontmatter(content);
|
|
32
|
+
const runtime = parsed.runtimeMetadata;
|
|
33
|
+
const requiredBins = runtime?.requires.bins || [];
|
|
34
|
+
if (!runtime || 0 === requiredBins.length) {
|
|
35
|
+
activeSkillNames.push(skillName);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const missingBins = findMissingBins(requiredBins, checkBin);
|
|
39
|
+
if (0 === missingBins.length) {
|
|
40
|
+
activeSkillNames.push(skillName);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
inactiveSkills.push({
|
|
44
|
+
name: skillName,
|
|
45
|
+
namespace: runtime.namespace,
|
|
46
|
+
requiredBins,
|
|
47
|
+
missingBins
|
|
48
|
+
});
|
|
49
|
+
} catch {
|
|
50
|
+
activeSkillNames.push(skillName);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
activeSkillNames,
|
|
55
|
+
inactiveSkills
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
export { resolveSkillActivation };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
isBinAvailable: ()=>isBinAvailable,
|
|
28
|
+
findMissingBins: ()=>findMissingBins
|
|
29
|
+
});
|
|
30
|
+
const external_node_child_process_namespaceObject = require("node:child_process");
|
|
31
|
+
const SAFE_BIN_REGEX = /^[A-Za-z0-9._-]+$/;
|
|
32
|
+
const isBinAvailable = (binName)=>{
|
|
33
|
+
const normalized = binName.trim();
|
|
34
|
+
if (!normalized || !SAFE_BIN_REGEX.test(normalized)) return false;
|
|
35
|
+
const lookupCommand = "win32" === process.platform ? "where" : "which";
|
|
36
|
+
const result = (0, external_node_child_process_namespaceObject.spawnSync)(lookupCommand, [
|
|
37
|
+
normalized
|
|
38
|
+
], {
|
|
39
|
+
stdio: "ignore"
|
|
40
|
+
});
|
|
41
|
+
return 0 === result.status;
|
|
42
|
+
};
|
|
43
|
+
const findMissingBins = (bins, checkBin = isBinAvailable)=>{
|
|
44
|
+
const seen = new Set();
|
|
45
|
+
const missing = [];
|
|
46
|
+
for (const bin of bins){
|
|
47
|
+
const normalized = bin.trim();
|
|
48
|
+
if (!(!normalized || seen.has(normalized))) {
|
|
49
|
+
seen.add(normalized);
|
|
50
|
+
if (!checkBin(normalized)) missing.push(normalized);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return missing;
|
|
54
|
+
};
|
|
55
|
+
exports.findMissingBins = __webpack_exports__.findMissingBins;
|
|
56
|
+
exports.isBinAvailable = __webpack_exports__.isBinAvailable;
|
|
57
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
58
|
+
"findMissingBins",
|
|
59
|
+
"isBinAvailable"
|
|
60
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
61
|
+
Object.defineProperty(exports, '__esModule', {
|
|
62
|
+
value: true
|
|
63
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
const SAFE_BIN_REGEX = /^[A-Za-z0-9._-]+$/;
|
|
3
|
+
const isBinAvailable = (binName)=>{
|
|
4
|
+
const normalized = binName.trim();
|
|
5
|
+
if (!normalized || !SAFE_BIN_REGEX.test(normalized)) return false;
|
|
6
|
+
const lookupCommand = "win32" === process.platform ? "where" : "which";
|
|
7
|
+
const result = spawnSync(lookupCommand, [
|
|
8
|
+
normalized
|
|
9
|
+
], {
|
|
10
|
+
stdio: "ignore"
|
|
11
|
+
});
|
|
12
|
+
return 0 === result.status;
|
|
13
|
+
};
|
|
14
|
+
const findMissingBins = (bins, checkBin = isBinAvailable)=>{
|
|
15
|
+
const seen = new Set();
|
|
16
|
+
const missing = [];
|
|
17
|
+
for (const bin of bins){
|
|
18
|
+
const normalized = bin.trim();
|
|
19
|
+
if (!(!normalized || seen.has(normalized))) {
|
|
20
|
+
seen.add(normalized);
|
|
21
|
+
if (!checkBin(normalized)) missing.push(normalized);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return missing;
|
|
25
|
+
};
|
|
26
|
+
export { findMissingBins, isBinAvailable };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
parseSkillRuntimeMetadata: ()=>parseSkillRuntimeMetadata,
|
|
28
|
+
parseSkillFrontmatter: ()=>parseSkillFrontmatter
|
|
29
|
+
});
|
|
30
|
+
const external_js_yaml_namespaceObject = require("js-yaml");
|
|
31
|
+
const FRONTMATTER_REGEX = /^---\s*\n([\s\S]*?)\n---/;
|
|
32
|
+
const SKILL_NAME_REGEX = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
33
|
+
const SUPPORTED_SKILL_METADATA_NAMESPACES = [
|
|
34
|
+
"wingman",
|
|
35
|
+
"openclaw"
|
|
36
|
+
];
|
|
37
|
+
const toRecord = (value)=>{
|
|
38
|
+
if (!value || "object" != typeof value || Array.isArray(value)) return null;
|
|
39
|
+
return value;
|
|
40
|
+
};
|
|
41
|
+
const toTrimmedString = (value)=>{
|
|
42
|
+
if ("string" != typeof value) return null;
|
|
43
|
+
const trimmed = value.trim();
|
|
44
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
45
|
+
};
|
|
46
|
+
const toStringArray = (value)=>{
|
|
47
|
+
if (Array.isArray(value)) {
|
|
48
|
+
const normalized = value.map((entry)=>"string" == typeof entry ? entry.trim() : "").filter(Boolean);
|
|
49
|
+
return Array.from(new Set(normalized));
|
|
50
|
+
}
|
|
51
|
+
if ("string" == typeof value) {
|
|
52
|
+
const normalized = value.split(/[\s,]+/).map((entry)=>entry.trim()).filter(Boolean);
|
|
53
|
+
return Array.from(new Set(normalized));
|
|
54
|
+
}
|
|
55
|
+
return [];
|
|
56
|
+
};
|
|
57
|
+
const parseInstallRecipe = (value)=>{
|
|
58
|
+
const recipe = toRecord(value);
|
|
59
|
+
if (!recipe) return null;
|
|
60
|
+
const kind = toTrimmedString(recipe.kind);
|
|
61
|
+
if (!kind) return null;
|
|
62
|
+
const id = toTrimmedString(recipe.id) || kind;
|
|
63
|
+
const label = toTrimmedString(recipe.label);
|
|
64
|
+
const formula = toTrimmedString(recipe.formula);
|
|
65
|
+
return {
|
|
66
|
+
id,
|
|
67
|
+
kind,
|
|
68
|
+
...label ? {
|
|
69
|
+
label
|
|
70
|
+
} : {},
|
|
71
|
+
...formula ? {
|
|
72
|
+
formula
|
|
73
|
+
} : {},
|
|
74
|
+
bins: toStringArray(recipe.bins)
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
const parseSkillRuntimeMetadata = (value)=>{
|
|
78
|
+
const metadata = toRecord(value);
|
|
79
|
+
if (!metadata) return null;
|
|
80
|
+
for (const namespace of SUPPORTED_SKILL_METADATA_NAMESPACES){
|
|
81
|
+
const namespaceConfig = toRecord(metadata[namespace]);
|
|
82
|
+
if (!namespaceConfig) continue;
|
|
83
|
+
const requires = toRecord(namespaceConfig.requires);
|
|
84
|
+
const installRaw = Array.isArray(namespaceConfig.install) ? namespaceConfig.install : [];
|
|
85
|
+
const emoji = toTrimmedString(namespaceConfig.emoji);
|
|
86
|
+
return {
|
|
87
|
+
namespace,
|
|
88
|
+
...emoji ? {
|
|
89
|
+
emoji
|
|
90
|
+
} : {},
|
|
91
|
+
requires: {
|
|
92
|
+
bins: toStringArray(requires?.bins)
|
|
93
|
+
},
|
|
94
|
+
install: installRaw.map(parseInstallRecipe).filter((recipe)=>Boolean(recipe))
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
};
|
|
99
|
+
const parseAllowedTools = (frontmatter)=>{
|
|
100
|
+
if (void 0 !== frontmatter["allowed-tools"]) return toStringArray(frontmatter["allowed-tools"]);
|
|
101
|
+
if (void 0 !== frontmatter.allowedTools) return toStringArray(frontmatter.allowedTools);
|
|
102
|
+
return [];
|
|
103
|
+
};
|
|
104
|
+
const parseSkillFrontmatter = (content)=>{
|
|
105
|
+
const match = content.match(FRONTMATTER_REGEX);
|
|
106
|
+
if (!match) throw new Error("Invalid SKILL.md format: missing YAML frontmatter");
|
|
107
|
+
const frontmatterRaw = match[1];
|
|
108
|
+
const parsed = external_js_yaml_namespaceObject.load(frontmatterRaw);
|
|
109
|
+
const frontmatter = toRecord(parsed);
|
|
110
|
+
if (!frontmatter) throw new Error("Invalid SKILL.md: frontmatter must be a YAML object");
|
|
111
|
+
const name = toTrimmedString(frontmatter.name);
|
|
112
|
+
if (!name) throw new Error("Invalid SKILL.md: missing required field 'name'");
|
|
113
|
+
if (!SKILL_NAME_REGEX.test(name)) throw new Error(`Invalid skill name '${name}': must be lowercase alphanumeric with hyphens only`);
|
|
114
|
+
const description = toTrimmedString(frontmatter.description);
|
|
115
|
+
if (!description) throw new Error("Invalid SKILL.md: missing required field 'description'");
|
|
116
|
+
const metadata = toRecord(frontmatter.metadata) || void 0;
|
|
117
|
+
const license = toTrimmedString(frontmatter.license);
|
|
118
|
+
const compatibility = toTrimmedString(frontmatter.compatibility);
|
|
119
|
+
return {
|
|
120
|
+
name,
|
|
121
|
+
description,
|
|
122
|
+
...license ? {
|
|
123
|
+
license
|
|
124
|
+
} : {},
|
|
125
|
+
...compatibility ? {
|
|
126
|
+
compatibility
|
|
127
|
+
} : {},
|
|
128
|
+
allowedTools: parseAllowedTools(frontmatter),
|
|
129
|
+
metadata,
|
|
130
|
+
runtimeMetadata: parseSkillRuntimeMetadata(metadata)
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
exports.parseSkillFrontmatter = __webpack_exports__.parseSkillFrontmatter;
|
|
134
|
+
exports.parseSkillRuntimeMetadata = __webpack_exports__.parseSkillRuntimeMetadata;
|
|
135
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
136
|
+
"parseSkillFrontmatter",
|
|
137
|
+
"parseSkillRuntimeMetadata"
|
|
138
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
139
|
+
Object.defineProperty(exports, '__esModule', {
|
|
140
|
+
value: true
|
|
141
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
declare const SUPPORTED_SKILL_METADATA_NAMESPACES: readonly ["wingman", "openclaw"];
|
|
2
|
+
export type SupportedSkillMetadataNamespace = (typeof SUPPORTED_SKILL_METADATA_NAMESPACES)[number];
|
|
3
|
+
export interface SkillInstallRecipe {
|
|
4
|
+
id: string;
|
|
5
|
+
kind: string;
|
|
6
|
+
label?: string;
|
|
7
|
+
formula?: string;
|
|
8
|
+
bins: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface SkillRuntimeMetadata {
|
|
11
|
+
namespace: SupportedSkillMetadataNamespace;
|
|
12
|
+
emoji?: string;
|
|
13
|
+
requires: {
|
|
14
|
+
bins: string[];
|
|
15
|
+
};
|
|
16
|
+
install: SkillInstallRecipe[];
|
|
17
|
+
}
|
|
18
|
+
export interface ParsedSkillFrontmatter {
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
license?: string;
|
|
22
|
+
compatibility?: string;
|
|
23
|
+
allowedTools: string[];
|
|
24
|
+
metadata?: Record<string, unknown>;
|
|
25
|
+
runtimeMetadata: SkillRuntimeMetadata | null;
|
|
26
|
+
}
|
|
27
|
+
export declare const parseSkillRuntimeMetadata: (value: unknown) => SkillRuntimeMetadata | null;
|
|
28
|
+
export declare const parseSkillFrontmatter: (content: string) => ParsedSkillFrontmatter;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { load } from "js-yaml";
|
|
2
|
+
const FRONTMATTER_REGEX = /^---\s*\n([\s\S]*?)\n---/;
|
|
3
|
+
const SKILL_NAME_REGEX = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
4
|
+
const SUPPORTED_SKILL_METADATA_NAMESPACES = [
|
|
5
|
+
"wingman",
|
|
6
|
+
"openclaw"
|
|
7
|
+
];
|
|
8
|
+
const toRecord = (value)=>{
|
|
9
|
+
if (!value || "object" != typeof value || Array.isArray(value)) return null;
|
|
10
|
+
return value;
|
|
11
|
+
};
|
|
12
|
+
const toTrimmedString = (value)=>{
|
|
13
|
+
if ("string" != typeof value) return null;
|
|
14
|
+
const trimmed = value.trim();
|
|
15
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
16
|
+
};
|
|
17
|
+
const toStringArray = (value)=>{
|
|
18
|
+
if (Array.isArray(value)) {
|
|
19
|
+
const normalized = value.map((entry)=>"string" == typeof entry ? entry.trim() : "").filter(Boolean);
|
|
20
|
+
return Array.from(new Set(normalized));
|
|
21
|
+
}
|
|
22
|
+
if ("string" == typeof value) {
|
|
23
|
+
const normalized = value.split(/[\s,]+/).map((entry)=>entry.trim()).filter(Boolean);
|
|
24
|
+
return Array.from(new Set(normalized));
|
|
25
|
+
}
|
|
26
|
+
return [];
|
|
27
|
+
};
|
|
28
|
+
const parseInstallRecipe = (value)=>{
|
|
29
|
+
const recipe = toRecord(value);
|
|
30
|
+
if (!recipe) return null;
|
|
31
|
+
const kind = toTrimmedString(recipe.kind);
|
|
32
|
+
if (!kind) return null;
|
|
33
|
+
const id = toTrimmedString(recipe.id) || kind;
|
|
34
|
+
const label = toTrimmedString(recipe.label);
|
|
35
|
+
const formula = toTrimmedString(recipe.formula);
|
|
36
|
+
return {
|
|
37
|
+
id,
|
|
38
|
+
kind,
|
|
39
|
+
...label ? {
|
|
40
|
+
label
|
|
41
|
+
} : {},
|
|
42
|
+
...formula ? {
|
|
43
|
+
formula
|
|
44
|
+
} : {},
|
|
45
|
+
bins: toStringArray(recipe.bins)
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
const parseSkillRuntimeMetadata = (value)=>{
|
|
49
|
+
const metadata = toRecord(value);
|
|
50
|
+
if (!metadata) return null;
|
|
51
|
+
for (const namespace of SUPPORTED_SKILL_METADATA_NAMESPACES){
|
|
52
|
+
const namespaceConfig = toRecord(metadata[namespace]);
|
|
53
|
+
if (!namespaceConfig) continue;
|
|
54
|
+
const requires = toRecord(namespaceConfig.requires);
|
|
55
|
+
const installRaw = Array.isArray(namespaceConfig.install) ? namespaceConfig.install : [];
|
|
56
|
+
const emoji = toTrimmedString(namespaceConfig.emoji);
|
|
57
|
+
return {
|
|
58
|
+
namespace,
|
|
59
|
+
...emoji ? {
|
|
60
|
+
emoji
|
|
61
|
+
} : {},
|
|
62
|
+
requires: {
|
|
63
|
+
bins: toStringArray(requires?.bins)
|
|
64
|
+
},
|
|
65
|
+
install: installRaw.map(parseInstallRecipe).filter((recipe)=>Boolean(recipe))
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
};
|
|
70
|
+
const parseAllowedTools = (frontmatter)=>{
|
|
71
|
+
if (void 0 !== frontmatter["allowed-tools"]) return toStringArray(frontmatter["allowed-tools"]);
|
|
72
|
+
if (void 0 !== frontmatter.allowedTools) return toStringArray(frontmatter.allowedTools);
|
|
73
|
+
return [];
|
|
74
|
+
};
|
|
75
|
+
const parseSkillFrontmatter = (content)=>{
|
|
76
|
+
const match = content.match(FRONTMATTER_REGEX);
|
|
77
|
+
if (!match) throw new Error("Invalid SKILL.md format: missing YAML frontmatter");
|
|
78
|
+
const frontmatterRaw = match[1];
|
|
79
|
+
const parsed = load(frontmatterRaw);
|
|
80
|
+
const frontmatter = toRecord(parsed);
|
|
81
|
+
if (!frontmatter) throw new Error("Invalid SKILL.md: frontmatter must be a YAML object");
|
|
82
|
+
const name = toTrimmedString(frontmatter.name);
|
|
83
|
+
if (!name) throw new Error("Invalid SKILL.md: missing required field 'name'");
|
|
84
|
+
if (!SKILL_NAME_REGEX.test(name)) throw new Error(`Invalid skill name '${name}': must be lowercase alphanumeric with hyphens only`);
|
|
85
|
+
const description = toTrimmedString(frontmatter.description);
|
|
86
|
+
if (!description) throw new Error("Invalid SKILL.md: missing required field 'description'");
|
|
87
|
+
const metadata = toRecord(frontmatter.metadata) || void 0;
|
|
88
|
+
const license = toTrimmedString(frontmatter.license);
|
|
89
|
+
const compatibility = toTrimmedString(frontmatter.compatibility);
|
|
90
|
+
return {
|
|
91
|
+
name,
|
|
92
|
+
description,
|
|
93
|
+
...license ? {
|
|
94
|
+
license
|
|
95
|
+
} : {},
|
|
96
|
+
...compatibility ? {
|
|
97
|
+
compatibility
|
|
98
|
+
} : {},
|
|
99
|
+
allowedTools: parseAllowedTools(frontmatter),
|
|
100
|
+
metadata,
|
|
101
|
+
runtimeMetadata: parseSkillRuntimeMetadata(metadata)
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
export { parseSkillFrontmatter, parseSkillRuntimeMetadata };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
createSkillOverlayDirectory: ()=>createSkillOverlayDirectory,
|
|
28
|
+
removeSkillOverlayDirectory: ()=>removeSkillOverlayDirectory
|
|
29
|
+
});
|
|
30
|
+
const promises_namespaceObject = require("node:fs/promises");
|
|
31
|
+
const external_node_path_namespaceObject = require("node:path");
|
|
32
|
+
const external_node_os_namespaceObject = require("node:os");
|
|
33
|
+
const uniqueSkillNames = (skills)=>{
|
|
34
|
+
const seen = new Set();
|
|
35
|
+
const unique = [];
|
|
36
|
+
for (const skill of skills){
|
|
37
|
+
const normalized = skill.trim();
|
|
38
|
+
if (!(!normalized || seen.has(normalized))) {
|
|
39
|
+
seen.add(normalized);
|
|
40
|
+
unique.push(normalized);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return unique;
|
|
44
|
+
};
|
|
45
|
+
const createSkillOverlayDirectory = async (skillsRoot, activeSkillNames)=>{
|
|
46
|
+
const overlayRoot = await promises_namespaceObject.mkdtemp((0, external_node_path_namespaceObject.join)((0, external_node_os_namespaceObject.tmpdir)(), "wingman-skill-overlay-"));
|
|
47
|
+
for (const skillName of uniqueSkillNames(activeSkillNames)){
|
|
48
|
+
const source = (0, external_node_path_namespaceObject.join)(skillsRoot, skillName);
|
|
49
|
+
const destination = (0, external_node_path_namespaceObject.join)(overlayRoot, skillName);
|
|
50
|
+
try {
|
|
51
|
+
await promises_namespaceObject.symlink(source, destination, "win32" === process.platform ? "junction" : "dir");
|
|
52
|
+
} catch {
|
|
53
|
+
await promises_namespaceObject.cp(source, destination, {
|
|
54
|
+
recursive: true,
|
|
55
|
+
force: true
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return overlayRoot;
|
|
60
|
+
};
|
|
61
|
+
const removeSkillOverlayDirectory = async (overlayPath)=>{
|
|
62
|
+
await promises_namespaceObject.rm(overlayPath, {
|
|
63
|
+
recursive: true,
|
|
64
|
+
force: true
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
exports.createSkillOverlayDirectory = __webpack_exports__.createSkillOverlayDirectory;
|
|
68
|
+
exports.removeSkillOverlayDirectory = __webpack_exports__.removeSkillOverlayDirectory;
|
|
69
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
70
|
+
"createSkillOverlayDirectory",
|
|
71
|
+
"removeSkillOverlayDirectory"
|
|
72
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
73
|
+
Object.defineProperty(exports, '__esModule', {
|
|
74
|
+
value: true
|
|
75
|
+
});
|