Files
Veskslop-t/poc/src/mock-vesktop.ts
T

89 lines
2.9 KiB
TypeScript

/*
* Veskslop Phase 0 spike — mock Vesktop control socket.
*
* Stands in for the real Vesktop main process so the MCP control bridge can be
* developed and tested without Electron. Implements the JSON-lines protocol.
*
* Usage:
* VESKSLOP_SOCKET=/tmp/veskslop-mock.sock pnpm control:mock
*/
import { rmSync } from "node:fs";
import { createServer } from "node:net";
import { socketPath } from "./vesktop-socket.js";
const FAKE_GUILDS = [
{
id: "100000000000000001",
name: "Mock Guild",
channels: [
{ id: "200000000000000001", name: "general", type: 0 },
{ id: "200000000000000002", name: "voice", type: 2 }
]
}
];
const FAKE_MESSAGES = [
{ id: "300000000000000001", author: { id: "1", username: "mockuser" }, content: "hello from the mock", timestamp: new Date().toISOString() }
];
function handle(command: string | undefined, data: any) {
switch (command) {
case "ping":
return "pong";
case "state:get":
return { user: { id: "1", username: "mockuser" }, guilds: FAKE_GUILDS };
case "message:send":
return { channelId: data?.channelId, content: data?.content, sent: true };
case "message:read":
return { channelId: data?.channelId, cached: FAKE_MESSAGES.length, messages: FAKE_MESSAGES };
case "dm:send":
return { userId: data?.userId, channelId: `dm-${data?.userId}`, content: data?.content, sent: true };
default:
throw new Error(`Unknown command: ${command}`);
}
}
rmSync(socketPath, { force: true });
const server = createServer(socket => {
socket.setEncoding("utf-8");
let buffer = "";
socket.on("data", (chunk: string) => {
buffer += chunk;
let newline: number;
while ((newline = buffer.indexOf("\n")) !== -1) {
const line = buffer.slice(0, newline).trim();
buffer = buffer.slice(newline + 1);
if (!line) continue;
const start = Date.now();
try {
const request = JSON.parse(line);
const result = handle(request.command, request.data);
console.log(`[mock] ${new Date().toISOString()} ${request.command} (${Date.now() - start}ms)`);
socket.write(JSON.stringify({ id: request.id, ok: true, data: result }) + "\n");
} catch (e) {
const error = e instanceof Error ? e.message : String(e);
console.log(`[mock] ${new Date().toISOString()} ERROR ${error}`);
socket.write(JSON.stringify({ ok: false, error }) + "\n");
}
}
});
socket.on("error", () => socket.destroy());
});
server.listen(socketPath, () => {
console.log(`[mock] listening on ${socketPath}`);
});
process.on("SIGINT", () => {
server.close();
rmSync(socketPath, { force: true });
process.exit(0);
});