#!/usr/bin/env node // A bundle that keeps and reads state through the runtime (novox/hq ADR 0201), written against the // protocol with no SDK: on start it watches STATE_NAME and writes every change it is handed to // STATE_LOG; its tools put, get, delete and list keys of whichever state they name. import { appendFileSync } from "node:fs"; import { createInterface } from "node:readline"; const say = (m) => process.stdout.write(JSON.stringify({ jsonrpc: "2.0", ...m }) + "\n"); let next = 1; const waiting = new Map(); const ask = (method, params) => new Promise((resolve, reject) => { const id = `keeper-${next++}`; waiting.set(id, { resolve, reject }); say({ id, method, params }); }); const log = (line) => appendFileSync(process.env.STATE_LOG, line + "\n"); const text = (v) => ({ content: [{ type: "text", text: JSON.stringify(v ?? null) }] }); const tool = (name) => ({ name, description: name, inputSchema: { type: "object", properties: {} } }); const TOOLS = ["put", "get", "del", "keys"].map(tool); createInterface({ input: process.stdin }).on("line", async (line) => { const m = JSON.parse(line); if (m.method === undefined && waiting.has(m.id)) { const w = waiting.get(m.id); waiting.delete(m.id); m.error ? w.reject(new Error(m.error.message)) : w.resolve(m.result); return; } const p = m.params ?? {}; switch (m.method) { case "initialize": say({ id: m.id, result: { protocolVersion: "2025-03-26", capabilities: { tools: {} }, serverInfo: { name: "keeper", version: "1" } } }); // Watched once the runtime has the handshake: the current values, then every change. ask("mesh/state.watch", { state: process.env.STATE_NAME }) .then(() => log("current"), (e) => log("watch refused: " + e.message)); return; case "tools/list": say({ id: m.id, result: { tools: TOOLS } }); return; case "mesh/state": { const c = p.change; log(`${c.current ? "was" : "now"} ${c.op} ${c.key}${c.value !== undefined ? " " + JSON.stringify(c.value) : ""}`); say({ id: m.id, result: {} }); return; } case "tools/call": { const a = p.arguments ?? {}; const verb = { put: "put", get: "get", del: "delete", keys: "keys" }[p.name]; try { say({ id: m.id, result: text(await ask(`mesh/state.${verb}`, { state: a.state, key: a.key, value: a.value })) }); } catch (e) { say({ id: m.id, result: { content: [{ type: "text", text: e.message }], isError: true } }); } return; } default: if (m.id !== undefined) say({ id: m.id, error: { code: -32601, message: "no " + m.method } }); } });