import { describe, expect, it } from 'vitest' import { addCodexLinkLine, CODEX_LINK_LINE, CODEX_LINK_RUN_COMMAND_MAX, codexAutostartPlan, codexBridgeArgs, codexBridgeCommandLine, codexBridgeConfig, codexBridgeLauncherSource, inspectCodexConfig, parseCodexLinkSettings, removeCodexLinkLine, serializeCodexLinkSettings } from './codex-link-config' const FOREIGN = 'openai_base_url = "http://127.0.0.1:8799/backend-api/codex"' // Add then remove must hand the user's file back exactly as it was. function expectRoundTrip(original: string) { const added = addCodexLinkLine(original) expect(added.changed).toBe(true) expect(added.owner).toBe('ours') expect(inspectCodexConfig(added.text)).toBe('ours') const removed = removeCodexLinkLine(added.text) expect(removed.changed).toBe(true) expect(removed.text).toBe(original) return added.text } describe('the contract line', () => { it('is the exact text Codex and the bridge agree on', () => { expect(CODEX_LINK_LINE).toBe( 'openai_base_url = "http://127.0.0.1:8795/backend-api/codex" # AITURK IDE Codex Baglama' ) }) }) describe('addCodexLinkLine', () => { it('writes the line into an empty file', () => { expect(expectRoundTrip('')).toBe(`${CODEX_LINK_LINE}\n`) }) it('puts the line before the first table when the file only has tables', () => { const original = '[projects."C:\\\\work"]\ntrust_level = "trusted"\n\n[mcp_servers.x]\ncommand = "node"\n' const text = expectRoundTrip(original) expect(text.indexOf(CODEX_LINK_LINE)).toBeLessThan(text.indexOf('[projects.')) expect(text.endsWith(original)).toBe(true) }) it('keeps existing top-level keys and tables intact', () => { const original = '# my config\nmodel = "gpt-6"\napproval_policy = "never"\n\n[features]\nweb = true\n' const text = expectRoundTrip(original) expect(text.indexOf(CODEX_LINK_LINE)).toBeLessThan(text.indexOf('[features]')) expect(text).toContain('model = "gpt-6"\napproval_policy = "never"\n\n[features]\nweb = true\n') }) it('preserves a CRLF file and writes its own line with CRLF', () => { const original = 'model = "gpt-6"\r\n\r\n[features]\r\nweb = true\r\n' const text = expectRoundTrip(original) expect(text).toBe(`${CODEX_LINK_LINE}\r\n${original}`) expect(text.replace(/\r\n/g, '')).not.toMatch(/[\r\n]/) }) it('keeps a byte-order mark at the very start', () => { const text = expectRoundTrip('\uFEFFmodel = "gpt-6"\n') expect(text.startsWith(`\uFEFF${CODEX_LINK_LINE}\n`)).toBe(true) }) it('keeps a file without a trailing newline exactly as it was', () => { expectRoundTrip('model = "gpt-6"\n[features]\nweb = true') }) it('is idempotent once our line is there', () => { const once = addCodexLinkLine('model = "gpt-6"\n[features]\n').text const twice = addCodexLinkLine(once) expect(twice.changed).toBe(false) expect(twice.owner).toBe('ours') expect(twice.text).toBe(once) }) it('refreshes a stale copy of our own line in place', () => { const stale = 'model = "gpt-6"\nopenai_base_url = "http://127.0.0.1:1/x" # AITURK IDE Codex Baglama\n[features]\n' const edit = addCodexLinkLine(stale) expect(edit.changed).toBe(true) expect(edit.text).toBe(`model = "gpt-6"\n${CODEX_LINK_LINE}\n[features]\n`) }) it('still owns its line after Codex rewrote the config and dropped the comment', () => { const rewritten = 'openai_base_url = "http://127.0.0.1:8795/backend-api/codex"\nmodel = "x"\n' expect(inspectCodexConfig(rewritten)).toBe('ours') expect(removeCodexLinkLine(rewritten).text).toBe('model = "x"\n') // Another local port is somebody else's bridge. expect(inspectCodexConfig('openai_base_url = "http://127.0.0.1:8799/backend-api/codex"\n')).toBe('foreign') }) it('does not touch a foreign openai_base_url and reports it', () => { for (const original of [ `${FOREIGN}\n[features]\n`, `model = "gpt-6"\r\n ${FOREIGN} # my own bridge\r\n`, '"openai_base_url" = "https://example.test/v1"\n', "'openai_base_url'='https://example.test/v1'\n" ]) { const edit = addCodexLinkLine(original) expect(edit).toEqual({ changed: false, owner: 'foreign', text: original }) expect(inspectCodexConfig(original)).toBe('foreign') } }) it('does not treat the same key under a table as top-level', () => { const original = 'model = "gpt-6"\n\n[model_providers.mine]\nopenai_base_url = "https://example.test/v1"\n' expect(inspectCodexConfig(original)).toBe('absent') const text = expectRoundTrip(original) expect(text.indexOf(CODEX_LINK_LINE)).toBeLessThan(text.indexOf('[model_providers.mine]')) expect(text).toContain('[model_providers.mine]\nopenai_base_url = "https://example.test/v1"\n') }) it('ignores the key inside a comment', () => { const original = '# openai_base_url = "https://example.test/v1"\n #openai_base_url = "x"\nmodel = "gpt-6"\n' expect(inspectCodexConfig(original)).toBe('absent') expectRoundTrip(original) }) it('ignores look-alikes inside multi-line values', () => { // Neither the "key" inside the string nor the "[table]" inside it is real, // so the genuine foreign key after it must still be found. const inString = 'notes = """\nopenai_base_url = "nope"\n[not.a.table]\n"""\nmodel = "gpt-6"\n' expect(inspectCodexConfig(inString)).toBe('absent') expect(inspectCodexConfig(`${inString}${FOREIGN}\n`)).toBe('foreign') const inArray = 'notify = [\n "a",\n ["b"]\n]\n' expect(inspectCodexConfig(`${inArray}${FOREIGN}\n`)).toBe('foreign') expect(inspectCodexConfig(`literal = '''\n[x]\n'''\n${FOREIGN}\n`)).toBe('foreign') }) it('is not fooled by a bracket or hash inside a quoted value', () => { const original = `title = "a [b] # c"\n${FOREIGN}\n` expect(inspectCodexConfig(original)).toBe('foreign') }) }) describe('removeCodexLinkLine', () => { it('removes only our line, wherever the user moved it', () => { const text = `model = "gpt-6"\r\n${CODEX_LINK_LINE}\r\napproval_policy = "never"\r\n[features]\r\n` const edit = removeCodexLinkLine(text) expect(edit).toEqual({ changed: true, owner: 'absent', text: 'model = "gpt-6"\r\napproval_policy = "never"\r\n[features]\r\n' }) }) it('leaves a file without our line untouched', () => { for (const original of ['', 'model = "gpt-6"\n', `${FOREIGN}\n[features]\n`]) { expect(removeCodexLinkLine(original).changed).toBe(false) expect(removeCodexLinkLine(original).text).toBe(original) } }) it('never removes a foreign line', () => { expect(removeCodexLinkLine(`${FOREIGN}\n`)).toEqual({ changed: false, owner: 'foreign', text: `${FOREIGN}\n` }) }) it('leaves our marker alone when it sits under a table', () => { const original = `[model_providers.mine]\n${CODEX_LINK_LINE}\n` expect(removeCodexLinkLine(original)).toEqual({ changed: false, owner: 'absent', text: original }) }) }) describe('preference file', () => { it('is on by default when the file is missing or malformed', () => { for (const raw of [null, undefined, '', '{', 'null', '[]', '"off"', '{"kapsam":"ide"}', '{"enabled":"false"}']) { expect(parseCodexLinkSettings(raw).enabled).toBe(true) } }) it('is off only when explicitly disabled', () => { expect(parseCodexLinkSettings('{"enabled": false, "kapsam": "ide"}').enabled).toBe(false) expect(parseCodexLinkSettings('{"enabled": true}').enabled).toBe(true) }) it('writes the contract shape and keeps unknown fields', () => { expect(JSON.parse(serializeCodexLinkSettings({}, false))).toEqual({ enabled: false, kapsam: 'ide' }) const { stored } = parseCodexLinkSettings('{"enabled": false, "kapsam": "hepsi", "gelecek": {"a": 1}}') expect(JSON.parse(serializeCodexLinkSettings(stored, true))).toEqual({ enabled: true, gelecek: { a: 1 }, kapsam: 'hepsi' }) }) }) describe('bridge configuration and command', () => { const launch = { bridgeHome: 'C:\\Users\\a b\\AppData\\Local\\TurkServis\\AITURK-IDE\\codex-bridge', bridgeScript: 'C:\\Program Files\\AITURK IDE\\resources\\codex-bridge\\bridge.py', hermesHome: 'C:\\Users\\a b\\AppData\\Local\\TurkServis\\AITURK-IDE\\agent' } const python = `${launch.hermesHome}\\hermes-agent\\venv\\Scripts\\pythonw.exe` it('writes the agreed bridge.json', () => { expect(codexBridgeConfig()).toEqual({ port: 8795, chatgpt_backend: 'https://chatgpt.com', routes: {}, nine_router_catalog: { enabled: false }, pano_kanca_user: false, ozet_kopru: { enabled: true, kapsam: 'hepsi', openai_modeli: 'gpt-6-luna', dongu_siniri: 8, dongu_art_arda: 3 } }) }) it('passes the same arguments to the spawn and the login item', () => { expect(codexBridgeArgs(launch)).toEqual([ launch.bridgeScript, '--home', launch.bridgeHome, '--hermes-home', launch.hermesHome ]) expect(codexBridgeCommandLine(python, launch)).toBe( `"${python}" "${launch.bridgeScript}" --home "${launch.bridgeHome}" --hermes-home "${launch.hermesHome}"` ) }) it('drops a trailing separator that would escape the closing quote', () => { expect( codexBridgeCommandLine('C:\\py\\pythonw.exe', { bridgeHome: 'C:\\d\\', bridgeScript: 'C:\\b.py', hermesHome: 'C:\\h\\' }) ).toBe('"C:\\py\\pythonw.exe" "C:\\b.py" --home "C:\\d" --hermes-home "C:\\h"') }) it('uses the direct command for the login item when it fits a Run value', () => { const short = { bridgeHome: 'C:\\d', bridgeScript: 'C:\\b\\bridge.py', hermesHome: 'C:\\h' } expect(codexAutostartPlan('C:\\py\\pythonw.exe', short, 'C:\\d\\baslat.pyw')).toEqual({ command: '"C:\\py\\pythonw.exe" "C:\\b\\bridge.py" --home "C:\\d" --hermes-home "C:\\h"', launcher: null }) }) it('falls back to a launcher when the direct command is too long for a Run value', () => { expect(codexBridgeCommandLine(python, launch).length).toBeGreaterThan(CODEX_LINK_RUN_COMMAND_MAX) const launcherPath = `${launch.bridgeHome}\\baslat.pyw` const plan = codexAutostartPlan(python, launch, launcherPath) expect(plan?.command).toBe(`"${python}" "${launcherPath}"`) expect(plan?.command.length).toBeLessThanOrEqual(CODEX_LINK_RUN_COMMAND_MAX) expect(plan?.launcher).toEqual({ path: launcherPath, source: codexBridgeLauncherSource(launch) }) // The launcher carries the very same argv as the direct command. expect(plan?.launcher?.source).toContain(`ARGV = ${JSON.stringify(codexBridgeArgs(launch))}`) }) it('registers nothing when not even the launcher command fits', () => { const deep = `C:\\${'x'.repeat(300)}` expect(codexAutostartPlan(`${deep}\\pythonw.exe`, launch, `${deep}\\baslat.pyw`)).toBeNull() }) })