@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
@@ -98,3 +98,366 @@ describe("SkillRepository clawhub provider", ()=>{
98
98
  expect(fetchMock).toHaveBeenCalledTimes(4);
99
99
  });
100
100
  });
101
+ describe("SkillRepository github provider", ()=>{
102
+ const originalFetch = globalThis.fetch;
103
+ afterEach(()=>{
104
+ globalThis.fetch = originalFetch;
105
+ vi.restoreAllMocks();
106
+ });
107
+ it("merges skills across repositories with later sources overriding earlier ones", async ()=>{
108
+ const encodeSkill = (name, description)=>Buffer.from(`---\nname: ${name}\ndescription: ${description}\n---\n`, "utf-8").toString("base64");
109
+ const fetchMock = vi.fn(async (input)=>{
110
+ const url = input.toString();
111
+ if (url.endsWith("/repos/example-org/community-skills/contents/skills")) return new Response(JSON.stringify([
112
+ {
113
+ name: "gog",
114
+ path: "skills/gog",
115
+ type: "dir",
116
+ url: "https://api.github.com/repos/example-org/community-skills/contents/skills/gog"
117
+ },
118
+ {
119
+ name: "alpha",
120
+ path: "skills/alpha",
121
+ type: "dir",
122
+ url: "https://api.github.com/repos/example-org/community-skills/contents/skills/alpha"
123
+ }
124
+ ]), {
125
+ status: 200
126
+ });
127
+ if (url.endsWith("/repos/example-team/custom-skills/contents/skills")) return new Response(JSON.stringify([
128
+ {
129
+ name: "alpha",
130
+ path: "skills/alpha",
131
+ type: "dir",
132
+ url: "https://api.github.com/repos/example-team/custom-skills/contents/skills/alpha"
133
+ },
134
+ {
135
+ name: "wingman-special",
136
+ path: "skills/wingman-special",
137
+ type: "dir",
138
+ url: "https://api.github.com/repos/example-team/custom-skills/contents/skills/wingman-special"
139
+ }
140
+ ]), {
141
+ status: 200
142
+ });
143
+ if (url.endsWith("/repos/example-org/community-skills/contents/skills/gog/SKILL.md")) return new Response(JSON.stringify({
144
+ type: "file",
145
+ content: encodeSkill("gog", "Community gog skill")
146
+ }), {
147
+ status: 200
148
+ });
149
+ if (url.endsWith("/repos/example-org/community-skills/contents/skills/alpha/SKILL.md")) return new Response(JSON.stringify({
150
+ type: "file",
151
+ content: encodeSkill("alpha", "Community alpha skill")
152
+ }), {
153
+ status: 200
154
+ });
155
+ if (url.endsWith("/repos/example-team/custom-skills/contents/skills/alpha/SKILL.md")) return new Response(JSON.stringify({
156
+ type: "file",
157
+ content: encodeSkill("alpha", "Custom alpha override")
158
+ }), {
159
+ status: 200
160
+ });
161
+ if (url.endsWith("/repos/example-team/custom-skills/contents/skills/wingman-special/SKILL.md")) return new Response(JSON.stringify({
162
+ type: "file",
163
+ content: encodeSkill("wingman-special", "Custom-only skill")
164
+ }), {
165
+ status: 200
166
+ });
167
+ return new Response("Not Found", {
168
+ status: 404
169
+ });
170
+ });
171
+ globalThis.fetch = fetchMock;
172
+ const repository = new SkillRepository({
173
+ provider: "github",
174
+ repositories: [
175
+ {
176
+ owner: "example-org",
177
+ name: "community-skills"
178
+ },
179
+ {
180
+ owner: "example-team",
181
+ name: "custom-skills"
182
+ }
183
+ ]
184
+ });
185
+ const skills = await repository.listAvailableSkills();
186
+ expect(skills).toEqual([
187
+ {
188
+ name: "gog",
189
+ description: "Community gog skill",
190
+ path: "skills/gog",
191
+ metadata: {
192
+ name: "gog",
193
+ description: "Community gog skill"
194
+ }
195
+ },
196
+ {
197
+ name: "alpha",
198
+ description: "Custom alpha override",
199
+ path: "skills/alpha",
200
+ metadata: {
201
+ name: "alpha",
202
+ description: "Custom alpha override"
203
+ }
204
+ },
205
+ {
206
+ name: "wingman-special",
207
+ description: "Custom-only skill",
208
+ path: "skills/wingman-special",
209
+ metadata: {
210
+ name: "wingman-special",
211
+ description: "Custom-only skill"
212
+ }
213
+ }
214
+ ]);
215
+ });
216
+ it("downloads a skill from the highest-priority matching repository", async ()=>{
217
+ const encodedSkill = Buffer.from("---\nname: alpha\ndescription: Custom alpha override\n---\n", "utf-8").toString("base64");
218
+ const encodedExample = Buffer.from("# Custom Example\n", "utf-8").toString("base64");
219
+ const fetchMock = vi.fn(async (input)=>{
220
+ const url = input.toString();
221
+ if (url.endsWith("/repos/example-team/custom-skills/contents/skills/alpha/SKILL.md")) return new Response(JSON.stringify({
222
+ type: "file",
223
+ content: encodedSkill,
224
+ encoding: "base64"
225
+ }), {
226
+ status: 200
227
+ });
228
+ if (url.endsWith("/repos/example-team/custom-skills/contents/skills/alpha")) return new Response(JSON.stringify([
229
+ {
230
+ type: "file",
231
+ name: "SKILL.md",
232
+ path: "skills/alpha/SKILL.md",
233
+ content: encodedSkill,
234
+ encoding: "base64"
235
+ },
236
+ {
237
+ type: "file",
238
+ name: "examples.md",
239
+ path: "skills/alpha/examples.md",
240
+ content: encodedExample,
241
+ encoding: "base64"
242
+ }
243
+ ]), {
244
+ status: 200
245
+ });
246
+ return new Response("Not Found", {
247
+ status: 404
248
+ });
249
+ });
250
+ globalThis.fetch = fetchMock;
251
+ const repository = new SkillRepository({
252
+ provider: "github",
253
+ repositories: [
254
+ {
255
+ owner: "example-org",
256
+ name: "community-skills"
257
+ },
258
+ {
259
+ owner: "example-team",
260
+ name: "custom-skills"
261
+ }
262
+ ]
263
+ });
264
+ const files = await repository.downloadSkill("alpha");
265
+ expect(files.size).toBe(2);
266
+ expect(files.get("SKILL.md")?.toString("utf-8")).toContain("Custom alpha override");
267
+ expect(files.get("examples.md")?.toString("utf-8")).toContain("Custom Example");
268
+ const requestedUrls = fetchMock.mock.calls.map((call)=>call[0].toString());
269
+ expect(requestedUrls.some((url)=>url.includes("/repos/example-org/community-skills/contents/skills/alpha"))).toBe(false);
270
+ });
271
+ it("uses legacy repositoryOwner/repositoryName when repositories are not provided", async ()=>{
272
+ const fetchMock = vi.fn(async (input)=>{
273
+ const url = input.toString();
274
+ if (url.endsWith("/repos/myorg/myskills/contents/skills")) return new Response(JSON.stringify([
275
+ {
276
+ name: "legacy-skill",
277
+ path: "skills/legacy-skill",
278
+ type: "dir",
279
+ url: "https://api.github.com/repos/myorg/myskills/contents/skills/legacy-skill"
280
+ }
281
+ ]), {
282
+ status: 200
283
+ });
284
+ if (url.endsWith("/repos/myorg/myskills/contents/skills/legacy-skill/SKILL.md")) return new Response(JSON.stringify({
285
+ type: "file",
286
+ content: Buffer.from("---\nname: legacy-skill\ndescription: Legacy source\n---\n", "utf-8").toString("base64")
287
+ }), {
288
+ status: 200
289
+ });
290
+ return new Response("Not Found", {
291
+ status: 404
292
+ });
293
+ });
294
+ globalThis.fetch = fetchMock;
295
+ const repository = new SkillRepository({
296
+ provider: "github",
297
+ repositoryOwner: "myorg",
298
+ repositoryName: "myskills"
299
+ });
300
+ const skills = await repository.listAvailableSkills();
301
+ expect(skills).toHaveLength(1);
302
+ expect(skills[0]?.name).toBe("legacy-skill");
303
+ });
304
+ it("fails clearly when github provider has no configured repositories", async ()=>{
305
+ const repository = new SkillRepository({
306
+ provider: "github"
307
+ });
308
+ await expect(repository.listAvailableSkills()).rejects.toThrow("No GitHub skill repositories configured");
309
+ });
310
+ });
311
+ describe("SkillRepository hybrid provider", ()=>{
312
+ const originalFetch = globalThis.fetch;
313
+ afterEach(()=>{
314
+ globalThis.fetch = originalFetch;
315
+ vi.restoreAllMocks();
316
+ });
317
+ it("merges ClawHub and GitHub skills, with GitHub overriding conflicts", async ()=>{
318
+ const encodeSkill = (name, description)=>Buffer.from(`---\nname: ${name}\ndescription: ${description}\n---\n`, "utf-8").toString("base64");
319
+ const fetchMock = vi.fn(async (input)=>{
320
+ const url = input.toString();
321
+ if ("https://clawhub.ai/api/v1/skills?sort=downloads&limit=100" === url) return new Response(JSON.stringify({
322
+ items: [
323
+ {
324
+ slug: "alpha",
325
+ summary: "ClawHub alpha skill"
326
+ },
327
+ {
328
+ slug: "weather",
329
+ summary: "ClawHub weather skill"
330
+ }
331
+ ],
332
+ nextCursor: null
333
+ }), {
334
+ status: 200
335
+ });
336
+ if (url.endsWith("/repos/example-team/custom-skills/contents/skills")) return new Response(JSON.stringify([
337
+ {
338
+ name: "alpha",
339
+ path: "skills/alpha",
340
+ type: "dir",
341
+ url: "https://api.github.com/repos/example-team/custom-skills/contents/skills/alpha"
342
+ },
343
+ {
344
+ name: "wingman-special",
345
+ path: "skills/wingman-special",
346
+ type: "dir",
347
+ url: "https://api.github.com/repos/example-team/custom-skills/contents/skills/wingman-special"
348
+ }
349
+ ]), {
350
+ status: 200
351
+ });
352
+ if (url.endsWith("/repos/example-team/custom-skills/contents/skills/alpha/SKILL.md")) return new Response(JSON.stringify({
353
+ type: "file",
354
+ content: encodeSkill("alpha", "GitHub alpha override")
355
+ }), {
356
+ status: 200
357
+ });
358
+ if (url.endsWith("/repos/example-team/custom-skills/contents/skills/wingman-special/SKILL.md")) return new Response(JSON.stringify({
359
+ type: "file",
360
+ content: encodeSkill("wingman-special", "GitHub only skill")
361
+ }), {
362
+ status: 200
363
+ });
364
+ return new Response("Not Found", {
365
+ status: 404
366
+ });
367
+ });
368
+ globalThis.fetch = fetchMock;
369
+ const repository = new SkillRepository({
370
+ provider: "hybrid",
371
+ repositories: [
372
+ {
373
+ owner: "example-team",
374
+ name: "custom-skills"
375
+ }
376
+ ],
377
+ clawhubBaseUrl: "https://clawhub.ai"
378
+ });
379
+ const skills = await repository.listAvailableSkills();
380
+ expect(skills).toEqual([
381
+ {
382
+ name: "weather",
383
+ description: "ClawHub weather skill",
384
+ path: "weather",
385
+ metadata: {
386
+ name: "weather",
387
+ description: "ClawHub weather skill"
388
+ }
389
+ },
390
+ {
391
+ name: "alpha",
392
+ description: "GitHub alpha override",
393
+ path: "skills/alpha",
394
+ metadata: {
395
+ name: "alpha",
396
+ description: "GitHub alpha override"
397
+ }
398
+ },
399
+ {
400
+ name: "wingman-special",
401
+ description: "GitHub only skill",
402
+ path: "skills/wingman-special",
403
+ metadata: {
404
+ name: "wingman-special",
405
+ description: "GitHub only skill"
406
+ }
407
+ }
408
+ ]);
409
+ });
410
+ it("falls back to ClawHub when a skill is missing from configured GitHub repos", async ()=>{
411
+ const fetchMock = vi.fn(async (input)=>{
412
+ const url = input.toString();
413
+ if (url.endsWith("/repos/example-team/custom-skills/contents/skills/gog/SKILL.md")) return new Response("Not Found", {
414
+ status: 404
415
+ });
416
+ if ("https://clawhub.ai/api/v1/skills/gog" === url) return new Response(JSON.stringify({
417
+ skill: {
418
+ slug: "gog",
419
+ summary: "Google workspace tooling"
420
+ },
421
+ latestVersion: {
422
+ version: "1.0.0"
423
+ }
424
+ }), {
425
+ status: 200
426
+ });
427
+ if ("https://clawhub.ai/api/v1/skills/gog/versions/1.0.0" === url) return new Response(JSON.stringify({
428
+ version: {
429
+ version: "1.0.0",
430
+ files: [
431
+ {
432
+ path: "SKILL.md"
433
+ }
434
+ ]
435
+ }
436
+ }), {
437
+ status: 200
438
+ });
439
+ if (url.includes("/api/v1/skills/gog/file?")) return new Response("---\nname: gog\ndescription: Test\n---\n", {
440
+ status: 200
441
+ });
442
+ return new Response("Not Found", {
443
+ status: 404
444
+ });
445
+ });
446
+ globalThis.fetch = fetchMock;
447
+ const repository = new SkillRepository({
448
+ provider: "hybrid",
449
+ repositories: [
450
+ {
451
+ owner: "example-team",
452
+ name: "custom-skills"
453
+ }
454
+ ],
455
+ clawhubBaseUrl: "https://clawhub.ai"
456
+ });
457
+ const metadata = await repository.getSkillMetadata("gog");
458
+ expect(metadata.name).toBe("gog");
459
+ expect(metadata.description).toContain("Google workspace tooling");
460
+ const files = await repository.downloadSkill("gog");
461
+ expect(files.has("SKILL.md")).toBe(true);
462
+ });
463
+ });
@@ -0,0 +1,183 @@
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 sms_cjs_namespaceObject = require("../gateway/http/sms.cjs");
8
+ const requireTempDir = (value)=>{
9
+ if (!value) throw new Error("temp dir not initialized");
10
+ return value;
11
+ };
12
+ (0, external_vitest_namespaceObject.describe)("sms policy api", ()=>{
13
+ let tempDir = null;
14
+ (0, external_vitest_namespaceObject.afterEach)(()=>{
15
+ if (!tempDir) return;
16
+ (0, external_node_fs_namespaceObject.rmSync)(tempDir, {
17
+ recursive: true,
18
+ force: true
19
+ });
20
+ tempDir = null;
21
+ });
22
+ (0, external_vitest_namespaceObject.it)("updates, fetches, and resets policy records", async ()=>{
23
+ tempDir = (0, external_node_fs_namespaceObject.mkdtempSync)((0, external_node_path_namespaceObject.join)((0, external_node_os_namespaceObject.tmpdir)(), "wingman-sms-api-"));
24
+ const store = (0, sms_cjs_namespaceObject.createSmsPolicyStateStore)(()=>requireTempDir(tempDir));
25
+ const target = encodeURIComponent("sms-macos:+15555550000");
26
+ const ctx = {};
27
+ const updateReq = new Request(`http://localhost/api/sms/policies/${target}`, {
28
+ method: "PUT",
29
+ headers: {
30
+ "Content-Type": "application/json"
31
+ },
32
+ body: JSON.stringify({
33
+ stopEnabled: true,
34
+ pauseForMs: 120000,
35
+ alertMode: "all"
36
+ })
37
+ });
38
+ const updateRes = await (0, sms_cjs_namespaceObject.handleSmsApi)(ctx, store, updateReq, new URL(updateReq.url));
39
+ (0, external_vitest_namespaceObject.expect)(updateRes?.status).toBe(200);
40
+ const updated = await updateRes?.json();
41
+ (0, external_vitest_namespaceObject.expect)(updated.paused).toBe(true);
42
+ (0, external_vitest_namespaceObject.expect)(updated.pausedUntil).toBeTypeOf("number");
43
+ (0, external_vitest_namespaceObject.expect)(updated.stopEnabled).toBe(true);
44
+ (0, external_vitest_namespaceObject.expect)(updated.alertMode).toBe("all");
45
+ const getRes = await (0, sms_cjs_namespaceObject.handleSmsApi)(ctx, store, new Request(`http://localhost/api/sms/policies/${target}`, {
46
+ method: "GET"
47
+ }), new URL(`http://localhost/api/sms/policies/${target}`));
48
+ (0, external_vitest_namespaceObject.expect)(getRes?.status).toBe(200);
49
+ const listRes = await (0, sms_cjs_namespaceObject.handleSmsApi)(ctx, store, new Request("http://localhost/api/sms/policies", {
50
+ method: "GET"
51
+ }), new URL("http://localhost/api/sms/policies"));
52
+ (0, external_vitest_namespaceObject.expect)(listRes?.status).toBe(200);
53
+ const listPayload = await listRes?.json();
54
+ (0, external_vitest_namespaceObject.expect)(listPayload.policies).toHaveLength(1);
55
+ const deleteRes = await (0, sms_cjs_namespaceObject.handleSmsApi)(ctx, store, new Request(`http://localhost/api/sms/policies/${target}`, {
56
+ method: "DELETE"
57
+ }), new URL(`http://localhost/api/sms/policies/${target}`));
58
+ (0, external_vitest_namespaceObject.expect)(deleteRes?.status).toBe(200);
59
+ const reset = await deleteRes?.json();
60
+ (0, external_vitest_namespaceObject.expect)(reset.paused).toBe(false);
61
+ (0, external_vitest_namespaceObject.expect)(reset.stopEnabled).toBe(false);
62
+ });
63
+ (0, external_vitest_namespaceObject.it)("applies control commands and leaves non-commands as pass-through text", async ()=>{
64
+ tempDir = (0, external_node_fs_namespaceObject.mkdtempSync)((0, external_node_path_namespaceObject.join)((0, external_node_os_namespaceObject.tmpdir)(), "wingman-sms-api-"));
65
+ const store = (0, sms_cjs_namespaceObject.createSmsPolicyStateStore)(()=>requireTempDir(tempDir));
66
+ const target = encodeURIComponent("sms-macos:+15555550000");
67
+ const ctx = {
68
+ router: {
69
+ selectAgent: ()=>"main",
70
+ buildSessionKey: ()=>"agent:main:sms-macos:dm:+15555550000"
71
+ }
72
+ };
73
+ const pauseReq = new Request(`http://localhost/api/sms/policies/${target}/command`, {
74
+ method: "POST",
75
+ headers: {
76
+ "Content-Type": "application/json"
77
+ },
78
+ body: JSON.stringify({
79
+ text: "PAUSE 2h",
80
+ nowMs: 10000
81
+ })
82
+ });
83
+ const pauseRes = await (0, sms_cjs_namespaceObject.handleSmsApi)(ctx, store, pauseReq, new URL(pauseReq.url));
84
+ (0, external_vitest_namespaceObject.expect)(pauseRes?.status).toBe(200);
85
+ const pausedPayload = await pauseRes?.json();
86
+ (0, external_vitest_namespaceObject.expect)(pausedPayload.handled).toBe(true);
87
+ (0, external_vitest_namespaceObject.expect)(pausedPayload.command?.name).toBe("pause");
88
+ (0, external_vitest_namespaceObject.expect)(pausedPayload.policy.paused).toBe(true);
89
+ const textReq = new Request(`http://localhost/api/sms/policies/${target}/command`, {
90
+ method: "POST",
91
+ headers: {
92
+ "Content-Type": "application/json"
93
+ },
94
+ body: JSON.stringify({
95
+ text: "deploy this now"
96
+ })
97
+ });
98
+ const textRes = await (0, sms_cjs_namespaceObject.handleSmsApi)(ctx, store, textReq, new URL(textReq.url));
99
+ (0, external_vitest_namespaceObject.expect)(textRes?.status).toBe(200);
100
+ const textPayload = await textRes?.json();
101
+ (0, external_vitest_namespaceObject.expect)(textPayload.handled).toBe(false);
102
+ (0, external_vitest_namespaceObject.expect)(textPayload.passThroughText).toBe("deploy this now");
103
+ });
104
+ (0, external_vitest_namespaceObject.it)("normalizes inbound messages into command, stopped, or agent results", async ()=>{
105
+ tempDir = (0, external_node_fs_namespaceObject.mkdtempSync)((0, external_node_path_namespaceObject.join)((0, external_node_os_namespaceObject.tmpdir)(), "wingman-sms-api-"));
106
+ const store = (0, sms_cjs_namespaceObject.createSmsPolicyStateStore)(()=>requireTempDir(tempDir));
107
+ const ctx = {
108
+ router: {
109
+ selectAgent: ()=>"main",
110
+ buildSessionKey: ()=>"agent:main:sms-macos:dm:+15555550000"
111
+ }
112
+ };
113
+ const commandReq = new Request("http://localhost/api/sms/messages", {
114
+ method: "POST",
115
+ headers: {
116
+ "Content-Type": "application/json"
117
+ },
118
+ body: JSON.stringify({
119
+ target: "sms-macos:+15555550000",
120
+ text: "HELP"
121
+ })
122
+ });
123
+ const commandRes = await (0, sms_cjs_namespaceObject.handleSmsApi)(ctx, store, commandReq, new URL(commandReq.url));
124
+ (0, external_vitest_namespaceObject.expect)(commandRes?.status).toBe(200);
125
+ const commandPayload = await commandRes?.json();
126
+ (0, external_vitest_namespaceObject.expect)(commandPayload.kind).toBe("command");
127
+ (0, external_vitest_namespaceObject.expect)(commandPayload.handled).toBe(true);
128
+ const stopReq = new Request("http://localhost/api/sms/messages", {
129
+ method: "POST",
130
+ headers: {
131
+ "Content-Type": "application/json"
132
+ },
133
+ body: JSON.stringify({
134
+ target: "sms-macos:+15555550000",
135
+ text: "STOP"
136
+ })
137
+ });
138
+ const stopRes = await (0, sms_cjs_namespaceObject.handleSmsApi)(ctx, store, stopReq, new URL(stopReq.url));
139
+ (0, external_vitest_namespaceObject.expect)(stopRes?.status).toBe(200);
140
+ const blockedReq = new Request("http://localhost/api/sms/messages", {
141
+ method: "POST",
142
+ headers: {
143
+ "Content-Type": "application/json"
144
+ },
145
+ body: JSON.stringify({
146
+ target: "sms-macos:+15555550000",
147
+ text: "summarize my build failures"
148
+ })
149
+ });
150
+ const blockedRes = await (0, sms_cjs_namespaceObject.handleSmsApi)(ctx, store, blockedReq, new URL(blockedReq.url));
151
+ (0, external_vitest_namespaceObject.expect)(blockedRes?.status).toBe(200);
152
+ const blockedPayload = await blockedRes?.json();
153
+ (0, external_vitest_namespaceObject.expect)(blockedPayload.kind).toBe("stopped");
154
+ (0, external_vitest_namespaceObject.expect)(blockedPayload.responseText).toContain("stopped");
155
+ store.upsert("sms-macos:+15555550000", {
156
+ stopEnabled: false
157
+ });
158
+ const agentReq = new Request("http://localhost/api/sms/messages", {
159
+ method: "POST",
160
+ headers: {
161
+ "Content-Type": "application/json"
162
+ },
163
+ body: JSON.stringify({
164
+ target: "sms-macos:+15555550000",
165
+ text: "summarize my build failures",
166
+ queueIfBusy: true
167
+ })
168
+ });
169
+ const agentRes = await (0, sms_cjs_namespaceObject.handleSmsApi)(ctx, store, agentReq, new URL(agentReq.url));
170
+ (0, external_vitest_namespaceObject.expect)(agentRes?.status).toBe(200);
171
+ const agentPayload = await agentRes?.json();
172
+ (0, external_vitest_namespaceObject.expect)(agentPayload.kind).toBe("agent");
173
+ (0, external_vitest_namespaceObject.expect)(agentPayload.request.agentId).toBe("main");
174
+ (0, external_vitest_namespaceObject.expect)(agentPayload.request.content).toBe("summarize my build failures");
175
+ (0, external_vitest_namespaceObject.expect)(agentPayload.request.sessionKey).toBe("agent:main:sms-macos:dm:+15555550000");
176
+ (0, external_vitest_namespaceObject.expect)(agentPayload.request.routing?.channel).toBe("sms-macos");
177
+ (0, external_vitest_namespaceObject.expect)(agentPayload.request.queueIfBusy).toBe(true);
178
+ });
179
+ });
180
+ for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
181
+ Object.defineProperty(exports, '__esModule', {
182
+ value: true
183
+ });
@@ -0,0 +1 @@
1
+ export {};