import assert from 'node:assert/strict' import fs, { mkdir, mkdtemp, readFile, realpath, stat, symlink, writeFile, rm } from 'node:fs/promises' import { syncBuiltinESMExports } from 'node:module' import { mock } from 'node:test' import { join } from 'node:path' import { tmpdir } from 'node:os' import { createConversionContext } from '../src/main/model-bridge/history' import { createServer } from 'node:http' import type { AddressInfo } from 'node:net' import { acquireModelBridge } from '../src/main/model-bridge' import { convertRequest, convertResponse, type ConversionContext } from '../src/main/model-bridge/protocol' import { readSSE } from '../src/main/model-bridge/stream' import type { ModelApi, ResolvedModel } from '../src/shared/models' let checks = 0 function check(value: unknown, message: string) { assert.ok(value, message); checks++ } const context = (): ConversionContext => ({ responsesHistory: new Map() }) function model(api: ModelApi, baseUrl = 'http://127.0.0.1:1/v1'): ResolvedModel { return { profile: { id: api, model: 'offline-model', name: 'Offline', providerId: 'offline', baseUrl, hasApiKey: false, keyStorage: 'none', supportsImages: true, supportsToolCall: true }, config: { api, model: 'offline-model', baseUrl, apiKey: 'mock-upstream-secret', temperature: 0.2, maxToolRounds: 3 } } } const request = { model: 'attacker-model', max_tokens: 128, system: [{ type: 'text', text: 'System' }], messages: [{ role: 'user', content: [{ type: 'text', text: 'hello' }, { type: 'image', source: { type: 'base64', media_type: 'image/png', data: 'aGk=' } }] }, { role: 'assistant', content: [{ type: 'tool_use', id: 'call_1', name: 'echo', input: { value: 'ok' } }] }, { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'call_1', content: 'ok' }, { type: 'text', text: 'continue' }] }], tools: [{ name: 'echo', input_schema: { type: 'object', properties: { value: { type: 'string' } } } }], tool_choice: { type: 'any', disable_parallel_tool_use: true } } for (const api of ['openai-completions', 'openai-responses'] as const) { const value = convertRequest(request, model(api), context()) check(value.model === 'offline-model', `${api}: immutable model`) check(value.tool_choice === 'required' && value.parallel_tool_calls === false, `${api}: tool choice`) check(!('apiKey' in value), `${api}: no credentials in payload`) if (api === 'openai-responses') { check(value.store === false && !value.previous_response_id, 'Responses stateless') check(value.input.some((x: any) => x.type === 'function_call') && value.input.some((x: any) => x.type === 'function_call_output'), 'Responses full tool history') check(value.input[1].content[1].image_url === 'data:image/png;base64,aGk=', 'Responses image') } else { check(value.messages[2].tool_calls[0].function.arguments === '{"value":"ok"}', 'Chat tool history') check(value.messages[3].role === 'tool' && value.messages[4].role === 'user', 'Chat tool result order') } assert.throws(() => convertRequest({ ...request, messages: [{ role: 'user', content: [{ type: 'document' }] }] }, model(api), context()), /Unsupported/); checks++ assert.throws(() => convertRequest({ ...request, messages: [{ role: 'user', content: [{ type: 'tool_result', tool_use_id: 'x', content: [{ type: 'document' }] }] }] }, model(api), context()), /Only text and image tool results/); checks++ for (const context_management of [null, {}, { edits: [] }, { edits: [{ type: 'clear_thinking_20251015', keep: 'all' }] }, { edits: [{ type: 'clear_thinking_20251015', keep: { type: 'all' } }] }]) { assert.deepEqual(convertRequest({ ...request, context_management }, model(api), context()), value); checks++ } for (const context_management of [false, { unknown: true }, { edits: null }, { edits: {} }, { edits: [null] }, { edits: [{ type: 'clear_thinking_20251015' }] }, { edits: [{ type: 'clear_thinking_20251015', keep: { type: 'thinking_turns', value: 1 } }] }, { edits: [{ type: 'clear_tool_uses_20250919' }] }, { edits: [{ type: 'compact_20260112' }] }, { edits: [{ type: 'clear_thinking_20251015', keep: 'all', unknown: true }] }]) { assert.throws(() => convertRequest({ ...request, context_management }, model(api), context()), /context_management/); checks++ } const environment = convertRequest({ ...request, messages: [...request.messages, { role: 'system', content: [{ type: 'text', text: 'SDK environment', cache_control: { type: 'ephemeral' } }] }] }, model(api), context()) check((environment.input ?? environment.messages).at(-1).role === 'system' && (environment.input ?? environment.messages).at(-1).content[0].text === 'SDK environment', `${api}: SDK in-history system instruction preserved in order`) assert.throws(() => convertRequest({ ...request, messages: [{ role: 'system', content: [{ type: 'image', source: { type: 'url', url: 'https://invalid.example/image.png' } }] }] }, model(api), context()), /Only text system blocks/); checks++ } const chat = convertResponse({ id: 'chat_1', choices: [{ message: { content: 'ok', reasoning_content: 'reason', tool_calls: [{ id: 'call_1', function: { name: 'echo', arguments: '{"v":1}' } }] }, finish_reason: 'tool_calls' }], usage: { prompt_tokens: 20, completion_tokens: 8, prompt_tokens_details: { cached_tokens: 5 } } }, 'm', false, context()) check(chat.content[0].thinking === 'reason' && !chat.content[0].signature && chat.stop_reason === 'tool_use', 'Chat reasoning and tools') check(chat.usage.input_tokens === 15 && chat.usage.cache_read_input_tokens === 5 && chat.usage.output_tokens === 8, 'Usage cached semantics') for (const api of ['openai-completions', 'openai-responses'] as const) { const m = model(api); m.config.supportsReasoning = true; m.config.thinkingLevel = 'auto' const auto = convertRequest(request, m, context()) check(!auto.reasoning_effort && !auto.reasoning?.effort, `${api}: auto effort is not forwarded`) m.config.thinkingLevel = 'high'; m.profile.supportedEfforts = ['high'] const high = convertRequest(request, m, context()) check((high.reasoning?.effort ?? high.reasoning_effort) === 'high', `${api}: supported effort forwarded`) m.config.thinkingLevel = 'low' assert.throws(() => convertRequest(request, m, context()), /reasoning effort/); checks++ const images = convertRequest({ max_tokens: 30, messages: [{ role: 'user', content: [{ type: 'tool_result', tool_use_id: 'img', content: [{ type: 'text', text: 'screenshot' }, { type: 'image', source: { type: 'base64', media_type: 'image/png', data: 'aGk=' } }] }] }] }, model(api), context()) const messages = images.input ?? images.messages check(messages[0].output === 'screenshot' || messages[0].content === 'screenshot', `${api}: tool text preserved with images`) check(JSON.stringify(messages[1]).includes('data:image/png;base64,aGk=') && JSON.stringify(messages[1]).includes('img'), `${api}: attributed tool image preserved`) } const rc = context(), responseData = { id: 'r1', status: 'completed', output: [{ type: 'reasoning', id: 'rs1', encrypted_content: 'opaque', summary: [{ type: 'summary_text', text: 'reason' }] }, { type: 'function_call', id: 'fc1', call_id: 'call_1', name: 'echo', arguments: '{"v":1}' }], usage: { input_tokens: 7, output_tokens: 4 } } const converted = convertResponse(responseData, 'm', true, rc) const replay = convertRequest({ max_tokens: 30, context_management: { edits: [{ type: 'clear_thinking_20251015', keep: 'all' }] }, messages: [{ role: 'assistant', content: converted.content }, { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'call_1', content: 'ok' }] }] }, model('openai-responses'), rc) check(replay.input[0].encrypted_content === 'opaque' && replay.input[1].call_id === 'call_1', 'Responses opaque reasoning exact-history replay') assert.throws(() => convertRequest({ max_tokens: 30, messages: [{ role: 'assistant', content: converted.content }] }, model('openai-responses'), context()), /history is not available/); checks++ rc.responsePrefix = undefined convertResponse({ ...responseData, output: [{ ...responseData.output[0], encrypted_content: 'different' }, responseData.output[1]] }, 'm', true, rc) assert.throws(() => convertRequest({ max_tokens: 30, messages: [{ role: 'assistant', content: converted.content }] }, model('openai-responses'), rc), /Ambiguous/); checks++ // Identical visible replies at different history occurrences must not share opaque state. const occurrences = context(), history: any[] = [{ role: 'user', content: 'first' }] const hiddenReply = (opaque: string) => ({ id: opaque, status: 'completed', output: [{ type: 'reasoning', id: opaque, summary: [], encrypted_content: opaque }, { type: 'message', role: 'assistant', content: [{ type: 'output_text', text: 'Done' }] }] }) convertRequest({ max_tokens: 20, messages: history }, model('openai-responses'), occurrences) const firstDone = convertResponse(hiddenReply('opaque-first'), 'm', true, occurrences) history.push({ role: 'assistant', content: firstDone.content }, { role: 'user', content: 'second' }) convertRequest({ max_tokens: 20, messages: history }, model('openai-responses'), occurrences) const secondDone = convertResponse(hiddenReply('opaque-second'), 'm', true, occurrences) history.push({ role: 'assistant', content: secondDone.content }, { role: 'user', content: 'third' }) const repeated = convertRequest({ max_tokens: 20, messages: history }, model('openai-responses'), occurrences) check(repeated.input.filter((x: any) => x.type === 'reasoning').map((x: any) => x.encrypted_content).join(',') === 'opaque-first,opaque-second', 'Identical visible responses replay their own history occurrence') assert.throws(() => convertRequest({ max_tokens: 20, messages: [{ role: 'assistant', content: firstDone.content }, { role: 'user', content: 'compacted' }] }, model('openai-responses'), occurrences), /compaction or fork/); checks++ // UTF-8/SSE fragmentation, CRLF and multiline data. const encoded = new TextEncoder().encode('data: {"text":\r\ndata: "你好"}\r\n\r\ndata: [DONE]\n\n') const parsed = [] for await (const value of readSSE(new ReadableStream({ start(c) { for (const byte of encoded) c.enqueue(new Uint8Array([byte])); c.close() } }))) parsed.push(value) check((parsed[0] as any).text === '你好' && parsed[1] === '[DONE]', 'SSE fragmented UTF8 and CRLF') let mode = 'normal', last: any, aborted = false, hits = 0 const upstream = createServer(async (req, res) => { hits++; const chunks = []; for await (const chunk of req) chunks.push(chunk) last = { path: req.url, auth: req.headers.authorization, body: JSON.parse(Buffer.concat(chunks).toString()) } if (mode === 'error') { res.writeHead(401); res.end('mock-upstream-secret'); return } if (mode === 'redirect') { res.writeHead(307, { location: 'http://127.0.0.1:1/never' }); res.end(); return } if (mode === 'cancel') { res.writeHead(200, { 'content-type': 'text/event-stream' }); res.write(': waiting\n\n'); res.once('close', () => { aborted = true }); return } const responses = req.url === '/v1/responses' const completion = responses ? { id: 'r2', status: 'completed', output: [{ type: 'message', role: 'assistant', content: [{ type: 'output_text', text: '你好' }] }, { type: 'function_call', call_id: 'call_2', name: 'echo', arguments: '{"v":2}' }], usage: { input_tokens: 9, output_tokens: 3 } } : { id: 'c2', choices: [{ message: { content: '你好', tool_calls: [{ id: 'call_2', function: { name: 'echo', arguments: '{"v":2}' } }] }, finish_reason: 'tool_calls' }], usage: { prompt_tokens: 9, completion_tokens: 3 } } if (responses && ['hidden', 'reasoning'].includes(mode)) completion.output.push({ type: 'reasoning', id: 'rs2', encrypted_content: 'opaque-private-history', summary: mode === 'hidden' ? [] : [{ type: 'summary_text', text: 'one' }, { type: 'summary_text', text: 'two' }] } as any) if (!last.body.stream) { res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify(completion)); return } res.writeHead(200, { 'content-type': 'text/event-stream' }) const events = responses ? [ { type: 'response.created', response: { id: 'r2' } }, { type: 'response.output_item.added', output_index: 0, item: { type: 'message', id: 'm1' } }, { type: 'response.output_text.delta', output_index: 0, content_index: 0, delta: '你好' }, { type: 'response.output_text.done', output_index: 0, content_index: 0, text: '你好' }, { type: 'response.output_item.added', output_index: 1, item: { type: 'function_call', call_id: 'call_2', name: 'echo' } }, { type: 'response.function_call_arguments.delta', output_index: 1, delta: '{"v":' }, { type: 'response.function_call_arguments.delta', output_index: 1, delta: '2}' }, { type: 'response.output_item.done', output_index: 1, item: completion.output[1] }, { type: 'response.completed', response: completion } ] : [ { choices: [{ index: 0, delta: { content: '你好' }, finish_reason: null }] }, { choices: [{ index: 0, delta: { tool_calls: [{ index: 0, id: 'call_2', function: { name: 'echo', arguments: '{"v":' } }] }, finish_reason: null }] }, { choices: [{ index: 0, delta: { tool_calls: [{ index: 0, function: { arguments: '2}' } }] }, finish_reason: 'tool_calls' }] }, { choices: [], usage: completion.usage } ] if (responses && mode === 'reasoning') events.splice(events.length - 1, 0, { type: 'response.output_item.added', output_index: 2, item: { type: 'reasoning', id: 'rs2' } } as any, { type: 'response.reasoning_summary_text.delta', output_index: 2, summary_index: 0, delta: 'one' } as any, { type: 'response.reasoning_summary_text.delta', output_index: 2, summary_index: 1, delta: 'two' } as any, { type: 'response.output_item.done', output_index: 2, item: completion.output[2] } as any) if (responses) events.splice(events.length - 1, 0, { type: 'response.metadata', sequence_number: 27, response_id: 'r2', metadata: { openai_chatgpt_moderation_metadata: { prompt: {}, generation: {}, tool_call: {}, tool_response: {} } } } as any) if (responses && mode === 'mismatch') (events[2] as any).delta = 'truncated' const wire = events.map(x => `data: ${JSON.stringify(x)}\r\n\r\n`).join('') + (responses ? '' : 'data: [DONE]\n\n') const bytes = Buffer.from(mode === 'eof' ? wire.slice(0, wire.indexOf('data:', 10)) : wire) for (let i = 0; i < bytes.length; i += 7) res.write(bytes.subarray(i, i + 7)) res.end() }) await new Promise(resolve => upstream.listen(0, '127.0.0.1', resolve)) const upstreamUrl = `http://127.0.0.1:${(upstream.address() as AddressInfo).port}/v1` try { for (const api of ['openai-completions', 'openai-responses'] as const) { const original = model(api, upstreamUrl), lease = await acquireModelBridge(original) original.config.model = 'changed'; original.config.apiKey = 'changed' const send = (body: any, path = '/v1/messages', token = lease.apiKey, signal?: AbortSignal) => fetch(lease.baseUrl + path, { method: 'POST', headers: { 'content-type': 'application/json', 'x-api-key': token }, body: JSON.stringify(body), signal }) try { for (const stream of [false, true]) { mode = 'normal' const result = await send({ ...request, stream, context_management: { edits: [{ type: 'clear_thinking_20251015', keep: 'all' }] } }) check(result.status === 200, `${api}: HTTP ${stream ? 'stream' : 'json'}`) check(!('context_management' in last.body), `${api}: SDK keep-all hint is not forwarded upstream`) check(last.path === (api === 'openai-responses' ? '/v1/responses' : '/v1/chat/completions') && last.body.model === 'offline-model' && last.auth === 'Bearer mock-upstream-secret', `${api}: frozen route and credentials`) if (stream) { const frames: any[] = []; for await (const event of readSSE(result.body!)) frames.push(event) check(frames[0].type === 'message_start' && frames.at(-1).type === 'message_stop', `${api}: valid stream envelope`) check(!frames.some(x => x.type === 'error'), `${api}: provider metadata does not interrupt the stream`) check(frames.filter(x => x.type === 'content_block_start').length === 2 && frames.filter(x => x.type === 'content_block_stop').length === 2, `${api}: closed text/tool blocks`) check(frames.find(x => x.type === 'message_delta').usage.input_tokens === 9, `${api}: reported stream usage`) check(frames.find(x => x.type === 'message_delta').delta.stop_reason === 'tool_use', `${api}: tool stop reason`) } else { const data = await result.json(); check(data.content[1].input.v === 2 && data.usage.input_tokens === 9, `${api}: nonstream content`) } } const before = hits check((await send(request, '/v1/messages', 'wrong')).status === 401, 'Wrong token denied') check((await send(request, '/v1/other')).status === 404, 'Unknown path denied') check((await send(request, '/v1/messages?url=http://bad')).status === 404, 'Query injection denied') check(hits === before, 'Invalid requests never reach upstream') const count = await send({ ...request, context_management: { edits: [{ type: 'clear_thinking_20251015', keep: 'all' }] } }, '/v1/messages/count_tokens'), countBody = await count.json() check(countBody.estimated === true && count.headers.get('x-ycode-token-count-source')?.includes('estimate'), 'Token count explicitly estimated') mode = 'error'; const error = await send(request); check(error.status === 401 && !(await error.text()).includes('mock-upstream-secret'), 'Upstream errors redacted') mode = 'redirect'; check((await send(request)).status === 502, 'Redirect not followed') mode = 'eof'; const eof = await (await send({ ...request, stream: true })).text(); check(eof.includes('event: error') && !eof.includes('event: message_stop'), 'Truncated stream fails explicitly') mode = 'cancel'; aborted = false const controller = new AbortController(), pending = await send({ ...request, stream: true }, '/v1/messages', lease.apiKey, controller.signal) controller.abort(); await pending.body?.cancel().catch(() => {}) for (let i = 0; i < 100 && !aborted; i++) await new Promise(r => setTimeout(r, 10)) check(aborted, `${api}: client disconnect aborts upstream`) } finally { await Promise.all([lease.close(), lease.close()]) } await assert.rejects(fetch(lease.baseUrl)); checks++ } const dir = await mkdtemp(join(await realpath(tmpdir()), 'ycode-bridge-')) try { for (const reasoningMode of ['hidden', 'reasoning']) { const file = join(dir, reasoningMode + '.json') const first = await acquireModelBridge(model('openai-responses', upstreamUrl), { historyFile: file }) mode = reasoningMode let assistant: any[] try { const result = await fetch(first.baseUrl + '/v1/messages', { method: 'POST', headers: { 'content-type': 'application/json', 'x-api-key': first.apiKey }, body: JSON.stringify({ ...request, stream: reasoningMode === 'reasoning' }) }) if (reasoningMode === 'reasoning') { const blocks: any[] = [] for await (const frame of readSSE(result.body!)) { const f = frame as any if (f.type === 'content_block_start') blocks[f.index] = { ...f.content_block } if (f.type === 'content_block_delta') { const b = blocks[f.index] if (f.delta.type === 'input_json_delta') b.args = (b.args ?? '') + f.delta.partial_json else b[b.type] += f.delta[b.type] } check(f.type !== 'error', 'Responses multioutput reasoning stream succeeds') } assistant = blocks.map(b => { if (b.type === 'tool_use') { b.input = JSON.parse(b.args); delete b.args }; return b }) } else assistant = (await result.json()).content } finally { await first.close() } const disk = await readFile(file, 'utf8') check(disk.includes('opaque-private-history') && !disk.includes('mock-upstream-secret'), 'History persists opaque state without API credentials') if (process.platform !== 'win32') check(((await stat(file)).mode & 0o777) === 0o600, 'History private file permissions') const second = await acquireModelBridge(model('openai-responses', upstreamUrl), { historyFile: file }) try { mode = 'normal' const result = await fetch(second.baseUrl + '/v1/messages', { method: 'POST', headers: { 'content-type': 'application/json', 'x-api-key': second.apiKey }, body: JSON.stringify({ max_tokens: 50, messages: [...request.messages, { role: 'assistant', content: assistant! }, { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'call_2', content: 'ok' }] }] }) }) check(result.status === 200 && last.body.input.some((x: any) => x.encrypted_content === 'opaque-private-history'), `${reasoningMode}: close/reacquire replays opaque reasoning`) await result.body?.cancel() mode = 'mismatch' const mismatch = await fetch(second.baseUrl + '/v1/messages', { method: 'POST', headers: { 'content-type': 'application/json', 'x-api-key': second.apiKey }, body: JSON.stringify({ ...request, stream: true }) }) check((await mismatch.text()).includes('event: error'), 'Responses final content mismatch fails') } finally { await second.close() } } const bad = join(dir, 'bad.json'); await writeFile(bad, '{broken') await assert.rejects(acquireModelBridge(model('openai-responses', upstreamUrl), { historyFile: bad }), /history/); checks++ await writeFile(bad, JSON.stringify({ version: 1, entries: [['[]', [{ type: 'reasoning', summary: 'invalid' }]]] })) await assert.rejects(createConversionContext(bad), /history/); checks++ const snapshotFile = join(dir, 'snapshot.json'), saved = await createConversionContext(snapshotFile) convertResponse(responseData, 'm', true, saved) const saving = saved.persist!(); saved.responsesHistory.clear(); await saving check((await createConversionContext(snapshotFile)).responsesHistory.size === 1, 'Persistence snapshots before await') await writeFile(join(dir, 'blocked'), 'not a directory') const blocked = await createConversionContext(join(dir, 'blocked', 'history.json')).catch(() => null) check(blocked === null, 'Invalid history path fails closed') await assert.rejects(createConversionContext(join(dir, 'blocked', 'missing', 'history.json')), /history/); checks++ await assert.rejects(createConversionContext(dir), /history/); checks++ const missingFile = join(dir, 'new', 'nested', 'history.json') const fresh = await createConversionContext(missingFile) check(fresh.responsesHistory.size === 0, 'Genuinely missing parents allow a new history') await fresh.persist!() check((await createConversionContext(missingFile)).responsesHistory.size === 0, 'New nested history persists and reloads') // Simulate Windows' leaf ENOENT below a regular-file parent on every platform. const blockedFile = join(dir, 'blocked', 'history.json'), originalLstat = fs.lstat mock.method(fs, 'lstat', async (...args: Parameters) => { if (String(args[0]) === blockedFile) throw Object.assign(new Error('missing'), { code: 'ENOENT' }) return originalLstat(...args) }) syncBuiltinESMExports() try { await assert.rejects(createConversionContext(blockedFile), /history/); checks++ } finally { mock.restoreAll(); syncBuiltinESMExports() } // Missing during read is not a new conversation; permission errors are never absence. for (const [method, code, target] of [['readFile', 'ENOENT', snapshotFile], ['lstat', 'EACCES', snapshotFile], ['lstat', 'EACCES', dir]] as const) { const original = fs[method] mock.method(fs, method, async (...args: any[]) => { if (String(args[0]) === target) throw Object.assign(new Error('unavailable'), { code }) return (original as Function)(...args) }) syncBuiltinESMExports() try { await assert.rejects(createConversionContext(snapshotFile), /history/); checks++ } finally { mock.restoreAll(); syncBuiltinESMExports() } } const linkedDir = join(dir, 'linked'), targetDir = join(dir, 'target') await mkdir(targetDir) await symlink(targetDir, linkedDir, process.platform === 'win32' ? 'junction' : 'dir') const linked = await createConversionContext(join(linkedDir, 'history.json')) await linked.persist!() check((await createConversionContext(join(targetDir, 'history.json'))).responsesHistory.size === 0, 'Trusted parent directory links remain supported') const changedFile = join(dir, 'changed', 'history.json'), changed = await createConversionContext(changedFile) await writeFile(join(dir, 'changed'), 'not a directory') await assert.rejects(changed.persist!(), /history/); checks++ const danglingDir = join(dir, 'dangling') await symlink(join(dir, 'absent-target'), danglingDir, process.platform === 'win32' ? 'junction' : 'dir') await assert.rejects(createConversionContext(join(danglingDir, 'history.json')), /history/); checks++ if (process.platform !== 'win32') { const linkedFile = join(dir, 'linked.json') await symlink(snapshotFile, linkedFile) await assert.rejects(createConversionContext(linkedFile), /history/); checks++ } const concurrentFile = join(dir, 'concurrent.json') const [left, right] = await Promise.all([createConversionContext(concurrentFile), createConversionContext(concurrentFile)]) left.responsesHistory.set(`${'a'.repeat(64)}:${'b'.repeat(64)}`, []) right.responsesHistory.set(`${'c'.repeat(64)}:${'d'.repeat(64)}`, []) await Promise.all([left.persist!(), right.persist!()]) check((await createConversionContext(concurrentFile)).responsesHistory.size === 2, 'Concurrent atomic history saves preserve both snapshots') check(!(await fs.readdir(dir)).some(name => name.endsWith('.tmp')), 'Atomic history saves leave no temporary files') } finally { await rm(dir, { recursive: true, force: true }) } } finally { upstream.closeAllConnections(); await new Promise(resolve => upstream.close(() => resolve())) } console.log(`Protocol bridge offline regression: ${checks} checks passed (no SDK/CLI or external API used)`)