@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.
Files changed (104) hide show
  1. package/README.md +29 -111
  2. package/dist/agent/config/agentConfig.cjs +2 -0
  3. package/dist/agent/config/agentConfig.d.ts +6 -0
  4. package/dist/agent/config/agentConfig.js +2 -0
  5. package/dist/agent/config/agentLoader.cjs +21 -18
  6. package/dist/agent/config/agentLoader.js +22 -19
  7. package/dist/agent/config/toolRegistry.cjs +19 -0
  8. package/dist/agent/config/toolRegistry.d.ts +4 -0
  9. package/dist/agent/config/toolRegistry.js +17 -1
  10. package/dist/agent/middleware/additional-messages.cjs +115 -11
  11. package/dist/agent/middleware/additional-messages.d.ts +9 -0
  12. package/dist/agent/middleware/additional-messages.js +115 -11
  13. package/dist/agent/tests/agentLoader.test.cjs +45 -0
  14. package/dist/agent/tests/agentLoader.test.js +45 -0
  15. package/dist/agent/tests/toolRegistry.test.cjs +2 -0
  16. package/dist/agent/tests/toolRegistry.test.js +2 -0
  17. package/dist/agent/tools/node_invoke.cjs +146 -0
  18. package/dist/agent/tools/node_invoke.d.ts +86 -0
  19. package/dist/agent/tools/node_invoke.js +109 -0
  20. package/dist/cli/commands/gateway.cjs +1 -1
  21. package/dist/cli/commands/gateway.js +1 -1
  22. package/dist/cli/commands/init.cjs +135 -1
  23. package/dist/cli/commands/init.js +136 -2
  24. package/dist/cli/commands/skill.cjs +7 -3
  25. package/dist/cli/commands/skill.js +7 -3
  26. package/dist/cli/config/loader.cjs +7 -3
  27. package/dist/cli/config/loader.js +7 -3
  28. package/dist/cli/config/schema.cjs +27 -9
  29. package/dist/cli/config/schema.d.ts +18 -4
  30. package/dist/cli/config/schema.js +23 -8
  31. package/dist/cli/core/agentInvoker.cjs +70 -14
  32. package/dist/cli/core/agentInvoker.d.ts +10 -0
  33. package/dist/cli/core/agentInvoker.js +70 -14
  34. package/dist/cli/services/skillRepository.cjs +155 -69
  35. package/dist/cli/services/skillRepository.d.ts +7 -2
  36. package/dist/cli/services/skillRepository.js +155 -69
  37. package/dist/cli/services/skillService.cjs +93 -26
  38. package/dist/cli/services/skillService.d.ts +7 -0
  39. package/dist/cli/services/skillService.js +96 -29
  40. package/dist/cli/types/skill.d.ts +8 -3
  41. package/dist/gateway/http/nodes.cjs +247 -0
  42. package/dist/gateway/http/nodes.d.ts +20 -0
  43. package/dist/gateway/http/nodes.js +210 -0
  44. package/dist/gateway/node.cjs +10 -1
  45. package/dist/gateway/node.d.ts +10 -1
  46. package/dist/gateway/node.js +10 -1
  47. package/dist/gateway/server.cjs +414 -27
  48. package/dist/gateway/server.d.ts +34 -0
  49. package/dist/gateway/server.js +408 -27
  50. package/dist/gateway/types.d.ts +6 -1
  51. package/dist/gateway/validation.cjs +2 -0
  52. package/dist/gateway/validation.d.ts +4 -0
  53. package/dist/gateway/validation.js +2 -0
  54. package/dist/skills/activation.cjs +92 -0
  55. package/dist/skills/activation.d.ts +12 -0
  56. package/dist/skills/activation.js +58 -0
  57. package/dist/skills/bin-requirements.cjs +63 -0
  58. package/dist/skills/bin-requirements.d.ts +3 -0
  59. package/dist/skills/bin-requirements.js +26 -0
  60. package/dist/skills/metadata.cjs +141 -0
  61. package/dist/skills/metadata.d.ts +29 -0
  62. package/dist/skills/metadata.js +104 -0
  63. package/dist/skills/overlay.cjs +75 -0
  64. package/dist/skills/overlay.d.ts +2 -0
  65. package/dist/skills/overlay.js +38 -0
  66. package/dist/tests/additionalMessageMiddleware.test.cjs +92 -0
  67. package/dist/tests/additionalMessageMiddleware.test.js +92 -0
  68. package/dist/tests/cli-config-loader.test.cjs +7 -3
  69. package/dist/tests/cli-config-loader.test.js +7 -3
  70. package/dist/tests/cli-init.test.cjs +54 -0
  71. package/dist/tests/cli-init.test.js +54 -0
  72. package/dist/tests/config-json-schema.test.cjs +12 -0
  73. package/dist/tests/config-json-schema.test.js +12 -0
  74. package/dist/tests/gateway-http-security.test.cjs +277 -0
  75. package/dist/tests/gateway-http-security.test.d.ts +1 -0
  76. package/dist/tests/gateway-http-security.test.js +271 -0
  77. package/dist/tests/gateway-node-mode.test.cjs +174 -0
  78. package/dist/tests/gateway-node-mode.test.d.ts +1 -0
  79. package/dist/tests/gateway-node-mode.test.js +168 -0
  80. package/dist/tests/gateway-origin-policy.test.cjs +60 -0
  81. package/dist/tests/gateway-origin-policy.test.d.ts +1 -0
  82. package/dist/tests/gateway-origin-policy.test.js +54 -0
  83. package/dist/tests/gateway.test.cjs +1 -0
  84. package/dist/tests/gateway.test.js +1 -0
  85. package/dist/tests/node-tools.test.cjs +77 -0
  86. package/dist/tests/node-tools.test.d.ts +1 -0
  87. package/dist/tests/node-tools.test.js +71 -0
  88. package/dist/tests/nodes-api.test.cjs +86 -0
  89. package/dist/tests/nodes-api.test.d.ts +1 -0
  90. package/dist/tests/nodes-api.test.js +80 -0
  91. package/dist/tests/skill-activation.test.cjs +86 -0
  92. package/dist/tests/skill-activation.test.d.ts +1 -0
  93. package/dist/tests/skill-activation.test.js +80 -0
  94. package/dist/tests/skill-metadata.test.cjs +119 -0
  95. package/dist/tests/skill-metadata.test.d.ts +1 -0
  96. package/dist/tests/skill-metadata.test.js +113 -0
  97. package/dist/tests/skill-repository.test.cjs +363 -0
  98. package/dist/tests/skill-repository.test.js +363 -0
  99. package/dist/webui/assets/{index-DHbfLOUR.js → index-BMekSELC.js} +106 -106
  100. package/dist/webui/index.html +1 -1
  101. package/package.json +4 -4
  102. package/skills/gog/SKILL.md +1 -1
  103. package/skills/weather/SKILL.md +1 -1
  104. package/skills/ui-registry/SKILL.md +0 -35
@@ -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
  /**
@@ -44,6 +44,8 @@ const MessageTypeSchema = external_zod_namespaceObject["enum"]([
44
44
  "req:agent",
45
45
  "req:agent:cancel",
46
46
  "event:agent",
47
+ "req:node",
48
+ "event:node",
47
49
  "session_subscribe",
48
50
  "session_unsubscribe",
49
51
  "register",
@@ -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";
@@ -5,6 +5,8 @@ const MessageTypeSchema = external_zod_enum([
5
5
  "req:agent",
6
6
  "req:agent:cancel",
7
7
  "event:agent",
8
+ "req:node",
9
+ "event:node",
8
10
  "session_subscribe",
9
11
  "session_unsubscribe",
10
12
  "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,3 @@
1
+ export type BinAvailabilityChecker = (binName: string) => boolean;
2
+ export declare const isBinAvailable: BinAvailabilityChecker;
3
+ export declare const findMissingBins: (bins: string[], checkBin?: BinAvailabilityChecker) => string[];
@@ -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
+ });
@@ -0,0 +1,2 @@
1
+ export declare const createSkillOverlayDirectory: (skillsRoot: string, activeSkillNames: string[]) => Promise<string>;
2
+ export declare const removeSkillOverlayDirectory: (overlayPath: string) => Promise<void>;