@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.
Files changed (200) hide show
  1. package/README.md +14 -0
  2. package/dist/agent/config/mcpClientManager.cjs +104 -1
  3. package/dist/agent/config/mcpClientManager.d.ts +30 -0
  4. package/dist/agent/config/mcpClientManager.js +104 -1
  5. package/dist/agent/config/modelFactory.cjs +10 -0
  6. package/dist/agent/config/modelFactory.js +10 -0
  7. package/dist/agent/config/xaiImageModel.cjs +242 -0
  8. package/dist/agent/config/xaiImageModel.d.ts +33 -0
  9. package/dist/agent/config/xaiImageModel.js +202 -0
  10. package/dist/agent/tests/mcpClientManager.test.cjs +116 -0
  11. package/dist/agent/tests/mcpClientManager.test.js +117 -1
  12. package/dist/agent/tests/mcpResourceTools.test.cjs +101 -0
  13. package/dist/agent/tests/mcpResourceTools.test.d.ts +1 -0
  14. package/dist/agent/tests/mcpResourceTools.test.js +95 -0
  15. package/dist/agent/tests/modelFactory.test.cjs +16 -2
  16. package/dist/agent/tests/modelFactory.test.js +16 -2
  17. package/dist/agent/tests/xaiImageModel.test.cjs +194 -0
  18. package/dist/agent/tests/xaiImageModel.test.d.ts +1 -0
  19. package/dist/agent/tests/xaiImageModel.test.js +188 -0
  20. package/dist/agent/tools/mcp_resources.cjs +111 -0
  21. package/dist/agent/tools/mcp_resources.d.ts +3 -0
  22. package/dist/agent/tools/mcp_resources.js +77 -0
  23. package/dist/bench/adapters/commandAdapter.cjs +93 -0
  24. package/dist/bench/adapters/commandAdapter.d.ts +6 -0
  25. package/dist/bench/adapters/commandAdapter.js +59 -0
  26. package/dist/bench/adapters/helpers.cjs +170 -0
  27. package/dist/bench/adapters/helpers.d.ts +7 -0
  28. package/dist/bench/adapters/helpers.js +133 -0
  29. package/dist/bench/adapters/index.cjs +41 -0
  30. package/dist/bench/adapters/index.d.ts +2 -0
  31. package/dist/bench/adapters/index.js +7 -0
  32. package/dist/bench/adapters/wingmanCliAdapter.cjs +100 -0
  33. package/dist/bench/adapters/wingmanCliAdapter.d.ts +6 -0
  34. package/dist/bench/adapters/wingmanCliAdapter.js +66 -0
  35. package/dist/bench/cleanup.cjs +122 -0
  36. package/dist/bench/cleanup.d.ts +9 -0
  37. package/dist/bench/cleanup.js +85 -0
  38. package/dist/bench/config.cjs +190 -0
  39. package/dist/bench/config.d.ts +2 -0
  40. package/dist/bench/config.js +156 -0
  41. package/dist/bench/index.cjs +43 -0
  42. package/dist/bench/index.d.ts +3 -0
  43. package/dist/bench/index.js +3 -0
  44. package/dist/bench/official.cjs +616 -0
  45. package/dist/bench/official.d.ts +80 -0
  46. package/dist/bench/official.js +546 -0
  47. package/dist/bench/officialCli.cjs +204 -0
  48. package/dist/bench/officialCli.d.ts +5 -0
  49. package/dist/bench/officialCli.js +170 -0
  50. package/dist/bench/process.cjs +78 -0
  51. package/dist/bench/process.d.ts +14 -0
  52. package/dist/bench/process.js +44 -0
  53. package/dist/bench/runner.cjs +237 -0
  54. package/dist/bench/runner.d.ts +7 -0
  55. package/dist/bench/runner.js +197 -0
  56. package/dist/bench/scoring.cjs +171 -0
  57. package/dist/bench/scoring.d.ts +9 -0
  58. package/dist/bench/scoring.js +137 -0
  59. package/dist/bench/types.cjs +18 -0
  60. package/dist/bench/types.d.ts +200 -0
  61. package/dist/bench/types.js +0 -0
  62. package/dist/bench/validator.cjs +92 -0
  63. package/dist/bench/validator.d.ts +2 -0
  64. package/dist/bench/validator.js +58 -0
  65. package/dist/cli/commands/init.cjs +135 -1
  66. package/dist/cli/commands/init.js +136 -2
  67. package/dist/cli/commands/skill.cjs +7 -3
  68. package/dist/cli/commands/skill.js +7 -3
  69. package/dist/cli/config/loader.cjs +7 -3
  70. package/dist/cli/config/loader.js +7 -3
  71. package/dist/cli/config/schema.cjs +63 -10
  72. package/dist/cli/config/schema.d.ts +64 -4
  73. package/dist/cli/config/schema.js +59 -9
  74. package/dist/cli/config/warnings.cjs +119 -51
  75. package/dist/cli/config/warnings.js +119 -51
  76. package/dist/cli/core/agentInvoker.cjs +58 -13
  77. package/dist/cli/core/agentInvoker.d.ts +1 -0
  78. package/dist/cli/core/agentInvoker.js +58 -13
  79. package/dist/cli/core/imagePersistence.cjs +17 -1
  80. package/dist/cli/core/imagePersistence.d.ts +2 -0
  81. package/dist/cli/core/imagePersistence.js +13 -3
  82. package/dist/cli/core/sessionManager.cjs +2 -0
  83. package/dist/cli/core/sessionManager.js +3 -1
  84. package/dist/cli/services/skillRepository.cjs +155 -69
  85. package/dist/cli/services/skillRepository.d.ts +7 -2
  86. package/dist/cli/services/skillRepository.js +155 -69
  87. package/dist/cli/services/skillService.cjs +93 -26
  88. package/dist/cli/services/skillService.d.ts +7 -0
  89. package/dist/cli/services/skillService.js +96 -29
  90. package/dist/cli/types/skill.d.ts +8 -3
  91. package/dist/cli/types.d.ts +18 -0
  92. package/dist/gateway/adapters/teams.cjs +419 -0
  93. package/dist/gateway/adapters/teams.d.ts +47 -0
  94. package/dist/gateway/adapters/teams.js +361 -0
  95. package/dist/gateway/http/sms.cjs +286 -0
  96. package/dist/gateway/http/sms.d.ts +4 -0
  97. package/dist/gateway/http/sms.js +249 -0
  98. package/dist/gateway/server.cjs +54 -3
  99. package/dist/gateway/server.d.ts +2 -0
  100. package/dist/gateway/server.js +54 -3
  101. package/dist/gateway/sms/commands.cjs +116 -0
  102. package/dist/gateway/sms/commands.d.ts +15 -0
  103. package/dist/gateway/sms/commands.js +79 -0
  104. package/dist/gateway/sms/control.cjs +118 -0
  105. package/dist/gateway/sms/control.d.ts +18 -0
  106. package/dist/gateway/sms/control.js +84 -0
  107. package/dist/gateway/sms/policyStore.cjs +198 -0
  108. package/dist/gateway/sms/policyStore.d.ts +37 -0
  109. package/dist/gateway/sms/policyStore.js +161 -0
  110. package/dist/providers/registry.cjs +1 -0
  111. package/dist/providers/registry.js +1 -0
  112. package/dist/skills/activation.cjs +92 -0
  113. package/dist/skills/activation.d.ts +12 -0
  114. package/dist/skills/activation.js +58 -0
  115. package/dist/skills/bin-requirements.cjs +63 -0
  116. package/dist/skills/bin-requirements.d.ts +3 -0
  117. package/dist/skills/bin-requirements.js +26 -0
  118. package/dist/skills/metadata.cjs +141 -0
  119. package/dist/skills/metadata.d.ts +29 -0
  120. package/dist/skills/metadata.js +104 -0
  121. package/dist/skills/overlay.cjs +75 -0
  122. package/dist/skills/overlay.d.ts +2 -0
  123. package/dist/skills/overlay.js +38 -0
  124. package/dist/tests/cli-config-loader.test.cjs +7 -3
  125. package/dist/tests/cli-config-loader.test.js +7 -3
  126. package/dist/tests/cli-config-warnings.test.cjs +41 -0
  127. package/dist/tests/cli-config-warnings.test.js +41 -0
  128. package/dist/tests/cli-init.test.cjs +86 -26
  129. package/dist/tests/cli-init.test.js +86 -26
  130. package/dist/tests/config-json-schema.test.cjs +12 -0
  131. package/dist/tests/config-json-schema.test.js +12 -0
  132. package/dist/tests/gateway-http-security.test.cjs +21 -0
  133. package/dist/tests/gateway-http-security.test.js +21 -0
  134. package/dist/tests/gateway-origin-policy.test.cjs +22 -0
  135. package/dist/tests/gateway-origin-policy.test.js +22 -0
  136. package/dist/tests/gateway.test.cjs +57 -0
  137. package/dist/tests/gateway.test.js +57 -0
  138. package/dist/tests/imagePersistence.test.cjs +26 -0
  139. package/dist/tests/imagePersistence.test.js +27 -1
  140. package/dist/tests/run-terminal-bench-official-script.test.cjs +61 -0
  141. package/dist/tests/run-terminal-bench-official-script.test.d.ts +1 -0
  142. package/dist/tests/run-terminal-bench-official-script.test.js +55 -0
  143. package/dist/tests/sessions-api.test.cjs +69 -1
  144. package/dist/tests/sessions-api.test.js +70 -2
  145. package/dist/tests/skill-activation.test.cjs +86 -0
  146. package/dist/tests/skill-activation.test.d.ts +1 -0
  147. package/dist/tests/skill-activation.test.js +80 -0
  148. package/dist/tests/skill-metadata.test.cjs +119 -0
  149. package/dist/tests/skill-metadata.test.d.ts +1 -0
  150. package/dist/tests/skill-metadata.test.js +113 -0
  151. package/dist/tests/skill-repository.test.cjs +363 -0
  152. package/dist/tests/skill-repository.test.js +363 -0
  153. package/dist/tests/sms-api.test.cjs +183 -0
  154. package/dist/tests/sms-api.test.d.ts +1 -0
  155. package/dist/tests/sms-api.test.js +177 -0
  156. package/dist/tests/sms-commands.test.cjs +90 -0
  157. package/dist/tests/sms-commands.test.d.ts +1 -0
  158. package/dist/tests/sms-commands.test.js +84 -0
  159. package/dist/tests/sms-policy-store.test.cjs +69 -0
  160. package/dist/tests/sms-policy-store.test.d.ts +1 -0
  161. package/dist/tests/sms-policy-store.test.js +63 -0
  162. package/dist/tests/teams-adapter.test.cjs +58 -0
  163. package/dist/tests/teams-adapter.test.d.ts +1 -0
  164. package/dist/tests/teams-adapter.test.js +52 -0
  165. package/dist/tests/terminal-bench-adapters-helpers.test.cjs +64 -0
  166. package/dist/tests/terminal-bench-adapters-helpers.test.d.ts +1 -0
  167. package/dist/tests/terminal-bench-adapters-helpers.test.js +58 -0
  168. package/dist/tests/terminal-bench-cleanup.test.cjs +93 -0
  169. package/dist/tests/terminal-bench-cleanup.test.d.ts +1 -0
  170. package/dist/tests/terminal-bench-cleanup.test.js +87 -0
  171. package/dist/tests/terminal-bench-config.test.cjs +62 -0
  172. package/dist/tests/terminal-bench-config.test.d.ts +1 -0
  173. package/dist/tests/terminal-bench-config.test.js +56 -0
  174. package/dist/tests/terminal-bench-official.test.cjs +194 -0
  175. package/dist/tests/terminal-bench-official.test.d.ts +1 -0
  176. package/dist/tests/terminal-bench-official.test.js +188 -0
  177. package/dist/tests/terminal-bench-runner.test.cjs +82 -0
  178. package/dist/tests/terminal-bench-runner.test.d.ts +1 -0
  179. package/dist/tests/terminal-bench-runner.test.js +76 -0
  180. package/dist/tests/terminal-bench-scoring.test.cjs +128 -0
  181. package/dist/tests/terminal-bench-scoring.test.d.ts +1 -0
  182. package/dist/tests/terminal-bench-scoring.test.js +122 -0
  183. package/dist/tools/mcp-fal-ai.cjs +1 -1
  184. package/dist/tools/mcp-fal-ai.js +1 -1
  185. package/dist/webui/assets/index-Cyg_Hs57.css +11 -0
  186. package/dist/webui/assets/{index-BMekSELC.js → index-DZXLLjaA.js} +109 -109
  187. package/dist/webui/index.html +2 -2
  188. package/package.json +14 -5
  189. package/skills/gog/SKILL.md +1 -1
  190. package/skills/weather/SKILL.md +1 -1
  191. package/templates/agents/game-dev/agent.md +122 -63
  192. package/templates/agents/game-dev/art-director.md +106 -0
  193. package/templates/agents/game-dev/game-designer.md +87 -0
  194. package/templates/agents/game-dev/scene-engineer.md +474 -0
  195. package/dist/webui/assets/index-Cwkg4DKj.css +0 -11
  196. package/skills/ui-registry/SKILL.md +0 -35
  197. package/templates/agents/game-dev/art-generation.md +0 -38
  198. package/templates/agents/game-dev/asset-refinement.md +0 -17
  199. package/templates/agents/game-dev/planning-idea.md +0 -17
  200. package/templates/agents/game-dev/ui-specialist.md +0 -17
@@ -1,7 +1,8 @@
1
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
1
+ import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
+ import { getSessionMediaDirectory, persistAssistantImagesToDisk } from "../cli/core/imagePersistence.js";
5
6
  import { SessionManager } from "../cli/core/sessionManager.js";
6
7
  import { handleSessionsApi } from "../gateway/http/sessions.js";
7
8
  const isBunRuntime = void 0 !== globalThis.Bun;
@@ -9,9 +10,11 @@ const describeIfBun = isBunRuntime ? describe : describe.skip;
9
10
  describeIfBun("sessions API", ()=>{
10
11
  let manager;
11
12
  let tempDir;
13
+ let dbPath;
14
+ const PNG_DATA_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO3X6S0AAAAASUVORK5CYII=";
12
15
  beforeEach(async ()=>{
13
16
  tempDir = mkdtempSync(join(tmpdir(), "wingman-sessions-"));
14
- const dbPath = join(tempDir, "sessions.db");
17
+ dbPath = join(tempDir, "sessions.db");
15
18
  manager = new SessionManager(dbPath);
16
19
  await manager.initialize();
17
20
  });
@@ -43,6 +46,23 @@ describeIfBun("sessions API", ()=>{
43
46
  expect(createRes).not.toBeNull();
44
47
  expect(createRes?.ok).toBe(true);
45
48
  const created = await createRes.json();
49
+ const mediaDir = getSessionMediaDirectory(dbPath, created.id);
50
+ persistAssistantImagesToDisk({
51
+ dbPath,
52
+ sessionId: created.id,
53
+ messages: [
54
+ {
55
+ role: "assistant",
56
+ attachments: [
57
+ {
58
+ kind: "image",
59
+ dataUrl: PNG_DATA_URL
60
+ }
61
+ ]
62
+ }
63
+ ]
64
+ });
65
+ expect(existsSync(mediaDir)).toBe(true);
46
66
  manager.updateSession(created.id, {
47
67
  messageCount: 2,
48
68
  lastMessagePreview: "Hello"
@@ -55,10 +75,58 @@ describeIfBun("sessions API", ()=>{
55
75
  expect(deleteRes?.ok).toBe(true);
56
76
  const payload = await deleteRes.json();
57
77
  expect(payload.messageCount).toBe(0);
78
+ expect(existsSync(mediaDir)).toBe(false);
58
79
  const updated = manager.getSession(created.id);
59
80
  expect(updated?.messageCount).toBe(0);
60
81
  expect(updated?.lastMessagePreview).toBeNull();
61
82
  });
83
+ it("removes persisted session media when deleting a session", async ()=>{
84
+ const ctx = {
85
+ getSessionManager: async ()=>manager,
86
+ router: {
87
+ selectAgent: (agentId)=>agentId || "main"
88
+ }
89
+ };
90
+ const createReq = new Request("http://localhost/api/sessions", {
91
+ method: "POST",
92
+ headers: {
93
+ "Content-Type": "application/json"
94
+ },
95
+ body: JSON.stringify({
96
+ agentId: "main",
97
+ name: "Delete Session Media"
98
+ })
99
+ });
100
+ const createRes = await handleSessionsApi(ctx, createReq, new URL(createReq.url));
101
+ expect(createRes).not.toBeNull();
102
+ expect(createRes?.ok).toBe(true);
103
+ const created = await createRes.json();
104
+ const mediaDir = getSessionMediaDirectory(dbPath, created.id);
105
+ persistAssistantImagesToDisk({
106
+ dbPath,
107
+ sessionId: created.id,
108
+ messages: [
109
+ {
110
+ role: "assistant",
111
+ attachments: [
112
+ {
113
+ kind: "image",
114
+ dataUrl: PNG_DATA_URL
115
+ }
116
+ ]
117
+ }
118
+ ]
119
+ });
120
+ expect(existsSync(mediaDir)).toBe(true);
121
+ const deleteReq = new Request(`http://localhost/api/sessions/${encodeURIComponent(created.id)}?agentId=main`, {
122
+ method: "DELETE"
123
+ });
124
+ const deleteRes = await handleSessionsApi(ctx, deleteReq, new URL(deleteReq.url));
125
+ expect(deleteRes).not.toBeNull();
126
+ expect(deleteRes?.ok).toBe(true);
127
+ expect(existsSync(mediaDir)).toBe(false);
128
+ expect(manager.getSession(created.id)).toBeNull();
129
+ });
62
130
  it("returns pending messages and clears them via DELETE", async ()=>{
63
131
  const ctx = {
64
132
  getSessionManager: async ()=>manager,
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __webpack_exports__ = {};
3
+ const external_node_fs_namespaceObject = require("node:fs");
4
+ const external_node_os_namespaceObject = require("node:os");
5
+ const external_node_path_namespaceObject = require("node:path");
6
+ const external_vitest_namespaceObject = require("vitest");
7
+ const activation_cjs_namespaceObject = require("../skills/activation.cjs");
8
+ const tempDirs = [];
9
+ const createSkill = (root, skillName, frontmatter)=>{
10
+ const skillDir = (0, external_node_path_namespaceObject.join)(root, skillName);
11
+ (0, external_node_fs_namespaceObject.mkdirSync)(skillDir, {
12
+ recursive: true
13
+ });
14
+ (0, external_node_fs_namespaceObject.writeFileSync)(skillDir + "/SKILL.md", `${frontmatter}\n\n# ${skillName}\n`);
15
+ };
16
+ (0, external_vitest_namespaceObject.afterEach)(()=>{
17
+ for (const dir of tempDirs)(0, external_node_fs_namespaceObject.rmSync)(dir, {
18
+ recursive: true,
19
+ force: true
20
+ });
21
+ tempDirs.length = 0;
22
+ });
23
+ (0, external_vitest_namespaceObject.describe)("resolveSkillActivation", ()=>{
24
+ (0, external_vitest_namespaceObject.it)("deactivates skills with missing required bins", async ()=>{
25
+ const root = (0, external_node_fs_namespaceObject.mkdtempSync)((0, external_node_path_namespaceObject.join)((0, external_node_os_namespaceObject.tmpdir)(), "wingman-skill-activation-"));
26
+ tempDirs.push(root);
27
+ createSkill(root, "gog", `---
28
+ name: gog
29
+ description: Google tooling
30
+ metadata:
31
+ wingman:
32
+ requires:
33
+ bins: ["gog"]
34
+ ---`);
35
+ createSkill(root, "weather", `---
36
+ name: weather
37
+ description: Weather tooling
38
+ ---`);
39
+ const result = await (0, activation_cjs_namespaceObject.resolveSkillActivation)(root, (binName)=>"gog" !== binName);
40
+ (0, external_vitest_namespaceObject.expect)(result.activeSkillNames).toContain("weather");
41
+ (0, external_vitest_namespaceObject.expect)(result.activeSkillNames).not.toContain("gog");
42
+ (0, external_vitest_namespaceObject.expect)(result.inactiveSkills).toEqual([
43
+ {
44
+ name: "gog",
45
+ namespace: "wingman",
46
+ requiredBins: [
47
+ "gog"
48
+ ],
49
+ missingBins: [
50
+ "gog"
51
+ ]
52
+ }
53
+ ]);
54
+ });
55
+ (0, external_vitest_namespaceObject.it)("ignores unsupported namespaces and keeps skills active", async ()=>{
56
+ const root = (0, external_node_fs_namespaceObject.mkdtempSync)((0, external_node_path_namespaceObject.join)((0, external_node_os_namespaceObject.tmpdir)(), "wingman-skill-activation-"));
57
+ tempDirs.push(root);
58
+ createSkill(root, "legacy", `---
59
+ name: legacy
60
+ description: Legacy metadata
61
+ metadata:
62
+ clawdbot:
63
+ requires:
64
+ bins: ["gog"]
65
+ ---`);
66
+ const result = await (0, activation_cjs_namespaceObject.resolveSkillActivation)(root, ()=>false);
67
+ (0, external_vitest_namespaceObject.expect)(result.activeSkillNames).toContain("legacy");
68
+ (0, external_vitest_namespaceObject.expect)(result.inactiveSkills).toHaveLength(0);
69
+ });
70
+ (0, external_vitest_namespaceObject.it)("keeps skill active when frontmatter parsing fails", async ()=>{
71
+ const root = (0, external_node_fs_namespaceObject.mkdtempSync)((0, external_node_path_namespaceObject.join)((0, external_node_os_namespaceObject.tmpdir)(), "wingman-skill-activation-"));
72
+ tempDirs.push(root);
73
+ const skillDir = (0, external_node_path_namespaceObject.join)(root, "broken");
74
+ (0, external_node_fs_namespaceObject.mkdirSync)(skillDir, {
75
+ recursive: true
76
+ });
77
+ (0, external_node_fs_namespaceObject.writeFileSync)((0, external_node_path_namespaceObject.join)(skillDir, "SKILL.md"), "---\nname: broken\nnot-valid\n---");
78
+ const result = await (0, activation_cjs_namespaceObject.resolveSkillActivation)(root, ()=>true);
79
+ (0, external_vitest_namespaceObject.expect)(result.activeSkillNames).toContain("broken");
80
+ (0, external_vitest_namespaceObject.expect)(result.inactiveSkills).toHaveLength(0);
81
+ });
82
+ });
83
+ for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
84
+ Object.defineProperty(exports, '__esModule', {
85
+ value: true
86
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,80 @@
1
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, describe, expect, it } from "vitest";
5
+ import { resolveSkillActivation } from "../skills/activation.js";
6
+ const tempDirs = [];
7
+ const createSkill = (root, skillName, frontmatter)=>{
8
+ const skillDir = join(root, skillName);
9
+ mkdirSync(skillDir, {
10
+ recursive: true
11
+ });
12
+ writeFileSync(skillDir + "/SKILL.md", `${frontmatter}\n\n# ${skillName}\n`);
13
+ };
14
+ afterEach(()=>{
15
+ for (const dir of tempDirs)rmSync(dir, {
16
+ recursive: true,
17
+ force: true
18
+ });
19
+ tempDirs.length = 0;
20
+ });
21
+ describe("resolveSkillActivation", ()=>{
22
+ it("deactivates skills with missing required bins", async ()=>{
23
+ const root = mkdtempSync(join(tmpdir(), "wingman-skill-activation-"));
24
+ tempDirs.push(root);
25
+ createSkill(root, "gog", `---
26
+ name: gog
27
+ description: Google tooling
28
+ metadata:
29
+ wingman:
30
+ requires:
31
+ bins: ["gog"]
32
+ ---`);
33
+ createSkill(root, "weather", `---
34
+ name: weather
35
+ description: Weather tooling
36
+ ---`);
37
+ const result = await resolveSkillActivation(root, (binName)=>"gog" !== binName);
38
+ expect(result.activeSkillNames).toContain("weather");
39
+ expect(result.activeSkillNames).not.toContain("gog");
40
+ expect(result.inactiveSkills).toEqual([
41
+ {
42
+ name: "gog",
43
+ namespace: "wingman",
44
+ requiredBins: [
45
+ "gog"
46
+ ],
47
+ missingBins: [
48
+ "gog"
49
+ ]
50
+ }
51
+ ]);
52
+ });
53
+ it("ignores unsupported namespaces and keeps skills active", async ()=>{
54
+ const root = mkdtempSync(join(tmpdir(), "wingman-skill-activation-"));
55
+ tempDirs.push(root);
56
+ createSkill(root, "legacy", `---
57
+ name: legacy
58
+ description: Legacy metadata
59
+ metadata:
60
+ clawdbot:
61
+ requires:
62
+ bins: ["gog"]
63
+ ---`);
64
+ const result = await resolveSkillActivation(root, ()=>false);
65
+ expect(result.activeSkillNames).toContain("legacy");
66
+ expect(result.inactiveSkills).toHaveLength(0);
67
+ });
68
+ it("keeps skill active when frontmatter parsing fails", async ()=>{
69
+ const root = mkdtempSync(join(tmpdir(), "wingman-skill-activation-"));
70
+ tempDirs.push(root);
71
+ const skillDir = join(root, "broken");
72
+ mkdirSync(skillDir, {
73
+ recursive: true
74
+ });
75
+ writeFileSync(join(skillDir, "SKILL.md"), "---\nname: broken\nnot-valid\n---");
76
+ const result = await resolveSkillActivation(root, ()=>true);
77
+ expect(result.activeSkillNames).toContain("broken");
78
+ expect(result.inactiveSkills).toHaveLength(0);
79
+ });
80
+ });
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ var __webpack_exports__ = {};
3
+ const external_vitest_namespaceObject = require("vitest");
4
+ const metadata_cjs_namespaceObject = require("../skills/metadata.cjs");
5
+ (0, external_vitest_namespaceObject.describe)("parseSkillFrontmatter", ()=>{
6
+ (0, external_vitest_namespaceObject.it)("parses wingman metadata with requires and install recipes", ()=>{
7
+ const content = `---
8
+ name: gog
9
+ description: Google tooling
10
+ metadata:
11
+ wingman:
12
+ emoji: "🎮"
13
+ requires:
14
+ bins: ["gog"]
15
+ install:
16
+ - id: brew
17
+ kind: brew
18
+ formula: steipete/tap/gogcli
19
+ bins: ["gog"]
20
+ label: Install gog (brew)
21
+ ---
22
+
23
+ # gog
24
+ `;
25
+ const parsed = (0, metadata_cjs_namespaceObject.parseSkillFrontmatter)(content);
26
+ (0, external_vitest_namespaceObject.expect)(parsed.name).toBe("gog");
27
+ (0, external_vitest_namespaceObject.expect)(parsed.description).toBe("Google tooling");
28
+ (0, external_vitest_namespaceObject.expect)(parsed.runtimeMetadata?.namespace).toBe("wingman");
29
+ (0, external_vitest_namespaceObject.expect)(parsed.runtimeMetadata?.requires.bins).toEqual([
30
+ "gog"
31
+ ]);
32
+ (0, external_vitest_namespaceObject.expect)(parsed.runtimeMetadata?.install).toEqual([
33
+ {
34
+ id: "brew",
35
+ kind: "brew",
36
+ formula: "steipete/tap/gogcli",
37
+ bins: [
38
+ "gog"
39
+ ],
40
+ label: "Install gog (brew)"
41
+ }
42
+ ]);
43
+ });
44
+ (0, external_vitest_namespaceObject.it)("prefers wingman over openclaw when both namespaces are present", ()=>{
45
+ const content = `---
46
+ name: dual
47
+ description: Dual namespace
48
+ metadata:
49
+ openclaw:
50
+ requires:
51
+ bins: ["oldbin"]
52
+ wingman:
53
+ requires:
54
+ bins: ["newbin"]
55
+ ---
56
+
57
+ # dual
58
+ `;
59
+ const parsed = (0, metadata_cjs_namespaceObject.parseSkillFrontmatter)(content);
60
+ (0, external_vitest_namespaceObject.expect)(parsed.runtimeMetadata?.namespace).toBe("wingman");
61
+ (0, external_vitest_namespaceObject.expect)(parsed.runtimeMetadata?.requires.bins).toEqual([
62
+ "newbin"
63
+ ]);
64
+ });
65
+ (0, external_vitest_namespaceObject.it)("supports openclaw namespace when wingman is absent", ()=>{
66
+ const content = `---
67
+ name: open
68
+ description: Openclaw namespace
69
+ metadata:
70
+ openclaw:
71
+ requires:
72
+ bins: ["gog"]
73
+ ---
74
+
75
+ # open
76
+ `;
77
+ const parsed = (0, metadata_cjs_namespaceObject.parseSkillFrontmatter)(content);
78
+ (0, external_vitest_namespaceObject.expect)(parsed.runtimeMetadata?.namespace).toBe("openclaw");
79
+ (0, external_vitest_namespaceObject.expect)(parsed.runtimeMetadata?.requires.bins).toEqual([
80
+ "gog"
81
+ ]);
82
+ });
83
+ (0, external_vitest_namespaceObject.it)("ignores unsupported namespaces like clawdbot", ()=>{
84
+ const content = `---
85
+ name: legacy
86
+ description: Legacy metadata
87
+ metadata:
88
+ clawdbot:
89
+ requires:
90
+ bins: ["gog"]
91
+ ---
92
+
93
+ # legacy
94
+ `;
95
+ const parsed = (0, metadata_cjs_namespaceObject.parseSkillFrontmatter)(content);
96
+ (0, external_vitest_namespaceObject.expect)(parsed.runtimeMetadata).toBeNull();
97
+ });
98
+ (0, external_vitest_namespaceObject.it)("normalizes allowed tools from either key", ()=>{
99
+ const content = `---
100
+ name: ui-registry
101
+ description: UI helpers
102
+ allowedTools:
103
+ - ui_registry_list
104
+ - ui_present
105
+ ---
106
+
107
+ # ui
108
+ `;
109
+ const parsed = (0, metadata_cjs_namespaceObject.parseSkillFrontmatter)(content);
110
+ (0, external_vitest_namespaceObject.expect)(parsed.allowedTools).toEqual([
111
+ "ui_registry_list",
112
+ "ui_present"
113
+ ]);
114
+ });
115
+ });
116
+ for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
117
+ Object.defineProperty(exports, '__esModule', {
118
+ value: true
119
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,113 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { parseSkillFrontmatter } from "../skills/metadata.js";
3
+ describe("parseSkillFrontmatter", ()=>{
4
+ it("parses wingman metadata with requires and install recipes", ()=>{
5
+ const content = `---
6
+ name: gog
7
+ description: Google tooling
8
+ metadata:
9
+ wingman:
10
+ emoji: "🎮"
11
+ requires:
12
+ bins: ["gog"]
13
+ install:
14
+ - id: brew
15
+ kind: brew
16
+ formula: steipete/tap/gogcli
17
+ bins: ["gog"]
18
+ label: Install gog (brew)
19
+ ---
20
+
21
+ # gog
22
+ `;
23
+ const parsed = parseSkillFrontmatter(content);
24
+ expect(parsed.name).toBe("gog");
25
+ expect(parsed.description).toBe("Google tooling");
26
+ expect(parsed.runtimeMetadata?.namespace).toBe("wingman");
27
+ expect(parsed.runtimeMetadata?.requires.bins).toEqual([
28
+ "gog"
29
+ ]);
30
+ expect(parsed.runtimeMetadata?.install).toEqual([
31
+ {
32
+ id: "brew",
33
+ kind: "brew",
34
+ formula: "steipete/tap/gogcli",
35
+ bins: [
36
+ "gog"
37
+ ],
38
+ label: "Install gog (brew)"
39
+ }
40
+ ]);
41
+ });
42
+ it("prefers wingman over openclaw when both namespaces are present", ()=>{
43
+ const content = `---
44
+ name: dual
45
+ description: Dual namespace
46
+ metadata:
47
+ openclaw:
48
+ requires:
49
+ bins: ["oldbin"]
50
+ wingman:
51
+ requires:
52
+ bins: ["newbin"]
53
+ ---
54
+
55
+ # dual
56
+ `;
57
+ const parsed = parseSkillFrontmatter(content);
58
+ expect(parsed.runtimeMetadata?.namespace).toBe("wingman");
59
+ expect(parsed.runtimeMetadata?.requires.bins).toEqual([
60
+ "newbin"
61
+ ]);
62
+ });
63
+ it("supports openclaw namespace when wingman is absent", ()=>{
64
+ const content = `---
65
+ name: open
66
+ description: Openclaw namespace
67
+ metadata:
68
+ openclaw:
69
+ requires:
70
+ bins: ["gog"]
71
+ ---
72
+
73
+ # open
74
+ `;
75
+ const parsed = parseSkillFrontmatter(content);
76
+ expect(parsed.runtimeMetadata?.namespace).toBe("openclaw");
77
+ expect(parsed.runtimeMetadata?.requires.bins).toEqual([
78
+ "gog"
79
+ ]);
80
+ });
81
+ it("ignores unsupported namespaces like clawdbot", ()=>{
82
+ const content = `---
83
+ name: legacy
84
+ description: Legacy metadata
85
+ metadata:
86
+ clawdbot:
87
+ requires:
88
+ bins: ["gog"]
89
+ ---
90
+
91
+ # legacy
92
+ `;
93
+ const parsed = parseSkillFrontmatter(content);
94
+ expect(parsed.runtimeMetadata).toBeNull();
95
+ });
96
+ it("normalizes allowed tools from either key", ()=>{
97
+ const content = `---
98
+ name: ui-registry
99
+ description: UI helpers
100
+ allowedTools:
101
+ - ui_registry_list
102
+ - ui_present
103
+ ---
104
+
105
+ # ui
106
+ `;
107
+ const parsed = parseSkillFrontmatter(content);
108
+ expect(parsed.allowedTools).toEqual([
109
+ "ui_registry_list",
110
+ "ui_present"
111
+ ]);
112
+ });
113
+ });