import fs from 'node:fs' import path from 'node:path' /** "AITURK iş hattı" choice, stored in the Codex bridge's `bridge.json` under `aiturk_hat`. * The bridge re-reads the field when the file changes, so no restart is needed. */ export type IsHattiSecim = 'onerilen' | 'buyuk' | 'kapali' | 'ozel' export interface IsHattiSettings { secim: IsHattiSecim talimat: string } const SECIMLER: IsHattiSecim[] = ['onerilen', 'buyuk', 'kapali', 'ozel'] const MAX_TALIMAT = 20000 export function readIsHatti(raw: null | string): IsHattiSettings { try { const hat = raw ? JSON.parse(raw)?.aiturk_hat : null if (!hat || typeof hat !== 'object') { return { secim: 'onerilen', talimat: '' } } const talimat = typeof hat.talimat === 'string' ? hat.talimat : '' if (SECIMLER.includes(hat.secim)) { return { secim: hat.secim, talimat } } // Written before this screen existed: same meaning the bridge gives it. return { secim: hat.enabled === false ? 'kapali' : talimat.trim() ? 'ozel' : 'onerilen', talimat } } catch { return { secim: 'onerilen', talimat: '' } } } export function writeIsHatti(raw: null | string, value: unknown): string { const v = value as Partial | null if (!v || !SECIMLER.includes(v.secim as IsHattiSecim)) throw new Error('Invalid choice') const talimat = typeof v.talimat === 'string' ? v.talimat : '' if (talimat.length > MAX_TALIMAT) throw new Error('Instruction too long') if (v.secim === 'ozel' && !talimat.trim()) throw new Error('Custom instruction is empty') let config: Record = {} try { const parsed = raw ? JSON.parse(raw) : {} config = parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {} } catch { throw new Error('bridge.json is not valid JSON') } const old = config.aiturk_hat && typeof config.aiturk_hat === 'object' ? (config.aiturk_hat as Record) : {} const hat: Record = { ...old, secim: v.secim, talimat } delete hat.enabled return `${JSON.stringify({ ...config, aiturk_hat: hat }, null, 2)}\n` } export function createIsHattiStore(directory: string) { const file = path.join(directory, 'bridge.json') const read = () => (fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : null) return { get: (): IsHattiSettings => readIsHatti(read()), save(value: unknown): IsHattiSettings { const text = writeIsHatti(read(), value) fs.mkdirSync(directory, { recursive: true }) const tmp = `${file}.${process.pid}.tmp` try { fs.writeFileSync(tmp, text, 'utf8') fs.renameSync(tmp, file) } finally { if (fs.existsSync(tmp)) fs.unlinkSync(tmp) } return readIsHatti(text) } } }