ruflo 3.6.12 → 3.6.13
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/package.json +4 -1
- package/src/ruvocal/.claude-flow/data/pending-insights.jsonl +25 -0
- package/src/ruvocal/.claude-flow/neural/stats.json +6 -0
- package/src/ruvocal/.dockerignore +5 -1
- package/src/ruvocal/.gcloudignore +18 -0
- package/src/ruvocal/README.md +107 -133
- package/src/ruvocal/cloudbuild.yaml +68 -0
- package/src/ruvocal/config/branding.env.example +19 -0
- package/src/ruvocal/mcp-bridge/index.js +15 -1
- package/src/ruvocal/src/lib/components/FoundationBackground.svelte +242 -0
- package/src/ruvocal/src/lib/components/NavMenu.svelte +18 -0
- package/src/ruvocal/src/lib/components/RufloHelpModal.svelte +411 -0
- package/src/ruvocal/src/lib/components/chat/ChatWindow.svelte +122 -4
- package/src/ruvocal/src/lib/components/wasm/GalleryPanel.svelte +357 -0
- package/src/ruvocal/src/lib/constants/mcpExamples.ts +56 -77
- package/src/ruvocal/src/lib/constants/routerExamples.ts +51 -127
- package/src/ruvocal/src/lib/constants/rvagentPresets.ts +206 -0
- package/src/ruvocal/src/lib/server/textGeneration/mcp/wasmTools.test.ts +633 -0
- package/src/ruvocal/src/lib/stores/mcpServers.ts +195 -6
- package/src/ruvocal/src/lib/stores/wasmMcp.ts +472 -0
- package/src/ruvocal/src/lib/types/Settings.ts +7 -0
- package/src/ruvocal/src/lib/types/Tool.ts +4 -1
- package/src/ruvocal/src/lib/wasm/idb.ts +438 -0
- package/src/ruvocal/src/lib/wasm/index.ts +1213 -0
- package/src/ruvocal/src/lib/wasm/tests/wasm-capabilities.test.ts +565 -0
- package/src/ruvocal/src/lib/wasm/wasm.worker.ts +332 -0
- package/src/ruvocal/src/lib/wasm/workerClient.ts +166 -0
- package/src/ruvocal/static/wasm/rvagent_wasm.js +1539 -0
- package/src/ruvocal/static/wasm/rvagent_wasm_bg.wasm +0 -0
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WASM MCP Server Capability Tests
|
|
3
|
+
* Tests all WASM capabilities: MCP server, gallery, RVF builder, IndexedDB persistence
|
|
4
|
+
*
|
|
5
|
+
* Run with: npx vitest run src/lib/wasm/tests/wasm-capabilities.test.ts
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, beforeAll, afterAll, vi } from "vitest";
|
|
9
|
+
|
|
10
|
+
// Mock browser environment
|
|
11
|
+
vi.mock("$app/environment", () => ({
|
|
12
|
+
browser: true,
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
// Mock IndexedDB for Node environment
|
|
16
|
+
const mockIDB = {
|
|
17
|
+
files: new Map<string, { path: string; content: string; createdAt: number; updatedAt: number }>(),
|
|
18
|
+
settings: new Map<string, unknown>(),
|
|
19
|
+
rvfContainers: new Map<string, { id: string; name: string; data: Uint8Array }>(),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
vi.mock("$lib/wasm/idb", () => ({
|
|
23
|
+
writeFile: vi.fn(async (path: string, content: string) => {
|
|
24
|
+
const now = Date.now();
|
|
25
|
+
mockIDB.files.set(path, { path, content, createdAt: now, updatedAt: now });
|
|
26
|
+
}),
|
|
27
|
+
readFile: vi.fn(async (path: string) => {
|
|
28
|
+
return mockIDB.files.get(path)?.content ?? null;
|
|
29
|
+
}),
|
|
30
|
+
deleteFile: vi.fn(async (path: string) => {
|
|
31
|
+
mockIDB.files.delete(path);
|
|
32
|
+
}),
|
|
33
|
+
listFiles: vi.fn(async () => {
|
|
34
|
+
return Array.from(mockIDB.files.values());
|
|
35
|
+
}),
|
|
36
|
+
clearFiles: vi.fn(async () => {
|
|
37
|
+
mockIDB.files.clear();
|
|
38
|
+
}),
|
|
39
|
+
getSetting: vi.fn(async <T>(key: string): Promise<T | null> => {
|
|
40
|
+
return (mockIDB.settings.get(key) as T) ?? null;
|
|
41
|
+
}),
|
|
42
|
+
setSetting: vi.fn(async <T>(key: string, value: T) => {
|
|
43
|
+
mockIDB.settings.set(key, value);
|
|
44
|
+
}),
|
|
45
|
+
saveRvfContainer: vi.fn(async (id: string, name: string, data: Uint8Array) => {
|
|
46
|
+
mockIDB.rvfContainers.set(id, { id, name, data });
|
|
47
|
+
}),
|
|
48
|
+
loadRvfContainer: vi.fn(async (id: string) => {
|
|
49
|
+
return mockIDB.rvfContainers.get(id) ?? null;
|
|
50
|
+
}),
|
|
51
|
+
listRvfContainers: vi.fn(async () => {
|
|
52
|
+
return Array.from(mockIDB.rvfContainers.values());
|
|
53
|
+
}),
|
|
54
|
+
deleteRvfContainer: vi.fn(async (id: string) => {
|
|
55
|
+
mockIDB.rvfContainers.delete(id);
|
|
56
|
+
}),
|
|
57
|
+
openDatabase: vi.fn(async () => ({})),
|
|
58
|
+
closeDatabase: vi.fn(() => {}),
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
describe("WASM MCP Server Capabilities", () => {
|
|
62
|
+
describe("Type Definitions", () => {
|
|
63
|
+
it("should export correct GalleryTemplate interface", async () => {
|
|
64
|
+
const template = {
|
|
65
|
+
id: "test-template",
|
|
66
|
+
name: "Test Template",
|
|
67
|
+
description: "A test template",
|
|
68
|
+
category: "development",
|
|
69
|
+
version: "1.0.0",
|
|
70
|
+
author: "test",
|
|
71
|
+
tags: ["test", "development"],
|
|
72
|
+
builtin: true,
|
|
73
|
+
tools: [],
|
|
74
|
+
prompts: [],
|
|
75
|
+
skills: [],
|
|
76
|
+
mcp_tools: [],
|
|
77
|
+
capabilities: [],
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
expect(template).toHaveProperty("id");
|
|
81
|
+
expect(template).toHaveProperty("name");
|
|
82
|
+
expect(template).toHaveProperty("category");
|
|
83
|
+
expect(template).toHaveProperty("builtin");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("should export correct SearchResult interface", () => {
|
|
87
|
+
const result = {
|
|
88
|
+
id: "test-id",
|
|
89
|
+
name: "Test",
|
|
90
|
+
description: "Test description",
|
|
91
|
+
category: "testing",
|
|
92
|
+
tags: ["test"],
|
|
93
|
+
relevance: 0.95,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
expect(result.relevance).toBeGreaterThanOrEqual(0);
|
|
97
|
+
expect(result.relevance).toBeLessThanOrEqual(1);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("should export correct MCPTool interface", () => {
|
|
101
|
+
const tool = {
|
|
102
|
+
name: "read_file",
|
|
103
|
+
description: "Read a file from the virtual filesystem",
|
|
104
|
+
inputSchema: {
|
|
105
|
+
type: "object",
|
|
106
|
+
properties: {
|
|
107
|
+
path: { type: "string", description: "File path to read" },
|
|
108
|
+
},
|
|
109
|
+
required: ["path"],
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
expect(tool).toHaveProperty("name");
|
|
114
|
+
expect(tool).toHaveProperty("inputSchema");
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe("IndexedDB Persistence Layer", () => {
|
|
119
|
+
beforeAll(() => {
|
|
120
|
+
mockIDB.files.clear();
|
|
121
|
+
mockIDB.settings.clear();
|
|
122
|
+
mockIDB.rvfContainers.clear();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("should write and read files", async () => {
|
|
126
|
+
const { writeFile, readFile } = await import("$lib/wasm/idb");
|
|
127
|
+
|
|
128
|
+
await writeFile("/test/hello.txt", "Hello, World!");
|
|
129
|
+
const content = await readFile("/test/hello.txt");
|
|
130
|
+
|
|
131
|
+
expect(content).toBe("Hello, World!");
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("should list all files", async () => {
|
|
135
|
+
const { writeFile, listFiles } = await import("$lib/wasm/idb");
|
|
136
|
+
|
|
137
|
+
await writeFile("/test/file1.txt", "content1");
|
|
138
|
+
await writeFile("/test/file2.txt", "content2");
|
|
139
|
+
|
|
140
|
+
const files = await listFiles();
|
|
141
|
+
expect(files.length).toBeGreaterThanOrEqual(2);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("should delete files", async () => {
|
|
145
|
+
const { writeFile, readFile, deleteFile } = await import("$lib/wasm/idb");
|
|
146
|
+
|
|
147
|
+
await writeFile("/test/to-delete.txt", "delete me");
|
|
148
|
+
await deleteFile("/test/to-delete.txt");
|
|
149
|
+
const content = await readFile("/test/to-delete.txt");
|
|
150
|
+
|
|
151
|
+
expect(content).toBeNull();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should save and load settings", async () => {
|
|
155
|
+
const { setSetting, getSetting } = await import("$lib/wasm/idb");
|
|
156
|
+
|
|
157
|
+
await setSetting("testKey", { value: 42 });
|
|
158
|
+
const setting = await getSetting<{ value: number }>("testKey");
|
|
159
|
+
|
|
160
|
+
expect(setting).toEqual({ value: 42 });
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("should save and load RVF containers", async () => {
|
|
164
|
+
const { saveRvfContainer, loadRvfContainer } = await import("$lib/wasm/idb");
|
|
165
|
+
|
|
166
|
+
const testData = new Uint8Array([0x52, 0x56, 0x46, 0x00]); // "RVF\0"
|
|
167
|
+
await saveRvfContainer("test-rvf", "Test Container", testData);
|
|
168
|
+
const container = await loadRvfContainer("test-rvf");
|
|
169
|
+
|
|
170
|
+
expect(container).not.toBeNull();
|
|
171
|
+
expect(container?.name).toBe("Test Container");
|
|
172
|
+
expect(container?.data).toEqual(testData);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("should list RVF containers", async () => {
|
|
176
|
+
const { listRvfContainers } = await import("$lib/wasm/idb");
|
|
177
|
+
|
|
178
|
+
const containers = await listRvfContainers();
|
|
179
|
+
expect(containers.length).toBeGreaterThanOrEqual(1);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
describe("MCP Server Protocol", () => {
|
|
184
|
+
it("should validate JSON-RPC request format", () => {
|
|
185
|
+
const request = {
|
|
186
|
+
jsonrpc: "2.0",
|
|
187
|
+
id: 1,
|
|
188
|
+
method: "tools/list",
|
|
189
|
+
params: {},
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
expect(request.jsonrpc).toBe("2.0");
|
|
193
|
+
expect(typeof request.id).toBe("number");
|
|
194
|
+
expect(request.method).toBe("tools/list");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("should validate JSON-RPC response format", () => {
|
|
198
|
+
const successResponse = {
|
|
199
|
+
jsonrpc: "2.0",
|
|
200
|
+
id: 1,
|
|
201
|
+
result: { tools: [] },
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const errorResponse = {
|
|
205
|
+
jsonrpc: "2.0",
|
|
206
|
+
id: 2,
|
|
207
|
+
error: { code: -32600, message: "Invalid Request" },
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
expect(successResponse.result).toBeDefined();
|
|
211
|
+
expect(errorResponse.error.code).toBe(-32600);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("should define expected MCP methods", () => {
|
|
215
|
+
const expectedMethods = [
|
|
216
|
+
"initialize",
|
|
217
|
+
"tools/list",
|
|
218
|
+
"tools/call",
|
|
219
|
+
"prompts/list",
|
|
220
|
+
"prompts/get",
|
|
221
|
+
"resources/list",
|
|
222
|
+
"resources/read",
|
|
223
|
+
"gallery/list",
|
|
224
|
+
"gallery/load",
|
|
225
|
+
"gallery/search",
|
|
226
|
+
];
|
|
227
|
+
|
|
228
|
+
expectedMethods.forEach((method) => {
|
|
229
|
+
expect(typeof method).toBe("string");
|
|
230
|
+
expect(method.length).toBeGreaterThan(0);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
describe("Gallery Template Structure", () => {
|
|
236
|
+
it("should define valid template categories", () => {
|
|
237
|
+
const validCategories = [
|
|
238
|
+
"development",
|
|
239
|
+
"research",
|
|
240
|
+
"testing",
|
|
241
|
+
"security",
|
|
242
|
+
"orchestration",
|
|
243
|
+
"documentation",
|
|
244
|
+
"devops",
|
|
245
|
+
"custom",
|
|
246
|
+
];
|
|
247
|
+
|
|
248
|
+
validCategories.forEach((category) => {
|
|
249
|
+
expect(typeof category).toBe("string");
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it("should validate tool definition structure", () => {
|
|
254
|
+
const tool = {
|
|
255
|
+
name: "write_file",
|
|
256
|
+
description: "Write content to a file",
|
|
257
|
+
parameters: {
|
|
258
|
+
type: "object",
|
|
259
|
+
properties: {
|
|
260
|
+
path: { type: "string" },
|
|
261
|
+
content: { type: "string" },
|
|
262
|
+
},
|
|
263
|
+
required: ["path", "content"],
|
|
264
|
+
},
|
|
265
|
+
returns: "boolean",
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
expect(tool.parameters.type).toBe("object");
|
|
269
|
+
expect(tool.parameters.required).toContain("path");
|
|
270
|
+
expect(tool.parameters.required).toContain("content");
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("should validate prompt definition structure", () => {
|
|
274
|
+
const prompt = {
|
|
275
|
+
name: "code-review",
|
|
276
|
+
system_prompt: "You are a senior code reviewer...",
|
|
277
|
+
version: "1.0.0",
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
expect(prompt.name).toBeTruthy();
|
|
281
|
+
expect(prompt.system_prompt.length).toBeGreaterThan(0);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("should validate skill definition structure", () => {
|
|
285
|
+
const skill = {
|
|
286
|
+
name: "git-commit",
|
|
287
|
+
description: "Create a git commit with conventional format",
|
|
288
|
+
trigger: "/commit",
|
|
289
|
+
content: "When the user types /commit...",
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
expect(skill.trigger).toMatch(/^\//);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it("should validate orchestrator configuration", () => {
|
|
296
|
+
const orchestrator = {
|
|
297
|
+
topology: "hierarchical",
|
|
298
|
+
agents: [
|
|
299
|
+
{ id: "coordinator", agent_type: "planner", prompt_ref: "coordinator" },
|
|
300
|
+
{ id: "coder", agent_type: "coder", prompt_ref: "coder" },
|
|
301
|
+
{ id: "reviewer", agent_type: "reviewer", prompt_ref: "reviewer" },
|
|
302
|
+
],
|
|
303
|
+
connections: [
|
|
304
|
+
["coordinator", "coder"],
|
|
305
|
+
["coordinator", "reviewer"],
|
|
306
|
+
["coder", "reviewer"],
|
|
307
|
+
],
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
expect(orchestrator.topology).toBe("hierarchical");
|
|
311
|
+
expect(orchestrator.agents.length).toBe(3);
|
|
312
|
+
expect(orchestrator.connections.length).toBe(3);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
describe("RVF Container Format", () => {
|
|
317
|
+
it("should define RVF magic bytes", () => {
|
|
318
|
+
const RVF_MAGIC = new Uint8Array([0x52, 0x56, 0x46, 0x00]); // "RVF\0"
|
|
319
|
+
expect(RVF_MAGIC[0]).toBe(0x52); // 'R'
|
|
320
|
+
expect(RVF_MAGIC[1]).toBe(0x56); // 'V'
|
|
321
|
+
expect(RVF_MAGIC[2]).toBe(0x46); // 'F'
|
|
322
|
+
expect(RVF_MAGIC[3]).toBe(0x00); // null terminator
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it("should validate RVF version format", () => {
|
|
326
|
+
const versions = ["1.0.0", "1.1.0", "2.0.0"];
|
|
327
|
+
const versionRegex = /^\d+\.\d+\.\d+$/;
|
|
328
|
+
|
|
329
|
+
versions.forEach((version) => {
|
|
330
|
+
expect(version).toMatch(versionRegex);
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it("should define RVF section types", () => {
|
|
335
|
+
const sectionTypes = {
|
|
336
|
+
METADATA: 0x01,
|
|
337
|
+
TOOLS: 0x02,
|
|
338
|
+
PROMPTS: 0x03,
|
|
339
|
+
SKILLS: 0x04,
|
|
340
|
+
MCP_TOOLS: 0x05,
|
|
341
|
+
CAPABILITIES: 0x06,
|
|
342
|
+
ORCHESTRATOR: 0x07,
|
|
343
|
+
CHECKSUM: 0xff,
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
expect(Object.keys(sectionTypes).length).toBe(8);
|
|
347
|
+
expect(sectionTypes.METADATA).toBe(0x01);
|
|
348
|
+
expect(sectionTypes.CHECKSUM).toBe(0xff);
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
describe("MCP Server Type Extension", () => {
|
|
353
|
+
it("should support wasm server type", () => {
|
|
354
|
+
type ServerType = "base" | "custom" | "wasm";
|
|
355
|
+
|
|
356
|
+
const serverTypes: ServerType[] = ["base", "custom", "wasm"];
|
|
357
|
+
expect(serverTypes).toContain("wasm");
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it("should define WASM server properties", () => {
|
|
361
|
+
const wasmServer = {
|
|
362
|
+
id: "wasm-rvagent",
|
|
363
|
+
name: "RVAgent Local (WASM)",
|
|
364
|
+
url: "wasm://local",
|
|
365
|
+
type: "wasm" as const,
|
|
366
|
+
status: "connected" as const,
|
|
367
|
+
isLocked: false,
|
|
368
|
+
tools: [],
|
|
369
|
+
wasmTemplateId: "development-agent",
|
|
370
|
+
wasmTemplateName: "Development Agent",
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
expect(wasmServer.type).toBe("wasm");
|
|
374
|
+
expect(wasmServer.url).toBe("wasm://local");
|
|
375
|
+
expect(wasmServer.wasmTemplateId).toBeDefined();
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
describe("Browser Integration", () => {
|
|
380
|
+
it("should detect browser environment", async () => {
|
|
381
|
+
const { browser } = await import("$app/environment");
|
|
382
|
+
expect(browser).toBe(true);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it("should handle IndexedDB availability", () => {
|
|
386
|
+
// In test environment, IndexedDB is mocked
|
|
387
|
+
const hasIndexedDB = typeof indexedDB !== "undefined" || true; // mocked
|
|
388
|
+
expect(hasIndexedDB).toBe(true);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it("should validate crypto.randomUUID availability", () => {
|
|
392
|
+
// crypto.randomUUID should be available in modern browsers
|
|
393
|
+
const uuid = crypto.randomUUID();
|
|
394
|
+
expect(uuid).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
describe("Error Handling", () => {
|
|
399
|
+
it("should define MCP error codes", () => {
|
|
400
|
+
const errorCodes = {
|
|
401
|
+
PARSE_ERROR: -32700,
|
|
402
|
+
INVALID_REQUEST: -32600,
|
|
403
|
+
METHOD_NOT_FOUND: -32601,
|
|
404
|
+
INVALID_PARAMS: -32602,
|
|
405
|
+
INTERNAL_ERROR: -32603,
|
|
406
|
+
SERVER_ERROR_START: -32099,
|
|
407
|
+
SERVER_ERROR_END: -32000,
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
expect(errorCodes.PARSE_ERROR).toBe(-32700);
|
|
411
|
+
expect(errorCodes.INTERNAL_ERROR).toBe(-32603);
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
it("should format error responses correctly", () => {
|
|
415
|
+
const errorResponse = {
|
|
416
|
+
jsonrpc: "2.0",
|
|
417
|
+
id: null,
|
|
418
|
+
error: {
|
|
419
|
+
code: -32603,
|
|
420
|
+
message: "WASM MCP server not initialized",
|
|
421
|
+
data: { reason: "Module failed to load" },
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
expect(errorResponse.error.code).toBeLessThan(0);
|
|
426
|
+
expect(errorResponse.error.message).toBeTruthy();
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
describe("WASM Gallery Operations", () => {
|
|
432
|
+
it("should define gallery list operation", () => {
|
|
433
|
+
const listRequest = {
|
|
434
|
+
jsonrpc: "2.0",
|
|
435
|
+
id: 1,
|
|
436
|
+
method: "gallery/list",
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
expect(listRequest.method).toBe("gallery/list");
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
it("should define gallery search operation", () => {
|
|
443
|
+
const searchRequest = {
|
|
444
|
+
jsonrpc: "2.0",
|
|
445
|
+
id: 2,
|
|
446
|
+
method: "gallery/search",
|
|
447
|
+
params: { query: "development" },
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
expect(searchRequest.params.query).toBe("development");
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
it("should define gallery load operation", () => {
|
|
454
|
+
const loadRequest = {
|
|
455
|
+
jsonrpc: "2.0",
|
|
456
|
+
id: 3,
|
|
457
|
+
method: "gallery/load",
|
|
458
|
+
params: { id: "development-agent" },
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
expect(loadRequest.params.id).toBe("development-agent");
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it("should define gallery categories operation", () => {
|
|
465
|
+
const categoriesRequest = {
|
|
466
|
+
jsonrpc: "2.0",
|
|
467
|
+
id: 4,
|
|
468
|
+
method: "gallery/categories",
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
expect(categoriesRequest.method).toBe("gallery/categories");
|
|
472
|
+
});
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
describe("Tool Execution", () => {
|
|
476
|
+
it("should define read_file tool schema", () => {
|
|
477
|
+
const readFileTool = {
|
|
478
|
+
name: "read_file",
|
|
479
|
+
description: "Read content from a file in the virtual filesystem",
|
|
480
|
+
inputSchema: {
|
|
481
|
+
type: "object",
|
|
482
|
+
properties: {
|
|
483
|
+
path: {
|
|
484
|
+
type: "string",
|
|
485
|
+
description: "Absolute path to the file",
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
required: ["path"],
|
|
489
|
+
},
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
expect(readFileTool.inputSchema.required).toContain("path");
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
it("should define write_file tool schema", () => {
|
|
496
|
+
const writeFileTool = {
|
|
497
|
+
name: "write_file",
|
|
498
|
+
description: "Write content to a file in the virtual filesystem",
|
|
499
|
+
inputSchema: {
|
|
500
|
+
type: "object",
|
|
501
|
+
properties: {
|
|
502
|
+
path: {
|
|
503
|
+
type: "string",
|
|
504
|
+
description: "Absolute path to the file",
|
|
505
|
+
},
|
|
506
|
+
content: {
|
|
507
|
+
type: "string",
|
|
508
|
+
description: "Content to write",
|
|
509
|
+
},
|
|
510
|
+
},
|
|
511
|
+
required: ["path", "content"],
|
|
512
|
+
},
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
expect(writeFileTool.inputSchema.required).toContain("path");
|
|
516
|
+
expect(writeFileTool.inputSchema.required).toContain("content");
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
it("should define list_files tool schema", () => {
|
|
520
|
+
const listFilesTool = {
|
|
521
|
+
name: "list_files",
|
|
522
|
+
description: "List all files in the virtual filesystem",
|
|
523
|
+
inputSchema: {
|
|
524
|
+
type: "object",
|
|
525
|
+
properties: {},
|
|
526
|
+
},
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
expect(listFilesTool.name).toBe("list_files");
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
it("should define edit_file tool schema", () => {
|
|
533
|
+
const editFileTool = {
|
|
534
|
+
name: "edit_file",
|
|
535
|
+
description: "Edit a file by replacing old content with new content",
|
|
536
|
+
inputSchema: {
|
|
537
|
+
type: "object",
|
|
538
|
+
properties: {
|
|
539
|
+
path: { type: "string" },
|
|
540
|
+
old_content: { type: "string" },
|
|
541
|
+
new_content: { type: "string" },
|
|
542
|
+
},
|
|
543
|
+
required: ["path", "old_content", "new_content"],
|
|
544
|
+
},
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
expect(editFileTool.inputSchema.required.length).toBe(3);
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
it("should define delete_file tool schema", () => {
|
|
551
|
+
const deleteFileTool = {
|
|
552
|
+
name: "delete_file",
|
|
553
|
+
description: "Delete a file from the virtual filesystem",
|
|
554
|
+
inputSchema: {
|
|
555
|
+
type: "object",
|
|
556
|
+
properties: {
|
|
557
|
+
path: { type: "string" },
|
|
558
|
+
},
|
|
559
|
+
required: ["path"],
|
|
560
|
+
},
|
|
561
|
+
};
|
|
562
|
+
|
|
563
|
+
expect(deleteFileTool.name).toBe("delete_file");
|
|
564
|
+
});
|
|
565
|
+
});
|