@wingman-ai/gateway 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/agent/config/mcpClientManager.cjs +104 -1
- package/dist/agent/config/mcpClientManager.d.ts +30 -0
- package/dist/agent/config/mcpClientManager.js +104 -1
- package/dist/agent/config/modelFactory.cjs +10 -0
- package/dist/agent/config/modelFactory.js +10 -0
- package/dist/agent/config/xaiImageModel.cjs +242 -0
- package/dist/agent/config/xaiImageModel.d.ts +33 -0
- package/dist/agent/config/xaiImageModel.js +202 -0
- package/dist/agent/tests/mcpClientManager.test.cjs +116 -0
- package/dist/agent/tests/mcpClientManager.test.js +117 -1
- package/dist/agent/tests/mcpResourceTools.test.cjs +101 -0
- package/dist/agent/tests/mcpResourceTools.test.d.ts +1 -0
- package/dist/agent/tests/mcpResourceTools.test.js +95 -0
- package/dist/agent/tests/modelFactory.test.cjs +16 -2
- package/dist/agent/tests/modelFactory.test.js +16 -2
- package/dist/agent/tests/xaiImageModel.test.cjs +194 -0
- package/dist/agent/tests/xaiImageModel.test.d.ts +1 -0
- package/dist/agent/tests/xaiImageModel.test.js +188 -0
- package/dist/agent/tools/mcp_resources.cjs +111 -0
- package/dist/agent/tools/mcp_resources.d.ts +3 -0
- package/dist/agent/tools/mcp_resources.js +77 -0
- package/dist/bench/adapters/commandAdapter.cjs +93 -0
- package/dist/bench/adapters/commandAdapter.d.ts +6 -0
- package/dist/bench/adapters/commandAdapter.js +59 -0
- package/dist/bench/adapters/helpers.cjs +170 -0
- package/dist/bench/adapters/helpers.d.ts +7 -0
- package/dist/bench/adapters/helpers.js +133 -0
- package/dist/bench/adapters/index.cjs +41 -0
- package/dist/bench/adapters/index.d.ts +2 -0
- package/dist/bench/adapters/index.js +7 -0
- package/dist/bench/adapters/wingmanCliAdapter.cjs +100 -0
- package/dist/bench/adapters/wingmanCliAdapter.d.ts +6 -0
- package/dist/bench/adapters/wingmanCliAdapter.js +66 -0
- package/dist/bench/cleanup.cjs +122 -0
- package/dist/bench/cleanup.d.ts +9 -0
- package/dist/bench/cleanup.js +85 -0
- package/dist/bench/config.cjs +190 -0
- package/dist/bench/config.d.ts +2 -0
- package/dist/bench/config.js +156 -0
- package/dist/bench/index.cjs +43 -0
- package/dist/bench/index.d.ts +3 -0
- package/dist/bench/index.js +3 -0
- package/dist/bench/official.cjs +616 -0
- package/dist/bench/official.d.ts +80 -0
- package/dist/bench/official.js +546 -0
- package/dist/bench/officialCli.cjs +204 -0
- package/dist/bench/officialCli.d.ts +5 -0
- package/dist/bench/officialCli.js +170 -0
- package/dist/bench/process.cjs +78 -0
- package/dist/bench/process.d.ts +14 -0
- package/dist/bench/process.js +44 -0
- package/dist/bench/runner.cjs +237 -0
- package/dist/bench/runner.d.ts +7 -0
- package/dist/bench/runner.js +197 -0
- package/dist/bench/scoring.cjs +171 -0
- package/dist/bench/scoring.d.ts +9 -0
- package/dist/bench/scoring.js +137 -0
- package/dist/bench/types.cjs +18 -0
- package/dist/bench/types.d.ts +200 -0
- package/dist/bench/types.js +0 -0
- package/dist/bench/validator.cjs +92 -0
- package/dist/bench/validator.d.ts +2 -0
- package/dist/bench/validator.js +58 -0
- package/dist/cli/commands/init.cjs +135 -1
- package/dist/cli/commands/init.js +136 -2
- package/dist/cli/commands/skill.cjs +7 -3
- package/dist/cli/commands/skill.js +7 -3
- package/dist/cli/config/loader.cjs +7 -3
- package/dist/cli/config/loader.js +7 -3
- package/dist/cli/config/schema.cjs +63 -10
- package/dist/cli/config/schema.d.ts +64 -4
- package/dist/cli/config/schema.js +59 -9
- package/dist/cli/config/warnings.cjs +119 -51
- package/dist/cli/config/warnings.js +119 -51
- package/dist/cli/core/agentInvoker.cjs +58 -13
- package/dist/cli/core/agentInvoker.d.ts +1 -0
- package/dist/cli/core/agentInvoker.js +58 -13
- package/dist/cli/core/imagePersistence.cjs +17 -1
- package/dist/cli/core/imagePersistence.d.ts +2 -0
- package/dist/cli/core/imagePersistence.js +13 -3
- package/dist/cli/core/sessionManager.cjs +2 -0
- package/dist/cli/core/sessionManager.js +3 -1
- package/dist/cli/services/skillRepository.cjs +155 -69
- package/dist/cli/services/skillRepository.d.ts +7 -2
- package/dist/cli/services/skillRepository.js +155 -69
- package/dist/cli/services/skillService.cjs +93 -26
- package/dist/cli/services/skillService.d.ts +7 -0
- package/dist/cli/services/skillService.js +96 -29
- package/dist/cli/types/skill.d.ts +8 -3
- package/dist/cli/types.d.ts +18 -0
- package/dist/gateway/adapters/teams.cjs +419 -0
- package/dist/gateway/adapters/teams.d.ts +47 -0
- package/dist/gateway/adapters/teams.js +361 -0
- package/dist/gateway/http/sms.cjs +286 -0
- package/dist/gateway/http/sms.d.ts +4 -0
- package/dist/gateway/http/sms.js +249 -0
- package/dist/gateway/server.cjs +54 -3
- package/dist/gateway/server.d.ts +2 -0
- package/dist/gateway/server.js +54 -3
- package/dist/gateway/sms/commands.cjs +116 -0
- package/dist/gateway/sms/commands.d.ts +15 -0
- package/dist/gateway/sms/commands.js +79 -0
- package/dist/gateway/sms/control.cjs +118 -0
- package/dist/gateway/sms/control.d.ts +18 -0
- package/dist/gateway/sms/control.js +84 -0
- package/dist/gateway/sms/policyStore.cjs +198 -0
- package/dist/gateway/sms/policyStore.d.ts +37 -0
- package/dist/gateway/sms/policyStore.js +161 -0
- package/dist/providers/registry.cjs +1 -0
- package/dist/providers/registry.js +1 -0
- package/dist/skills/activation.cjs +92 -0
- package/dist/skills/activation.d.ts +12 -0
- package/dist/skills/activation.js +58 -0
- package/dist/skills/bin-requirements.cjs +63 -0
- package/dist/skills/bin-requirements.d.ts +3 -0
- package/dist/skills/bin-requirements.js +26 -0
- package/dist/skills/metadata.cjs +141 -0
- package/dist/skills/metadata.d.ts +29 -0
- package/dist/skills/metadata.js +104 -0
- package/dist/skills/overlay.cjs +75 -0
- package/dist/skills/overlay.d.ts +2 -0
- package/dist/skills/overlay.js +38 -0
- package/dist/tests/cli-config-loader.test.cjs +7 -3
- package/dist/tests/cli-config-loader.test.js +7 -3
- package/dist/tests/cli-config-warnings.test.cjs +41 -0
- package/dist/tests/cli-config-warnings.test.js +41 -0
- package/dist/tests/cli-init.test.cjs +86 -26
- package/dist/tests/cli-init.test.js +86 -26
- package/dist/tests/config-json-schema.test.cjs +12 -0
- package/dist/tests/config-json-schema.test.js +12 -0
- package/dist/tests/gateway-http-security.test.cjs +21 -0
- package/dist/tests/gateway-http-security.test.js +21 -0
- package/dist/tests/gateway-origin-policy.test.cjs +22 -0
- package/dist/tests/gateway-origin-policy.test.js +22 -0
- package/dist/tests/gateway.test.cjs +57 -0
- package/dist/tests/gateway.test.js +57 -0
- package/dist/tests/imagePersistence.test.cjs +26 -0
- package/dist/tests/imagePersistence.test.js +27 -1
- package/dist/tests/run-terminal-bench-official-script.test.cjs +61 -0
- package/dist/tests/run-terminal-bench-official-script.test.d.ts +1 -0
- package/dist/tests/run-terminal-bench-official-script.test.js +55 -0
- package/dist/tests/sessions-api.test.cjs +69 -1
- package/dist/tests/sessions-api.test.js +70 -2
- package/dist/tests/skill-activation.test.cjs +86 -0
- package/dist/tests/skill-activation.test.d.ts +1 -0
- package/dist/tests/skill-activation.test.js +80 -0
- package/dist/tests/skill-metadata.test.cjs +119 -0
- package/dist/tests/skill-metadata.test.d.ts +1 -0
- package/dist/tests/skill-metadata.test.js +113 -0
- package/dist/tests/skill-repository.test.cjs +363 -0
- package/dist/tests/skill-repository.test.js +363 -0
- package/dist/tests/sms-api.test.cjs +183 -0
- package/dist/tests/sms-api.test.d.ts +1 -0
- package/dist/tests/sms-api.test.js +177 -0
- package/dist/tests/sms-commands.test.cjs +90 -0
- package/dist/tests/sms-commands.test.d.ts +1 -0
- package/dist/tests/sms-commands.test.js +84 -0
- package/dist/tests/sms-policy-store.test.cjs +69 -0
- package/dist/tests/sms-policy-store.test.d.ts +1 -0
- package/dist/tests/sms-policy-store.test.js +63 -0
- package/dist/tests/teams-adapter.test.cjs +58 -0
- package/dist/tests/teams-adapter.test.d.ts +1 -0
- package/dist/tests/teams-adapter.test.js +52 -0
- package/dist/tests/terminal-bench-adapters-helpers.test.cjs +64 -0
- package/dist/tests/terminal-bench-adapters-helpers.test.d.ts +1 -0
- package/dist/tests/terminal-bench-adapters-helpers.test.js +58 -0
- package/dist/tests/terminal-bench-cleanup.test.cjs +93 -0
- package/dist/tests/terminal-bench-cleanup.test.d.ts +1 -0
- package/dist/tests/terminal-bench-cleanup.test.js +87 -0
- package/dist/tests/terminal-bench-config.test.cjs +62 -0
- package/dist/tests/terminal-bench-config.test.d.ts +1 -0
- package/dist/tests/terminal-bench-config.test.js +56 -0
- package/dist/tests/terminal-bench-official.test.cjs +194 -0
- package/dist/tests/terminal-bench-official.test.d.ts +1 -0
- package/dist/tests/terminal-bench-official.test.js +188 -0
- package/dist/tests/terminal-bench-runner.test.cjs +82 -0
- package/dist/tests/terminal-bench-runner.test.d.ts +1 -0
- package/dist/tests/terminal-bench-runner.test.js +76 -0
- package/dist/tests/terminal-bench-scoring.test.cjs +128 -0
- package/dist/tests/terminal-bench-scoring.test.d.ts +1 -0
- package/dist/tests/terminal-bench-scoring.test.js +122 -0
- package/dist/tools/mcp-fal-ai.cjs +1 -1
- package/dist/tools/mcp-fal-ai.js +1 -1
- package/dist/webui/assets/index-Cyg_Hs57.css +11 -0
- package/dist/webui/assets/{index-BMekSELC.js → index-DZXLLjaA.js} +109 -109
- package/dist/webui/index.html +2 -2
- package/package.json +14 -5
- package/skills/gog/SKILL.md +1 -1
- package/skills/weather/SKILL.md +1 -1
- package/templates/agents/game-dev/agent.md +122 -63
- package/templates/agents/game-dev/art-director.md +106 -0
- package/templates/agents/game-dev/game-designer.md +87 -0
- package/templates/agents/game-dev/scene-engineer.md +474 -0
- package/dist/webui/assets/index-Cwkg4DKj.css +0 -11
- package/skills/ui-registry/SKILL.md +0 -35
- package/templates/agents/game-dev/art-generation.md +0 -38
- package/templates/agents/game-dev/asset-refinement.md +0 -17
- package/templates/agents/game-dev/planning-idea.md +0 -17
- package/templates/agents/game-dev/ui-specialist.md +0 -17
|
@@ -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 {};
|