08a7051Chat panel with a local Claude Code bridge: app-state, YAML, run and playback toolsJeremy Magland 1// Manual smoke test of bridge/server.mjs with a scripted fake page. Starts the bridge on a spare
2// port, connects, answers tool calls with canned state, sends one short prompt and prints the
3// events. It runs a real Claude Code turn (uses your login/quota), so it is not part of `npm test`.
4import { spawn } from "node:child_process";
5const port = 8799;
6const bridge = spawn(process.execPath, ["bridge/server.mjs", "--port", String(port)], { stdio: ["ignore", "pipe", "pipe"] });
7bridge.stdout.on("data", (d) => process.stdout.write(`[bridge stdout] ${d}`));
8bridge.stderr.on("data", (d) => process.stdout.write(`[bridge stderr] ${d}`));
9await new Promise((r) => setTimeout(r, 1500));
10const ws = new WebSocket(`ws://localhost:${port}`);
11const fakeState = { yaml: "hits:\n- time: 0\n r: 0.137\n phi: 0.3\n velocity: 8\n exciter: {kind: mallet}\n", issues: [], preset: "crash_mallet", backend: "webgpu",
12 run: { state: "done", samplesDone: 88200, samplesTotal: 88200, audioSeconds: 2, wallSeconds: 41, audioAvailableSeconds: 1.9999, signal: "unbaffled" },
13 setup: "mesh: 4657 nodes ...", diagnostics: { time: 2, kinetic: 0.1, membrane: 0.02, bending: 0.05, exciters: 5.2, maxWoverH: 3.1, hits: [{ kind: "mallet", peakForceN: 1310, contactMs: 5.8, exciterVelocity: 5.9 }] },
14 spectrogram: { bands: [{ lo: 125, hi: 250, onsetMs: 3, peakMs: 29, levelDb: -23 }, { lo: 2000, hi: 4000, onsetMs: 7.3, peakMs: 123, levelDb: -9.6 }, { lo: 8000, hi: 16000, onsetMs: 36, peakMs: 300, levelDb: -30 }], centroidHz: [{ ms: 5, hz: 612 }, { ms: 100, hz: 2393 }] } };
15let text = "";
16const done = new Promise((resolve) => {
17 ws.onmessage = (ev) => {
18 const m = JSON.parse(ev.data);
19 if (m.type === "delta") { text += m.text; return; }
20 if (m.type === "tool_call") { console.log(`[page] tool call ${m.name} ${JSON.stringify(m.args)}`); ws.send(JSON.stringify({ type: "tool_result", id: m.id, text: m.name === "get_app_state" ? JSON.stringify(fakeState) : "ok" })); return; }
21 console.log(`[event] ${JSON.stringify(m).slice(0, 200)}`);
22 if (m.type === "result") resolve(m);
23 };
24});
25ws.onopen = () => ws.send(JSON.stringify({ type: "user", text: "Look at the app state and tell me in two sentences whether the last run shows an upward cascade. Do not read any files." }));
26const result = await Promise.race([done, new Promise((r) => setTimeout(() => r({ timeout: true }), 240000))]);
27console.log("=== assistant text ===\n" + text + "\n=== result", JSON.stringify(result));
28ws.close(); bridge.kill();
29process.exit(result.ok ? 0 : 1);