#!/usr/bin/env node // fake-tht.mjs — hermetic THT_BIN stub for e2e tests. // Parses argv and emits the minimal JSON the backend expects. // The backend's ThtRunner prepends: thtBin -c [args...] // So we skip the first two args after node (-c ). const argv = process.argv.slice(2); // drop "node" + script path // Archive integration tests run the actual harness through the production runner. // Unrelated session/LLM operations remain deterministic fixtures. if ((argv[0] === "memory" || argv[0] === "evidence" && argv[1] === "admin") && process.env.THT_E2E_MEMORY_BIN) { const { spawnSync } = await import("node:child_process"); const result = spawnSync(process.env.THT_E2E_MEMORY_BIN, argv, { env: process.env, stdio: ["ignore", "inherit", "inherit", 3], }); process.exit(result.status ?? 1); } // Strip leading "-c " pair (ThtRunner always prepends this). let args = argv; if (args[0] === "-c") { args = args.slice(2); } // args now starts with the subcommand group, e.g. ["session","new","...","--json"] const sub = args.slice(0, 2).join(" "); if (sub === "session new") { // session new [--provider p] [--model m] [--thinking t] [--name n] --json process.stdout.write(JSON.stringify({ id: "e2e-1" }) + "\n"); } else if (sub === "session list") { process.stdout.write(JSON.stringify([]) + "\n"); } else if (sub === "session show") { const id = args[2] ?? "e2e-1"; process.stdout.write( JSON.stringify({ id, status: "open", provider: null, model: null, thinking: null }) + "\n", ); } else if (sub === "sql preview") { process.stdout.write( JSON.stringify({ columns: [], rows: [], execution_ms: 0, truncated: false }) + "\n", ); } else { // Unknown subcommand — exit 0 with empty JSON so the backend doesn't crash. process.stdout.write("{}\n"); } process.exit(0);