test/helpers/codex-recovery-fixture.cjs
Rama main · réplica de lectura del repositorio original.
var createAdapter = require('../../lib/yoke/adapters/codex').createCodexAdapter;
function tick() { return new Promise(function(resolve) { setImmediate(resolve); }); }
async function until(check) {
var deadline = Date.now() + 3000;
while (!check()) {
if (Date.now() > deadline) throw new Error('Condition did not settle');
await new Promise(function(resolve) { setTimeout(resolve, 10); });
}
}
function fixture(t, override, options) {
var servers = [], nextThread = 0, nextTurn = 0;
function createServer(options) {
var server = { started: false, stopped: 0, calls: [], handlers: [], loaded: [], options: options };
server.start = function() { server.started = true; return Promise.resolve(); };
server.stop = function() { server.stopped++; server.started = false; };
server.addHandler = function(fn) { var entry = { threadId: null, fn: fn }; server.handlers.push(entry); return entry; };
server.removeHandler = function(entry) { server.handlers = server.handlers.filter(function(current) { return current !== entry; }); };
server.notify = function() {};
server.respond = function(id, response) { server.calls.push({ method: 'response', id: id, params: response }); };
server.send = function(method, params) {
server.calls.push({ method: method, params: params });
if (override) { var result = override(server, method, params); if (result !== undefined) return result; }
if (method === 'thread/start' || method === 'thread/resume') {
var id = params.threadId || 'thread-' + (++nextThread);
if (server.loaded.indexOf(id) === -1) server.loaded.push(id);
return Promise.resolve({ thread: { id: id } });
}
if (method === 'thread/loaded/list') return Promise.resolve({ data: server.loaded.slice(), nextCursor: null });
if (method === 'thread/unsubscribe') {
server.loaded = server.loaded.filter(function(id) { return id !== params.threadId; });
return Promise.resolve({ status: 'unsubscribed' });
}
if (method === 'turn/start') return Promise.resolve({ turn: { id: 'turn-' + (++nextTurn) } });
return Promise.resolve({ data: [], nextCursor: null });
};
server.emit = function(method, params) {
server.handlers.slice().forEach(function(entry) { if (!params.threadId || entry.threadId === params.threadId) entry.fn({ method: method, params: params }); });
};
server.complete = function(threadId) {
var calls = server.calls.filter(function(call) { return call.method === 'turn/start' && call.params.threadId === threadId; });
var all = servers.reduce(function(result, current) { return result.concat(current.calls.filter(function(call) { return call.method === 'turn/start'; })); }, []);
var call = calls[calls.length - 1];
server.emit('turn/completed', { threadId: threadId, turn: { id: 'turn-' + (all.indexOf(call) + 1), status: 'completed' } });
};
servers.push(server);
return server;
}
var adapter = createAdapter(Object.assign({ cwd: process.cwd(), createAppServer: createServer, skillOptions: { disable: true } }, options));
t.after(function() { return adapter.shutdown(); });
return { adapter: adapter, servers: servers,
fresh: function(opts) { return adapter.createQuery(Object.assign({ model: 'gpt-test' }, opts)); },
recover: function(opts) { return adapter.createQuery(Object.assign({ resumeSessionId: 'saved-thread',
sessionMcpServer: { name: 'clay-session-tools', command: process.execPath, args: ['fixture-only.js'] },
}, opts)); },
};
}
module.exports = { fixture: fixture, tick: tick, until: until };