test/issues-bridge-recovery.test.js
Rama main · réplica de lectura del repositorio original.
var test = require("node:test");
var assert = require("node:assert/strict");
var http = require("node:http");
var path = require("node:path");
var spawn = require("node:child_process").spawn;
var readline = require("node:readline");
var yoke = require("../lib/yoke");
var CodexAppServer = require("../lib/yoke/codex-app-server").CodexAppServer;
var createSDKBridge = require("../lib/sdk-bridge").createSDKBridge;
test("project factory retains authenticated TLS bridge defaults through recovery and restart", async function (t) {
var servers = [];
t.mock.method(CodexAppServer.prototype, "start", function () {
this.started = true; servers.push(this); return Promise.resolve();
});
t.mock.method(CodexAppServer.prototype, "send", function () { return Promise.resolve({ data: [] }); });
t.mock.method(CodexAppServer.prototype, "stop", function () { this.started = false; });
var adapter = yoke.createAdapters({
cwd: process.cwd(), slug: "recovery-fixture", _installed: { codex: true },
clayPort: 3888, clayTls: true, clayAuthToken: "relay-fixture", clayBridgeToken: "bridge-fixture",
}).adapters.codex;
t.after(function () { return adapter.shutdown(); });
await adapter.init({});
var recovery = {
name: "clay-session-tools", command: process.execPath,
args: ["bridge.js", "--tls", "--session", "7", "--query-generation", "3"],
env: { CLAY_BRIDGE_TOKEN: "bridge-fixture" },
};
var handle = await adapter.createQuery({ cwd: process.cwd(), resumeSessionId: "saved-thread", sessionMcpServer: recovery });
assert.equal(servers.length, 2);
assert.deepEqual(servers[1].opts.config.mcp_servers[recovery.name], {
command: recovery.command, args: recovery.args, env: recovery.env,
});
handle.abort();
await adapter.shutdown();
await adapter.init({});
assert.equal(servers.length, 3);
servers.forEach(function (server) {
var bridge = server.opts.config.mcp_servers["clay-tools"];
assert.deepEqual(bridge.args.slice(1), ["--port", "3888", "--slug", "recovery-fixture", "--tls"]);
assert.deepEqual(bridge.env, { CLAY_AUTH_TOKEN: "relay-fixture", CLAY_BRIDGE_TOKEN: "bridge-fixture" });
});
});
test("SDK warmup forwards the project bridge capability", async function () {
var received;
var adapter = { vendor: "codex", init: function (options) {
received = options; return Promise.resolve({ models: [] });
} };
var bridge = createSDKBridge({
cwd: process.cwd(), slug: "warmup-fixture", clayPort: 3888, clayTls: true,
clayBridgeToken: "warmup-capability", adapter: adapter, adapters: { codex: adapter },
sessionManager: {}, send: function () {},
});
await bridge.warmup();
assert.equal(received.clayBridgeToken, "warmup-capability");
assert.equal(received.clayTls, true);
assert.equal(received.clayPort, 3888);
});
test("stdio discovery surfaces HTTP failures and retries with its bound capability", { timeout: 15000 }, async function (t) {
var status = 302;
var seen = [];
var server = http.createServer(function (req, res) {
var chunks = [];
req.on("data", function (chunk) { chunks.push(chunk); });
req.on("end", function () {
seen.push({ url: req.url, token: req.headers["x-clay-bridge-token"], body: JSON.parse(Buffer.concat(chunks)) });
res.writeHead(status, { "Content-Type": "application/json" });
res.end(JSON.stringify(status === 200 ? { tools: [{ server: "clay-issues", name: "read_issue", description: "Read", inputSchema: { type: "object" } }] } : { error: "fixture denied" }));
});
});
await new Promise(function (resolve) { server.listen(0, "127.0.0.1", resolve); });
t.after(function () { server.closeAllConnections(); server.close(); });
var child = spawn(process.execPath, [path.join(__dirname, "../lib/yoke/mcp-bridge-server.js"),
"--port", String(server.address().port), "--slug", "fixture", "--session", "7", "--query-generation", "3", "--session-only"], {
env: Object.assign({}, process.env, { CLAY_BRIDGE_TOKEN: "stdio-capability" }), stdio: ["pipe", "pipe", "ignore"],
});
t.after(function () { child.kill(); });
var lines = readline.createInterface({ input: child.stdout });
var pending = new Map();
lines.on("line", function (line) {
var message = JSON.parse(line);
if (pending.has(message.id)) { pending.get(message.id)(message); pending.delete(message.id); }
});
function request(id) {
return new Promise(function (resolve) {
pending.set(id, resolve);
child.stdin.write(JSON.stringify({ jsonrpc: "2.0", id: id, method: "tools/list", params: {} }) + "\n");
});
}
var redirect = await request(1);
assert.equal(redirect.error.code, -32001);
assert.match(redirect.error.message, /HTTP 302/);
status = 403;
assert.match((await request(2)).error.message, /HTTP 403/);
status = 200;
assert.equal((await request(3)).result.tools[0].name, "clay-issues__read_issue");
seen.forEach(function (item) {
assert.equal(item.token, "stdio-capability");
assert.equal(item.url, "/p/fixture/api/mcp-bridge");
assert.equal(item.body.sessionId, 7);
assert.equal(item.body.queryGeneration, 3);
assert.equal(item.body.sessionOnly, true);
});
});