// redis's tools — redis's own code (novox/hq ADR 0039), importing redis's own RESP client. They // return structured data; the mesh serves them through the sdk's tool harness. import { registerModuleTools, type ToolDefinition } from "@novox/mesh-sdk/tools"; import { RedisClient, type RespValue } from "../client.js"; export function getRedisTools(redis: RedisClient): ToolDefinition[] { return [ { name: "redis_ping", description: "Check that the redis server is reachable and responding (PONG).", input: {}, run: async () => ({ ok: await redis.ping() }), }, { name: "redis_info", description: "Redis server info — memory, clients, keyspace. Omit section for everything.", input: { section: { type: "string", description: "an INFO section, e.g. 'memory', 'clients', 'keyspace'" } }, run: async (args) => { const { raw, fields } = await redis.info(args.section ? String(args.section) : undefined); return { fields, raw }; }, }, { name: "redis_command", description: "Run an arbitrary redis command, e.g. 'DBSIZE', 'GET key', 'ACL LIST'. Admin surface.", input: { command: { type: "string", description: "the command and its arguments, space-separated" } }, run: async (args) => { const parts = tokenize(String(args.command ?? "")); if (parts.length === 0) throw new Error("redis_command: empty command"); const reply: RespValue = await redis.command(...parts); return { command: parts.join(" "), reply }; }, }, ]; } /** Split a command line into arguments, honouring double-quoted spans. */ function tokenize(command: string): string[] { const matches = command.match(/(?:[^\s"]+|"[^"]*")+/g) ?? []; return matches.map((p) => p.replace(/^"|"$/g, "")); } // The tools exist only when the server can be reached from the environment; without it, redis // contributes none rather than failing the whole tool runtime. registerModuleTools("redis", (env) => { try { return getRedisTools(RedisClient.fromEnv(env)); } catch { return []; } });