@cognisos/liminal 2.4.2 → 2.6.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/rsc/pipeline.ts","../src/version.ts","../src/config/loader.ts","../src/config/paths.ts","../src/config/schema.ts","../src/config/shell.ts","../src/ui/prompts.ts","../src/commands/login.ts","../src/auth/supabase.ts","../src/connectors/claude-code.ts","../src/connectors/codex.ts","../src/connectors/cursor.ts","../src/connectors/openai-compatible.ts","../src/connectors/index.ts","../src/commands/init.ts","../src/commands/logout.ts","../src/proxy/completions.ts","../src/rsc/message-compressor.ts","../src/rsc/content-segmenter.ts","../src/rsc/conversation-analyzer.ts","../src/rsc/learning.ts","../src/proxy/streaming.ts","../src/terminology.ts","../src/proxy/messages.ts","../src/proxy/anthropic-streaming.ts","../src/proxy/responses.ts","../src/proxy/responses-streaming.ts","../src/proxy/session-identity.ts","../src/proxy/handler.ts","../src/proxy/server.ts","../src/daemon/logger.ts","../src/rsc/session-manager.ts","../src/rsc/semaphore.ts","../src/rsc/latency-monitor.ts","../src/tls/connect-handler.ts","../src/tls/allowlist.ts","../src/tls/ca.ts","../src/tls/trust.ts","../src/tls/mitm-bridge.ts","../src/tls/cert-generator.ts","../src/tls/mitm-stats.ts","../src/daemon/lifecycle.ts","../src/commands/start.ts","../src/commands/stop.ts","../src/commands/status.ts","../src/commands/summary.ts","../src/commands/config.ts","../src/commands/logs.ts","../src/commands/uninstall.ts","../src/commands/trust-ca.ts","../src/commands/untrust-ca.ts","../src/commands/setup-cursor.ts","../src/bin.ts"],"sourcesContent":["import {\n CompressionPipeline,\n RSCTransport,\n RSCEventEmitter,\n Session,\n CircuitBreaker,\n} from '@cognisos/rsc-sdk'\nimport type { SessionSummary, CircuitState } from '@cognisos/rsc-sdk'\n\nexport interface PipelineConfig {\n rscApiKey: string\n rscBaseUrl: string\n compressionThreshold: number\n learnFromResponses: boolean\n latencyBudgetMs?: number\n sessionId?: string\n}\n\nexport class RSCPipelineWrapper {\n readonly pipeline: CompressionPipeline\n readonly session: Session\n readonly events: RSCEventEmitter\n readonly transport: RSCTransport\n private readonly circuitBreaker: CircuitBreaker\n\n constructor(config: PipelineConfig) {\n this.circuitBreaker = new CircuitBreaker(5, 5 * 60 * 1000)\n\n this.transport = new RSCTransport({\n baseUrl: config.rscBaseUrl,\n apiKey: config.rscApiKey,\n timeout: 30_000,\n maxRetries: 3,\n circuitBreaker: this.circuitBreaker,\n })\n\n this.events = new RSCEventEmitter()\n this.session = new Session(config.sessionId)\n\n this.pipeline = new CompressionPipeline(\n this.transport,\n {\n threshold: config.compressionThreshold,\n learnFromResponses: config.learnFromResponses,\n latencyBudgetMs: config.latencyBudgetMs,\n sessionId: this.session.sessionId,\n },\n this.events,\n )\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n await this.transport.get<{ status: string }>('/health')\n return true\n } catch {\n return false\n }\n }\n\n getSessionSummary(): SessionSummary {\n return this.session.getSummary()\n }\n\n getCircuitState(): CircuitState {\n return this.circuitBreaker.getState()\n }\n\n isCircuitOpen(): boolean {\n return this.circuitBreaker.getState() === 'open'\n }\n\n resetCircuitBreaker(): void {\n this.circuitBreaker.reset()\n }\n}\n","declare const __VERSION__: string\nexport const VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : '0.2.1'\n\n// FIGlet-style \"LIMINAL\" banner\nconst BANNER_LINES = [\n ' ___ ___ _____ ______ ___ ________ ________ ___',\n '|\\\\ \\\\ |\\\\ \\\\|\\\\ _ \\\\ _ \\\\|\\\\ \\\\|\\\\ ___ \\\\|\\\\ __ \\\\|\\\\ \\\\',\n '\\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\\\\\\\\\__\\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\\\\\ \\\\ \\\\ \\\\ \\\\|\\\\ \\\\ \\\\ \\\\',\n ' \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\\\\\|__| \\\\ \\\\ \\\\ \\\\ \\\\ \\\\\\\\ \\\\ \\\\ \\\\ __ \\\\ \\\\ \\\\',\n ' \\\\ \\\\ \\\\____\\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\\\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\____',\n ' \\\\ \\\\_______\\\\ \\\\__\\\\ \\\\__\\\\ \\\\ \\\\__\\\\ \\\\__\\\\ \\\\__\\\\\\\\ \\\\__\\\\ \\\\__\\\\ \\\\__\\\\ \\\\_______\\\\',\n ' \\\\|_______|\\\\|__|\\\\|__| \\\\|__|\\\\|__|\\\\|__| \\\\|__|\\\\|__|\\\\|__|\\\\|_______|',\n]\n\nexport function printBanner(): void {\n console.log()\n for (const line of BANNER_LINES) {\n console.log(line)\n }\n console.log()\n console.log(` v${VERSION} -- brought to you by Cognisos`)\n console.log()\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { LIMINAL_DIR, CONFIG_FILE, LOG_DIR } from './paths.js'\nimport { DEFAULTS } from './schema.js'\nimport type { RSCConfig } from './schema.js'\n\n/**\n * Load config from ~/.liminal/config.json, merged with defaults and env var overrides.\n * Priority: env vars > config file > defaults\n */\nexport function loadConfig(): RSCConfig {\n let fileConfig: Partial<RSCConfig> = {}\n\n if (existsSync(CONFIG_FILE)) {\n try {\n const raw = readFileSync(CONFIG_FILE, 'utf-8')\n fileConfig = JSON.parse(raw)\n } catch {\n // Corrupted config file — fall through to defaults\n }\n }\n\n const merged: RSCConfig = {\n apiKey: fileConfig.apiKey ?? '',\n apiBaseUrl: DEFAULTS.apiBaseUrl,\n upstreamBaseUrl: DEFAULTS.upstreamBaseUrl,\n anthropicUpstreamUrl: DEFAULTS.anthropicUpstreamUrl,\n port: DEFAULTS.port,\n compressionThreshold: DEFAULTS.compressionThreshold,\n aggregateThreshold: DEFAULTS.aggregateThreshold,\n hotFraction: DEFAULTS.hotFraction,\n coldFraction: DEFAULTS.coldFraction,\n compressRoles: DEFAULTS.compressRoles,\n compressToolResults: DEFAULTS.compressToolResults,\n learnFromResponses: DEFAULTS.learnFromResponses,\n latencyBudgetMs: DEFAULTS.latencyBudgetMs,\n enabled: DEFAULTS.enabled,\n tools: DEFAULTS.tools,\n concurrencyLimit: DEFAULTS.concurrencyLimit,\n concurrencyTimeoutMs: DEFAULTS.concurrencyTimeoutMs,\n maxSessions: DEFAULTS.maxSessions,\n sessionTtlMs: DEFAULTS.sessionTtlMs,\n latencyWarningMs: DEFAULTS.latencyWarningMs,\n latencyCriticalMs: DEFAULTS.latencyCriticalMs,\n ...fileConfig,\n }\n\n // Environment variable overrides\n if (process.env.LIMINAL_API_KEY) merged.apiKey = process.env.LIMINAL_API_KEY\n if (process.env.LIMINAL_API_URL) merged.apiBaseUrl = process.env.LIMINAL_API_URL\n if (process.env.LIMINAL_UPSTREAM_URL) merged.upstreamBaseUrl = process.env.LIMINAL_UPSTREAM_URL\n if (process.env.LIMINAL_ANTHROPIC_URL) merged.anthropicUpstreamUrl = process.env.LIMINAL_ANTHROPIC_URL\n if (process.env.LIMINAL_PORT) merged.port = parseInt(process.env.LIMINAL_PORT, 10)\n\n return merged\n}\n\n/**\n * Apply CLI flag overrides on top of loaded config.\n */\nexport function applyOverrides(\n config: RSCConfig,\n overrides: Partial<Pick<RSCConfig, 'port' | 'upstreamBaseUrl'>>,\n): RSCConfig {\n return { ...config, ...overrides }\n}\n\n/**\n * Save config to ~/.liminal/config.json. Creates ~/.liminal/ and ~/.liminal/logs/ if needed.\n */\nexport function saveConfig(config: Partial<RSCConfig>): void {\n ensureDirectories()\n\n let existing: Partial<RSCConfig> = {}\n if (existsSync(CONFIG_FILE)) {\n try {\n existing = JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'))\n } catch {\n // Overwrite corrupted file\n }\n }\n\n const merged = { ...existing, ...config }\n writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2) + '\\n', { encoding: 'utf-8', mode: 0o600 })\n try { chmodSync(CONFIG_FILE, 0o600) } catch { /* best effort */ }\n}\n\n/**\n * Ensure ~/.liminal/ and ~/.liminal/logs/ directories exist.\n */\nexport function ensureDirectories(): void {\n if (!existsSync(LIMINAL_DIR)) mkdirSync(LIMINAL_DIR, { recursive: true, mode: 0o700 })\n if (!existsSync(LOG_DIR)) mkdirSync(LOG_DIR, { recursive: true, mode: 0o700 })\n // Ensure parent of config file exists\n const configDir = dirname(CONFIG_FILE)\n if (!existsSync(configDir)) mkdirSync(configDir, { recursive: true })\n}\n\n/**\n * Check if a valid config file exists with an API key.\n */\nexport function isConfigured(): boolean {\n try {\n const config = loadConfig()\n return config.apiKey.length > 0\n } catch {\n return false\n }\n}\n\n/**\n * Mask an API key for display: show first 8 chars + last 4.\n */\nexport function maskApiKey(key: string): string {\n if (key.length <= 12) return '****'\n return key.slice(0, 8) + '...' + key.slice(-4)\n}\n","import { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport const LIMINAL_DIR = join(homedir(), '.liminal')\nexport const CONFIG_FILE = join(LIMINAL_DIR, 'config.json')\nexport const PID_FILE = join(LIMINAL_DIR, 'liminal.pid')\nexport const LOG_DIR = join(LIMINAL_DIR, 'logs')\nexport const LOG_FILE = join(LOG_DIR, 'liminal.log')\n","export interface RSCConfig {\n apiKey: string\n apiBaseUrl: string\n upstreamBaseUrl: string\n anthropicUpstreamUrl: string\n port: number\n compressionThreshold: number\n aggregateThreshold: number\n hotFraction: number\n coldFraction: number\n compressRoles: string[]\n compressToolResults: boolean\n learnFromResponses: boolean\n latencyBudgetMs: number\n enabled: boolean\n tools: string[]\n // Multi-session concurrency settings\n concurrencyLimit: number\n concurrencyTimeoutMs: number\n maxSessions: number\n sessionTtlMs: number\n latencyWarningMs: number\n latencyCriticalMs: number\n}\n\nexport const DEFAULTS: Omit<RSCConfig, 'apiKey'> = {\n apiBaseUrl: 'https://api.cognisos.ai',\n upstreamBaseUrl: 'https://api.openai.com',\n anthropicUpstreamUrl: 'https://api.anthropic.com',\n port: 3141,\n compressionThreshold: 100,\n aggregateThreshold: 500,\n hotFraction: 0.3,\n coldFraction: 0.3,\n compressRoles: ['user', 'assistant'],\n compressToolResults: true,\n learnFromResponses: true,\n latencyBudgetMs: 10000,\n enabled: true,\n tools: [],\n concurrencyLimit: 6,\n concurrencyTimeoutMs: 15000,\n maxSessions: 10,\n sessionTtlMs: 1800000,\n latencyWarningMs: 4000,\n latencyCriticalMs: 8000,\n}\n\n/** Keys that can be set via `liminal config --set` */\nexport const CONFIGURABLE_KEYS = new Set<string>([\n 'apiBaseUrl',\n 'upstreamBaseUrl',\n 'anthropicUpstreamUrl',\n 'port',\n 'compressionThreshold',\n 'aggregateThreshold',\n 'hotFraction',\n 'coldFraction',\n 'compressRoles',\n 'compressToolResults',\n 'learnFromResponses',\n 'latencyBudgetMs',\n 'enabled',\n 'tools',\n 'concurrencyLimit',\n 'concurrencyTimeoutMs',\n 'maxSessions',\n 'sessionTtlMs',\n 'latencyWarningMs',\n 'latencyCriticalMs',\n])\n","/**\n * Shell profile detection and modification utilities.\n * Shared by init (append exports) and uninstall (remove exports).\n */\n\nimport { existsSync, readFileSync, writeFileSync, appendFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { homedir } from 'node:os'\n\nexport interface ShellProfile {\n name: string\n path: string\n}\n\nconst LIMINAL_BLOCK_HEADER = '# Liminal — route AI tools through compression proxy'\n\n/**\n * Detect the user's shell profile file.\n */\nexport function detectShellProfile(): ShellProfile | null {\n const shell = process.env.SHELL || ''\n const home = homedir()\n\n if (shell.endsWith('/zsh')) {\n return { name: '~/.zshrc', path: join(home, '.zshrc') }\n }\n\n if (shell.endsWith('/bash')) {\n const bashProfile = join(home, '.bash_profile')\n if (existsSync(bashProfile)) {\n return { name: '~/.bash_profile', path: bashProfile }\n }\n return { name: '~/.bashrc', path: join(home, '.bashrc') }\n }\n\n const candidates: ShellProfile[] = [\n { name: '~/.zshrc', path: join(home, '.zshrc') },\n { name: '~/.bashrc', path: join(home, '.bashrc') },\n { name: '~/.profile', path: join(home, '.profile') },\n ]\n\n for (const c of candidates) {\n if (existsSync(c.path)) return c\n }\n\n return null\n}\n\n/**\n * Check if a line already exists in a file.\n */\nexport function lineExistsInFile(filePath: string, line: string): boolean {\n if (!existsSync(filePath)) return false\n try {\n const content = readFileSync(filePath, 'utf-8')\n return content.includes(line)\n } catch {\n return false\n }\n}\n\n/**\n * Append export lines to shell profile with a Liminal comment header.\n * Only appends lines that don't already exist.\n */\nexport function appendToShellProfile(profile: ShellProfile, lines: string[]): string[] {\n const newLines = lines.filter((line) => !lineExistsInFile(profile.path, line))\n if (newLines.length === 0) return []\n\n const block = [\n '',\n LIMINAL_BLOCK_HEADER,\n ...newLines,\n ].join('\\n') + '\\n'\n\n appendFileSync(profile.path, block, 'utf-8')\n return newLines\n}\n\n/**\n * Remove all Liminal-related lines from a shell profile.\n * Removes the header comment and any export lines containing Liminal proxy URLs.\n * Returns the lines that were removed.\n */\nexport function removeLiminalFromShellProfile(profile: ShellProfile): string[] {\n if (!existsSync(profile.path)) return []\n\n let content: string\n try {\n content = readFileSync(profile.path, 'utf-8')\n } catch {\n return []\n }\n\n const lines = content.split('\\n')\n const removed: string[] = []\n const kept: string[] = []\n\n for (const line of lines) {\n if (line.trim() === LIMINAL_BLOCK_HEADER) {\n removed.push(line)\n continue\n }\n\n // Match Liminal proxy export lines:\n // export ANTHROPIC_BASE_URL=http://127.0.0.1:XXXX\n // export OPENAI_BASE_URL=http://127.0.0.1:XXXX/v1\n if (isLiminalExportLine(line)) {\n removed.push(line)\n continue\n }\n\n kept.push(line)\n }\n\n if (removed.length > 0) {\n // Clean up consecutive blank lines left by removal\n const cleaned = kept.join('\\n').replace(/\\n{3,}/g, '\\n\\n')\n writeFileSync(profile.path, cleaned, 'utf-8')\n }\n\n return removed\n}\n\n/**\n * Check if a line is a Liminal proxy export.\n */\nfunction isLiminalExportLine(line: string): boolean {\n const trimmed = line.trim()\n if (!trimmed.startsWith('export ')) return false\n // Match export ANTHROPIC_BASE_URL=http://127.0.0.1:XXXX or similar\n if (trimmed.includes('ANTHROPIC_BASE_URL=http://127.0.0.1:')) return true\n if (trimmed.includes('OPENAI_BASE_URL=http://127.0.0.1:')) return true\n return false\n}\n\n/**\n * Find all Liminal export lines currently in a shell profile.\n */\nexport function findLiminalExportsInProfile(profile: ShellProfile): string[] {\n if (!existsSync(profile.path)) return []\n try {\n const content = readFileSync(profile.path, 'utf-8')\n return content.split('\\n').filter(isLiminalExportLine)\n } catch {\n return []\n }\n}\n","/**\n * Lightweight interactive terminal prompts — zero external dependencies.\n * Uses raw stdin mode for arrow-key navigation.\n */\n\n// ─── ANSI escape sequences ───────────────────────────────────────────\n\nconst ANSI = {\n HIDE_CURSOR: '\\x1b[?25l',\n SHOW_CURSOR: '\\x1b[?25h',\n CLEAR_LINE: '\\x1b[2K',\n BOLD: '\\x1b[1m',\n DIM: '\\x1b[2m',\n CYAN: '\\x1b[36m',\n RESET: '\\x1b[0m',\n moveUp: (n: number) => (n > 0 ? `\\x1b[${n}A` : ''),\n} as const\n\n// ─── Key parsing ─────────────────────────────────────────────────────\n\nexport type KeyPress =\n | { type: 'up' }\n | { type: 'down' }\n | { type: 'enter' }\n | { type: 'space' }\n | { type: 'escape' }\n | { type: 'ctrlc' }\n | { type: 'backspace' }\n | { type: 'char'; char: string }\n | { type: 'other' }\n\nexport function parseKey(data: Buffer): KeyPress {\n if (data.length === 0) return { type: 'other' }\n\n // Ctrl+C\n if (data[0] === 0x03) return { type: 'ctrlc' }\n\n // Arrow keys: ESC [ A/B\n if (data.length >= 3 && data[0] === 0x1b && data[1] === 0x5b) {\n if (data[2] === 0x41) return { type: 'up' }\n if (data[2] === 0x42) return { type: 'down' }\n return { type: 'other' }\n }\n\n // Standalone Escape\n if (data.length === 1 && data[0] === 0x1b) return { type: 'escape' }\n\n // Enter\n if (data[0] === 0x0d || data[0] === 0x0a) return { type: 'enter' }\n\n // Space\n if (data[0] === 0x20) return { type: 'space' }\n\n // Backspace (DEL on macOS)\n if (data[0] === 0x7f || data[0] === 0x08) return { type: 'backspace' }\n\n // Printable ASCII characters (0x21-0x7e)\n if (data.length === 1 && data[0] >= 0x21 && data[0] <= 0x7e) {\n return { type: 'char', char: String.fromCharCode(data[0]) }\n }\n\n return { type: 'other' }\n}\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface SelectOption<T> {\n label: string\n value: T\n description?: string\n}\n\nexport interface MultiSelectOption<T> extends SelectOption<T> {\n default?: boolean\n}\n\ninterface Streams {\n stdin: NodeJS.ReadableStream & { setRawMode?: (mode: boolean) => void; isTTY?: boolean }\n stdout: { write: (s: string) => boolean }\n}\n\ninterface SelectConfig<T> {\n message: string\n options: SelectOption<T>[]\n defaultIndex?: number\n _streams?: Streams\n}\n\ninterface MultiSelectConfig<T> {\n message: string\n options: MultiSelectOption<T>[]\n _streams?: Streams\n}\n\n// ─── Render helpers ──────────────────────────────────────────────────\n\nexport interface RenderResult {\n text: string\n lineCount: number\n}\n\nexport function renderSelect<T>(\n options: SelectOption<T>[],\n cursorIndex: number,\n message: string,\n): RenderResult {\n const lines: string[] = []\n lines.push(` ${ANSI.BOLD}${message}${ANSI.RESET}`)\n lines.push('')\n\n const maxLabel = Math.max(...options.map((o) => o.label.length))\n\n for (let i = 0; i < options.length; i++) {\n const focused = i === cursorIndex\n const pointer = focused ? `${ANSI.CYAN}->${ANSI.RESET}` : ' '\n const label = focused\n ? `${ANSI.BOLD}${options[i].label.padEnd(maxLabel)}${ANSI.RESET}`\n : `${options[i].label.padEnd(maxLabel)}`\n const desc = options[i].description\n ? ` ${ANSI.DIM}${options[i].description}${ANSI.RESET}`\n : ''\n lines.push(` ${pointer} ${label}${desc}`)\n }\n\n lines.push('')\n return { text: lines.join('\\n'), lineCount: lines.length }\n}\n\nexport function renderMultiSelect<T>(\n options: MultiSelectOption<T>[],\n cursorIndex: number,\n selected: Set<number>,\n message: string,\n): RenderResult {\n const lines: string[] = []\n lines.push(` ${ANSI.BOLD}${message}${ANSI.RESET}`)\n lines.push('')\n\n const maxLabel = Math.max(...options.map((o) => o.label.length))\n\n for (let i = 0; i < options.length; i++) {\n const focused = i === cursorIndex\n const checked = selected.has(i)\n const pointer = focused ? `${ANSI.CYAN}->${ANSI.RESET}` : ' '\n const box = checked\n ? `${ANSI.CYAN}[x]${ANSI.RESET}`\n : `${ANSI.DIM}[ ]${ANSI.RESET}`\n const label = focused\n ? `${ANSI.BOLD}${options[i].label.padEnd(maxLabel)}${ANSI.RESET}`\n : `${options[i].label.padEnd(maxLabel)}`\n const desc = options[i].description\n ? ` ${ANSI.DIM}${options[i].description}${ANSI.RESET}`\n : ''\n lines.push(` ${pointer} ${box} ${label}${desc}`)\n }\n\n lines.push('')\n lines.push(` ${ANSI.DIM}↑/↓ Navigate ${ANSI.RESET}${ANSI.CYAN}Space${ANSI.RESET}${ANSI.DIM} Select ${ANSI.RESET}${ANSI.CYAN}Enter${ANSI.RESET}${ANSI.DIM} Confirm${ANSI.RESET}`)\n lines.push('')\n return { text: lines.join('\\n'), lineCount: lines.length }\n}\n\n// ─── Raw mode lifecycle ──────────────────────────────────────────────\n\nfunction withRawMode<T>(\n streams: Streams,\n handler: (\n resolve: (value: T) => void,\n ) => (key: KeyPress) => void,\n): Promise<T> {\n const { stdin, stdout } = streams\n\n return new Promise<T>((resolve, reject) => {\n let cleaned = false\n\n function cleanup() {\n if (cleaned) return\n cleaned = true\n stdin.removeListener('data', onData)\n if (stdin.setRawMode) stdin.setRawMode(false)\n if ('pause' in stdin && typeof (stdin as any).pause === 'function') {\n (stdin as any).pause()\n }\n stdout.write(ANSI.SHOW_CURSOR)\n process.removeListener('exit', cleanup)\n }\n\n function onData(data: Buffer) {\n const key = parseKey(data)\n if (key.type === 'ctrlc') {\n cleanup()\n process.exit(130)\n }\n keyHandler(key)\n }\n\n const keyHandler = handler((value: T) => {\n cleanup()\n resolve(value)\n })\n\n // Safety: restore terminal on unexpected exit\n process.on('exit', cleanup)\n\n try {\n if (stdin.setRawMode) stdin.setRawMode(true)\n stdout.write(ANSI.HIDE_CURSOR)\n stdin.on('data', onData)\n if ('resume' in stdin && typeof (stdin as any).resume === 'function') {\n (stdin as any).resume()\n }\n } catch (err) {\n cleanup()\n reject(err)\n }\n })\n}\n\n// ─── Public API ──────────────────────────────────────────────────────\n\nexport async function selectPrompt<T>(config: SelectConfig<T>): Promise<T | null> {\n const { message, options, defaultIndex = 0, _streams } = config\n const streams = _streams ?? { stdin: process.stdin, stdout: process.stdout }\n let cursorIndex = defaultIndex\n let prevLineCount = 0\n\n function draw() {\n const { text, lineCount } = renderSelect(options, cursorIndex, message)\n // Move up to overwrite previous render\n if (prevLineCount > 0) {\n streams.stdout.write(ANSI.moveUp(prevLineCount))\n }\n // Clear and write each line\n const lines = text.split('\\n')\n for (const line of lines) {\n streams.stdout.write(ANSI.CLEAR_LINE + line + '\\n')\n }\n prevLineCount = lineCount\n }\n\n draw()\n\n const result = await withRawMode<T | null>(streams, (resolve) => {\n return (key: KeyPress) => {\n switch (key.type) {\n case 'up':\n cursorIndex = (cursorIndex - 1 + options.length) % options.length\n draw()\n break\n case 'down':\n cursorIndex = (cursorIndex + 1) % options.length\n draw()\n break\n case 'enter':\n resolve(options[cursorIndex].value)\n break\n case 'escape':\n resolve(null)\n break\n }\n }\n })\n\n // Show confirmed selection\n if (result !== null) {\n const selected = options.find((o) => o.value === result)\n if (selected) {\n // Overwrite prompt with confirmed value\n if (prevLineCount > 0) {\n streams.stdout.write(ANSI.moveUp(prevLineCount))\n }\n for (let i = 0; i < prevLineCount; i++) {\n streams.stdout.write(ANSI.CLEAR_LINE + '\\n')\n }\n streams.stdout.write(ANSI.moveUp(prevLineCount))\n streams.stdout.write(` ${ANSI.BOLD}${message}${ANSI.RESET} ${ANSI.CYAN}${selected.label}${ANSI.RESET}\\n`)\n }\n }\n\n return result\n}\n\nexport async function multiSelectPrompt<T>(config: MultiSelectConfig<T>): Promise<T[] | null> {\n const { message, options, _streams } = config\n const streams = _streams ?? { stdin: process.stdin, stdout: process.stdout }\n let cursorIndex = 0\n const selected = new Set<number>()\n let prevLineCount = 0\n\n // Pre-fill defaults\n for (let i = 0; i < options.length; i++) {\n if (options[i].default) selected.add(i)\n }\n\n function draw() {\n const { text, lineCount } = renderMultiSelect(options, cursorIndex, selected, message)\n if (prevLineCount > 0) {\n streams.stdout.write(ANSI.moveUp(prevLineCount))\n }\n const lines = text.split('\\n')\n for (const line of lines) {\n streams.stdout.write(ANSI.CLEAR_LINE + line + '\\n')\n }\n prevLineCount = lineCount\n }\n\n draw()\n\n const result = await withRawMode<T[] | null>(streams, (resolve) => {\n return (key: KeyPress) => {\n switch (key.type) {\n case 'up':\n cursorIndex = (cursorIndex - 1 + options.length) % options.length\n draw()\n break\n case 'down':\n cursorIndex = (cursorIndex + 1) % options.length\n draw()\n break\n case 'space':\n if (selected.has(cursorIndex)) {\n selected.delete(cursorIndex)\n } else {\n selected.add(cursorIndex)\n }\n draw()\n break\n case 'enter':\n if (selected.size > 0) {\n const values = [...selected].sort().map((i) => options[i].value)\n resolve(values)\n }\n // If nothing selected, ignore Enter (must select at least 1)\n break\n case 'escape':\n resolve(null)\n break\n }\n }\n })\n\n // Show confirmed selection\n if (result !== null) {\n const labels = [...selected].sort().map((i) => options[i].label)\n if (prevLineCount > 0) {\n streams.stdout.write(ANSI.moveUp(prevLineCount))\n }\n for (let i = 0; i < prevLineCount; i++) {\n streams.stdout.write(ANSI.CLEAR_LINE + '\\n')\n }\n streams.stdout.write(ANSI.moveUp(prevLineCount))\n streams.stdout.write(` ${ANSI.BOLD}${message}${ANSI.RESET} ${ANSI.CYAN}${labels.join(', ')}${ANSI.RESET}\\n`)\n }\n\n return result\n}\n\n// ─── Password prompt ─────────────────────────────────────────────────\n\ninterface PasswordConfig {\n message: string\n _streams?: Streams\n}\n\nexport async function passwordPrompt(config: PasswordConfig): Promise<string> {\n const { message, _streams } = config\n const streams = _streams ?? { stdin: process.stdin, stdout: process.stdout }\n let password = ''\n\n streams.stdout.write(` ${ANSI.BOLD}${message}${ANSI.RESET}: `)\n\n const result = await withRawMode<string>(streams, (resolve) => {\n return (key: KeyPress) => {\n switch (key.type) {\n case 'char':\n password += (key as { type: 'char'; char: string }).char\n streams.stdout.write('*')\n break\n case 'space':\n password += ' '\n streams.stdout.write('*')\n break\n case 'backspace':\n if (password.length > 0) {\n password = password.slice(0, -1)\n streams.stdout.write('\\b \\b')\n }\n break\n case 'enter':\n streams.stdout.write('\\n')\n resolve(password)\n break\n case 'escape':\n streams.stdout.write('\\n')\n resolve('')\n break\n }\n }\n })\n\n return result\n}\n","import { createInterface } from 'node:readline/promises'\nimport { stdin, stdout } from 'node:process'\nimport { signIn, signUp, authenticateAndGetKey } from '../auth/supabase.js'\nimport { saveConfig, ensureDirectories, loadConfig } from '../config/loader.js'\nimport { DEFAULTS } from '../config/schema.js'\nimport { printBanner } from '../version.js'\nimport { selectPrompt, passwordPrompt } from '../ui/prompts.js'\nimport type { AuthError } from '../auth/supabase.js'\n\nexport async function loginCommand(): Promise<void> {\n printBanner()\n\n // Check if already logged in\n try {\n const config = loadConfig()\n if (config.apiKey && (config.apiKey.startsWith('lim_') || config.apiKey.startsWith('fmcp_'))) {\n console.log(' Already logged in.')\n console.log(' Run \\x1b[1mliminal logout\\x1b[0m first to switch accounts.')\n return\n }\n } catch {\n // No config yet — proceed with login\n }\n\n await runAuthFlow()\n}\n\n/**\n * Shared auth flow used by both `liminal login` and `liminal init`.\n * Returns the API key on success.\n */\nexport async function runAuthFlow(): Promise<string> {\n const modeResult = await selectPrompt<'login' | 'signup'>({\n message: 'Welcome to Liminal',\n options: [\n { label: 'Log in', value: 'login', description: 'I have an account' },\n { label: 'Create account', value: 'signup', description: 'New to Liminal' },\n ],\n defaultIndex: 0,\n })\n const mode = modeResult ?? 'login'\n\n console.log()\n\n // Collect credentials\n const rl = createInterface({ input: stdin, output: stdout })\n let name = ''\n let email: string\n\n try {\n if (mode === 'signup') {\n name = (await rl.question(' \\x1b[1mName\\x1b[0m: ')).trim()\n if (!name) {\n console.error('\\n Error: Name is required.')\n process.exit(1)\n }\n }\n\n email = (await rl.question(' \\x1b[1mEmail\\x1b[0m: ')).trim()\n if (!email) {\n console.error('\\n Error: Email is required.')\n process.exit(1)\n }\n } finally {\n rl.close()\n }\n\n // Password (masked)\n const password = await passwordPrompt({ message: 'Password' })\n if (!password) {\n console.error('\\n Error: Password is required.')\n process.exit(1)\n }\n\n console.log()\n\n // Authenticate\n const action = mode === 'signup' ? 'Creating account' : 'Logging in'\n process.stdout.write(` ${action}... `)\n\n try {\n const auth = mode === 'signup'\n ? await signUp(email, password, name)\n : await signIn(email, password)\n\n console.log('OK')\n\n // Fetch or create API key\n process.stdout.write(' Setting up API key... ')\n const apiKey = await authenticateAndGetKey(auth)\n console.log('OK')\n\n // Save to config\n ensureDirectories()\n saveConfig({\n apiKey,\n apiBaseUrl: DEFAULTS.apiBaseUrl,\n })\n\n console.log()\n console.log(` Logged in as \\x1b[1m${auth.email}\\x1b[0m`)\n\n return apiKey\n } catch (err) {\n console.log('FAILED')\n const authErr = err as AuthError\n console.error(`\\n ${authErr.message}`)\n\n if (mode === 'login' && authErr.message?.includes('Invalid login')) {\n console.error(' Check your email and password, then try again.')\n }\n\n process.exit(1)\n }\n}\n","/**\n * Lightweight Supabase Auth client using fetch — zero npm dependencies.\n * Uses the public anon key (same as web frontend).\n */\nimport { randomBytes, createHash } from 'node:crypto'\n\nconst SUPABASE_URL = 'https://nzcneiyymvgxvttbenhp.supabase.co'\nconst SUPABASE_ANON_KEY =\n 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im56Y25laXl5bXZneHZ0dGJlbmhwIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQwNjQ0MjcsImV4cCI6MjA2OTY0MDQyN30.x3E-zGRadbPMmxRqT_PB_KOi00htKpgeb8GiQa4g2z0'\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface AuthResult {\n accessToken: string\n userId: string\n email: string\n}\n\nexport interface AuthError {\n message: string\n status?: number\n}\n\n// ─── Auth ────────────────────────────────────────────────────────────\n\nfunction supabaseHeaders(accessToken?: string): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'apikey': SUPABASE_ANON_KEY,\n }\n if (accessToken) {\n headers['Authorization'] = `Bearer ${accessToken}`\n }\n return headers\n}\n\n/**\n * Sign in with email and password.\n */\nexport async function signIn(email: string, password: string): Promise<AuthResult> {\n const res = await fetch(`${SUPABASE_URL}/auth/v1/token?grant_type=password`, {\n method: 'POST',\n headers: supabaseHeaders(),\n body: JSON.stringify({ email, password }),\n })\n\n const body = (await res.json()) as Record<string, any>\n\n if (!res.ok) {\n const msg = body?.error_description || body?.error || body?.msg || 'Authentication failed'\n const err: AuthError = { message: msg, status: res.status }\n throw err\n }\n\n return {\n accessToken: body.access_token,\n userId: body.user?.id,\n email: body.user?.email ?? email,\n }\n}\n\n/**\n * Sign up with email, password, and name.\n */\nexport async function signUp(\n email: string,\n password: string,\n name: string,\n): Promise<AuthResult> {\n const res = await fetch(`${SUPABASE_URL}/auth/v1/signup`, {\n method: 'POST',\n headers: supabaseHeaders(),\n body: JSON.stringify({\n email,\n password,\n data: { name },\n }),\n })\n\n const body = (await res.json()) as Record<string, any>\n\n if (!res.ok) {\n const msg = body?.error_description || body?.error || body?.msg || 'Sign up failed'\n const err: AuthError = { message: msg, status: res.status }\n throw err\n }\n\n // Supabase may return identities: [] if email confirmation is required\n if (body.user?.identities?.length === 0) {\n const err: AuthError = { message: 'Account already exists. Try logging in instead.' }\n throw err\n }\n\n return {\n accessToken: body.access_token,\n userId: body.user?.id,\n email: body.user?.email ?? email,\n }\n}\n\n// ─── API Key Management ──────────────────────────────────────────────\n\n/**\n * Check if the user already has an active API key.\n * Since only key_hash is stored (not plaintext), we can only check existence.\n */\nexport async function hasExistingKey(accessToken: string, userId: string): Promise<boolean> {\n const params = new URLSearchParams({\n user_id: `eq.${userId}`,\n is_active: 'eq.true',\n select: 'id',\n limit: '1',\n })\n\n const res = await fetch(`${SUPABASE_URL}/rest/v1/user_api_keys?${params}`, {\n headers: supabaseHeaders(accessToken),\n })\n\n if (!res.ok) return false\n\n const rows = await res.json()\n return Array.isArray(rows) && rows.length > 0\n}\n\n/**\n * Generate a new API key, store its SHA-256 hash in the database,\n * and return the plaintext key (only shown once).\n */\nexport async function createApiKey(accessToken: string, userId: string): Promise<string> {\n // Delete any existing keys to avoid unique constraint on (user_id, key_name)\n await fetch(`${SUPABASE_URL}/rest/v1/user_api_keys?user_id=eq.${userId}`, {\n method: 'DELETE',\n headers: supabaseHeaders(accessToken),\n })\n\n const apiKey = `lim_${randomBytes(32).toString('hex')}`\n const keyHash = createHash('sha256').update(apiKey).digest('hex')\n\n const res = await fetch(`${SUPABASE_URL}/rest/v1/user_api_keys`, {\n method: 'POST',\n headers: {\n ...supabaseHeaders(accessToken),\n 'Prefer': 'return=representation',\n },\n body: JSON.stringify({\n user_id: userId,\n key_name: 'Liminal CLI',\n key_hash: keyHash,\n is_active: true,\n }),\n })\n\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as Record<string, any>\n const msg = body?.message || body?.error || 'Failed to create API key'\n throw { message: msg, status: res.status } as AuthError\n }\n\n return apiKey\n}\n\n/**\n * Full login flow: authenticate then create API key.\n * Since only hashes are stored, we always generate a fresh key.\n * The plaintext is saved locally in ~/.liminal/config.json.\n */\nexport async function authenticateAndGetKey(\n auth: AuthResult,\n): Promise<string> {\n return createApiKey(auth.accessToken, auth.userId)\n}\n","/**\n * Claude Code connector.\n *\n * Claude Code reads the ANTHROPIC_BASE_URL environment variable to determine\n * where to send API requests. Setting this to Liminal's proxy address routes\n * all traffic through the compression pipeline.\n *\n * Protocol: Anthropic Messages API (POST /v1/messages)\n * Auth: x-api-key header (user's Anthropic API key)\n * Setup: Shell profile export — fully automatic\n */\n\nimport { execSync } from 'node:child_process'\nimport type { Connector, ConnectorInfo, ConnectorStatus, SetupResult, TeardownResult } from './types.js'\n\nconst ENV_VAR = 'ANTHROPIC_BASE_URL'\n\nconst INFO: ConnectorInfo = {\n id: 'claude-code',\n label: 'Claude Code',\n description: 'Anthropic CLI for coding with Claude',\n protocol: 'anthropic-messages',\n automatable: true,\n}\n\nfunction isClaudeInstalled(): boolean {\n try {\n execSync('which claude', { stdio: 'ignore' })\n return true\n } catch {\n return false\n }\n}\n\nfunction getCurrentBaseUrl(): string | undefined {\n return process.env[ENV_VAR] || undefined\n}\n\nexport const claudeCodeConnector: Connector = {\n info: INFO,\n\n async detect(): Promise<ConnectorStatus> {\n const installed = isClaudeInstalled()\n const currentUrl = getCurrentBaseUrl()\n const configured = currentUrl?.includes('127.0.0.1') ?? false\n\n if (!installed) {\n return { installed, configured: false, detail: 'Claude Code not found in PATH' }\n }\n\n if (configured) {\n return { installed, configured, detail: `Routing through ${currentUrl}` }\n }\n\n return { installed, configured, detail: 'Installed but not routing through Liminal' }\n },\n\n getShellExports(port: number): string[] {\n return [`export ${ENV_VAR}=http://127.0.0.1:${port}`]\n },\n\n async setup(port: number): Promise<SetupResult> {\n const exports = this.getShellExports(port)\n\n return {\n success: true,\n shellExports: exports,\n postSetupInstructions: [\n 'Claude Code will automatically route through Liminal.',\n 'Make sure to source your shell profile or restart your terminal.',\n ],\n }\n },\n\n async teardown(): Promise<TeardownResult> {\n return {\n success: true,\n manualSteps: [\n `Remove the line \\`export ${ENV_VAR}=...\\` from your shell profile (~/.zshrc or ~/.bashrc).`,\n 'Restart your terminal or run: unset ANTHROPIC_BASE_URL',\n ],\n }\n },\n}\n","/**\n * OpenAI Codex CLI connector.\n *\n * Codex CLI reads OPENAI_BASE_URL to override its API endpoint. It can also\n * be configured via ~/.codex/config.toml with a custom provider block.\n *\n * Protocol: OpenAI Responses API (POST /v1/responses) — this is the default\n * wire format. Chat completions is a secondary option via config.toml\n * (wire_api = \"chat_completions\") but Responses API is primary.\n * Auth: Authorization: Bearer header (user's OpenAI API key)\n * Setup: Shell profile export — fully automatic. Optional TOML config\n * for advanced users who want a named provider.\n */\n\nimport { execSync } from 'node:child_process'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { homedir } from 'node:os'\nimport type { Connector, ConnectorInfo, ConnectorStatus, SetupResult, TeardownResult } from './types.js'\n\nconst ENV_VAR = 'OPENAI_BASE_URL'\nconst CODEX_CONFIG_DIR = join(homedir(), '.codex')\nconst CODEX_CONFIG_FILE = join(CODEX_CONFIG_DIR, 'config.toml')\n\nconst INFO: ConnectorInfo = {\n id: 'codex',\n label: 'Codex CLI',\n description: 'OpenAI CLI agent for coding (Responses API)',\n protocol: 'openai-responses',\n automatable: true,\n}\n\nfunction isCodexInstalled(): boolean {\n try {\n execSync('which codex', { stdio: 'ignore' })\n return true\n } catch {\n return false\n }\n}\n\nfunction getCurrentBaseUrl(): string | undefined {\n return process.env[ENV_VAR] || undefined\n}\n\nfunction hasCodexConfig(): boolean {\n return existsSync(CODEX_CONFIG_FILE)\n}\n\nfunction codexConfigMentionsLiminal(): boolean {\n if (!hasCodexConfig()) return false\n try {\n const content = readFileSync(CODEX_CONFIG_FILE, 'utf-8')\n return content.includes('127.0.0.1') || content.includes('liminal')\n } catch {\n return false\n }\n}\n\nexport const codexConnector: Connector = {\n info: INFO,\n\n async detect(): Promise<ConnectorStatus> {\n const installed = isCodexInstalled()\n const currentUrl = getCurrentBaseUrl()\n const envConfigured = currentUrl?.includes('127.0.0.1') ?? false\n const tomlConfigured = codexConfigMentionsLiminal()\n const configured = envConfigured || tomlConfigured\n\n if (!installed) {\n return { installed, configured: false, detail: 'Codex CLI not found in PATH' }\n }\n\n if (configured) {\n const via = envConfigured ? ENV_VAR : 'config.toml'\n return { installed, configured, detail: `Routing through Liminal (via ${via})` }\n }\n\n return { installed, configured, detail: 'Installed but not routing through Liminal' }\n },\n\n getShellExports(port: number): string[] {\n // Codex expects base_url to include /v1\n return [`export ${ENV_VAR}=http://127.0.0.1:${port}/v1`]\n },\n\n async setup(port: number): Promise<SetupResult> {\n const exports = this.getShellExports(port)\n\n const instructions = [\n 'Codex CLI will automatically route through Liminal.',\n 'Make sure to source your shell profile or restart your terminal.',\n ]\n\n // Note about Responses API requirement\n instructions.push(\n 'Codex uses the OpenAI Responses API (/v1/responses) by default.',\n )\n\n return {\n success: true,\n shellExports: exports,\n postSetupInstructions: instructions,\n }\n },\n\n async teardown(): Promise<TeardownResult> {\n const steps = [\n `Remove the line \\`export ${ENV_VAR}=...\\` from your shell profile (~/.zshrc or ~/.bashrc).`,\n 'Restart your terminal or run: unset OPENAI_BASE_URL',\n ]\n\n if (codexConfigMentionsLiminal()) {\n steps.push(\n `Remove the Liminal provider block from ${CODEX_CONFIG_FILE}.`,\n )\n }\n\n return { success: true, manualSteps: steps }\n },\n}\n","/**\n * Cursor IDE connector.\n *\n * Uses a TLS MITM proxy approach: Cursor is launched with\n * --proxy-server=http://127.0.0.1:PORT\n * which routes ALL HTTPS traffic through our proxy. We intercept only\n * LLM API hosts (api.openai.com, api.anthropic.com, etc.) via CONNECT\n * + dynamic TLS certs signed by our local CA.\n *\n * This approach:\n * - Requires no GUI configuration changes in Cursor\n * - Works with all models (BYOK, Cursor-provided, any provider)\n * - Survives Cursor updates (Electron's --proxy-server is stable)\n * - Uses `liminal setup cursor` for one-command setup\n *\n * Protocol: OpenAI Chat Completions + Responses API (intercepted transparently)\n * Auth: User's own API keys (passed through to upstream providers)\n * Setup: Automated via `liminal setup cursor` (trust CA + launch with proxy flag)\n */\n\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { homedir } from 'node:os'\nimport type { Connector, ConnectorInfo, ConnectorStatus, SetupResult, TeardownResult } from './types.js'\n\nconst INFO: ConnectorInfo = {\n id: 'cursor',\n label: 'Cursor',\n description: 'AI-first code editor (proxy-based, automated)',\n protocol: 'openai-chat',\n automatable: true,\n}\n\n/** Platform-specific Cursor app paths */\nfunction getCursorPaths(): { app: string; data: string } {\n const platform = process.platform\n const home = homedir()\n\n if (platform === 'darwin') {\n return {\n app: '/Applications/Cursor.app',\n data: join(home, 'Library', 'Application Support', 'Cursor'),\n }\n }\n\n if (platform === 'win32') {\n const appData = process.env.APPDATA || join(home, 'AppData', 'Roaming')\n const localAppData = process.env.LOCALAPPDATA || join(home, 'AppData', 'Local')\n return {\n app: join(localAppData, 'Programs', 'Cursor', 'Cursor.exe'),\n data: join(appData, 'Cursor'),\n }\n }\n\n // Linux\n return {\n app: '/usr/bin/cursor',\n data: join(home, '.config', 'Cursor'),\n }\n}\n\nfunction isCursorInstalled(): boolean {\n const { app, data } = getCursorPaths()\n return existsSync(app) || existsSync(data)\n}\n\nfunction getSettingsDbPath(): string {\n const { data } = getCursorPaths()\n return join(data, 'User', 'globalStorage', 'state.vscdb')\n}\n\nexport const cursorConnector: Connector = {\n info: INFO,\n\n async detect(): Promise<ConnectorStatus> {\n const installed = isCursorInstalled()\n const dbExists = existsSync(getSettingsDbPath())\n\n if (!installed) {\n return { installed, configured: false, detail: 'Cursor not found on this system' }\n }\n\n // We can't reliably check if Cursor is configured to use Liminal\n // without reading the SQLite DB, which requires a sqlite3 dependency.\n // Report as installed but unknown configuration state.\n return {\n installed,\n configured: false,\n detail: dbExists\n ? 'Installed — configuration requires Cursor Settings GUI'\n : 'Installed but settings database not found',\n }\n },\n\n getShellExports(_port: number): string[] {\n // Cursor does not read env vars for its LLM base URL\n return []\n },\n\n async setup(port: number): Promise<SetupResult> {\n return {\n success: true,\n shellExports: [],\n postSetupInstructions: [\n 'Run the automated setup:',\n '',\n ' liminal setup cursor',\n '',\n 'This will:',\n ' 1. Generate and install a local CA certificate',\n ' 2. Launch Cursor with --proxy-server=http://127.0.0.1:' + port,\n '',\n 'All LLM API calls are transparently intercepted and compressed.',\n 'No Cursor settings changes needed — works with all models.',\n '',\n 'Or launch Cursor manually:',\n ` cursor --proxy-server=http://127.0.0.1:${port}`,\n ],\n }\n },\n\n async teardown(): Promise<TeardownResult> {\n return {\n success: true,\n manualSteps: [\n 'In Cursor Settings > Models:',\n ' 1. Disable \"Override OpenAI Base URL (when using key)\"',\n ' 2. Clear the base URL field',\n ' 3. Restart Cursor',\n ],\n }\n },\n}\n","/**\n * Generic OpenAI-compatible connector.\n *\n * Catch-all for any tool that speaks the OpenAI API format and reads\n * OPENAI_BASE_URL or OPENAI_API_BASE. This covers tools like:\n * - Aider, Continue, Cline, Copilot alternatives\n * - Custom scripts using the OpenAI SDK\n * - Any tool that respects OPENAI_BASE_URL\n *\n * Protocol: OpenAI Chat Completions (POST /v1/chat/completions)\n * Auth: Authorization: Bearer header\n * Setup: Shell profile export — fully automatic\n */\n\nimport type { Connector, ConnectorInfo, ConnectorStatus, SetupResult, TeardownResult } from './types.js'\n\nconst ENV_VAR = 'OPENAI_BASE_URL'\n\nconst INFO: ConnectorInfo = {\n id: 'openai-compatible',\n label: 'Other / OpenAI-compatible',\n description: 'Any tool that reads OPENAI_BASE_URL',\n protocol: 'openai-chat',\n automatable: true,\n}\n\nfunction getCurrentBaseUrl(): string | undefined {\n return process.env[ENV_VAR] || undefined\n}\n\nexport const openaiCompatibleConnector: Connector = {\n info: INFO,\n\n async detect(): Promise<ConnectorStatus> {\n const currentUrl = getCurrentBaseUrl()\n const configured = currentUrl?.includes('127.0.0.1') ?? false\n\n return {\n installed: true, // Generic — always \"available\"\n configured,\n detail: configured\n ? `OPENAI_BASE_URL → ${currentUrl}`\n : 'OPENAI_BASE_URL not set to Liminal',\n }\n },\n\n getShellExports(port: number): string[] {\n return [`export ${ENV_VAR}=http://127.0.0.1:${port}/v1`]\n },\n\n async setup(port: number): Promise<SetupResult> {\n const exports = this.getShellExports(port)\n\n return {\n success: true,\n shellExports: exports,\n postSetupInstructions: [\n 'Any tool that reads OPENAI_BASE_URL will route through Liminal.',\n 'Make sure to source your shell profile or restart your terminal.',\n '',\n 'If your tool uses a different env var (e.g., OPENAI_API_BASE),',\n `set it to: http://127.0.0.1:${port}/v1`,\n ],\n }\n },\n\n async teardown(): Promise<TeardownResult> {\n return {\n success: true,\n manualSteps: [\n `Remove the line \\`export ${ENV_VAR}=...\\` from your shell profile (~/.zshrc or ~/.bashrc).`,\n 'Restart your terminal or run: unset OPENAI_BASE_URL',\n ],\n }\n },\n}\n","/**\n * Connector registry — maps tool IDs to their connector implementations.\n */\n\nimport { claudeCodeConnector } from './claude-code.js'\nimport { codexConnector } from './codex.js'\nimport { cursorConnector } from './cursor.js'\nimport { openaiCompatibleConnector } from './openai-compatible.js'\nimport type { Connector, ConnectorId } from './types.js'\n\n/** All registered connectors in display order */\nexport const CONNECTORS: readonly Connector[] = [\n claudeCodeConnector,\n codexConnector,\n cursorConnector,\n openaiCompatibleConnector,\n]\n\n/** Lookup a connector by its tool ID */\nexport function getConnector(id: ConnectorId): Connector {\n const connector = CONNECTORS.find((c) => c.info.id === id)\n if (!connector) {\n throw new Error(`Unknown connector: ${id}`)\n }\n return connector\n}\n\n/** Get connectors for a list of tool IDs */\nexport function getConnectors(ids: ConnectorId[]): Connector[] {\n return ids.map(getConnector)\n}\n\n/** Detect which tools are installed on this system */\nexport async function detectInstalledTools(): Promise<Map<ConnectorId, Connector>> {\n const results = await Promise.all(\n CONNECTORS.map(async (c) => {\n const status = await c.detect()\n return { connector: c, status }\n }),\n )\n\n const installed = new Map<ConnectorId, Connector>()\n for (const { connector, status } of results) {\n if (status.installed) {\n installed.set(connector.info.id, connector)\n }\n }\n\n return installed\n}\n\n// Re-export types for convenience\nexport type { Connector, ConnectorId, ConnectorInfo, ConnectorStatus, SetupResult, TeardownResult } from './types.js'\n","import { saveConfig, ensureDirectories } from '../config/loader.js'\nimport { DEFAULTS } from '../config/schema.js'\nimport { CONFIG_FILE } from '../config/paths.js'\nimport {\n detectShellProfile,\n appendToShellProfile,\n lineExistsInFile,\n} from '../config/shell.js'\nimport { printBanner } from '../version.js'\nimport { multiSelectPrompt, selectPrompt } from '../ui/prompts.js'\nimport { runAuthFlow } from './login.js'\nimport { CONNECTORS, getConnectors } from '../connectors/index.js'\nimport type { ConnectorId } from '../connectors/types.js'\nimport type { Tool } from '../types.js'\n\n// ─── ANSI helpers ────────────────────────────────────────────────────\nconst BOLD = '\\x1b[1m'\nconst DIM = '\\x1b[2m'\nconst CYAN = '\\x1b[36m'\nconst GREEN = '\\x1b[32m'\nconst YELLOW = '\\x1b[33m'\nconst RESET = '\\x1b[0m'\n\nexport async function initCommand(): Promise<void> {\n printBanner()\n console.log(' Welcome to Liminal -- Your Transparency & Context Partner')\n console.log()\n console.log(\" Let's start evolving.\")\n console.log()\n\n // ── 1. Authenticate ───────────────────────────────────────────\n const apiKey = await runAuthFlow()\n console.log()\n\n // ── 2. Port (use default, configurable via `liminal config --set port=XXXX`) ──\n const port = DEFAULTS.port\n\n // ── 3. Tool detection ─────────────────────────────────────────\n console.log(` ${BOLD}Detecting installed tools...${RESET}`)\n console.log()\n const detectionResults = await Promise.all(\n CONNECTORS.map(async (c) => {\n const status = await c.detect()\n return { connector: c, status }\n }),\n )\n\n for (const { connector, status } of detectionResults) {\n const icon = status.installed ? `${GREEN}✓${RESET}` : `${DIM}·${RESET}`\n console.log(` ${icon} ${connector.info.label} ${DIM}${status.detail}${RESET}`)\n }\n console.log()\n\n // ── 4. Tool selection ─────────────────────────────────────────\n const toolOptions = CONNECTORS.map((c) => {\n const detected = detectionResults.find((r) => r.connector.info.id === c.info.id)\n const installed = detected?.status.installed ?? false\n\n let description = c.info.description\n if (!installed) description += ` ${DIM}(not detected)${RESET}`\n if (!c.info.automatable) description += ` ${DIM}(manual setup)${RESET}`\n\n return {\n label: c.info.label,\n value: c.info.id as ConnectorId,\n description,\n default: c.info.id === 'claude-code' && installed,\n }\n })\n\n const toolsResult = await multiSelectPrompt<ConnectorId>({\n message: 'Which AI tools will you use with Liminal?',\n options: toolOptions,\n })\n const selectedIds: ConnectorId[] = toolsResult ?? ['claude-code']\n\n console.log()\n\n // ── 5. Response learning ──────────────────────────────────────\n const learnResult = await selectPrompt<boolean>({\n message: 'Learn from LLM responses?',\n options: [\n { label: 'Yes', value: true, description: 'Improve compression over time' },\n { label: 'No', value: false, description: 'Skip response learning' },\n ],\n defaultIndex: 0,\n })\n const learnFromResponses = learnResult ?? true\n\n console.log()\n\n // ── 6. Save config ────────────────────────────────────────────\n ensureDirectories()\n saveConfig({\n apiKey,\n apiBaseUrl: DEFAULTS.apiBaseUrl,\n upstreamBaseUrl: DEFAULTS.upstreamBaseUrl,\n anthropicUpstreamUrl: DEFAULTS.anthropicUpstreamUrl,\n port,\n learnFromResponses,\n tools: selectedIds as Tool[],\n compressionThreshold: DEFAULTS.compressionThreshold,\n compressRoles: DEFAULTS.compressRoles,\n latencyBudgetMs: DEFAULTS.latencyBudgetMs,\n enabled: DEFAULTS.enabled,\n })\n\n console.log(` ${GREEN}✓${RESET} Configuration saved to ${DIM}${CONFIG_FILE}${RESET}`)\n console.log()\n\n // ── 7. Per-connector setup ────────────────────────────────────\n // Each selected tool gets its own visible setup section so the user\n // can see exactly what's being configured for every tool they chose.\n\n const connectors = getConnectors(selectedIds)\n const allShellExports: string[] = []\n const profile = detectShellProfile()\n\n console.log(` ${BOLD}Configuring ${connectors.length} tool${connectors.length > 1 ? 's' : ''}...${RESET}`)\n\n for (const connector of connectors) {\n const result = await connector.setup(port)\n const protocol = connector.info.protocol === 'anthropic-messages'\n ? 'Anthropic Messages API'\n : connector.info.protocol === 'openai-responses'\n ? 'Responses API'\n : 'Chat Completions API'\n\n console.log()\n console.log(` ${CYAN}── ${connector.info.label} ${RESET}${DIM}(${protocol})${RESET}`)\n\n if (connector.info.automatable && result.shellExports.length > 0) {\n // Automatable: show the env var(s) being set\n for (const line of result.shellExports) {\n console.log(` ${GREEN}✓${RESET} ${line}`)\n }\n allShellExports.push(...result.shellExports)\n }\n\n // Show all setup instructions for this connector\n for (const line of result.postSetupInstructions) {\n if (line === '') {\n console.log()\n } else {\n // Skip generic \"source your shell\" messages — we handle that globally below\n if (line.includes('source your shell profile') || line.includes('restart your terminal')) continue\n if (line.includes('will automatically route through Liminal')) {\n console.log(` ${DIM}${line}${RESET}`)\n } else if (line.startsWith(' ')) {\n // Indented instructions (e.g., Cursor numbered steps)\n console.log(` ${line}`)\n } else {\n console.log(` ${line}`)\n }\n }\n }\n\n // Show manual setup badge for non-automatable connectors\n if (!connector.info.automatable) {\n console.log(` ${YELLOW}⚠ Requires manual configuration (see steps above)${RESET}`)\n }\n }\n\n // ── 8. Shell auto-configuration ───────────────────────────────\n // Deduplicate (codex + openai-compatible both set OPENAI_BASE_URL)\n const uniqueExports = [...new Set(allShellExports)]\n\n if (uniqueExports.length > 0 && profile) {\n const allExist = uniqueExports.every((line) => lineExistsInFile(profile.path, line))\n\n console.log()\n if (allExist) {\n console.log(` ${GREEN}✓${RESET} Shell already configured in ${profile.name}`)\n } else {\n const autoResult = await selectPrompt<boolean>({\n message: `Add proxy exports to ${profile.name}?`,\n options: [\n { label: 'Yes', value: true, description: 'Automatic shell configuration' },\n { label: 'No', value: false, description: \"I'll set it up manually\" },\n ],\n defaultIndex: 0,\n })\n\n if (autoResult === true) {\n const added = appendToShellProfile(profile, uniqueExports)\n if (added.length > 0) {\n console.log()\n console.log(` ${GREEN}✓${RESET} Added to ${profile.name}`)\n console.log()\n console.log(` Run ${BOLD}source ${profile.name}${RESET} or restart your terminal.`)\n }\n } else {\n console.log()\n console.log(' Add these to your shell profile:')\n console.log()\n for (const line of uniqueExports) {\n console.log(` ${CYAN}${line}${RESET}`)\n }\n }\n }\n } else if (uniqueExports.length > 0) {\n // No shell profile detected\n console.log()\n console.log(' Add these to your shell profile:')\n console.log()\n for (const line of uniqueExports) {\n console.log(` ${CYAN}${line}${RESET}`)\n }\n }\n\n // ── 9. Done ───────────────────────────────────────────────────\n console.log()\n console.log(` ${BOLD}Setup complete!${RESET}`)\n console.log()\n console.log(' Next step:')\n console.log(` ${BOLD}liminal start${RESET}`)\n console.log()\n}\n","import { saveConfig, isConfigured } from '../config/loader.js'\n\nexport async function logoutCommand(): Promise<void> {\n if (!isConfigured()) {\n console.log(' Not currently logged in.')\n return\n }\n\n saveConfig({ apiKey: '' })\n console.log(' Logged out.')\n console.log(' Run \\x1b[1mliminal login\\x1b[0m to reconnect.')\n}\n","import * as http from 'node:http'\nimport { RSCCircuitOpenError } from '@cognisos/rsc-sdk'\nimport { compressConversation, type ConversationCompressOptions } from '../rsc/message-compressor.js'\nimport { analyzeConversation } from '../rsc/conversation-analyzer.js'\nimport { createStreamLearningBuffer } from '../rsc/learning.js'\nimport { pipeSSEResponse } from './streaming.js'\nimport type { RSCPipelineWrapper } from '../rsc/pipeline.js'\nimport type { ChatCompletionRequest, ResolvedConfig } from '../types.js'\nimport { formatTiersLog, formatSavedLog, formatDegradeLog, formatResponseLog } from '../terminology.js'\nimport type { Logger } from './handler.js'\nimport type { Semaphore } from '../rsc/semaphore.js'\nimport type { LatencyMonitor } from '../rsc/latency-monitor.js'\n\nfunction setCORSHeaders(res: http.ServerResponse): void {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')\n}\n\nfunction sendJSON(res: http.ServerResponse, status: number, body: unknown): void {\n setCORSHeaders(res)\n res.writeHead(status, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(body))\n}\n\n/**\n * Extract the bearer token from the Authorization header.\n * This is the user's LLM API key — used to forward to the upstream LLM.\n */\nfunction extractBearerToken(req: http.IncomingMessage): string | null {\n const auth = req.headers.authorization\n if (!auth || !auth.startsWith('Bearer ')) return null\n return auth.slice(7)\n}\n\nexport async function handleChatCompletions(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: unknown,\n pipeline: RSCPipelineWrapper,\n config: ResolvedConfig,\n logger: Logger,\n semaphore: Semaphore,\n latencyMonitor: LatencyMonitor,\n sessionKey: string,\n): Promise<void> {\n const request = body as ChatCompletionRequest\n\n // Validate required fields\n if (!request.messages || !Array.isArray(request.messages)) {\n sendJSON(res, 400, {\n error: { message: 'messages is required and must be an array', type: 'invalid_request_error' },\n })\n return\n }\n\n // Extract LLM API key from the incoming request\n const llmApiKey = extractBearerToken(req)\n if (!llmApiKey) {\n sendJSON(res, 401, {\n error: { message: 'Authorization header with Bearer token is required', type: 'authentication_error' },\n })\n return\n }\n\n // Compress messages (or passthrough if circuit is open / disabled)\n let messages = request.messages\n let anyCompressed = false\n let totalTokensSaved = 0\n\n if (config.enabled && !pipeline.isCircuitOpen()) {\n const compressStart = Date.now()\n try {\n const compressRoles = new Set(config.compressRoles)\n\n const plan = analyzeConversation(request.messages, {\n hotFraction: config.hotFraction,\n coldFraction: config.coldFraction,\n aggregateThreshold: config.aggregateThreshold,\n compressRoles,\n compressToolResults: config.compressToolResults,\n })\n\n if (plan.shouldCompress) {\n logger.log(formatTiersLog(plan.hotCount, plan.warmCount, plan.coldCount, plan.totalEligibleTokens))\n }\n\n const result = await compressConversation(\n pipeline.pipeline,\n pipeline.session,\n plan,\n {\n compressToolResults: config.compressToolResults,\n compressionThreshold: config.compressionThreshold,\n logFn: (msg) => logger.log(msg),\n semaphore,\n semaphoreTimeoutMs: config.concurrencyTimeoutMs,\n },\n )\n messages = result.messages\n anyCompressed = result.anyCompressed\n totalTokensSaved = result.totalTokensSaved\n\n const latencyMs = Date.now() - compressStart\n const alert = latencyMonitor.record(sessionKey, latencyMs)\n if (alert) {\n logger.log(`[LATENCY] ${alert.type.toUpperCase()}: ${alert.message}`)\n }\n\n if (result.totalTokensSaved > 0) {\n logger.log(formatSavedLog(result.totalTokensSaved, latencyMs))\n }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n logger.log(formatDegradeLog())\n } else {\n logger.log(`[ERROR] Compression failed: ${err instanceof Error ? err.message : String(err)}`)\n }\n // Fall through with original messages\n messages = request.messages\n }\n }\n\n // Build upstream request\n const upstreamUrl = `${config.upstreamBaseUrl}/v1/chat/completions`\n const upstreamBody = { ...request, messages }\n\n const upstreamHeaders: Record<string, string> = {\n 'Authorization': `Bearer ${llmApiKey}`,\n 'Content-Type': 'application/json',\n }\n\n // Forward streaming preference\n if (request.stream) {\n upstreamHeaders['Accept'] = 'text/event-stream'\n }\n\n try {\n const upstreamResponse = await fetch(upstreamUrl, {\n method: 'POST',\n headers: upstreamHeaders,\n body: JSON.stringify(upstreamBody),\n })\n\n // Handle upstream errors\n if (!upstreamResponse.ok) {\n const errorBody = await upstreamResponse.text()\n setCORSHeaders(res)\n res.writeHead(upstreamResponse.status, {\n 'Content-Type': upstreamResponse.headers.get('Content-Type') || 'application/json',\n })\n res.end(errorBody)\n return\n }\n\n // Streaming response\n if (request.stream && upstreamResponse.body) {\n const learningBuffer = anyCompressed\n ? createStreamLearningBuffer(pipeline.pipeline)\n : null\n\n logger.log(formatResponseLog(request.model, totalTokensSaved, true))\n await pipeSSEResponse(\n upstreamResponse,\n res,\n (text) => learningBuffer?.append(text),\n () => learningBuffer?.flush(),\n totalTokensSaved,\n )\n return\n }\n\n // Non-streaming response\n const responseBody = await upstreamResponse.text()\n logger.log(formatResponseLog(request.model, totalTokensSaved))\n\n // Adjust usage to reflect pre-compression token count\n let finalBody = responseBody\n if (totalTokensSaved > 0) {\n try {\n const parsed = JSON.parse(responseBody)\n if (parsed?.usage?.prompt_tokens != null) {\n parsed.usage.prompt_tokens += totalTokensSaved\n if (parsed.usage.total_tokens != null) {\n parsed.usage.total_tokens += totalTokensSaved\n }\n finalBody = JSON.stringify(parsed)\n logger.log(`[TOKENS] Adjusted prompt_tokens by +${totalTokensSaved}`)\n }\n } catch {\n // Pass through unmodified on parse error\n }\n }\n\n setCORSHeaders(res)\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(finalBody)\n\n // Trigger learning from response (fire-and-forget, uses original body)\n if (anyCompressed) {\n try {\n const parsed = JSON.parse(responseBody)\n const content = parsed?.choices?.[0]?.message?.content\n if (typeof content === 'string' && content.length > 0) {\n pipeline.pipeline.triggerLearning(content)\n }\n } catch {\n // Ignore learning parse errors\n }\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n logger.log(`[ERROR] Upstream request failed: ${message}`)\n if (!res.headersSent) {\n sendJSON(res, 502, {\n error: { message: `Failed to reach upstream LLM: ${message}`, type: 'server_error' },\n })\n }\n }\n}\n","import type { CompressionPipeline, Session } from '@cognisos/rsc-sdk'\nimport { RSCCircuitOpenError } from '@cognisos/rsc-sdk'\nimport type { ChatCompletionMessage, ContentPart } from '../types.js'\nimport { segmentContent } from './content-segmenter.js'\nimport type { ConversationPlan } from './conversation-analyzer.js'\nimport type { Semaphore } from './semaphore.js'\n\nexport interface CompressedMessagesResult {\n messages: ChatCompletionMessage[]\n anyCompressed: boolean\n totalTokensSaved: number\n}\n\n/** Content block types that must never be modified. */\nconst PASSTHROUGH_BLOCK_TYPES = new Set(['thinking', 'tool_use', 'image'])\n\n/**\n * Sanitize text returned from RSC decompress to remove characters that\n * would break JSON serialization (lone surrogates, control chars except\n * newlines/tabs). This prevents \"Invalid character\" errors on upstream fetch.\n */\nfunction sanitizeCompressedText(text: string): string {\n // eslint-disable-next-line no-control-regex\n return text.replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]/g, '')\n}\n\ntype RecordFn = (compressed: boolean, saved: number) => void\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Legacy per-message compression (kept for backward compatibility).\n * Callers should prefer compressConversation() for tier-aware compression.\n */\nexport async function compressMessages(\n messages: ChatCompletionMessage[],\n pipeline: CompressionPipeline,\n session: Session,\n compressRoles: Set<string>,\n): Promise<CompressedMessagesResult> {\n let anyCompressed = false\n let totalTokensSaved = 0\n\n const compressed = await Promise.all(\n messages.map(async (msg) => {\n if (!compressRoles.has(msg.role)) return msg\n return compressMessage(msg, pipeline, session, (c, saved) => {\n anyCompressed = anyCompressed || c\n totalTokensSaved += saved\n })\n }),\n )\n\n return { messages: compressed, anyCompressed, totalTokensSaved }\n}\n\n/**\n * Tier-aware conversation compression with per-message text batching.\n *\n * - HOT messages pass through verbatim (zero latency).\n * - WARM and COLD messages have all eligible text extracted, concatenated,\n * and compressed in a single API call per message. This avoids many\n * sub-threshold skips when messages contain multiple small blocks.\n * - If the plan says shouldCompress=false, everything passes through.\n */\nexport interface ConversationCompressOptions {\n compressToolResults: boolean\n /** Minimum token count for compression (blocks below this are skipped). */\n compressionThreshold?: number\n /** Optional callback for block-level diagnostic logging */\n logFn?: (msg: string) => void\n /** Optional semaphore to limit concurrent RSC API calls across sessions */\n semaphore?: Semaphore\n /** Timeout for semaphore acquire (ms). Defaults to 15000. */\n semaphoreTimeoutMs?: number\n}\n\nexport async function compressConversation(\n pipeline: CompressionPipeline,\n session: Session,\n plan: ConversationPlan,\n options: ConversationCompressOptions = { compressToolResults: true },\n): Promise<CompressedMessagesResult> {\n // Fast path: aggregate threshold not met\n if (!plan.shouldCompress) {\n return {\n messages: plan.messages.map((tm) => tm.message),\n anyCompressed: false,\n totalTokensSaved: 0,\n }\n }\n\n let anyCompressed = false\n let totalTokensSaved = 0\n\n const record: RecordFn = (c, saved) => {\n anyCompressed = anyCompressed || c\n totalTokensSaved += saved\n }\n\n const log = options.logFn\n const threshold = options.compressionThreshold ?? 100\n\n // Build output array indexed by original position\n const results: ChatCompletionMessage[] = new Array(plan.messages.length)\n\n // Separate blocks into passthrough vs compressible\n const compressible: Array<{ planIdx: number; tm: typeof plan.messages[0] }> = []\n\n for (let i = 0; i < plan.messages.length; i++) {\n const tm = plan.messages[i]\n const role = tm.message.role\n const blockTypes = Array.isArray(tm.message.content)\n ? (tm.message.content as ContentPart[]).map((b) => b.type).join(',')\n : 'string'\n\n // HOT: always verbatim\n if (tm.tier === 'hot') {\n log?.(`[BLOCK] #${tm.index} ${role} [${blockTypes}] → HOT (verbatim)`)\n results[i] = tm.message\n continue\n }\n\n // WARM / COLD with no eligible tokens: skip\n if (tm.eligibleTokens === 0) {\n log?.(`[BLOCK] #${tm.index} ${role} [${blockTypes}] → ${tm.tier.toUpperCase()} (0 eligible tok, skip)`)\n results[i] = tm.message\n continue\n }\n\n // Pre-filter: estimate prose tokens after code segmentation.\n // If the actual compressible prose is below threshold, skip\n // without making an API call (avoids wasting latency budget).\n const proseEstimate = estimateProseTokens(tm.message, options.compressToolResults)\n if (proseEstimate < threshold) {\n log?.(`[BLOCK] #${tm.index} ${role} [${blockTypes}] → ${tm.tier.toUpperCase()} (${proseEstimate} prose tok after segmentation < ${threshold} threshold, skip)`)\n results[i] = tm.message\n continue\n }\n\n log?.(`[BLOCK] #${tm.index} ${role} [${blockTypes}] → ${tm.tier.toUpperCase()} (${tm.eligibleTokens} eligible tok, ~${proseEstimate} prose tok, compressing)`)\n compressible.push({ planIdx: i, tm })\n }\n\n // Sort by eligible tokens descending — largest blocks get first\n // crack at the latency budget for maximum token savings.\n compressible.sort((a, b) => b.tm.eligibleTokens - a.tm.eligibleTokens)\n\n // Process sequentially in priority order so the latency budget\n // is spent on the highest-value blocks first.\n for (const { planIdx, tm } of compressible) {\n results[planIdx] = await batchCompressMessage(tm.message, pipeline, session, record, options)\n }\n\n return { messages: results, anyCompressed, totalTokensSaved }\n}\n\n// ---------------------------------------------------------------------------\n// Pre-filtering: estimate compressible prose tokens\n// ---------------------------------------------------------------------------\n\n/**\n * Estimate how many tokens of prose (non-code) content a message contains\n * AFTER code-block segmentation. This lets us skip messages whose eligible\n * content is mostly code — avoiding a wasted API call that would just\n * return \"below threshold\" and eat into the latency budget.\n *\n * Uses chars/4 as a rough token estimate (good enough for filtering).\n */\nfunction estimateProseTokens(msg: ChatCompletionMessage, compressToolResults: boolean): number {\n const text = extractCompressibleText(msg, compressToolResults)\n if (!text) return 0\n\n const segments = segmentContent(text)\n return segments\n .filter((s) => s.type === 'prose')\n .reduce((sum, s) => sum + Math.ceil(s.text.length / 4), 0)\n}\n\n/**\n * Extract all compressible text from a message (same logic as\n * batchCompressMessage uses) without actually compressing anything.\n */\nfunction extractCompressibleText(msg: ChatCompletionMessage, compressToolResults: boolean): string | null {\n if (typeof msg.content === 'string') {\n return msg.content.trim() ? msg.content : null\n }\n\n if (!Array.isArray(msg.content)) return null\n\n const parts = msg.content as ContentPart[]\n const textSegments: string[] = []\n\n for (const part of parts) {\n if (PASSTHROUGH_BLOCK_TYPES.has(part.type)) continue\n\n if (part.type === 'text' && typeof part.text === 'string' && part.text.trim()) {\n textSegments.push(part.text)\n }\n\n if (part.type === 'tool_result' && compressToolResults) {\n const extracted = extractToolResultText(part)\n if (extracted) textSegments.push(extracted)\n }\n }\n\n return textSegments.length > 0 ? textSegments.join('\\n\\n') : null\n}\n\n// ---------------------------------------------------------------------------\n// Batch compression\n// ---------------------------------------------------------------------------\n\n/**\n * Extract all text from a tool_result block's content.\n * Returns null if no compressible text is found.\n */\nfunction extractToolResultText(part: ContentPart): string | null {\n if (typeof part.content === 'string' && part.content.trim()) {\n return part.content\n }\n if (Array.isArray(part.content)) {\n const texts = (part.content as ContentPart[])\n .filter((inner) => inner.type === 'text' && typeof inner.text === 'string' && (inner.text as string).trim())\n .map((inner) => inner.text as string)\n return texts.length > 0 ? texts.join('\\n') : null\n }\n return null\n}\n\n/**\n * Batch-compress all eligible text from a message into a single API call.\n *\n * Instead of compressing each text/tool_result block individually (which\n * results in many sub-threshold skips for small blocks), this:\n * 1. Extracts all eligible text from the message's content blocks\n * 2. Concatenates into a single string\n * 3. Makes ONE compressForLLM() call\n * 4. Places the compressed result as a text block, clears text from\n * batched blocks while preserving structure (tool_use_id pairing)\n */\nasync function batchCompressMessage(\n msg: ChatCompletionMessage,\n pipeline: CompressionPipeline,\n session: Session,\n record: RecordFn,\n options: ConversationCompressOptions = { compressToolResults: true },\n): Promise<ChatCompletionMessage> {\n // String content: compress directly (already one block)\n if (typeof msg.content === 'string') {\n return compressStringContent(msg, pipeline, session, record, options.semaphore, options.semaphoreTimeoutMs)\n }\n\n if (!Array.isArray(msg.content)) return msg\n\n const parts = msg.content as ContentPart[]\n\n // Collect all eligible text and track which parts contributed\n const textSegments: string[] = []\n const batchedIndices = new Set<number>()\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]\n if (PASSTHROUGH_BLOCK_TYPES.has(part.type)) continue\n\n if (part.type === 'text' && typeof part.text === 'string' && part.text.trim()) {\n textSegments.push(part.text)\n batchedIndices.add(i)\n }\n\n if (part.type === 'tool_result' && options.compressToolResults) {\n const extracted = extractToolResultText(part)\n if (extracted) {\n textSegments.push(extracted)\n batchedIndices.add(i)\n }\n }\n }\n\n // Nothing to compress\n if (textSegments.length === 0) return msg\n\n // Concatenate all eligible text into one batch\n const batchText = textSegments.join('\\n\\n')\n\n try {\n const compressed = await compressTextWithSegmentation(batchText, pipeline, session, record, options.semaphore, options.semaphoreTimeoutMs)\n\n // Rebuild content array in-place to preserve block ordering.\n // The Anthropic API requires tool_result blocks to appear in the\n // same position (immediately after the corresponding tool_use\n // message). We MUST NOT prepend, append, remove, or reorder blocks.\n //\n // Strategy: put the compressed batch into the first eligible block,\n // clear text in remaining batched blocks, keep everything else as-is.\n // Build the output content array in-place.\n // - First eligible block gets the full compressed batch text.\n // - Remaining batched text blocks are REMOVED (API rejects empty text blocks).\n // - Remaining batched tool_result blocks keep structure with cleared content\n // (tool_use_id pairing must be preserved).\n // - Non-batched blocks (passthrough, non-eligible) are kept as-is.\n const newParts: ContentPart[] = []\n let isFirstEligible = true\n\n for (let i = 0; i < parts.length; i++) {\n if (!batchedIndices.has(i)) {\n // Not batched — keep as-is\n newParts.push(parts[i])\n continue\n }\n\n if (isFirstEligible) {\n // First eligible block gets the compressed text\n if (parts[i].type === 'text') {\n newParts.push({ ...parts[i], text: compressed })\n } else if (parts[i].type === 'tool_result') {\n newParts.push({ ...parts[i], content: compressed })\n }\n isFirstEligible = false\n } else {\n // Remaining batched blocks:\n // - text blocks: drop entirely (API rejects empty text blocks)\n // - tool_result: keep with empty content (preserves tool_use_id pairing)\n if (parts[i].type === 'tool_result') {\n newParts.push({ ...parts[i], content: '' })\n }\n // text blocks are simply not pushed — removed from the array\n }\n }\n\n return { ...msg, content: newParts }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n session.recordFailure()\n throw err\n }\n session.recordFailure()\n return msg\n }\n}\n\n// ---------------------------------------------------------------------------\n// Per-block helpers (used by legacy compressMessages path)\n// ---------------------------------------------------------------------------\n\n/**\n * Compress a single message's content, handling both string and array forms.\n */\nasync function compressMessage(\n msg: ChatCompletionMessage,\n pipeline: CompressionPipeline,\n session: Session,\n record: RecordFn,\n options: ConversationCompressOptions = { compressToolResults: true },\n): Promise<ChatCompletionMessage> {\n if (typeof msg.content === 'string') {\n return compressStringContent(msg, pipeline, session, record)\n }\n\n if (Array.isArray(msg.content)) {\n return compressArrayContent(msg, pipeline, session, record, options)\n }\n\n return msg\n}\n\n/**\n * Compress plain-string message content with code-block segmentation.\n */\nasync function compressStringContent(\n msg: ChatCompletionMessage,\n pipeline: CompressionPipeline,\n session: Session,\n record: RecordFn,\n semaphore?: Semaphore,\n semaphoreTimeoutMs?: number,\n): Promise<ChatCompletionMessage> {\n const text = msg.content as string\n try {\n const compressed = await compressTextWithSegmentation(text, pipeline, session, record, semaphore, semaphoreTimeoutMs)\n return { ...msg, content: compressed }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n session.recordFailure()\n throw err\n }\n session.recordFailure()\n return msg\n }\n}\n\n/**\n * Compress array content blocks (text, tool_result). Skips thinking, tool_use, image.\n * Used by the legacy compressMessages() path.\n */\nasync function compressArrayContent(\n msg: ChatCompletionMessage,\n pipeline: CompressionPipeline,\n session: Session,\n record: RecordFn,\n options: ConversationCompressOptions = { compressToolResults: true },\n): Promise<ChatCompletionMessage> {\n const parts = msg.content as ContentPart[]\n\n const compressedParts = await Promise.all(\n parts.map(async (part) => {\n // Skip blocks that must not be modified\n if (PASSTHROUGH_BLOCK_TYPES.has(part.type)) return part\n\n // text block\n if (part.type === 'text' && typeof part.text === 'string') {\n try {\n const compressed = await compressTextWithSegmentation(part.text, pipeline, session, record)\n return { ...part, text: compressed }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n session.recordFailure()\n throw err\n }\n session.recordFailure()\n return part\n }\n }\n\n // tool_result block — compress if enabled\n if (part.type === 'tool_result' && options.compressToolResults) {\n return compressToolResult(part, pipeline, session, record)\n }\n\n // Unknown block type or disabled tool_result — pass through\n return part\n }),\n )\n\n return { ...msg, content: compressedParts }\n}\n\n/**\n * Compress text content within a tool_result block.\n * tool_result.content can be a plain string or an array of content blocks.\n * Used by the legacy compressMessages() path.\n */\nasync function compressToolResult(\n part: ContentPart,\n pipeline: CompressionPipeline,\n session: Session,\n record: RecordFn,\n): Promise<ContentPart> {\n const content = part.content\n\n // String content\n if (typeof content === 'string') {\n try {\n const compressed = await compressTextWithSegmentation(content, pipeline, session, record)\n return { ...part, content: compressed }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n session.recordFailure()\n throw err\n }\n session.recordFailure()\n return part\n }\n }\n\n // Nested content blocks (e.g. [{type:\"text\", text:\"...\"}])\n if (Array.isArray(content)) {\n try {\n const compressedInner = await Promise.all(\n (content as ContentPart[]).map(async (inner) => {\n if (inner.type === 'text' && typeof inner.text === 'string') {\n try {\n const compressed = await compressTextWithSegmentation(inner.text, pipeline, session, record)\n return { ...inner, text: compressed }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) throw err\n session.recordFailure()\n return inner\n }\n }\n return inner\n }),\n )\n return { ...part, content: compressedInner }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n session.recordFailure()\n throw err\n }\n session.recordFailure()\n return part\n }\n }\n\n return part\n}\n\n/**\n * Compress a text string, preserving code blocks verbatim.\n * When a semaphore is provided, each compressForLLM() call acquires a permit\n * first — this limits concurrent RSC API calls across all sessions.\n */\nasync function compressTextWithSegmentation(\n text: string,\n pipeline: CompressionPipeline,\n session: Session,\n record: RecordFn,\n semaphore?: Semaphore,\n semaphoreTimeoutMs?: number,\n): Promise<string> {\n const segments = segmentContent(text)\n const hasCode = segments.some((s) => s.type === 'code')\n\n if (!hasCode) {\n if (semaphore) await semaphore.acquire(semaphoreTimeoutMs)\n try {\n const result = await pipeline.compressForLLM(text)\n session.recordCompression(result.metrics)\n const saved = Math.max(0, result.metrics.tokensSaved)\n record(!result.metrics.skipped, saved)\n return sanitizeCompressedText(result.text)\n } finally {\n if (semaphore) semaphore.release()\n }\n }\n\n const parts = await Promise.all(\n segments.map(async (seg) => {\n if (seg.type === 'code') return seg.text\n if (seg.text.trim().length === 0) return seg.text\n if (semaphore) await semaphore.acquire(semaphoreTimeoutMs)\n try {\n const result = await pipeline.compressForLLM(seg.text)\n session.recordCompression(result.metrics)\n const saved = Math.max(0, result.metrics.tokensSaved)\n record(!result.metrics.skipped, saved)\n return sanitizeCompressedText(result.text)\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) throw err\n session.recordFailure()\n return seg.text\n } finally {\n if (semaphore) semaphore.release()\n }\n }),\n )\n return parts.join('')\n}\n","/**\n * Content segmenter — splits mixed text into code and prose segments.\n * Code segments (fenced blocks, indented blocks) pass through compression\n * unchanged to avoid destructive normalization (casefold, punct strip, lemmatize).\n */\n\nexport interface ContentSegment {\n type: 'prose' | 'code'\n text: string\n}\n\n/**\n * Segment text content into code and prose blocks.\n *\n * Detection rules:\n * 1. Fenced code blocks: ``` or ~~~ (with optional language tag) through closing fence\n * 2. Indented code blocks: 4+ space or tab-indented contiguous lines\n * 3. Everything else → prose\n *\n * Round-trip invariant: segments.map(s => s.text).join('') === input\n */\nexport function segmentContent(text: string): ContentSegment[] {\n if (text.length === 0) return [{ type: 'prose', text: '' }]\n\n const segments: ContentSegment[] = []\n const lines = text.split('\\n')\n let i = 0\n let proseBuf: string[] = []\n\n function flushProse(): void {\n if (proseBuf.length > 0) {\n segments.push({ type: 'prose', text: proseBuf.join('\\n') })\n proseBuf = []\n }\n }\n\n while (i < lines.length) {\n const line = lines[i]\n\n // Check for fenced code block opening\n const fenceMatch = matchFenceOpen(line)\n if (fenceMatch) {\n // Before flushing prose, add the newline that separated prose from this fence\n if (proseBuf.length > 0) {\n // The newline before this line belongs to the prose segment\n flushProse()\n // Add the newline separator between prose and code\n segments[segments.length - 1].text += '\\n'\n }\n\n const codeBuf: string[] = [line]\n i++\n\n // Scan until closing fence of same type and length\n let closed = false\n while (i < lines.length) {\n codeBuf.push(lines[i])\n if (matchFenceClose(lines[i], fenceMatch.char, fenceMatch.length)) {\n closed = true\n i++\n break\n }\n i++\n }\n\n // Add trailing newline if not at end of input\n let codeText = codeBuf.join('\\n')\n if (i < lines.length) {\n codeText += '\\n'\n }\n\n segments.push({ type: 'code', text: codeText })\n continue\n }\n\n // Check for indented code block (4+ spaces or tab)\n if (isIndentedCodeLine(line)) {\n if (proseBuf.length > 0) {\n flushProse()\n segments[segments.length - 1].text += '\\n'\n }\n\n const codeBuf: string[] = [line]\n i++\n\n // Consume contiguous indented lines (allow blank lines within)\n while (i < lines.length) {\n if (isIndentedCodeLine(lines[i])) {\n codeBuf.push(lines[i])\n i++\n } else if (lines[i].trim() === '' && i + 1 < lines.length && isIndentedCodeLine(lines[i + 1])) {\n // Blank line between indented lines — still part of code block\n codeBuf.push(lines[i])\n i++\n } else {\n break\n }\n }\n\n let codeText = codeBuf.join('\\n')\n if (i < lines.length) {\n codeText += '\\n'\n }\n\n segments.push({ type: 'code', text: codeText })\n continue\n }\n\n // Regular prose line\n if (proseBuf.length > 0) {\n proseBuf.push(line)\n } else {\n proseBuf.push(line)\n }\n i++\n }\n\n // Flush remaining prose\n if (proseBuf.length > 0) {\n flushProse()\n }\n\n // Ensure at least one segment\n if (segments.length === 0) {\n return [{ type: 'prose', text }]\n }\n\n return segments\n}\n\ninterface FenceInfo {\n char: string\n length: number\n}\n\nfunction matchFenceOpen(line: string): FenceInfo | null {\n // Match ``` or ~~~ with optional language tag, allowing leading whitespace (0-3 spaces)\n const match = line.match(/^( {0,3})((`{3,})|~{3,})(.*)$/)\n if (!match) return null\n\n const fenceStr = match[2]\n const char = fenceStr[0]\n\n // Backtick fences: info string must not contain backticks\n if (char === '`' && match[4] && match[4].includes('`')) return null\n\n return { char, length: fenceStr.length }\n}\n\nfunction matchFenceClose(line: string, char: string, minLength: number): boolean {\n const match = line.match(/^( {0,3})((`{3,})|(~{3,}))\\s*$/)\n if (!match) return false\n const fenceStr = match[2]\n return fenceStr[0] === char && fenceStr.length >= minLength\n}\n\nfunction isIndentedCodeLine(line: string): boolean {\n // 4+ spaces or starts with tab (and not blank)\n return (line.startsWith(' ') || line.startsWith('\\t')) && line.trim().length > 0\n}\n","import type { ChatCompletionMessage, ContentPart } from '../types.js'\n\nexport type MessageTier = 'hot' | 'warm' | 'cold'\n\nexport interface TieredMessage {\n index: number\n message: ChatCompletionMessage\n tier: MessageTier\n eligibleTokens: number\n}\n\nexport interface ConversationPlan {\n messages: TieredMessage[]\n totalEligibleTokens: number\n shouldCompress: boolean\n hotCount: number\n warmCount: number\n coldCount: number\n}\n\nexport interface TierConfig {\n hotFraction: number\n coldFraction: number\n aggregateThreshold: number\n compressRoles: Set<string>\n compressToolResults: boolean\n}\n\n/**\n * Content block types that should never be compressed.\n * tool_use contains structured JSON input; thinking contains reasoning chains.\n */\nconst SKIP_BLOCK_TYPES = new Set(['thinking', 'tool_use', 'image'])\n\n/**\n * Estimate token count for a string using the 4-chars-per-token heuristic.\n */\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4)\n}\n\n/**\n * Estimate eligible (compressible) tokens in a single content block.\n */\nfunction estimateBlockTokens(block: ContentPart, compressToolResults: boolean): number {\n if (SKIP_BLOCK_TYPES.has(block.type)) return 0\n\n // text block\n if (block.type === 'text' && typeof block.text === 'string') {\n return estimateTokens(block.text)\n }\n\n // tool_result block — content can be string or nested blocks\n if (block.type === 'tool_result' && compressToolResults) {\n if (typeof block.content === 'string') {\n return estimateTokens(block.content)\n }\n if (Array.isArray(block.content)) {\n return (block.content as ContentPart[]).reduce(\n (sum, inner) => sum + estimateBlockTokens(inner, compressToolResults),\n 0,\n )\n }\n }\n\n return 0\n}\n\n/**\n * Estimate eligible tokens in a message's content.\n */\nfunction estimateMessageTokens(msg: ChatCompletionMessage, config: TierConfig): number {\n if (!config.compressRoles.has(msg.role)) return 0\n\n if (typeof msg.content === 'string') {\n return estimateTokens(msg.content)\n }\n\n if (Array.isArray(msg.content)) {\n return (msg.content as ContentPart[]).reduce(\n (sum, part) => sum + estimateBlockTokens(part, config.compressToolResults),\n 0,\n )\n }\n\n return 0\n}\n\n/**\n * Assign a tier to each message based on its position in the conversation.\n *\n * Messages are ordered oldest-first (index 0 = oldest). The last `hotFraction`\n * of messages are HOT (verbatim), the first `coldFraction` are COLD, and\n * everything in between is WARM.\n *\n * For short conversations (< 5 messages), all messages are HOT to avoid\n * compressing context before there's enough to matter.\n */\nexport function analyzeConversation(\n messages: ChatCompletionMessage[],\n config: TierConfig,\n): ConversationPlan {\n const n = messages.length\n\n // Short conversations: everything is hot, skip analysis\n if (n < 5) {\n const tiered: TieredMessage[] = messages.map((msg, i) => ({\n index: i,\n message: msg,\n tier: 'hot' as MessageTier,\n eligibleTokens: estimateMessageTokens(msg, config),\n }))\n return {\n messages: tiered,\n totalEligibleTokens: 0,\n shouldCompress: false,\n hotCount: n,\n warmCount: 0,\n coldCount: 0,\n }\n }\n\n // Compute tier boundaries (message indices)\n const coldEnd = Math.floor(n * config.coldFraction)\n const hotStart = n - Math.floor(n * config.hotFraction)\n\n let totalEligibleTokens = 0\n let hotCount = 0\n let warmCount = 0\n let coldCount = 0\n\n const tiered: TieredMessage[] = messages.map((msg, i) => {\n let tier: MessageTier\n if (i >= hotStart) {\n tier = 'hot'\n hotCount++\n } else if (i < coldEnd) {\n tier = 'cold'\n coldCount++\n } else {\n tier = 'warm'\n warmCount++\n }\n\n const eligibleTokens = estimateMessageTokens(msg, config)\n\n // Only WARM and COLD messages contribute to compression budget\n if (tier !== 'hot') {\n totalEligibleTokens += eligibleTokens\n }\n\n return { index: i, message: msg, tier, eligibleTokens }\n })\n\n return {\n messages: tiered,\n totalEligibleTokens,\n shouldCompress: totalEligibleTokens >= config.aggregateThreshold,\n hotCount,\n warmCount,\n coldCount,\n }\n}\n","import type { CompressionPipeline } from '@cognisos/rsc-sdk'\n\n/**\n * Creates a buffer that accumulates streamed response text and triggers\n * background learning when the stream completes.\n */\nexport function createStreamLearningBuffer(pipeline: CompressionPipeline) {\n let buffer = ''\n\n return {\n /** Append a text delta from an SSE chunk */\n append(text: string): void {\n buffer += text\n },\n\n /** Flush the buffer — triggers fire-and-forget learning */\n flush(): void {\n if (buffer.length > 0) {\n pipeline.triggerLearning(buffer)\n buffer = ''\n }\n },\n\n /** Get current buffer contents (for testing) */\n getBuffer(): string {\n return buffer\n },\n }\n}\n","import * as http from 'node:http'\n\n/**\n * Pipe an SSE response from an upstream LLM to the client,\n * parsing content deltas for the learning buffer.\n *\n * When totalTokensSaved > 0, intercepts the final usage chunk to adjust\n * prompt_tokens and total_tokens to reflect the pre-compression token count.\n *\n * Writes each chunk immediately — zero buffering, zero added latency\n * (except for the single usage chunk which may get rewritten).\n */\nexport async function pipeSSEResponse(\n upstreamResponse: Response,\n clientRes: http.ServerResponse,\n onContentDelta: (text: string) => void,\n onComplete: () => void,\n totalTokensSaved = 0,\n): Promise<void> {\n clientRes.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'Access-Control-Allow-Origin': '*',\n })\n\n const reader = upstreamResponse.body!.getReader()\n const decoder = new TextDecoder()\n let lineBuf = ''\n const needsAdjustment = totalTokensSaved > 0\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n\n // Fast path: no token adjustment needed\n if (!needsAdjustment) {\n clientRes.write(chunk)\n\n lineBuf += chunk\n const lines = lineBuf.split('\\n')\n lineBuf = lines.pop() || ''\n\n for (const line of lines) {\n if (line.startsWith('data: ') && line !== 'data: [DONE]') {\n try {\n const json = JSON.parse(line.slice(6))\n const content = json?.choices?.[0]?.delta?.content\n if (typeof content === 'string') {\n onContentDelta(content)\n }\n } catch {\n // Malformed SSE data — ignore for learning\n }\n }\n }\n continue\n }\n\n // Slow path: check each data line for usage to adjust\n lineBuf += chunk\n const lines = lineBuf.split('\\n')\n lineBuf = lines.pop() || ''\n\n let adjusted = false\n const outputLines: string[] = []\n\n for (const line of lines) {\n if (line.startsWith('data: ') && line !== 'data: [DONE]') {\n try {\n const json = JSON.parse(line.slice(6))\n\n // Check for usage in this chunk (OpenAI sends it in the final chunk)\n if (json?.usage?.prompt_tokens != null) {\n json.usage.prompt_tokens += totalTokensSaved\n if (json.usage.total_tokens != null) {\n json.usage.total_tokens += totalTokensSaved\n }\n outputLines.push(`data: ${JSON.stringify(json)}`)\n adjusted = true\n } else {\n outputLines.push(line)\n }\n\n // Learning: extract content deltas\n const content = json?.choices?.[0]?.delta?.content\n if (typeof content === 'string') {\n onContentDelta(content)\n }\n } catch {\n outputLines.push(line)\n }\n } else {\n outputLines.push(line)\n }\n }\n\n if (adjusted) {\n const reconstructed = outputLines.join('\\n') + '\\n'\n clientRes.write(reconstructed)\n } else {\n clientRes.write(chunk)\n }\n }\n } finally {\n clientRes.end()\n onComplete()\n }\n}\n","/**\n * User-facing terminology for CLI log output.\n *\n * Mirrors web/src/lib/terminology.ts — kept in sync manually\n * since web and CLI are separate packages with no shared dependency.\n *\n * Source of truth: GitHub issue #55\n */\n\n// ── Memory tier labels ────────────────────────────────────────────\n\nexport const TIER_LABELS = {\n HOT: 'Active',\n WARM: 'Recent',\n COLD: 'Archived',\n} as const\n\n// ── Log tag formatting helpers ────────────────────────────────────\n\nexport function formatTiersLog(hot: number, warm: number, cold: number, eligibleTokens: number): string {\n return `[MEMORY] ${TIER_LABELS.HOT}:${hot} ${TIER_LABELS.WARM}:${warm} ${TIER_LABELS.COLD}:${cold} · ${eligibleTokens} tokens eligible`\n}\n\nexport function formatSavedLog(tokensSaved: number, latencyMs: number): string {\n return `[SAVED] ${tokensSaved} tokens (${latencyMs}ms)`\n}\n\nexport function formatDegradeLog(): string {\n return '[STATUS] Connection degraded — passing through directly'\n}\n\nexport function formatResponseLog(model: string, tokensSaved: number, streaming = false): string {\n return `[RESPONSE] ${streaming ? 'Streaming ' : ''}${model} response → client (saved:${tokensSaved}tok)`\n}\n","import * as http from 'node:http'\nimport { RSCCircuitOpenError } from '@cognisos/rsc-sdk'\nimport { compressConversation, type ConversationCompressOptions } from '../rsc/message-compressor.js'\nimport { analyzeConversation } from '../rsc/conversation-analyzer.js'\nimport { createStreamLearningBuffer } from '../rsc/learning.js'\nimport { pipeAnthropicSSEResponse } from './anthropic-streaming.js'\nimport type { RSCPipelineWrapper } from '../rsc/pipeline.js'\nimport type { ChatCompletionMessage, ResolvedConfig } from '../types.js'\nimport type { AnthropicMessagesRequest, AnthropicMessage, AnthropicContentBlock } from '../types/anthropic.js'\nimport { formatTiersLog, formatSavedLog, formatDegradeLog, formatResponseLog } from '../terminology.js'\nimport type { Logger } from './handler.js'\nimport type { Semaphore } from '../rsc/semaphore.js'\nimport type { LatencyMonitor } from '../rsc/latency-monitor.js'\n\nfunction setCORSHeaders(res: http.ServerResponse): void {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key, anthropic-version, anthropic-beta, x-liminal-session')\n}\n\nfunction sendAnthropicError(res: http.ServerResponse, status: number, type: string, message: string): void {\n setCORSHeaders(res)\n res.writeHead(status, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ type: 'error', error: { type, message } }))\n}\n\n/**\n * Extract auth headers from incoming request.\n * Supports both x-api-key (API users) and Authorization: Bearer (subscription/OAuth users).\n */\nfunction extractAuthHeaders(req: http.IncomingMessage): Record<string, string> {\n const headers: Record<string, string> = {}\n\n const xApiKey = req.headers['x-api-key']\n if (typeof xApiKey === 'string' && xApiKey.length > 0) {\n headers['x-api-key'] = xApiKey\n }\n\n const auth = req.headers['authorization']\n if (typeof auth === 'string' && auth.length > 0) {\n headers['Authorization'] = auth\n }\n\n return headers\n}\n\n/**\n * Convert Anthropic messages to ChatCompletionMessage[] for the compressor.\n * The structures are compatible — this is a thin adapter.\n */\nfunction convertAnthropicToCompressible(messages: AnthropicMessage[]): ChatCompletionMessage[] {\n return messages.map((msg) => ({\n role: msg.role,\n content: msg.content as string | AnthropicContentBlock[],\n }))\n}\n\n/**\n * Convert compressed ChatCompletionMessage[] back to Anthropic format.\n */\nfunction convertCompressedToAnthropic(messages: ChatCompletionMessage[]): AnthropicMessage[] {\n return messages.map((msg) => ({\n role: msg.role as 'user' | 'assistant',\n content: msg.content as string | AnthropicContentBlock[],\n }))\n}\n\nexport async function handleAnthropicMessages(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: unknown,\n pipeline: RSCPipelineWrapper,\n config: ResolvedConfig,\n logger: Logger,\n semaphore: Semaphore,\n latencyMonitor: LatencyMonitor,\n sessionKey: string,\n): Promise<void> {\n const request = body as AnthropicMessagesRequest\n\n // Validate required fields\n if (!request.messages || !Array.isArray(request.messages)) {\n sendAnthropicError(res, 400, 'invalid_request_error', 'messages is required and must be an array')\n return\n }\n\n if (typeof request.max_tokens !== 'number') {\n sendAnthropicError(res, 400, 'invalid_request_error', 'max_tokens is required')\n return\n }\n\n // Extract auth headers (x-api-key for API users, Authorization for subscription/OAuth)\n const authHeaders = extractAuthHeaders(req)\n if (Object.keys(authHeaders).length === 0) {\n sendAnthropicError(res, 401, 'authentication_error', 'Authentication required (x-api-key or Authorization header)')\n return\n }\n\n // Analyze conversation and compress by tier\n let messages = request.messages\n let anyCompressed = false\n let totalTokensSaved = 0\n\n if (config.enabled && !pipeline.isCircuitOpen()) {\n const compressStart = Date.now()\n try {\n const compressRoles = new Set(config.compressRoles)\n const compressible = convertAnthropicToCompressible(request.messages)\n\n const plan = analyzeConversation(compressible, {\n hotFraction: config.hotFraction,\n coldFraction: config.coldFraction,\n aggregateThreshold: config.aggregateThreshold,\n compressRoles,\n compressToolResults: config.compressToolResults,\n })\n\n if (plan.shouldCompress) {\n logger.log(formatTiersLog(plan.hotCount, plan.warmCount, plan.coldCount, plan.totalEligibleTokens))\n }\n\n const result = await compressConversation(\n pipeline.pipeline,\n pipeline.session,\n plan,\n {\n compressToolResults: config.compressToolResults,\n compressionThreshold: config.compressionThreshold,\n logFn: (msg) => logger.log(msg),\n semaphore,\n semaphoreTimeoutMs: config.concurrencyTimeoutMs,\n },\n )\n messages = convertCompressedToAnthropic(result.messages)\n anyCompressed = result.anyCompressed\n totalTokensSaved = result.totalTokensSaved\n\n const latencyMs = Date.now() - compressStart\n const alert = latencyMonitor.record(sessionKey, latencyMs)\n if (alert) {\n logger.log(`[LATENCY] ${alert.type.toUpperCase()}: ${alert.message}`)\n }\n\n if (result.totalTokensSaved > 0) {\n logger.log(formatSavedLog(result.totalTokensSaved, latencyMs))\n }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n logger.log(formatDegradeLog())\n } else {\n logger.log(`[ERROR] Compression failed: ${err instanceof Error ? err.message : String(err)}`)\n }\n messages = request.messages\n }\n }\n\n // Build upstream request\n const upstreamUrl = `${config.anthropicUpstreamUrl}/v1/messages`\n const upstreamBody = { ...request, messages }\n\n const upstreamHeaders: Record<string, string> = {\n ...authHeaders,\n 'anthropic-version': (req.headers['anthropic-version'] as string) || '2023-06-01',\n 'Content-Type': 'application/json',\n }\n\n // Forward anthropic-beta header if present\n const betaHeader = req.headers['anthropic-beta']\n if (typeof betaHeader === 'string') {\n upstreamHeaders['anthropic-beta'] = betaHeader\n }\n\n // Log request details for debugging\n const authTypes = Object.keys(authHeaders).join(', ') || 'none'\n logger.log(`[ANTHROPIC] ${request.model} → ${upstreamUrl} (auth: ${authTypes})`)\n\n try {\n const upstreamResponse = await fetch(upstreamUrl, {\n method: 'POST',\n headers: upstreamHeaders,\n body: JSON.stringify(upstreamBody),\n })\n\n // Handle upstream errors\n if (!upstreamResponse.ok) {\n const errorBody = await upstreamResponse.text()\n logger.log(`[ANTHROPIC] Upstream error ${upstreamResponse.status}: ${errorBody.slice(0, 500)}`)\n setCORSHeaders(res)\n res.writeHead(upstreamResponse.status, {\n 'Content-Type': upstreamResponse.headers.get('Content-Type') || 'application/json',\n })\n res.end(errorBody)\n return\n }\n\n // Streaming response\n if (request.stream && upstreamResponse.body) {\n const learningBuffer = anyCompressed\n ? createStreamLearningBuffer(pipeline.pipeline)\n : null\n\n logger.log(formatResponseLog(request.model, totalTokensSaved, true))\n await pipeAnthropicSSEResponse(\n upstreamResponse,\n res,\n (text) => learningBuffer?.append(text),\n () => learningBuffer?.flush(),\n totalTokensSaved,\n )\n return\n }\n\n // Non-streaming response\n const responseBody = await upstreamResponse.text()\n logger.log(formatResponseLog(request.model, totalTokensSaved))\n\n // Adjust usage.input_tokens to reflect pre-compression token count\n let finalBody = responseBody\n if (totalTokensSaved > 0) {\n try {\n const parsed = JSON.parse(responseBody)\n if (parsed?.usage?.input_tokens != null) {\n parsed.usage.input_tokens += totalTokensSaved\n finalBody = JSON.stringify(parsed)\n logger.log(`[TOKENS] Adjusted input_tokens by +${totalTokensSaved}`)\n }\n } catch {\n // Pass through unmodified on parse error\n }\n }\n\n setCORSHeaders(res)\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(finalBody)\n\n // Trigger learning from response (fire-and-forget, uses original body)\n if (anyCompressed) {\n try {\n const parsed = JSON.parse(responseBody)\n const textBlocks = parsed?.content?.filter(\n (b: AnthropicContentBlock) => b.type === 'text' && typeof b.text === 'string',\n )\n const content = textBlocks?.map((b: AnthropicContentBlock) => b.text).join('')\n if (typeof content === 'string' && content.length > 0) {\n pipeline.pipeline.triggerLearning(content)\n }\n } catch {\n // Ignore learning parse errors\n }\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n logger.log(`[ERROR] Upstream request failed: ${message}`)\n if (!res.headersSent) {\n sendAnthropicError(res, 502, 'api_error', `Failed to reach upstream: ${message}`)\n }\n }\n}\n","import * as http from 'node:http'\n\n/**\n * Adjust a `message_start` SSE data line to restore pre-compression input_tokens.\n * Returns the adjusted line if modified, or null if no adjustment was made.\n */\nfunction adjustMessageStartLine(dataLine: string, tokensSaved: number): string | null {\n try {\n const json = JSON.parse(dataLine.slice(6)) // strip \"data: \"\n if (json?.message?.usage?.input_tokens != null) {\n json.message.usage.input_tokens += tokensSaved\n return `data: ${JSON.stringify(json)}`\n }\n } catch {\n // Malformed JSON — don't adjust\n }\n return null\n}\n\n/**\n * Pipe an Anthropic SSE response from the upstream to the client,\n * parsing content_block_delta events for the learning buffer.\n *\n * Anthropic SSE format:\n * event: content_block_delta\n * data: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"Hello\"}}\n *\n * When totalTokensSaved > 0, intercepts the message_start event to adjust\n * usage.input_tokens to reflect the pre-compression token count.\n *\n * Writes each chunk immediately — zero buffering, zero added latency\n * (except for the single message_start chunk which gets rewritten).\n */\nexport async function pipeAnthropicSSEResponse(\n upstreamResponse: Response,\n clientRes: http.ServerResponse,\n onContentDelta: (text: string) => void,\n onComplete: () => void,\n totalTokensSaved = 0,\n): Promise<void> {\n clientRes.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'Access-Control-Allow-Origin': '*',\n })\n\n const reader = upstreamResponse.body!.getReader()\n const decoder = new TextDecoder()\n let lineBuf = ''\n let currentEvent = ''\n let usageAdjusted = false\n const needsAdjustment = totalTokensSaved > 0\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n\n // Fast path: if no adjustment needed (or already done), write immediately\n if (!needsAdjustment || usageAdjusted) {\n clientRes.write(chunk)\n\n // Still parse for learning\n lineBuf += chunk\n const lines = lineBuf.split('\\n')\n lineBuf = lines.pop() || ''\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n currentEvent = line.slice(7).trim()\n } else if (line.startsWith('data: ') && currentEvent === 'content_block_delta') {\n try {\n const json = JSON.parse(line.slice(6))\n if (json?.delta?.type === 'text_delta' && typeof json.delta.text === 'string') {\n onContentDelta(json.delta.text)\n }\n } catch {\n // Malformed data — ignore for learning\n }\n }\n }\n continue\n }\n\n // Slow path: need to check for message_start to adjust usage\n lineBuf += chunk\n const lines = lineBuf.split('\\n')\n lineBuf = lines.pop() || ''\n\n let adjusted = false\n const outputLines: string[] = []\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n currentEvent = line.slice(7).trim()\n outputLines.push(line)\n } else if (line.startsWith('data: ') && currentEvent === 'message_start' && !usageAdjusted) {\n const adjustedLine = adjustMessageStartLine(line, totalTokensSaved)\n if (adjustedLine) {\n outputLines.push(adjustedLine)\n usageAdjusted = true\n adjusted = true\n } else {\n outputLines.push(line)\n }\n } else {\n outputLines.push(line)\n\n // Learning: extract content deltas\n if (line.startsWith('data: ') && currentEvent === 'content_block_delta') {\n try {\n const json = JSON.parse(line.slice(6))\n if (json?.delta?.type === 'text_delta' && typeof json.delta.text === 'string') {\n onContentDelta(json.delta.text)\n }\n } catch {\n // Malformed data — ignore for learning\n }\n }\n }\n }\n\n if (adjusted) {\n // Reconstruct the chunk from adjusted lines + remaining buffer\n const reconstructed = outputLines.join('\\n') + '\\n' + (lineBuf ? '' : '')\n clientRes.write(reconstructed)\n } else {\n // No adjustment made in this chunk — write original\n clientRes.write(chunk)\n }\n }\n } finally {\n clientRes.end()\n onComplete()\n }\n}\n","import * as http from 'node:http'\nimport { RSCCircuitOpenError } from '@cognisos/rsc-sdk'\nimport { compressMessages } from '../rsc/message-compressor.js'\nimport { createStreamLearningBuffer } from '../rsc/learning.js'\nimport { pipeResponsesSSE } from './responses-streaming.js'\nimport type { RSCPipelineWrapper } from '../rsc/pipeline.js'\nimport type { ChatCompletionMessage, ResolvedConfig } from '../types.js'\nimport { formatSavedLog, formatDegradeLog, formatResponseLog } from '../terminology.js'\nimport type { Logger } from './handler.js'\nimport type { Semaphore } from '../rsc/semaphore.js'\nimport type { LatencyMonitor } from '../rsc/latency-monitor.js'\nimport type {\n ResponsesRequest,\n ResponsesInputItem,\n ResponsesMessageItem,\n ResponsesInputContent,\n ResponsesInputTextContent,\n ResponsesResponse,\n ResponsesOutputItem,\n ResponsesOutputMessage,\n} from '../types/responses.js'\n\nfunction setCORSHeaders(res: http.ServerResponse): void {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')\n}\n\nfunction sendJSON(res: http.ServerResponse, status: number, body: unknown): void {\n setCORSHeaders(res)\n res.writeHead(status, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(body))\n}\n\nfunction extractBearerToken(req: http.IncomingMessage): string | null {\n const auth = req.headers.authorization\n if (!auth || !auth.startsWith('Bearer ')) return null\n return auth.slice(7)\n}\n\n// ─── Input conversion ───────────────────────────────────────────────\n// Convert Responses API input items to ChatCompletionMessage[] for the\n// shared message compressor. Only message items with text content are\n// compressible — function call outputs, item references, images, and\n// files pass through unchanged.\n\nfunction isMessageItem(item: ResponsesInputItem): item is ResponsesMessageItem {\n return item.type === 'message'\n}\n\nfunction inputToCompressibleMessages(input: string | ResponsesInputItem[]): ChatCompletionMessage[] {\n // Simple string input\n if (typeof input === 'string') {\n return [{ role: 'user', content: input }]\n }\n\n const messages: ChatCompletionMessage[] = []\n\n for (const item of input) {\n if (!isMessageItem(item)) continue\n\n if (typeof item.content === 'string') {\n // Map 'developer' role → 'system' for the compressor\n const role = item.role === 'developer' ? 'system' : item.role\n messages.push({ role, content: item.content })\n } else if (Array.isArray(item.content)) {\n // Content array — extract text parts, preserve structure\n const role = item.role === 'developer' ? 'system' : item.role\n const parts = item.content.map((c: ResponsesInputContent) => {\n if (c.type === 'input_text') {\n return { type: 'text' as const, text: (c as ResponsesInputTextContent).text }\n }\n // Images and files pass through as non-text parts\n return c as unknown as { type: string; [key: string]: unknown }\n })\n messages.push({ role, content: parts })\n }\n }\n\n return messages\n}\n\n// ─── Apply compressed messages back to input ────────────────────────\n// After compression, we need to write the compressed text back into the\n// original Responses API input structure, preserving non-message items,\n// images, file references, etc.\n\nfunction applyCompressedToInput(\n originalInput: string | ResponsesInputItem[],\n compressedMessages: ChatCompletionMessage[],\n): string | ResponsesInputItem[] {\n // Simple string input — return compressed string directly\n if (typeof originalInput === 'string') {\n const first = compressedMessages[0]\n if (first && typeof first.content === 'string') {\n return first.content\n }\n return originalInput\n }\n\n // Array input — walk through and replace message items\n let msgIdx = 0\n const result: ResponsesInputItem[] = []\n\n for (const item of originalInput) {\n if (!isMessageItem(item)) {\n // Non-message items (function_call_output, item_reference, etc.) pass through\n result.push(item)\n continue\n }\n\n const compressed = compressedMessages[msgIdx]\n msgIdx++\n\n if (!compressed) {\n result.push(item)\n continue\n }\n\n if (typeof compressed.content === 'string') {\n result.push({\n ...item,\n content: compressed.content,\n } as ResponsesMessageItem)\n } else if (Array.isArray(compressed.content)) {\n // Convert back to Responses API content format\n const content: ResponsesInputContent[] = compressed.content.map((part) => {\n if (part.type === 'text' && 'text' in part) {\n return { type: 'input_text' as const, text: part.text as string }\n }\n return part as unknown as ResponsesInputContent\n })\n result.push({\n ...item,\n content,\n } as ResponsesMessageItem)\n } else {\n result.push(item)\n }\n }\n\n return result\n}\n\n// ─── Extract text from response output for learning ─────────────────\n\nfunction extractOutputText(output: ResponsesOutputItem[]): string {\n const texts: string[] = []\n for (const item of output) {\n if (item.type === 'message') {\n const msg = item as ResponsesOutputMessage\n for (const block of msg.content) {\n if (block.type === 'output_text' && typeof block.text === 'string') {\n texts.push(block.text)\n }\n }\n }\n }\n return texts.join('')\n}\n\n// ─── Main handler ───────────────────────────────────────────────────\n\nexport async function handleResponses(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: unknown,\n pipeline: RSCPipelineWrapper,\n config: ResolvedConfig,\n logger: Logger,\n semaphore: Semaphore,\n latencyMonitor: LatencyMonitor,\n sessionKey: string,\n): Promise<void> {\n const request = body as ResponsesRequest\n\n // Validate required fields\n if (request.input === undefined || request.input === null) {\n sendJSON(res, 400, {\n error: { message: 'input is required', type: 'invalid_request_error' },\n })\n return\n }\n\n // Extract LLM API key\n const llmApiKey = extractBearerToken(req)\n if (!llmApiKey) {\n sendJSON(res, 401, {\n error: { message: 'Authorization header with Bearer token is required', type: 'authentication_error' },\n })\n return\n }\n\n // ── Compress input ────────────────────────────────────────────\n let compressedInput = request.input\n let anyCompressed = false\n let totalTokensSaved = 0\n\n if (config.enabled && !pipeline.isCircuitOpen()) {\n const compressStart = Date.now()\n try {\n const compressRoles = new Set(config.compressRoles)\n const compressible = inputToCompressibleMessages(request.input)\n\n if (compressible.length > 0) {\n const result = await compressMessages(\n compressible,\n pipeline.pipeline,\n pipeline.session,\n compressRoles,\n )\n\n compressedInput = applyCompressedToInput(request.input, result.messages)\n anyCompressed = result.anyCompressed\n totalTokensSaved = result.totalTokensSaved\n\n const latencyMs = Date.now() - compressStart\n const alert = latencyMonitor.record(sessionKey, latencyMs)\n if (alert) {\n logger.log(`[LATENCY] ${alert.type.toUpperCase()}: ${alert.message}`)\n }\n\n if (result.totalTokensSaved > 0) {\n logger.log(formatSavedLog(result.totalTokensSaved, latencyMs))\n }\n }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n logger.log(formatDegradeLog())\n } else {\n logger.log(`[ERROR] Compression failed: ${err instanceof Error ? err.message : String(err)}`)\n }\n compressedInput = request.input\n }\n }\n\n // ── Build upstream request ────────────────────────────────────\n const upstreamUrl = `${config.upstreamBaseUrl}/v1/responses`\n const upstreamBody = { ...request, input: compressedInput }\n\n const upstreamHeaders: Record<string, string> = {\n 'Authorization': `Bearer ${llmApiKey}`,\n 'Content-Type': 'application/json',\n }\n\n if (request.stream) {\n upstreamHeaders['Accept'] = 'text/event-stream'\n }\n\n logger.log(`[RESPONSES] ${request.model} → ${upstreamUrl}`)\n\n try {\n const upstreamResponse = await fetch(upstreamUrl, {\n method: 'POST',\n headers: upstreamHeaders,\n body: JSON.stringify(upstreamBody),\n })\n\n // Handle upstream errors\n if (!upstreamResponse.ok) {\n const errorBody = await upstreamResponse.text()\n logger.log(`[RESPONSES] Upstream error ${upstreamResponse.status}: ${errorBody.slice(0, 500)}`)\n setCORSHeaders(res)\n res.writeHead(upstreamResponse.status, {\n 'Content-Type': upstreamResponse.headers.get('Content-Type') || 'application/json',\n })\n res.end(errorBody)\n return\n }\n\n // ── Streaming response ────────────────────────────────────\n if (request.stream && upstreamResponse.body) {\n const learningBuffer = anyCompressed\n ? createStreamLearningBuffer(pipeline.pipeline)\n : null\n\n logger.log(formatResponseLog(request.model, totalTokensSaved, true))\n await pipeResponsesSSE(\n upstreamResponse,\n res,\n (text) => learningBuffer?.append(text),\n () => learningBuffer?.flush(),\n totalTokensSaved,\n )\n return\n }\n\n // ── Non-streaming response ────────────────────────────────\n const responseBody = await upstreamResponse.text()\n logger.log(formatResponseLog(request.model, totalTokensSaved))\n\n // Adjust usage to reflect pre-compression token count\n let finalBody = responseBody\n if (totalTokensSaved > 0) {\n try {\n const parsed = JSON.parse(responseBody) as ResponsesResponse\n if (parsed?.usage?.input_tokens != null) {\n parsed.usage.input_tokens += totalTokensSaved\n if (parsed.usage.total_tokens != null) {\n parsed.usage.total_tokens += totalTokensSaved\n }\n finalBody = JSON.stringify(parsed)\n logger.log(`[TOKENS] Adjusted input_tokens by +${totalTokensSaved}`)\n }\n } catch {\n // Pass through unmodified on parse error\n }\n }\n\n setCORSHeaders(res)\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(finalBody)\n\n // Trigger learning from response (fire-and-forget)\n if (anyCompressed) {\n try {\n const parsed = JSON.parse(responseBody) as ResponsesResponse\n if (parsed?.output) {\n const text = extractOutputText(parsed.output)\n if (text.length > 0) {\n pipeline.pipeline.triggerLearning(text)\n }\n }\n } catch {\n // Ignore learning parse errors\n }\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n logger.log(`[ERROR] Upstream request failed: ${message}`)\n if (!res.headersSent) {\n sendJSON(res, 502, {\n error: { message: `Failed to reach upstream LLM: ${message}`, type: 'server_error' },\n })\n }\n }\n}\n","import * as http from 'node:http'\n\n/**\n * Pipe an OpenAI Responses API SSE stream from upstream to the client.\n *\n * Responses API SSE format differs from Chat Completions:\n * - Each chunk has both `event:` and `data:` lines\n * - Text deltas arrive as `response.output_text.delta` events\n * - Usage is reported in the `response.completed` event\n * - Stream ends with `data: [DONE]`\n *\n * When totalTokensSaved > 0, adjusts usage.input_tokens in the\n * `response.completed` event to reflect pre-compression token count.\n *\n * Writes each chunk immediately — zero buffering, zero added latency\n * (except for the single response.completed chunk which may get rewritten).\n */\nexport async function pipeResponsesSSE(\n upstreamResponse: Response,\n clientRes: http.ServerResponse,\n onContentDelta: (text: string) => void,\n onComplete: () => void,\n totalTokensSaved = 0,\n): Promise<void> {\n clientRes.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'Access-Control-Allow-Origin': '*',\n })\n\n const reader = upstreamResponse.body!.getReader()\n const decoder = new TextDecoder()\n let lineBuf = ''\n let currentEvent = ''\n let usageAdjusted = false\n const needsAdjustment = totalTokensSaved > 0\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n\n // Fast path: no adjustment needed (or already done), write immediately\n if (!needsAdjustment || usageAdjusted) {\n clientRes.write(chunk)\n\n // Still parse for learning\n lineBuf += chunk\n const lines = lineBuf.split('\\n')\n lineBuf = lines.pop() || ''\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n currentEvent = line.slice(7).trim()\n } else if (line.startsWith('data: ') && currentEvent === 'response.output_text.delta') {\n try {\n const json = JSON.parse(line.slice(6))\n if (typeof json?.delta === 'string') {\n onContentDelta(json.delta)\n }\n } catch {\n // Malformed data — ignore for learning\n }\n }\n }\n continue\n }\n\n // Slow path: need to check for response.completed to adjust usage\n lineBuf += chunk\n const lines = lineBuf.split('\\n')\n lineBuf = lines.pop() || ''\n\n let adjusted = false\n const outputLines: string[] = []\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n currentEvent = line.slice(7).trim()\n outputLines.push(line)\n } else if (\n line.startsWith('data: ') &&\n currentEvent === 'response.completed' &&\n !usageAdjusted\n ) {\n // Adjust usage in the response.completed event\n try {\n const json = JSON.parse(line.slice(6))\n if (json?.response?.usage?.input_tokens != null) {\n json.response.usage.input_tokens += totalTokensSaved\n if (json.response.usage.total_tokens != null) {\n json.response.usage.total_tokens += totalTokensSaved\n }\n outputLines.push(`data: ${JSON.stringify(json)}`)\n usageAdjusted = true\n adjusted = true\n } else {\n outputLines.push(line)\n }\n } catch {\n outputLines.push(line)\n }\n } else {\n outputLines.push(line)\n\n // Learning: extract text deltas\n if (line.startsWith('data: ') && currentEvent === 'response.output_text.delta') {\n try {\n const json = JSON.parse(line.slice(6))\n if (typeof json?.delta === 'string') {\n onContentDelta(json.delta)\n }\n } catch {\n // Malformed data — ignore for learning\n }\n }\n }\n }\n\n if (adjusted) {\n const reconstructed = outputLines.join('\\n') + '\\n'\n clientRes.write(reconstructed)\n } else {\n clientRes.write(chunk)\n }\n }\n } finally {\n clientRes.end()\n onComplete()\n }\n}\n","import * as http from 'node:http'\nimport * as crypto from 'node:crypto'\n\nexport interface SessionKey {\n connector: 'claude-code' | 'cursor' | 'codex' | 'openai-compatible' | 'unknown'\n windowHash: string\n raw: string\n}\n\nexport function identifySession(req: http.IncomingMessage, pathname: string): SessionKey {\n const connector = detectConnector(req, pathname)\n const windowHash = deriveWindowHash(req)\n return { connector, windowHash, raw: `${connector}:${windowHash}` }\n}\n\n// ─── Connector detection ──────────────────────────────────────────────\n\nfunction detectConnector(\n req: http.IncomingMessage,\n pathname: string,\n): SessionKey['connector'] {\n if (req.headers['x-api-key'] || req.headers['anthropic-version']) {\n return 'claude-code'\n }\n if (pathname.startsWith('/v1/responses') || pathname.startsWith('/responses')) {\n return 'codex'\n }\n const ua = req.headers['user-agent'] ?? ''\n if (/cursor/i.test(ua)) {\n return 'cursor'\n }\n return 'openai-compatible'\n}\n\n// ─── Window hash derivation ───────────────────────────────────────────\n\nfunction deriveWindowHash(req: http.IncomingMessage): string {\n // Explicit session header takes priority\n const liminalSession = req.headers['x-liminal-session']\n if (typeof liminalSession === 'string' && liminalSession.length > 0) {\n return liminalSession\n }\n\n // Extract credential from x-api-key or Authorization bearer token\n const credential = extractCredential(req)\n if (!credential) return 'anonymous'\n\n return crypto.createHash('sha256').update(credential).digest('hex').slice(0, 8)\n}\n\nfunction extractCredential(req: http.IncomingMessage): string | null {\n const apiKey = req.headers['x-api-key']\n if (typeof apiKey === 'string' && apiKey.length > 0) return apiKey\n\n const auth = req.headers['authorization']\n if (typeof auth === 'string') {\n const match = auth.match(/^Bearer\\s+(.+)$/i)\n if (match) return match[1]\n }\n\n return null\n}\n","import * as http from 'node:http'\nimport { handleChatCompletions } from './completions.js'\nimport { handleAnthropicMessages } from './messages.js'\nimport { handleResponses } from './responses.js'\nimport { identifySession } from './session-identity.js'\nimport type { SessionManager } from '../rsc/session-manager.js'\nimport type { Semaphore } from '../rsc/semaphore.js'\nimport type { LatencyMonitor } from '../rsc/latency-monitor.js'\nimport type { ResolvedConfig } from '../types.js'\nimport type { MitmStats } from '../tls/mitm-stats.js'\n\nexport interface Logger {\n log(message: string): void\n}\n\n/** Dependencies injected into the request handler. */\nexport interface HandlerDeps {\n sessions: SessionManager\n semaphore: Semaphore\n latencyMonitor: LatencyMonitor\n mitmStats: MitmStats\n config: ResolvedConfig\n logger: Logger\n}\n\nfunction setCORSHeaders(res: http.ServerResponse): void {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT, DELETE, PATCH')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key, anthropic-version, anthropic-beta, anthropic-dangerous-direct-browser-access, x-liminal-session')\n res.setHeader('Access-Control-Max-Age', '86400')\n}\n\nfunction sendJSON(res: http.ServerResponse, status: number, body: unknown): void {\n setCORSHeaders(res)\n res.writeHead(status, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(body))\n}\n\nfunction readBody(req: http.IncomingMessage): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = []\n req.on('data', (chunk: Buffer) => chunks.push(chunk))\n req.on('end', () => resolve(Buffer.concat(chunks)))\n req.on('error', reject)\n })\n}\n\n// ─── Upstream detection ──────────────────────────────────────────────\n\ntype UpstreamTarget = 'anthropic' | 'openai'\n\nfunction detectUpstream(req: http.IncomingMessage, url: string): UpstreamTarget {\n if (req.headers['x-api-key']) return 'anthropic'\n if (req.headers['anthropic-version']) return 'anthropic'\n if (url.startsWith('/v1/messages') || url.startsWith('/messages')) return 'anthropic'\n return 'anthropic'\n}\n\nfunction getUpstreamBaseUrl(target: UpstreamTarget, config: ResolvedConfig): string {\n return target === 'anthropic'\n ? config.anthropicUpstreamUrl\n : config.upstreamBaseUrl\n}\n\n// ─── Header forwarding ──────────────────────────────────────────────\n\nconst HOP_BY_HOP = new Set([\n 'host', 'connection', 'keep-alive', 'transfer-encoding',\n 'te', 'trailer', 'upgrade', 'proxy-authorization', 'proxy-authenticate',\n])\n\nfunction buildUpstreamHeaders(req: http.IncomingMessage): Record<string, string> {\n const headers: Record<string, string> = {}\n\n for (const [key, value] of Object.entries(req.headers)) {\n if (HOP_BY_HOP.has(key)) continue\n if (value === undefined) continue\n headers[key] = Array.isArray(value) ? value.join(', ') : value\n }\n\n return headers\n}\n\n// ─── Adaptive passthrough ────────────────────────────────────────────\n\nasync function passthroughToUpstream(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n fullUrl: string,\n config: ResolvedConfig,\n logger: Logger,\n): Promise<void> {\n const target = detectUpstream(req, fullUrl)\n const upstreamBase = getUpstreamBaseUrl(target, config)\n const upstreamUrl = `${upstreamBase}${fullUrl}`\n const method = req.method?.toUpperCase() ?? 'GET'\n\n logger.log(`[PASSTHROUGH] ${method} ${fullUrl} → ${target} (${upstreamUrl})`)\n\n const headers = buildUpstreamHeaders(req)\n\n try {\n const hasBody = method !== 'GET' && method !== 'HEAD'\n const body = hasBody ? await readBody(req) : undefined\n\n const upstreamRes = await fetch(upstreamUrl, {\n method,\n headers,\n body,\n })\n\n const contentType = upstreamRes.headers.get('Content-Type') || 'application/json'\n const isStreaming = contentType.includes('text/event-stream')\n\n if (isStreaming && upstreamRes.body) {\n setCORSHeaders(res)\n res.writeHead(upstreamRes.status, {\n 'Content-Type': contentType,\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n })\n\n const reader = upstreamRes.body.getReader()\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n res.write(value)\n }\n } finally {\n res.end()\n }\n } else {\n const responseBody = await upstreamRes.arrayBuffer()\n setCORSHeaders(res)\n\n const responseHeaders: Record<string, string> = { 'Content-Type': contentType }\n const reqId = upstreamRes.headers.get('request-id')\n if (reqId) responseHeaders['request-id'] = reqId\n\n res.writeHead(upstreamRes.status, responseHeaders)\n res.end(Buffer.from(responseBody))\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n logger.log(`[ERROR] Passthrough to ${target} failed: ${message}`)\n if (!res.headersSent) {\n setCORSHeaders(res)\n res.writeHead(502, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({\n type: 'error',\n error: { type: 'api_error', message: `Liminal proxy: failed to reach ${target} upstream: ${message}` },\n }))\n }\n }\n}\n\nexport function createRequestHandler(\n deps: HandlerDeps,\n): (req: http.IncomingMessage, res: http.ServerResponse) => void {\n const { sessions, semaphore, latencyMonitor, mitmStats, config, logger } = deps\n const startTime = Date.now()\n\n return async (req, res) => {\n try {\n const method = req.method?.toUpperCase() ?? ''\n const fullUrl = req.url ?? ''\n const url = fullUrl.split('?')[0]\n\n const authType = req.headers['x-api-key'] ? 'x-api-key' : req.headers['authorization'] ? 'bearer' : 'none'\n logger.log(`[REQUEST] ${method} ${fullUrl} (auth: ${authType})`)\n\n // CORS preflight\n if (method === 'OPTIONS') {\n setCORSHeaders(res)\n res.writeHead(204)\n res.end()\n return\n }\n\n // Health check — expanded with per-session data\n if (method === 'GET' && (url === '/health' || url === '/')) {\n const sessionSummaries = sessions.getAllSummaries()\n sendJSON(res, 200, {\n status: 'ok',\n version: config.rscApiKey ? 'connected' : 'no-api-key',\n uptime_ms: Date.now() - startTime,\n concurrency: {\n active_sessions: sessions.activeCount,\n semaphore_available: semaphore.available,\n semaphore_waiting: semaphore.waiting,\n max_concurrent_rsc_calls: config.concurrencyLimit,\n },\n latency: {\n global_p95_ms: latencyMonitor.getGlobalP95(),\n },\n mitm: mitmStats.snapshot(),\n sessions: sessionSummaries.map(s => ({\n session_key: s.key,\n connector: s.connector,\n circuit_state: s.circuitState,\n tokens_processed: s.tokensProcessed,\n tokens_saved: s.tokensSaved,\n calls_total: s.totalCalls,\n calls_compressed: s.compressedCalls,\n calls_failed: s.failedCalls,\n p95_latency_ms: latencyMonitor.getSessionP95(s.key),\n last_active_ago_ms: Date.now() - s.lastAccessedAt,\n })),\n })\n return\n }\n\n // ── Identify session and resolve pipeline ────────────────────\n const sessionKey = identifySession(req, url)\n const pipeline = sessions.getOrCreate(sessionKey)\n\n // ── Compression routes ───────────────────────────────────────\n\n if (method === 'POST' && (url === '/v1/chat/completions' || url === '/chat/completions')) {\n const body = await readBody(req)\n let parsed: unknown\n try {\n parsed = JSON.parse(body.toString('utf-8'))\n } catch {\n sendJSON(res, 400, {\n error: { message: 'Invalid JSON body', type: 'invalid_request_error' },\n })\n return\n }\n\n await handleChatCompletions(req, res, parsed, pipeline, config, logger, semaphore, latencyMonitor, sessionKey.raw)\n return\n }\n\n if (method === 'POST' && (url === '/v1/responses' || url === '/responses')) {\n const body = await readBody(req)\n let parsed: unknown\n try {\n parsed = JSON.parse(body.toString('utf-8'))\n } catch {\n sendJSON(res, 400, {\n error: { message: 'Invalid JSON body', type: 'invalid_request_error' },\n })\n return\n }\n\n await handleResponses(req, res, parsed, pipeline, config, logger, semaphore, latencyMonitor, sessionKey.raw)\n return\n }\n\n if (method === 'POST' && (url === '/v1/messages' || url === '/messages')) {\n const body = await readBody(req)\n let parsed: unknown\n try {\n parsed = JSON.parse(body.toString('utf-8'))\n } catch {\n sendJSON(res, 400, {\n type: 'error',\n error: { type: 'invalid_request_error', message: 'Invalid JSON body' },\n })\n return\n }\n\n await handleAnthropicMessages(req, res, parsed, pipeline, config, logger, semaphore, latencyMonitor, sessionKey.raw)\n return\n }\n\n // ── Adaptive passthrough ─────────────────────────────────────\n await passthroughToUpstream(req, res, fullUrl, config, logger)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n logger.log(`[ERROR] Proxy handler error: ${message}`)\n if (!res.headersSent) {\n sendJSON(res, 500, {\n error: { message: 'Internal proxy error', type: 'server_error' },\n })\n }\n }\n }\n}\n","import * as http from 'node:http'\nimport * as net from 'node:net'\n\nconst MAX_PORT_RETRIES = 5\n\nexport type ConnectHandler = (\n req: http.IncomingMessage,\n socket: net.Socket,\n head: Buffer,\n) => void\n\nexport class ProxyServer {\n private server: http.Server | null = null\n private activePort: number | null = null\n private readonly requestedPort: number\n private readonly handler: (req: http.IncomingMessage, res: http.ServerResponse) => void\n private readonly connectHandler: ConnectHandler | null\n\n constructor(\n port: number,\n handler: (req: http.IncomingMessage, res: http.ServerResponse) => void,\n connectHandler?: ConnectHandler,\n ) {\n this.requestedPort = port\n this.handler = handler\n this.connectHandler = connectHandler ?? null\n }\n\n async start(): Promise<number> {\n let lastError: Error | null = null\n\n for (let attempt = 0; attempt < MAX_PORT_RETRIES; attempt++) {\n const port = this.requestedPort + attempt\n try {\n await this.listen(port)\n this.activePort = port\n return port\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err))\n if ((err as NodeJS.ErrnoException).code !== 'EADDRINUSE') {\n throw lastError\n }\n }\n }\n\n throw lastError ?? new Error(`All ports ${this.requestedPort}-${this.requestedPort + MAX_PORT_RETRIES - 1} in use`)\n }\n\n private listen(port: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const server = http.createServer(this.handler)\n\n // Wire up CONNECT handler for forward proxy mode (Cursor MITM)\n if (this.connectHandler) {\n server.on('connect', this.connectHandler)\n }\n\n server.on('error', reject)\n server.listen(port, '127.0.0.1', () => {\n server.removeListener('error', reject)\n this.server = server\n resolve()\n })\n })\n }\n\n async stop(): Promise<void> {\n if (!this.server) return\n return new Promise((resolve) => {\n this.server!.close(() => {\n this.server = null\n this.activePort = null\n resolve()\n })\n })\n }\n\n isRunning(): boolean {\n return this.server !== null && this.server.listening\n }\n\n getPort(): number | null {\n return this.activePort\n }\n\n /** Expose internal HTTP server for MITM bridge socket injection */\n getHttpServer(): http.Server | null {\n return this.server\n }\n}\n","import { appendFileSync, statSync, renameSync, mkdirSync, existsSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { LOG_FILE, LOG_DIR } from '../config/paths.js'\nimport type { Logger } from '../proxy/handler.js'\n\nconst MAX_LOG_SIZE = 10 * 1024 * 1024 // 10 MB\nconst MAX_BACKUPS = 2\n\nexport class FileLogger implements Logger {\n private readonly logFile: string\n private readonly mirrorStdout: boolean\n\n constructor(options?: { logFile?: string; mirrorStdout?: boolean }) {\n this.logFile = options?.logFile ?? LOG_FILE\n this.mirrorStdout = options?.mirrorStdout ?? false\n\n // Ensure log directory exists\n const logDir = dirname(this.logFile)\n if (!existsSync(logDir)) {\n mkdirSync(logDir, { recursive: true })\n }\n }\n\n log(message: string): void {\n const timestamp = new Date().toISOString().slice(11, 23)\n const line = `[${timestamp}] ${message}\\n`\n\n try {\n appendFileSync(this.logFile, line)\n } catch {\n // If log write fails, try stdout as fallback\n process.stderr.write(`[LOG-WRITE-FAILED] ${line}`)\n }\n\n if (this.mirrorStdout) {\n process.stdout.write(line)\n }\n\n this.rotateIfNeeded()\n }\n\n private rotateIfNeeded(): void {\n try {\n const stats = statSync(this.logFile)\n if (stats.size <= MAX_LOG_SIZE) return\n\n // Rotate: liminal.log -> liminal.log.1 -> liminal.log.2 (drop oldest)\n for (let i = MAX_BACKUPS - 1; i >= 1; i--) {\n const from = `${this.logFile}.${i}`\n const to = `${this.logFile}.${i + 1}`\n if (existsSync(from)) renameSync(from, to)\n }\n renameSync(this.logFile, `${this.logFile}.1`)\n } catch {\n // Rotation failure is non-fatal\n }\n }\n\n getLogFile(): string {\n return this.logFile\n }\n}\n\n/**\n * A simple logger that only writes to stdout (for use during init or when log file isn't available).\n */\nexport class ConsoleLogger implements Logger {\n log(message: string): void {\n const timestamp = new Date().toISOString().slice(11, 23)\n process.stdout.write(`[${timestamp}] ${message}\\n`)\n }\n}\n","import type { SessionKey } from '../proxy/session-identity.js'\nimport { RSCPipelineWrapper } from './pipeline.js'\nimport type { PipelineConfig } from './pipeline.js'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SessionManagerConfig {\n pipelineConfig: PipelineConfig\n maxSessions: number\n sessionTtlMs: number\n onSessionCreated?: (key: string, pipeline: RSCPipelineWrapper) => void\n onSessionEvicted?: (key: string) => void\n}\n\nexport interface SessionHealthEntry {\n key: string\n connector: string\n circuitState: string\n tokensProcessed: number\n tokensSaved: number\n totalCalls: number\n compressedCalls: number\n failedCalls: number\n lastAccessedAt: number\n}\n\ninterface ManagedSession {\n pipeline: RSCPipelineWrapper\n lastAccessedAt: number\n requestCount: number\n connector: string\n}\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_MAX_SESSIONS = 10\nconst DEFAULT_SESSION_TTL_MS = 30 * 60 * 1000 // 30 minutes\nconst EVICTION_INTERVAL_MS = 60_000 // 60 seconds\n\n// ---------------------------------------------------------------------------\n// SessionManager\n// ---------------------------------------------------------------------------\n\nexport class SessionManager {\n private readonly sessions = new Map<string, ManagedSession>()\n private readonly config: Required<Pick<SessionManagerConfig, 'maxSessions' | 'sessionTtlMs'>> &\n SessionManagerConfig\n private evictionTimer: ReturnType<typeof setInterval> | null = null\n\n constructor(config: SessionManagerConfig) {\n this.config = {\n ...config,\n maxSessions: config.maxSessions ?? DEFAULT_MAX_SESSIONS,\n sessionTtlMs: config.sessionTtlMs ?? DEFAULT_SESSION_TTL_MS,\n }\n\n this.evictionTimer = setInterval(() => this.evictStale(), EVICTION_INTERVAL_MS)\n // Allow the process to exit even if the timer is still running\n if (this.evictionTimer.unref) {\n this.evictionTimer.unref()\n }\n }\n\n // ── Public API ──────────────────────────────────────────────────────\n\n getOrCreate(key: SessionKey): RSCPipelineWrapper {\n const existing = this.sessions.get(key.raw)\n if (existing) {\n existing.lastAccessedAt = Date.now()\n existing.requestCount++\n return existing.pipeline\n }\n\n // At capacity — evict least-recently-used\n if (this.sessions.size >= this.config.maxSessions) {\n this.evictLRU()\n }\n\n const pipeline = new RSCPipelineWrapper({\n ...this.config.pipelineConfig,\n sessionId: key.raw,\n })\n\n this.sessions.set(key.raw, {\n pipeline,\n lastAccessedAt: Date.now(),\n requestCount: 1,\n connector: key.connector,\n })\n\n this.config.onSessionCreated?.(key.raw, pipeline)\n return pipeline\n }\n\n getAllSummaries(): SessionHealthEntry[] {\n const entries: SessionHealthEntry[] = []\n for (const [key, managed] of this.sessions) {\n entries.push(this.buildHealthEntry(key, managed))\n }\n return entries\n }\n\n getSessionSummary(key: string): SessionHealthEntry | null {\n const managed = this.sessions.get(key)\n if (!managed) return null\n return this.buildHealthEntry(key, managed)\n }\n\n get activeCount(): number {\n return this.sessions.size\n }\n\n shutdown(): void {\n if (this.evictionTimer !== null) {\n clearInterval(this.evictionTimer)\n this.evictionTimer = null\n }\n this.sessions.clear()\n }\n\n // ── Internals ───────────────────────────────────────────────────────\n\n private buildHealthEntry(key: string, managed: ManagedSession): SessionHealthEntry {\n const summary = managed.pipeline.getSessionSummary()\n return {\n key,\n connector: managed.connector,\n circuitState: managed.pipeline.getCircuitState(),\n tokensProcessed: summary.tokensProcessed,\n tokensSaved: summary.tokensSaved,\n totalCalls: summary.totalCalls,\n compressedCalls: summary.compressedCalls,\n failedCalls: summary.failedCalls,\n lastAccessedAt: managed.lastAccessedAt,\n }\n }\n\n private evictStale(): void {\n const now = Date.now()\n const cutoff = now - this.config.sessionTtlMs\n\n for (const [key, managed] of this.sessions) {\n if (managed.lastAccessedAt < cutoff) {\n this.sessions.delete(key)\n this.config.onSessionEvicted?.(key)\n }\n }\n }\n\n private evictLRU(): void {\n let oldestKey: string | null = null\n let oldestTime = Infinity\n\n for (const [key, managed] of this.sessions) {\n if (managed.lastAccessedAt < oldestTime) {\n oldestTime = managed.lastAccessedAt\n oldestKey = key\n }\n }\n\n if (oldestKey !== null) {\n this.sessions.delete(oldestKey)\n this.config.onSessionEvicted?.(oldestKey)\n }\n }\n}\n","export class SemaphoreTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`Semaphore acquire timed out after ${timeoutMs}ms`)\n this.name = 'SemaphoreTimeoutError'\n }\n}\n\ninterface Waiter {\n resolve: () => void\n reject: (err: Error) => void\n}\n\nexport class Semaphore {\n private permits: number\n private readonly queue: Waiter[] = []\n\n constructor(maxPermits: number) {\n if (maxPermits < 1) throw new RangeError('maxPermits must be >= 1')\n this.permits = maxPermits\n }\n\n get available(): number {\n return this.permits\n }\n\n get waiting(): number {\n return this.queue.length\n }\n\n acquire(timeoutMs?: number): Promise<void> {\n if (this.permits > 0) {\n this.permits--\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve, reject) => {\n const waiter: Waiter = { resolve, reject }\n this.queue.push(waiter)\n\n if (timeoutMs !== undefined && timeoutMs >= 0) {\n const timer = setTimeout(() => {\n const idx = this.queue.indexOf(waiter)\n if (idx !== -1) {\n this.queue.splice(idx, 1)\n reject(new SemaphoreTimeoutError(timeoutMs))\n }\n }, timeoutMs)\n\n const originalResolve = waiter.resolve\n waiter.resolve = () => {\n clearTimeout(timer)\n originalResolve()\n }\n }\n })\n }\n\n release(): void {\n const next = this.queue.shift()\n if (next) {\n next.resolve()\n } else {\n this.permits++\n }\n }\n}\n","export interface LatencyAlert {\n type: 'warning' | 'critical'\n message: string\n sessionKey: string\n p95Ms: number\n thresholdMs: number\n activeSessions: number\n suggestion: string\n}\n\nexport interface LatencyMonitorConfig {\n warningThresholdMs: number\n criticalThresholdMs: number\n windowSize: number\n}\n\nconst DEFAULT_CONFIG: LatencyMonitorConfig = {\n warningThresholdMs: 4000,\n criticalThresholdMs: 8000,\n windowSize: 50,\n}\n\nclass CircularBuffer {\n private readonly buffer: number[]\n private index = 0\n private count = 0\n private readonly capacity: number\n\n constructor(capacity: number) {\n this.capacity = capacity\n this.buffer = new Array<number>(capacity)\n }\n\n push(value: number): void {\n this.buffer[this.index] = value\n this.index = (this.index + 1) % this.capacity\n if (this.count < this.capacity) {\n this.count++\n }\n }\n\n getValues(): number[] {\n if (this.count < this.capacity) {\n return this.buffer.slice(0, this.count)\n }\n return [...this.buffer.slice(this.index), ...this.buffer.slice(0, this.index)]\n }\n\n get size(): number {\n return this.count\n }\n}\n\nfunction calculateP95(values: number[]): number | null {\n if (values.length === 0) return null\n const sorted = [...values].sort((a, b) => a - b)\n const idx = Math.floor(sorted.length * 0.95)\n return sorted[Math.min(idx, sorted.length - 1)]\n}\n\nexport class LatencyMonitor {\n private readonly config: LatencyMonitorConfig\n private readonly sessionWindows = new Map<string, CircularBuffer>()\n private readonly globalWindow: CircularBuffer\n private readonly callbacks: Array<(alert: LatencyAlert) => void> = []\n\n constructor(config?: Partial<LatencyMonitorConfig>) {\n this.config = { ...DEFAULT_CONFIG, ...config }\n this.globalWindow = new CircularBuffer(this.config.windowSize * 4)\n }\n\n record(sessionKey: string, latencyMs: number): LatencyAlert | null {\n let sessionBuf = this.sessionWindows.get(sessionKey)\n if (!sessionBuf) {\n sessionBuf = new CircularBuffer(this.config.windowSize)\n this.sessionWindows.set(sessionKey, sessionBuf)\n }\n sessionBuf.push(latencyMs)\n this.globalWindow.push(latencyMs)\n\n const globalP95 = calculateP95(this.globalWindow.getValues())\n if (globalP95 === null) return null\n\n let alert: LatencyAlert | null = null\n\n if (globalP95 >= this.config.criticalThresholdMs) {\n alert = {\n type: 'critical',\n message: `Global p95 latency ${globalP95.toFixed(0)}ms exceeds critical threshold ${this.config.criticalThresholdMs}ms`,\n sessionKey,\n p95Ms: globalP95,\n thresholdMs: this.config.criticalThresholdMs,\n activeSessions: this.sessionWindows.size,\n suggestion: 'Reduce active sessions or increase latency budget',\n }\n } else if (globalP95 >= this.config.warningThresholdMs) {\n alert = {\n type: 'warning',\n message: `Global p95 latency ${globalP95.toFixed(0)}ms exceeds warning threshold ${this.config.warningThresholdMs}ms`,\n sessionKey,\n p95Ms: globalP95,\n thresholdMs: this.config.warningThresholdMs,\n activeSessions: this.sessionWindows.size,\n suggestion: 'Consider reducing active sessions',\n }\n }\n\n if (alert) {\n for (const cb of this.callbacks) {\n cb(alert)\n }\n }\n\n return alert\n }\n\n getSessionP95(sessionKey: string): number | null {\n const buf = this.sessionWindows.get(sessionKey)\n if (!buf) return null\n return calculateP95(buf.getValues())\n }\n\n getGlobalP95(): number | null {\n return calculateP95(this.globalWindow.getValues())\n }\n\n onAlert(cb: (alert: LatencyAlert) => void): void {\n this.callbacks.push(cb)\n }\n\n get sessionCount(): number {\n return this.sessionWindows.size\n }\n}\n","/**\n * HTTP CONNECT handler for forward proxy mode.\n *\n * When Cursor is launched with --proxy-server=http://127.0.0.1:PORT,\n * it sends CONNECT requests for HTTPS destinations. This handler:\n *\n * 1. Parses the CONNECT host:port request\n * 2. Checks the allowlist — is this an LLM API host?\n * 3. If YES: responds 200 and hands off to MITM interceptor (Phase 3+4)\n * 4. If NO: opens a plain TCP tunnel to the destination (passthrough)\n *\n * The CONNECT event is emitted by Node's http.Server separately from\n * the normal 'request' event, so this is wired up independently.\n */\n\nimport * as net from 'node:net'\nimport type * as http from 'node:http'\nimport { shouldIntercept } from './allowlist.js'\n\nexport interface ConnectLogger {\n log(message: string): void\n}\n\nexport type MitmHandler = (\n clientSocket: net.Socket,\n hostname: string,\n port: number,\n) => void\n\nexport interface ConnectHandlerOptions {\n logger: ConnectLogger\n /** Called for allowlisted hosts that should be MITM-intercepted. */\n onIntercept?: MitmHandler\n /** Called when a connection is passed through (non-allowlisted). */\n onPassthrough?: () => void\n}\n\n/**\n * Create a handler for the http.Server 'connect' event.\n *\n * Usage:\n * server.on('connect', createConnectHandler({ logger }))\n */\nexport function createConnectHandler(\n options: ConnectHandlerOptions,\n): (req: http.IncomingMessage, clientSocket: net.Socket, head: Buffer) => void {\n const { logger, onIntercept, onPassthrough } = options\n\n return (req: http.IncomingMessage, clientSocket: net.Socket, head: Buffer) => {\n const target = req.url ?? ''\n const [hostname, portStr] = parseConnectTarget(target)\n const port = parseInt(portStr, 10) || 443\n\n if (!hostname) {\n logger.log(`[CONNECT] Invalid target: ${target}`)\n clientSocket.write('HTTP/1.1 400 Bad Request\\r\\n\\r\\n')\n clientSocket.destroy()\n return\n }\n\n if (shouldIntercept(hostname) && onIntercept) {\n // Allowlisted host — MITM intercept\n logger.log(`[CONNECT] ${hostname}:${port} → intercept`)\n\n // Tell the client the tunnel is established\n clientSocket.write('HTTP/1.1 200 Connection Established\\r\\n\\r\\n')\n\n // Hand off to the MITM handler (Phase 3+4)\n // Pass any data that arrived with the CONNECT request\n if (head.length > 0) {\n clientSocket.unshift(head)\n }\n\n onIntercept(clientSocket, hostname, port)\n } else {\n // Non-allowlisted host — plain TCP tunnel passthrough\n logger.log(`[TUNNEL] ${hostname}:${port} → passthrough`)\n onPassthrough?.()\n\n const upstreamSocket = net.connect(port, hostname, () => {\n clientSocket.write('HTTP/1.1 200 Connection Established\\r\\n\\r\\n')\n\n // Forward any data that arrived with the CONNECT request\n if (head.length > 0) {\n upstreamSocket.write(head)\n }\n\n // Bidirectional pipe\n clientSocket.pipe(upstreamSocket)\n upstreamSocket.pipe(clientSocket)\n })\n\n // Error handling\n upstreamSocket.on('error', (err) => {\n logger.log(`[TUNNEL] ${hostname}:${port} upstream error: ${err.message}`)\n clientSocket.write('HTTP/1.1 502 Bad Gateway\\r\\n\\r\\n')\n clientSocket.destroy()\n })\n\n clientSocket.on('error', (err) => {\n logger.log(`[TUNNEL] ${hostname}:${port} client error: ${err.message}`)\n upstreamSocket.destroy()\n })\n\n // Cleanup on close\n clientSocket.on('close', () => upstreamSocket.destroy())\n upstreamSocket.on('close', () => clientSocket.destroy())\n }\n }\n}\n\n/**\n * Parse \"host:port\" from CONNECT target.\n * Returns [hostname, port] or ['', ''] on failure.\n */\nfunction parseConnectTarget(target: string): [string, string] {\n const colonIdx = target.lastIndexOf(':')\n if (colonIdx === -1) return [target, '443']\n return [target.slice(0, colonIdx), target.slice(colonIdx + 1)]\n}\n","/**\n * MITM interception allowlist.\n *\n * Only hosts in this list get TLS-intercepted for compression.\n * Everything else passes through as a plain TCP tunnel.\n */\n\nconst MITM_HOSTS = new Set([\n 'api.openai.com',\n 'api.anthropic.com',\n 'generativelanguage.googleapis.com',\n])\n\n/**\n * Check if a hostname should be MITM-intercepted for compression.\n */\nexport function shouldIntercept(hostname: string): boolean {\n return MITM_HOSTS.has(hostname)\n}\n\n/**\n * Get the list of intercepted hosts (for status display).\n */\nexport function getInterceptedHosts(): string[] {\n return [...MITM_HOSTS]\n}\n","/**\n * CA certificate generation and management.\n *\n * Generates a self-signed CA key pair for TLS MITM interception.\n * The CA cert is installed in the system trust store so that Cursor\n * (via --proxy-server) accepts dynamically generated host certs.\n *\n * Storage: ~/.liminal/ca.pem + ca-key.pem (mode 0o600)\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { LIMINAL_DIR } from '../config/paths.js'\nimport forge from 'node-forge'\n\nexport const CA_CERT_PATH = join(LIMINAL_DIR, 'ca.pem')\nexport const CA_KEY_PATH = join(LIMINAL_DIR, 'ca-key.pem')\n\n// ─── Generation ──────────────────────────────────────────────────────\n\n/**\n * Generate a new self-signed CA certificate and private key.\n * Returns { cert, key } as PEM strings.\n */\nexport function generateCA(): { certPem: string; keyPem: string } {\n const keys = forge.pki.rsa.generateKeyPair(2048)\n\n const cert = forge.pki.createCertificate()\n cert.publicKey = keys.publicKey\n cert.serialNumber = generateSerialNumber()\n\n // Valid from now, for 5 years\n cert.validity.notBefore = new Date()\n cert.validity.notAfter = new Date()\n cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 5)\n\n const attrs = [\n { name: 'commonName', value: 'Liminal Proxy CA' },\n { name: 'organizationName', value: 'Liminal (Cognisos)' },\n { shortName: 'OU', value: 'Local Development' },\n ]\n cert.setSubject(attrs)\n cert.setIssuer(attrs) // Self-signed\n\n cert.setExtensions([\n { name: 'basicConstraints', cA: true, critical: true },\n { name: 'keyUsage', keyCertSign: true, cRLSign: true, critical: true },\n {\n name: 'subjectKeyIdentifier',\n },\n ])\n\n // Self-sign with SHA-256\n cert.sign(keys.privateKey, forge.md.sha256.create())\n\n return {\n certPem: forge.pki.certificateToPem(cert),\n keyPem: forge.pki.privateKeyToPem(keys.privateKey),\n }\n}\n\n// ─── Persistence ─────────────────────────────────────────────────────\n\n/**\n * Generate and save CA cert + key to ~/.liminal/.\n * Overwrites existing files.\n */\nexport function generateAndSaveCA(): { certPem: string; keyPem: string } {\n if (!existsSync(LIMINAL_DIR)) {\n mkdirSync(LIMINAL_DIR, { recursive: true, mode: 0o700 })\n }\n\n const { certPem, keyPem } = generateCA()\n\n writeFileSync(CA_CERT_PATH, certPem, { encoding: 'utf-8', mode: 0o644 })\n writeFileSync(CA_KEY_PATH, keyPem, { encoding: 'utf-8', mode: 0o600 })\n\n return { certPem, keyPem }\n}\n\n/**\n * Load existing CA cert and key from disk.\n * Returns null if either file is missing.\n */\nexport function loadCA(): { certPem: string; keyPem: string } | null {\n if (!existsSync(CA_CERT_PATH) || !existsSync(CA_KEY_PATH)) {\n return null\n }\n\n return {\n certPem: readFileSync(CA_CERT_PATH, 'utf-8'),\n keyPem: readFileSync(CA_KEY_PATH, 'utf-8'),\n }\n}\n\n/**\n * Load or generate CA. Prefers existing, generates if missing.\n */\nexport function ensureCA(): { certPem: string; keyPem: string } {\n const existing = loadCA()\n if (existing) return existing\n return generateAndSaveCA()\n}\n\n/**\n * Check if CA certificate files exist.\n */\nexport function hasCA(): boolean {\n return existsSync(CA_CERT_PATH) && existsSync(CA_KEY_PATH)\n}\n\n/**\n * Delete CA cert and key files.\n */\nexport function removeCA(): void {\n if (existsSync(CA_CERT_PATH)) unlinkSync(CA_CERT_PATH)\n if (existsSync(CA_KEY_PATH)) unlinkSync(CA_KEY_PATH)\n}\n\n/**\n * Parse CA cert PEM and return readable info.\n */\nexport function getCAInfo(): { commonName: string; validFrom: Date; validTo: Date; fingerprint: string } | null {\n const ca = loadCA()\n if (!ca) return null\n\n const cert = forge.pki.certificateFromPem(ca.certPem)\n const cn = cert.subject.getField('CN')\n\n // SHA-256 fingerprint\n const der = forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).getBytes()\n const md = forge.md.sha256.create()\n md.update(der)\n const fingerprint = md.digest().toHex().match(/.{2}/g)!.join(':').toUpperCase()\n\n return {\n commonName: cn ? cn.value : 'Unknown',\n validFrom: cert.validity.notBefore,\n validTo: cert.validity.notAfter,\n fingerprint,\n }\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────\n\nfunction generateSerialNumber(): string {\n // Random 16-byte serial number as hex string\n const bytes = forge.random.getBytesSync(16)\n return forge.util.bytesToHex(bytes)\n}\n","/**\n * Platform-specific CA certificate trust management.\n *\n * Installs/removes the Liminal CA from the system trust store\n * so that Cursor (and other Electron apps) accept our dynamic certs.\n */\n\nimport { execSync } from 'node:child_process'\nimport { existsSync, copyFileSync, unlinkSync } from 'node:fs'\nimport { CA_CERT_PATH } from './ca.js'\n\nexport interface TrustResult {\n success: boolean\n message: string\n requiresSudo: boolean\n}\n\n// ─── Install ─────────────────────────────────────────────────────────\n\nexport function installCA(): TrustResult {\n if (!existsSync(CA_CERT_PATH)) {\n return { success: false, message: 'CA certificate not found. Run \"liminal init\" first.', requiresSudo: false }\n }\n\n const platform = process.platform\n\n if (platform === 'darwin') return installMacOS()\n if (platform === 'linux') return installLinux()\n if (platform === 'win32') return installWindows()\n\n return { success: false, message: `Unsupported platform: ${platform}`, requiresSudo: false }\n}\n\n// ─── Remove ──────────────────────────────────────────────────────────\n\nexport function removeCA(): TrustResult {\n const platform = process.platform\n\n if (platform === 'darwin') return removeMacOS()\n if (platform === 'linux') return removeLinux()\n if (platform === 'win32') return removeWindows()\n\n return { success: false, message: `Unsupported platform: ${platform}`, requiresSudo: false }\n}\n\n// ─── Check ───────────────────────────────────────────────────────────\n\nexport function isCATrusted(): boolean {\n const platform = process.platform\n\n if (platform === 'darwin') return isTrustedMacOS()\n if (platform === 'linux') return isTrustedLinux()\n if (platform === 'win32') return isTrustedWindows()\n\n return false\n}\n\n// ─── macOS ───────────────────────────────────────────────────────────\n\nconst MACOS_LABEL = 'Liminal Proxy CA'\n\nfunction installMacOS(): TrustResult {\n try {\n // Add to login keychain and mark as trusted for SSL\n execSync(\n `security add-trusted-cert -r trustRoot -k ~/Library/Keychains/login.keychain-db \"${CA_CERT_PATH}\"`,\n { stdio: 'pipe' },\n )\n return { success: true, message: 'CA installed in login keychain (trusted for SSL)', requiresSudo: false }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (msg.includes('authorization') || msg.includes('permission')) {\n return {\n success: false,\n message: 'Keychain access denied. You may need to unlock your keychain or run with sudo.',\n requiresSudo: true,\n }\n }\n return { success: false, message: `Failed to install CA: ${msg}`, requiresSudo: false }\n }\n}\n\nfunction removeMacOS(): TrustResult {\n try {\n execSync(\n `security delete-certificate -c \"${MACOS_LABEL}\" ~/Library/Keychains/login.keychain-db`,\n { stdio: 'pipe' },\n )\n return { success: true, message: 'CA removed from login keychain', requiresSudo: false }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (msg.includes('could not be found')) {\n return { success: true, message: 'CA was not in keychain (already removed)', requiresSudo: false }\n }\n return { success: false, message: `Failed to remove CA: ${msg}`, requiresSudo: false }\n }\n}\n\nfunction isTrustedMacOS(): boolean {\n try {\n const out = execSync(\n `security find-certificate -c \"${MACOS_LABEL}\" ~/Library/Keychains/login.keychain-db`,\n { stdio: 'pipe', encoding: 'utf-8' },\n )\n return out.includes(MACOS_LABEL)\n } catch {\n return false\n }\n}\n\n// ─── Linux ───────────────────────────────────────────────────────────\n\nconst LINUX_CERT_PATH = '/usr/local/share/ca-certificates/liminal-proxy-ca.crt'\n\nfunction installLinux(): TrustResult {\n try {\n copyFileSync(CA_CERT_PATH, LINUX_CERT_PATH)\n execSync('update-ca-certificates', { stdio: 'pipe' })\n return { success: true, message: 'CA installed in system trust store', requiresSudo: true }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (msg.includes('EACCES') || msg.includes('permission')) {\n return {\n success: false,\n message: `Permission denied. Run with sudo:\\n sudo liminal trust-ca`,\n requiresSudo: true,\n }\n }\n return { success: false, message: `Failed to install CA: ${msg}`, requiresSudo: true }\n }\n}\n\nfunction removeLinux(): TrustResult {\n try {\n if (existsSync(LINUX_CERT_PATH)) {\n unlinkSync(LINUX_CERT_PATH)\n execSync('update-ca-certificates --fresh', { stdio: 'pipe' })\n }\n return { success: true, message: 'CA removed from system trust store', requiresSudo: true }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n return { success: false, message: `Failed to remove CA: ${msg}`, requiresSudo: true }\n }\n}\n\nfunction isTrustedLinux(): boolean {\n return existsSync(LINUX_CERT_PATH)\n}\n\n// ─── Windows ─────────────────────────────────────────────────────────\n\nfunction installWindows(): TrustResult {\n try {\n execSync(`certutil -addstore -user -f \"ROOT\" \"${CA_CERT_PATH}\"`, { stdio: 'pipe' })\n return { success: true, message: 'CA installed in user certificate store', requiresSudo: false }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n return { success: false, message: `Failed to install CA: ${msg}`, requiresSudo: false }\n }\n}\n\nfunction removeWindows(): TrustResult {\n try {\n execSync(`certutil -delstore -user \"ROOT\" \"${MACOS_LABEL}\"`, { stdio: 'pipe' })\n return { success: true, message: 'CA removed from user certificate store', requiresSudo: false }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n return { success: false, message: `Failed to remove CA: ${msg}`, requiresSudo: false }\n }\n}\n\nfunction isTrustedWindows(): boolean {\n try {\n const out = execSync(`certutil -verifystore -user \"ROOT\" \"${MACOS_LABEL}\"`, {\n stdio: 'pipe',\n encoding: 'utf-8',\n })\n return out.includes('Liminal')\n } catch {\n return false\n }\n}\n","/**\n * TLS MITM bridge for intercepting HTTPS LLM API calls.\n *\n * When a CONNECT request arrives for an allowlisted host (e.g. api.openai.com),\n * this bridge:\n *\n * 1. Generates a dynamic TLS certificate for the hostname (signed by our CA)\n * 2. Wraps the client socket in a TLS server socket using that cert\n * 3. Injects the decrypted TLS socket into the existing HTTP server\n * 4. Our normal request handler processes it — compression, forwarding, etc.\n *\n * The client (Cursor) sees a valid certificate chain:\n * Cursor → [our dynamic cert for api.openai.com] → [our CA cert in trust store]\n *\n * The upstream sees a normal HTTPS request from our proxy.\n */\n\nimport * as tls from 'node:tls'\nimport * as net from 'node:net'\nimport type * as http from 'node:http'\nimport { CertGenerator } from './cert-generator.js'\nimport type { MitmHandler, ConnectLogger } from './connect-handler.js'\n\nexport interface MitmBridgeOptions {\n /** The HTTP server to inject decrypted connections into */\n httpServer: http.Server\n /** CA certificate PEM */\n caCertPem: string\n /** CA private key PEM */\n caKeyPem: string\n /** Logger for MITM events */\n logger: ConnectLogger\n}\n\n/**\n * Create a MITM handler that can be passed to createConnectHandler's onIntercept.\n *\n * When called, it wraps the client socket in TLS (presenting a cert for the\n * target hostname), then injects it into the HTTP server so our existing\n * request handlers process it transparently.\n */\nexport function createMitmBridge(options: MitmBridgeOptions): MitmHandler {\n const { httpServer, caCertPem, caKeyPem, logger } = options\n const certGen = new CertGenerator(caCertPem, caKeyPem)\n\n return (clientSocket: net.Socket, hostname: string, _port: number) => {\n try {\n // Generate (or retrieve cached) cert for this hostname\n const { certPem, keyPem } = certGen.getCert(hostname)\n\n // Create a TLS server socket wrapping the client connection\n const tlsSocket = new tls.TLSSocket(clientSocket, {\n isServer: true,\n key: keyPem,\n cert: certPem,\n })\n\n tlsSocket.on('error', (err) => {\n logger.log(`[MITM] TLS error for ${hostname}: ${err.message}`)\n tlsSocket.destroy()\n })\n\n // Inject the decrypted socket into our HTTP server.\n // The server's 'request' event handler will fire with the\n // decrypted HTTP request — our compression pipeline takes over.\n httpServer.emit('connection', tlsSocket)\n\n logger.log(`[MITM] TLS bridge established for ${hostname} (cert cache: ${certGen.cacheSize})`)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n logger.log(`[MITM] Failed to establish bridge for ${hostname}: ${message}`)\n clientSocket.destroy()\n }\n }\n}\n","/**\n * Dynamic TLS certificate generation for MITM interception.\n *\n * When Cursor connects to api.openai.com through our proxy, we need\n * to present a certificate for api.openai.com signed by our CA.\n * This module generates those certificates on-the-fly and caches them.\n */\n\nimport forge from 'node-forge'\n\nexport interface CertPair {\n certPem: string\n keyPem: string\n}\n\ninterface CacheEntry {\n cert: CertPair\n expiresAt: number\n}\n\nconst CERT_TTL_MS = 24 * 60 * 60 * 1000 // 24 hours\nconst MAX_CACHE_SIZE = 50\n\nexport class CertGenerator {\n private readonly caCert: forge.pki.Certificate\n private readonly caKey: forge.pki.rsa.PrivateKey\n private readonly cache = new Map<string, CacheEntry>()\n\n constructor(caCertPem: string, caKeyPem: string) {\n this.caCert = forge.pki.certificateFromPem(caCertPem)\n this.caKey = forge.pki.privateKeyFromPem(caKeyPem)\n }\n\n /**\n * Get or generate a TLS certificate for the given hostname.\n * Certificates are cached for 24 hours.\n */\n getCert(hostname: string): CertPair {\n const now = Date.now()\n\n // Check cache\n const cached = this.cache.get(hostname)\n if (cached && cached.expiresAt > now) {\n return cached.cert\n }\n\n // Generate new cert\n const cert = this.generate(hostname)\n\n // Evict oldest if at capacity\n if (this.cache.size >= MAX_CACHE_SIZE) {\n const oldest = this.cache.keys().next().value\n if (oldest) this.cache.delete(oldest)\n }\n\n this.cache.set(hostname, { cert, expiresAt: now + CERT_TTL_MS })\n return cert\n }\n\n get cacheSize(): number {\n return this.cache.size\n }\n\n private generate(hostname: string): CertPair {\n const keys = forge.pki.rsa.generateKeyPair(2048)\n\n const cert = forge.pki.createCertificate()\n cert.publicKey = keys.publicKey\n cert.serialNumber = randomSerial()\n\n // Valid from 1 day ago (clock skew tolerance) to 24 hours from now\n cert.validity.notBefore = new Date(Date.now() - 24 * 60 * 60 * 1000)\n cert.validity.notAfter = new Date(Date.now() + 24 * 60 * 60 * 1000)\n\n cert.setSubject([\n { name: 'commonName', value: hostname },\n { name: 'organizationName', value: 'Liminal Proxy (local)' },\n ])\n\n // Issuer is our CA\n cert.setIssuer(this.caCert.subject.attributes)\n\n cert.setExtensions([\n { name: 'basicConstraints', cA: false },\n {\n name: 'keyUsage',\n digitalSignature: true,\n keyEncipherment: true,\n critical: true,\n },\n {\n name: 'extKeyUsage',\n serverAuth: true,\n },\n {\n name: 'subjectAltName',\n altNames: [{ type: 2, value: hostname }], // DNS name\n },\n ])\n\n // Sign with our CA's private key\n cert.sign(this.caKey, forge.md.sha256.create())\n\n return {\n certPem: forge.pki.certificateToPem(cert),\n keyPem: forge.pki.privateKeyToPem(keys.privateKey),\n }\n }\n}\n\nfunction randomSerial(): string {\n return forge.util.bytesToHex(forge.random.getBytesSync(16))\n}\n","/**\n * Lightweight MITM connection stats for the health/status endpoints.\n */\n\nexport interface MitmSnapshot {\n /** Total CONNECT requests intercepted (TLS MITM) */\n intercepted: number\n /** Total CONNECT requests passed through (non-allowlisted) */\n passthrough: number\n /** Currently active TLS bridges */\n activeBridges: number\n /** Unique hostnames intercepted */\n hostsIntercepted: string[]\n /** Whether the MITM bridge is wired and ready */\n enabled: boolean\n}\n\nexport class MitmStats {\n private _intercepted = 0\n private _passthrough = 0\n private _activeBridges = 0\n private _hosts = new Set<string>()\n private _enabled = false\n\n enable(): void {\n this._enabled = true\n }\n\n recordIntercept(hostname: string): void {\n this._intercepted++\n this._activeBridges++\n this._hosts.add(hostname)\n }\n\n recordBridgeClosed(): void {\n if (this._activeBridges > 0) this._activeBridges--\n }\n\n recordPassthrough(): void {\n this._passthrough++\n }\n\n snapshot(): MitmSnapshot {\n return {\n intercepted: this._intercepted,\n passthrough: this._passthrough,\n activeBridges: this._activeBridges,\n hostsIntercepted: [...this._hosts],\n enabled: this._enabled,\n }\n }\n}\n","import { readFileSync, writeFileSync, unlinkSync, existsSync } from 'node:fs'\nimport { fork } from 'node:child_process'\nimport { fileURLToPath } from 'node:url'\nimport { PID_FILE } from '../config/paths.js'\nimport type { ProxyServer } from '../proxy/server.js'\nimport type { Logger } from '../proxy/handler.js'\n\n/**\n * Write the current process PID to ~/.liminal/liminal.pid.\n */\nexport function writePidFile(pid: number): void {\n writeFileSync(PID_FILE, String(pid), 'utf-8')\n}\n\n/**\n * Read PID from ~/.liminal/liminal.pid. Returns null if file doesn't exist.\n */\nexport function readPidFile(): number | null {\n if (!existsSync(PID_FILE)) return null\n try {\n const content = readFileSync(PID_FILE, 'utf-8').trim()\n const pid = parseInt(content, 10)\n return isNaN(pid) ? null : pid\n } catch {\n return null\n }\n}\n\n/**\n * Remove the PID file.\n */\nexport function removePidFile(): void {\n try {\n if (existsSync(PID_FILE)) unlinkSync(PID_FILE)\n } catch {\n // Ignore — file may already be gone\n }\n}\n\n/**\n * Check if a process with the given PID is alive.\n */\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Check if the Liminal daemon is currently running.\n * Cleans up stale PID files automatically.\n */\nexport function isDaemonRunning(): { running: boolean; pid?: number } {\n const pid = readPidFile()\n if (pid === null) return { running: false }\n\n if (isProcessAlive(pid)) {\n return { running: true, pid }\n }\n\n // Stale PID file — process is dead\n removePidFile()\n return { running: false }\n}\n\n/**\n * Set up signal handlers for graceful shutdown.\n */\nexport function setupSignalHandlers(server: ProxyServer, logger: Logger): void {\n const shutdown = async (signal: string) => {\n logger.log(`[DAEMON] Received ${signal}, shutting down...`)\n try {\n await server.stop()\n } catch {\n // Best-effort server stop\n }\n removePidFile()\n logger.log('[DAEMON] Stopped.')\n process.exit(0)\n }\n\n process.on('SIGTERM', () => shutdown('SIGTERM'))\n process.on('SIGINT', () => shutdown('SIGINT'))\n\n process.on('uncaughtException', (err) => {\n logger.log(`[FATAL] Uncaught exception: ${err.message}`)\n removePidFile()\n process.exit(1)\n })\n\n process.on('unhandledRejection', (reason) => {\n const message = reason instanceof Error ? reason.message : String(reason)\n logger.log(`[FATAL] Unhandled rejection: ${message}`)\n removePidFile()\n process.exit(1)\n })\n}\n\n/**\n * Fork a detached child process to run the daemon in the background.\n * Returns the child PID.\n */\nexport function forkDaemon(binPath: string, extraArgs: string[] = []): number {\n const child = fork(binPath, ['start', '--_forked', ...extraArgs], {\n detached: true,\n stdio: 'ignore',\n })\n\n child.unref()\n return child.pid!\n}\n\n/**\n * Resolve the bin.ts/bin.js entry point path from import.meta.url.\n */\nexport function resolveBinPath(importMetaUrl: string): string {\n return fileURLToPath(importMetaUrl)\n}\n\n/**\n * Sleep for a given number of milliseconds.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","import { loadConfig, applyOverrides, isConfigured } from '../config/loader.js'\nimport { createRequestHandler } from '../proxy/handler.js'\nimport type { HandlerDeps } from '../proxy/handler.js'\nimport { ProxyServer } from '../proxy/server.js'\nimport { FileLogger } from '../daemon/logger.js'\nimport { SessionManager } from '../rsc/session-manager.js'\nimport { Semaphore } from '../rsc/semaphore.js'\nimport { LatencyMonitor } from '../rsc/latency-monitor.js'\nimport { createConnectHandler } from '../tls/connect-handler.js'\nimport { hasCA, loadCA } from '../tls/ca.js'\nimport { isCATrusted } from '../tls/trust.js'\nimport { createMitmBridge } from '../tls/mitm-bridge.js'\nimport { MitmStats } from '../tls/mitm-stats.js'\nimport {\n isDaemonRunning,\n writePidFile,\n setupSignalHandlers,\n forkDaemon,\n resolveBinPath,\n} from '../daemon/lifecycle.js'\nimport type { ResolvedConfig, Tool } from '../types.js'\nimport { printBanner } from '../version.js'\n\nexport async function startCommand(flags: Map<string, string | true>): Promise<void> {\n const isDaemon = flags.has('d') || flags.has('daemon')\n const isForked = flags.has('_forked')\n\n // Check if already running (skip for forked processes — parent already checked)\n if (!isForked) {\n const state = isDaemonRunning()\n if (state.running) {\n console.error(`Liminal daemon is already running (PID ${state.pid}).`)\n console.error('Use \"liminal stop\" first, or \"liminal status\" to check.')\n process.exit(1)\n }\n }\n\n // Check config\n if (!isConfigured()) {\n console.error('Liminal is not configured. Run \"liminal init\" first.')\n process.exit(1)\n }\n\n // Load and apply config\n let config = loadConfig()\n const portOverride = flags.get('port')\n const upstreamOverride = flags.get('upstream')\n config = applyOverrides(config, {\n ...(typeof portOverride === 'string' ? { port: parseInt(portOverride, 10) } : {}),\n ...(typeof upstreamOverride === 'string' ? { upstreamBaseUrl: upstreamOverride } : {}),\n })\n\n // Background mode: fork and exit parent\n if (isDaemon && !isForked) {\n const extraArgs: string[] = []\n if (portOverride) extraArgs.push('--port', String(portOverride))\n if (upstreamOverride) extraArgs.push('--upstream', String(upstreamOverride))\n\n const binPath = resolveBinPath(import.meta.url)\n const childPid = forkDaemon(binPath, extraArgs)\n\n console.log(`Liminal daemon started in background (PID ${childPid})`)\n console.log(`Proxy: http://127.0.0.1:${config.port}/v1`)\n console.log('Logs: ~/.liminal/logs/liminal.log')\n process.exit(0)\n }\n\n // Foreground mode: run the server in this process\n const isForeground = !isDaemon || isForked\n const logger = new FileLogger({ mirrorStdout: isForeground && !isForked })\n\n // Build the resolved config for the proxy\n const resolvedConfig: ResolvedConfig = {\n rscApiKey: config.apiKey,\n rscBaseUrl: config.apiBaseUrl,\n proxyPort: config.port,\n compressionThreshold: config.compressionThreshold,\n aggregateThreshold: config.aggregateThreshold,\n hotFraction: config.hotFraction,\n coldFraction: config.coldFraction,\n compressRoles: config.compressRoles,\n compressToolResults: config.compressToolResults,\n learnFromResponses: config.learnFromResponses,\n latencyBudgetMs: config.latencyBudgetMs || undefined,\n upstreamBaseUrl: config.upstreamBaseUrl,\n anthropicUpstreamUrl: config.anthropicUpstreamUrl,\n enabled: config.enabled,\n tools: config.tools as Tool[],\n concurrencyLimit: config.concurrencyLimit,\n concurrencyTimeoutMs: config.concurrencyTimeoutMs,\n maxSessions: config.maxSessions,\n sessionTtlMs: config.sessionTtlMs,\n latencyWarningMs: config.latencyWarningMs,\n latencyCriticalMs: config.latencyCriticalMs,\n }\n\n // Create multi-session infrastructure\n const semaphore = new Semaphore(resolvedConfig.concurrencyLimit)\n const latencyMonitor = new LatencyMonitor({\n warningThresholdMs: resolvedConfig.latencyWarningMs,\n criticalThresholdMs: resolvedConfig.latencyCriticalMs,\n })\n\n // Wire up pipeline events for each new session\n function wireSessionEvents(key: string, pipeline: import('../rsc/pipeline.js').RSCPipelineWrapper): void {\n pipeline.events.on('compression', (event) => {\n if (event.tokensSaved > 0) {\n logger.log(`[LIMINAL] [${key}] Compressed: ${event.tokensSaved} tokens saved (${event.ratio.toFixed(3)} ratio)`)\n }\n })\n pipeline.events.on('compression_skipped', (event) => {\n const detail = event.reason === 'latency_budget'\n ? `${event.reason} (${event.estimatedTokens}tok, budget:${event.budgetMs}ms, elapsed:${event.elapsedMs}ms)`\n : event.reason === 'below_threshold'\n ? `${event.reason} (${event.estimatedTokens}tok < ${config.compressionThreshold}tok threshold)`\n : `${event.reason} (${event.estimatedTokens}tok)`\n logger.log(`[LIMINAL] [${key}] Skipped: ${detail}`)\n })\n pipeline.events.on('error', (event) => {\n logger.log(`[LIMINAL] [${key}] Error: ${event.error.message}`)\n })\n pipeline.events.on('degradation', (event) => {\n logger.log(`[LIMINAL] [${key}] Circuit ${event.circuitState}: ${event.reason}`)\n })\n }\n\n const sessions = new SessionManager({\n pipelineConfig: {\n rscApiKey: config.apiKey,\n rscBaseUrl: config.apiBaseUrl,\n compressionThreshold: config.compressionThreshold,\n learnFromResponses: config.learnFromResponses,\n latencyBudgetMs: config.latencyBudgetMs || undefined,\n },\n maxSessions: resolvedConfig.maxSessions,\n sessionTtlMs: resolvedConfig.sessionTtlMs,\n onSessionCreated: (key, pipeline) => {\n logger.log(`[SESSION] Created: ${key}`)\n wireSessionEvents(key, pipeline)\n },\n onSessionEvicted: (key) => {\n logger.log(`[SESSION] Evicted: ${key} (idle)`)\n },\n })\n\n latencyMonitor.onAlert((alert) => {\n logger.log(`[LATENCY] ${alert.type.toUpperCase()}: ${alert.message} (${alert.activeSessions} sessions) — ${alert.suggestion}`)\n })\n\n // MITM stats tracker\n const mitmStats = new MitmStats()\n\n // Create server with optional CONNECT handler for Cursor MITM\n const deps: HandlerDeps = { sessions, semaphore, latencyMonitor, mitmStats, config: resolvedConfig, logger }\n const handler = createRequestHandler(deps)\n\n // MITM intercept handler — set after server starts (needs http.Server ref)\n let mitmHandler: ((socket: import('node:net').Socket, hostname: string, port: number) => void) | undefined\n\n const connectHandler = createConnectHandler({\n logger,\n onIntercept: (socket, hostname, port) => {\n if (mitmHandler) {\n mitmStats.recordIntercept(hostname)\n mitmHandler(socket, hostname, port)\n } else {\n logger.log(`[MITM] No bridge available for ${hostname} — falling back to passthrough`)\n mitmStats.recordPassthrough()\n }\n },\n onPassthrough: () => {\n mitmStats.recordPassthrough()\n },\n })\n\n const server = new ProxyServer(config.port, handler, connectHandler)\n\n // Setup graceful shutdown\n setupSignalHandlers(server, logger)\n\n // Start listening\n try {\n const actualPort = await server.start()\n writePidFile(process.pid)\n\n logger.log(`[DAEMON] Liminal proxy started on http://127.0.0.1:${actualPort}`)\n logger.log(`[DAEMON] Upstream (OpenAI): ${config.upstreamBaseUrl}`)\n logger.log(`[DAEMON] Upstream (Anthropic): ${config.anthropicUpstreamUrl}`)\n logger.log(`[DAEMON] Liminal API: ${config.apiBaseUrl}`)\n logger.log(`[DAEMON] PID: ${process.pid}`)\n logger.log(`[DAEMON] Max sessions: ${resolvedConfig.maxSessions}, Concurrency limit: ${resolvedConfig.concurrencyLimit}`)\n\n // Wire MITM bridge if CA is available and trusted\n const caReady = hasCA() && isCATrusted()\n if (caReady) {\n const httpServer = server.getHttpServer()\n const ca = loadCA()\n if (httpServer && ca) {\n mitmHandler = createMitmBridge({\n httpServer,\n caCertPem: ca.certPem,\n caKeyPem: ca.keyPem,\n logger,\n })\n mitmStats.enable()\n logger.log('[MITM] TLS bridge active — intercepting LLM API calls')\n }\n }\n\n // Log MITM proxy status\n logger.log(`[DAEMON] CONNECT handler: active | MITM: ${caReady ? 'ready (CA trusted)' : 'passthrough only (run liminal trust-ca)'}`)\n\n if (isForeground && !isForked) {\n printBanner()\n console.log(` Liminal proxy running on http://127.0.0.1:${actualPort}/v1`)\n console.log(` Upstream: ${config.upstreamBaseUrl}`)\n console.log(` Max sessions: ${resolvedConfig.maxSessions} | Concurrency: ${resolvedConfig.concurrencyLimit}`)\n if (caReady) {\n console.log(' MITM: active (Cursor interception ready)')\n }\n console.log()\n console.log(' Point your AI tool\\'s base URL here. Press Ctrl+C to stop.')\n console.log()\n }\n\n // Check RSC API health on startup using a temporary probe pipeline\n const { RSCPipelineWrapper } = await import('../rsc/pipeline.js')\n const probe = new RSCPipelineWrapper({\n rscApiKey: config.apiKey,\n rscBaseUrl: config.apiBaseUrl,\n compressionThreshold: config.compressionThreshold,\n learnFromResponses: false,\n })\n const healthy = await probe.healthCheck()\n if (healthy) {\n logger.log('[DAEMON] Liminal API health check: OK')\n } else {\n logger.log('[DAEMON] Liminal API health check: FAILED (will retry on first request)')\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n console.error(`Failed to start proxy: ${message}`)\n process.exit(1)\n }\n}\n","import {\n isDaemonRunning,\n readPidFile,\n removePidFile,\n isProcessAlive,\n sleep,\n} from '../daemon/lifecycle.js'\n\nexport async function stopCommand(): Promise<void> {\n const state = isDaemonRunning()\n\n if (!state.running || !state.pid) {\n console.log('Liminal daemon is not running.')\n return\n }\n\n const pid = state.pid\n console.log(`Stopping Liminal daemon (PID ${pid})...`)\n\n // Send SIGTERM for graceful shutdown\n try {\n process.kill(pid, 'SIGTERM')\n } catch {\n // Process may have already exited\n removePidFile()\n console.log('Liminal daemon stopped.')\n return\n }\n\n // Poll for up to 5 seconds\n for (let i = 0; i < 25; i++) {\n await sleep(200)\n if (!isProcessAlive(pid)) {\n removePidFile()\n console.log(`Liminal daemon stopped (PID ${pid}).`)\n return\n }\n }\n\n // Force kill after timeout\n try {\n process.kill(pid, 'SIGKILL')\n } catch {\n // Already dead\n }\n\n removePidFile()\n console.log(`Liminal daemon force-killed (PID ${pid}).`)\n}\n","import { isDaemonRunning } from '../daemon/lifecycle.js'\nimport { loadConfig, isConfigured } from '../config/loader.js'\n\ninterface SessionInfo {\n session_key: string\n connector: string\n circuit_state: string\n tokens_processed: number\n tokens_saved: number\n calls_total: number\n calls_compressed: number\n calls_failed: number\n p95_latency_ms: number | null\n last_active_ago_ms: number\n}\n\ninterface MitmInfo {\n enabled: boolean\n intercepted: number\n passthrough: number\n activeBridges: number\n hostsIntercepted: string[]\n}\n\ninterface HealthResponse {\n status: string\n version: string\n uptime_ms: number\n concurrency: {\n active_sessions: number\n semaphore_available: number\n semaphore_waiting: number\n max_concurrent_rsc_calls: number\n }\n latency: {\n global_p95_ms: number | null\n }\n mitm?: MitmInfo\n sessions: SessionInfo[]\n}\n\nexport async function statusCommand(): Promise<void> {\n if (!isConfigured()) {\n console.log('Liminal: not configured')\n console.log('Run \"liminal init\" to set up.')\n return\n }\n\n const state = isDaemonRunning()\n\n if (!state.running || !state.pid) {\n console.log('Liminal Daemon: stopped')\n console.log('Run \"liminal start\" to start the proxy.')\n return\n }\n\n const config = loadConfig()\n const port = config.port\n\n // Try to reach the daemon's /health endpoint\n try {\n const res = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: AbortSignal.timeout(3000),\n })\n const data = await res.json() as HealthResponse\n\n const uptime = formatUptime(data.uptime_ms)\n\n console.log(`Liminal Daemon: running (PID ${state.pid}, port ${port})`)\n console.log(`Status: ${data.status} (${data.version})`)\n console.log(`Uptime: ${uptime}`)\n console.log()\n\n // Concurrency\n const c = data.concurrency\n console.log(`Sessions: ${c.active_sessions} active (max ${config.maxSessions})`)\n console.log(`Semaphore: ${c.semaphore_available}/${c.max_concurrent_rsc_calls} available` +\n (c.semaphore_waiting > 0 ? ` (${c.semaphore_waiting} waiting)` : ''))\n\n // Global latency\n const globalP95 = data.latency.global_p95_ms\n if (globalP95 !== null) {\n const latencyFlag = globalP95 >= config.latencyCriticalMs ? ' CRITICAL'\n : globalP95 >= config.latencyWarningMs ? ' WARNING'\n : ''\n console.log(`Latency: p95 ${globalP95.toFixed(0)}ms${latencyFlag}`)\n }\n\n // MITM proxy info\n if (data.mitm) {\n const m = data.mitm\n if (m.enabled) {\n console.log(`MITM: active (${m.intercepted} intercepted, ${m.passthrough} passthrough, ${m.activeBridges} active)`)\n if (m.hostsIntercepted.length > 0) {\n console.log(` Hosts: ${m.hostsIntercepted.join(', ')}`)\n }\n } else {\n console.log('MITM: disabled (run \"liminal trust-ca\" to enable)')\n }\n }\n\n // Per-session details\n if (data.sessions.length > 0) {\n console.log()\n console.log('─── Sessions ───')\n for (const s of data.sessions) {\n const savingsPercent = s.tokens_processed > 0\n ? ((s.tokens_saved / s.tokens_processed) * 100).toFixed(1)\n : '0.0'\n const activeAgo = formatUptime(s.last_active_ago_ms)\n const p95 = s.p95_latency_ms !== null ? `${s.p95_latency_ms.toFixed(0)}ms` : '-'\n\n console.log()\n console.log(` ${s.connector} [${s.session_key}]`)\n console.log(` Circuit: ${s.circuit_state}`)\n console.log(` Tokens: ${s.tokens_processed.toLocaleString()} processed, ${s.tokens_saved.toLocaleString()} saved (${savingsPercent}%)`)\n console.log(` Calls: ${s.calls_total} total (${s.calls_compressed} compressed, ${s.calls_failed} failed)`)\n console.log(` Latency: p95 ${p95}`)\n console.log(` Active: ${activeAgo} ago`)\n }\n } else {\n console.log()\n console.log('No active sessions.')\n }\n } catch {\n // Can't reach the daemon, but PID is alive — might still be starting\n console.log(`Liminal Daemon: running (PID ${state.pid}, port ${port})`)\n console.log('Status: unknown (could not reach /health)')\n }\n}\n\nfunction formatUptime(ms: number): string {\n const seconds = Math.floor(ms / 1000)\n const minutes = Math.floor(seconds / 60)\n const hours = Math.floor(minutes / 60)\n const days = Math.floor(hours / 24)\n\n if (days > 0) return `${days}d ${hours % 24}h ${minutes % 60}m`\n if (hours > 0) return `${hours}h ${minutes % 60}m`\n if (minutes > 0) return `${minutes}m ${seconds % 60}s`\n return `${seconds}s`\n}\n","import { isDaemonRunning } from '../daemon/lifecycle.js'\nimport { loadConfig, isConfigured } from '../config/loader.js'\n\nexport async function summaryCommand(): Promise<void> {\n if (!isConfigured()) {\n console.log('Liminal is not configured. Run \"liminal init\" first.')\n return\n }\n\n const state = isDaemonRunning()\n\n if (!state.running || !state.pid) {\n console.log('Liminal daemon is not running. Start it with \"liminal start\".')\n return\n }\n\n const config = loadConfig()\n const port = config.port\n\n try {\n const res = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: AbortSignal.timeout(3000),\n })\n const data = await res.json() as {\n circuit_state: string\n session_id: string\n uptime_ms: number\n session?: {\n tokens_processed: number\n tokens_saved: number\n calls_total: number\n calls_compressed: number\n calls_skipped: number\n calls_failed: number\n patterns_learned: number\n estimated_cost_saved_usd: number\n }\n }\n\n const uptime = formatUptime(data.uptime_ms)\n\n console.log()\n console.log(` Session: ${data.session_id}`)\n console.log(` Uptime: ${uptime}`)\n console.log()\n\n if (data.session) {\n const s = data.session\n const savingsPercent = s.tokens_processed > 0\n ? ((s.tokens_saved / s.tokens_processed) * 100).toFixed(1)\n : '0.0'\n const compressionRate = s.calls_total > 0\n ? ((s.calls_compressed / s.calls_total) * 100).toFixed(0)\n : '0'\n\n console.log(' Compression:')\n console.log(` Tokens processed: ${s.tokens_processed.toLocaleString()}`)\n console.log(` Tokens saved: ${s.tokens_saved.toLocaleString()} (${savingsPercent}%)`)\n console.log(` Compression rate: ${compressionRate}% of calls compressed`)\n console.log(` Patterns learned: ${s.patterns_learned.toLocaleString()}`)\n console.log()\n console.log(' Calls:')\n console.log(` Total: ${s.calls_total}`)\n console.log(` Compressed: ${s.calls_compressed}`)\n console.log(` Skipped: ${s.calls_skipped}`)\n console.log(` Failed: ${s.calls_failed}`)\n console.log()\n console.log(' Cost Savings:')\n console.log(` Estimated: $${s.estimated_cost_saved_usd.toFixed(4)} USD`)\n console.log()\n } else {\n console.log(' No session data available yet.')\n console.log()\n }\n\n console.log(` Circuit: ${data.circuit_state}`)\n console.log(` API: ${config.apiBaseUrl}`)\n console.log(` Upstream: ${config.upstreamBaseUrl}`)\n console.log()\n } catch {\n console.error('Could not reach the Liminal daemon. Is it running?')\n console.error(`Tried http://127.0.0.1:${port}/health`)\n process.exit(1)\n }\n}\n\nfunction formatUptime(ms: number): string {\n const seconds = Math.floor(ms / 1000)\n const minutes = Math.floor(seconds / 60)\n const hours = Math.floor(minutes / 60)\n const days = Math.floor(hours / 24)\n\n if (days > 0) return `${days}d ${hours % 24}h ${minutes % 60}m`\n if (hours > 0) return `${hours}h ${minutes % 60}m`\n if (minutes > 0) return `${minutes}m ${seconds % 60}s`\n return `${seconds}s`\n}\n","import { loadConfig, saveConfig, isConfigured, maskApiKey } from '../config/loader.js'\nimport { CONFIGURABLE_KEYS } from '../config/schema.js'\nimport { CONFIG_FILE } from '../config/paths.js'\n\nexport async function configCommand(flags: Map<string, string | true>): Promise<void> {\n const getKey = flags.get('get')\n const setKv = flags.get('set')\n\n // rsc config --get <key>\n if (typeof getKey === 'string') {\n if (!isConfigured()) {\n console.error('Liminal is not configured. Run \"liminal init\" first.')\n process.exit(1)\n }\n const config = loadConfig()\n const value = (config as unknown as Record<string, unknown>)[getKey]\n if (value === undefined) {\n console.error(`Unknown config key: ${getKey}`)\n process.exit(1)\n }\n console.log(getKey === 'apiKey' ? maskApiKey(String(value)) : String(value))\n return\n }\n\n // rsc config --set <key>=<value>\n if (typeof setKv === 'string') {\n const eqIdx = setKv.indexOf('=')\n if (eqIdx === -1) {\n console.error('Usage: liminal config --set key=value')\n process.exit(1)\n }\n const key = setKv.slice(0, eqIdx)\n const rawValue = setKv.slice(eqIdx + 1)\n\n if (!CONFIGURABLE_KEYS.has(key) && key !== 'apiKey') {\n console.error(`Unknown or non-configurable key: ${key}`)\n console.error(`Configurable keys: ${[...CONFIGURABLE_KEYS].join(', ')}`)\n process.exit(1)\n }\n\n // Parse value based on key type\n let parsedValue: unknown = rawValue\n if (key === 'port' || key === 'compressionThreshold' || key === 'latencyBudgetMs') {\n parsedValue = parseInt(rawValue, 10)\n if (isNaN(parsedValue as number)) {\n console.error(`Invalid number for ${key}: ${rawValue}`)\n process.exit(1)\n }\n } else if (key === 'learnFromResponses' || key === 'enabled') {\n parsedValue = rawValue === 'true' || rawValue === '1'\n } else if (key === 'compressRoles') {\n parsedValue = rawValue.split(',').map((s) => s.trim())\n }\n\n saveConfig({ [key]: parsedValue })\n console.log(`Set ${key} = ${key === 'apiKey' ? maskApiKey(rawValue) : rawValue}`)\n return\n }\n\n // rsc config (no flags) — show all\n if (!isConfigured()) {\n console.log(`Liminal is not configured. Run \"liminal init\" first.`)\n console.log(`Config file: ${CONFIG_FILE}`)\n return\n }\n\n const config = loadConfig()\n console.log()\n console.log(` Config: ${CONFIG_FILE}`)\n console.log()\n console.log(` apiKey: ${maskApiKey(config.apiKey)}`)\n console.log(` apiBaseUrl: ${config.apiBaseUrl}`)\n console.log(` upstreamBaseUrl: ${config.upstreamBaseUrl}`)\n console.log(` anthropicUpstreamUrl: ${config.anthropicUpstreamUrl}`)\n console.log(` tools: ${config.tools.length > 0 ? config.tools.join(', ') : '(none)'}`)\n console.log(` port: ${config.port}`)\n console.log(` compressionThreshold: ${config.compressionThreshold}`)\n console.log(` compressRoles: ${config.compressRoles.join(', ')}`)\n console.log(` learnFromResponses: ${config.learnFromResponses}`)\n console.log(` latencyBudgetMs: ${config.latencyBudgetMs || 'auto'}`)\n console.log(` enabled: ${config.enabled}`)\n console.log()\n}\n","import { readFileSync, existsSync, statSync, createReadStream } from 'node:fs'\nimport { watchFile, unwatchFile } from 'node:fs'\nimport { LOG_FILE } from '../config/paths.js'\n\nexport async function logsCommand(flags: Map<string, string | true>): Promise<void> {\n const follow = flags.has('follow') || flags.has('f')\n const linesFlag = flags.get('lines') ?? flags.get('n')\n const lines = typeof linesFlag === 'string' ? parseInt(linesFlag, 10) : 50\n\n if (!existsSync(LOG_FILE)) {\n console.log('No log file found. Start the daemon with \"liminal start\" to generate logs.')\n return\n }\n\n // Read and display last N lines\n const content = readFileSync(LOG_FILE, 'utf-8')\n const allLines = content.split('\\n')\n const tail = allLines.slice(-lines - 1) // -1 to account for trailing newline\n process.stdout.write(tail.join('\\n'))\n\n if (!follow) return\n\n // Follow mode: watch for changes and stream new content\n let lastSize = statSync(LOG_FILE).size\n\n watchFile(LOG_FILE, { interval: 500 }, (curr) => {\n if (curr.size > lastSize) {\n const stream = createReadStream(LOG_FILE, { start: lastSize, encoding: 'utf-8' })\n stream.on('data', (chunk) => process.stdout.write(chunk as string))\n stream.on('end', () => { lastSize = curr.size })\n } else if (curr.size < lastSize) {\n // File was rotated — read from beginning\n lastSize = 0\n }\n })\n\n // Keep the process alive and handle Ctrl+C\n process.on('SIGINT', () => {\n unwatchFile(LOG_FILE)\n process.exit(0)\n })\n\n // Block forever\n await new Promise(() => {})\n}\n","import { existsSync, rmSync, readFileSync } from 'node:fs'\nimport {\n detectShellProfile,\n removeLiminalFromShellProfile,\n findLiminalExportsInProfile,\n} from '../config/shell.js'\nimport { LIMINAL_DIR, CONFIG_FILE } from '../config/paths.js'\nimport { isDaemonRunning, removePidFile, isProcessAlive, sleep } from '../daemon/lifecycle.js'\nimport { CONNECTORS, getConnectors } from '../connectors/index.js'\nimport { selectPrompt } from '../ui/prompts.js'\nimport type { ConnectorId } from '../connectors/types.js'\n\n// ─── ANSI helpers ────────────────────────────────────────────────────\nconst BOLD = '\\x1b[1m'\nconst DIM = '\\x1b[2m'\nconst CYAN = '\\x1b[36m'\nconst GREEN = '\\x1b[32m'\nconst YELLOW = '\\x1b[33m'\nconst RED = '\\x1b[31m'\nconst RESET = '\\x1b[0m'\n\n/**\n * Load the list of configured tools from ~/.liminal/config.json.\n */\nfunction loadConfiguredTools(): ConnectorId[] {\n if (!existsSync(CONFIG_FILE)) return []\n try {\n const raw = readFileSync(CONFIG_FILE, 'utf-8')\n const config = JSON.parse(raw)\n if (Array.isArray(config.tools)) return config.tools as ConnectorId[]\n } catch {\n // Corrupted config — treat as empty\n }\n return []\n}\n\nexport async function uninstallCommand(): Promise<void> {\n console.log()\n console.log(` ${BOLD}Liminal Uninstall${RESET}`)\n console.log()\n\n // ── 1. Confirm ────────────────────────────────────────────────\n const confirm = await selectPrompt<boolean>({\n message: 'Remove Liminal configuration and restore tool settings?',\n options: [\n { label: 'Yes', value: true, description: 'Undo all Liminal setup' },\n { label: 'No', value: false, description: 'Cancel' },\n ],\n defaultIndex: 1, // Default to No for safety\n })\n\n if (confirm !== true) {\n console.log()\n console.log(' Cancelled.')\n console.log()\n return\n }\n\n console.log()\n\n // ── 2. Stop daemon if running ─────────────────────────────────\n const state = isDaemonRunning()\n if (state.running && state.pid) {\n console.log(` Stopping Liminal daemon (PID ${state.pid})...`)\n try {\n process.kill(state.pid, 'SIGTERM')\n // Wait up to 3 seconds for graceful shutdown\n for (let i = 0; i < 15; i++) {\n await sleep(200)\n if (!isProcessAlive(state.pid)) break\n }\n if (isProcessAlive(state.pid)) {\n process.kill(state.pid, 'SIGKILL')\n }\n } catch {\n // Already dead\n }\n removePidFile()\n console.log(` ${GREEN}✓${RESET} Daemon stopped`)\n } else {\n console.log(` ${DIM}·${RESET} Daemon not running`)\n }\n\n // ── 3. Remove shell profile exports ───────────────────────────\n const profile = detectShellProfile()\n if (profile) {\n const existing = findLiminalExportsInProfile(profile)\n if (existing.length > 0) {\n const removed = removeLiminalFromShellProfile(profile)\n if (removed.length > 0) {\n console.log(` ${GREEN}✓${RESET} Removed ${removed.length} line${removed.length > 1 ? 's' : ''} from ${profile.name}:`)\n for (const line of removed) {\n const trimmed = line.trim()\n if (trimmed && trimmed !== '# Liminal — route AI tools through compression proxy') {\n console.log(` ${DIM}${trimmed}${RESET}`)\n }\n }\n }\n } else {\n console.log(` ${DIM}·${RESET} No Liminal exports found in ${profile.name}`)\n }\n }\n\n // ── 4. Run connector-specific teardown ────────────────────────\n const configuredTools = loadConfiguredTools()\n const allTools = configuredTools.length > 0 ? configuredTools : CONNECTORS.map((c) => c.info.id)\n const connectors = getConnectors(allTools)\n\n const manualSteps: Array<{ label: string; steps: string[] }> = []\n\n for (const connector of connectors) {\n const result = await connector.teardown()\n if (result.manualSteps.length > 0 && !connector.info.automatable) {\n manualSteps.push({\n label: connector.info.label,\n steps: result.manualSteps,\n })\n }\n }\n\n if (manualSteps.length > 0) {\n console.log()\n console.log(` ${YELLOW}Manual steps needed:${RESET}`)\n for (const { label, steps } of manualSteps) {\n console.log()\n console.log(` ${BOLD}${label}:${RESET}`)\n for (const step of steps) {\n console.log(` ${step}`)\n }\n }\n }\n\n // ── 5. Optionally remove ~/.liminal/ ──────────────────────────\n if (existsSync(LIMINAL_DIR)) {\n console.log()\n const removeData = await selectPrompt<boolean>({\n message: 'Remove ~/.liminal/ directory? (config, logs, PID file)',\n options: [\n { label: 'Yes', value: true, description: 'Delete all Liminal data' },\n { label: 'No', value: false, description: 'Keep config and logs' },\n ],\n defaultIndex: 1, // Default to keep\n })\n\n if (removeData === true) {\n rmSync(LIMINAL_DIR, { recursive: true, force: true })\n console.log(` ${GREEN}✓${RESET} Removed ~/.liminal/`)\n } else {\n console.log(` ${DIM}·${RESET} Kept ~/.liminal/`)\n }\n }\n\n // ── 6. Summary ────────────────────────────────────────────────\n console.log()\n console.log(` ${GREEN}Liminal has been uninstalled.${RESET}`)\n console.log()\n console.log(` ${DIM}Your AI tools will connect directly to their APIs.${RESET}`)\n console.log(` ${DIM}Restart your terminal for shell changes to take effect.${RESET}`)\n\n if (manualSteps.length > 0) {\n console.log(` ${YELLOW}Don't forget the manual steps above for ${manualSteps.map((s) => s.label).join(', ')}.${RESET}`)\n }\n\n console.log()\n console.log(` ${DIM}To reinstall: npx @cognisos/liminal init${RESET}`)\n console.log()\n}\n","import { hasCA, ensureCA, getCAInfo, CA_CERT_PATH } from '../tls/ca.js'\nimport { installCA, isCATrusted } from '../tls/trust.js'\nimport { printBanner } from '../version.js'\n\nexport async function trustCACommand(): Promise<void> {\n printBanner()\n\n // Check if already trusted\n if (isCATrusted()) {\n console.log(' Liminal CA is already trusted.')\n const info = getCAInfo()\n if (info) {\n console.log(` Fingerprint: ${info.fingerprint}`)\n console.log(` Valid until: ${info.validTo.toLocaleDateString()}`)\n }\n return\n }\n\n // Ensure CA exists\n if (!hasCA()) {\n console.log(' Generating CA certificate...')\n ensureCA()\n console.log(' Created ~/.liminal/ca.pem')\n console.log()\n }\n\n // Explain what this does\n console.log(' Installing Liminal CA certificate')\n console.log()\n console.log(' This allows Liminal to transparently compress LLM API')\n console.log(' traffic from Cursor and other Electron-based editors.')\n console.log()\n console.log(' The certificate is scoped to your user account and only')\n console.log(' used by the local Liminal proxy on 127.0.0.1.')\n console.log()\n console.log(` Certificate: ${CA_CERT_PATH}`)\n console.log()\n\n // Install\n const result = installCA()\n\n if (result.success) {\n console.log(` ${result.message}`)\n console.log()\n const info = getCAInfo()\n if (info) {\n console.log(` Fingerprint: ${info.fingerprint}`)\n console.log(` Valid until: ${info.validTo.toLocaleDateString()}`)\n }\n console.log()\n console.log(' You can now use Liminal with Cursor:')\n console.log(' liminal start')\n console.log(' cursor --proxy-server=http://127.0.0.1:3141 --disable-http2')\n } else {\n console.error(` Failed: ${result.message}`)\n if (result.requiresSudo) {\n console.log()\n console.log(' Try running with elevated permissions:')\n console.log(' sudo liminal trust-ca')\n }\n process.exit(1)\n }\n}\n","import { removeCA as removeCAFiles, hasCA } from '../tls/ca.js'\nimport { removeCA as untrustCA, isCATrusted } from '../tls/trust.js'\nimport { printBanner } from '../version.js'\n\nexport async function untrustCACommand(): Promise<void> {\n printBanner()\n\n if (!hasCA() && !isCATrusted()) {\n console.log(' No Liminal CA found (nothing to remove).')\n return\n }\n\n // Remove from trust store first\n if (isCATrusted()) {\n console.log(' Removing CA from system trust store...')\n const result = untrustCA()\n\n if (result.success) {\n console.log(` ${result.message}`)\n } else {\n console.error(` ${result.message}`)\n if (result.requiresSudo) {\n console.log()\n console.log(' Try running with elevated permissions:')\n console.log(' sudo liminal untrust-ca')\n }\n process.exit(1)\n }\n }\n\n // Remove cert files\n if (hasCA()) {\n console.log(' Removing CA certificate files...')\n removeCAFiles()\n console.log(' Removed ~/.liminal/ca.pem and ca-key.pem')\n }\n\n console.log()\n console.log(' Liminal CA fully removed.')\n console.log(' Cursor MITM interception is no longer available.')\n}\n","/**\n * `liminal setup cursor` — One-command Cursor + Liminal integration.\n *\n * Steps:\n * 1. Verify Cursor is installed\n * 2. Ensure CA certificate exists and is trusted (like trust-ca)\n * 3. Ensure Liminal proxy is running (or tell user to start it)\n * 4. Launch Cursor with --proxy-server pointing at the running proxy\n */\n\nimport { existsSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { execSync, spawn } from 'node:child_process'\nimport { hasCA, ensureCA, getCAInfo, CA_CERT_PATH } from '../tls/ca.js'\nimport { installCA, isCATrusted } from '../tls/trust.js'\nimport { isDaemonRunning } from '../daemon/lifecycle.js'\nimport { loadConfig, isConfigured } from '../config/loader.js'\nimport { printBanner } from '../version.js'\n\n/** Resolve the Cursor binary path per platform */\nfunction findCursorBinary(): string | null {\n const platform = process.platform\n\n if (platform === 'darwin') {\n // Check the CLI symlink first, then the app bundle\n const cliPath = '/usr/local/bin/cursor'\n if (existsSync(cliPath)) return cliPath\n\n const appPath = '/Applications/Cursor.app'\n if (existsSync(appPath)) {\n return 'open' // We'll use `open -a Cursor` with args\n }\n return null\n }\n\n if (platform === 'win32') {\n const localAppData = process.env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local')\n const exePath = join(localAppData, 'Programs', 'Cursor', 'Cursor.exe')\n if (existsSync(exePath)) return exePath\n return null\n }\n\n // Linux\n const linuxPath = '/usr/bin/cursor'\n if (existsSync(linuxPath)) return linuxPath\n\n // Try which\n try {\n return execSync('which cursor', { encoding: 'utf-8' }).trim()\n } catch {\n return null\n }\n}\n\nexport async function setupCursorCommand(flags: Map<string, string | true>): Promise<void> {\n printBanner()\n\n const launch = !flags.has('no-launch')\n\n // Step 1: Check Cursor is installed\n console.log(' [1/4] Checking Cursor installation...')\n const cursorBin = findCursorBinary()\n if (!cursorBin) {\n console.error(' Cursor not found. Install Cursor from https://cursor.com')\n process.exit(1)\n }\n console.log(` Found: ${cursorBin}`)\n console.log()\n\n // Step 2: Ensure CA is generated and trusted\n console.log(' [2/4] Checking CA certificate...')\n if (!hasCA()) {\n console.log(' Generating CA certificate...')\n ensureCA()\n console.log(` Created ${CA_CERT_PATH}`)\n }\n\n if (!isCATrusted()) {\n console.log(' Installing CA into system trust store...')\n console.log()\n console.log(' This allows Liminal to transparently compress LLM API')\n console.log(' traffic from Cursor. The certificate is scoped to your')\n console.log(' user account and only used locally.')\n console.log()\n\n const result = installCA()\n if (!result.success) {\n console.error(` CA install failed: ${result.message}`)\n if (result.requiresSudo) {\n console.log(' Try: sudo liminal setup cursor')\n }\n process.exit(1)\n }\n console.log(` ${result.message}`)\n } else {\n console.log(' CA already trusted')\n }\n\n const info = getCAInfo()\n if (info) {\n console.log(` Fingerprint: ${info.fingerprint}`)\n }\n console.log()\n\n // Step 3: Check proxy is running\n console.log(' [3/4] Checking Liminal proxy...')\n if (!isConfigured()) {\n console.error(' Liminal is not configured. Run \"liminal init\" first.')\n process.exit(1)\n }\n\n const state = isDaemonRunning()\n const config = loadConfig()\n const port = config.port\n\n if (!state.running) {\n console.log(' Proxy is not running.')\n console.log()\n console.log(' Start the proxy first, then re-run this command:')\n console.log(' liminal start -d')\n console.log(' liminal setup cursor')\n console.log()\n console.log(' Or start in foreground + launch Cursor manually:')\n console.log(` liminal start & cursor --proxy-server=http://127.0.0.1:${port}`)\n process.exit(1)\n }\n console.log(` Proxy running on port ${port} (PID ${state.pid})`)\n console.log()\n\n // Step 4: Launch Cursor with proxy flag\n const proxyUrl = `http://127.0.0.1:${port}`\n\n if (launch) {\n console.log(' [4/4] Launching Cursor with proxy...')\n console.log(` --proxy-server=${proxyUrl}`)\n console.log()\n\n launchCursor(cursorBin, proxyUrl)\n\n console.log(' Cursor launched with Liminal compression active.')\n console.log()\n console.log(' All LLM API calls will be transparently compressed.')\n console.log(' Use \"liminal status\" to monitor compression stats.')\n console.log(' Use \"liminal logs -f\" to watch live traffic.')\n } else {\n console.log(' [4/4] Ready! Launch Cursor with:')\n console.log()\n console.log(` cursor --proxy-server=${proxyUrl}`)\n console.log()\n console.log(' Or create a shell alias:')\n console.log(` alias cursor-liminal='cursor --proxy-server=${proxyUrl}'`)\n }\n}\n\nfunction launchCursor(bin: string, proxyUrl: string): void {\n const args = [`--proxy-server=${proxyUrl}`]\n\n if (bin === 'open' && process.platform === 'darwin') {\n // macOS: use `open -a Cursor --args --proxy-server=...`\n spawn('open', ['-a', 'Cursor', '--args', ...args], {\n detached: true,\n stdio: 'ignore',\n }).unref()\n } else {\n spawn(bin, args, {\n detached: true,\n stdio: 'ignore',\n }).unref()\n }\n}\n","import { VERSION } from './version.js'\nimport { initCommand } from './commands/init.js'\nimport { loginCommand } from './commands/login.js'\nimport { logoutCommand } from './commands/logout.js'\nimport { startCommand } from './commands/start.js'\nimport { stopCommand } from './commands/stop.js'\nimport { statusCommand } from './commands/status.js'\nimport { summaryCommand } from './commands/summary.js'\nimport { configCommand } from './commands/config.js'\nimport { logsCommand } from './commands/logs.js'\nimport { uninstallCommand } from './commands/uninstall.js'\nimport { trustCACommand } from './commands/trust-ca.js'\nimport { untrustCACommand } from './commands/untrust-ca.js'\nimport { setupCursorCommand } from './commands/setup-cursor.js'\n\nconst USAGE = `\n liminal v${VERSION} — Transparent LLM context compression proxy\n\n Usage:\n liminal init Set up Liminal (login, config)\n liminal login Log in or create an account\n liminal logout Log out of your account\n liminal start [-d] [--port PORT] Start the compression proxy\n liminal stop Stop the running proxy\n liminal status Show proxy health and stats\n liminal summary Detailed session metrics\n liminal config [--set k=v] [--get k] View or edit configuration\n liminal logs [--follow] [--lines N] View proxy logs\n liminal setup cursor [--no-launch] Set up and launch Cursor with Liminal\n liminal trust-ca Install CA cert (for Cursor MITM)\n liminal untrust-ca Remove CA cert\n liminal uninstall Remove Liminal configuration\n\n Options:\n -h, --help Show this help message\n -v, --version Show version number\n\n Getting started:\n 1. liminal init # Log in + select tools\n 2. liminal start # Start the proxy\n 3. Connect your AI tools:\n Claude Code: export ANTHROPIC_BASE_URL=http://localhost:3141\n Codex: export OPENAI_BASE_URL=http://localhost:3141/v1\n Cursor: liminal trust-ca && cursor --proxy-server=http://localhost:3141\n`\n\nfunction parseArgs(argv: string[]): { command: string; flags: Map<string, string | true> } {\n const command = argv[2] ?? ''\n const flags = new Map<string, string | true>()\n\n for (let i = 3; i < argv.length; i++) {\n const arg = argv[i]\n if (arg.startsWith('--')) {\n const key = arg.slice(2)\n // Check if next arg is a value (not another flag)\n if (i + 1 < argv.length && !argv[i + 1].startsWith('-')) {\n flags.set(key, argv[i + 1])\n i++\n } else {\n flags.set(key, true)\n }\n } else if (arg.startsWith('-') && arg.length === 2) {\n const key = arg.slice(1)\n if (i + 1 < argv.length && !argv[i + 1].startsWith('-')) {\n flags.set(key, argv[i + 1])\n i++\n } else {\n flags.set(key, true)\n }\n }\n }\n\n return { command, flags }\n}\n\nasync function main(): Promise<void> {\n const { command, flags } = parseArgs(process.argv)\n\n // Global flags — handle --help and --version as both commands and flags\n if (flags.has('h') || flags.has('help') || command === 'help' || command === '--help' || command === '-h') {\n console.log(USAGE)\n process.exit(0)\n }\n\n if (flags.has('v') || flags.has('version') || command === 'version' || command === '--version' || command === '-v') {\n console.log(VERSION)\n process.exit(0)\n }\n\n try {\n switch (command) {\n case 'init':\n await initCommand()\n break\n\n case 'login':\n await loginCommand()\n break\n\n case 'logout':\n await logoutCommand()\n break\n\n case 'start':\n await startCommand(flags)\n break\n\n case 'stop':\n await stopCommand()\n break\n\n case 'status':\n await statusCommand()\n break\n\n case 'summary':\n await summaryCommand()\n break\n\n case 'config':\n await configCommand(flags)\n break\n\n case 'logs':\n await logsCommand(flags)\n break\n\n case 'setup': {\n const subcommand = process.argv[3]\n if (subcommand === 'cursor') {\n await setupCursorCommand(flags)\n } else {\n console.error(`Unknown setup target: ${subcommand ?? '(none)'}`)\n console.error('Available: liminal setup cursor')\n process.exit(1)\n }\n break\n }\n\n case 'trust-ca':\n await trustCACommand()\n break\n\n case 'untrust-ca':\n await untrustCACommand()\n break\n\n case 'uninstall':\n await uninstallCommand()\n break\n\n case '':\n console.log(USAGE)\n process.exit(0)\n break\n\n default:\n console.error(`Unknown command: ${command}`)\n console.log(USAGE)\n process.exit(1)\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n console.error(`Error: ${message}`)\n process.exit(1)\n }\n}\n\nmain()\n"],"mappings":"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","names":["existsSync","readFileSync","writeFileSync","join","homedir","stdin","stdout","execSync","existsSync","readFileSync","join","homedir","ENV_VAR","INFO","getCurrentBaseUrl","existsSync","join","homedir","INFO","ENV_VAR","INFO","getCurrentBaseUrl","RSCCircuitOpenError","tiered","lines","RSCCircuitOpenError","RSCCircuitOpenError","lines","setCORSHeaders","RSCCircuitOpenError","RSCCircuitOpenError","lines","setCORSHeaders","sendJSON","extractBearerToken","RSCCircuitOpenError","setCORSHeaders","sendJSON","appendFileSync","mkdirSync","existsSync","dirname","dirname","existsSync","mkdirSync","appendFileSync","existsSync","readFileSync","writeFileSync","mkdirSync","join","join","existsSync","mkdirSync","writeFileSync","readFileSync","execSync","existsSync","unlinkSync","existsSync","removeCA","execSync","unlinkSync","forge","readFileSync","writeFileSync","unlinkSync","existsSync","writeFileSync","existsSync","readFileSync","unlinkSync","RSCPipelineWrapper","formatUptime","config","readFileSync","existsSync","statSync","existsSync","readFileSync","statSync","existsSync","readFileSync","BOLD","DIM","GREEN","YELLOW","RESET","existsSync","readFileSync","BOLD","GREEN","DIM","YELLOW","removeCA","existsSync","homedir","join","execSync","existsSync","join","homedir","execSync"]}
1
+ {"version":3,"sources":["../src/ui/format.ts","../src/version.ts","../src/config/paths.ts","../src/config/schema.ts","../src/config/loader.ts","../src/ui/prompts.ts","../src/rsc/pipeline.ts","../src/rsc/tokenizer.ts","../src/daemon/lifecycle.ts","../src/stats/aggregator.ts","../src/stats/store.ts","../src/cursor/stats.ts","../src/ui/screen.ts","../src/ui/layout.ts","../src/ui/views/dashboard.ts","../src/ui/views/stats-view.ts","../src/ui/views/config-view.ts","../src/ui/views/logs-view.ts","../src/ui/hub.ts","../src/bin.ts","../src/commands/init.ts","../src/config/shell.ts","../src/commands/login.ts","../src/auth/supabase.ts","../src/connectors/claude-code.ts","../src/connectors/codex.ts","../src/connectors/cursor.ts","../src/connectors/openai-compatible.ts","../src/connectors/index.ts","../src/ui/wizard.ts","../src/tls/ca.ts","../src/tls/trust.ts","../src/commands/logout.ts","../src/commands/start.ts","../src/proxy/completions.ts","../src/rsc/message-compressor.ts","../src/rsc/content-segmenter.ts","../src/rsc/conversation-analyzer.ts","../src/rsc/learning.ts","../src/proxy/streaming.ts","../src/terminology.ts","../src/proxy/messages.ts","../src/proxy/anthropic-streaming.ts","../src/proxy/responses.ts","../src/proxy/responses-streaming.ts","../src/proxy/session-identity.ts","../src/tls/allowlist.ts","../src/proxy/handler.ts","../src/proxy/server.ts","../src/daemon/logger.ts","../src/rsc/session-manager.ts","../src/rsc/semaphore.ts","../src/rsc/latency-monitor.ts","../src/tls/connect-handler.ts","../src/tls/mitm-bridge.ts","../src/tls/cert-generator.ts","../src/tls/mitm-stats.ts","../src/commands/stop.ts","../src/commands/status.ts","../src/commands/config.ts","../src/commands/logs.ts","../src/commands/uninstall.ts","../src/commands/trust-ca.ts","../src/commands/untrust-ca.ts","../src/commands/setup-cursor.ts","../src/cursor/hook-template.ts","../src/commands/stats.ts"],"sourcesContent":["/**\n * Shared UI formatting primitives for the Liminal CLI.\n *\n * All user-facing output should use these helpers to ensure visual consistency.\n * Respects NO_COLOR env var and --no-color flag per https://no-color.org/\n *\n * Color palette:\n * Green = success / active\n * Cyan = info / interactive / instructions\n * Yellow = warning\n * Red = error\n * Dim = secondary / metadata\n * Bold = emphasis / labels\n */\n\n// ─── Color support detection ────────────────────────────────────────\n\nlet _noColor = false\n\n/** Call once at startup to disable colors (e.g. from --no-color flag). */\nexport function disableColor(): void {\n _noColor = true\n}\n\nfunction colorEnabled(): boolean {\n if (_noColor) return false\n if (typeof process !== 'undefined') {\n if (process.env.NO_COLOR !== undefined) return false\n if (process.env.FORCE_COLOR !== undefined) return true\n if (process.stdout && !process.stdout.isTTY) return false\n }\n return true\n}\n\n// ─── ANSI codes ─────────────────────────────────────────────────────\n\nfunction code(ansi: string): string {\n return colorEnabled() ? ansi : ''\n}\n\nexport const c = {\n get bold() { return code('\\x1b[1m') },\n get dim() { return code('\\x1b[2m') },\n get italic() { return code('\\x1b[3m') },\n get red() { return code('\\x1b[31m') },\n get green() { return code('\\x1b[32m') },\n get yellow() { return code('\\x1b[33m') },\n get cyan() { return code('\\x1b[36m') },\n get reset() { return code('\\x1b[0m') },\n} as const\n\n// ─── Icons ──────────────────────────────────────────────────────────\n\nexport const icons = {\n success: '\\u2713', // ✓\n error: '\\u2717', // ✗\n warning: '\\u26A0', // ⚠\n info: '\\u2139', // ℹ\n pending: '\\u276F', // ❯\n skip: '\\u00B7', // ·\n arrow: '\\u2192', // →\n bullet: '\\u2022', // •\n} as const\n\n// ─── Line-level primitives ──────────────────────────────────────────\n\nconst INDENT = ' '\n\nexport function success(msg: string, detail?: string): string {\n const d = detail ? ` ${c.dim}${detail}${c.reset}` : ''\n return `${INDENT}${c.green}${icons.success}${c.reset} ${msg}${d}`\n}\n\nexport function error(msg: string, suggestion?: string): string {\n const lines = [`${INDENT}${c.red}${icons.error}${c.reset} ${msg}`]\n if (suggestion) {\n lines.push(`${INDENT} ${c.dim}${icons.arrow} ${suggestion}${c.reset}`)\n }\n return lines.join('\\n')\n}\n\nexport function warn(msg: string, detail?: string): string {\n const d = detail ? ` ${c.dim}${detail}${c.reset}` : ''\n return `${INDENT}${c.yellow}${icons.warning}${c.reset} ${msg}${d}`\n}\n\nexport function info(msg: string, detail?: string): string {\n const d = detail ? ` ${c.dim}${detail}${c.reset}` : ''\n return `${INDENT}${c.cyan}${icons.info}${c.reset} ${msg}${d}`\n}\n\nexport function pending(msg: string): string {\n return `${INDENT}${c.cyan}${icons.pending}${c.reset} ${msg}`\n}\n\nexport function skip(msg: string): string {\n return `${INDENT}${c.dim}${icons.skip} ${msg}${c.reset}`\n}\n\nexport function label(key: string, value: string): string {\n return `${INDENT}${c.bold}${key}:${c.reset} ${value}`\n}\n\nexport function dimText(msg: string): string {\n return `${c.dim}${msg}${c.reset}`\n}\n\n// ─── Section headers ────────────────────────────────────────────────\n\nconst RULE_CHAR = '\\u2501' // ━\n\nexport function stepHeader(step: number, total: number, title: string): string {\n const tag = `Step ${step} of ${total}`\n const content = `${tag} ${icons.bullet} ${title}`\n const ruleLen = Math.max(content.length + 4, 44)\n const rule = RULE_CHAR.repeat(ruleLen)\n return [\n '',\n `${INDENT}${c.dim}${rule}${c.reset}`,\n `${INDENT}${c.bold}${content}${c.reset}`,\n `${INDENT}${c.dim}${rule}${c.reset}`,\n ].join('\\n')\n}\n\nexport function sectionHeader(title: string): string {\n const padded = ` ${title} `\n const sideLen = Math.max(Math.floor((44 - padded.length) / 2), 3)\n const rule = RULE_CHAR.repeat(sideLen)\n return `\\n${INDENT}${c.dim}${rule}${c.reset}${c.bold}${padded}${c.reset}${c.dim}${rule}${c.reset}`\n}\n\n// ─── Box drawing ────────────────────────────────────────────────────\n\nconst BOX = {\n tl: '\\u250C', tr: '\\u2510',\n bl: '\\u2514', br: '\\u2518',\n h: '\\u2500', v: '\\u2502',\n} as const\n\n/**\n * Draw a box around key-value rows.\n * @param title Optional bold title for the top edge\n * @param rows Array of [label, value] pairs\n * @param minWidth Minimum inner width (default 38)\n */\nexport function box(rows: [string, string][], title?: string, minWidth = 38): string {\n // Calculate inner width from content\n const contentWidths = rows.map(([k, v]) => stripAnsi(k).length + stripAnsi(v).length + 4)\n const titleWidth = title ? stripAnsi(title).length + 4 : 0\n const innerWidth = Math.max(minWidth, titleWidth, ...contentWidths)\n\n const lines: string[] = []\n\n // Top edge\n if (title) {\n const afterTitle = innerWidth - stripAnsi(title).length - 3\n lines.push(`${INDENT}${BOX.tl}${BOX.h} ${c.bold}${title}${c.reset} ${BOX.h.repeat(Math.max(0, afterTitle))}${BOX.tr}`)\n } else {\n lines.push(`${INDENT}${BOX.tl}${BOX.h.repeat(innerWidth)}${BOX.tr}`)\n }\n\n // Content rows\n for (const [key, value] of rows) {\n const content = `${key} ${value}`\n const pad = innerWidth - stripAnsi(content).length - 2\n lines.push(`${INDENT}${BOX.v} ${content}${' '.repeat(Math.max(0, pad))} ${BOX.v}`)\n }\n\n // Bottom edge\n lines.push(`${INDENT}${BOX.tl === BOX.tl ? BOX.bl : BOX.bl}${BOX.h.repeat(innerWidth)}${BOX.br}`)\n\n return lines.join('\\n')\n}\n\n// ─── Table formatting ───────────────────────────────────────────────\n\n/**\n * Render a simple aligned table.\n * @param headers Column headers\n * @param rows Data rows (same length as headers)\n * @param indent Number of leading spaces (default 2)\n */\nexport function table(headers: string[], rows: string[][], indent = 2): string {\n const colWidths = headers.map((h, i) => {\n const dataMax = Math.max(0, ...rows.map(r => stripAnsi(r[i] ?? '').length))\n return Math.max(stripAnsi(h).length, dataMax)\n })\n\n const pad = ' '.repeat(indent)\n const lines: string[] = []\n\n // Header\n const headerLine = headers.map((h, i) => h.padEnd(colWidths[i])).join(' ')\n lines.push(`${pad}${c.bold}${headerLine}${c.reset}`)\n\n // Separator\n const sep = colWidths.map(w => '\\u2500'.repeat(w)).join(' ')\n lines.push(`${pad}${c.dim}${sep}${c.reset}`)\n\n // Data\n for (const row of rows) {\n const cells = row.map((cell, i) => {\n const visible = stripAnsi(cell).length\n return cell + ' '.repeat(Math.max(0, colWidths[i] - visible))\n })\n lines.push(`${pad}${cells.join(' ')}`)\n }\n\n return lines.join('\\n')\n}\n\n// ─── Utility ────────────────────────────────────────────────────────\n\n/** Strip ANSI escape codes for width calculation. */\nexport function stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex\n return str.replace(/\\x1b\\[[0-9;]*m/g, '')\n}\n\n/** Format milliseconds as human-readable uptime. */\nexport function formatUptime(ms: number): string {\n const seconds = Math.floor(ms / 1000)\n const minutes = Math.floor(seconds / 60)\n const hours = Math.floor(minutes / 60)\n const days = Math.floor(hours / 24)\n\n if (days > 0) return `${days}d ${hours % 24}h ${minutes % 60}m`\n if (hours > 0) return `${hours}h ${minutes % 60}m`\n if (minutes > 0) return `${minutes}m ${seconds % 60}s`\n return `${seconds}s`\n}\n\n/** Format bytes as human-readable size. */\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`\n}\n\n/** Format a number with locale thousands separators. */\nexport function formatNum(n: number): string {\n return n.toLocaleString()\n}\n\n/** Format a percentage from a ratio. */\nexport function formatPct(ratio: number, decimals = 1): string {\n return `${(ratio * 100).toFixed(decimals)}%`\n}\n\n/** Format a connector maturity badge. */\nexport function maturityBadge(maturity: string | undefined): string {\n if (!maturity || maturity === 'stable') return ''\n if (maturity === 'preview') return ` ${c.yellow}Preview${c.reset}`\n if (maturity === 'coming-soon') return ` ${c.dim}Coming Soon${c.reset}`\n return ''\n}\n","import { c } from './ui/format.js'\n\ndeclare const __VERSION__: string\nexport const VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : '2.5.0'\n\n// FIGlet-style \"LIMINAL\" banner\nexport const BANNER_LINES = [\n ' ___ ___ _____ ______ ___ ________ ________ ___',\n '|\\\\ \\\\ |\\\\ \\\\|\\\\ _ \\\\ _ \\\\|\\\\ \\\\|\\\\ ___ \\\\|\\\\ __ \\\\|\\\\ \\\\',\n '\\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\\\\\\\\\__\\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\\\\\ \\\\ \\\\ \\\\ \\\\|\\\\ \\\\ \\\\ \\\\',\n ' \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\\\\\|__| \\\\ \\\\ \\\\ \\\\ \\\\ \\\\\\\\ \\\\ \\\\ \\\\ __ \\\\ \\\\ \\\\',\n ' \\\\ \\\\ \\\\____\\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\\\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\____',\n ' \\\\ \\\\_______\\\\ \\\\__\\\\ \\\\__\\\\ \\\\ \\\\__\\\\ \\\\__\\\\ \\\\__\\\\\\\\ \\\\__\\\\ \\\\__\\\\ \\\\__\\\\ \\\\_______\\\\',\n ' \\\\|_______|\\\\|__|\\\\|__| \\\\|__|\\\\|__|\\\\|__| \\\\|__|\\\\|__|\\\\|__|\\\\|_______|',\n]\n\nexport function printBanner(): void {\n console.log()\n for (const line of BANNER_LINES) {\n console.log(`${c.cyan}${line}${c.reset}`)\n }\n console.log()\n console.log(` ${c.bold}v${VERSION}${c.reset} ${c.dim}\\u2014 Transparent LLM Context Compression${c.reset}`)\n console.log()\n}\n","import { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport const LIMINAL_DIR = join(homedir(), '.liminal')\nexport const CONFIG_FILE = join(LIMINAL_DIR, 'config.json')\nexport const PID_FILE = join(LIMINAL_DIR, 'liminal.pid')\nexport const LOG_DIR = join(LIMINAL_DIR, 'logs')\nexport const LOG_FILE = join(LOG_DIR, 'liminal.log')\n","export interface RSCConfig {\n apiKey: string\n apiBaseUrl: string\n upstreamBaseUrl: string\n anthropicUpstreamUrl: string\n port: number\n compressionThreshold: number\n aggregateThreshold: number\n hotFraction: number\n coldFraction: number\n compressRoles: string[]\n compressToolResults: boolean\n learnFromResponses: boolean\n latencyBudgetMs: number\n enabled: boolean\n tools: string[]\n // Multi-session concurrency settings\n concurrencyLimit: number\n concurrencyTimeoutMs: number\n maxSessions: number\n sessionTtlMs: number\n latencyWarningMs: number\n latencyCriticalMs: number\n}\n\nexport const DEFAULTS: Omit<RSCConfig, 'apiKey'> = {\n apiBaseUrl: 'https://api.cognisos.ai',\n upstreamBaseUrl: 'https://api.openai.com',\n anthropicUpstreamUrl: 'https://api.anthropic.com',\n port: 3141,\n compressionThreshold: 50,\n aggregateThreshold: 500,\n hotFraction: 0.1,\n coldFraction: 0.3,\n compressRoles: ['user', 'assistant'],\n compressToolResults: true,\n learnFromResponses: true,\n latencyBudgetMs: 10000,\n enabled: true,\n tools: [],\n concurrencyLimit: 6,\n concurrencyTimeoutMs: 15000,\n maxSessions: 10,\n sessionTtlMs: 1800000,\n latencyWarningMs: 4000,\n latencyCriticalMs: 8000,\n}\n\n/** Keys that can be set via `liminal config --set` */\nexport const CONFIGURABLE_KEYS = new Set<string>([\n 'apiBaseUrl',\n 'upstreamBaseUrl',\n 'anthropicUpstreamUrl',\n 'port',\n 'compressionThreshold',\n 'aggregateThreshold',\n 'hotFraction',\n 'coldFraction',\n 'compressRoles',\n 'compressToolResults',\n 'learnFromResponses',\n 'latencyBudgetMs',\n 'enabled',\n 'tools',\n 'concurrencyLimit',\n 'concurrencyTimeoutMs',\n 'maxSessions',\n 'sessionTtlMs',\n 'latencyWarningMs',\n 'latencyCriticalMs',\n])\n","import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { LIMINAL_DIR, CONFIG_FILE, LOG_DIR } from './paths.js'\nimport { DEFAULTS } from './schema.js'\nimport type { RSCConfig } from './schema.js'\n\n/**\n * Load config from ~/.liminal/config.json, merged with defaults and env var overrides.\n * Priority: env vars > config file > defaults\n */\nexport function loadConfig(): RSCConfig {\n let fileConfig: Partial<RSCConfig> = {}\n\n if (existsSync(CONFIG_FILE)) {\n try {\n const raw = readFileSync(CONFIG_FILE, 'utf-8')\n fileConfig = JSON.parse(raw)\n } catch {\n // Corrupted config file — fall through to defaults\n }\n }\n\n const merged: RSCConfig = {\n apiKey: fileConfig.apiKey ?? '',\n apiBaseUrl: DEFAULTS.apiBaseUrl,\n upstreamBaseUrl: DEFAULTS.upstreamBaseUrl,\n anthropicUpstreamUrl: DEFAULTS.anthropicUpstreamUrl,\n port: DEFAULTS.port,\n compressionThreshold: DEFAULTS.compressionThreshold,\n aggregateThreshold: DEFAULTS.aggregateThreshold,\n hotFraction: DEFAULTS.hotFraction,\n coldFraction: DEFAULTS.coldFraction,\n compressRoles: DEFAULTS.compressRoles,\n compressToolResults: DEFAULTS.compressToolResults,\n learnFromResponses: DEFAULTS.learnFromResponses,\n latencyBudgetMs: DEFAULTS.latencyBudgetMs,\n enabled: DEFAULTS.enabled,\n tools: DEFAULTS.tools,\n concurrencyLimit: DEFAULTS.concurrencyLimit,\n concurrencyTimeoutMs: DEFAULTS.concurrencyTimeoutMs,\n maxSessions: DEFAULTS.maxSessions,\n sessionTtlMs: DEFAULTS.sessionTtlMs,\n latencyWarningMs: DEFAULTS.latencyWarningMs,\n latencyCriticalMs: DEFAULTS.latencyCriticalMs,\n ...fileConfig,\n }\n\n // Environment variable overrides\n if (process.env.LIMINAL_API_KEY) merged.apiKey = process.env.LIMINAL_API_KEY\n if (process.env.LIMINAL_API_URL) merged.apiBaseUrl = process.env.LIMINAL_API_URL\n if (process.env.LIMINAL_UPSTREAM_URL) merged.upstreamBaseUrl = process.env.LIMINAL_UPSTREAM_URL\n if (process.env.LIMINAL_ANTHROPIC_URL) merged.anthropicUpstreamUrl = process.env.LIMINAL_ANTHROPIC_URL\n if (process.env.LIMINAL_PORT) merged.port = parseInt(process.env.LIMINAL_PORT, 10)\n\n return merged\n}\n\n/**\n * Apply CLI flag overrides on top of loaded config.\n */\nexport function applyOverrides(\n config: RSCConfig,\n overrides: Partial<Pick<RSCConfig, 'port' | 'upstreamBaseUrl'>>,\n): RSCConfig {\n return { ...config, ...overrides }\n}\n\n/**\n * Save config to ~/.liminal/config.json. Creates ~/.liminal/ and ~/.liminal/logs/ if needed.\n */\nexport function saveConfig(config: Partial<RSCConfig>): void {\n ensureDirectories()\n\n let existing: Partial<RSCConfig> = {}\n if (existsSync(CONFIG_FILE)) {\n try {\n existing = JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'))\n } catch {\n // Overwrite corrupted file\n }\n }\n\n const merged = { ...existing, ...config }\n writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2) + '\\n', { encoding: 'utf-8', mode: 0o600 })\n try { chmodSync(CONFIG_FILE, 0o600) } catch { /* best effort */ }\n}\n\n/**\n * Ensure ~/.liminal/ and ~/.liminal/logs/ directories exist.\n */\nexport function ensureDirectories(): void {\n if (!existsSync(LIMINAL_DIR)) mkdirSync(LIMINAL_DIR, { recursive: true, mode: 0o700 })\n if (!existsSync(LOG_DIR)) mkdirSync(LOG_DIR, { recursive: true, mode: 0o700 })\n // Ensure parent of config file exists\n const configDir = dirname(CONFIG_FILE)\n if (!existsSync(configDir)) mkdirSync(configDir, { recursive: true })\n}\n\n/**\n * Check if a valid config file exists with an API key.\n */\nexport function isConfigured(): boolean {\n try {\n const config = loadConfig()\n return config.apiKey.length > 0\n } catch {\n return false\n }\n}\n\n/**\n * Mask an API key for display: show first 8 chars + last 4.\n */\nexport function maskApiKey(key: string): string {\n if (key.length <= 12) return '****'\n return key.slice(0, 8) + '...' + key.slice(-4)\n}\n","/**\n * Lightweight interactive terminal prompts — zero external dependencies.\n * Uses raw stdin mode for arrow-key navigation.\n */\n\nimport { c } from './format.js'\n\n// ─── ANSI escape sequences ───────────────────────────────────────────\n// Terminal control codes (cursor, clear) are always emitted — they're not\n// cosmetic. Color codes come from the shared `c` object which respects NO_COLOR.\n\nconst ANSI = {\n HIDE_CURSOR: '\\x1b[?25l',\n SHOW_CURSOR: '\\x1b[?25h',\n CLEAR_LINE: '\\x1b[2K',\n get BOLD() { return c.bold },\n get DIM() { return c.dim },\n get CYAN() { return c.cyan },\n get RESET() { return c.reset },\n moveUp: (n: number) => (n > 0 ? `\\x1b[${n}A` : ''),\n} as const\n\n// ─── Key parsing ─────────────────────────────────────────────────────\n\nexport type KeyPress =\n | { type: 'up' }\n | { type: 'down' }\n | { type: 'left' }\n | { type: 'right' }\n | { type: 'tab' }\n | { type: 'enter' }\n | { type: 'space' }\n | { type: 'escape' }\n | { type: 'ctrlc' }\n | { type: 'backspace' }\n | { type: 'char'; char: string }\n | { type: 'other' }\n\nexport function parseKey(data: Buffer): KeyPress {\n if (data.length === 0) return { type: 'other' }\n\n // Ctrl+C\n if (data[0] === 0x03) return { type: 'ctrlc' }\n\n // Arrow keys: ESC [ A/B/C/D\n if (data.length >= 3 && data[0] === 0x1b && data[1] === 0x5b) {\n if (data[2] === 0x41) return { type: 'up' }\n if (data[2] === 0x42) return { type: 'down' }\n if (data[2] === 0x43) return { type: 'right' }\n if (data[2] === 0x44) return { type: 'left' }\n return { type: 'other' }\n }\n\n // Tab\n if (data[0] === 0x09) return { type: 'tab' }\n\n // Standalone Escape\n if (data.length === 1 && data[0] === 0x1b) return { type: 'escape' }\n\n // Enter\n if (data[0] === 0x0d || data[0] === 0x0a) return { type: 'enter' }\n\n // Space\n if (data[0] === 0x20) return { type: 'space' }\n\n // Backspace (DEL on macOS)\n if (data[0] === 0x7f || data[0] === 0x08) return { type: 'backspace' }\n\n // Printable ASCII characters (0x21-0x7e)\n if (data.length === 1 && data[0] >= 0x21 && data[0] <= 0x7e) {\n return { type: 'char', char: String.fromCharCode(data[0]) }\n }\n\n return { type: 'other' }\n}\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface SelectOption<T> {\n label: string\n value: T\n description?: string\n}\n\nexport interface MultiSelectOption<T> extends SelectOption<T> {\n default?: boolean\n}\n\ninterface Streams {\n stdin: NodeJS.ReadableStream & { setRawMode?: (mode: boolean) => void; isTTY?: boolean }\n stdout: { write: (s: string) => boolean }\n}\n\ninterface SelectConfig<T> {\n message: string\n options: SelectOption<T>[]\n defaultIndex?: number\n _streams?: Streams\n}\n\ninterface MultiSelectConfig<T> {\n message: string\n options: MultiSelectOption<T>[]\n _streams?: Streams\n}\n\n// ─── Render helpers ──────────────────────────────────────────────────\n\nexport interface RenderResult {\n text: string\n lineCount: number\n}\n\nexport function renderSelect<T>(\n options: SelectOption<T>[],\n cursorIndex: number,\n message: string,\n): RenderResult {\n const lines: string[] = []\n lines.push(` ${ANSI.BOLD}${message}${ANSI.RESET}`)\n lines.push('')\n\n const maxLabel = Math.max(...options.map((o) => o.label.length))\n\n for (let i = 0; i < options.length; i++) {\n const focused = i === cursorIndex\n const pointer = focused ? `${ANSI.CYAN}->${ANSI.RESET}` : ' '\n const label = focused\n ? `${ANSI.BOLD}${options[i].label.padEnd(maxLabel)}${ANSI.RESET}`\n : `${options[i].label.padEnd(maxLabel)}`\n const desc = options[i].description\n ? ` ${ANSI.DIM}${options[i].description}${ANSI.RESET}`\n : ''\n lines.push(` ${pointer} ${label}${desc}`)\n }\n\n lines.push('')\n return { text: lines.join('\\n'), lineCount: lines.length }\n}\n\nexport function renderMultiSelect<T>(\n options: MultiSelectOption<T>[],\n cursorIndex: number,\n selected: Set<number>,\n message: string,\n): RenderResult {\n const lines: string[] = []\n lines.push(` ${ANSI.BOLD}${message}${ANSI.RESET}`)\n lines.push('')\n\n const maxLabel = Math.max(...options.map((o) => o.label.length))\n\n for (let i = 0; i < options.length; i++) {\n const focused = i === cursorIndex\n const checked = selected.has(i)\n const pointer = focused ? `${ANSI.CYAN}->${ANSI.RESET}` : ' '\n const box = checked\n ? `${ANSI.CYAN}[x]${ANSI.RESET}`\n : `${ANSI.DIM}[ ]${ANSI.RESET}`\n const label = focused\n ? `${ANSI.BOLD}${options[i].label.padEnd(maxLabel)}${ANSI.RESET}`\n : `${options[i].label.padEnd(maxLabel)}`\n const desc = options[i].description\n ? ` ${ANSI.DIM}${options[i].description}${ANSI.RESET}`\n : ''\n lines.push(` ${pointer} ${box} ${label}${desc}`)\n }\n\n lines.push('')\n lines.push(` ${ANSI.DIM}↑/↓ Navigate ${ANSI.RESET}${ANSI.CYAN}Space${ANSI.RESET}${ANSI.DIM} Select ${ANSI.RESET}${ANSI.CYAN}Enter${ANSI.RESET}${ANSI.DIM} Confirm${ANSI.RESET}`)\n lines.push('')\n return { text: lines.join('\\n'), lineCount: lines.length }\n}\n\n// ─── Raw mode lifecycle ──────────────────────────────────────────────\n\nfunction withRawMode<T>(\n streams: Streams,\n handler: (\n resolve: (value: T) => void,\n ) => (key: KeyPress) => void,\n): Promise<T> {\n const { stdin, stdout } = streams\n\n return new Promise<T>((resolve, reject) => {\n let cleaned = false\n\n function cleanup() {\n if (cleaned) return\n cleaned = true\n stdin.removeListener('data', onData)\n if (stdin.setRawMode) stdin.setRawMode(false)\n if ('pause' in stdin && typeof (stdin as any).pause === 'function') {\n (stdin as any).pause()\n }\n stdout.write(ANSI.SHOW_CURSOR)\n process.removeListener('exit', cleanup)\n }\n\n function onData(data: Buffer) {\n const key = parseKey(data)\n if (key.type === 'ctrlc') {\n cleanup()\n process.exit(130)\n }\n keyHandler(key)\n }\n\n const keyHandler = handler((value: T) => {\n cleanup()\n resolve(value)\n })\n\n // Safety: restore terminal on unexpected exit\n process.on('exit', cleanup)\n\n try {\n if (stdin.setRawMode) stdin.setRawMode(true)\n stdout.write(ANSI.HIDE_CURSOR)\n stdin.on('data', onData)\n if ('resume' in stdin && typeof (stdin as any).resume === 'function') {\n (stdin as any).resume()\n }\n } catch (err) {\n cleanup()\n reject(err)\n }\n })\n}\n\n// ─── Public API ──────────────────────────────────────────────────────\n\nexport async function selectPrompt<T>(config: SelectConfig<T>): Promise<T | null> {\n const { message, options, defaultIndex = 0, _streams } = config\n const streams = _streams ?? { stdin: process.stdin, stdout: process.stdout }\n let cursorIndex = defaultIndex\n let prevLineCount = 0\n\n function draw() {\n const { text, lineCount } = renderSelect(options, cursorIndex, message)\n // Move up to overwrite previous render\n if (prevLineCount > 0) {\n streams.stdout.write(ANSI.moveUp(prevLineCount))\n }\n // Clear and write each line\n const lines = text.split('\\n')\n for (const line of lines) {\n streams.stdout.write(ANSI.CLEAR_LINE + line + '\\n')\n }\n prevLineCount = lineCount\n }\n\n draw()\n\n const result = await withRawMode<T | null>(streams, (resolve) => {\n return (key: KeyPress) => {\n switch (key.type) {\n case 'up':\n cursorIndex = (cursorIndex - 1 + options.length) % options.length\n draw()\n break\n case 'down':\n cursorIndex = (cursorIndex + 1) % options.length\n draw()\n break\n case 'enter':\n resolve(options[cursorIndex].value)\n break\n case 'escape':\n resolve(null)\n break\n }\n }\n })\n\n // Show confirmed selection\n if (result !== null) {\n const selected = options.find((o) => o.value === result)\n if (selected) {\n // Overwrite prompt with confirmed value\n if (prevLineCount > 0) {\n streams.stdout.write(ANSI.moveUp(prevLineCount))\n }\n for (let i = 0; i < prevLineCount; i++) {\n streams.stdout.write(ANSI.CLEAR_LINE + '\\n')\n }\n streams.stdout.write(ANSI.moveUp(prevLineCount))\n streams.stdout.write(` ${ANSI.BOLD}${message}${ANSI.RESET} ${ANSI.CYAN}${selected.label}${ANSI.RESET}\\n`)\n }\n }\n\n return result\n}\n\nexport async function multiSelectPrompt<T>(config: MultiSelectConfig<T>): Promise<T[] | null> {\n const { message, options, _streams } = config\n const streams = _streams ?? { stdin: process.stdin, stdout: process.stdout }\n let cursorIndex = 0\n const selected = new Set<number>()\n let prevLineCount = 0\n\n // Pre-fill defaults\n for (let i = 0; i < options.length; i++) {\n if (options[i].default) selected.add(i)\n }\n\n function draw() {\n const { text, lineCount } = renderMultiSelect(options, cursorIndex, selected, message)\n if (prevLineCount > 0) {\n streams.stdout.write(ANSI.moveUp(prevLineCount))\n }\n const lines = text.split('\\n')\n for (const line of lines) {\n streams.stdout.write(ANSI.CLEAR_LINE + line + '\\n')\n }\n prevLineCount = lineCount\n }\n\n draw()\n\n const result = await withRawMode<T[] | null>(streams, (resolve) => {\n return (key: KeyPress) => {\n switch (key.type) {\n case 'up':\n cursorIndex = (cursorIndex - 1 + options.length) % options.length\n draw()\n break\n case 'down':\n cursorIndex = (cursorIndex + 1) % options.length\n draw()\n break\n case 'space':\n if (selected.has(cursorIndex)) {\n selected.delete(cursorIndex)\n } else {\n selected.add(cursorIndex)\n }\n draw()\n break\n case 'enter':\n if (selected.size > 0) {\n const values = [...selected].sort().map((i) => options[i].value)\n resolve(values)\n }\n // If nothing selected, ignore Enter (must select at least 1)\n break\n case 'escape':\n resolve(null)\n break\n }\n }\n })\n\n // Show confirmed selection\n if (result !== null) {\n const labels = [...selected].sort().map((i) => options[i].label)\n if (prevLineCount > 0) {\n streams.stdout.write(ANSI.moveUp(prevLineCount))\n }\n for (let i = 0; i < prevLineCount; i++) {\n streams.stdout.write(ANSI.CLEAR_LINE + '\\n')\n }\n streams.stdout.write(ANSI.moveUp(prevLineCount))\n streams.stdout.write(` ${ANSI.BOLD}${message}${ANSI.RESET} ${ANSI.CYAN}${labels.join(', ')}${ANSI.RESET}\\n`)\n }\n\n return result\n}\n\n// ─── Password prompt ─────────────────────────────────────────────────\n\ninterface PasswordConfig {\n message: string\n _streams?: Streams\n}\n\nexport async function passwordPrompt(config: PasswordConfig): Promise<string> {\n const { message, _streams } = config\n const streams = _streams ?? { stdin: process.stdin, stdout: process.stdout }\n let password = ''\n\n streams.stdout.write(` ${ANSI.BOLD}${message}${ANSI.RESET}: `)\n\n const result = await withRawMode<string>(streams, (resolve) => {\n return (key: KeyPress) => {\n switch (key.type) {\n case 'char':\n password += (key as { type: 'char'; char: string }).char\n streams.stdout.write('*')\n break\n case 'space':\n password += ' '\n streams.stdout.write('*')\n break\n case 'backspace':\n if (password.length > 0) {\n password = password.slice(0, -1)\n streams.stdout.write('\\b \\b')\n }\n break\n case 'enter':\n streams.stdout.write('\\n')\n resolve(password)\n break\n case 'escape':\n streams.stdout.write('\\n')\n resolve('')\n break\n }\n }\n })\n\n return result\n}\n","import {\n CompressionPipeline,\n RSCTransport,\n RSCEventEmitter,\n Session,\n CircuitBreaker,\n} from '@cognisos/rsc-sdk'\nimport type { SessionSummary, CircuitState } from '@cognisos/rsc-sdk'\n\nexport interface PipelineConfig {\n rscApiKey: string\n rscBaseUrl: string\n compressionThreshold: number\n learnFromResponses: boolean\n latencyBudgetMs?: number\n sessionId?: string\n}\n\nexport class RSCPipelineWrapper {\n readonly pipeline: CompressionPipeline\n readonly session: Session\n readonly events: RSCEventEmitter\n readonly transport: RSCTransport\n private readonly circuitBreaker: CircuitBreaker\n\n constructor(config: PipelineConfig) {\n this.circuitBreaker = new CircuitBreaker(5, 5 * 60 * 1000)\n\n this.transport = new RSCTransport({\n baseUrl: config.rscBaseUrl,\n apiKey: config.rscApiKey,\n timeout: 30_000,\n maxRetries: 3,\n circuitBreaker: this.circuitBreaker,\n })\n\n this.events = new RSCEventEmitter()\n this.session = new Session(config.sessionId)\n\n this.pipeline = new CompressionPipeline(\n this.transport,\n {\n threshold: config.compressionThreshold,\n learnFromResponses: config.learnFromResponses,\n latencyBudgetMs: config.latencyBudgetMs,\n sessionId: this.session.sessionId,\n },\n this.events,\n )\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n await this.transport.get<{ status: string }>('/health')\n return true\n } catch {\n return false\n }\n }\n\n getSessionSummary(): SessionSummary {\n return this.session.getSummary()\n }\n\n getCircuitState(): CircuitState {\n return this.circuitBreaker.getState()\n }\n\n isCircuitOpen(): boolean {\n return this.circuitBreaker.getState() === 'open'\n }\n\n resetCircuitBreaker(): void {\n this.circuitBreaker.reset()\n }\n}\n","/**\n * Token counting using Anthropic's official tokenizer.\n *\n * Uses @anthropic-ai/tokenizer (Claude's BPE tokenizer) for exact token\n * counts. This is the source of truth for billing — matches what Anthropic\n * charges for input/output tokens.\n *\n * Lazy-loaded: the tokenizer BPE ranks are loaded on first call (~50ms),\n * then cached for the process lifetime.\n */\n\nlet _countTokens: ((text: string) => number) | null = null\n\n/**\n * Count tokens in text using Claude's tokenizer.\n * Falls back to bytes/4 if the tokenizer fails to load.\n */\nexport function countTokens(text: string): number {\n if (!_countTokens) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mod = require('@anthropic-ai/tokenizer')\n _countTokens = mod.countTokens\n } catch {\n // Fallback: bytes / 4 if tokenizer unavailable\n _countTokens = (t: string) => Math.ceil(Buffer.byteLength(t, 'utf-8') / 4)\n }\n }\n return _countTokens!(text)\n}\n\n/**\n * Estimate tokens for a raw byte buffer (e.g., base64-decoded content).\n * Decodes to UTF-8 first, then counts tokens.\n */\nexport function countTokensBytes(bytes: Buffer | Uint8Array): number {\n const text = Buffer.from(bytes).toString('utf-8')\n return countTokens(text)\n}\n","import { readFileSync, writeFileSync, unlinkSync, existsSync } from 'node:fs'\nimport { fork } from 'node:child_process'\nimport { fileURLToPath } from 'node:url'\nimport { PID_FILE } from '../config/paths.js'\nimport type { ProxyServer } from '../proxy/server.js'\nimport type { Logger } from '../proxy/handler.js'\n\n/**\n * Write the current process PID to ~/.liminal/liminal.pid.\n */\nexport function writePidFile(pid: number): void {\n writeFileSync(PID_FILE, String(pid), 'utf-8')\n}\n\n/**\n * Read PID from ~/.liminal/liminal.pid. Returns null if file doesn't exist.\n */\nexport function readPidFile(): number | null {\n if (!existsSync(PID_FILE)) return null\n try {\n const content = readFileSync(PID_FILE, 'utf-8').trim()\n const pid = parseInt(content, 10)\n return isNaN(pid) ? null : pid\n } catch {\n return null\n }\n}\n\n/**\n * Remove the PID file.\n */\nexport function removePidFile(): void {\n try {\n if (existsSync(PID_FILE)) unlinkSync(PID_FILE)\n } catch {\n // Ignore — file may already be gone\n }\n}\n\n/**\n * Check if a process with the given PID is alive.\n */\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Check if the Liminal daemon is currently running.\n * Cleans up stale PID files automatically.\n */\nexport function isDaemonRunning(): { running: boolean; pid?: number } {\n const pid = readPidFile()\n if (pid === null) return { running: false }\n\n if (isProcessAlive(pid)) {\n return { running: true, pid }\n }\n\n // Stale PID file — process is dead\n removePidFile()\n return { running: false }\n}\n\n/**\n * Set up signal handlers for graceful shutdown.\n */\nexport function setupSignalHandlers(server: ProxyServer, logger: Logger): void {\n const shutdown = async (signal: string) => {\n logger.log(`[DAEMON] Received ${signal}, shutting down...`)\n try {\n await server.stop()\n } catch {\n // Best-effort server stop\n }\n removePidFile()\n logger.log('[DAEMON] Stopped.')\n process.exit(0)\n }\n\n process.on('SIGTERM', () => shutdown('SIGTERM'))\n process.on('SIGINT', () => shutdown('SIGINT'))\n\n process.on('uncaughtException', (err) => {\n logger.log(`[FATAL] Uncaught exception: ${err.message}`)\n removePidFile()\n process.exit(1)\n })\n\n process.on('unhandledRejection', (reason) => {\n const message = reason instanceof Error ? reason.message : String(reason)\n logger.log(`[FATAL] Unhandled rejection: ${message}`)\n removePidFile()\n process.exit(1)\n })\n}\n\n/**\n * Fork a detached child process to run the daemon in the background.\n * Returns the child PID.\n */\nexport function forkDaemon(binPath: string, extraArgs: string[] = []): number {\n const child = fork(binPath, ['start', '--_forked', ...extraArgs], {\n detached: true,\n stdio: 'ignore',\n })\n\n child.unref()\n return child.pid!\n}\n\n/**\n * Resolve the bin.ts/bin.js entry point path from import.meta.url.\n */\nexport function resolveBinPath(importMetaUrl: string): string {\n return fileURLToPath(importMetaUrl)\n}\n\n/**\n * Sleep for a given number of milliseconds.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","/**\n * In-memory stats aggregator for the current daemon session.\n *\n * Collects per-event metrics from the proxy pipeline and Cursor hooks,\n * provides computed rollups (savings rate, context extension, cost estimate),\n * and exposes a snapshot for the stats command and periodic persistence.\n */\n\n// ─── Types ──────────────────────────────────────────────────────────\n\nexport interface ToolMetrics {\n calls: number\n callsCompressed: number\n callsFailed: number\n tokensProcessed: number\n tokensSaved: number\n /** Sum of compression latencies in ms (for computing averages) */\n latencySumMs: number\n /** Count of latency samples */\n latencySamples: number\n}\n\nexport interface CursorMetrics {\n files: number\n compressions: number\n errors: number\n tokensProcessed: number\n tokensSaved: number\n apiMsSumMs: number\n cacheCount: number\n}\n\nexport interface StatsSnapshot {\n /** When this daemon session started */\n sessionStartedAt: string\n /** Session uptime in ms */\n uptimeMs: number\n\n // ── Aggregate totals (heuristic-based, bytes/4) ──\n calls: number\n callsCompressed: number\n callsFailed: number\n tokensProcessed: number\n tokensSaved: number\n\n // ── Verified tokens (from Anthropic API) ──\n /** Actual input_tokens from API responses (post-compression, ground truth) */\n actualInputTokens: number\n /** Actual output_tokens from API responses (ground truth) */\n actualOutputTokens: number\n /** Pre-compression input estimate: original message bytes / 4 */\n originalInputEstimate: number\n /** Verified input savings: originalInputEstimate - actualInputTokens */\n verifiedInputSaved: number\n /** Verified savings rate: verifiedInputSaved / originalInputEstimate */\n verifiedSavingsRate: number\n /** Number of API responses with usage data captured */\n verifiedRequestCount: number\n\n // ── Computed ──\n savingsRate: number\n contextExtension: number\n estimatedCostSavedUsd: number\n\n // ── Per-tool breakdown ──\n byTool: Record<string, ToolMetrics>\n cursor?: CursorMetrics\n}\n\nexport interface CumulativeStats {\n /** Total across all sessions ever */\n calls: number\n callsCompressed: number\n callsFailed: number\n tokensProcessed: number\n tokensSaved: number\n /** Total daemon runtime in ms */\n totalUptimeMs: number\n /** Number of sessions recorded */\n sessionCount: number\n}\n\n// ─── Cost model ─────────────────────────────────────────────────────\n\n// Conservative blended rate across popular models.\n// $3/M tokens is roughly GPT-4o input; $15/M is Claude Opus input.\n// We use $5/M as a reasonable middle ground for \"input tokens saved\".\nconst DEFAULT_COST_PER_MILLION_TOKENS = 5\n\n// ─── Aggregator ─────────────────────────────────────────────────────\n\nexport class StatsAggregator {\n private readonly startedAt = new Date()\n private readonly tools = new Map<string, ToolMetrics>()\n private cursorMetrics: CursorMetrics | null = null\n private costPerMillionTokens: number\n\n /** Actual input_tokens from Anthropic API responses (verified ground truth) */\n private actualInputTokensTotal = 0\n /** Actual output_tokens from Anthropic API responses */\n private actualOutputTokensTotal = 0\n /** Pre-compression input token count from tokenizer */\n private originalInputEstimateTotal = 0\n /** Verified tokens saved: countTokens(pre) - countTokens(post) */\n private verifiedSavedTotal = 0\n /** Number of API responses with verified usage data */\n private verifiedRequestCount = 0\n\n constructor(costPerMillionTokens = DEFAULT_COST_PER_MILLION_TOKENS) {\n this.costPerMillionTokens = costPerMillionTokens\n }\n\n // ── Recording events ──────────────────────────────────────────────\n\n /**\n * Record verified token counts from an Anthropic API response.\n *\n * @param actualInput - usage.input_tokens from Anthropic (post-compression ground truth)\n * @param actualOutput - usage.output_tokens from Anthropic (generated tokens ground truth)\n * @param verifiedSaved - tokens saved, computed as countTokens(pre) - countTokens(post) using real tokenizer\n * @param originalInputTokens - token count of full request before compression\n */\n recordApiUsage(actualInput: number, actualOutput: number, verifiedSaved: number, originalInputTokens: number): void {\n this.actualInputTokensTotal += actualInput\n this.actualOutputTokensTotal += actualOutput\n this.originalInputEstimateTotal += originalInputTokens\n this.verifiedSavedTotal += verifiedSaved\n this.verifiedRequestCount++\n }\n\n recordCompression(\n toolId: string,\n tokensProcessed: number,\n tokensSaved: number,\n latencyMs: number,\n ): void {\n const m = this.getOrCreateTool(toolId)\n m.calls++\n m.callsCompressed++\n m.tokensProcessed += tokensProcessed\n m.tokensSaved += tokensSaved\n m.latencySumMs += latencyMs\n m.latencySamples++\n }\n\n recordSkipped(toolId: string, tokensProcessed: number): void {\n const m = this.getOrCreateTool(toolId)\n m.calls++\n m.tokensProcessed += tokensProcessed\n }\n\n recordFailure(toolId: string): void {\n const m = this.getOrCreateTool(toolId)\n m.calls++\n m.callsFailed++\n }\n\n /** Bulk-update cursor metrics from the JSONL log parse. */\n setCursorMetrics(metrics: CursorMetrics): void {\n this.cursorMetrics = metrics\n }\n\n // ── Computed metrics ──────────────────────────────────────────────\n\n private getTotals(): {\n calls: number\n callsCompressed: number\n callsFailed: number\n tokensProcessed: number\n tokensSaved: number\n } {\n let calls = 0, callsCompressed = 0, callsFailed = 0\n let tokensProcessed = 0, tokensSaved = 0\n\n for (const m of this.tools.values()) {\n calls += m.calls\n callsCompressed += m.callsCompressed\n callsFailed += m.callsFailed\n tokensProcessed += m.tokensProcessed\n tokensSaved += m.tokensSaved\n }\n\n // Include Cursor hook metrics in totals\n if (this.cursorMetrics) {\n calls += this.cursorMetrics.compressions + this.cursorMetrics.errors\n callsCompressed += this.cursorMetrics.compressions\n callsFailed += this.cursorMetrics.errors\n tokensProcessed += this.cursorMetrics.tokensProcessed\n tokensSaved += this.cursorMetrics.tokensSaved\n }\n\n return { calls, callsCompressed, callsFailed, tokensProcessed, tokensSaved }\n }\n\n /** Savings rate: tokensSaved / tokensProcessed (0-1). */\n savingsRate(tokensProcessed: number, tokensSaved: number): number {\n return tokensProcessed > 0 ? tokensSaved / tokensProcessed : 0\n }\n\n /**\n * Context extension multiplier.\n * If you save 25% of tokens, your effective context is 1/(1-0.25) = 1.33x.\n */\n contextExtension(savingsRate: number): number {\n return savingsRate < 1 ? 1 / (1 - savingsRate) : 1\n }\n\n /** Estimated cost saved in USD. */\n estimatedCostSaved(tokensSaved: number): number {\n return (tokensSaved / 1_000_000) * this.costPerMillionTokens\n }\n\n // ── Snapshot ──────────────────────────────────────────────────────\n\n snapshot(): StatsSnapshot {\n const uptimeMs = Date.now() - this.startedAt.getTime()\n const totals = this.getTotals()\n const rate = this.savingsRate(totals.tokensProcessed, totals.tokensSaved)\n\n const byTool: Record<string, ToolMetrics> = {}\n for (const [id, m] of this.tools) {\n byTool[id] = { ...m }\n }\n\n const verifiedInputSaved = this.verifiedSavedTotal\n const verifiedSavingsRate = this.originalInputEstimateTotal > 0\n ? verifiedInputSaved / this.originalInputEstimateTotal\n : 0\n\n return {\n sessionStartedAt: this.startedAt.toISOString(),\n uptimeMs,\n ...totals,\n actualInputTokens: this.actualInputTokensTotal,\n actualOutputTokens: this.actualOutputTokensTotal,\n originalInputEstimate: this.originalInputEstimateTotal,\n verifiedInputSaved,\n verifiedSavingsRate,\n verifiedRequestCount: this.verifiedRequestCount,\n savingsRate: rate,\n contextExtension: this.contextExtension(rate),\n estimatedCostSavedUsd: this.estimatedCostSaved(totals.tokensSaved),\n byTool,\n cursor: this.cursorMetrics ?? undefined,\n }\n }\n\n // ── Internals ─────────────────────────────────────────────────────\n\n private getOrCreateTool(toolId: string): ToolMetrics {\n let m = this.tools.get(toolId)\n if (!m) {\n m = {\n calls: 0,\n callsCompressed: 0,\n callsFailed: 0,\n tokensProcessed: 0,\n tokensSaved: 0,\n latencySumMs: 0,\n latencySamples: 0,\n }\n this.tools.set(toolId, m)\n }\n return m\n }\n}\n","/**\n * Persistent stats store — reads/writes ~/.liminal/stats.json.\n *\n * On daemon startup, cumulative stats are loaded from disk.\n * On each flush (every 60s and on shutdown), the current session\n * snapshot is merged into cumulative totals and written back.\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { LIMINAL_DIR } from '../config/paths.js'\nimport { join } from 'node:path'\nimport type { StatsSnapshot, CumulativeStats } from './aggregator.js'\n\nexport const STATS_FILE = join(LIMINAL_DIR, 'stats.json')\n\n// ─── Schema ─────────────────────────────────────────────────────────\n\nexport interface PersistedStats {\n /** Schema version for forward compatibility */\n version: 1\n /** Cumulative totals across all daemon sessions */\n cumulative: CumulativeStats\n /** Snapshot of the last/current daemon session */\n lastSession: StatsSnapshot | null\n /** ISO timestamp of last write */\n lastUpdated: string\n}\n\nfunction emptyStats(): PersistedStats {\n return {\n version: 1,\n cumulative: {\n calls: 0,\n callsCompressed: 0,\n callsFailed: 0,\n tokensProcessed: 0,\n tokensSaved: 0,\n totalUptimeMs: 0,\n sessionCount: 0,\n },\n lastSession: null,\n lastUpdated: new Date().toISOString(),\n }\n}\n\n// ─── Read / Write ───────────────────────────────────────────────────\n\nexport function loadStats(): PersistedStats {\n try {\n if (!existsSync(STATS_FILE)) return emptyStats()\n const raw = readFileSync(STATS_FILE, 'utf-8')\n const data = JSON.parse(raw) as PersistedStats\n if (data.version !== 1) return emptyStats()\n return data\n } catch {\n return emptyStats()\n }\n}\n\nexport function saveStats(stats: PersistedStats): void {\n const dir = dirname(STATS_FILE)\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true })\n stats.lastUpdated = new Date().toISOString()\n writeFileSync(STATS_FILE, JSON.stringify(stats, null, 2) + '\\n')\n}\n\n// ─── Merge logic ────────────────────────────────────────────────────\n\n/**\n * Merge a session snapshot into persisted cumulative stats.\n *\n * Called on flush and on shutdown. Uses the session snapshot's totals\n * (not deltas) — so the caller must track what was already flushed\n * to avoid double-counting.\n */\nexport function mergeSessionIntoCumulative(\n persisted: PersistedStats,\n snapshot: StatsSnapshot,\n previousSnapshot: StatsSnapshot | null,\n): PersistedStats {\n const c = persisted.cumulative\n\n // Compute deltas since the last flush\n const prev = previousSnapshot\n const deltaCalls = snapshot.calls - (prev?.calls ?? 0)\n const deltaCompressed = snapshot.callsCompressed - (prev?.callsCompressed ?? 0)\n const deltaFailed = snapshot.callsFailed - (prev?.callsFailed ?? 0)\n const deltaProcessed = snapshot.tokensProcessed - (prev?.tokensProcessed ?? 0)\n const deltaSaved = snapshot.tokensSaved - (prev?.tokensSaved ?? 0)\n const deltaUptime = snapshot.uptimeMs - (prev?.uptimeMs ?? 0)\n\n c.calls += deltaCalls\n c.callsCompressed += deltaCompressed\n c.callsFailed += deltaFailed\n c.tokensProcessed += deltaProcessed\n c.tokensSaved += deltaSaved\n c.totalUptimeMs += deltaUptime\n\n persisted.lastSession = snapshot\n return persisted\n}\n\n/**\n * Increment the session count (call once on daemon startup, not on every flush).\n */\nexport function incrementSessionCount(persisted: PersistedStats): PersistedStats {\n persisted.cumulative.sessionCount++\n return persisted\n}\n","/**\n * Parse Cursor hook compression logs from .fabric/compress.log.\n *\n * Shared between the stats command and the health endpoint so the TUI\n * can display Cursor metrics alongside Claude Code metrics.\n */\n\nimport { existsSync, readFileSync, readdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { CursorMetrics } from '../stats/aggregator.js'\n\ninterface HookLogEntry {\n ts: string\n type: 'compressed' | 'error'\n file: string\n inputSize?: number\n outputSize?: number\n inputTokens?: number\n outputTokens?: number\n tokensSaved?: number\n savedPct?: number\n apiMs?: number\n error?: string\n}\n\n/** Recent log entries for display in the TUI logs view. */\nexport interface CursorLogEntry {\n /** ISO timestamp */\n ts: string\n /** Formatted log line for display */\n line: string\n}\n\n/**\n * Parse .fabric/compress.log and return aggregated CursorMetrics.\n * Returns null if the log file doesn't exist.\n */\nexport function parseCursorHookStats(cwd = process.cwd()): CursorMetrics | null {\n const logPath = join(cwd, '.fabric', 'compress.log')\n if (!existsSync(logPath)) return null\n\n let compressions = 0, errors = 0\n let tokensProcessed = 0, tokensSaved = 0\n let apiMsSumMs = 0\n const files = new Set<string>()\n\n const content = readFileSync(logPath, 'utf-8').trim()\n if (!content) return null\n\n for (const line of content.split('\\n')) {\n try {\n const entry = JSON.parse(line) as HookLogEntry\n if (entry.type === 'compressed') {\n compressions++\n tokensProcessed += entry.inputTokens ?? Math.ceil((entry.inputSize ?? 0) / 3)\n tokensSaved += entry.tokensSaved ?? 0\n apiMsSumMs += entry.apiMs ?? 0\n files.add(entry.file)\n } else if (entry.type === 'error') {\n errors++\n }\n } catch {\n // Skip malformed lines\n }\n }\n\n let cacheCount = 0\n try {\n cacheCount = countFilesRecursive(join(cwd, '.fabric', 'cache'))\n } catch { /* ok */ }\n\n return {\n files: files.size,\n compressions,\n errors,\n tokensProcessed,\n tokensSaved,\n apiMsSumMs,\n cacheCount,\n }\n}\n\n/**\n * Read recent entries from .fabric/compress.log formatted for the TUI logs view.\n * Returns the last `maxEntries` entries as formatted log lines.\n */\nexport function readCursorLogEntries(maxEntries = 50, cwd = process.cwd()): CursorLogEntry[] {\n const logPath = join(cwd, '.fabric', 'compress.log')\n if (!existsSync(logPath)) return []\n\n const content = readFileSync(logPath, 'utf-8').trim()\n if (!content) return []\n\n const lines = content.split('\\n')\n const recent = lines.slice(-maxEntries)\n const entries: CursorLogEntry[] = []\n\n for (const line of recent) {\n try {\n const entry = JSON.parse(line) as HookLogEntry\n const ts = entry.ts ? new Date(entry.ts) : new Date()\n const time = ts.toTimeString().slice(0, 8)\n\n if (entry.type === 'compressed') {\n const pct = entry.savedPct ?? (entry.inputTokens && entry.tokensSaved\n ? +((entry.tokensSaved / entry.inputTokens) * 100).toFixed(1)\n : 0)\n entries.push({\n ts: entry.ts,\n line: `[${time}] [CURSOR] ${entry.file} → ${entry.tokensSaved} tok saved (${pct}%) ${entry.apiMs}ms`,\n })\n } else if (entry.type === 'error') {\n entries.push({\n ts: entry.ts,\n line: `[${time}] [CURSOR] ${entry.file} → ERROR: ${entry.error ?? 'unknown'}`,\n })\n }\n } catch {\n // Skip malformed\n }\n }\n\n return entries\n}\n\nfunction countFilesRecursive(dir: string): number {\n if (!existsSync(dir)) return 0\n let count = 0\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n count += countFilesRecursive(join(dir, entry.name))\n } else {\n count++\n }\n }\n return count\n}\n","/**\n * Screen manager — alternate buffer, full-screen rendering, terminal lifecycle.\n *\n * Enters the alternate screen buffer so the user's terminal is preserved.\n * Provides a render loop that clears and redraws the full screen.\n * Restores the original terminal on exit (even on crash).\n */\n\nimport { c } from './format.js'\nimport { parseKey } from './prompts.js'\nimport type { KeyPress } from './prompts.js'\n\n// ─── ANSI sequences for screen control ──────────────────────────────\n\nconst SEQ = {\n ALT_BUFFER_ON: '\\x1b[?1049h',\n ALT_BUFFER_OFF: '\\x1b[?1049l',\n CLEAR_SCREEN: '\\x1b[2J',\n CURSOR_HOME: '\\x1b[H',\n CURSOR_TO: (row: number, col: number) => `\\x1b[${row};${col}H`,\n HIDE_CURSOR: '\\x1b[?25l',\n SHOW_CURSOR: '\\x1b[?25h',\n CLEAR_LINE: '\\x1b[2K',\n} as const\n\n// ─── Types ──────────────────────────────────────────────────────────\n\nexport interface ScreenSize {\n cols: number\n rows: number\n}\n\nexport interface ScreenCallbacks {\n /** Called on each render tick. Return lines to draw (array of strings). */\n render: (size: ScreenSize) => string[]\n /** Called on each keypress. Return false to exit the screen. */\n onKey: (key: KeyPress, size: ScreenSize) => boolean\n /** Called when terminal is resized. */\n onResize?: (size: ScreenSize) => void\n /** Called on cleanup (before exiting alternate buffer). */\n onExit?: () => void\n}\n\n// ─── Screen manager ─────────────────────────────────────────────────\n\nexport class Screen {\n private readonly stdout = process.stdout\n private readonly stdin = process.stdin\n private cleaned = false\n private refreshTimer: ReturnType<typeof setInterval> | null = null\n private callbacks: ScreenCallbacks\n\n constructor(callbacks: ScreenCallbacks) {\n this.callbacks = callbacks\n }\n\n /** Get current terminal dimensions. */\n getSize(): ScreenSize {\n return {\n cols: this.stdout.columns || 80,\n rows: this.stdout.rows || 24,\n }\n }\n\n /**\n * Enter full-screen mode and start the render/input loop.\n * Resolves when the user exits (onKey returns false).\n */\n async run(refreshMs = 2000): Promise<void> {\n return new Promise<void>((resolve) => {\n // Enter alternate screen buffer\n this.stdout.write(SEQ.ALT_BUFFER_ON)\n this.stdout.write(SEQ.HIDE_CURSOR)\n\n // Initial render\n this.draw()\n\n // Periodic refresh for live data\n this.refreshTimer = setInterval(() => this.draw(), refreshMs)\n if (this.refreshTimer.unref) this.refreshTimer.unref()\n\n // Listen for resize\n const onResize = () => {\n this.callbacks.onResize?.(this.getSize())\n this.draw()\n }\n this.stdout.on('resize', onResize)\n\n // Key input\n const onData = (data: Buffer) => {\n const key = parseKey(data)\n\n if (key.type === 'ctrlc') {\n this.cleanup(onData, onResize)\n resolve()\n return\n }\n\n const continueRunning = this.callbacks.onKey(key, this.getSize())\n if (!continueRunning) {\n this.cleanup(onData, onResize)\n resolve()\n return\n }\n\n // Re-render after key input for immediate feedback\n this.draw()\n }\n\n // Safety: restore terminal on unexpected exit\n const exitHandler = () => this.cleanup(onData, onResize)\n process.on('exit', exitHandler)\n\n // Enter raw mode\n if (this.stdin.setRawMode) this.stdin.setRawMode(true)\n this.stdin.on('data', onData)\n if (this.stdin.resume) this.stdin.resume()\n\n // Store exit handler ref for cleanup\n this._exitHandler = exitHandler\n this._onData = onData\n this._onResize = onResize\n })\n }\n\n private _exitHandler: (() => void) | null = null\n private _onData: ((data: Buffer) => void) | null = null\n private _onResize: (() => void) | null = null\n\n /** Render the full screen. */\n private draw(): void {\n const size = this.getSize()\n const lines = this.callbacks.render(size)\n\n // Build the full frame\n let frame = SEQ.CURSOR_HOME\n for (let i = 0; i < size.rows; i++) {\n const line = lines[i] ?? ''\n frame += SEQ.CLEAR_LINE + line\n if (i < size.rows - 1) frame += '\\n'\n }\n\n this.stdout.write(frame)\n }\n\n /** Restore terminal state. */\n private cleanup(\n onData: (data: Buffer) => void,\n onResize: () => void,\n ): void {\n if (this.cleaned) return\n this.cleaned = true\n\n // Stop refresh timer\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer)\n this.refreshTimer = null\n }\n\n // Callback\n this.callbacks.onExit?.()\n\n // Remove listeners\n this.stdin.removeListener('data', onData)\n this.stdout.removeListener('resize', onResize)\n if (this._exitHandler) {\n process.removeListener('exit', this._exitHandler)\n }\n\n // Restore terminal\n if (this.stdin.setRawMode) this.stdin.setRawMode(false)\n if (typeof this.stdin.pause === 'function') (this.stdin as any).pause()\n this.stdout.write(SEQ.SHOW_CURSOR)\n this.stdout.write(SEQ.ALT_BUFFER_OFF)\n }\n}\n","/**\n * Layout engine — panels, borders, text wrapping for the TUI.\n *\n * Renders content into fixed-size regions within the terminal.\n * All rendering is line-based: each function returns string[] to be\n * composed by the screen manager.\n */\n\nimport { c, stripAnsi, icons } from './format.js'\n\n// ─── Types ──────────────────────────────────────────────────────────\n\nexport interface PanelOptions {\n /** Panel title (shown in top border) */\n title?: string\n /** Panel width (default: full terminal width) */\n width?: number\n /** Panel height (content lines, excluding borders) */\n height?: number\n /** Whether this panel is currently focused/active */\n focused?: boolean\n}\n\n// ─── Box characters ─────────────────────────────────────────────────\n\nconst HEAVY = {\n tl: '\\u250F', tr: '\\u2513',\n bl: '\\u2517', br: '\\u251B',\n h: '\\u2501', v: '\\u2503',\n} as const\n\nconst LIGHT = {\n tl: '\\u250C', tr: '\\u2510',\n bl: '\\u2514', br: '\\u2518',\n h: '\\u2500', v: '\\u2502',\n} as const\n\n// ─── Panel rendering ────────────────────────────────────────────────\n\n/**\n * Render a bordered panel containing lines of content.\n *\n * @param content Lines to display inside the panel\n * @param opts Panel options\n * @returns Array of rendered lines (including borders)\n */\nexport function panel(content: string[], opts: PanelOptions = {}): string[] {\n const width = opts.width ?? 80\n const innerWidth = width - 4 // 2 border + 2 padding\n const box = opts.focused ? HEAVY : LIGHT\n const titleColor = opts.focused ? c.cyan : c.dim\n const borderColor = opts.focused ? c.cyan : c.dim\n\n const lines: string[] = []\n\n // Top border\n if (opts.title) {\n const titleText = ` ${opts.title} `\n const titleLen = stripAnsi(titleText).length\n const afterTitle = Math.max(0, width - 2 - titleLen)\n lines.push(\n `${borderColor}${box.tl}${titleText}${box.h.repeat(afterTitle)}${box.tr}${c.reset}`,\n )\n } else {\n lines.push(`${borderColor}${box.tl}${box.h.repeat(width - 2)}${box.tr}${c.reset}`)\n }\n\n // Content lines (pad or truncate to fit)\n const maxLines = opts.height ?? content.length\n for (let i = 0; i < maxLines; i++) {\n const raw = content[i] ?? ''\n const visible = stripAnsi(raw).length\n const padded = visible < innerWidth\n ? raw + ' '.repeat(innerWidth - visible)\n : truncate(raw, innerWidth)\n lines.push(`${borderColor}${box.v}${c.reset} ${padded} ${borderColor}${box.v}${c.reset}`)\n }\n\n // Bottom border\n lines.push(`${borderColor}${box.bl}${box.h.repeat(width - 2)}${box.br}${c.reset}`)\n\n return lines\n}\n\n// ─── Tab bar ────────────────────────────────────────────────────────\n\n/**\n * Render a horizontal tab bar.\n *\n * @param tabs Tab labels\n * @param activeIndex Currently active tab index\n * @param width Total width\n */\nexport function tabBar(tabs: string[], activeIndex: number, width: number): string {\n const parts: string[] = []\n\n for (let i = 0; i < tabs.length; i++) {\n if (i === activeIndex) {\n parts.push(`${c.bold}${c.cyan} ${tabs[i]} ${c.reset}`)\n } else {\n parts.push(`${c.dim} ${tabs[i]} ${c.reset}`)\n }\n }\n\n const joined = parts.join(`${c.dim}\\u2502${c.reset}`)\n return ` ${joined}`\n}\n\n// ─── Status bar ─────────────────────────────────────────────────────\n\n/**\n * Render a bottom status bar with key hints.\n */\nexport function statusBar(hints: [string, string][], width: number): string {\n const parts: string[] = []\n for (const [key, label] of hints) {\n parts.push(`${c.bold}${key}${c.reset}${c.dim}:${label}${c.reset}`)\n }\n const content = ` ${parts.join(' ')}`\n const visible = stripAnsi(content).length\n const pad = Math.max(0, width - visible)\n return `${c.dim}${c.bold}${content}${' '.repeat(pad)}${c.reset}`\n}\n\n// ─── Header ─────────────────────────────────────────────────────────\n\n/**\n * Render the top header line with branding.\n */\nexport function header(title: string, rightText: string, width: number): string {\n const left = ` ${c.bold}${c.cyan}${title}${c.reset}`\n const right = `${c.dim}${rightText} ${c.reset}`\n const leftLen = stripAnsi(left).length\n const rightLen = stripAnsi(right).length\n const gap = Math.max(1, width - leftLen - rightLen)\n return left + ' '.repeat(gap) + right\n}\n\n// ─── Content helpers ────────────────────────────────────────────────\n\n/** Create a key-value line with aligned columns. */\nexport function kvLine(key: string, value: string, keyWidth = 18): string {\n const keyText = `${c.dim}${key}${c.reset}`\n const keyLen = stripAnsi(key).length\n const pad = Math.max(1, keyWidth - keyLen)\n return `${keyText}${' '.repeat(pad)}${value}`\n}\n\n/** Create a section divider. */\nexport function divider(label: string, width: number): string {\n const text = ` ${label} `\n const textLen = stripAnsi(text).length\n const sideLen = Math.max(2, Math.floor((width - textLen) / 2))\n const rule = '\\u2500'.repeat(sideLen)\n return `${c.dim}${rule}${c.reset}${c.bold}${text}${c.reset}${c.dim}${rule}${c.reset}`\n}\n\n/** Create a blank line. */\nexport function blank(): string {\n return ''\n}\n\n/** Create a status indicator line. */\nexport function statusLine(ok: boolean, label: string, detail?: string): string {\n const icon = ok ? `${c.green}${icons.success}${c.reset}` : `${c.red}${icons.error}${c.reset}`\n const det = detail ? ` ${c.dim}${detail}${c.reset}` : ''\n return `${icon} ${label}${det}`\n}\n\n// ─── Utility ────────────────────────────────────────────────────────\n\n/** Truncate a string (accounting for ANSI) to fit within maxWidth. */\nfunction truncate(str: string, maxWidth: number): string {\n let visible = 0\n let result = ''\n let inEscape = false\n\n for (let i = 0; i < str.length; i++) {\n const ch = str[i]\n\n if (ch === '\\x1b') {\n inEscape = true\n result += ch\n continue\n }\n\n if (inEscape) {\n result += ch\n if (ch === 'm') inEscape = false\n continue\n }\n\n if (visible >= maxWidth - 1) {\n result += '\\u2026' // …\n break\n }\n\n result += ch\n visible++\n }\n\n return result\n}\n\n/** Pad lines array to a minimum length. */\nexport function padLines(lines: string[], minLength: number): string[] {\n while (lines.length < minLength) {\n lines.push('')\n }\n return lines\n}\n","/**\n * Dashboard view — live overview of daemon health, tool routing, and session stats.\n */\n\nimport { c, icons, formatUptime, formatNum } from '../format.js'\nimport { kvLine, statusLine, divider, blank } from '../layout.js'\nimport type { View, HubState } from './types.js'\nimport type { ScreenSize } from '../screen.js'\n\nexport const dashboardView: View = {\n id: 'dashboard',\n label: 'Dashboard',\n\n render(state: HubState, size: ScreenSize): string[] {\n const lines: string[] = []\n const w = Math.max(40, size.cols - 6)\n\n // ── Daemon status ───────────────────────────────────────────\n lines.push(divider('Status', w))\n lines.push(blank())\n\n if (!state.daemonRunning) {\n lines.push(statusLine(false, 'Daemon not running'))\n lines.push(` ${c.dim}${icons.arrow} Run ${c.bold}liminal start${c.reset}${c.dim} to begin${c.reset}`)\n lines.push(blank())\n return lines\n }\n\n const health = state.health\n lines.push(statusLine(true, `Daemon running`, `PID ${state.daemonPid}`))\n\n if (health) {\n lines.push(statusLine(true, `Uptime ${formatUptime(health.uptime_ms)}`, `${health.status} (${health.version})`))\n\n // API health\n const apiOk = health.status === 'ok' || health.status === 'healthy'\n lines.push(statusLine(apiOk, 'Cognisos API', apiOk ? 'healthy' : health.status))\n\n // MITM\n if (health.mitm) {\n lines.push(statusLine(\n health.mitm.enabled,\n 'MITM bridge',\n health.mitm.enabled\n ? `${health.mitm.intercepted} intercepted`\n : 'disabled',\n ))\n }\n } else {\n lines.push(` ${c.yellow}${icons.warning}${c.reset} Waiting for health data...`)\n }\n\n lines.push(blank())\n\n // ── Tool routing ────────────────────────────────────────────\n lines.push(divider('Tools', w))\n lines.push(blank())\n\n if (health && health.sessions.length > 0) {\n // Group sessions by connector\n const connectors = new Map<string, { calls: number; processed: number; saved: number; circuit: string }>()\n for (const s of health.sessions) {\n const existing = connectors.get(s.connector) ?? { calls: 0, processed: 0, saved: 0, circuit: s.circuit_state }\n existing.calls += s.calls_total\n existing.processed += s.tokens_processed\n existing.saved += s.tokens_saved\n existing.circuit = s.circuit_state\n connectors.set(s.connector, existing)\n }\n\n for (const [name, data] of connectors) {\n const circuitColor = data.circuit === 'closed' ? c.green\n : data.circuit === 'open' ? c.red : c.yellow\n const savingsPct = data.processed > 0\n ? `${(data.saved / data.processed * 100).toFixed(1)}%`\n : '—'\n lines.push(statusLine(true, formatConnectorLabel(name), `${circuitColor}${data.circuit}${c.reset}`))\n lines.push(` ${c.dim}${data.calls} calls | ${formatNum(data.processed)} tok processed | ${savingsPct} saved${c.reset}`)\n }\n } else if (state.tools.length > 0) {\n for (const tool of state.tools) {\n lines.push(statusLine(true, formatConnectorLabel(tool), 'configured'))\n }\n lines.push(` ${c.dim}No active sessions yet${c.reset}`)\n } else {\n lines.push(` ${c.dim}No tools configured${c.reset}`)\n }\n\n lines.push(blank())\n\n // ── Session metrics ─────────────────────────────────────────\n if (health) {\n lines.push(divider('This Session', w))\n lines.push(blank())\n\n let totalCalls = 0, totalCompressed = 0, totalFailed = 0\n let totalProcessed = 0, totalSaved = 0\n\n for (const s of health.sessions) {\n totalCalls += s.calls_total\n totalCompressed += s.calls_compressed\n totalFailed += s.calls_failed\n totalProcessed += s.tokens_processed\n totalSaved += s.tokens_saved\n }\n\n const savingsRate = totalProcessed > 0 ? totalSaved / totalProcessed : 0\n const contextExt = savingsRate < 1 ? 1 / (1 - savingsRate) : 1\n const costSaved = (totalSaved / 1_000_000) * 5\n\n lines.push(kvLine('API Calls', `${totalCalls}${totalCompressed > 0 ? ` (${totalCompressed} compressed)` : ''}${totalFailed > 0 ? ` ${c.red}${totalFailed} failed${c.reset}` : ''}`))\n lines.push(kvLine('Tokens Processed', formatNum(totalProcessed)))\n lines.push(kvLine('Tokens Saved', totalSaved > 0 ? `${formatNum(totalSaved)} ${c.cyan}(${(savingsRate * 100).toFixed(1)}%)${c.reset}` : '—'))\n lines.push(kvLine('Context Extension', savingsRate > 0 ? `${c.green}~${contextExt.toFixed(2)}x${c.reset}` : '~1.00x'))\n lines.push(kvLine('Est. Cost Saved', costSaved > 0 ? `${c.green}$${costSaved.toFixed(2)}${c.reset}` : '—'))\n\n // Latency\n const p95 = health.latency.global_p95_ms\n if (p95 !== null) {\n lines.push(kvLine('Latency (p95)', `${p95.toFixed(0)}ms`))\n }\n\n // Concurrency\n const conc = health.concurrency\n lines.push(kvLine('Sessions', `${conc.active_sessions} active`))\n\n lines.push(blank())\n }\n\n // ── Recent activity ─────────────────────────────────────────\n if (state.recentLogs.length > 0) {\n lines.push(divider('Recent Activity', w))\n lines.push(blank())\n\n // Show last N log lines that fit\n const maxLogLines = Math.max(3, size.rows - lines.length - 5)\n const recent = state.recentLogs.slice(-maxLogLines)\n for (const log of recent) {\n lines.push(colorizeLogLine(log, w))\n }\n lines.push(blank())\n }\n\n return lines\n },\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────\n\nfunction formatConnectorLabel(id: string): string {\n const map: Record<string, string> = {\n 'claude-code': 'Claude Code',\n 'anthropic-messages': 'Claude Code',\n 'codex': 'Codex CLI',\n 'cursor': 'Cursor',\n 'openai-compatible': 'OpenAI Compatible',\n 'openai-chat': 'OpenAI',\n 'openai-responses': 'Codex',\n }\n return map[id] ?? id\n}\n\nfunction colorizeLogLine(line: string, maxWidth: number): string {\n // Extract timestamp if present\n const match = line.match(/^\\[(\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?)\\]\\s*(.*)$/)\n if (!match) {\n const truncated = line.length > maxWidth ? line.slice(0, maxWidth - 1) + '\\u2026' : line\n return `${c.dim}${truncated}${c.reset}`\n }\n\n const [, ts, rest] = match\n let colored = rest\n\n // Highlight key patterns\n if (rest.includes('Compressed')) {\n colored = `${c.green}${rest}${c.reset}`\n } else if (rest.includes('Error') || rest.includes('FAILED')) {\n colored = `${c.red}${rest}${c.reset}`\n } else if (rest.includes('Skipped')) {\n colored = `${c.yellow}${rest}${c.reset}`\n } else if (rest.includes('Circuit')) {\n colored = `${c.yellow}${rest}${c.reset}`\n } else {\n colored = `${c.dim}${rest}${c.reset}`\n }\n\n return `${c.dim}${ts}${c.reset} ${colored}`\n}\n","/**\n * Stats view — token savings, cost impact, per-tool breakdown.\n */\n\nimport { c, formatUptime, formatNum } from '../format.js'\nimport { kvLine, divider, blank } from '../layout.js'\nimport { loadStats } from '../../stats/store.js'\nimport type { View, HubState } from './types.js'\nimport type { ScreenSize } from '../screen.js'\n\nexport const statsView: View = {\n id: 'stats',\n label: 'Stats',\n\n render(state: HubState, size: ScreenSize): string[] {\n const lines: string[] = []\n const w = Math.max(40, size.cols - 6)\n const health = state.health\n const persisted = loadStats()\n const cum = persisted.cumulative\n\n // ── Session overview ────────────────────────────────────────\n lines.push(divider('Session', w))\n lines.push(blank())\n\n // Session column values\n let sCalls = '—', sCompressed = '—'\n let sProcessed = '—', sSaved = '—', sRate = '—', sExt = '—'\n let sCost = '—', sUptime = '—'\n\n if (health) {\n let totalCalls = 0, totalCompressed = 0, totalFailed = 0\n let totalProcessed = 0, totalSaved = 0\n for (const s of health.sessions) {\n totalCalls += s.calls_total\n totalCompressed += s.calls_compressed\n totalFailed += s.calls_failed\n totalProcessed += s.tokens_processed\n totalSaved += s.tokens_saved\n }\n\n const rate = totalProcessed > 0 ? totalSaved / totalProcessed : 0\n const ext = rate < 1 ? 1 / (1 - rate) : 1\n\n sUptime = formatUptime(health.uptime_ms)\n sCalls = String(totalCalls)\n sCompressed = totalCalls > 0 ? `${totalCompressed} (${(totalCompressed / totalCalls * 100).toFixed(1)}%)` : '—'\n sProcessed = formatNum(totalProcessed)\n sSaved = formatNum(totalSaved)\n sRate = `${(rate * 100).toFixed(1)}%`\n sExt = `~${ext.toFixed(2)}x`\n sCost = `$${((totalSaved / 1_000_000) * 5).toFixed(2)}`\n }\n\n // All-time column values\n const aUptime = cum.totalUptimeMs > 0 ? formatUptime(cum.totalUptimeMs) : '—'\n const aCalls = cum.calls > 0 ? formatNum(cum.calls) : '—'\n const aCompressed = cum.calls > 0 ? `${formatNum(cum.callsCompressed)} (${(cum.callsCompressed / cum.calls * 100).toFixed(1)}%)` : '—'\n const aProcessed = cum.tokensProcessed > 0 ? formatNum(cum.tokensProcessed) : '—'\n const aSaved = cum.tokensSaved > 0 ? formatNum(cum.tokensSaved) : '—'\n const allTimeRate = cum.tokensProcessed > 0 ? cum.tokensSaved / cum.tokensProcessed : 0\n const aRate = cum.tokensProcessed > 0 ? `${(allTimeRate * 100).toFixed(1)}%` : '—'\n const aExt = allTimeRate > 0 ? `~${(1 / (1 - allTimeRate)).toFixed(2)}x` : '—'\n const aCost = cum.tokensSaved > 0 ? `$${((cum.tokensSaved / 1_000_000) * 5).toFixed(2)}` : '—'\n\n // Render as two-column table\n const colW = 16\n const hdr = `${''.padEnd(20)}${c.bold}${'This Session'.padEnd(colW)}${'All Time'.padEnd(colW)}${c.reset}`\n const sep = `${c.dim}${'─'.repeat(20)}${'─'.repeat(colW)}${'─'.repeat(colW)}${c.reset}`\n\n lines.push(hdr)\n lines.push(sep)\n lines.push(formatRow('Uptime', sUptime, aUptime, colW))\n lines.push(formatRow('API Calls', sCalls, aCalls, colW))\n lines.push(formatRow('Compressed', sCompressed, aCompressed, colW))\n lines.push(blank())\n\n // ── Token savings ───────────────────────────────────────────\n lines.push(divider('Token Savings', w))\n lines.push(blank())\n lines.push(hdr)\n lines.push(sep)\n lines.push(formatRow('Tokens Processed', sProcessed, aProcessed, colW))\n lines.push(formatRow('Tokens Saved', sSaved, aSaved, colW))\n lines.push(formatRow('Savings Rate', sRate, aRate, colW))\n lines.push(formatRow('Context Extension', sExt, aExt, colW))\n lines.push(blank())\n\n // ── Verified tokens (from Anthropic API) ──────────────────\n lines.push(divider('Verified (Anthropic API)', w))\n lines.push(blank())\n\n if (health && health.verifiedRequestCount && health.verifiedRequestCount > 0) {\n const actualIn = health.actualInputTokens ?? 0\n const actualOut = health.actualOutputTokens ?? 0\n const origEst = health.originalInputEstimate ?? 0\n const saved = health.verifiedInputSaved ?? 0\n const rate = health.verifiedSavingsRate ?? 0\n const reqs = health.verifiedRequestCount\n\n lines.push(formatRow('Input (actual)', formatNum(actualIn), '—', colW))\n lines.push(formatRow('Input (pre-comp)', formatNum(origEst), '—', colW))\n lines.push(formatRow('Input Saved', formatNum(saved), '—', colW))\n lines.push(formatRow('Input Savings Rate', `${(rate * 100).toFixed(1)}%`, '—', colW))\n lines.push(blank())\n lines.push(formatRow('Output (actual)', formatNum(actualOut), '—', colW))\n lines.push(formatRow('Total (in + out)', formatNum(actualIn + actualOut), '—', colW))\n lines.push(blank())\n lines.push(formatRow('Verified Requests', String(reqs), '—', colW))\n } else {\n lines.push(` ${c.dim}No verified data yet — waiting for API responses${c.reset}`)\n }\n lines.push(blank())\n\n // ── Cost impact ─────────────────────────────────────────────\n lines.push(divider('Cost Impact', w))\n lines.push(blank())\n lines.push(hdr)\n lines.push(sep)\n lines.push(formatRow('Est. Cost Saved', sCost, aCost, colW))\n lines.push(blank())\n\n // ── Per-tool breakdown ──────────────────────────────────────\n let byToolRendered = false\n if (health && health.sessions.length > 0) {\n lines.push(divider('By Tool', w))\n lines.push(blank())\n byToolRendered = true\n\n const byTool = new Map<string, { calls: number; compressed: number; failed: number; processed: number; saved: number; p95: number | null }>()\n for (const s of health.sessions) {\n const existing = byTool.get(s.connector) ?? { calls: 0, compressed: 0, failed: 0, processed: 0, saved: 0, p95: null }\n existing.calls += s.calls_total\n existing.compressed += s.calls_compressed\n existing.failed += s.calls_failed\n existing.processed += s.tokens_processed\n existing.saved += s.tokens_saved\n if (s.p95_latency_ms !== null) existing.p95 = s.p95_latency_ms\n byTool.set(s.connector, existing)\n }\n\n for (const [name, data] of byTool) {\n const pct = data.processed > 0 ? `${(data.saved / data.processed * 100).toFixed(1)}%` : '—'\n lines.push(`${c.bold}${formatLabel(name)}${c.reset}`)\n lines.push(` Calls: ${data.calls} (${data.compressed} compressed)${data.failed > 0 ? ` ${c.red}${data.failed} failed${c.reset}` : ''} | Saved: ${formatNum(data.saved)} tok (${pct})`)\n if (data.p95 !== null) {\n lines.push(` Latency: p95 ${data.p95.toFixed(0)}ms`)\n }\n lines.push(blank())\n }\n }\n\n // ── Cursor hooks ────────────────────────────────────────────\n if (health?.cursor) {\n const cur = health.cursor\n if (!byToolRendered) {\n lines.push(divider('By Tool', w))\n lines.push(blank())\n }\n const curPct = cur.tokensProcessed > 0 ? `${(cur.tokensSaved / cur.tokensProcessed * 100).toFixed(1)}%` : '—'\n const avgMs = cur.compressions > 0 ? Math.round(cur.apiMsSumMs / cur.compressions) : 0\n lines.push(`${c.bold}${formatLabel('cursor')}${c.reset}`)\n lines.push(` Files: ${cur.files} unique (${cur.compressions} compressions${cur.errors > 0 ? `, ${c.red}${cur.errors} errors${c.reset}` : ''}) | Saved: ${formatNum(cur.tokensSaved)} tok (${curPct})`)\n lines.push(` Cache: ${cur.cacheCount} files | Avg API: ${avgMs}ms/file`)\n lines.push(blank())\n }\n\n // Sessions info\n if (cum.sessionCount > 0) {\n lines.push(`${c.dim}${cum.sessionCount} session${cum.sessionCount !== 1 ? 's' : ''} recorded${c.reset}`)\n }\n\n return lines\n },\n}\n\nfunction formatRow(label: string, session: string, allTime: string, colW: number): string {\n return `${label.padEnd(20)}${session.padEnd(colW)}${allTime.padEnd(colW)}`\n}\n\nfunction formatLabel(id: string): string {\n const map: Record<string, string> = {\n 'claude-code': 'Claude Code',\n 'anthropic-messages': 'Claude Code',\n 'codex': 'Codex CLI',\n 'cursor': 'Cursor',\n 'openai-compatible': 'OpenAI Compatible',\n }\n return map[id] ?? id\n}\n","/**\n * Config view — displays current configuration.\n */\n\nimport { c } from '../format.js'\nimport { kvLine, divider, blank } from '../layout.js'\nimport type { View, HubState } from './types.js'\nimport type { ScreenSize } from '../screen.js'\n\nexport const configView: View = {\n id: 'config',\n label: 'Config',\n\n render(state: HubState, size: ScreenSize): string[] {\n const lines: string[] = []\n const w = Math.max(40, size.cols - 6)\n\n lines.push(divider('Configuration', w))\n lines.push(blank())\n\n if (state.configEntries.length === 0) {\n lines.push(`${c.dim}No configuration loaded.${c.reset}`)\n lines.push(`${c.dim}Run liminal init to set up.${c.reset}`)\n } else {\n for (const [key, value] of state.configEntries) {\n lines.push(kvLine(key, value, 24))\n }\n }\n\n lines.push(blank())\n lines.push(`${c.dim}Edit: liminal config --set key=value${c.reset}`)\n\n return lines\n },\n}\n","/**\n * Logs view — live tail of daemon + Cursor hook logs, interleaved by timestamp.\n */\n\nimport { c } from '../format.js'\nimport { divider, blank } from '../layout.js'\nimport type { View, HubState } from './types.js'\nimport type { ScreenSize } from '../screen.js'\n\nlet _readCursorLogs: (() => { ts: string; line: string }[]) | null = null\nfunction getCursorLogs(): { ts: string; line: string }[] {\n if (!_readCursorLogs) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mod = require('../../cursor/stats.js')\n _readCursorLogs = () => mod.readCursorLogEntries(50)\n } catch {\n _readCursorLogs = () => []\n }\n }\n return _readCursorLogs()\n}\n\nexport const logsView: View = {\n id: 'logs',\n label: 'Logs',\n\n render(state: HubState, size: ScreenSize): string[] {\n const lines: string[] = []\n const w = Math.max(40, size.cols - 6)\n\n lines.push(divider('All Logs', w))\n lines.push(blank())\n\n // Merge daemon logs + Cursor hook logs by timestamp\n const cursorEntries = getCursorLogs()\n const allLogs: { ts: string; line: string; source: 'daemon' | 'cursor' }[] = []\n\n for (const line of state.recentLogs) {\n // Extract timestamp from daemon log: [HH:MM:SS.mmm]\n const match = line.match(/^\\[(\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?)\\]/)\n allLogs.push({ ts: match?.[1] ?? '99:99:99', line, source: 'daemon' })\n }\n for (const entry of cursorEntries) {\n allLogs.push({ ts: entry.ts, line: entry.line, source: 'cursor' })\n }\n\n // Sort by timestamp (cursor entries have ISO timestamps, daemon have HH:MM:SS)\n // For simplicity, just append cursor entries at the end since they're\n // already chronological and interleaving ISO vs HH:MM:SS is fragile\n const daemonLogs = state.recentLogs\n const combined = [...daemonLogs, ...cursorEntries.map(e => e.line)]\n\n if (combined.length === 0) {\n if (!state.daemonRunning) {\n lines.push(`${c.dim}Daemon not running — no logs to show.${c.reset}`)\n } else {\n lines.push(`${c.dim}Waiting for log output...${c.reset}`)\n }\n lines.push(blank())\n return lines\n }\n\n // Fill available space with log lines\n const maxLines = Math.max(5, size.rows - 7)\n const tail = combined.slice(-maxLines)\n\n for (const line of tail) {\n lines.push(colorizeLog(line, w))\n }\n\n lines.push(blank())\n lines.push(`${c.dim}Showing last ${tail.length} lines (daemon + cursor) — refreshes every 2s${c.reset}`)\n\n return lines\n },\n}\n\nfunction colorizeLog(line: string, maxWidth: number): string {\n // Truncate if needed\n const display = line.length > maxWidth ? line.slice(0, maxWidth - 1) + '\\u2026' : line\n\n // Extract timestamp\n const match = display.match(/^\\[(\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?)\\]\\s*(.*)$/)\n if (!match) return `${c.dim}${display}${c.reset}`\n\n const [, ts, rest] = match\n\n // Color by content\n if (rest.includes('Compressed') && rest.includes('tokens saved')) {\n return `${c.dim}${ts}${c.reset} ${c.green}${rest}${c.reset}`\n }\n if (rest.includes('Error') || rest.includes('FAILED')) {\n return `${c.dim}${ts}${c.reset} ${c.red}${rest}${c.reset}`\n }\n if (rest.includes('Skipped')) {\n return `${c.dim}${ts}${c.reset} ${c.yellow}${rest}${c.reset}`\n }\n if (rest.includes('Circuit')) {\n return `${c.dim}${ts}${c.reset} ${c.yellow}${rest}${c.reset}`\n }\n if (rest.includes('[SESSION]') || rest.includes('[DAEMON]')) {\n return `${c.dim}${ts}${c.reset} ${c.cyan}${rest}${c.reset}`\n }\n\n return `${c.dim}${ts} ${rest}${c.reset}`\n}\n","/**\n * Hub — the TUI orchestrator.\n *\n * Launches a persistent full-screen interface with tab-navigable views.\n * Polls the daemon health endpoint and log file for live data.\n * Exits cleanly on 'q' or Ctrl+C, restoring the terminal.\n */\n\nimport { existsSync, readFileSync, statSync } from 'node:fs'\nimport { Screen } from './screen.js'\nimport type { ScreenSize } from './screen.js'\nimport type { KeyPress } from './prompts.js'\nimport { c } from './format.js'\nimport { header, tabBar, statusBar, panel } from './layout.js'\nimport { VERSION, BANNER_LINES } from '../version.js'\nimport { isDaemonRunning } from '../daemon/lifecycle.js'\nimport { loadConfig, isConfigured } from '../config/loader.js'\nimport { maskApiKey } from '../config/loader.js'\nimport { LOG_FILE } from '../config/paths.js'\nimport { CONFIGURABLE_KEYS } from '../config/schema.js'\nimport type { HubState, View } from './views/types.js'\n\n// Views\nimport { dashboardView } from './views/dashboard.js'\nimport { statsView } from './views/stats-view.js'\nimport { configView } from './views/config-view.js'\nimport { logsView } from './views/logs-view.js'\n\n// ─── View registry ──────────────────────────────────────────────────\n\nconst VIEWS: View[] = [dashboardView, statsView, configView, logsView]\n\n// ─── State management ───────────────────────────────────────────────\n\nfunction createInitialState(): HubState {\n const state: HubState = {\n health: null,\n daemonRunning: false,\n port: 3141,\n tools: [],\n lastFetchedAt: 0,\n recentLogs: [],\n configEntries: [],\n }\n\n // Load config\n if (isConfigured()) {\n try {\n const config = loadConfig()\n state.port = config.port\n state.tools = (config.tools ?? []) as string[]\n state.configEntries = buildConfigEntries(config as unknown as Record<string, unknown>)\n } catch { /* use defaults */ }\n }\n\n // Check daemon\n const daemon = isDaemonRunning()\n state.daemonRunning = daemon.running\n state.daemonPid = daemon.pid\n\n return state\n}\n\nfunction buildConfigEntries(config: Record<string, unknown>): [string, string][] {\n const entries: [string, string][] = []\n const display: Record<string, (v: unknown) => string> = {\n apiKey: (v) => maskApiKey(String(v)),\n tools: (v) => Array.isArray(v) ? v.join(', ') : String(v),\n compressRoles: (v) => Array.isArray(v) ? v.join(', ') : String(v),\n }\n\n for (const key of CONFIGURABLE_KEYS) {\n if (key in config) {\n const val = config[key as keyof typeof config]\n const formatter = display[key]\n entries.push([key, formatter ? formatter(val) : String(val)])\n }\n }\n\n return entries\n}\n\nasync function refreshState(state: HubState): Promise<void> {\n // Check daemon\n const daemon = isDaemonRunning()\n state.daemonRunning = daemon.running\n state.daemonPid = daemon.pid\n\n // Fetch health\n if (state.daemonRunning) {\n try {\n const res = await fetch(`http://127.0.0.1:${state.port}/health`, {\n signal: AbortSignal.timeout(2000),\n })\n state.health = await res.json() as HubState['health']\n state.lastFetchedAt = Date.now()\n } catch {\n // Keep stale data\n }\n } else {\n state.health = null\n }\n\n // Tail log file\n state.recentLogs = tailLogFile(100)\n}\n\nfunction tailLogFile(maxLines: number): string[] {\n try {\n if (!existsSync(LOG_FILE)) return []\n const stat = statSync(LOG_FILE)\n // Don't read huge files — read last 32KB\n const readSize = Math.min(stat.size, 32 * 1024)\n if (readSize === 0) return []\n\n const fd = require('node:fs').openSync(LOG_FILE, 'r')\n const buffer = Buffer.alloc(readSize)\n require('node:fs').readSync(fd, buffer, 0, readSize, Math.max(0, stat.size - readSize))\n require('node:fs').closeSync(fd)\n\n const text = buffer.toString('utf-8')\n const lines = text.split('\\n').filter((l: string) => l.trim().length > 0)\n return lines.slice(-maxLines)\n } catch {\n return []\n }\n}\n\n// ─── Hub entry point ────────────────────────────────────────────────\n\nexport async function runHub(): Promise<void> {\n let activeView = 0\n const state = createInitialState()\n\n // Initial data fetch\n await refreshState(state)\n\n const screen = new Screen({\n render(size: ScreenSize): string[] {\n const lines: string[] = []\n const w = size.cols\n\n // Logo banner — centered, cyan\n const bannerWidth = BANNER_LINES[0]?.length ?? 0\n const bannerPad = Math.max(0, Math.floor((w - bannerWidth) / 2))\n const padStr = ' '.repeat(bannerPad)\n for (const bline of BANNER_LINES) {\n lines.push(`${c.cyan}${padStr}${bline}${c.reset}`)\n }\n lines.push(header('', `v${VERSION} \\u2014 Transparent LLM Context Compression`, w))\n lines.push('')\n\n // Tab bar\n const tabs = VIEWS.map((v) => v.label)\n lines.push(tabBar(tabs, activeView, w))\n lines.push('')\n\n // Active view content\n const view = VIEWS[activeView]\n const bannerHeight = BANNER_LINES.length + 2 // banner + subtitle + blank\n const contentHeight = size.rows - bannerHeight - 4 // tabs + blank + status bar + pad\n const content = view.render(state, size)\n\n // Pad content to fill the screen\n while (content.length < contentHeight) {\n content.push('')\n }\n\n // Add content lines (no panel border for cleaner look)\n for (let i = 0; i < contentHeight; i++) {\n lines.push(` ${content[i] ?? ''}`)\n }\n\n // Status bar at the bottom\n const hints: [string, string][] = [\n ['\\u2190\\u2192', 'navigate'],\n ['Tab', 'next'],\n ['1-4', 'jump'],\n ['r', 'refresh'],\n ['q', 'quit'],\n ]\n lines.push(statusBar(hints, w))\n\n return lines\n },\n\n onKey(key: KeyPress, size: ScreenSize): boolean {\n switch (key.type) {\n case 'char':\n if ((key as { type: 'char'; char: string }).char === 'q') return false\n if ((key as { type: 'char'; char: string }).char === 'r') {\n // Manual refresh\n refreshState(state)\n return true\n }\n // Number keys to jump to views\n const num = parseInt((key as { type: 'char'; char: string }).char, 10)\n if (num >= 1 && num <= VIEWS.length) {\n activeView = num - 1\n }\n return true\n\n case 'escape':\n return false\n\n case 'tab':\n case 'right':\n activeView = (activeView + 1) % VIEWS.length\n return true\n\n case 'left':\n activeView = (activeView - 1 + VIEWS.length) % VIEWS.length\n return true\n\n default:\n return true\n }\n },\n\n onResize(size: ScreenSize) {\n // Re-render happens automatically\n },\n\n onExit() {\n // Nothing to clean up — state is ephemeral\n },\n })\n\n // Background refresh loop (separate from screen refresh)\n const refreshInterval = setInterval(() => refreshState(state), 2000)\n if (refreshInterval.unref) refreshInterval.unref()\n\n try {\n await screen.run(1000) // Render refresh every 1s\n } finally {\n clearInterval(refreshInterval)\n }\n}\n","import { VERSION } from './version.js'\nimport { disableColor, c } from './ui/format.js'\nimport { initCommand } from './commands/init.js'\nimport { loginCommand } from './commands/login.js'\nimport { logoutCommand } from './commands/logout.js'\nimport { startCommand } from './commands/start.js'\nimport { stopCommand } from './commands/stop.js'\nimport { statusCommand } from './commands/status.js'\nimport { summaryCommand } from './commands/summary.js'\nimport { configCommand } from './commands/config.js'\nimport { logsCommand } from './commands/logs.js'\nimport { uninstallCommand } from './commands/uninstall.js'\nimport { trustCACommand } from './commands/trust-ca.js'\nimport { untrustCACommand } from './commands/untrust-ca.js'\nimport { setupCursorCommand } from './commands/setup-cursor.js'\nimport { statsCommand } from './commands/stats.js'\nimport { error as fmtError } from './ui/format.js'\n\nfunction usage(): string {\n return `\n ${c.bold}liminal${c.reset} v${VERSION} ${c.dim}\\u2014 Transparent LLM context compression proxy${c.reset}\n\n ${c.bold}Usage:${c.reset}\n liminal init Set up Liminal (login, config)\n liminal login Log in or create an account\n liminal logout Log out of your account\n liminal start [-d] [--port PORT] Start the compression proxy\n liminal stop Stop the running proxy\n liminal status Show proxy health check\n liminal stats [--json] Compression metrics & savings\n liminal config [--set k=v] [--get k] View or edit configuration\n liminal logs [--follow] [--lines N] View proxy logs\n liminal setup cursor [--teardown] Install file compression hooks for Cursor\n liminal trust-ca Install CA cert (for TLS intercept)\n liminal untrust-ca Remove CA cert\n liminal uninstall Remove Liminal configuration\n\n ${c.bold}Options:${c.reset}\n -h, --help Show this help message\n -v, --version Show version number\n --no-color Disable colored output\n\n ${c.bold}Quick start:${c.reset}\n ${c.dim}$${c.reset} liminal init ${c.dim}# Log in + select tools${c.reset}\n ${c.dim}$${c.reset} liminal start ${c.dim}# Start the proxy${c.reset}\n ${c.dim}$${c.reset} liminal stats ${c.dim}# See your compression savings${c.reset}\n`\n}\n\nfunction parseArgs(argv: string[]): { command: string; flags: Map<string, string | true> } {\n const command = argv[2] ?? ''\n const flags = new Map<string, string | true>()\n\n for (let i = 3; i < argv.length; i++) {\n const arg = argv[i]\n if (arg.startsWith('--')) {\n const key = arg.slice(2)\n // Check if next arg is a value (not another flag)\n if (i + 1 < argv.length && !argv[i + 1].startsWith('-')) {\n flags.set(key, argv[i + 1])\n i++\n } else {\n flags.set(key, true)\n }\n } else if (arg.startsWith('-') && arg.length === 2) {\n const key = arg.slice(1)\n if (i + 1 < argv.length && !argv[i + 1].startsWith('-')) {\n flags.set(key, argv[i + 1])\n i++\n } else {\n flags.set(key, true)\n }\n }\n }\n\n // Handle --no-color before anything renders\n if (flags.has('no-color')) {\n disableColor()\n }\n\n return { command, flags }\n}\n\nasync function main(): Promise<void> {\n const { command, flags } = parseArgs(process.argv)\n\n // Global flags — handle --help and --version as both commands and flags\n if (flags.has('h') || flags.has('help') || command === 'help' || command === '--help' || command === '-h') {\n console.log(usage())\n process.exit(0)\n }\n\n if (flags.has('v') || flags.has('version') || command === 'version' || command === '--version' || command === '-v') {\n console.log(VERSION)\n process.exit(0)\n }\n\n try {\n switch (command) {\n case 'init':\n await initCommand()\n break\n\n case 'login':\n await loginCommand()\n break\n\n case 'logout':\n await logoutCommand()\n break\n\n case 'start':\n await startCommand(flags)\n break\n\n case 'stop':\n await stopCommand()\n break\n\n case 'status':\n await statusCommand()\n break\n\n case 'stats':\n await statsCommand(flags)\n break\n\n case 'summary':\n console.log(`\\n ${c.yellow}Note:${c.reset} ${c.dim}liminal summary${c.reset} is deprecated. Use ${c.bold}liminal stats${c.reset} instead.\\n`)\n await statsCommand(flags)\n break\n\n case 'config':\n await configCommand(flags)\n break\n\n case 'logs':\n await logsCommand(flags)\n break\n\n case 'setup': {\n const subcommand = process.argv[3]\n if (subcommand === 'cursor') {\n await setupCursorCommand(flags)\n } else {\n console.error(`Unknown setup target: ${subcommand ?? '(none)'}`)\n console.error('Available: liminal setup cursor')\n process.exit(1)\n }\n break\n }\n\n case 'trust-ca':\n await trustCACommand()\n break\n\n case 'untrust-ca':\n await untrustCACommand()\n break\n\n case 'uninstall':\n await uninstallCommand()\n break\n\n case '': {\n // No command — launch the TUI hub if in a TTY, otherwise show help\n if (process.stdout.isTTY && process.stdin.isTTY) {\n const { runHub } = await import('./ui/hub.js')\n await runHub()\n } else {\n console.log(usage())\n }\n process.exit(0)\n break\n }\n\n default:\n console.error(fmtError(\n `Unknown command: ${command}`,\n `Run ${c.bold}liminal --help${c.reset}${c.dim} to see available commands`,\n ))\n process.exit(1)\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n console.error(fmtError(message))\n process.exit(1)\n }\n}\n\nmain()\n","import { saveConfig, ensureDirectories, loadConfig, isConfigured } from '../config/loader.js'\nimport { DEFAULTS } from '../config/schema.js'\nimport { CONFIG_FILE } from '../config/paths.js'\nimport {\n detectShellProfile,\n appendToShellProfile,\n lineExistsInFile,\n} from '../config/shell.js'\nimport { printBanner } from '../version.js'\nimport { multiSelectPrompt, selectPrompt } from '../ui/prompts.js'\nimport { runAuthFlow } from './login.js'\nimport { CONNECTORS, getConnectors } from '../connectors/index.js'\nimport type { ConnectorId } from '../connectors/types.js'\nimport type { Tool } from '../types.js'\nimport { c, success, warn, info, box, maturityBadge } from '../ui/format.js'\nimport { runWizard } from '../ui/wizard.js'\nimport type { WizardStepDef } from '../ui/wizard.js'\nimport { hasCA, ensureCA } from '../tls/ca.js'\nimport { installCA, isCATrusted } from '../tls/trust.js'\n\n// ─── Wizard context shared across all steps ─────────────────────────\n\ninterface InitContext {\n apiKey: string\n port: number\n selectedIds: ConnectorId[]\n learnFromResponses: boolean\n allShellExports: string[]\n mitmActive: boolean\n}\n\n// ─── Step 1: Authentication ─────────────────────────────────────────\n\nconst authStep: WizardStepDef<InitContext> = {\n title: 'Authentication',\n async execute(ctx) {\n // Check if already authenticated\n try {\n const existing = loadConfig()\n if (existing.apiKey && (existing.apiKey.startsWith('lim_') || existing.apiKey.startsWith('fmcp_'))) {\n console.log(success(`Already authenticated`, `API key on file`))\n ctx.apiKey = existing.apiKey\n return\n }\n } catch { /* no config yet */ }\n\n ctx.apiKey = await runAuthFlow()\n },\n}\n\n// ─── Step 2: Tool Detection & Selection ─────────────────────────────\n\nconst toolDetectionStep: WizardStepDef<InitContext> = {\n title: 'Tool Detection',\n async execute(ctx) {\n console.log(` Scanning for AI development tools...`)\n console.log()\n\n const detectionResults = await Promise.all(\n CONNECTORS.map(async (conn) => {\n const status = await conn.detect()\n return { connector: conn, status }\n }),\n )\n\n for (const { connector, status } of detectionResults) {\n if (status.installed) {\n console.log(success(`${connector.info.label}`, status.detail))\n } else {\n console.log(` ${c.dim}\\u00B7 ${connector.info.label} ${status.detail}${c.reset}`)\n }\n }\n console.log()\n\n // Tool selection\n const toolOptions = CONNECTORS.map((conn) => {\n const detected = detectionResults.find((r) => r.connector.info.id === conn.info.id)\n const installed = detected?.status.installed ?? false\n const badge = maturityBadge(conn.info.maturity)\n\n let description = conn.info.description\n if (!installed) description += ` ${c.dim}(not detected)${c.reset}`\n if (!conn.info.automatable) description += ` ${c.dim}(manual setup)${c.reset}`\n\n return {\n label: conn.info.label + badge,\n value: conn.info.id as ConnectorId,\n description,\n default: conn.info.id === 'claude-code' && installed,\n }\n })\n\n const toolsResult = await multiSelectPrompt<ConnectorId>({\n message: 'Which tools should route through Liminal?',\n options: toolOptions,\n })\n ctx.selectedIds = toolsResult ?? ['claude-code']\n },\n}\n\n// ─── Step 3: Configuration ──────────────────────────────────────────\n\nconst configStep: WizardStepDef<InitContext> = {\n title: 'Configuration',\n async execute(ctx) {\n // Response learning preference\n const learnResult = await selectPrompt<boolean>({\n message: 'Learn from LLM responses to improve compression?',\n options: [\n { label: 'Yes', value: true, description: 'Recommended' },\n { label: 'No', value: false, description: 'Skip response learning' },\n ],\n defaultIndex: 0,\n })\n ctx.learnFromResponses = learnResult ?? true\n\n console.log()\n\n // Save config\n ensureDirectories()\n saveConfig({\n apiKey: ctx.apiKey,\n apiBaseUrl: DEFAULTS.apiBaseUrl,\n upstreamBaseUrl: DEFAULTS.upstreamBaseUrl,\n anthropicUpstreamUrl: DEFAULTS.anthropicUpstreamUrl,\n port: ctx.port,\n learnFromResponses: ctx.learnFromResponses,\n tools: ctx.selectedIds as Tool[],\n compressionThreshold: DEFAULTS.compressionThreshold,\n compressRoles: DEFAULTS.compressRoles,\n latencyBudgetMs: DEFAULTS.latencyBudgetMs,\n enabled: DEFAULTS.enabled,\n })\n\n console.log(success('Configuration saved', CONFIG_FILE))\n console.log()\n\n // Per-connector setup\n const connectors = getConnectors(ctx.selectedIds)\n const profile = detectShellProfile()\n\n console.log(` ${c.bold}Configuring ${connectors.length} tool${connectors.length > 1 ? 's' : ''}...${c.reset}`)\n\n for (const connector of connectors) {\n const result = await connector.setup(ctx.port)\n const protocol = connector.info.protocol === 'anthropic-messages'\n ? 'Anthropic Messages API'\n : connector.info.protocol === 'openai-responses'\n ? 'Responses API'\n : 'Chat Completions API'\n\n console.log()\n console.log(` ${c.cyan}\\u2500\\u2500 ${connector.info.label} ${c.reset}${c.dim}(${protocol})${c.reset}`)\n\n if (connector.info.automatable && result.shellExports.length > 0) {\n for (const line of result.shellExports) {\n console.log(` ${c.green}\\u2713${c.reset} ${line}`)\n }\n ctx.allShellExports.push(...result.shellExports)\n }\n\n // Show setup instructions\n for (const line of result.postSetupInstructions) {\n if (line === '') {\n console.log()\n } else {\n if (line.includes('source your shell profile') || line.includes('restart your terminal')) continue\n if (line.includes('will automatically route through Liminal')) {\n console.log(` ${c.dim}${line}${c.reset}`)\n } else if (line.startsWith(' ')) {\n console.log(` ${line}`)\n } else {\n console.log(` ${line}`)\n }\n }\n }\n\n if (!connector.info.automatable) {\n console.log(` ${warn('Requires manual configuration (see steps above)')}`)\n }\n }\n\n // Auto-install CA for Cursor if selected (task 1.2.7)\n if (ctx.selectedIds.includes('cursor')) {\n console.log()\n console.log(` ${c.cyan}\\u2500\\u2500 CA Certificate ${c.reset}${c.dim}(for TLS interception)${c.reset}`)\n\n if (isCATrusted()) {\n console.log(success('CA already trusted'))\n ctx.mitmActive = true\n } else {\n // Generate CA if needed\n if (!hasCA()) {\n ensureCA()\n console.log(success('CA certificate generated'))\n }\n // Install to system trust store\n const trustResult = installCA()\n if (trustResult.success) {\n console.log(success('CA installed to system trust store'))\n ctx.mitmActive = true\n } else {\n console.log(warn('CA trust failed', trustResult.message))\n if (trustResult.requiresSudo) {\n console.log(` ${c.dim}\\u2192 Run ${c.bold}sudo liminal trust-ca${c.reset}${c.dim} after setup${c.reset}`)\n }\n }\n }\n }\n\n // Shell auto-configuration\n const uniqueExports = [...new Set(ctx.allShellExports)]\n\n if (uniqueExports.length > 0 && profile) {\n const allExist = uniqueExports.every((line) => lineExistsInFile(profile.path, line))\n\n console.log()\n if (allExist) {\n console.log(success(`Shell already configured in ${profile.name}`))\n } else {\n const autoResult = await selectPrompt<boolean>({\n message: `Add proxy exports to ${profile.name}?`,\n options: [\n { label: 'Yes', value: true, description: 'Automatic shell configuration' },\n { label: 'No', value: false, description: \"I'll set it up manually\" },\n ],\n defaultIndex: 0,\n })\n\n if (autoResult === true) {\n const added = appendToShellProfile(profile, uniqueExports)\n if (added.length > 0) {\n console.log()\n console.log(success(`Added to ${profile.name}`))\n }\n } else {\n console.log()\n console.log(' Add these to your shell profile:')\n console.log()\n for (const line of uniqueExports) {\n console.log(` ${c.cyan}${line}${c.reset}`)\n }\n }\n }\n } else if (uniqueExports.length > 0) {\n console.log()\n console.log(' Add these to your shell profile:')\n console.log()\n for (const line of uniqueExports) {\n console.log(` ${c.cyan}${line}${c.reset}`)\n }\n }\n },\n}\n\n// ─── Step 4: Verification ───────────────────────────────────────────\n\nconst verificationStep: WizardStepDef<InitContext> = {\n title: 'Verification',\n skippable: true,\n async execute(ctx) {\n console.log(` Running health checks...`)\n console.log()\n\n // Check 1: Cognisos API reachable\n const { RSCPipelineWrapper } = await import('../rsc/pipeline.js')\n const config = loadConfig()\n const probe = new RSCPipelineWrapper({\n rscApiKey: config.apiKey,\n rscBaseUrl: config.apiBaseUrl,\n compressionThreshold: config.compressionThreshold,\n learnFromResponses: false,\n })\n\n const apiHealthy = await probe.healthCheck()\n if (apiHealthy) {\n console.log(success('Cognisos API reachable', config.apiBaseUrl))\n } else {\n console.log(warn('Cognisos API unreachable', 'compression will retry on first request'))\n }\n\n // Check 2: Port available (quick bind test)\n const portFree = await checkPort(ctx.port)\n if (portFree) {\n console.log(success(`Port ${ctx.port} available`))\n } else {\n console.log(warn(`Port ${ctx.port} in use`, 'the proxy will claim it on start'))\n }\n\n // Check 3: Connector routing readiness\n for (const id of ctx.selectedIds) {\n const connector = getConnectors([id])[0]\n const status = await connector.detect()\n if (status.installed) {\n const routeMethod = connector.info.id === 'cursor' ? 'hooks' : 'env var'\n console.log(success(`${connector.info.label} routing ready`, `via ${routeMethod}`))\n } else {\n console.log(warn(`${connector.info.label}`, 'not detected — install to use'))\n }\n }\n\n // Check 4: MITM status for Cursor\n if (ctx.selectedIds.includes('cursor') && ctx.mitmActive) {\n console.log(success('MITM bridge ready', 'CA trusted'))\n }\n },\n}\n\n// ─── Step 5: Ready ──────────────────────────────────────────────────\n\nconst readyStep: WizardStepDef<InitContext> = {\n title: 'Ready!',\n async execute(ctx) {\n console.log(` Liminal is fully configured and verified.`)\n console.log()\n\n // Build summary rows\n const toolLabels = getConnectors(ctx.selectedIds).map((cn) => cn.info.label).join(', ')\n const rows: [string, string][] = [\n [`${c.bold}Tools:${c.reset}`, toolLabels],\n [`${c.bold}Proxy:${c.reset}`, `http://127.0.0.1:${ctx.port}`],\n ]\n\n if (ctx.selectedIds.includes('cursor')) {\n rows.push([`${c.bold}MITM:${c.reset}`, ctx.mitmActive ? `${c.green}active${c.reset} (CA trusted)` : `${c.dim}inactive${c.reset}`])\n }\n\n rows.push(\n [`${c.bold}Learning:${c.reset}`, ctx.learnFromResponses ? 'enabled' : 'disabled'],\n [`${c.bold}Config:${c.reset}`, CONFIG_FILE],\n )\n\n console.log(box(rows))\n console.log()\n console.log(` Next: ${c.bold}liminal start${c.reset}`)\n },\n}\n\n// ─── Main command ───────────────────────────────────────────────────\n\nexport async function initCommand(): Promise<void> {\n printBanner()\n console.log(` ${c.bold}Welcome to Liminal${c.reset} ${c.dim}\\u2014 Transparent LLM Context Compression${c.reset}`)\n\n const ctx: InitContext = {\n apiKey: '',\n port: DEFAULTS.port,\n selectedIds: [],\n learnFromResponses: true,\n allShellExports: [],\n mitmActive: false,\n }\n\n const steps: WizardStepDef<InitContext>[] = [\n authStep,\n toolDetectionStep,\n configStep,\n verificationStep,\n readyStep,\n ]\n\n const result = await runWizard(steps, ctx)\n\n if (!result.completed) {\n console.log()\n console.log(` ${c.dim}Setup incomplete. Run ${c.bold}liminal init${c.reset}${c.dim} to try again.${c.reset}`)\n console.log()\n process.exit(1)\n }\n\n console.log()\n}\n\n// ─── Utilities ──────────────────────────────────────────────────────\n\n/** Quick check if a TCP port is free. */\nasync function checkPort(port: number): Promise<boolean> {\n const { createServer } = await import('node:net')\n return new Promise((resolve) => {\n const server = createServer()\n server.once('error', () => resolve(false))\n server.once('listening', () => {\n server.close(() => resolve(true))\n })\n server.listen(port, '127.0.0.1')\n })\n}\n","/**\n * Shell profile detection and modification utilities.\n * Shared by init (append exports) and uninstall (remove exports).\n */\n\nimport { existsSync, readFileSync, writeFileSync, appendFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { homedir } from 'node:os'\n\nexport interface ShellProfile {\n name: string\n path: string\n}\n\nconst LIMINAL_BLOCK_HEADER = '# Liminal — route AI tools through compression proxy'\n\n/**\n * Detect the user's shell profile file.\n */\nexport function detectShellProfile(): ShellProfile | null {\n const shell = process.env.SHELL || ''\n const home = homedir()\n\n if (shell.endsWith('/zsh')) {\n return { name: '~/.zshrc', path: join(home, '.zshrc') }\n }\n\n if (shell.endsWith('/bash')) {\n const bashProfile = join(home, '.bash_profile')\n if (existsSync(bashProfile)) {\n return { name: '~/.bash_profile', path: bashProfile }\n }\n return { name: '~/.bashrc', path: join(home, '.bashrc') }\n }\n\n const candidates: ShellProfile[] = [\n { name: '~/.zshrc', path: join(home, '.zshrc') },\n { name: '~/.bashrc', path: join(home, '.bashrc') },\n { name: '~/.profile', path: join(home, '.profile') },\n ]\n\n for (const c of candidates) {\n if (existsSync(c.path)) return c\n }\n\n return null\n}\n\n/**\n * Check if a line already exists in a file.\n */\nexport function lineExistsInFile(filePath: string, line: string): boolean {\n if (!existsSync(filePath)) return false\n try {\n const content = readFileSync(filePath, 'utf-8')\n return content.includes(line)\n } catch {\n return false\n }\n}\n\n/**\n * Append export lines to shell profile with a Liminal comment header.\n * Only appends lines that don't already exist.\n */\nexport function appendToShellProfile(profile: ShellProfile, lines: string[]): string[] {\n const newLines = lines.filter((line) => !lineExistsInFile(profile.path, line))\n if (newLines.length === 0) return []\n\n const block = [\n '',\n LIMINAL_BLOCK_HEADER,\n ...newLines,\n ].join('\\n') + '\\n'\n\n appendFileSync(profile.path, block, 'utf-8')\n return newLines\n}\n\n/**\n * Remove all Liminal-related lines from a shell profile.\n * Removes the header comment and any export lines containing Liminal proxy URLs.\n * Returns the lines that were removed.\n */\nexport function removeLiminalFromShellProfile(profile: ShellProfile): string[] {\n if (!existsSync(profile.path)) return []\n\n let content: string\n try {\n content = readFileSync(profile.path, 'utf-8')\n } catch {\n return []\n }\n\n const lines = content.split('\\n')\n const removed: string[] = []\n const kept: string[] = []\n\n for (const line of lines) {\n if (line.trim() === LIMINAL_BLOCK_HEADER) {\n removed.push(line)\n continue\n }\n\n // Match Liminal proxy export lines:\n // export ANTHROPIC_BASE_URL=http://127.0.0.1:XXXX\n // export OPENAI_BASE_URL=http://127.0.0.1:XXXX/v1\n if (isLiminalExportLine(line)) {\n removed.push(line)\n continue\n }\n\n kept.push(line)\n }\n\n if (removed.length > 0) {\n // Clean up consecutive blank lines left by removal\n const cleaned = kept.join('\\n').replace(/\\n{3,}/g, '\\n\\n')\n writeFileSync(profile.path, cleaned, 'utf-8')\n }\n\n return removed\n}\n\n/**\n * Check if a line is a Liminal proxy export.\n */\nfunction isLiminalExportLine(line: string): boolean {\n const trimmed = line.trim()\n if (!trimmed.startsWith('export ')) return false\n // Match export ANTHROPIC_BASE_URL=http://127.0.0.1:XXXX or similar\n if (trimmed.includes('ANTHROPIC_BASE_URL=http://127.0.0.1:')) return true\n if (trimmed.includes('OPENAI_BASE_URL=http://127.0.0.1:')) return true\n return false\n}\n\n/**\n * Find all Liminal export lines currently in a shell profile.\n */\nexport function findLiminalExportsInProfile(profile: ShellProfile): string[] {\n if (!existsSync(profile.path)) return []\n try {\n const content = readFileSync(profile.path, 'utf-8')\n return content.split('\\n').filter(isLiminalExportLine)\n } catch {\n return []\n }\n}\n","import { createInterface } from 'node:readline/promises'\nimport { stdin, stdout } from 'node:process'\nimport { signIn, signUp, authenticateAndGetKey } from '../auth/supabase.js'\nimport { saveConfig, ensureDirectories, loadConfig } from '../config/loader.js'\nimport { DEFAULTS } from '../config/schema.js'\nimport { printBanner } from '../version.js'\nimport { selectPrompt, passwordPrompt } from '../ui/prompts.js'\nimport { c, success, error as fmtError } from '../ui/format.js'\nimport type { AuthError } from '../auth/supabase.js'\n\nexport async function loginCommand(): Promise<void> {\n printBanner()\n\n // Check if already logged in\n try {\n const config = loadConfig()\n if (config.apiKey && (config.apiKey.startsWith('lim_') || config.apiKey.startsWith('fmcp_'))) {\n console.log(success('Already logged in'))\n console.log(` ${c.dim}\\u2192 Run ${c.bold}liminal logout${c.reset}${c.dim} first to switch accounts${c.reset}`)\n return\n }\n } catch {\n // No config yet — proceed with login\n }\n\n await runAuthFlow()\n}\n\n/**\n * Shared auth flow used by both `liminal login` and `liminal init`.\n * Returns the API key on success.\n */\nexport async function runAuthFlow(): Promise<string> {\n const modeResult = await selectPrompt<'login' | 'signup'>({\n message: 'Welcome to Liminal',\n options: [\n { label: 'Log in', value: 'login', description: 'I have an account' },\n { label: 'Create account', value: 'signup', description: 'New to Liminal' },\n ],\n defaultIndex: 0,\n })\n const mode = modeResult ?? 'login'\n\n console.log()\n\n // Collect credentials\n const rl = createInterface({ input: stdin, output: stdout })\n let name = ''\n let email: string\n\n try {\n if (mode === 'signup') {\n name = (await rl.question(` ${c.bold}Name${c.reset}: `)).trim()\n if (!name) {\n console.error('\\n' + fmtError('Name is required'))\n process.exit(1)\n }\n }\n\n email = (await rl.question(` ${c.bold}Email${c.reset}: `)).trim()\n if (!email) {\n console.error('\\n' + fmtError('Email is required'))\n process.exit(1)\n }\n } finally {\n rl.close()\n }\n\n // Password (masked)\n const password = await passwordPrompt({ message: 'Password' })\n if (!password) {\n console.error('\\n' + fmtError('Password is required'))\n process.exit(1)\n }\n\n console.log()\n\n // Authenticate\n const action = mode === 'signup' ? 'Creating account' : 'Logging in'\n process.stdout.write(` ${action}... `)\n\n try {\n const auth = mode === 'signup'\n ? await signUp(email, password, name)\n : await signIn(email, password)\n\n console.log('OK')\n\n // Fetch or create API key\n process.stdout.write(' Setting up API key... ')\n const apiKey = await authenticateAndGetKey(auth)\n console.log('OK')\n\n // Save to config\n ensureDirectories()\n saveConfig({\n apiKey,\n apiBaseUrl: DEFAULTS.apiBaseUrl,\n })\n\n console.log()\n console.log(success(`Authenticated as ${c.bold}${auth.email}${c.reset}`))\n console.log(success('API key stored securely'))\n\n return apiKey\n } catch (err) {\n console.log('FAILED')\n const authErr = err as AuthError\n const msg = authErr.message ?? String(err)\n\n if (mode === 'login' && msg.includes('Invalid login')) {\n console.error('\\n' + fmtError(msg, 'Check your email and password, then try again'))\n } else {\n console.error('\\n' + fmtError(msg))\n }\n\n process.exit(1)\n }\n}\n","/**\n * Lightweight Supabase Auth client using fetch — zero npm dependencies.\n * Uses the public anon key (same as web frontend).\n */\nimport { randomBytes, createHash } from 'node:crypto'\n\nconst SUPABASE_URL = 'https://nzcneiyymvgxvttbenhp.supabase.co'\nconst SUPABASE_ANON_KEY =\n 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im56Y25laXl5bXZneHZ0dGJlbmhwIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQwNjQ0MjcsImV4cCI6MjA2OTY0MDQyN30.x3E-zGRadbPMmxRqT_PB_KOi00htKpgeb8GiQa4g2z0'\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface AuthResult {\n accessToken: string\n userId: string\n email: string\n}\n\nexport interface AuthError {\n message: string\n status?: number\n}\n\n// ─── Auth ────────────────────────────────────────────────────────────\n\nfunction supabaseHeaders(accessToken?: string): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'apikey': SUPABASE_ANON_KEY,\n }\n if (accessToken) {\n headers['Authorization'] = `Bearer ${accessToken}`\n }\n return headers\n}\n\n/**\n * Sign in with email and password.\n */\nexport async function signIn(email: string, password: string): Promise<AuthResult> {\n const res = await fetch(`${SUPABASE_URL}/auth/v1/token?grant_type=password`, {\n method: 'POST',\n headers: supabaseHeaders(),\n body: JSON.stringify({ email, password }),\n signal: AbortSignal.timeout(15_000),\n }).catch((err) => {\n if (err?.name === 'TimeoutError') {\n throw { message: 'Login timed out — Supabase auth may be unavailable. Try again shortly.' } as AuthError\n }\n throw { message: `Network error: ${err?.message ?? 'unknown'}` } as AuthError\n })\n\n const body = (await res.json()) as Record<string, any>\n\n if (!res.ok) {\n const msg = body?.error_description || body?.error || body?.msg || 'Authentication failed'\n const err: AuthError = { message: msg, status: res.status }\n throw err\n }\n\n return {\n accessToken: body.access_token,\n userId: body.user?.id,\n email: body.user?.email ?? email,\n }\n}\n\n/**\n * Sign up with email, password, and name.\n */\nexport async function signUp(\n email: string,\n password: string,\n name: string,\n): Promise<AuthResult> {\n const res = await fetch(`${SUPABASE_URL}/auth/v1/signup`, {\n method: 'POST',\n headers: supabaseHeaders(),\n body: JSON.stringify({\n email,\n password,\n data: { name },\n }),\n signal: AbortSignal.timeout(15_000),\n }).catch((err) => {\n if (err?.name === 'TimeoutError') {\n throw { message: 'Sign up timed out — Supabase auth may be unavailable. Try again shortly.' } as AuthError\n }\n throw { message: `Network error: ${err?.message ?? 'unknown'}` } as AuthError\n })\n\n const body = (await res.json()) as Record<string, any>\n\n if (!res.ok) {\n const msg = body?.error_description || body?.error || body?.msg || 'Sign up failed'\n const err: AuthError = { message: msg, status: res.status }\n throw err\n }\n\n // Supabase may return identities: [] if email confirmation is required\n if (body.user?.identities?.length === 0) {\n const err: AuthError = { message: 'Account already exists. Try logging in instead.' }\n throw err\n }\n\n return {\n accessToken: body.access_token,\n userId: body.user?.id,\n email: body.user?.email ?? email,\n }\n}\n\n// ─── API Key Management ──────────────────────────────────────────────\n\n/**\n * Check if the user already has an active API key.\n * Since only key_hash is stored (not plaintext), we can only check existence.\n */\nexport async function hasExistingKey(accessToken: string, userId: string): Promise<boolean> {\n const params = new URLSearchParams({\n user_id: `eq.${userId}`,\n is_active: 'eq.true',\n select: 'id',\n limit: '1',\n })\n\n const res = await fetch(`${SUPABASE_URL}/rest/v1/user_api_keys?${params}`, {\n headers: supabaseHeaders(accessToken),\n signal: AbortSignal.timeout(10_000),\n })\n\n if (!res.ok) return false\n\n const rows = await res.json()\n return Array.isArray(rows) && rows.length > 0\n}\n\n/**\n * Known key sources — each gets its own independent key_name slot so\n * rotating one never invalidates the other.\n */\nexport type KeySource = 'cli' | 'mcp'\n\nconst KEY_SOURCE_META: Record<KeySource, { prefix: string; keyName: string }> = {\n cli: { prefix: 'lim_', keyName: 'Liminal CLI' },\n mcp: { prefix: 'fmcp_', keyName: 'Fabric MCP' },\n}\n\n/**\n * Generate a new API key, store its SHA-256 hash in the database,\n * and return the plaintext key (only shown once).\n *\n * Only replaces the key for the given `source` — other sources are untouched.\n */\nexport async function createApiKey(\n accessToken: string,\n userId: string,\n source: KeySource = 'cli',\n): Promise<string> {\n const { prefix, keyName } = KEY_SOURCE_META[source]\n\n // Delete only keys with this key_name (scoped rotation, leaves other sources intact)\n await fetch(\n `${SUPABASE_URL}/rest/v1/user_api_keys?user_id=eq.${userId}&key_name=eq.${encodeURIComponent(keyName)}`,\n {\n method: 'DELETE',\n headers: supabaseHeaders(accessToken),\n signal: AbortSignal.timeout(10_000),\n },\n )\n\n const apiKey = `${prefix}${randomBytes(32).toString('hex')}`\n const keyHash = createHash('sha256').update(apiKey).digest('hex')\n\n // Look up user's project and org (project.id = user_id by convention)\n let projectId: string | undefined\n let orgId: string | undefined\n try {\n const projRes = await fetch(\n `${SUPABASE_URL}/rest/v1/projects?id=eq.${userId}&select=id,org_id&limit=1`,\n { headers: supabaseHeaders(accessToken), signal: AbortSignal.timeout(10_000) },\n )\n if (projRes.ok) {\n const rows = await projRes.json()\n if (Array.isArray(rows) && rows.length > 0) {\n projectId = rows[0].id\n orgId = rows[0].org_id\n }\n }\n } catch {\n // Non-fatal — key will work without project_id (backwards compat)\n }\n\n const insertPayload: Record<string, unknown> = {\n user_id: userId,\n key_name: keyName,\n key_hash: keyHash,\n is_active: true,\n }\n if (projectId) insertPayload.project_id = projectId\n if (orgId) insertPayload.organization_id = orgId\n\n const res = await fetch(`${SUPABASE_URL}/rest/v1/user_api_keys`, {\n method: 'POST',\n headers: {\n ...supabaseHeaders(accessToken),\n 'Prefer': 'return=representation',\n },\n body: JSON.stringify(insertPayload),\n })\n\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as Record<string, any>\n const msg = body?.message || body?.error || 'Failed to create API key'\n throw { message: msg, status: res.status } as AuthError\n }\n\n return apiKey\n}\n\n/**\n * Full login flow: authenticate then create API key.\n * Since only hashes are stored, we always generate a fresh key.\n * The plaintext is saved locally in ~/.liminal/config.json.\n */\nexport async function authenticateAndGetKey(\n auth: AuthResult,\n source: KeySource = 'cli',\n): Promise<string> {\n return createApiKey(auth.accessToken, auth.userId, source)\n}\n","/**\n * Claude Code connector.\n *\n * Claude Code reads the ANTHROPIC_BASE_URL environment variable to determine\n * where to send API requests. Setting this to Liminal's proxy address routes\n * all traffic through the compression pipeline.\n *\n * Protocol: Anthropic Messages API (POST /v1/messages)\n * Auth: x-api-key header (user's Anthropic API key)\n * Setup: Shell profile export — fully automatic\n */\n\nimport { execSync } from 'node:child_process'\nimport type { Connector, ConnectorInfo, ConnectorStatus, SetupResult, TeardownResult } from './types.js'\n\nconst ENV_VAR = 'ANTHROPIC_BASE_URL'\n\nconst INFO: ConnectorInfo = {\n id: 'claude-code',\n label: 'Claude Code',\n description: 'Anthropic CLI for coding with Claude',\n protocol: 'anthropic-messages',\n automatable: true,\n}\n\nfunction isClaudeInstalled(): boolean {\n try {\n execSync('which claude', { stdio: 'ignore' })\n return true\n } catch {\n return false\n }\n}\n\nfunction getCurrentBaseUrl(): string | undefined {\n return process.env[ENV_VAR] || undefined\n}\n\nexport const claudeCodeConnector: Connector = {\n info: INFO,\n\n async detect(): Promise<ConnectorStatus> {\n const installed = isClaudeInstalled()\n const currentUrl = getCurrentBaseUrl()\n const configured = currentUrl?.includes('127.0.0.1') ?? false\n\n if (!installed) {\n return { installed, configured: false, detail: 'Claude Code not found in PATH' }\n }\n\n if (configured) {\n return { installed, configured, detail: `Routing through ${currentUrl}` }\n }\n\n return { installed, configured, detail: 'Installed but not routing through Liminal' }\n },\n\n getShellExports(port: number): string[] {\n return [`export ${ENV_VAR}=http://127.0.0.1:${port}`]\n },\n\n async setup(port: number): Promise<SetupResult> {\n const exports = this.getShellExports(port)\n\n return {\n success: true,\n shellExports: exports,\n postSetupInstructions: [\n 'Claude Code will automatically route through Liminal.',\n 'Make sure to source your shell profile or restart your terminal.',\n ],\n }\n },\n\n async teardown(): Promise<TeardownResult> {\n return {\n success: true,\n manualSteps: [\n `Remove the line \\`export ${ENV_VAR}=...\\` from your shell profile (~/.zshrc or ~/.bashrc).`,\n 'Restart your terminal or run: unset ANTHROPIC_BASE_URL',\n ],\n }\n },\n}\n","/**\n * OpenAI Codex CLI connector.\n *\n * Codex CLI reads OPENAI_BASE_URL to override its API endpoint. It can also\n * be configured via ~/.codex/config.toml with a custom provider block.\n *\n * Protocol: OpenAI Responses API (POST /v1/responses) — this is the default\n * wire format. Chat completions is a secondary option via config.toml\n * (wire_api = \"chat_completions\") but Responses API is primary.\n * Auth: Authorization: Bearer header (user's OpenAI API key)\n * Setup: Shell profile export — fully automatic. Optional TOML config\n * for advanced users who want a named provider.\n */\n\nimport { execSync } from 'node:child_process'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { homedir } from 'node:os'\nimport type { Connector, ConnectorInfo, ConnectorStatus, SetupResult, TeardownResult } from './types.js'\n\nconst ENV_VAR = 'OPENAI_BASE_URL'\nconst CODEX_CONFIG_DIR = join(homedir(), '.codex')\nconst CODEX_CONFIG_FILE = join(CODEX_CONFIG_DIR, 'config.toml')\n\nconst INFO: ConnectorInfo = {\n id: 'codex',\n label: 'Codex CLI',\n description: 'OpenAI CLI agent for coding (Responses API)',\n protocol: 'openai-responses',\n automatable: true,\n maturity: 'preview',\n}\n\nfunction isCodexInstalled(): boolean {\n try {\n execSync('which codex', { stdio: 'ignore' })\n return true\n } catch {\n return false\n }\n}\n\nfunction getCurrentBaseUrl(): string | undefined {\n return process.env[ENV_VAR] || undefined\n}\n\nfunction hasCodexConfig(): boolean {\n return existsSync(CODEX_CONFIG_FILE)\n}\n\nfunction codexConfigMentionsLiminal(): boolean {\n if (!hasCodexConfig()) return false\n try {\n const content = readFileSync(CODEX_CONFIG_FILE, 'utf-8')\n return content.includes('127.0.0.1') || content.includes('liminal')\n } catch {\n return false\n }\n}\n\nexport const codexConnector: Connector = {\n info: INFO,\n\n async detect(): Promise<ConnectorStatus> {\n const installed = isCodexInstalled()\n const currentUrl = getCurrentBaseUrl()\n const envConfigured = currentUrl?.includes('127.0.0.1') ?? false\n const tomlConfigured = codexConfigMentionsLiminal()\n const configured = envConfigured || tomlConfigured\n\n if (!installed) {\n return { installed, configured: false, detail: 'Codex CLI not found in PATH' }\n }\n\n if (configured) {\n const via = envConfigured ? ENV_VAR : 'config.toml'\n return { installed, configured, detail: `Routing through Liminal (via ${via})` }\n }\n\n return { installed, configured, detail: 'Installed but not routing through Liminal' }\n },\n\n getShellExports(port: number): string[] {\n // Codex expects base_url to include /v1\n return [`export ${ENV_VAR}=http://127.0.0.1:${port}/v1`]\n },\n\n async setup(port: number): Promise<SetupResult> {\n const exports = this.getShellExports(port)\n\n const instructions = [\n 'Codex routing is functional. Advanced compression',\n 'features for Codex are in active development.',\n '',\n 'Codex uses the OpenAI Responses API (/v1/responses) by default.',\n ]\n\n return {\n success: true,\n shellExports: exports,\n postSetupInstructions: instructions,\n }\n },\n\n async teardown(): Promise<TeardownResult> {\n const steps = [\n `Remove the line \\`export ${ENV_VAR}=...\\` from your shell profile (~/.zshrc or ~/.bashrc).`,\n 'Restart your terminal or run: unset OPENAI_BASE_URL',\n ]\n\n if (codexConfigMentionsLiminal()) {\n steps.push(\n `Remove the Liminal provider block from ${CODEX_CONFIG_FILE}.`,\n )\n }\n\n return { success: true, manualSteps: steps }\n },\n}\n","/**\n * Cursor IDE connector.\n *\n * Uses Cursor's preToolUse hooks to intercept file reads and serve\n * RSC-compressed content transparently. No network interception needed.\n *\n * How it works:\n * 1. `liminal setup cursor` installs a hook script + hooks.json\n * 2. When Cursor's agent reads a file, the hook fires\n * 3. The hook compresses via RSC API, caches in .fabric/cache/\n * 4. Returns updated_input to redirect the read to the cached file\n * 5. Agent sees compressed content — transparently\n *\n * No sudo, no TLS certs, no DNS manipulation, no kernel hacks.\n * Cross-platform (macOS, Linux, Windows).\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { homedir } from 'node:os'\nimport type { Connector, ConnectorInfo, ConnectorStatus, SetupResult, TeardownResult } from './types.js'\n\nconst INFO: ConnectorInfo = {\n id: 'cursor',\n label: 'Cursor',\n description: 'AI-first code editor (file compression hooks)',\n protocol: 'openai-chat',\n automatable: true,\n}\n\n/** Platform-specific Cursor app paths */\nfunction getCursorPaths(): { app: string; data: string } {\n const platform = process.platform\n const home = homedir()\n\n if (platform === 'darwin') {\n return {\n app: '/Applications/Cursor.app',\n data: join(home, 'Library', 'Application Support', 'Cursor'),\n }\n }\n\n if (platform === 'win32') {\n const appData = process.env.APPDATA || join(home, 'AppData', 'Roaming')\n const localAppData = process.env.LOCALAPPDATA || join(home, 'AppData', 'Local')\n return {\n app: join(localAppData, 'Programs', 'Cursor', 'Cursor.exe'),\n data: join(appData, 'Cursor'),\n }\n }\n\n // Linux\n return {\n app: '/usr/bin/cursor',\n data: join(home, '.config', 'Cursor'),\n }\n}\n\nfunction isCursorInstalled(): boolean {\n const { app, data } = getCursorPaths()\n return existsSync(app) || existsSync(data)\n}\n\n/** Check if our hook is installed in the current workspace. */\nfunction isHookInstalled(): boolean {\n try {\n const hooksPath = join(process.cwd(), '.cursor', 'hooks.json')\n if (!existsSync(hooksPath)) return false\n const data = JSON.parse(readFileSync(hooksPath, 'utf-8'))\n const entries = data?.hooks?.preToolUse ?? []\n return entries.some((e: { command?: string }) => e.command?.includes('fabric-compress'))\n } catch {\n return false\n }\n}\n\nexport const cursorConnector: Connector = {\n info: INFO,\n\n async detect(): Promise<ConnectorStatus> {\n const installed = isCursorInstalled()\n\n if (!installed) {\n return { installed, configured: false, detail: 'Cursor not found on this system' }\n }\n\n const hookActive = isHookInstalled()\n if (hookActive) {\n return {\n installed,\n configured: true,\n detail: 'Installed — compression hooks active',\n }\n }\n\n return {\n installed,\n configured: false,\n detail: 'Installed — run \"liminal setup cursor\" to install compression hooks',\n }\n },\n\n getShellExports(_port: number): string[] {\n // Hooks don't use env vars\n return []\n },\n\n async setup(_port: number): Promise<SetupResult> {\n return {\n success: true,\n shellExports: [],\n postSetupInstructions: [\n 'Run the setup in your project directory:',\n '',\n ' cd <your-project>',\n ' liminal setup cursor',\n '',\n 'This installs a preToolUse hook that compresses files',\n 'the agent reads, transparently via RSC normalization.',\n '',\n 'Then reload Cursor to activate the hooks.',\n 'No sudo or special flags needed.',\n ],\n }\n },\n\n async teardown(): Promise<TeardownResult> {\n return {\n success: true,\n manualSteps: [\n 'Remove the compression hooks:',\n ' cd <your-project>',\n ' liminal setup cursor --teardown',\n '',\n 'Then reload Cursor to deactivate.',\n ],\n }\n },\n}\n","/**\n * Generic OpenAI-compatible connector.\n *\n * Catch-all for any tool that speaks the OpenAI API format and reads\n * OPENAI_BASE_URL or OPENAI_API_BASE. This covers tools like:\n * - Aider, Continue, Cline, Copilot alternatives\n * - Custom scripts using the OpenAI SDK\n * - Any tool that respects OPENAI_BASE_URL\n *\n * Protocol: OpenAI Chat Completions (POST /v1/chat/completions)\n * Auth: Authorization: Bearer header\n * Setup: Shell profile export — fully automatic\n */\n\nimport type { Connector, ConnectorInfo, ConnectorStatus, SetupResult, TeardownResult } from './types.js'\n\nconst ENV_VAR = 'OPENAI_BASE_URL'\n\nconst INFO: ConnectorInfo = {\n id: 'openai-compatible',\n label: 'Other / OpenAI-compatible',\n description: 'Any tool that reads OPENAI_BASE_URL',\n protocol: 'openai-chat',\n automatable: true,\n}\n\nfunction getCurrentBaseUrl(): string | undefined {\n return process.env[ENV_VAR] || undefined\n}\n\nexport const openaiCompatibleConnector: Connector = {\n info: INFO,\n\n async detect(): Promise<ConnectorStatus> {\n const currentUrl = getCurrentBaseUrl()\n const configured = currentUrl?.includes('127.0.0.1') ?? false\n\n return {\n installed: true, // Generic — always \"available\"\n configured,\n detail: configured\n ? `OPENAI_BASE_URL → ${currentUrl}`\n : 'OPENAI_BASE_URL not set to Liminal',\n }\n },\n\n getShellExports(port: number): string[] {\n return [`export ${ENV_VAR}=http://127.0.0.1:${port}/v1`]\n },\n\n async setup(port: number): Promise<SetupResult> {\n const exports = this.getShellExports(port)\n\n return {\n success: true,\n shellExports: exports,\n postSetupInstructions: [\n 'Any tool that reads OPENAI_BASE_URL will route through Liminal.',\n 'Make sure to source your shell profile or restart your terminal.',\n '',\n 'If your tool uses a different env var (e.g., OPENAI_API_BASE),',\n `set it to: http://127.0.0.1:${port}/v1`,\n ],\n }\n },\n\n async teardown(): Promise<TeardownResult> {\n return {\n success: true,\n manualSteps: [\n `Remove the line \\`export ${ENV_VAR}=...\\` from your shell profile (~/.zshrc or ~/.bashrc).`,\n 'Restart your terminal or run: unset OPENAI_BASE_URL',\n ],\n }\n },\n}\n","/**\n * Connector registry — maps tool IDs to their connector implementations.\n */\n\nimport { claudeCodeConnector } from './claude-code.js'\nimport { codexConnector } from './codex.js'\nimport { cursorConnector } from './cursor.js'\nimport { openaiCompatibleConnector } from './openai-compatible.js'\nimport type { Connector, ConnectorId } from './types.js'\n\n/** All registered connectors in display order */\nexport const CONNECTORS: readonly Connector[] = [\n claudeCodeConnector,\n codexConnector,\n cursorConnector,\n openaiCompatibleConnector,\n]\n\n/** Lookup a connector by its tool ID */\nexport function getConnector(id: ConnectorId): Connector {\n const connector = CONNECTORS.find((c) => c.info.id === id)\n if (!connector) {\n throw new Error(`Unknown connector: ${id}`)\n }\n return connector\n}\n\n/** Get connectors for a list of tool IDs */\nexport function getConnectors(ids: ConnectorId[]): Connector[] {\n return ids.map(getConnector)\n}\n\n/** Detect which tools are installed on this system */\nexport async function detectInstalledTools(): Promise<Map<ConnectorId, Connector>> {\n const results = await Promise.all(\n CONNECTORS.map(async (c) => {\n const status = await c.detect()\n return { connector: c, status }\n }),\n )\n\n const installed = new Map<ConnectorId, Connector>()\n for (const { connector, status } of results) {\n if (status.installed) {\n installed.set(connector.info.id, connector)\n }\n }\n\n return installed\n}\n\n// Re-export types for convenience\nexport type { Connector, ConnectorId, ConnectorInfo, ConnectorStatus, SetupResult, TeardownResult } from './types.js'\n","/**\n * Wizard step abstraction for multi-step CLI flows.\n *\n * Provides a generic step runner with:\n * - Numbered step headers (━━━ Step N of M • Title ━━━)\n * - Per-step try/catch with retry / skip / abort recovery\n * - Success/failure display per step\n * - Final summary tracking\n */\n\nimport { c, stepHeader, error as fmtError } from './format.js'\nimport { selectPrompt } from './prompts.js'\n\n// ─── Types ──────────────────────────────────────────────────────────\n\nexport interface WizardStepDef<TCtx> {\n /** Short title shown in the step header */\n title: string\n /** Whether this step can be skipped on failure (default: false) */\n skippable?: boolean\n /**\n * Execute the step logic.\n * May mutate ctx to pass data to later steps.\n * Throw to signal failure.\n */\n execute: (ctx: TCtx) => Promise<void>\n}\n\nexport type StepOutcome = 'passed' | 'failed' | 'skipped'\n\nexport interface StepResult {\n title: string\n outcome: StepOutcome\n error?: string\n}\n\nexport interface WizardResult {\n completed: boolean\n steps: StepResult[]\n}\n\n// ─── Runner ─────────────────────────────────────────────────────────\n\n/**\n * Run a series of wizard steps with progress headers and error recovery.\n *\n * @param steps Ordered step definitions\n * @param ctx Shared mutable context object passed to every step\n * @returns WizardResult summarizing outcomes\n */\nexport async function runWizard<TCtx>(\n steps: WizardStepDef<TCtx>[],\n ctx: TCtx,\n): Promise<WizardResult> {\n const results: StepResult[] = []\n const total = steps.length\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n const stepNum = i + 1\n\n // Print step header\n console.log(stepHeader(stepNum, total, step.title))\n console.log()\n\n let outcome: StepOutcome = 'passed'\n let errorMsg: string | undefined\n\n // Retry loop for this step\n let shouldRetry = true\n while (shouldRetry) {\n shouldRetry = false\n try {\n await step.execute(ctx)\n outcome = 'passed'\n } catch (err) {\n errorMsg = err instanceof Error ? err.message : String(err)\n console.log()\n console.log(fmtError(errorMsg))\n\n // Offer recovery options\n const recovery = await promptRecovery(step.title, step.skippable ?? false)\n\n switch (recovery) {\n case 'retry':\n shouldRetry = true\n console.log()\n continue\n case 'skip':\n outcome = 'skipped'\n console.log(` ${c.dim}Skipped ${step.title}${c.reset}`)\n break\n case 'abort':\n outcome = 'failed'\n results.push({ title: step.title, outcome, error: errorMsg })\n // Mark remaining steps as skipped\n for (let j = i + 1; j < steps.length; j++) {\n results.push({ title: steps[j].title, outcome: 'skipped' })\n }\n return { completed: false, steps: results }\n }\n }\n }\n\n results.push({ title: step.title, outcome, error: errorMsg })\n }\n\n const completed = results.every((r) => r.outcome !== 'failed')\n return { completed, steps: results }\n}\n\n// ─── Recovery prompt ────────────────────────────────────────────────\n\ntype RecoveryAction = 'retry' | 'skip' | 'abort'\n\nasync function promptRecovery(\n stepTitle: string,\n skippable: boolean,\n): Promise<RecoveryAction> {\n const options: { label: string; value: RecoveryAction; description?: string }[] = [\n { label: 'Retry', value: 'retry', description: `Try \"${stepTitle}\" again` },\n ]\n\n if (skippable) {\n options.push({ label: 'Skip', value: 'skip', description: 'Continue without this step' })\n }\n\n options.push({ label: 'Abort', value: 'abort', description: 'Exit setup' })\n\n console.log()\n const result = await selectPrompt<RecoveryAction>({\n message: 'What would you like to do?',\n options,\n defaultIndex: 0,\n })\n\n return result ?? 'abort'\n}\n","/**\n * CA certificate generation and management.\n *\n * Generates a self-signed CA key pair for TLS MITM interception.\n * The CA cert is installed in the system trust store so that Cursor\n * (via --proxy-server) accepts dynamically generated host certs.\n *\n * Storage: ~/.liminal/ca.pem + ca-key.pem (mode 0o600)\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { LIMINAL_DIR } from '../config/paths.js'\nimport forge from 'node-forge'\n\nexport const CA_CERT_PATH = join(LIMINAL_DIR, 'ca.pem')\nexport const CA_KEY_PATH = join(LIMINAL_DIR, 'ca-key.pem')\n\n// ─── Generation ──────────────────────────────────────────────────────\n\n/**\n * Generate a new self-signed CA certificate and private key.\n * Returns { cert, key } as PEM strings.\n */\nexport function generateCA(): { certPem: string; keyPem: string } {\n const keys = forge.pki.rsa.generateKeyPair(2048)\n\n const cert = forge.pki.createCertificate()\n cert.publicKey = keys.publicKey\n cert.serialNumber = generateSerialNumber()\n\n // Valid from now, for 5 years\n cert.validity.notBefore = new Date()\n cert.validity.notAfter = new Date()\n cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 5)\n\n const attrs = [\n { name: 'commonName', value: 'Liminal Proxy CA' },\n { name: 'organizationName', value: 'Liminal (Cognisos)' },\n { shortName: 'OU', value: 'Local Development' },\n ]\n cert.setSubject(attrs)\n cert.setIssuer(attrs) // Self-signed\n\n cert.setExtensions([\n { name: 'basicConstraints', cA: true, critical: true },\n { name: 'keyUsage', keyCertSign: true, cRLSign: true, critical: true },\n {\n name: 'subjectKeyIdentifier',\n },\n ])\n\n // Self-sign with SHA-256\n cert.sign(keys.privateKey, forge.md.sha256.create())\n\n return {\n certPem: forge.pki.certificateToPem(cert),\n keyPem: forge.pki.privateKeyToPem(keys.privateKey),\n }\n}\n\n// ─── Persistence ─────────────────────────────────────────────────────\n\n/**\n * Generate and save CA cert + key to ~/.liminal/.\n * Overwrites existing files.\n */\nexport function generateAndSaveCA(): { certPem: string; keyPem: string } {\n if (!existsSync(LIMINAL_DIR)) {\n mkdirSync(LIMINAL_DIR, { recursive: true, mode: 0o700 })\n }\n\n const { certPem, keyPem } = generateCA()\n\n writeFileSync(CA_CERT_PATH, certPem, { encoding: 'utf-8', mode: 0o644 })\n writeFileSync(CA_KEY_PATH, keyPem, { encoding: 'utf-8', mode: 0o600 })\n\n return { certPem, keyPem }\n}\n\n/**\n * Load existing CA cert and key from disk.\n * Returns null if either file is missing.\n */\nexport function loadCA(): { certPem: string; keyPem: string } | null {\n if (!existsSync(CA_CERT_PATH) || !existsSync(CA_KEY_PATH)) {\n return null\n }\n\n return {\n certPem: readFileSync(CA_CERT_PATH, 'utf-8'),\n keyPem: readFileSync(CA_KEY_PATH, 'utf-8'),\n }\n}\n\n/**\n * Load or generate CA. Prefers existing, generates if missing.\n */\nexport function ensureCA(): { certPem: string; keyPem: string } {\n const existing = loadCA()\n if (existing) return existing\n return generateAndSaveCA()\n}\n\n/**\n * Check if CA certificate files exist.\n */\nexport function hasCA(): boolean {\n return existsSync(CA_CERT_PATH) && existsSync(CA_KEY_PATH)\n}\n\n/**\n * Delete CA cert and key files.\n */\nexport function removeCA(): void {\n if (existsSync(CA_CERT_PATH)) unlinkSync(CA_CERT_PATH)\n if (existsSync(CA_KEY_PATH)) unlinkSync(CA_KEY_PATH)\n}\n\n/**\n * Parse CA cert PEM and return readable info.\n */\nexport function getCAInfo(): { commonName: string; validFrom: Date; validTo: Date; fingerprint: string } | null {\n const ca = loadCA()\n if (!ca) return null\n\n const cert = forge.pki.certificateFromPem(ca.certPem)\n const cn = cert.subject.getField('CN')\n\n // SHA-256 fingerprint\n const der = forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).getBytes()\n const md = forge.md.sha256.create()\n md.update(der)\n const fingerprint = md.digest().toHex().match(/.{2}/g)!.join(':').toUpperCase()\n\n return {\n commonName: cn ? cn.value : 'Unknown',\n validFrom: cert.validity.notBefore,\n validTo: cert.validity.notAfter,\n fingerprint,\n }\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────\n\nfunction generateSerialNumber(): string {\n // Random 16-byte serial number as hex string\n const bytes = forge.random.getBytesSync(16)\n return forge.util.bytesToHex(bytes)\n}\n","/**\n * Platform-specific CA certificate trust management.\n *\n * Installs/removes the Liminal CA from the system trust store\n * so that Cursor (and other Electron apps) accept our dynamic certs.\n */\n\nimport { execSync } from 'node:child_process'\nimport { existsSync, copyFileSync, unlinkSync } from 'node:fs'\nimport { CA_CERT_PATH } from './ca.js'\n\nexport interface TrustResult {\n success: boolean\n message: string\n requiresSudo: boolean\n}\n\n// ─── Install ─────────────────────────────────────────────────────────\n\nexport function installCA(): TrustResult {\n if (!existsSync(CA_CERT_PATH)) {\n return { success: false, message: 'CA certificate not found. Run \"liminal init\" first.', requiresSudo: false }\n }\n\n const platform = process.platform\n\n if (platform === 'darwin') return installMacOS()\n if (platform === 'linux') return installLinux()\n if (platform === 'win32') return installWindows()\n\n return { success: false, message: `Unsupported platform: ${platform}`, requiresSudo: false }\n}\n\n// ─── Remove ──────────────────────────────────────────────────────────\n\nexport function removeCA(): TrustResult {\n const platform = process.platform\n\n if (platform === 'darwin') return removeMacOS()\n if (platform === 'linux') return removeLinux()\n if (platform === 'win32') return removeWindows()\n\n return { success: false, message: `Unsupported platform: ${platform}`, requiresSudo: false }\n}\n\n// ─── Check ───────────────────────────────────────────────────────────\n\nexport function isCATrusted(): boolean {\n const platform = process.platform\n\n if (platform === 'darwin') return isTrustedMacOS()\n if (platform === 'linux') return isTrustedLinux()\n if (platform === 'win32') return isTrustedWindows()\n\n return false\n}\n\n// ─── macOS ───────────────────────────────────────────────────────────\n\nconst MACOS_LABEL = 'Liminal Proxy CA'\n\nfunction installMacOS(): TrustResult {\n try {\n // Add to login keychain and mark as trusted for SSL\n execSync(\n `security add-trusted-cert -r trustRoot -k ~/Library/Keychains/login.keychain-db \"${CA_CERT_PATH}\"`,\n { stdio: 'pipe' },\n )\n return { success: true, message: 'CA installed in login keychain (trusted for SSL)', requiresSudo: false }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (msg.includes('authorization') || msg.includes('permission')) {\n return {\n success: false,\n message: 'Keychain access denied. You may need to unlock your keychain or run with sudo.',\n requiresSudo: true,\n }\n }\n return { success: false, message: `Failed to install CA: ${msg}`, requiresSudo: false }\n }\n}\n\nfunction removeMacOS(): TrustResult {\n try {\n execSync(\n `security delete-certificate -c \"${MACOS_LABEL}\" ~/Library/Keychains/login.keychain-db`,\n { stdio: 'pipe' },\n )\n return { success: true, message: 'CA removed from login keychain', requiresSudo: false }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (msg.includes('could not be found')) {\n return { success: true, message: 'CA was not in keychain (already removed)', requiresSudo: false }\n }\n return { success: false, message: `Failed to remove CA: ${msg}`, requiresSudo: false }\n }\n}\n\nfunction isTrustedMacOS(): boolean {\n try {\n const out = execSync(\n `security find-certificate -c \"${MACOS_LABEL}\" ~/Library/Keychains/login.keychain-db`,\n { stdio: 'pipe', encoding: 'utf-8' },\n )\n return out.includes(MACOS_LABEL)\n } catch {\n return false\n }\n}\n\n// ─── Linux ───────────────────────────────────────────────────────────\n\nconst LINUX_CERT_PATH = '/usr/local/share/ca-certificates/liminal-proxy-ca.crt'\n\nfunction installLinux(): TrustResult {\n try {\n copyFileSync(CA_CERT_PATH, LINUX_CERT_PATH)\n execSync('update-ca-certificates', { stdio: 'pipe' })\n return { success: true, message: 'CA installed in system trust store', requiresSudo: true }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (msg.includes('EACCES') || msg.includes('permission')) {\n return {\n success: false,\n message: `Permission denied. Run with sudo:\\n sudo liminal trust-ca`,\n requiresSudo: true,\n }\n }\n return { success: false, message: `Failed to install CA: ${msg}`, requiresSudo: true }\n }\n}\n\nfunction removeLinux(): TrustResult {\n try {\n if (existsSync(LINUX_CERT_PATH)) {\n unlinkSync(LINUX_CERT_PATH)\n execSync('update-ca-certificates --fresh', { stdio: 'pipe' })\n }\n return { success: true, message: 'CA removed from system trust store', requiresSudo: true }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n return { success: false, message: `Failed to remove CA: ${msg}`, requiresSudo: true }\n }\n}\n\nfunction isTrustedLinux(): boolean {\n return existsSync(LINUX_CERT_PATH)\n}\n\n// ─── Windows ─────────────────────────────────────────────────────────\n\nfunction installWindows(): TrustResult {\n try {\n execSync(`certutil -addstore -user -f \"ROOT\" \"${CA_CERT_PATH}\"`, { stdio: 'pipe' })\n return { success: true, message: 'CA installed in user certificate store', requiresSudo: false }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n return { success: false, message: `Failed to install CA: ${msg}`, requiresSudo: false }\n }\n}\n\nfunction removeWindows(): TrustResult {\n try {\n execSync(`certutil -delstore -user \"ROOT\" \"${MACOS_LABEL}\"`, { stdio: 'pipe' })\n return { success: true, message: 'CA removed from user certificate store', requiresSudo: false }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n return { success: false, message: `Failed to remove CA: ${msg}`, requiresSudo: false }\n }\n}\n\nfunction isTrustedWindows(): boolean {\n try {\n const out = execSync(`certutil -verifystore -user \"ROOT\" \"${MACOS_LABEL}\"`, {\n stdio: 'pipe',\n encoding: 'utf-8',\n })\n return out.includes('Liminal')\n } catch {\n return false\n }\n}\n","import { saveConfig, isConfigured } from '../config/loader.js'\n\nexport async function logoutCommand(): Promise<void> {\n if (!isConfigured()) {\n console.log(' Not currently logged in.')\n return\n }\n\n saveConfig({ apiKey: '' })\n console.log(' Logged out.')\n console.log(' Run \\x1b[1mliminal login\\x1b[0m to reconnect.')\n}\n","import { loadConfig, applyOverrides, isConfigured } from '../config/loader.js'\nimport { createRequestHandler } from '../proxy/handler.js'\nimport type { HandlerDeps } from '../proxy/handler.js'\nimport { ProxyServer } from '../proxy/server.js'\nimport { FileLogger } from '../daemon/logger.js'\nimport { SessionManager } from '../rsc/session-manager.js'\nimport { Semaphore } from '../rsc/semaphore.js'\nimport { LatencyMonitor } from '../rsc/latency-monitor.js'\nimport { createConnectHandler } from '../tls/connect-handler.js'\nimport { hasCA, loadCA } from '../tls/ca.js'\nimport { isCATrusted } from '../tls/trust.js'\nimport { createMitmBridge } from '../tls/mitm-bridge.js'\nimport { MitmStats } from '../tls/mitm-stats.js'\nimport {\n isDaemonRunning,\n writePidFile,\n setupSignalHandlers,\n forkDaemon,\n resolveBinPath,\n} from '../daemon/lifecycle.js'\nimport type { ResolvedConfig, Tool } from '../types.js'\nimport { printBanner } from '../version.js'\nimport {\n c, success, warn, error as fmtError, box, maturityBadge,\n} from '../ui/format.js'\nimport { getConnectors } from '../connectors/index.js'\nimport type { ConnectorId } from '../connectors/types.js'\n\n// ─── Connector routing status ───────────────────────────────────────\n\ninterface ToolStatus {\n label: string\n routing: boolean\n method: string // \"proxy\" | \"hooks\" | \"MITM\"\n badge: string // maturity badge (empty for stable)\n}\n\nasync function detectToolStatus(\n toolIds: string[],\n caReady: boolean,\n): Promise<ToolStatus[]> {\n const results: ToolStatus[] = []\n const connectors = getConnectors(toolIds as ConnectorId[])\n\n for (const conn of connectors) {\n const status = await conn.detect()\n let method = 'proxy'\n if (conn.info.id === 'cursor') {\n method = caReady ? 'MITM' : 'hooks'\n }\n results.push({\n label: conn.info.label,\n routing: status.configured || status.installed,\n method,\n badge: maturityBadge(conn.info.maturity),\n })\n }\n\n return results\n}\n\nfunction printToolStatus(tools: ToolStatus[]): void {\n for (const tool of tools) {\n const suffix = tool.badge ? ` ${c.dim}(${tool.badge.trim()})${c.reset}` : ''\n if (tool.routing) {\n console.log(success(`${tool.label}`, `routing via ${tool.method}${suffix}`))\n } else {\n console.log(warn(`${tool.label}`, `not detected${suffix}`))\n }\n }\n}\n\n// ─── Main command ───────────────────────────────────────────────────\n\nexport async function startCommand(flags: Map<string, string | true>): Promise<void> {\n const startTime = Date.now()\n const isDaemon = flags.has('d') || flags.has('daemon')\n const isForked = flags.has('_forked')\n\n // Check if already running (skip for forked processes — parent already checked)\n if (!isForked) {\n const state = isDaemonRunning()\n if (state.running) {\n console.error(fmtError(\n `Liminal daemon is already running (PID ${state.pid})`,\n `Run ${c.bold}liminal stop${c.reset}${c.dim} first, or ${c.bold}liminal status${c.reset}${c.dim} to check`,\n ))\n process.exit(1)\n }\n }\n\n // Check config\n if (!isConfigured()) {\n console.error(fmtError(\n 'Liminal is not configured',\n `Run ${c.bold}liminal init${c.reset}${c.dim} to set up`,\n ))\n process.exit(1)\n }\n\n // Load and apply config\n let config = loadConfig()\n const portOverride = flags.get('port')\n const upstreamOverride = flags.get('upstream')\n config = applyOverrides(config, {\n ...(typeof portOverride === 'string' ? { port: parseInt(portOverride, 10) } : {}),\n ...(typeof upstreamOverride === 'string' ? { upstreamBaseUrl: upstreamOverride } : {}),\n })\n\n const toolIds = (config.tools ?? []) as string[]\n const caReady = hasCA() && isCATrusted()\n\n // Background mode: fork and exit parent\n if (isDaemon && !isForked) {\n const extraArgs: string[] = []\n if (portOverride) extraArgs.push('--port', String(portOverride))\n if (upstreamOverride) extraArgs.push('--upstream', String(upstreamOverride))\n\n const binPath = resolveBinPath(import.meta.url)\n const childPid = forkDaemon(binPath, extraArgs)\n\n console.log()\n console.log(success(`Liminal daemon started (PID ${childPid})`))\n console.log()\n\n // Show tool routing status for daemon mode (task 2.2.4)\n const toolStatus = await detectToolStatus(toolIds, caReady)\n printToolStatus(toolStatus)\n\n console.log()\n console.log(` ${c.bold}Proxy:${c.reset} http://127.0.0.1:${config.port}`)\n console.log(` ${c.bold}Logs:${c.reset} ~/.liminal/logs/liminal.log`)\n console.log()\n process.exit(0)\n }\n\n // Foreground mode: run the server in this process\n const isForeground = !isDaemon || isForked\n const logger = new FileLogger({ mirrorStdout: isForeground && !isForked })\n\n // Build the resolved config for the proxy\n const resolvedConfig: ResolvedConfig = {\n rscApiKey: config.apiKey,\n rscBaseUrl: config.apiBaseUrl,\n proxyPort: config.port,\n compressionThreshold: config.compressionThreshold,\n aggregateThreshold: config.aggregateThreshold,\n hotFraction: config.hotFraction,\n coldFraction: config.coldFraction,\n compressRoles: config.compressRoles,\n compressToolResults: config.compressToolResults,\n learnFromResponses: config.learnFromResponses,\n latencyBudgetMs: config.latencyBudgetMs || undefined,\n upstreamBaseUrl: config.upstreamBaseUrl,\n anthropicUpstreamUrl: config.anthropicUpstreamUrl,\n enabled: config.enabled,\n tools: config.tools as Tool[],\n concurrencyLimit: config.concurrencyLimit,\n concurrencyTimeoutMs: config.concurrencyTimeoutMs,\n maxSessions: config.maxSessions,\n sessionTtlMs: config.sessionTtlMs,\n latencyWarningMs: config.latencyWarningMs,\n latencyCriticalMs: config.latencyCriticalMs,\n }\n\n // Create multi-session infrastructure\n const semaphore = new Semaphore(resolvedConfig.concurrencyLimit)\n const latencyMonitor = new LatencyMonitor({\n warningThresholdMs: resolvedConfig.latencyWarningMs,\n criticalThresholdMs: resolvedConfig.latencyCriticalMs,\n })\n\n // ── Stats aggregator + persistence (task 4.4.3) ────────────────\n const { StatsAggregator } = await import('../stats/aggregator.js')\n const { loadStats: loadPersistedStats, saveStats: savePersistedStats, mergeSessionIntoCumulative, incrementSessionCount } = await import('../stats/store.js')\n\n const statsAggregator = new StatsAggregator()\n const persistedStats = loadPersistedStats()\n incrementSessionCount(persistedStats)\n let lastFlushedSnapshot = statsAggregator.snapshot()\n\n // Flush stats to disk every 60 seconds\n const statsFlushTimer = setInterval(() => {\n try {\n const snap = statsAggregator.snapshot()\n mergeSessionIntoCumulative(persistedStats, snap, lastFlushedSnapshot)\n savePersistedStats(persistedStats)\n lastFlushedSnapshot = snap\n } catch (err) {\n logger.log(`[STATS] Flush error: ${err instanceof Error ? err.message : String(err)}`)\n }\n }, 60_000)\n if (statsFlushTimer.unref) statsFlushTimer.unref()\n\n // Flush on shutdown\n const flushStatsOnExit = () => {\n try {\n clearInterval(statsFlushTimer)\n const snap = statsAggregator.snapshot()\n mergeSessionIntoCumulative(persistedStats, snap, lastFlushedSnapshot)\n savePersistedStats(persistedStats)\n } catch { /* best effort */ }\n }\n process.on('SIGTERM', flushStatsOnExit)\n process.on('SIGINT', flushStatsOnExit)\n process.on('exit', flushStatsOnExit)\n\n // Wire up pipeline events for each new session\n function wireSessionEvents(key: string, pipeline: import('../rsc/pipeline.js').RSCPipelineWrapper): void {\n const connector = key.split(':')[0] || 'unknown'\n pipeline.events.on('compression', (event) => {\n if (event.tokensSaved > 0) {\n logger.log(`[LIMINAL] [${key}] Compressed: ${event.tokensSaved} tokens saved (${event.ratio.toFixed(3)} ratio)`)\n }\n statsAggregator.recordCompression(\n connector,\n event.inputTokens ?? 0,\n event.tokensSaved,\n event.processingTimeMs ?? 0,\n )\n })\n pipeline.events.on('compression_skipped', (event) => {\n const detail = event.reason === 'latency_budget'\n ? `${event.reason} (${event.estimatedTokens}tok, budget:${event.budgetMs}ms, elapsed:${event.elapsedMs}ms)`\n : event.reason === 'below_threshold'\n ? `${event.reason} (${event.estimatedTokens}tok < ${config.compressionThreshold}tok threshold)`\n : `${event.reason} (${event.estimatedTokens}tok)`\n logger.log(`[LIMINAL] [${key}] Skipped: ${detail}`)\n statsAggregator.recordSkipped(connector, event.estimatedTokens ?? 0)\n })\n pipeline.events.on('error', (event) => {\n logger.log(`[LIMINAL] [${key}] Error: ${event.error.message}`)\n statsAggregator.recordFailure(connector)\n })\n pipeline.events.on('learning', (event) => {\n if (event.error) {\n logger.log(`[LIMINAL] [${key}] Learning error: ${event.error}`)\n } else if (event.tokensIngested > 0) {\n logger.log(`[LIMINAL] [${key}] Learning: ${event.tokensIngested} tokens ingested (deferred:${event.deferred})`)\n }\n })\n pipeline.events.on('degradation', (event) => {\n logger.log(`[LIMINAL] [${key}] Circuit ${event.circuitState}: ${event.reason}`)\n })\n }\n\n const sessions = new SessionManager({\n pipelineConfig: {\n rscApiKey: config.apiKey,\n rscBaseUrl: config.apiBaseUrl,\n compressionThreshold: config.compressionThreshold,\n learnFromResponses: config.learnFromResponses,\n latencyBudgetMs: config.latencyBudgetMs || undefined,\n },\n maxSessions: resolvedConfig.maxSessions,\n sessionTtlMs: resolvedConfig.sessionTtlMs,\n onSessionCreated: (key, pipeline) => {\n logger.log(`[SESSION] Created: ${key}`)\n wireSessionEvents(key, pipeline)\n },\n onSessionEvicted: (key) => {\n logger.log(`[SESSION] Evicted: ${key} (idle)`)\n },\n })\n\n latencyMonitor.onAlert((alert) => {\n logger.log(`[LATENCY] ${alert.type.toUpperCase()}: ${alert.message} (${alert.activeSessions} sessions) — ${alert.suggestion}`)\n })\n\n // MITM stats tracker\n const mitmStats = new MitmStats()\n\n // Create server with optional CONNECT handler for Cursor MITM\n const deps: HandlerDeps = {\n sessions, semaphore, latencyMonitor, mitmStats, config: resolvedConfig, logger,\n onUsage: (usage, verifiedSaved, originalInputTokens) => {\n statsAggregator.recordApiUsage(usage.inputTokens, usage.outputTokens, verifiedSaved, originalInputTokens)\n\n // Fire-and-forget: report verified usage to backend (Issue #72)\n if (resolvedConfig.rscApiKey && resolvedConfig.rscBaseUrl) {\n const body = JSON.stringify({\n model: 'cli',\n actual_input_tokens: usage.inputTokens,\n actual_output_tokens: usage.outputTokens,\n original_input_bytes: originalInputTokens * 4,\n })\n fetch(`${resolvedConfig.rscBaseUrl}/api/v1/usage/verified`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${resolvedConfig.rscApiKey}`,\n },\n body,\n signal: AbortSignal.timeout(5_000),\n }).catch(() => { /* non-fatal */ })\n }\n },\n getVerifiedTokens: () => {\n const snap = statsAggregator.snapshot()\n return {\n actualInputTokens: snap.actualInputTokens,\n actualOutputTokens: snap.actualOutputTokens,\n originalInputEstimate: snap.originalInputEstimate,\n verifiedInputSaved: snap.verifiedInputSaved,\n verifiedSavingsRate: snap.verifiedSavingsRate,\n verifiedRequestCount: snap.verifiedRequestCount,\n }\n },\n getCursorMetrics: () => {\n const { parseCursorHookStats } = require('../cursor/stats.js')\n return parseCursorHookStats()\n },\n }\n const handler = createRequestHandler(deps)\n\n // MITM intercept handler — set after server starts (needs http.Server ref)\n let mitmHandler: ((socket: import('node:net').Socket, hostname: string, port: number) => void) | undefined\n\n const connectHandler = createConnectHandler({\n logger,\n onIntercept: (socket, hostname, port) => {\n if (mitmHandler) {\n mitmStats.recordIntercept(hostname)\n mitmHandler(socket, hostname, port)\n } else {\n logger.log(`[MITM] No bridge available for ${hostname} — falling back to passthrough`)\n mitmStats.recordPassthrough()\n }\n },\n onPassthrough: () => {\n mitmStats.recordPassthrough()\n },\n })\n\n const server = new ProxyServer(config.port, handler, connectHandler)\n\n // Setup graceful shutdown\n setupSignalHandlers(server, logger)\n\n // Start listening\n try {\n const actualPort = await server.start()\n writePidFile(process.pid)\n\n logger.log(`[DAEMON] Liminal proxy started on http://127.0.0.1:${actualPort}`)\n logger.log(`[DAEMON] Upstream (OpenAI): ${config.upstreamBaseUrl}`)\n logger.log(`[DAEMON] Upstream (Anthropic): ${config.anthropicUpstreamUrl}`)\n logger.log(`[DAEMON] Liminal API: ${config.apiBaseUrl}`)\n logger.log(`[DAEMON] PID: ${process.pid}`)\n logger.log(`[DAEMON] Max sessions: ${resolvedConfig.maxSessions}, Concurrency limit: ${resolvedConfig.concurrencyLimit}`)\n\n // Wire MITM bridge if CA is available and trusted\n if (caReady) {\n const httpServer = server.getHttpServer()\n const ca = loadCA()\n if (httpServer && ca) {\n mitmHandler = createMitmBridge({\n httpServer,\n caCertPem: ca.certPem,\n caKeyPem: ca.keyPem,\n logger,\n })\n mitmStats.enable()\n logger.log('[MITM] TLS bridge active — intercepting LLM API calls')\n }\n }\n\n // Log MITM proxy status\n logger.log(`[DAEMON] CONNECT handler: active | MITM: ${caReady ? 'ready (CA trusted)' : 'passthrough only (run liminal trust-ca)'}`)\n\n if (isForeground && !isForked) {\n printBanner()\n\n console.log(success('Configuration loaded', `${toolIds.length} tool${toolIds.length !== 1 ? 's' : ''} configured`))\n console.log(success(`Proxy started on http://127.0.0.1:${actualPort}`))\n if (caReady) {\n console.log(success('MITM bridge active', 'CA trusted'))\n }\n\n // Health check (run early so result is ready for display)\n const { RSCPipelineWrapper } = await import('../rsc/pipeline.js')\n const probe = new RSCPipelineWrapper({\n rscApiKey: config.apiKey,\n rscBaseUrl: config.apiBaseUrl,\n compressionThreshold: config.compressionThreshold,\n learnFromResponses: false,\n })\n const healthy = await probe.healthCheck()\n if (healthy) {\n console.log(success('Cognisos API healthy'))\n logger.log('[DAEMON] Liminal API health check: OK')\n } else {\n console.log(warn('Cognisos API unreachable', 'will retry on first request'))\n logger.log('[DAEMON] Liminal API health check: FAILED (will retry on first request)')\n }\n\n console.log()\n\n // Tool routing status (task 2.2.1)\n const toolStatus = await detectToolStatus(toolIds, caReady)\n\n // Build box rows with per-tool status\n const boxRows: [string, string][] = []\n for (const tool of toolStatus) {\n const icon = tool.routing ? `${c.green}\\u2713${c.reset}` : `${c.dim}\\u00B7${c.reset}`\n const badgeSuffix = tool.badge ? ` ${c.dim}(${tool.badge.trim()})${c.reset}` : ''\n boxRows.push([\n `${c.bold}${tool.label}${c.reset}`,\n `${icon} routing via ${tool.method}${badgeSuffix}`,\n ])\n }\n boxRows.push(['', ''])\n boxRows.push([`${c.bold}Proxy:${c.reset}`, `http://127.0.0.1:${actualPort}`])\n boxRows.push([`${c.bold}Since:${c.reset}`, new Date().toISOString().replace('T', ' ').slice(0, 16) + ' UTC'])\n boxRows.push(['', ''])\n boxRows.push(['', `Press ${c.bold}Ctrl+C${c.reset} to stop`])\n\n console.log(box(boxRows, 'LIMINAL ACTIVE'))\n\n // Startup timing (task 2.2.5)\n const elapsed = ((Date.now() - startTime) / 1000).toFixed(1)\n console.log()\n console.log(` ${c.dim}Started in ${elapsed}s${c.reset}`)\n console.log()\n\n // Health check already done above — skip the duplicate below\n return\n }\n\n // Check RSC API health on startup using a temporary probe pipeline\n const { RSCPipelineWrapper } = await import('../rsc/pipeline.js')\n const probe = new RSCPipelineWrapper({\n rscApiKey: config.apiKey,\n rscBaseUrl: config.apiBaseUrl,\n compressionThreshold: config.compressionThreshold,\n learnFromResponses: false,\n })\n const healthy = await probe.healthCheck()\n if (healthy) {\n logger.log('[DAEMON] Liminal API health check: OK')\n } else {\n logger.log('[DAEMON] Liminal API health check: FAILED (will retry on first request)')\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n const portInUse = message.includes('EADDRINUSE')\n console.error(fmtError(\n `Failed to start proxy: ${message}`,\n portInUse\n ? `Port ${config.port} is in use. Try ${c.bold}liminal stop${c.reset}${c.dim} or ${c.bold}liminal config --set port=3142${c.reset}`\n : undefined,\n ))\n process.exit(1)\n }\n}\n","import * as http from 'node:http'\nimport { RSCCircuitOpenError } from '@cognisos/rsc-sdk'\nimport { compressConversation, type ConversationCompressOptions } from '../rsc/message-compressor.js'\nimport { analyzeConversation } from '../rsc/conversation-analyzer.js'\nimport { createStreamLearningBuffer } from '../rsc/learning.js'\nimport { pipeSSEResponse } from './streaming.js'\nimport type { RSCPipelineWrapper } from '../rsc/pipeline.js'\nimport type { ChatCompletionRequest, ResolvedConfig } from '../types.js'\nimport { formatTiersLog, formatSavedLog, formatDegradeLog, formatResponseLog } from '../terminology.js'\nimport type { Logger } from './handler.js'\nimport type { Semaphore } from '../rsc/semaphore.js'\nimport type { LatencyMonitor } from '../rsc/latency-monitor.js'\n\nfunction setCORSHeaders(res: http.ServerResponse): void {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')\n}\n\nfunction sendJSON(res: http.ServerResponse, status: number, body: unknown): void {\n setCORSHeaders(res)\n res.writeHead(status, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(body))\n}\n\n/**\n * Extract the bearer token from the Authorization header.\n * This is the user's LLM API key — used to forward to the upstream LLM.\n */\nfunction extractBearerToken(req: http.IncomingMessage): string | null {\n const auth = req.headers.authorization\n if (!auth || !auth.startsWith('Bearer ')) return null\n return auth.slice(7)\n}\n\nexport async function handleChatCompletions(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: unknown,\n pipeline: RSCPipelineWrapper,\n config: ResolvedConfig,\n logger: Logger,\n semaphore: Semaphore,\n latencyMonitor: LatencyMonitor,\n sessionKey: string,\n stickyCache?: Map<string, string>,\n): Promise<void> {\n const request = body as ChatCompletionRequest\n\n // Validate required fields\n if (!request.messages || !Array.isArray(request.messages)) {\n sendJSON(res, 400, {\n error: { message: 'messages is required and must be an array', type: 'invalid_request_error' },\n })\n return\n }\n\n // Extract LLM API key from the incoming request\n const llmApiKey = extractBearerToken(req)\n if (!llmApiKey) {\n sendJSON(res, 401, {\n error: { message: 'Authorization header with Bearer token is required', type: 'authentication_error' },\n })\n return\n }\n\n // Compress messages (or passthrough if circuit is open / disabled)\n let messages = request.messages\n let anyCompressed = false\n let totalTokensSaved = 0\n\n if (config.enabled && !pipeline.isCircuitOpen()) {\n const compressStart = Date.now()\n try {\n const compressRoles = new Set(config.compressRoles)\n\n const plan = analyzeConversation(request.messages, {\n hotFraction: config.hotFraction,\n coldFraction: config.coldFraction,\n aggregateThreshold: config.aggregateThreshold,\n compressRoles,\n compressToolResults: config.compressToolResults,\n })\n\n if (plan.shouldCompress) {\n logger.log(formatTiersLog(plan.hotCount, plan.warmCount, plan.coldCount, plan.totalEligibleTokens))\n }\n\n let batchedCount = 0\n let batchedProseTok = 0\n let skippedCount = 0\n let hotCount = 0\n let compressError = ''\n const blockLogFn = (msg: string) => {\n if (msg.includes('[COMPRESS-ERROR]')) {\n compressError = msg\n } else if (msg.includes('batching)')) {\n batchedCount++\n const proseMatch = msg.match(/~(\\d+) prose tok/)\n if (proseMatch) batchedProseTok += parseInt(proseMatch[1], 10)\n } else if (msg.includes('skip)')) {\n skippedCount++\n } else if (msg.includes('HOT')) {\n hotCount++\n }\n }\n\n const result = await compressConversation(\n pipeline.pipeline,\n pipeline.session,\n plan,\n {\n compressToolResults: config.compressToolResults,\n compressionThreshold: config.compressionThreshold,\n logFn: blockLogFn,\n semaphore,\n semaphoreTimeoutMs: config.concurrencyTimeoutMs,\n stickyCache,\n },\n )\n\n const totalBlocks = batchedCount + skippedCount + hotCount\n logger.log(`[COMPRESS] ${totalBlocks} blocks: ${batchedCount} batched (${batchedProseTok.toLocaleString()} prose tok) · ${skippedCount} skipped · ${hotCount} hot`)\n if (compressError) logger.log(compressError)\n messages = result.messages\n anyCompressed = result.anyCompressed\n totalTokensSaved = result.totalTokensSaved\n\n const latencyMs = Date.now() - compressStart\n const alert = latencyMonitor.record(sessionKey, latencyMs)\n if (alert) {\n logger.log(`[LATENCY] ${alert.type.toUpperCase()}: ${alert.message}`)\n }\n\n if (result.totalTokensSaved > 0) {\n logger.log(formatSavedLog(result.totalTokensSaved, latencyMs))\n }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n logger.log(formatDegradeLog())\n } else {\n logger.log(`[ERROR] Compression failed: ${err instanceof Error ? err.message : String(err)}`)\n }\n // Fall through with original messages\n messages = request.messages\n }\n }\n\n // Build upstream request\n const upstreamUrl = `${config.upstreamBaseUrl}/v1/chat/completions`\n const upstreamBody = { ...request, messages }\n\n const upstreamHeaders: Record<string, string> = {\n 'Authorization': `Bearer ${llmApiKey}`,\n 'Content-Type': 'application/json',\n }\n\n // Forward streaming preference\n if (request.stream) {\n upstreamHeaders['Accept'] = 'text/event-stream'\n }\n\n try {\n const upstreamResponse = await fetch(upstreamUrl, {\n method: 'POST',\n headers: upstreamHeaders,\n body: JSON.stringify(upstreamBody),\n })\n\n // Handle upstream errors\n if (!upstreamResponse.ok) {\n const errorBody = await upstreamResponse.text()\n setCORSHeaders(res)\n res.writeHead(upstreamResponse.status, {\n 'Content-Type': upstreamResponse.headers.get('Content-Type') || 'application/json',\n })\n res.end(errorBody)\n return\n }\n\n // Streaming response\n if (request.stream && upstreamResponse.body) {\n // Always buffer for learning — even when no compression savings yet,\n // learning discovers patterns that enable future compression.\n const learningBuffer = createStreamLearningBuffer(pipeline.pipeline)\n\n logger.log(formatResponseLog(request.model, totalTokensSaved, true))\n await pipeSSEResponse(\n upstreamResponse,\n res,\n (text) => learningBuffer?.append(text),\n () => learningBuffer?.flush(),\n totalTokensSaved,\n )\n return\n }\n\n // Non-streaming response\n const responseBody = await upstreamResponse.text()\n logger.log(formatResponseLog(request.model, totalTokensSaved))\n\n // Adjust usage to reflect pre-compression token count\n let finalBody = responseBody\n if (totalTokensSaved > 0) {\n try {\n const parsed = JSON.parse(responseBody)\n if (parsed?.usage?.prompt_tokens != null) {\n parsed.usage.prompt_tokens += totalTokensSaved\n if (parsed.usage.total_tokens != null) {\n parsed.usage.total_tokens += totalTokensSaved\n }\n finalBody = JSON.stringify(parsed)\n logger.log(`[TOKENS] Adjusted prompt_tokens by +${totalTokensSaved}`)\n }\n } catch {\n // Pass through unmodified on parse error\n }\n }\n\n setCORSHeaders(res)\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(finalBody)\n\n // Trigger learning from response (fire-and-forget).\n // Always learn — pattern discovery must run even before compression produces savings.\n {\n try {\n const parsed = JSON.parse(responseBody)\n const content = parsed?.choices?.[0]?.message?.content\n if (typeof content === 'string' && content.length > 0) {\n pipeline.pipeline.triggerLearning(content)\n }\n } catch {\n // Ignore learning parse errors\n }\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n logger.log(`[ERROR] Upstream request failed: ${message}`)\n if (!res.headersSent) {\n sendJSON(res, 502, {\n error: { message: `Failed to reach upstream LLM: ${message}`, type: 'server_error' },\n })\n }\n }\n}\n","import { createHash } from 'node:crypto'\nimport type { CompressionPipeline, Session } from '@cognisos/rsc-sdk'\nimport { RSCCircuitOpenError } from '@cognisos/rsc-sdk'\nimport type { ChatCompletionMessage, ContentPart } from '../types.js'\nimport { segmentContent } from './content-segmenter.js'\nimport type { ConversationPlan } from './conversation-analyzer.js'\nimport type { Semaphore } from './semaphore.js'\nimport { countTokens } from './tokenizer.js'\n\n/** Fast 16-char hex hash for sticky cache keys. */\nfunction contentHash(text: string): string {\n return createHash('sha256').update(text).digest('hex').slice(0, 16)\n}\n\nexport interface CompressedMessagesResult {\n messages: ChatCompletionMessage[]\n anyCompressed: boolean\n totalTokensSaved: number\n}\n\n/** Content block types that must never be modified. */\nconst PASSTHROUGH_BLOCK_TYPES = new Set(['thinking', 'tool_use', 'image'])\n\n/**\n * Sanitize text returned from RSC decompress to remove characters that\n * would break JSON serialization (lone surrogates, control chars except\n * newlines/tabs). This prevents \"Invalid character\" errors on upstream fetch.\n */\nfunction sanitizeCompressedText(text: string): string {\n // eslint-disable-next-line no-control-regex\n return text.replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]/g, '')\n}\n\ntype RecordFn = (compressed: boolean, saved: number) => void\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Legacy per-message compression (kept for backward compatibility).\n * Callers should prefer compressConversation() for tier-aware compression.\n */\nexport async function compressMessages(\n messages: ChatCompletionMessage[],\n pipeline: CompressionPipeline,\n session: Session,\n compressRoles: Set<string>,\n): Promise<CompressedMessagesResult> {\n let anyCompressed = false\n let totalTokensSaved = 0\n\n const compressed = await Promise.all(\n messages.map(async (msg) => {\n if (!compressRoles.has(msg.role)) return msg\n return compressMessage(msg, pipeline, session, (c, saved) => {\n anyCompressed = anyCompressed || c\n totalTokensSaved += saved\n })\n }),\n )\n\n return { messages: compressed, anyCompressed, totalTokensSaved }\n}\n\n/**\n * Tier-aware conversation compression with per-message text batching.\n *\n * - HOT messages pass through verbatim (zero latency).\n * - WARM and COLD messages have all eligible text extracted, concatenated,\n * and compressed in a single API call per message. This avoids many\n * sub-threshold skips when messages contain multiple small blocks.\n * - If the plan says shouldCompress=false, everything passes through.\n */\nexport interface ConversationCompressOptions {\n compressToolResults: boolean\n /** Minimum token count for compression (blocks below this are skipped). */\n compressionThreshold?: number\n /** Optional callback for block-level diagnostic logging */\n logFn?: (msg: string) => void\n /** Optional semaphore to limit concurrent RSC API calls across sessions */\n semaphore?: Semaphore\n /** Timeout for semaphore acquire (ms). Defaults to 15000. */\n semaphoreTimeoutMs?: number\n /** Per-session cache: content-hash → compressed text.\n * Reuses previous compression results to preserve Anthropic prefix caching. */\n stickyCache?: Map<string, string>\n}\n\nexport async function compressConversation(\n pipeline: CompressionPipeline,\n session: Session,\n plan: ConversationPlan,\n options: ConversationCompressOptions = { compressToolResults: true },\n): Promise<CompressedMessagesResult> {\n // Fast path: aggregate threshold not met\n if (!plan.shouldCompress) {\n return {\n messages: plan.messages.map((tm) => tm.message),\n anyCompressed: false,\n totalTokensSaved: 0,\n }\n }\n\n const log = options.logFn\n const threshold = options.compressionThreshold ?? 100\n\n // Build output array indexed by original position\n const results: ChatCompletionMessage[] = new Array(plan.messages.length)\n\n // ── Phase 1: Triage messages into passthrough vs compressible ───────\n // For each compressible message, extract its prose text and track which\n // content blocks contributed so we can reassemble after batch normalize.\n interface CompressibleEntry {\n planIdx: number\n tm: typeof plan.messages[0]\n batchText: string\n /** Indices of content parts that were batched (for array content) */\n batchedIndices: Set<number>\n }\n\n const compressible: CompressibleEntry[] = []\n\n for (let i = 0; i < plan.messages.length; i++) {\n const tm = plan.messages[i]\n const role = tm.message.role\n const blockTypes = Array.isArray(tm.message.content)\n ? (tm.message.content as ContentPart[]).map((b) => b.type).join(',')\n : 'string'\n\n // HOT: always verbatim\n if (tm.tier === 'hot') {\n log?.(`[BLOCK] #${tm.index} ${role} [${blockTypes}] → HOT (verbatim)`)\n results[i] = tm.message\n continue\n }\n\n // WARM / COLD with no eligible tokens: skip\n if (tm.eligibleTokens === 0) {\n log?.(`[BLOCK] #${tm.index} ${role} [${blockTypes}] → ${tm.tier.toUpperCase()} (0 eligible tok, skip)`)\n results[i] = tm.message\n continue\n }\n\n // Pre-filter: estimate prose tokens after code segmentation\n const proseEstimate = estimateProseTokens(tm.message, options.compressToolResults)\n if (proseEstimate < threshold) {\n log?.(`[BLOCK] #${tm.index} ${role} [${blockTypes}] → ${tm.tier.toUpperCase()} (${proseEstimate} prose tok after segmentation < ${threshold} threshold, skip)`)\n results[i] = tm.message\n continue\n }\n\n // Extract compressible text and track batched indices\n const { batchText, batchedIndices } = extractBatchableText(tm.message, options.compressToolResults)\n if (!batchText) {\n results[i] = tm.message\n continue\n }\n\n log?.(`[BLOCK] #${tm.index} ${role} [${blockTypes}] → ${tm.tier.toUpperCase()} (${tm.eligibleTokens} eligible tok, ~${proseEstimate} prose tok, batching)`)\n compressible.push({ planIdx: i, tm, batchText, batchedIndices })\n }\n\n if (compressible.length === 0) {\n return {\n messages: results,\n anyCompressed: false,\n totalTokensSaved: 0,\n }\n }\n\n // ── Phase 2: Check sticky cache, then batch-normalize uncached ──────\n let anyCompressed = false\n let totalTokensSaved = 0\n\n const cache = options.stickyCache\n const uncached: CompressibleEntry[] = []\n\n // Resolve sticky cache hits first (no API call, no semaphore needed)\n for (const entry of compressible) {\n if (!cache) {\n uncached.push(entry)\n continue\n }\n const hash = contentHash(entry.batchText)\n const cached = cache.get(hash)\n if (cached !== undefined) {\n log?.(`[STICKY] Cache hit for message #${entry.tm.index}`)\n const originalTokens = countTokens(entry.batchText)\n const compressedTokens = countTokens(cached)\n const saved = Math.max(0, originalTokens - compressedTokens)\n if (saved > 0) {\n anyCompressed = true\n totalTokensSaved += saved\n }\n session.recordCompression({\n inputTokens: originalTokens,\n outputTokens: compressedTokens,\n tokensSaved: saved,\n skipped: false,\n fabricHits: 0,\n fabricMisses: 0,\n ratio: compressedTokens / Math.max(originalTokens, 1),\n deltaMdlBits: 0,\n processingTimeMs: 0,\n })\n results[entry.planIdx] = reassembleMessage(entry.tm.message, cached, entry.batchedIndices)\n } else {\n uncached.push(entry)\n }\n }\n\n // Batch-normalize only the uncached entries\n if (uncached.length > 0) {\n if (options.semaphore) await options.semaphore.acquire(options.semaphoreTimeoutMs)\n try {\n const batchSegments = uncached.map((entry) => ({\n index: entry.planIdx,\n text: entry.batchText,\n }))\n\n const batchResults = await pipeline.normalizeBatch(batchSegments)\n\n // ── Phase 3: Reassemble messages from batch results ─────────────\n for (const entry of uncached) {\n const result = batchResults.get(entry.planIdx)\n if (!result || result.metrics.skipped) {\n results[entry.planIdx] = entry.tm.message\n continue\n }\n\n const compressed = sanitizeCompressedText(result.text)\n\n const originalTokens = countTokens(entry.batchText)\n const compressedTokens = countTokens(compressed)\n const saved = Math.max(0, originalTokens - compressedTokens)\n\n const realMetrics = {\n ...result.metrics,\n inputTokens: originalTokens,\n outputTokens: compressedTokens,\n tokensSaved: saved,\n }\n\n if (saved > 0) {\n anyCompressed = true\n totalTokensSaved += saved\n }\n session.recordCompression(realMetrics)\n\n results[entry.planIdx] = reassembleMessage(entry.tm.message, compressed, entry.batchedIndices)\n\n // Store in sticky cache for future turns\n if (cache) {\n cache.set(contentHash(entry.batchText), compressed)\n }\n }\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err)\n if (err instanceof RSCCircuitOpenError) {\n session.recordFailure()\n log?.(`[COMPRESS-ERROR] Circuit open — passing through (${errMsg})`)\n } else {\n log?.(`[COMPRESS-ERROR] ${errMsg}`)\n }\n for (const entry of uncached) {\n if (!results[entry.planIdx]) {\n results[entry.planIdx] = entry.tm.message\n }\n }\n } finally {\n if (options.semaphore) options.semaphore.release()\n }\n }\n\n return { messages: results, anyCompressed, totalTokensSaved }\n}\n\n/**\n * Extract all compressible text from a message and return which content\n * block indices contributed (for reassembly after batch normalize).\n */\nfunction extractBatchableText(\n msg: ChatCompletionMessage,\n compressToolResults: boolean,\n): { batchText: string | null; batchedIndices: Set<number> } {\n const batchedIndices = new Set<number>()\n\n if (typeof msg.content === 'string') {\n if (msg.content.trim()) {\n return { batchText: msg.content, batchedIndices }\n }\n return { batchText: null, batchedIndices }\n }\n\n if (!Array.isArray(msg.content)) return { batchText: null, batchedIndices }\n\n const parts = msg.content as ContentPart[]\n const textSegments: string[] = []\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]\n if (PASSTHROUGH_BLOCK_TYPES.has(part.type)) continue\n\n if (part.type === 'text' && typeof part.text === 'string' && part.text.trim()) {\n textSegments.push(part.text)\n batchedIndices.add(i)\n }\n\n if (part.type === 'tool_result' && compressToolResults) {\n // Never compress error tool_results — API requires non-empty content when is_error is true\n if (part.is_error) continue\n const extracted = extractToolResultText(part)\n if (extracted) {\n textSegments.push(extracted)\n batchedIndices.add(i)\n }\n }\n }\n\n return {\n batchText: textSegments.length > 0 ? textSegments.join('\\n\\n') : null,\n batchedIndices,\n }\n}\n\n/**\n * Rebuild a message with compressed text substituted into the original\n * structure. Preserves block ordering and tool_use_id pairing.\n */\nfunction reassembleMessage(\n msg: ChatCompletionMessage,\n compressedText: string,\n batchedIndices: Set<number>,\n): ChatCompletionMessage {\n // String content: simple replacement\n if (typeof msg.content === 'string') {\n return { ...msg, content: compressedText }\n }\n\n if (!Array.isArray(msg.content)) return msg\n\n const parts = msg.content as ContentPart[]\n const newParts: ContentPart[] = []\n let isFirstEligible = true\n\n for (let i = 0; i < parts.length; i++) {\n if (!batchedIndices.has(i)) {\n newParts.push(parts[i])\n continue\n }\n\n if (isFirstEligible) {\n if (parts[i].type === 'text') {\n newParts.push({ ...parts[i], text: compressedText })\n } else if (parts[i].type === 'tool_result') {\n newParts.push({ ...parts[i], content: compressedText })\n }\n isFirstEligible = false\n } else {\n // Remaining batched blocks: drop text, keep tool_result structure\n if (parts[i].type === 'tool_result') {\n // Preserve original content if is_error — API rejects empty error results\n const cleared = parts[i].is_error ? parts[i] : { ...parts[i], content: '' }\n newParts.push(cleared)\n }\n }\n }\n\n return { ...msg, content: newParts }\n}\n\n// ---------------------------------------------------------------------------\n// Pre-filtering: estimate compressible prose tokens\n// ---------------------------------------------------------------------------\n\n/**\n * Estimate how many tokens of prose (non-code) content a message contains\n * AFTER code-block segmentation. This lets us skip messages whose eligible\n * content is mostly code — avoiding a wasted API call that would just\n * return \"below threshold\" and eat into the latency budget.\n *\n * Uses chars/4 as a rough token estimate (good enough for filtering).\n */\nfunction estimateProseTokens(msg: ChatCompletionMessage, compressToolResults: boolean): number {\n const text = extractCompressibleText(msg, compressToolResults)\n if (!text) return 0\n\n const segments = segmentContent(text)\n return segments\n .filter((s) => s.type === 'prose')\n .reduce((sum, s) => sum + Math.ceil(s.text.length / 4), 0)\n}\n\n/**\n * Extract all compressible text from a message (same logic as\n * batchCompressMessage uses) without actually compressing anything.\n */\nfunction extractCompressibleText(msg: ChatCompletionMessage, compressToolResults: boolean): string | null {\n if (typeof msg.content === 'string') {\n return msg.content.trim() ? msg.content : null\n }\n\n if (!Array.isArray(msg.content)) return null\n\n const parts = msg.content as ContentPart[]\n const textSegments: string[] = []\n\n for (const part of parts) {\n if (PASSTHROUGH_BLOCK_TYPES.has(part.type)) continue\n\n if (part.type === 'text' && typeof part.text === 'string' && part.text.trim()) {\n textSegments.push(part.text)\n }\n\n if (part.type === 'tool_result' && compressToolResults) {\n const extracted = extractToolResultText(part)\n if (extracted) textSegments.push(extracted)\n }\n }\n\n return textSegments.length > 0 ? textSegments.join('\\n\\n') : null\n}\n\n// ---------------------------------------------------------------------------\n// Batch compression\n// ---------------------------------------------------------------------------\n\n/**\n * Extract all text from a tool_result block's content.\n * Returns null if no compressible text is found.\n */\nfunction extractToolResultText(part: ContentPart): string | null {\n if (typeof part.content === 'string' && part.content.trim()) {\n return part.content\n }\n if (Array.isArray(part.content)) {\n const texts = (part.content as ContentPart[])\n .filter((inner) => inner.type === 'text' && typeof inner.text === 'string' && (inner.text as string).trim())\n .map((inner) => inner.text as string)\n return texts.length > 0 ? texts.join('\\n') : null\n }\n return null\n}\n\n/**\n * Batch-compress all eligible text from a message into a single API call.\n *\n * Instead of compressing each text/tool_result block individually (which\n * results in many sub-threshold skips for small blocks), this:\n * 1. Extracts all eligible text from the message's content blocks\n * 2. Concatenates into a single string\n * 3. Makes ONE compressForLLM() call\n * 4. Places the compressed result as a text block, clears text from\n * batched blocks while preserving structure (tool_use_id pairing)\n */\nasync function batchCompressMessage(\n msg: ChatCompletionMessage,\n pipeline: CompressionPipeline,\n session: Session,\n record: RecordFn,\n options: ConversationCompressOptions = { compressToolResults: true },\n): Promise<ChatCompletionMessage> {\n // String content: compress directly (already one block)\n if (typeof msg.content === 'string') {\n return compressStringContent(msg, pipeline, session, record, options.semaphore, options.semaphoreTimeoutMs)\n }\n\n if (!Array.isArray(msg.content)) return msg\n\n const parts = msg.content as ContentPart[]\n\n // Collect all eligible text and track which parts contributed\n const textSegments: string[] = []\n const batchedIndices = new Set<number>()\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]\n if (PASSTHROUGH_BLOCK_TYPES.has(part.type)) continue\n\n if (part.type === 'text' && typeof part.text === 'string' && part.text.trim()) {\n textSegments.push(part.text)\n batchedIndices.add(i)\n }\n\n if (part.type === 'tool_result' && options.compressToolResults && !part.is_error) {\n const extracted = extractToolResultText(part)\n if (extracted) {\n textSegments.push(extracted)\n batchedIndices.add(i)\n }\n }\n }\n\n // Nothing to compress\n if (textSegments.length === 0) return msg\n\n // Concatenate all eligible text into one batch\n const batchText = textSegments.join('\\n\\n')\n\n try {\n const compressed = await compressTextWithSegmentation(batchText, pipeline, session, record, options.semaphore, options.semaphoreTimeoutMs)\n\n // Rebuild content array in-place to preserve block ordering.\n // The Anthropic API requires tool_result blocks to appear in the\n // same position (immediately after the corresponding tool_use\n // message). We MUST NOT prepend, append, remove, or reorder blocks.\n //\n // Strategy: put the compressed batch into the first eligible block,\n // clear text in remaining batched blocks, keep everything else as-is.\n // Build the output content array in-place.\n // - First eligible block gets the full compressed batch text.\n // - Remaining batched text blocks are REMOVED (API rejects empty text blocks).\n // - Remaining batched tool_result blocks keep structure with cleared content\n // (tool_use_id pairing must be preserved).\n // - Non-batched blocks (passthrough, non-eligible) are kept as-is.\n const newParts: ContentPart[] = []\n let isFirstEligible = true\n\n for (let i = 0; i < parts.length; i++) {\n if (!batchedIndices.has(i)) {\n // Not batched — keep as-is\n newParts.push(parts[i])\n continue\n }\n\n if (isFirstEligible) {\n // First eligible block gets the compressed text\n if (parts[i].type === 'text') {\n newParts.push({ ...parts[i], text: compressed })\n } else if (parts[i].type === 'tool_result') {\n newParts.push({ ...parts[i], content: compressed })\n }\n isFirstEligible = false\n } else {\n // Remaining batched blocks:\n // - text blocks: drop entirely (API rejects empty text blocks)\n // - tool_result: keep with empty content (preserves tool_use_id pairing)\n if (parts[i].type === 'tool_result') {\n // Preserve original content if is_error — API rejects empty error results\n const cleared = parts[i].is_error ? parts[i] : { ...parts[i], content: '' }\n newParts.push(cleared)\n }\n // text blocks are simply not pushed — removed from the array\n }\n }\n\n return { ...msg, content: newParts }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n session.recordFailure()\n throw err\n }\n session.recordFailure()\n return msg\n }\n}\n\n// ---------------------------------------------------------------------------\n// Per-block helpers (used by legacy compressMessages path)\n// ---------------------------------------------------------------------------\n\n/**\n * Compress a single message's content, handling both string and array forms.\n */\nasync function compressMessage(\n msg: ChatCompletionMessage,\n pipeline: CompressionPipeline,\n session: Session,\n record: RecordFn,\n options: ConversationCompressOptions = { compressToolResults: true },\n): Promise<ChatCompletionMessage> {\n if (typeof msg.content === 'string') {\n return compressStringContent(msg, pipeline, session, record)\n }\n\n if (Array.isArray(msg.content)) {\n return compressArrayContent(msg, pipeline, session, record, options)\n }\n\n return msg\n}\n\n/**\n * Compress plain-string message content with code-block segmentation.\n */\nasync function compressStringContent(\n msg: ChatCompletionMessage,\n pipeline: CompressionPipeline,\n session: Session,\n record: RecordFn,\n semaphore?: Semaphore,\n semaphoreTimeoutMs?: number,\n): Promise<ChatCompletionMessage> {\n const text = msg.content as string\n try {\n const compressed = await compressTextWithSegmentation(text, pipeline, session, record, semaphore, semaphoreTimeoutMs)\n return { ...msg, content: compressed }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n session.recordFailure()\n throw err\n }\n session.recordFailure()\n return msg\n }\n}\n\n/**\n * Compress array content blocks (text, tool_result). Skips thinking, tool_use, image.\n * Used by the legacy compressMessages() path.\n */\nasync function compressArrayContent(\n msg: ChatCompletionMessage,\n pipeline: CompressionPipeline,\n session: Session,\n record: RecordFn,\n options: ConversationCompressOptions = { compressToolResults: true },\n): Promise<ChatCompletionMessage> {\n const parts = msg.content as ContentPart[]\n\n const compressedParts = await Promise.all(\n parts.map(async (part) => {\n // Skip blocks that must not be modified\n if (PASSTHROUGH_BLOCK_TYPES.has(part.type)) return part\n\n // text block\n if (part.type === 'text' && typeof part.text === 'string') {\n try {\n const compressed = await compressTextWithSegmentation(part.text, pipeline, session, record)\n return { ...part, text: compressed }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n session.recordFailure()\n throw err\n }\n session.recordFailure()\n return part\n }\n }\n\n // tool_result block — compress if enabled (never compress error results)\n if (part.type === 'tool_result' && options.compressToolResults && !part.is_error) {\n return compressToolResult(part, pipeline, session, record)\n }\n\n // Unknown block type or disabled tool_result — pass through\n return part\n }),\n )\n\n return { ...msg, content: compressedParts }\n}\n\n/**\n * Compress text content within a tool_result block.\n * tool_result.content can be a plain string or an array of content blocks.\n * Used by the legacy compressMessages() path.\n */\nasync function compressToolResult(\n part: ContentPart,\n pipeline: CompressionPipeline,\n session: Session,\n record: RecordFn,\n): Promise<ContentPart> {\n const content = part.content\n\n // String content\n if (typeof content === 'string') {\n try {\n const compressed = await compressTextWithSegmentation(content, pipeline, session, record)\n return { ...part, content: compressed }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n session.recordFailure()\n throw err\n }\n session.recordFailure()\n return part\n }\n }\n\n // Nested content blocks (e.g. [{type:\"text\", text:\"...\"}])\n if (Array.isArray(content)) {\n try {\n const compressedInner = await Promise.all(\n (content as ContentPart[]).map(async (inner) => {\n if (inner.type === 'text' && typeof inner.text === 'string') {\n try {\n const compressed = await compressTextWithSegmentation(inner.text, pipeline, session, record)\n return { ...inner, text: compressed }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) throw err\n session.recordFailure()\n return inner\n }\n }\n return inner\n }),\n )\n return { ...part, content: compressedInner }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n session.recordFailure()\n throw err\n }\n session.recordFailure()\n return part\n }\n }\n\n return part\n}\n\n/**\n * Compress a text string, preserving code blocks verbatim.\n * When a semaphore is provided, each compressForLLM() call acquires a permit\n * first — this limits concurrent RSC API calls across all sessions.\n */\nasync function compressTextWithSegmentation(\n text: string,\n pipeline: CompressionPipeline,\n session: Session,\n record: RecordFn,\n semaphore?: Semaphore,\n semaphoreTimeoutMs?: number,\n): Promise<string> {\n const segments = segmentContent(text)\n const hasCode = segments.some((s) => s.type === 'code')\n\n if (!hasCode) {\n if (semaphore) await semaphore.acquire(semaphoreTimeoutMs)\n try {\n const result = await pipeline.compressForLLM(text)\n const originalTok = countTokens(text)\n const compressedTok = countTokens(sanitizeCompressedText(result.text))\n const saved = Math.max(0, originalTok - compressedTok)\n const realMetrics = { ...result.metrics, inputTokens: originalTok, outputTokens: compressedTok, tokensSaved: saved }\n session.recordCompression(realMetrics)\n record(!result.metrics.skipped, saved)\n return sanitizeCompressedText(result.text)\n } finally {\n if (semaphore) semaphore.release()\n }\n }\n\n const parts = await Promise.all(\n segments.map(async (seg) => {\n if (seg.type === 'code') return seg.text\n if (seg.text.trim().length === 0) return seg.text\n if (semaphore) await semaphore.acquire(semaphoreTimeoutMs)\n try {\n const result = await pipeline.compressForLLM(seg.text)\n const originalTok = countTokens(seg.text)\n const compressedTok = countTokens(sanitizeCompressedText(result.text))\n const saved = Math.max(0, originalTok - compressedTok)\n const realMetrics = { ...result.metrics, inputTokens: originalTok, outputTokens: compressedTok, tokensSaved: saved }\n session.recordCompression(realMetrics)\n record(!result.metrics.skipped, saved)\n return sanitizeCompressedText(result.text)\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) throw err\n session.recordFailure()\n return seg.text\n } finally {\n if (semaphore) semaphore.release()\n }\n }),\n )\n return parts.join('')\n}\n","/**\n * Content segmenter — splits mixed text into code and prose segments.\n * Code segments (fenced blocks, indented blocks) pass through compression\n * unchanged to avoid destructive normalization (casefold, punct strip, lemmatize).\n */\n\nexport interface ContentSegment {\n type: 'prose' | 'code'\n text: string\n}\n\n/**\n * Segment text content into code and prose blocks.\n *\n * Detection rules:\n * 1. Fenced code blocks: ``` or ~~~ (with optional language tag) through closing fence\n * 2. Indented code blocks: 4+ space or tab-indented contiguous lines\n * 3. Everything else → prose\n *\n * Round-trip invariant: segments.map(s => s.text).join('') === input\n */\nexport function segmentContent(text: string): ContentSegment[] {\n if (text.length === 0) return [{ type: 'prose', text: '' }]\n\n const segments: ContentSegment[] = []\n const lines = text.split('\\n')\n let i = 0\n let proseBuf: string[] = []\n\n function flushProse(): void {\n if (proseBuf.length > 0) {\n segments.push({ type: 'prose', text: proseBuf.join('\\n') })\n proseBuf = []\n }\n }\n\n while (i < lines.length) {\n const line = lines[i]\n\n // Check for fenced code block opening\n const fenceMatch = matchFenceOpen(line)\n if (fenceMatch) {\n // Before flushing prose, add the newline that separated prose from this fence\n if (proseBuf.length > 0) {\n // The newline before this line belongs to the prose segment\n flushProse()\n // Add the newline separator between prose and code\n segments[segments.length - 1].text += '\\n'\n }\n\n const codeBuf: string[] = [line]\n i++\n\n // Scan until closing fence of same type and length\n let closed = false\n while (i < lines.length) {\n codeBuf.push(lines[i])\n if (matchFenceClose(lines[i], fenceMatch.char, fenceMatch.length)) {\n closed = true\n i++\n break\n }\n i++\n }\n\n // Add trailing newline if not at end of input\n let codeText = codeBuf.join('\\n')\n if (i < lines.length) {\n codeText += '\\n'\n }\n\n segments.push({ type: 'code', text: codeText })\n continue\n }\n\n // Check for indented code block (4+ spaces or tab)\n if (isIndentedCodeLine(line)) {\n if (proseBuf.length > 0) {\n flushProse()\n segments[segments.length - 1].text += '\\n'\n }\n\n const codeBuf: string[] = [line]\n i++\n\n // Consume contiguous indented lines (allow blank lines within)\n while (i < lines.length) {\n if (isIndentedCodeLine(lines[i])) {\n codeBuf.push(lines[i])\n i++\n } else if (lines[i].trim() === '' && i + 1 < lines.length && isIndentedCodeLine(lines[i + 1])) {\n // Blank line between indented lines — still part of code block\n codeBuf.push(lines[i])\n i++\n } else {\n break\n }\n }\n\n let codeText = codeBuf.join('\\n')\n if (i < lines.length) {\n codeText += '\\n'\n }\n\n segments.push({ type: 'code', text: codeText })\n continue\n }\n\n // Regular prose line\n if (proseBuf.length > 0) {\n proseBuf.push(line)\n } else {\n proseBuf.push(line)\n }\n i++\n }\n\n // Flush remaining prose\n if (proseBuf.length > 0) {\n flushProse()\n }\n\n // Ensure at least one segment\n if (segments.length === 0) {\n return [{ type: 'prose', text }]\n }\n\n return segments\n}\n\ninterface FenceInfo {\n char: string\n length: number\n}\n\nfunction matchFenceOpen(line: string): FenceInfo | null {\n // Match ``` or ~~~ with optional language tag, allowing leading whitespace (0-3 spaces)\n const match = line.match(/^( {0,3})((`{3,})|~{3,})(.*)$/)\n if (!match) return null\n\n const fenceStr = match[2]\n const char = fenceStr[0]\n\n // Backtick fences: info string must not contain backticks\n if (char === '`' && match[4] && match[4].includes('`')) return null\n\n return { char, length: fenceStr.length }\n}\n\nfunction matchFenceClose(line: string, char: string, minLength: number): boolean {\n const match = line.match(/^( {0,3})((`{3,})|(~{3,}))\\s*$/)\n if (!match) return false\n const fenceStr = match[2]\n return fenceStr[0] === char && fenceStr.length >= minLength\n}\n\nfunction isIndentedCodeLine(line: string): boolean {\n // 4+ spaces or starts with tab (and not blank)\n return (line.startsWith(' ') || line.startsWith('\\t')) && line.trim().length > 0\n}\n","import type { ChatCompletionMessage, ContentPart } from '../types.js'\n\nexport type MessageTier = 'hot' | 'warm' | 'cold'\n\nexport interface TieredMessage {\n index: number\n message: ChatCompletionMessage\n tier: MessageTier\n eligibleTokens: number\n}\n\nexport interface ConversationPlan {\n messages: TieredMessage[]\n totalEligibleTokens: number\n shouldCompress: boolean\n hotCount: number\n warmCount: number\n coldCount: number\n}\n\nexport interface TierConfig {\n hotFraction: number\n coldFraction: number\n aggregateThreshold: number\n compressRoles: Set<string>\n compressToolResults: boolean\n}\n\n/**\n * Content block types that should never be compressed.\n * tool_use contains structured JSON input; thinking contains reasoning chains.\n */\nconst SKIP_BLOCK_TYPES = new Set(['thinking', 'tool_use', 'image'])\n\n/**\n * Estimate token count for a string using the 4-chars-per-token heuristic.\n */\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4)\n}\n\n/**\n * Estimate eligible (compressible) tokens in a single content block.\n */\nfunction estimateBlockTokens(block: ContentPart, compressToolResults: boolean): number {\n if (SKIP_BLOCK_TYPES.has(block.type)) return 0\n\n // text block\n if (block.type === 'text' && typeof block.text === 'string') {\n return estimateTokens(block.text)\n }\n\n // tool_result block — content can be string or nested blocks (never compress error results)\n if (block.type === 'tool_result' && compressToolResults && !block.is_error) {\n if (typeof block.content === 'string') {\n return estimateTokens(block.content)\n }\n if (Array.isArray(block.content)) {\n return (block.content as ContentPart[]).reduce(\n (sum, inner) => sum + estimateBlockTokens(inner, compressToolResults),\n 0,\n )\n }\n }\n\n return 0\n}\n\n/**\n * Estimate eligible tokens in a message's content.\n */\nfunction estimateMessageTokens(msg: ChatCompletionMessage, config: TierConfig): number {\n if (!config.compressRoles.has(msg.role)) return 0\n\n if (typeof msg.content === 'string') {\n return estimateTokens(msg.content)\n }\n\n if (Array.isArray(msg.content)) {\n return (msg.content as ContentPart[]).reduce(\n (sum, part) => sum + estimateBlockTokens(part, config.compressToolResults),\n 0,\n )\n }\n\n return 0\n}\n\n/**\n * Assign a tier to each message based on its position in the conversation.\n *\n * Messages are ordered oldest-first (index 0 = oldest). The last `hotFraction`\n * of messages are HOT (verbatim), the first `coldFraction` are COLD, and\n * everything in between is WARM.\n *\n * For short conversations (< 5 messages), all messages are HOT to avoid\n * compressing context before there's enough to matter.\n */\nexport function analyzeConversation(\n messages: ChatCompletionMessage[],\n config: TierConfig,\n): ConversationPlan {\n const n = messages.length\n\n // Short conversations: everything is hot, skip analysis\n if (n < 5) {\n const tiered: TieredMessage[] = messages.map((msg, i) => ({\n index: i,\n message: msg,\n tier: 'hot' as MessageTier,\n eligibleTokens: estimateMessageTokens(msg, config),\n }))\n return {\n messages: tiered,\n totalEligibleTokens: 0,\n shouldCompress: false,\n hotCount: n,\n warmCount: 0,\n coldCount: 0,\n }\n }\n\n // Compute tier boundaries (message indices)\n const coldEnd = Math.floor(n * config.coldFraction)\n const hotStart = n - Math.floor(n * config.hotFraction)\n\n let totalEligibleTokens = 0\n let hotCount = 0\n let warmCount = 0\n let coldCount = 0\n\n const tiered: TieredMessage[] = messages.map((msg, i) => {\n let tier: MessageTier\n if (i >= hotStart) {\n tier = 'hot'\n hotCount++\n } else if (i < coldEnd) {\n tier = 'cold'\n coldCount++\n } else {\n tier = 'warm'\n warmCount++\n }\n\n const eligibleTokens = estimateMessageTokens(msg, config)\n\n // Only WARM and COLD messages contribute to compression budget\n if (tier !== 'hot') {\n totalEligibleTokens += eligibleTokens\n }\n\n return { index: i, message: msg, tier, eligibleTokens }\n })\n\n return {\n messages: tiered,\n totalEligibleTokens,\n shouldCompress: totalEligibleTokens >= config.aggregateThreshold,\n hotCount,\n warmCount,\n coldCount,\n }\n}\n","import type { CompressionPipeline } from '@cognisos/rsc-sdk'\n\n/**\n * Creates a buffer that accumulates streamed response text and triggers\n * background learning when the stream completes.\n */\nexport function createStreamLearningBuffer(pipeline: CompressionPipeline) {\n let buffer = ''\n\n return {\n /** Append a text delta from an SSE chunk */\n append(text: string): void {\n buffer += text\n },\n\n /** Flush the buffer — triggers fire-and-forget learning */\n flush(): void {\n if (buffer.length > 0) {\n pipeline.triggerLearning(buffer)\n buffer = ''\n }\n },\n\n /** Get current buffer contents (for testing) */\n getBuffer(): string {\n return buffer\n },\n }\n}\n","import * as http from 'node:http'\n\n/**\n * Pipe an SSE response from an upstream LLM to the client,\n * parsing content deltas for the learning buffer.\n *\n * When totalTokensSaved > 0, intercepts the final usage chunk to adjust\n * prompt_tokens and total_tokens to reflect the pre-compression token count.\n *\n * Writes each chunk immediately — zero buffering, zero added latency\n * (except for the single usage chunk which may get rewritten).\n */\nexport async function pipeSSEResponse(\n upstreamResponse: Response,\n clientRes: http.ServerResponse,\n onContentDelta: (text: string) => void,\n onComplete: () => void,\n totalTokensSaved = 0,\n): Promise<void> {\n clientRes.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'Access-Control-Allow-Origin': '*',\n })\n\n const reader = upstreamResponse.body!.getReader()\n const decoder = new TextDecoder()\n let lineBuf = ''\n const needsAdjustment = totalTokensSaved > 0\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n\n // Fast path: no token adjustment needed\n if (!needsAdjustment) {\n clientRes.write(chunk)\n\n lineBuf += chunk\n const lines = lineBuf.split('\\n')\n lineBuf = lines.pop() || ''\n\n for (const line of lines) {\n if (line.startsWith('data: ') && line !== 'data: [DONE]') {\n try {\n const json = JSON.parse(line.slice(6))\n const content = json?.choices?.[0]?.delta?.content\n if (typeof content === 'string') {\n onContentDelta(content)\n }\n } catch {\n // Malformed SSE data — ignore for learning\n }\n }\n }\n continue\n }\n\n // Slow path: check each data line for usage to adjust\n lineBuf += chunk\n const lines = lineBuf.split('\\n')\n lineBuf = lines.pop() || ''\n\n let adjusted = false\n const outputLines: string[] = []\n\n for (const line of lines) {\n if (line.startsWith('data: ') && line !== 'data: [DONE]') {\n try {\n const json = JSON.parse(line.slice(6))\n\n // Check for usage in this chunk (OpenAI sends it in the final chunk)\n if (json?.usage?.prompt_tokens != null) {\n json.usage.prompt_tokens += totalTokensSaved\n if (json.usage.total_tokens != null) {\n json.usage.total_tokens += totalTokensSaved\n }\n outputLines.push(`data: ${JSON.stringify(json)}`)\n adjusted = true\n } else {\n outputLines.push(line)\n }\n\n // Learning: extract content deltas\n const content = json?.choices?.[0]?.delta?.content\n if (typeof content === 'string') {\n onContentDelta(content)\n }\n } catch {\n outputLines.push(line)\n }\n } else {\n outputLines.push(line)\n }\n }\n\n if (adjusted) {\n const reconstructed = outputLines.join('\\n') + '\\n'\n clientRes.write(reconstructed)\n } else {\n clientRes.write(chunk)\n }\n }\n } finally {\n clientRes.end()\n onComplete()\n }\n}\n","/**\n * User-facing terminology for CLI log output.\n *\n * Mirrors web/src/lib/terminology.ts — kept in sync manually\n * since web and CLI are separate packages with no shared dependency.\n *\n * Source of truth: GitHub issue #55\n */\n\n// ── Memory tier labels ────────────────────────────────────────────\n\nexport const TIER_LABELS = {\n HOT: 'Active',\n WARM: 'Recent',\n COLD: 'Archived',\n} as const\n\n// ── Log tag formatting helpers ────────────────────────────────────\n\nexport function formatTiersLog(hot: number, warm: number, cold: number, eligibleTokens: number): string {\n return `[MEMORY] ${TIER_LABELS.HOT}:${hot} ${TIER_LABELS.WARM}:${warm} ${TIER_LABELS.COLD}:${cold} · ${eligibleTokens} tokens eligible`\n}\n\nexport function formatSavedLog(tokensSaved: number, latencyMs: number): string {\n return `[SAVED] ${tokensSaved} tokens (${latencyMs}ms)`\n}\n\nexport function formatDegradeLog(): string {\n return '[STATUS] Connection degraded — passing through directly'\n}\n\nexport function formatResponseLog(model: string, tokensSaved: number, streaming = false): string {\n return `[RESPONSE] ${streaming ? 'Streaming ' : ''}${model} response → client (saved:${tokensSaved}tok)`\n}\n","import * as http from 'node:http'\nimport { RSCCircuitOpenError } from '@cognisos/rsc-sdk'\nimport { compressConversation, type ConversationCompressOptions } from '../rsc/message-compressor.js'\nimport { analyzeConversation } from '../rsc/conversation-analyzer.js'\nimport { createStreamLearningBuffer } from '../rsc/learning.js'\nimport { pipeAnthropicSSEResponse, type AnthropicUsage } from './anthropic-streaming.js'\nimport type { RSCPipelineWrapper } from '../rsc/pipeline.js'\nimport type { ChatCompletionMessage, ResolvedConfig } from '../types.js'\nimport type { AnthropicMessagesRequest, AnthropicMessage, AnthropicContentBlock } from '../types/anthropic.js'\nimport { formatTiersLog, formatSavedLog, formatDegradeLog, formatResponseLog } from '../terminology.js'\nimport type { Logger } from './handler.js'\nimport type { Semaphore } from '../rsc/semaphore.js'\nimport type { LatencyMonitor } from '../rsc/latency-monitor.js'\n\nfunction setCORSHeaders(res: http.ServerResponse): void {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key, anthropic-version, anthropic-beta, x-liminal-session')\n}\n\nfunction sendAnthropicError(res: http.ServerResponse, status: number, type: string, message: string): void {\n setCORSHeaders(res)\n res.writeHead(status, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ type: 'error', error: { type, message } }))\n}\n\n/**\n * Extract auth headers from incoming request.\n * Supports both x-api-key (API users) and Authorization: Bearer (subscription/OAuth users).\n */\nfunction extractAuthHeaders(req: http.IncomingMessage): Record<string, string> {\n const headers: Record<string, string> = {}\n\n const xApiKey = req.headers['x-api-key']\n if (typeof xApiKey === 'string' && xApiKey.length > 0) {\n headers['x-api-key'] = xApiKey\n }\n\n const auth = req.headers['authorization']\n if (typeof auth === 'string' && auth.length > 0) {\n headers['Authorization'] = auth\n }\n\n return headers\n}\n\n/**\n * Convert Anthropic messages to ChatCompletionMessage[] for the compressor.\n * The structures are compatible — this is a thin adapter.\n */\nfunction convertAnthropicToCompressible(messages: AnthropicMessage[]): ChatCompletionMessage[] {\n return messages.map((msg) => ({\n role: msg.role,\n content: msg.content as string | AnthropicContentBlock[],\n }))\n}\n\n/**\n * Convert compressed ChatCompletionMessage[] back to Anthropic format.\n */\nfunction convertCompressedToAnthropic(messages: ChatCompletionMessage[]): AnthropicMessage[] {\n return messages.map((msg) => ({\n role: msg.role as 'user' | 'assistant',\n content: msg.content as string | AnthropicContentBlock[],\n }))\n}\n\nexport async function handleAnthropicMessages(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: unknown,\n pipeline: RSCPipelineWrapper,\n config: ResolvedConfig,\n logger: Logger,\n semaphore: Semaphore,\n latencyMonitor: LatencyMonitor,\n sessionKey: string,\n onUsage?: (usage: AnthropicUsage, verifiedSaved: number, originalInputTokens: number) => void,\n stickyCache?: Map<string, string>,\n): Promise<void> {\n const request = body as AnthropicMessagesRequest\n\n // Validate required fields\n if (!request.messages || !Array.isArray(request.messages)) {\n sendAnthropicError(res, 400, 'invalid_request_error', 'messages is required and must be an array')\n return\n }\n\n if (typeof request.max_tokens !== 'number') {\n sendAnthropicError(res, 400, 'invalid_request_error', 'max_tokens is required')\n return\n }\n\n // Extract auth headers (x-api-key for API users, Authorization for subscription/OAuth)\n const authHeaders = extractAuthHeaders(req)\n if (Object.keys(authHeaders).length === 0) {\n sendAnthropicError(res, 401, 'authentication_error', 'Authentication required (x-api-key or Authorization header)')\n return\n }\n\n // Count original input tokens before compression (Anthropic tokenizer = ground truth)\n // Tokenize the full request body (system + messages + tools) to match what Anthropic counts\n const { countTokens: countTok } = await import('../rsc/tokenizer.js')\n const originalInputTokens = countTok(JSON.stringify(request))\n\n // Analyze conversation and compress by tier\n let messages = request.messages\n let anyCompressed = false\n let totalTokensSaved = 0\n\n if (config.enabled && !pipeline.isCircuitOpen()) {\n const compressStart = Date.now()\n try {\n const compressRoles = new Set(config.compressRoles)\n const compressible = convertAnthropicToCompressible(request.messages)\n\n const plan = analyzeConversation(compressible, {\n hotFraction: config.hotFraction,\n coldFraction: config.coldFraction,\n aggregateThreshold: config.aggregateThreshold,\n compressRoles,\n compressToolResults: config.compressToolResults,\n })\n\n if (plan.shouldCompress) {\n logger.log(formatTiersLog(plan.hotCount, plan.warmCount, plan.coldCount, plan.totalEligibleTokens))\n }\n\n // Collect block stats for a compact summary instead of per-block logging\n let batchedCount = 0\n let batchedProseTok = 0\n let skippedCount = 0\n let hotCount = 0\n let compressError = ''\n const blockLogFn = (msg: string) => {\n if (msg.includes('[COMPRESS-ERROR]')) {\n compressError = msg\n } else if (msg.includes('batching)')) {\n batchedCount++\n const proseMatch = msg.match(/~(\\d+) prose tok/)\n if (proseMatch) batchedProseTok += parseInt(proseMatch[1], 10)\n } else if (msg.includes('skip)')) {\n skippedCount++\n } else if (msg.includes('HOT')) {\n hotCount++\n }\n }\n\n const result = await compressConversation(\n pipeline.pipeline,\n pipeline.session,\n plan,\n {\n compressToolResults: config.compressToolResults,\n compressionThreshold: config.compressionThreshold,\n logFn: blockLogFn,\n semaphore,\n semaphoreTimeoutMs: config.concurrencyTimeoutMs,\n stickyCache,\n },\n )\n\n const totalBlocks = batchedCount + skippedCount + hotCount\n logger.log(`[COMPRESS] ${totalBlocks} blocks: ${batchedCount} batched (${batchedProseTok.toLocaleString()} prose tok) · ${skippedCount} skipped · ${hotCount} hot`)\n if (compressError) logger.log(compressError)\n messages = convertCompressedToAnthropic(result.messages)\n anyCompressed = result.anyCompressed\n totalTokensSaved = result.totalTokensSaved\n\n const latencyMs = Date.now() - compressStart\n const alert = latencyMonitor.record(sessionKey, latencyMs)\n if (alert) {\n logger.log(`[LATENCY] ${alert.type.toUpperCase()}: ${alert.message}`)\n }\n\n if (result.totalTokensSaved > 0) {\n logger.log(formatSavedLog(result.totalTokensSaved, latencyMs))\n }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n logger.log(formatDegradeLog())\n } else {\n logger.log(`[ERROR] Compression failed: ${err instanceof Error ? err.message : String(err)}`)\n }\n messages = request.messages\n }\n }\n\n // Build upstream request\n const upstreamUrl = `${config.anthropicUpstreamUrl}/v1/messages`\n const upstreamBody = { ...request, messages }\n\n // Tokenize the post-compression request to get the real delta\n const compressedInputTokens = countTok(JSON.stringify(upstreamBody))\n const verifiedTokensSaved = Math.max(0, originalInputTokens - compressedInputTokens)\n\n const upstreamHeaders: Record<string, string> = {\n ...authHeaders,\n 'anthropic-version': (req.headers['anthropic-version'] as string) || '2023-06-01',\n 'Content-Type': 'application/json',\n }\n\n // Forward anthropic-beta header if present\n const betaHeader = req.headers['anthropic-beta']\n if (typeof betaHeader === 'string') {\n upstreamHeaders['anthropic-beta'] = betaHeader\n }\n\n // Log request details for debugging\n const authTypes = Object.keys(authHeaders).join(', ') || 'none'\n logger.log(`[ANTHROPIC] ${request.model} → ${upstreamUrl} (auth: ${authTypes})`)\n\n try {\n const upstreamResponse = await fetch(upstreamUrl, {\n method: 'POST',\n headers: upstreamHeaders,\n body: JSON.stringify(upstreamBody),\n })\n\n // Handle upstream errors\n if (!upstreamResponse.ok) {\n const errorBody = await upstreamResponse.text()\n logger.log(`[ANTHROPIC] Upstream error ${upstreamResponse.status}: ${errorBody.slice(0, 500)}`)\n setCORSHeaders(res)\n res.writeHead(upstreamResponse.status, {\n 'Content-Type': upstreamResponse.headers.get('Content-Type') || 'application/json',\n })\n res.end(errorBody)\n return\n }\n\n // Streaming response\n if (request.stream && upstreamResponse.body) {\n // Always buffer for learning — even when no compression savings yet,\n // learning discovers patterns that enable future compression.\n const learningBuffer = createStreamLearningBuffer(pipeline.pipeline)\n\n logger.log(formatResponseLog(request.model, totalTokensSaved, true))\n await pipeAnthropicSSEResponse(\n upstreamResponse,\n res,\n (text) => learningBuffer?.append(text),\n () => learningBuffer?.flush(),\n totalTokensSaved,\n onUsage\n ? (usage) => {\n onUsage(usage, verifiedTokensSaved, originalInputTokens)\n logger.log(`[TOKENS] input: ${usage.inputTokens} | output: ${usage.outputTokens} | verified_saved: ${verifiedTokensSaved} | orig_tok: ${originalInputTokens} | comp_tok: ${compressedInputTokens}`)\n }\n : undefined,\n )\n return\n }\n\n // Non-streaming response\n const responseBody = await upstreamResponse.text()\n logger.log(formatResponseLog(request.model, totalTokensSaved))\n\n // Capture actual usage + adjust input_tokens for client\n let finalBody = responseBody\n try {\n const parsed = JSON.parse(responseBody)\n if (parsed?.usage) {\n const actualInput = (parsed.usage.input_tokens ?? 0)\n + (parsed.usage.cache_creation_input_tokens ?? 0)\n + (parsed.usage.cache_read_input_tokens ?? 0)\n const actualOutput = parsed.usage.output_tokens ?? 0\n if (onUsage) {\n onUsage({ inputTokens: actualInput, outputTokens: actualOutput }, verifiedTokensSaved, originalInputTokens)\n logger.log(`[TOKENS] input: ${actualInput} | output: ${actualOutput} | verified_saved: ${verifiedTokensSaved} | orig_tok: ${originalInputTokens} | comp_tok: ${compressedInputTokens}`)\n }\n if (totalTokensSaved > 0 && parsed.usage.input_tokens != null) {\n parsed.usage.input_tokens += totalTokensSaved\n finalBody = JSON.stringify(parsed)\n }\n }\n } catch {\n // Pass through unmodified on parse error\n }\n\n setCORSHeaders(res)\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(finalBody)\n\n // Trigger learning from response (fire-and-forget).\n // Always learn — even when no compression savings yet, learning discovers\n // patterns that enable future compression (bootstrap the pattern_map).\n {\n try {\n const parsed = JSON.parse(responseBody)\n const textBlocks = parsed?.content?.filter(\n (b: AnthropicContentBlock) => b.type === 'text' && typeof b.text === 'string',\n )\n const content = textBlocks?.map((b: AnthropicContentBlock) => b.text).join('')\n if (typeof content === 'string' && content.length > 0) {\n pipeline.pipeline.triggerLearning(content)\n }\n } catch {\n // Ignore learning parse errors\n }\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n logger.log(`[ERROR] Upstream request failed: ${message}`)\n if (!res.headersSent) {\n sendAnthropicError(res, 502, 'api_error', `Failed to reach upstream: ${message}`)\n }\n }\n}\n","import * as http from 'node:http'\n\n/** Actual token counts from the Anthropic API response. */\nexport interface AnthropicUsage {\n /** input_tokens from message_start (post-compression actual) */\n inputTokens: number\n /** output_tokens from message_delta (generated tokens) */\n outputTokens: number\n}\n\n/**\n * Parse a message_start data line for usage.input_tokens.\n * Returns [adjustedLine, actualInputTokens] or [null, null].\n */\nfunction parseMessageStart(dataLine: string, tokensSaved: number): [string | null, number | null] {\n try {\n const json = JSON.parse(dataLine.slice(6)) // strip \"data: \"\n const usage = json?.message?.usage\n if (usage?.input_tokens != null) {\n // Total input = input_tokens + cache_creation + cache_read\n // (prompt caching splits the count across these fields)\n const actual =\n (usage.input_tokens as number) +\n ((usage.cache_creation_input_tokens as number) ?? 0) +\n ((usage.cache_read_input_tokens as number) ?? 0)\n if (tokensSaved > 0) {\n json.message.usage.input_tokens += tokensSaved\n return [`data: ${JSON.stringify(json)}`, actual]\n }\n return [null, actual] // no adjustment needed, but captured\n }\n } catch {\n // Malformed JSON\n }\n return [null, null]\n}\n\n/**\n * Parse a message_delta data line for usage.output_tokens.\n * Returns output_tokens or null.\n */\nfunction parseMessageDelta(dataLine: string): number | null {\n try {\n const json = JSON.parse(dataLine.slice(6))\n if (json?.usage?.output_tokens != null) {\n return json.usage.output_tokens as number\n }\n } catch {\n // Malformed JSON\n }\n return null\n}\n\n/**\n * Pipe an Anthropic SSE response from the upstream to the client,\n * parsing content_block_delta events for the learning buffer.\n *\n * Captures actual usage from the API:\n * - input_tokens from `message_start` event (beginning of stream)\n * - output_tokens from `message_delta` event (end of stream)\n *\n * When totalTokensSaved > 0, intercepts message_start to adjust\n * usage.input_tokens to reflect the pre-compression token count.\n *\n * Writes each chunk immediately — zero buffering, zero added latency\n * (except for the message_start chunk which may get rewritten).\n */\nexport async function pipeAnthropicSSEResponse(\n upstreamResponse: Response,\n clientRes: http.ServerResponse,\n onContentDelta: (text: string) => void,\n onComplete: () => void,\n totalTokensSaved = 0,\n onUsage?: (usage: AnthropicUsage) => void,\n): Promise<void> {\n clientRes.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'Access-Control-Allow-Origin': '*',\n })\n\n const reader = upstreamResponse.body!.getReader()\n const decoder = new TextDecoder()\n let lineBuf = ''\n let currentEvent = ''\n\n // Usage capture state\n let capturedInputTokens: number | null = null\n let capturedOutputTokens: number | null = null\n let inputAdjusted = false\n\n const needsAdjustment = totalTokensSaved > 0\n const needsCapture = !!onUsage\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n\n // Fast path: no adjustment needed AND input already captured (or not needed)\n // We still need the slow path until we've seen message_delta for output_tokens\n const inputDone = !needsAdjustment || inputAdjusted\n const captureDone = !needsCapture || (capturedInputTokens != null && capturedOutputTokens != null)\n\n if (inputDone && captureDone) {\n clientRes.write(chunk)\n\n // Still parse for learning\n lineBuf += chunk\n const lines = lineBuf.split('\\n')\n lineBuf = lines.pop() || ''\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n currentEvent = line.slice(7).trim()\n } else if (line.startsWith('data: ') && currentEvent === 'content_block_delta') {\n try {\n const json = JSON.parse(line.slice(6))\n if (json?.delta?.type === 'text_delta' && typeof json.delta.text === 'string') {\n onContentDelta(json.delta.text)\n }\n } catch {\n // Malformed data — ignore for learning\n }\n }\n }\n continue\n }\n\n // Slow path: parse for usage capture and/or input_tokens adjustment\n lineBuf += chunk\n const lines = lineBuf.split('\\n')\n lineBuf = lines.pop() || ''\n\n let lineModified = false\n const outputLines: string[] = []\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n currentEvent = line.slice(7).trim()\n outputLines.push(line)\n } else if (line.startsWith('data: ') && currentEvent === 'message_start' && capturedInputTokens == null) {\n // Capture input_tokens + optionally adjust\n const [adjusted, actual] = parseMessageStart(line, totalTokensSaved)\n if (actual != null) {\n capturedInputTokens = actual\n inputAdjusted = true\n if (adjusted && needsAdjustment) {\n outputLines.push(adjusted)\n lineModified = true\n } else {\n outputLines.push(line)\n }\n } else {\n outputLines.push(line)\n }\n } else if (line.startsWith('data: ') && currentEvent === 'message_delta' && capturedOutputTokens == null) {\n // Capture output_tokens from end-of-stream usage\n const outputTok = parseMessageDelta(line)\n if (outputTok != null) {\n capturedOutputTokens = outputTok\n }\n outputLines.push(line)\n\n // Learning: extract content deltas\n } else {\n outputLines.push(line)\n\n if (line.startsWith('data: ') && currentEvent === 'content_block_delta') {\n try {\n const json = JSON.parse(line.slice(6))\n if (json?.delta?.type === 'text_delta' && typeof json.delta.text === 'string') {\n onContentDelta(json.delta.text)\n }\n } catch {\n // Malformed data — ignore for learning\n }\n }\n }\n }\n\n if (lineModified) {\n const reconstructed = outputLines.join('\\n') + '\\n'\n clientRes.write(reconstructed)\n } else {\n clientRes.write(chunk)\n }\n }\n } finally {\n // Emit captured usage before closing\n if (onUsage && (capturedInputTokens != null || capturedOutputTokens != null)) {\n onUsage({\n inputTokens: capturedInputTokens ?? 0,\n outputTokens: capturedOutputTokens ?? 0,\n })\n }\n\n clientRes.end()\n onComplete()\n }\n}\n","import * as http from 'node:http'\nimport { RSCCircuitOpenError } from '@cognisos/rsc-sdk'\nimport { compressMessages } from '../rsc/message-compressor.js'\nimport { createStreamLearningBuffer } from '../rsc/learning.js'\nimport { pipeResponsesSSE } from './responses-streaming.js'\nimport type { RSCPipelineWrapper } from '../rsc/pipeline.js'\nimport type { ChatCompletionMessage, ResolvedConfig } from '../types.js'\nimport { formatSavedLog, formatDegradeLog, formatResponseLog } from '../terminology.js'\nimport type { Logger } from './handler.js'\nimport type { Semaphore } from '../rsc/semaphore.js'\nimport type { LatencyMonitor } from '../rsc/latency-monitor.js'\nimport type {\n ResponsesRequest,\n ResponsesInputItem,\n ResponsesMessageItem,\n ResponsesInputContent,\n ResponsesInputTextContent,\n ResponsesResponse,\n ResponsesOutputItem,\n ResponsesOutputMessage,\n} from '../types/responses.js'\n\nfunction setCORSHeaders(res: http.ServerResponse): void {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')\n}\n\nfunction sendJSON(res: http.ServerResponse, status: number, body: unknown): void {\n setCORSHeaders(res)\n res.writeHead(status, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(body))\n}\n\nfunction extractBearerToken(req: http.IncomingMessage): string | null {\n const auth = req.headers.authorization\n if (!auth || !auth.startsWith('Bearer ')) return null\n return auth.slice(7)\n}\n\n// ─── Input conversion ───────────────────────────────────────────────\n// Convert Responses API input items to ChatCompletionMessage[] for the\n// shared message compressor. Only message items with text content are\n// compressible — function call outputs, item references, images, and\n// files pass through unchanged.\n\nfunction isMessageItem(item: ResponsesInputItem): item is ResponsesMessageItem {\n return item.type === 'message'\n}\n\nfunction inputToCompressibleMessages(input: string | ResponsesInputItem[]): ChatCompletionMessage[] {\n // Simple string input\n if (typeof input === 'string') {\n return [{ role: 'user', content: input }]\n }\n\n const messages: ChatCompletionMessage[] = []\n\n for (const item of input) {\n if (!isMessageItem(item)) continue\n\n if (typeof item.content === 'string') {\n // Map 'developer' role → 'system' for the compressor\n const role = item.role === 'developer' ? 'system' : item.role\n messages.push({ role, content: item.content })\n } else if (Array.isArray(item.content)) {\n // Content array — extract text parts, preserve structure\n const role = item.role === 'developer' ? 'system' : item.role\n const parts = item.content.map((c: ResponsesInputContent) => {\n if (c.type === 'input_text') {\n return { type: 'text' as const, text: (c as ResponsesInputTextContent).text }\n }\n // Images and files pass through as non-text parts\n return c as unknown as { type: string; [key: string]: unknown }\n })\n messages.push({ role, content: parts })\n }\n }\n\n return messages\n}\n\n// ─── Apply compressed messages back to input ────────────────────────\n// After compression, we need to write the compressed text back into the\n// original Responses API input structure, preserving non-message items,\n// images, file references, etc.\n\nfunction applyCompressedToInput(\n originalInput: string | ResponsesInputItem[],\n compressedMessages: ChatCompletionMessage[],\n): string | ResponsesInputItem[] {\n // Simple string input — return compressed string directly\n if (typeof originalInput === 'string') {\n const first = compressedMessages[0]\n if (first && typeof first.content === 'string') {\n return first.content\n }\n return originalInput\n }\n\n // Array input — walk through and replace message items\n let msgIdx = 0\n const result: ResponsesInputItem[] = []\n\n for (const item of originalInput) {\n if (!isMessageItem(item)) {\n // Non-message items (function_call_output, item_reference, etc.) pass through\n result.push(item)\n continue\n }\n\n const compressed = compressedMessages[msgIdx]\n msgIdx++\n\n if (!compressed) {\n result.push(item)\n continue\n }\n\n if (typeof compressed.content === 'string') {\n result.push({\n ...item,\n content: compressed.content,\n } as ResponsesMessageItem)\n } else if (Array.isArray(compressed.content)) {\n // Convert back to Responses API content format\n const content: ResponsesInputContent[] = compressed.content.map((part) => {\n if (part.type === 'text' && 'text' in part) {\n return { type: 'input_text' as const, text: part.text as string }\n }\n return part as unknown as ResponsesInputContent\n })\n result.push({\n ...item,\n content,\n } as ResponsesMessageItem)\n } else {\n result.push(item)\n }\n }\n\n return result\n}\n\n// ─── Extract text from response output for learning ─────────────────\n\nfunction extractOutputText(output: ResponsesOutputItem[]): string {\n const texts: string[] = []\n for (const item of output) {\n if (item.type === 'message') {\n const msg = item as ResponsesOutputMessage\n for (const block of msg.content) {\n if (block.type === 'output_text' && typeof block.text === 'string') {\n texts.push(block.text)\n }\n }\n }\n }\n return texts.join('')\n}\n\n// ─── Main handler ───────────────────────────────────────────────────\n\nexport async function handleResponses(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: unknown,\n pipeline: RSCPipelineWrapper,\n config: ResolvedConfig,\n logger: Logger,\n semaphore: Semaphore,\n latencyMonitor: LatencyMonitor,\n sessionKey: string,\n): Promise<void> {\n const request = body as ResponsesRequest\n\n // Validate required fields\n if (request.input === undefined || request.input === null) {\n sendJSON(res, 400, {\n error: { message: 'input is required', type: 'invalid_request_error' },\n })\n return\n }\n\n // Extract LLM API key\n const llmApiKey = extractBearerToken(req)\n if (!llmApiKey) {\n sendJSON(res, 401, {\n error: { message: 'Authorization header with Bearer token is required', type: 'authentication_error' },\n })\n return\n }\n\n // ── Compress input ────────────────────────────────────────────\n let compressedInput = request.input\n let anyCompressed = false\n let totalTokensSaved = 0\n\n if (config.enabled && !pipeline.isCircuitOpen()) {\n const compressStart = Date.now()\n try {\n const compressRoles = new Set(config.compressRoles)\n const compressible = inputToCompressibleMessages(request.input)\n\n if (compressible.length > 0) {\n const result = await compressMessages(\n compressible,\n pipeline.pipeline,\n pipeline.session,\n compressRoles,\n )\n\n compressedInput = applyCompressedToInput(request.input, result.messages)\n anyCompressed = result.anyCompressed\n totalTokensSaved = result.totalTokensSaved\n\n const latencyMs = Date.now() - compressStart\n const alert = latencyMonitor.record(sessionKey, latencyMs)\n if (alert) {\n logger.log(`[LATENCY] ${alert.type.toUpperCase()}: ${alert.message}`)\n }\n\n if (result.totalTokensSaved > 0) {\n logger.log(formatSavedLog(result.totalTokensSaved, latencyMs))\n }\n }\n } catch (err) {\n if (err instanceof RSCCircuitOpenError) {\n logger.log(formatDegradeLog())\n } else {\n logger.log(`[ERROR] Compression failed: ${err instanceof Error ? err.message : String(err)}`)\n }\n compressedInput = request.input\n }\n }\n\n // ── Build upstream request ────────────────────────────────────\n const upstreamUrl = `${config.upstreamBaseUrl}/v1/responses`\n const upstreamBody = { ...request, input: compressedInput }\n\n const upstreamHeaders: Record<string, string> = {\n 'Authorization': `Bearer ${llmApiKey}`,\n 'Content-Type': 'application/json',\n }\n\n if (request.stream) {\n upstreamHeaders['Accept'] = 'text/event-stream'\n }\n\n logger.log(`[RESPONSES] ${request.model} → ${upstreamUrl}`)\n\n try {\n const upstreamResponse = await fetch(upstreamUrl, {\n method: 'POST',\n headers: upstreamHeaders,\n body: JSON.stringify(upstreamBody),\n })\n\n // Handle upstream errors\n if (!upstreamResponse.ok) {\n const errorBody = await upstreamResponse.text()\n logger.log(`[RESPONSES] Upstream error ${upstreamResponse.status}: ${errorBody.slice(0, 500)}`)\n setCORSHeaders(res)\n res.writeHead(upstreamResponse.status, {\n 'Content-Type': upstreamResponse.headers.get('Content-Type') || 'application/json',\n })\n res.end(errorBody)\n return\n }\n\n // ── Streaming response ────────────────────────────────────\n if (request.stream && upstreamResponse.body) {\n // Always buffer for learning — even when no compression savings yet,\n // learning discovers patterns that enable future compression.\n const learningBuffer = createStreamLearningBuffer(pipeline.pipeline)\n\n logger.log(formatResponseLog(request.model, totalTokensSaved, true))\n await pipeResponsesSSE(\n upstreamResponse,\n res,\n (text) => learningBuffer?.append(text),\n () => learningBuffer?.flush(),\n totalTokensSaved,\n )\n return\n }\n\n // ── Non-streaming response ────────────────────────────────\n const responseBody = await upstreamResponse.text()\n logger.log(formatResponseLog(request.model, totalTokensSaved))\n\n // Adjust usage to reflect pre-compression token count\n let finalBody = responseBody\n if (totalTokensSaved > 0) {\n try {\n const parsed = JSON.parse(responseBody) as ResponsesResponse\n if (parsed?.usage?.input_tokens != null) {\n parsed.usage.input_tokens += totalTokensSaved\n if (parsed.usage.total_tokens != null) {\n parsed.usage.total_tokens += totalTokensSaved\n }\n finalBody = JSON.stringify(parsed)\n logger.log(`[TOKENS] Adjusted input_tokens by +${totalTokensSaved}`)\n }\n } catch {\n // Pass through unmodified on parse error\n }\n }\n\n setCORSHeaders(res)\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(finalBody)\n\n // Trigger learning from response (fire-and-forget).\n // Always learn — pattern discovery must run even before compression produces savings.\n {\n try {\n const parsed = JSON.parse(responseBody) as ResponsesResponse\n if (parsed?.output) {\n const text = extractOutputText(parsed.output)\n if (text.length > 0) {\n pipeline.pipeline.triggerLearning(text)\n }\n }\n } catch {\n // Ignore learning parse errors\n }\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n logger.log(`[ERROR] Upstream request failed: ${message}`)\n if (!res.headersSent) {\n sendJSON(res, 502, {\n error: { message: `Failed to reach upstream LLM: ${message}`, type: 'server_error' },\n })\n }\n }\n}\n","import * as http from 'node:http'\n\n/**\n * Pipe an OpenAI Responses API SSE stream from upstream to the client.\n *\n * Responses API SSE format differs from Chat Completions:\n * - Each chunk has both `event:` and `data:` lines\n * - Text deltas arrive as `response.output_text.delta` events\n * - Usage is reported in the `response.completed` event\n * - Stream ends with `data: [DONE]`\n *\n * When totalTokensSaved > 0, adjusts usage.input_tokens in the\n * `response.completed` event to reflect pre-compression token count.\n *\n * Writes each chunk immediately — zero buffering, zero added latency\n * (except for the single response.completed chunk which may get rewritten).\n */\nexport async function pipeResponsesSSE(\n upstreamResponse: Response,\n clientRes: http.ServerResponse,\n onContentDelta: (text: string) => void,\n onComplete: () => void,\n totalTokensSaved = 0,\n): Promise<void> {\n clientRes.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'Access-Control-Allow-Origin': '*',\n })\n\n const reader = upstreamResponse.body!.getReader()\n const decoder = new TextDecoder()\n let lineBuf = ''\n let currentEvent = ''\n let usageAdjusted = false\n const needsAdjustment = totalTokensSaved > 0\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n\n // Fast path: no adjustment needed (or already done), write immediately\n if (!needsAdjustment || usageAdjusted) {\n clientRes.write(chunk)\n\n // Still parse for learning\n lineBuf += chunk\n const lines = lineBuf.split('\\n')\n lineBuf = lines.pop() || ''\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n currentEvent = line.slice(7).trim()\n } else if (line.startsWith('data: ') && currentEvent === 'response.output_text.delta') {\n try {\n const json = JSON.parse(line.slice(6))\n if (typeof json?.delta === 'string') {\n onContentDelta(json.delta)\n }\n } catch {\n // Malformed data — ignore for learning\n }\n }\n }\n continue\n }\n\n // Slow path: need to check for response.completed to adjust usage\n lineBuf += chunk\n const lines = lineBuf.split('\\n')\n lineBuf = lines.pop() || ''\n\n let adjusted = false\n const outputLines: string[] = []\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n currentEvent = line.slice(7).trim()\n outputLines.push(line)\n } else if (\n line.startsWith('data: ') &&\n currentEvent === 'response.completed' &&\n !usageAdjusted\n ) {\n // Adjust usage in the response.completed event\n try {\n const json = JSON.parse(line.slice(6))\n if (json?.response?.usage?.input_tokens != null) {\n json.response.usage.input_tokens += totalTokensSaved\n if (json.response.usage.total_tokens != null) {\n json.response.usage.total_tokens += totalTokensSaved\n }\n outputLines.push(`data: ${JSON.stringify(json)}`)\n usageAdjusted = true\n adjusted = true\n } else {\n outputLines.push(line)\n }\n } catch {\n outputLines.push(line)\n }\n } else {\n outputLines.push(line)\n\n // Learning: extract text deltas\n if (line.startsWith('data: ') && currentEvent === 'response.output_text.delta') {\n try {\n const json = JSON.parse(line.slice(6))\n if (typeof json?.delta === 'string') {\n onContentDelta(json.delta)\n }\n } catch {\n // Malformed data — ignore for learning\n }\n }\n }\n }\n\n if (adjusted) {\n const reconstructed = outputLines.join('\\n') + '\\n'\n clientRes.write(reconstructed)\n } else {\n clientRes.write(chunk)\n }\n }\n } finally {\n clientRes.end()\n onComplete()\n }\n}\n","import * as http from 'node:http'\nimport * as crypto from 'node:crypto'\n\nexport interface SessionKey {\n connector: 'claude-code' | 'cursor' | 'codex' | 'openai-compatible' | 'unknown'\n windowHash: string\n raw: string\n}\n\nexport function identifySession(req: http.IncomingMessage, pathname: string): SessionKey {\n const connector = detectConnector(req, pathname)\n const windowHash = deriveWindowHash(req)\n return { connector, windowHash, raw: `${connector}:${windowHash}` }\n}\n\n// ─── Connector detection ──────────────────────────────────────────────\n\nfunction detectConnector(\n req: http.IncomingMessage,\n pathname: string,\n): SessionKey['connector'] {\n if (req.headers['x-api-key'] || req.headers['anthropic-version']) {\n return 'claude-code'\n }\n if (pathname.startsWith('/v1/responses') || pathname.startsWith('/responses')) {\n return 'codex'\n }\n const ua = req.headers['user-agent'] ?? ''\n if (/cursor/i.test(ua)) {\n return 'cursor'\n }\n return 'openai-compatible'\n}\n\n// ─── Window hash derivation ───────────────────────────────────────────\n\nfunction deriveWindowHash(req: http.IncomingMessage): string {\n // Explicit session header takes priority\n const liminalSession = req.headers['x-liminal-session']\n if (typeof liminalSession === 'string' && liminalSession.length > 0) {\n return liminalSession\n }\n\n // Extract credential from x-api-key or Authorization bearer token\n const credential = extractCredential(req)\n if (!credential) return 'anonymous'\n\n return crypto.createHash('sha256').update(credential).digest('hex').slice(0, 8)\n}\n\nfunction extractCredential(req: http.IncomingMessage): string | null {\n const apiKey = req.headers['x-api-key']\n if (typeof apiKey === 'string' && apiKey.length > 0) return apiKey\n\n const auth = req.headers['authorization']\n if (typeof auth === 'string') {\n const match = auth.match(/^Bearer\\s+(.+)$/i)\n if (match) return match[1]\n }\n\n return null\n}\n","/**\n * MITM interception allowlist.\n *\n * Only hosts in this list get TLS-intercepted for compression.\n * Everything else passes through as a plain TCP tunnel.\n */\n\nconst MITM_HOSTS = new Set([\n 'api.openai.com',\n 'api.anthropic.com',\n 'generativelanguage.googleapis.com',\n])\n\n/**\n * Check if a hostname should be MITM-intercepted for compression.\n */\nexport function shouldIntercept(hostname: string): boolean {\n return MITM_HOSTS.has(hostname)\n}\n\n/**\n * Get the list of intercepted hosts (for status display).\n */\nexport function getInterceptedHosts(): string[] {\n return [...MITM_HOSTS]\n}\n","import * as http from 'node:http'\nimport { handleChatCompletions } from './completions.js'\nimport { handleAnthropicMessages } from './messages.js'\nimport { handleResponses } from './responses.js'\nimport { identifySession } from './session-identity.js'\nimport { shouldIntercept } from '../tls/allowlist.js'\nimport type { SessionManager } from '../rsc/session-manager.js'\nimport type { Semaphore } from '../rsc/semaphore.js'\nimport type { LatencyMonitor } from '../rsc/latency-monitor.js'\nimport type { ResolvedConfig } from '../types.js'\nimport type { MitmStats } from '../tls/mitm-stats.js'\n\nexport interface Logger {\n log(message: string): void\n}\n\n/** Dependencies injected into the request handler. */\nexport interface HandlerDeps {\n sessions: SessionManager\n semaphore: Semaphore\n latencyMonitor: LatencyMonitor\n mitmStats: MitmStats\n config: ResolvedConfig\n logger: Logger\n /** Callback for verified token counts from Anthropic API responses */\n onUsage?: (usage: import('./anthropic-streaming.js').AnthropicUsage, verifiedSaved: number, originalInputTokens: number) => void\n /** Returns Cursor hook metrics for the health endpoint */\n getCursorMetrics?: () => import('../stats/aggregator.js').CursorMetrics | null\n /** Returns verified token stats for the health endpoint */\n getVerifiedTokens?: () => {\n actualInputTokens: number\n actualOutputTokens: number\n originalInputEstimate: number\n verifiedInputSaved: number\n verifiedSavingsRate: number\n verifiedRequestCount: number\n }\n}\n\nfunction setCORSHeaders(res: http.ServerResponse): void {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT, DELETE, PATCH')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key, anthropic-version, anthropic-beta, anthropic-dangerous-direct-browser-access, x-liminal-session')\n res.setHeader('Access-Control-Max-Age', '86400')\n}\n\nfunction sendJSON(res: http.ServerResponse, status: number, body: unknown): void {\n setCORSHeaders(res)\n res.writeHead(status, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(body))\n}\n\nfunction readBody(req: http.IncomingMessage): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = []\n req.on('data', (chunk: Buffer) => chunks.push(chunk))\n req.on('end', () => resolve(Buffer.concat(chunks)))\n req.on('error', reject)\n })\n}\n\n// ─── Upstream detection ──────────────────────────────────────────────\n\ntype UpstreamTarget = 'anthropic' | 'openai'\n\nfunction detectUpstream(req: http.IncomingMessage, url: string): UpstreamTarget {\n if (req.headers['x-api-key']) return 'anthropic'\n if (req.headers['anthropic-version']) return 'anthropic'\n if (url.startsWith('/v1/messages') || url.startsWith('/messages')) return 'anthropic'\n return 'openai'\n}\n\nfunction getUpstreamBaseUrl(target: UpstreamTarget, config: ResolvedConfig): string {\n return target === 'anthropic'\n ? config.anthropicUpstreamUrl\n : config.upstreamBaseUrl\n}\n\n// ─── Header forwarding ──────────────────────────────────────────────\n\nconst HOP_BY_HOP = new Set([\n 'host', 'connection', 'keep-alive', 'transfer-encoding',\n 'te', 'trailer', 'upgrade', 'proxy-authorization', 'proxy-authenticate',\n])\n\nfunction buildUpstreamHeaders(req: http.IncomingMessage): Record<string, string> {\n const headers: Record<string, string> = {}\n\n for (const [key, value] of Object.entries(req.headers)) {\n if (HOP_BY_HOP.has(key)) continue\n if (value === undefined) continue\n headers[key] = Array.isArray(value) ? value.join(', ') : value\n }\n\n return headers\n}\n\n// ─── MITM host detection ─────────────────────────────────────────────\n\n/**\n * Check if a request arrived via the MITM bridge (i.e. its Host header\n * is one of the intercepted domains). If so, we must forward to that\n * original host, not our configured upstream.\n */\nfunction getMitmUpstreamBase(req: http.IncomingMessage): string | null {\n const host = req.headers['host']\n if (!host) return null\n // Strip port if present\n const hostname = host.split(':')[0]\n if (shouldIntercept(hostname)) {\n return `https://${hostname}`\n }\n return null\n}\n\n// ─── Adaptive passthrough ────────────────────────────────────────────\n\nasync function passthroughToUpstream(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n fullUrl: string,\n config: ResolvedConfig,\n logger: Logger,\n): Promise<void> {\n // For MITM'd requests, forward to the original host, not our configured upstream\n const mitmBase = getMitmUpstreamBase(req)\n let upstreamUrl: string\n let target: string\n\n if (mitmBase) {\n upstreamUrl = `${mitmBase}${fullUrl}`\n target = req.headers['host'] ?? 'mitm'\n } else {\n const detected = detectUpstream(req, fullUrl)\n const upstreamBase = getUpstreamBaseUrl(detected, config)\n upstreamUrl = `${upstreamBase}${fullUrl}`\n target = detected\n }\n const method = req.method?.toUpperCase() ?? 'GET'\n\n // Only log passthrough detail for non-routine calls\n const passShort = fullUrl.split('/').pop()?.split('?')[0] ?? fullUrl\n const isRoutine = passShort === 'Batch' || passShort === 'rgstr'\n || passShort.includes('Metrics') || passShort.includes('Analytics')\n if (!isRoutine) {\n logger.log(`[PROXY] ${method} ${passShort} → ${target}`)\n }\n\n const headers = buildUpstreamHeaders(req)\n\n try {\n const hasBody = method !== 'GET' && method !== 'HEAD'\n const body = hasBody ? await readBody(req) : undefined\n\n const upstreamRes = await fetch(upstreamUrl, {\n method,\n headers,\n body,\n })\n\n const contentType = upstreamRes.headers.get('Content-Type') || 'application/json'\n const isStreaming = contentType.includes('text/event-stream')\n\n if (isStreaming && upstreamRes.body) {\n setCORSHeaders(res)\n res.writeHead(upstreamRes.status, {\n 'Content-Type': contentType,\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n })\n\n const reader = upstreamRes.body.getReader()\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n res.write(value)\n }\n } finally {\n res.end()\n }\n } else {\n const responseBody = await upstreamRes.arrayBuffer()\n setCORSHeaders(res)\n\n const responseHeaders: Record<string, string> = { 'Content-Type': contentType }\n const reqId = upstreamRes.headers.get('request-id')\n if (reqId) responseHeaders['request-id'] = reqId\n\n res.writeHead(upstreamRes.status, responseHeaders)\n res.end(Buffer.from(responseBody))\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n logger.log(`[ERROR] Passthrough to ${target} failed: ${message}`)\n if (!res.headersSent) {\n setCORSHeaders(res)\n res.writeHead(502, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({\n type: 'error',\n error: { type: 'api_error', message: `Liminal proxy: failed to reach ${target} upstream: ${message}` },\n }))\n }\n }\n}\n\nexport function createRequestHandler(\n deps: HandlerDeps,\n): (req: http.IncomingMessage, res: http.ServerResponse) => void {\n const { sessions, semaphore, latencyMonitor, mitmStats, config, logger } = deps\n const startTime = Date.now()\n\n return async (req, res) => {\n try {\n const method = req.method?.toUpperCase() ?? ''\n const fullUrl = req.url ?? ''\n const url = fullUrl.split('?')[0]\n\n const host = req.headers['host'] ?? 'unknown'\n const isMitm = !!getMitmUpstreamBase(req)\n\n // Condensed logging: full detail for LLM/chat endpoints, summary for noise\n const shortPath = url.split('/').pop() ?? url\n const contentType = req.headers['content-type'] ?? ''\n const isLikelyChat = shortPath.includes('Stream') || shortPath.includes('Chat')\n || shortPath.includes('completions') || shortPath.includes('messages')\n || shortPath.includes('Completion') || shortPath.includes('Generate')\n || shortPath.includes('Conversation') || shortPath.includes('Ask')\n || contentType.includes('text/event-stream')\n\n if (isLikelyChat) {\n const authType = req.headers['x-api-key'] ? 'x-api-key' : req.headers['authorization'] ? 'bearer' : 'none'\n logger.log(`[LLM] ${method} ${host}${fullUrl} (auth: ${authType}, content-type: ${contentType})`)\n } else if (isMitm && method !== 'OPTIONS') {\n // Compact log for MITM service calls\n logger.log(`[MITM-REQ] ${method} ${shortPath} → ${host}`)\n }\n\n // CORS preflight — for MITM'd requests, forward to original host\n if (method === 'OPTIONS') {\n if (getMitmUpstreamBase(req)) {\n await passthroughToUpstream(req, res, fullUrl, config, logger)\n } else {\n setCORSHeaders(res)\n res.writeHead(204)\n res.end()\n }\n return\n }\n\n // Health check — only for direct proxy requests, not MITM'd traffic\n if (method === 'GET' && (url === '/health' || url === '/') && !getMitmUpstreamBase(req)) {\n const sessionSummaries = sessions.getAllSummaries()\n sendJSON(res, 200, {\n status: 'ok',\n version: config.rscApiKey ? 'connected' : 'no-api-key',\n uptime_ms: Date.now() - startTime,\n concurrency: {\n active_sessions: sessions.activeCount,\n semaphore_available: semaphore.available,\n semaphore_waiting: semaphore.waiting,\n max_concurrent_rsc_calls: config.concurrencyLimit,\n },\n latency: {\n global_p95_ms: latencyMonitor.getGlobalP95(),\n },\n mitm: mitmStats.snapshot(),\n sessions: sessionSummaries.map(s => ({\n session_key: s.key,\n connector: s.connector,\n circuit_state: s.circuitState,\n tokens_processed: s.tokensProcessed,\n tokens_saved: s.tokensSaved,\n calls_total: s.totalCalls,\n calls_compressed: s.compressedCalls,\n calls_failed: s.failedCalls,\n p95_latency_ms: latencyMonitor.getSessionP95(s.key),\n last_active_ago_ms: Date.now() - s.lastAccessedAt,\n })),\n ...(deps.getVerifiedTokens ? deps.getVerifiedTokens() : {}),\n ...(deps.getCursorMetrics ? { cursor: deps.getCursorMetrics() } : {}),\n })\n return\n }\n\n // ── Identify session and resolve pipeline ────────────────────\n const sessionKey = identifySession(req, url)\n const { pipeline, stickyCache } = sessions.getOrCreate(sessionKey)\n\n // ── Compression routes ───────────────────────────────────────\n\n if (method === 'POST' && (url === '/v1/chat/completions' || url === '/chat/completions')) {\n const body = await readBody(req)\n let parsed: unknown\n try {\n parsed = JSON.parse(body.toString('utf-8'))\n } catch {\n sendJSON(res, 400, {\n error: { message: 'Invalid JSON body', type: 'invalid_request_error' },\n })\n return\n }\n\n await handleChatCompletions(req, res, parsed, pipeline, config, logger, semaphore, latencyMonitor, sessionKey.raw, stickyCache)\n return\n }\n\n if (method === 'POST' && (url === '/v1/responses' || url === '/responses')) {\n const body = await readBody(req)\n let parsed: unknown\n try {\n parsed = JSON.parse(body.toString('utf-8'))\n } catch {\n sendJSON(res, 400, {\n error: { message: 'Invalid JSON body', type: 'invalid_request_error' },\n })\n return\n }\n\n await handleResponses(req, res, parsed, pipeline, config, logger, semaphore, latencyMonitor, sessionKey.raw)\n return\n }\n\n if (method === 'POST' && (url === '/v1/messages' || url === '/messages')) {\n const body = await readBody(req)\n let parsed: unknown\n try {\n parsed = JSON.parse(body.toString('utf-8'))\n } catch {\n sendJSON(res, 400, {\n type: 'error',\n error: { type: 'invalid_request_error', message: 'Invalid JSON body' },\n })\n return\n }\n\n await handleAnthropicMessages(req, res, parsed, pipeline, config, logger, semaphore, latencyMonitor, sessionKey.raw, deps.onUsage, stickyCache)\n return\n }\n\n // ── Adaptive passthrough ─────────────────────────────────────\n await passthroughToUpstream(req, res, fullUrl, config, logger)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n logger.log(`[ERROR] Proxy handler error: ${message}`)\n if (!res.headersSent) {\n sendJSON(res, 500, {\n error: { message: 'Internal proxy error', type: 'server_error' },\n })\n }\n }\n }\n}\n","import * as http from 'node:http'\nimport * as net from 'node:net'\n\nconst MAX_PORT_RETRIES = 5\n\nexport type ConnectHandler = (\n req: http.IncomingMessage,\n socket: net.Socket,\n head: Buffer,\n) => void\n\nexport class ProxyServer {\n private server: http.Server | null = null\n private activePort: number | null = null\n private readonly requestedPort: number\n private readonly handler: (req: http.IncomingMessage, res: http.ServerResponse) => void\n private readonly connectHandler: ConnectHandler | null\n\n constructor(\n port: number,\n handler: (req: http.IncomingMessage, res: http.ServerResponse) => void,\n connectHandler?: ConnectHandler,\n ) {\n this.requestedPort = port\n this.handler = handler\n this.connectHandler = connectHandler ?? null\n }\n\n async start(): Promise<number> {\n let lastError: Error | null = null\n\n for (let attempt = 0; attempt < MAX_PORT_RETRIES; attempt++) {\n const port = this.requestedPort + attempt\n try {\n await this.listen(port)\n this.activePort = port\n return port\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err))\n if ((err as NodeJS.ErrnoException).code !== 'EADDRINUSE') {\n throw lastError\n }\n }\n }\n\n throw lastError ?? new Error(`All ports ${this.requestedPort}-${this.requestedPort + MAX_PORT_RETRIES - 1} in use`)\n }\n\n private listen(port: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const server = http.createServer(this.handler)\n\n // Wire up CONNECT handler for forward proxy mode (Cursor MITM)\n if (this.connectHandler) {\n server.on('connect', this.connectHandler)\n }\n\n server.on('error', reject)\n server.listen(port, '127.0.0.1', () => {\n server.removeListener('error', reject)\n this.server = server\n resolve()\n })\n })\n }\n\n async stop(): Promise<void> {\n if (!this.server) return\n return new Promise((resolve) => {\n this.server!.close(() => {\n this.server = null\n this.activePort = null\n resolve()\n })\n })\n }\n\n isRunning(): boolean {\n return this.server !== null && this.server.listening\n }\n\n getPort(): number | null {\n return this.activePort\n }\n\n /** Expose internal HTTP server for MITM bridge socket injection */\n getHttpServer(): http.Server | null {\n return this.server\n }\n}\n","import { appendFileSync, statSync, renameSync, mkdirSync, existsSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { LOG_FILE, LOG_DIR } from '../config/paths.js'\nimport type { Logger } from '../proxy/handler.js'\n\nconst MAX_LOG_SIZE = 10 * 1024 * 1024 // 10 MB\nconst MAX_BACKUPS = 2\n\nexport class FileLogger implements Logger {\n private readonly logFile: string\n private readonly mirrorStdout: boolean\n /** Once true, stop attempting file writes (avoids repeated EACCES spam) */\n private fileWriteDisabled = false\n\n constructor(options?: { logFile?: string; mirrorStdout?: boolean }) {\n this.logFile = options?.logFile ?? LOG_FILE\n this.mirrorStdout = options?.mirrorStdout ?? false\n\n // Ensure log directory exists\n const logDir = dirname(this.logFile)\n if (!existsSync(logDir)) {\n mkdirSync(logDir, { recursive: true })\n }\n }\n\n log(message: string): void {\n const timestamp = new Date().toISOString().slice(11, 23)\n const line = `[${timestamp}] ${message}\\n`\n\n if (!this.fileWriteDisabled) {\n try {\n appendFileSync(this.logFile, line)\n } catch {\n // Warn once, then fall back to stdout-only for the rest of the session\n this.fileWriteDisabled = true\n process.stderr.write(`[WARN] Cannot write to ${this.logFile} (permission denied?) — logging to stdout only. Fix: sudo chown $(whoami) ${this.logFile}\\n`)\n }\n }\n\n if (this.mirrorStdout || this.fileWriteDisabled) {\n process.stdout.write(line)\n }\n\n this.rotateIfNeeded()\n }\n\n private rotateIfNeeded(): void {\n try {\n const stats = statSync(this.logFile)\n if (stats.size <= MAX_LOG_SIZE) return\n\n // Rotate: liminal.log -> liminal.log.1 -> liminal.log.2 (drop oldest)\n for (let i = MAX_BACKUPS - 1; i >= 1; i--) {\n const from = `${this.logFile}.${i}`\n const to = `${this.logFile}.${i + 1}`\n if (existsSync(from)) renameSync(from, to)\n }\n renameSync(this.logFile, `${this.logFile}.1`)\n } catch {\n // Rotation failure is non-fatal\n }\n }\n\n getLogFile(): string {\n return this.logFile\n }\n}\n\n/**\n * A simple logger that only writes to stdout (for use during init or when log file isn't available).\n */\nexport class ConsoleLogger implements Logger {\n log(message: string): void {\n const timestamp = new Date().toISOString().slice(11, 23)\n process.stdout.write(`[${timestamp}] ${message}\\n`)\n }\n}\n","import type { SessionKey } from '../proxy/session-identity.js'\nimport { RSCPipelineWrapper } from './pipeline.js'\nimport type { PipelineConfig } from './pipeline.js'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SessionManagerConfig {\n pipelineConfig: PipelineConfig\n maxSessions: number\n sessionTtlMs: number\n onSessionCreated?: (key: string, pipeline: RSCPipelineWrapper) => void\n onSessionEvicted?: (key: string) => void\n}\n\nexport interface SessionHealthEntry {\n key: string\n connector: string\n circuitState: string\n tokensProcessed: number\n tokensSaved: number\n totalCalls: number\n compressedCalls: number\n failedCalls: number\n lastAccessedAt: number\n}\n\n/** Returned from getOrCreate() so callers get both the pipeline and its sticky cache. */\nexport interface SessionResult {\n pipeline: RSCPipelineWrapper\n /** Per-session memoization of compressed text (content-hash → compressed).\n * Ensures identical compressed output across turns, preserving Anthropic prefix caching. */\n stickyCache: Map<string, string>\n}\n\ninterface ManagedSession {\n pipeline: RSCPipelineWrapper\n stickyCache: Map<string, string>\n lastAccessedAt: number\n requestCount: number\n connector: string\n}\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_MAX_SESSIONS = 10\nconst DEFAULT_SESSION_TTL_MS = 30 * 60 * 1000 // 30 minutes\nconst EVICTION_INTERVAL_MS = 60_000 // 60 seconds\n\n// ---------------------------------------------------------------------------\n// SessionManager\n// ---------------------------------------------------------------------------\n\nexport class SessionManager {\n private readonly sessions = new Map<string, ManagedSession>()\n private readonly config: Required<Pick<SessionManagerConfig, 'maxSessions' | 'sessionTtlMs'>> &\n SessionManagerConfig\n private evictionTimer: ReturnType<typeof setInterval> | null = null\n\n constructor(config: SessionManagerConfig) {\n this.config = {\n ...config,\n maxSessions: config.maxSessions ?? DEFAULT_MAX_SESSIONS,\n sessionTtlMs: config.sessionTtlMs ?? DEFAULT_SESSION_TTL_MS,\n }\n\n this.evictionTimer = setInterval(() => this.evictStale(), EVICTION_INTERVAL_MS)\n // Allow the process to exit even if the timer is still running\n if (this.evictionTimer.unref) {\n this.evictionTimer.unref()\n }\n }\n\n // ── Public API ──────────────────────────────────────────────────────\n\n getOrCreate(key: SessionKey): SessionResult {\n const existing = this.sessions.get(key.raw)\n if (existing) {\n existing.lastAccessedAt = Date.now()\n existing.requestCount++\n return { pipeline: existing.pipeline, stickyCache: existing.stickyCache }\n }\n\n // At capacity — evict least-recently-used\n if (this.sessions.size >= this.config.maxSessions) {\n this.evictLRU()\n }\n\n const pipeline = new RSCPipelineWrapper({\n ...this.config.pipelineConfig,\n sessionId: key.raw,\n })\n const stickyCache = new Map<string, string>()\n\n this.sessions.set(key.raw, {\n pipeline,\n stickyCache,\n lastAccessedAt: Date.now(),\n requestCount: 1,\n connector: key.connector,\n })\n\n this.config.onSessionCreated?.(key.raw, pipeline)\n return { pipeline, stickyCache }\n }\n\n getAllSummaries(): SessionHealthEntry[] {\n const entries: SessionHealthEntry[] = []\n for (const [key, managed] of this.sessions) {\n entries.push(this.buildHealthEntry(key, managed))\n }\n return entries\n }\n\n getSessionSummary(key: string): SessionHealthEntry | null {\n const managed = this.sessions.get(key)\n if (!managed) return null\n return this.buildHealthEntry(key, managed)\n }\n\n get activeCount(): number {\n return this.sessions.size\n }\n\n shutdown(): void {\n if (this.evictionTimer !== null) {\n clearInterval(this.evictionTimer)\n this.evictionTimer = null\n }\n this.sessions.clear()\n }\n\n // ── Internals ───────────────────────────────────────────────────────\n\n private buildHealthEntry(key: string, managed: ManagedSession): SessionHealthEntry {\n const summary = managed.pipeline.getSessionSummary()\n return {\n key,\n connector: managed.connector,\n circuitState: managed.pipeline.getCircuitState(),\n tokensProcessed: summary.tokensProcessed,\n tokensSaved: summary.tokensSaved,\n totalCalls: summary.totalCalls,\n compressedCalls: summary.compressedCalls,\n failedCalls: summary.failedCalls,\n lastAccessedAt: managed.lastAccessedAt,\n }\n }\n\n private evictStale(): void {\n const now = Date.now()\n const cutoff = now - this.config.sessionTtlMs\n\n for (const [key, managed] of this.sessions) {\n if (managed.lastAccessedAt < cutoff) {\n this.sessions.delete(key)\n this.config.onSessionEvicted?.(key)\n }\n }\n }\n\n private evictLRU(): void {\n let oldestKey: string | null = null\n let oldestTime = Infinity\n\n for (const [key, managed] of this.sessions) {\n if (managed.lastAccessedAt < oldestTime) {\n oldestTime = managed.lastAccessedAt\n oldestKey = key\n }\n }\n\n if (oldestKey !== null) {\n this.sessions.delete(oldestKey)\n this.config.onSessionEvicted?.(oldestKey)\n }\n }\n}\n","export class SemaphoreTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`Semaphore acquire timed out after ${timeoutMs}ms`)\n this.name = 'SemaphoreTimeoutError'\n }\n}\n\ninterface Waiter {\n resolve: () => void\n reject: (err: Error) => void\n}\n\nexport class Semaphore {\n private permits: number\n private readonly queue: Waiter[] = []\n\n constructor(maxPermits: number) {\n if (maxPermits < 1) throw new RangeError('maxPermits must be >= 1')\n this.permits = maxPermits\n }\n\n get available(): number {\n return this.permits\n }\n\n get waiting(): number {\n return this.queue.length\n }\n\n acquire(timeoutMs?: number): Promise<void> {\n if (this.permits > 0) {\n this.permits--\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve, reject) => {\n const waiter: Waiter = { resolve, reject }\n this.queue.push(waiter)\n\n if (timeoutMs !== undefined && timeoutMs >= 0) {\n const timer = setTimeout(() => {\n const idx = this.queue.indexOf(waiter)\n if (idx !== -1) {\n this.queue.splice(idx, 1)\n reject(new SemaphoreTimeoutError(timeoutMs))\n }\n }, timeoutMs)\n\n const originalResolve = waiter.resolve\n waiter.resolve = () => {\n clearTimeout(timer)\n originalResolve()\n }\n }\n })\n }\n\n release(): void {\n const next = this.queue.shift()\n if (next) {\n next.resolve()\n } else {\n this.permits++\n }\n }\n}\n","export interface LatencyAlert {\n type: 'warning' | 'critical'\n message: string\n sessionKey: string\n p95Ms: number\n thresholdMs: number\n activeSessions: number\n suggestion: string\n}\n\nexport interface LatencyMonitorConfig {\n warningThresholdMs: number\n criticalThresholdMs: number\n windowSize: number\n}\n\nconst DEFAULT_CONFIG: LatencyMonitorConfig = {\n warningThresholdMs: 4000,\n criticalThresholdMs: 8000,\n windowSize: 50,\n}\n\nclass CircularBuffer {\n private readonly buffer: number[]\n private index = 0\n private count = 0\n private readonly capacity: number\n\n constructor(capacity: number) {\n this.capacity = capacity\n this.buffer = new Array<number>(capacity)\n }\n\n push(value: number): void {\n this.buffer[this.index] = value\n this.index = (this.index + 1) % this.capacity\n if (this.count < this.capacity) {\n this.count++\n }\n }\n\n getValues(): number[] {\n if (this.count < this.capacity) {\n return this.buffer.slice(0, this.count)\n }\n return [...this.buffer.slice(this.index), ...this.buffer.slice(0, this.index)]\n }\n\n get size(): number {\n return this.count\n }\n}\n\nfunction calculateP95(values: number[]): number | null {\n if (values.length === 0) return null\n const sorted = [...values].sort((a, b) => a - b)\n const idx = Math.floor(sorted.length * 0.95)\n return sorted[Math.min(idx, sorted.length - 1)]\n}\n\nexport class LatencyMonitor {\n private readonly config: LatencyMonitorConfig\n private readonly sessionWindows = new Map<string, CircularBuffer>()\n private readonly globalWindow: CircularBuffer\n private readonly callbacks: Array<(alert: LatencyAlert) => void> = []\n\n constructor(config?: Partial<LatencyMonitorConfig>) {\n this.config = { ...DEFAULT_CONFIG, ...config }\n this.globalWindow = new CircularBuffer(this.config.windowSize * 4)\n }\n\n record(sessionKey: string, latencyMs: number): LatencyAlert | null {\n let sessionBuf = this.sessionWindows.get(sessionKey)\n if (!sessionBuf) {\n sessionBuf = new CircularBuffer(this.config.windowSize)\n this.sessionWindows.set(sessionKey, sessionBuf)\n }\n sessionBuf.push(latencyMs)\n this.globalWindow.push(latencyMs)\n\n const globalP95 = calculateP95(this.globalWindow.getValues())\n if (globalP95 === null) return null\n\n let alert: LatencyAlert | null = null\n\n if (globalP95 >= this.config.criticalThresholdMs) {\n alert = {\n type: 'critical',\n message: `Global p95 latency ${globalP95.toFixed(0)}ms exceeds critical threshold ${this.config.criticalThresholdMs}ms`,\n sessionKey,\n p95Ms: globalP95,\n thresholdMs: this.config.criticalThresholdMs,\n activeSessions: this.sessionWindows.size,\n suggestion: 'Reduce active sessions or increase latency budget',\n }\n } else if (globalP95 >= this.config.warningThresholdMs) {\n alert = {\n type: 'warning',\n message: `Global p95 latency ${globalP95.toFixed(0)}ms exceeds warning threshold ${this.config.warningThresholdMs}ms`,\n sessionKey,\n p95Ms: globalP95,\n thresholdMs: this.config.warningThresholdMs,\n activeSessions: this.sessionWindows.size,\n suggestion: 'Consider reducing active sessions',\n }\n }\n\n if (alert) {\n for (const cb of this.callbacks) {\n cb(alert)\n }\n }\n\n return alert\n }\n\n getSessionP95(sessionKey: string): number | null {\n const buf = this.sessionWindows.get(sessionKey)\n if (!buf) return null\n return calculateP95(buf.getValues())\n }\n\n getGlobalP95(): number | null {\n return calculateP95(this.globalWindow.getValues())\n }\n\n onAlert(cb: (alert: LatencyAlert) => void): void {\n this.callbacks.push(cb)\n }\n\n get sessionCount(): number {\n return this.sessionWindows.size\n }\n}\n","/**\n * HTTP CONNECT handler for forward proxy mode.\n *\n * When Cursor is launched with --proxy-server=http://127.0.0.1:PORT,\n * it sends CONNECT requests for HTTPS destinations. This handler:\n *\n * 1. Parses the CONNECT host:port request\n * 2. Checks the allowlist — is this an LLM API host?\n * 3. If YES: responds 200 and hands off to MITM interceptor (Phase 3+4)\n * 4. If NO: opens a plain TCP tunnel to the destination (passthrough)\n *\n * The CONNECT event is emitted by Node's http.Server separately from\n * the normal 'request' event, so this is wired up independently.\n */\n\nimport * as net from 'node:net'\nimport type * as http from 'node:http'\nimport { shouldIntercept } from './allowlist.js'\n\nexport interface ConnectLogger {\n log(message: string): void\n}\n\nexport type MitmHandler = (\n clientSocket: net.Socket,\n hostname: string,\n port: number,\n) => void\n\nexport interface ConnectHandlerOptions {\n logger: ConnectLogger\n /** Called for allowlisted hosts that should be MITM-intercepted. */\n onIntercept?: MitmHandler\n /** Called when a connection is passed through (non-allowlisted). */\n onPassthrough?: () => void\n}\n\n/**\n * Create a handler for the http.Server 'connect' event.\n *\n * Usage:\n * server.on('connect', createConnectHandler({ logger }))\n */\nexport function createConnectHandler(\n options: ConnectHandlerOptions,\n): (req: http.IncomingMessage, clientSocket: net.Socket, head: Buffer) => void {\n const { logger, onIntercept, onPassthrough } = options\n const seenHosts = new Set<string>()\n\n return (req: http.IncomingMessage, clientSocket: net.Socket, head: Buffer) => {\n const target = req.url ?? ''\n const [hostname, portStr] = parseConnectTarget(target)\n const port = parseInt(portStr, 10) || 443\n\n if (!hostname) {\n logger.log(`[CONNECT] Invalid target: ${target}`)\n clientSocket.write('HTTP/1.1 400 Bad Request\\r\\n\\r\\n')\n clientSocket.destroy()\n return\n }\n\n if (shouldIntercept(hostname) && onIntercept) {\n // Allowlisted host — MITM intercept (log only first time per host)\n if (!seenHosts.has(hostname)) {\n seenHosts.add(hostname)\n logger.log(`[CONNECT] ${hostname} → intercept (MITM active)`)\n }\n\n // Tell the client the tunnel is established\n clientSocket.write('HTTP/1.1 200 Connection Established\\r\\n\\r\\n')\n\n // Hand off to the MITM handler (Phase 3+4)\n // Pass any data that arrived with the CONNECT request\n if (head.length > 0) {\n clientSocket.unshift(head)\n }\n\n onIntercept(clientSocket, hostname, port)\n } else {\n // Non-allowlisted host — plain TCP tunnel passthrough (log first time only)\n if (!seenHosts.has(hostname)) {\n seenHosts.add(hostname)\n logger.log(`[TUNNEL] ${hostname} → passthrough`)\n }\n onPassthrough?.()\n\n const upstreamSocket = net.connect(port, hostname, () => {\n clientSocket.write('HTTP/1.1 200 Connection Established\\r\\n\\r\\n')\n\n // Forward any data that arrived with the CONNECT request\n if (head.length > 0) {\n upstreamSocket.write(head)\n }\n\n // Bidirectional pipe\n clientSocket.pipe(upstreamSocket)\n upstreamSocket.pipe(clientSocket)\n })\n\n // Error handling\n upstreamSocket.on('error', (err) => {\n logger.log(`[TUNNEL] ${hostname}:${port} upstream error: ${err.message}`)\n clientSocket.write('HTTP/1.1 502 Bad Gateway\\r\\n\\r\\n')\n clientSocket.destroy()\n })\n\n clientSocket.on('error', (err) => {\n logger.log(`[TUNNEL] ${hostname}:${port} client error: ${err.message}`)\n upstreamSocket.destroy()\n })\n\n // Cleanup on close\n clientSocket.on('close', () => upstreamSocket.destroy())\n upstreamSocket.on('close', () => clientSocket.destroy())\n }\n }\n}\n\n/**\n * Parse \"host:port\" from CONNECT target.\n * Returns [hostname, port] or ['', ''] on failure.\n */\nfunction parseConnectTarget(target: string): [string, string] {\n const colonIdx = target.lastIndexOf(':')\n if (colonIdx === -1) return [target, '443']\n return [target.slice(0, colonIdx), target.slice(colonIdx + 1)]\n}\n","/**\n * TLS MITM bridge for intercepting HTTPS LLM API calls.\n *\n * When a CONNECT request arrives for an allowlisted host (e.g. api.openai.com),\n * this bridge:\n *\n * 1. Generates a dynamic TLS certificate for the hostname (signed by our CA)\n * 2. Wraps the client socket in a TLS server socket using that cert\n * 3. Injects the decrypted TLS socket into the existing HTTP server\n * 4. Our normal request handler processes it — compression, forwarding, etc.\n *\n * The client (Cursor) sees a valid certificate chain:\n * Cursor → [our dynamic cert for api.openai.com] → [our CA cert in trust store]\n *\n * The upstream sees a normal HTTPS request from our proxy.\n */\n\nimport * as tls from 'node:tls'\nimport * as net from 'node:net'\nimport type * as http from 'node:http'\nimport { CertGenerator } from './cert-generator.js'\nimport type { MitmHandler, ConnectLogger } from './connect-handler.js'\n\nexport interface MitmBridgeOptions {\n /** The HTTP server to inject decrypted connections into */\n httpServer: http.Server\n /** CA certificate PEM */\n caCertPem: string\n /** CA private key PEM */\n caKeyPem: string\n /** Logger for MITM events */\n logger: ConnectLogger\n}\n\n/**\n * Create a MITM handler that can be passed to createConnectHandler's onIntercept.\n *\n * When called, it wraps the client socket in TLS (presenting a cert for the\n * target hostname), then injects it into the HTTP server so our existing\n * request handlers process it transparently.\n */\nexport function createMitmBridge(options: MitmBridgeOptions): MitmHandler {\n const { httpServer, caCertPem, caKeyPem, logger } = options\n const certGen = new CertGenerator(caCertPem, caKeyPem)\n const loggedHosts = new Set<string>()\n\n return (clientSocket: net.Socket, hostname: string, _port: number) => {\n try {\n // Generate (or retrieve cached) cert for this hostname\n const { certPem, keyPem } = certGen.getCert(hostname)\n\n // Create a TLS server socket wrapping the client connection\n const tlsSocket = new tls.TLSSocket(clientSocket, {\n isServer: true,\n key: keyPem,\n cert: certPem,\n })\n\n tlsSocket.on('error', (err) => {\n logger.log(`[MITM] TLS error for ${hostname}: ${err.message}`)\n tlsSocket.destroy()\n })\n\n // Inject the decrypted socket into our HTTP server.\n httpServer.emit('connection', tlsSocket)\n\n // Only log the first bridge per host to reduce noise\n if (!loggedHosts.has(hostname)) {\n loggedHosts.add(hostname)\n logger.log(`[MITM] Intercepting ${hostname} (cert cached)`)\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n logger.log(`[MITM] Failed to establish bridge for ${hostname}: ${message}`)\n clientSocket.destroy()\n }\n }\n}\n","/**\n * Dynamic TLS certificate generation for MITM interception.\n *\n * When Cursor connects to api.openai.com through our proxy, we need\n * to present a certificate for api.openai.com signed by our CA.\n * This module generates those certificates on-the-fly and caches them.\n */\n\nimport forge from 'node-forge'\n\nexport interface CertPair {\n certPem: string\n keyPem: string\n}\n\ninterface CacheEntry {\n cert: CertPair\n expiresAt: number\n}\n\nconst CERT_TTL_MS = 24 * 60 * 60 * 1000 // 24 hours\nconst MAX_CACHE_SIZE = 50\n\nexport class CertGenerator {\n private readonly caCert: forge.pki.Certificate\n private readonly caKey: forge.pki.rsa.PrivateKey\n private readonly cache = new Map<string, CacheEntry>()\n\n constructor(caCertPem: string, caKeyPem: string) {\n this.caCert = forge.pki.certificateFromPem(caCertPem)\n this.caKey = forge.pki.privateKeyFromPem(caKeyPem)\n }\n\n /**\n * Get or generate a TLS certificate for the given hostname.\n * Certificates are cached for 24 hours.\n */\n getCert(hostname: string): CertPair {\n const now = Date.now()\n\n // Check cache\n const cached = this.cache.get(hostname)\n if (cached && cached.expiresAt > now) {\n return cached.cert\n }\n\n // Generate new cert\n const cert = this.generate(hostname)\n\n // Evict oldest if at capacity\n if (this.cache.size >= MAX_CACHE_SIZE) {\n const oldest = this.cache.keys().next().value\n if (oldest) this.cache.delete(oldest)\n }\n\n this.cache.set(hostname, { cert, expiresAt: now + CERT_TTL_MS })\n return cert\n }\n\n get cacheSize(): number {\n return this.cache.size\n }\n\n private generate(hostname: string): CertPair {\n const keys = forge.pki.rsa.generateKeyPair(2048)\n\n const cert = forge.pki.createCertificate()\n cert.publicKey = keys.publicKey\n cert.serialNumber = randomSerial()\n\n // Valid from 1 day ago (clock skew tolerance) to 24 hours from now\n cert.validity.notBefore = new Date(Date.now() - 24 * 60 * 60 * 1000)\n cert.validity.notAfter = new Date(Date.now() + 24 * 60 * 60 * 1000)\n\n cert.setSubject([\n { name: 'commonName', value: hostname },\n { name: 'organizationName', value: 'Liminal Proxy (local)' },\n ])\n\n // Issuer is our CA\n cert.setIssuer(this.caCert.subject.attributes)\n\n cert.setExtensions([\n { name: 'basicConstraints', cA: false },\n {\n name: 'keyUsage',\n digitalSignature: true,\n keyEncipherment: true,\n critical: true,\n },\n {\n name: 'extKeyUsage',\n serverAuth: true,\n },\n {\n name: 'subjectAltName',\n altNames: [{ type: 2, value: hostname }], // DNS name\n },\n ])\n\n // Sign with our CA's private key\n cert.sign(this.caKey, forge.md.sha256.create())\n\n return {\n certPem: forge.pki.certificateToPem(cert),\n keyPem: forge.pki.privateKeyToPem(keys.privateKey),\n }\n }\n}\n\nfunction randomSerial(): string {\n return forge.util.bytesToHex(forge.random.getBytesSync(16))\n}\n","/**\n * Lightweight MITM connection stats for the health/status endpoints.\n */\n\nexport interface MitmSnapshot {\n /** Total CONNECT requests intercepted (TLS MITM) */\n intercepted: number\n /** Total CONNECT requests passed through (non-allowlisted) */\n passthrough: number\n /** Currently active TLS bridges */\n activeBridges: number\n /** Unique hostnames intercepted */\n hostsIntercepted: string[]\n /** Whether the MITM bridge is wired and ready */\n enabled: boolean\n}\n\nexport class MitmStats {\n private _intercepted = 0\n private _passthrough = 0\n private _activeBridges = 0\n private _hosts = new Set<string>()\n private _enabled = false\n\n enable(): void {\n this._enabled = true\n }\n\n recordIntercept(hostname: string): void {\n this._intercepted++\n this._activeBridges++\n this._hosts.add(hostname)\n }\n\n recordBridgeClosed(): void {\n if (this._activeBridges > 0) this._activeBridges--\n }\n\n recordPassthrough(): void {\n this._passthrough++\n }\n\n snapshot(): MitmSnapshot {\n return {\n intercepted: this._intercepted,\n passthrough: this._passthrough,\n activeBridges: this._activeBridges,\n hostsIntercepted: [...this._hosts],\n enabled: this._enabled,\n }\n }\n}\n","import { execSync } from 'node:child_process'\nimport {\n isDaemonRunning,\n readPidFile,\n removePidFile,\n isProcessAlive,\n sleep,\n} from '../daemon/lifecycle.js'\n\n/**\n * Find liminal/node processes that look like our daemon.\n * Fallback when the PID file is stale or missing.\n */\nfunction findLiminalProcesses(): number[] {\n try {\n // Find node processes running liminal\n const output = execSync('ps aux', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] })\n const pids: number[] = []\n for (const line of output.split('\\n')) {\n if (line.includes('liminal') && line.includes('start') && !line.includes('grep') && !line.includes('stop')) {\n const parts = line.trim().split(/\\s+/)\n const pid = parseInt(parts[1], 10)\n if (!isNaN(pid) && pid !== process.pid) {\n pids.push(pid)\n }\n }\n }\n return pids\n } catch {\n return []\n }\n}\n\nfunction killPid(pid: number, signal: NodeJS.Signals = 'SIGTERM'): 'ok' | 'eperm' | 'gone' {\n try {\n process.kill(pid, signal)\n return 'ok'\n } catch (err: unknown) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === 'EPERM') return 'eperm'\n return 'gone' // ESRCH or other — process doesn't exist\n }\n}\n\nexport async function stopCommand(): Promise<void> {\n const state = isDaemonRunning()\n\n // If PID file says not running, check for orphaned processes\n if (!state.running || !state.pid) {\n const orphans = findLiminalProcesses()\n if (orphans.length === 0) {\n console.log('Liminal daemon is not running.')\n return\n }\n\n console.log(`Found ${orphans.length} orphaned liminal process(es): ${orphans.join(', ')}`)\n let needsSudo = false\n for (const pid of orphans) {\n const result = killPid(pid)\n if (result === 'eperm') {\n needsSudo = true\n } else if (result === 'ok') {\n console.log(` Stopped PID ${pid}`)\n }\n }\n\n if (needsSudo) {\n console.log()\n console.log('Some processes require elevated privileges to stop.')\n console.log('Run: sudo liminal stop')\n }\n removePidFile()\n return\n }\n\n const pid = state.pid\n console.log(`Stopping Liminal daemon (PID ${pid})...`)\n\n // Send SIGTERM for graceful shutdown\n const result = killPid(pid)\n if (result === 'gone') {\n removePidFile()\n console.log('Liminal daemon stopped (already exited).')\n return\n }\n if (result === 'eperm') {\n console.log(`Cannot stop PID ${pid} — permission denied.`)\n console.log('The daemon was started with sudo. Run: sudo liminal stop')\n return\n }\n\n // Poll for up to 5 seconds\n for (let i = 0; i < 25; i++) {\n await sleep(200)\n if (!isProcessAlive(pid)) {\n removePidFile()\n console.log(`Liminal daemon stopped (PID ${pid}).`)\n return\n }\n }\n\n // Force kill after timeout\n const forceResult = killPid(pid, 'SIGKILL')\n if (forceResult === 'eperm') {\n console.log(`Cannot force-kill PID ${pid} — permission denied.`)\n console.log('Run: sudo liminal stop')\n return\n }\n\n removePidFile()\n console.log(`Liminal daemon force-killed (PID ${pid}).`)\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { isDaemonRunning } from '../daemon/lifecycle.js'\nimport { loadConfig, isConfigured } from '../config/loader.js'\nimport {\n c, success, error as fmtError, warn, info,\n sectionHeader, label, dimText,\n formatUptime as fmtUptime, formatBytes as fmtBytes, formatNum,\n} from '../ui/format.js'\n\ninterface SessionInfo {\n session_key: string\n connector: string\n circuit_state: string\n tokens_processed: number\n tokens_saved: number\n calls_total: number\n calls_compressed: number\n calls_failed: number\n p95_latency_ms: number | null\n last_active_ago_ms: number\n}\n\ninterface MitmInfo {\n enabled: boolean\n intercepted: number\n passthrough: number\n activeBridges: number\n hostsIntercepted: string[]\n}\n\ninterface HealthResponse {\n status: string\n version: string\n uptime_ms: number\n concurrency: {\n active_sessions: number\n semaphore_available: number\n semaphore_waiting: number\n max_concurrent_rsc_calls: number\n }\n latency: {\n global_p95_ms: number | null\n }\n mitm?: MitmInfo\n sessions: SessionInfo[]\n}\n\nexport async function statusCommand(): Promise<void> {\n if (!isConfigured()) {\n console.log(fmtError(\n 'Liminal is not configured',\n `Run ${c.bold}liminal init${c.reset}${c.dim} to set up`,\n ))\n return\n }\n\n // Cursor hooks stats (independent of daemon)\n printCursorHookStats()\n\n const state = isDaemonRunning()\n\n if (!state.running || !state.pid) {\n console.log()\n console.log(label('Daemon', `${c.dim}stopped${c.reset}`))\n console.log(` ${c.dim}\\u2192 Run ${c.bold}liminal start${c.reset}${c.dim} to start the proxy${c.reset}`)\n console.log()\n return\n }\n\n const config = loadConfig()\n const port = config.port\n\n // Try to reach the daemon's /health endpoint\n try {\n const res = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: AbortSignal.timeout(3000),\n })\n const data = await res.json() as HealthResponse\n\n const uptime = fmtUptime(data.uptime_ms)\n\n console.log()\n console.log(success(`Daemon running`, `PID ${state.pid}, port ${port}`))\n console.log(label('Status', `${data.status} ${c.dim}(${data.version})${c.reset}`))\n console.log(label('Uptime', uptime))\n console.log()\n\n // Concurrency\n const conc = data.concurrency\n console.log(label('Sessions', `${conc.active_sessions} active ${c.dim}(max ${config.maxSessions})${c.reset}`))\n console.log(label('Semaphore', `${conc.semaphore_available}/${conc.max_concurrent_rsc_calls} available` +\n (conc.semaphore_waiting > 0 ? ` ${c.yellow}(${conc.semaphore_waiting} waiting)${c.reset}` : '')))\n\n // Global latency\n const globalP95 = data.latency.global_p95_ms\n if (globalP95 !== null) {\n const latencyColor = globalP95 >= config.latencyCriticalMs ? c.red\n : globalP95 >= config.latencyWarningMs ? c.yellow\n : c.green\n const latencyFlag = globalP95 >= config.latencyCriticalMs ? ' CRITICAL'\n : globalP95 >= config.latencyWarningMs ? ' WARNING'\n : ''\n console.log(label('Latency', `${latencyColor}p95 ${globalP95.toFixed(0)}ms${latencyFlag}${c.reset}`))\n }\n\n // MITM proxy info\n if (data.mitm) {\n const m = data.mitm\n if (m.enabled) {\n console.log(label('MITM', `${c.green}active${c.reset} ${c.dim}(${m.intercepted} intercepted, ${m.passthrough} passthrough)${c.reset}`))\n if (m.hostsIntercepted.length > 0) {\n console.log(` ${c.dim}Hosts: ${m.hostsIntercepted.join(', ')}${c.reset}`)\n }\n } else {\n console.log(label('MITM', `${c.dim}disabled${c.reset}`))\n console.log(` ${c.dim}\\u2192 Run ${c.bold}liminal trust-ca${c.reset}${c.dim} to enable${c.reset}`)\n }\n }\n\n // Quick session summary\n if (data.sessions.length > 0) {\n console.log(label('Active', `${data.sessions.length} session${data.sessions.length !== 1 ? 's' : ''}`))\n } else {\n console.log(label('Active', `${c.dim}no sessions${c.reset}`))\n }\n\n console.log()\n console.log(` ${c.dim}\\u2192 Run ${c.bold}liminal stats${c.reset}${c.dim} for detailed metrics & savings${c.reset}`)\n console.log()\n } catch {\n // Can't reach the daemon, but PID is alive — might still be starting\n console.log()\n console.log(success(`Daemon running`, `PID ${state.pid}, port ${port}`))\n console.log(label('Status', `${c.yellow}unknown${c.reset} ${c.dim}(could not reach /health)${c.reset}`))\n console.log()\n }\n}\n\ninterface HookLogEntry {\n ts: string\n type: 'compressed' | 'error'\n file: string\n inputSize?: number\n outputSize?: number\n inputTokens?: number\n outputTokens?: number\n tokensSaved?: number\n savedPct?: number\n apiMs?: number\n error?: string\n}\n\nfunction printCursorHookStats(): void {\n const logPath = join(process.cwd(), '.fabric', 'compress.log')\n const hooksPath = join(process.cwd(), '.cursor', 'hooks.json')\n\n // Check if hooks are installed\n let hooksActive = false\n try {\n if (existsSync(hooksPath)) {\n const data = JSON.parse(readFileSync(hooksPath, 'utf-8'))\n const entries = data?.hooks?.preToolUse ?? []\n hooksActive = entries.some((e: { command?: string }) => e.command?.includes('fabric-compress'))\n }\n } catch { /* ignore */ }\n\n if (!hooksActive && !existsSync(logPath)) return\n\n console.log(sectionHeader('Cursor Hooks'))\n console.log()\n console.log(label('Status', hooksActive ? `${c.green}active${c.reset}` : `${c.dim}not installed${c.reset}`))\n\n if (!existsSync(logPath)) {\n console.log(label('Stats', `${c.dim}no compression data yet${c.reset}`))\n console.log()\n return\n }\n\n // Parse JSONL log\n const lines = readFileSync(logPath, 'utf-8').trim().split('\\n')\n let compressed = 0\n let errors = 0\n let totalInputSize = 0\n let totalOutputSize = 0\n let totalInputTokens = 0\n let totalOutputTokens = 0\n let totalTokensSaved = 0\n let totalApiMs = 0\n const files = new Set<string>()\n\n for (const line of lines) {\n try {\n const entry = JSON.parse(line) as HookLogEntry\n if (entry.type === 'compressed') {\n compressed++\n totalInputSize += entry.inputSize ?? 0\n totalOutputSize += entry.outputSize ?? 0\n totalInputTokens += entry.inputTokens ?? Math.ceil((entry.inputSize ?? 0) / 4)\n totalOutputTokens += entry.outputTokens ?? Math.ceil((entry.outputSize ?? 0) / 4)\n totalTokensSaved += entry.tokensSaved ?? 0\n totalApiMs += entry.apiMs ?? 0\n files.add(entry.file)\n } else if (entry.type === 'error') {\n errors++\n }\n } catch {\n // Handle old plain-text format lines\n if (line.includes('ERROR')) errors++\n else if (line.includes('->')) compressed++\n }\n }\n\n const overallPct = totalInputTokens > 0 ? ((totalTokensSaved / totalInputTokens) * 100).toFixed(1) : '0.0'\n const avgApiMs = compressed > 0 ? Math.round(totalApiMs / compressed) : 0\n\n // Count cached files\n let cacheCount = 0\n try {\n cacheCount = countFiles(join(process.cwd(), '.fabric', 'cache'))\n } catch { /* ok */ }\n\n console.log(label('Files', `${files.size} unique ${c.dim}(${compressed} compressions${errors > 0 ? `, ${c.red}${errors} errors${c.reset}${c.dim}` : ''})${c.reset}`))\n console.log(label('Tokens', `${formatNum(totalInputTokens)} processed, ${formatNum(totalTokensSaved)} saved ${c.cyan}(${overallPct}%)${c.reset}`))\n console.log(label('Bytes', `${fmtBytes(totalInputSize - totalOutputSize)} saved of ${fmtBytes(totalInputSize)}`))\n console.log(label('Cache', `${cacheCount} files in .fabric/cache/`))\n if (compressed > 0) {\n console.log(label('Avg API', `${avgApiMs}ms per file`))\n }\n console.log()\n}\n\nfunction countFiles(dir: string): number {\n if (!existsSync(dir)) return 0\n const { readdirSync, statSync } = require('node:fs')\n let count = 0\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n count += countFiles(join(dir, entry.name))\n } else {\n count++\n }\n }\n return count\n}\n\n// formatBytes and formatUptime are now in ui/format.ts\n","import { loadConfig, saveConfig, isConfigured, maskApiKey } from '../config/loader.js'\nimport { CONFIGURABLE_KEYS } from '../config/schema.js'\nimport { CONFIG_FILE } from '../config/paths.js'\n\nexport async function configCommand(flags: Map<string, string | true>): Promise<void> {\n const getKey = flags.get('get')\n const setKv = flags.get('set')\n\n // rsc config --get <key>\n if (typeof getKey === 'string') {\n if (!isConfigured()) {\n console.error('Liminal is not configured. Run \"liminal init\" first.')\n process.exit(1)\n }\n const config = loadConfig()\n const value = (config as unknown as Record<string, unknown>)[getKey]\n if (value === undefined) {\n console.error(`Unknown config key: ${getKey}`)\n process.exit(1)\n }\n console.log(getKey === 'apiKey' ? maskApiKey(String(value)) : String(value))\n return\n }\n\n // rsc config --set <key>=<value>\n if (typeof setKv === 'string') {\n const eqIdx = setKv.indexOf('=')\n if (eqIdx === -1) {\n console.error('Usage: liminal config --set key=value')\n process.exit(1)\n }\n const key = setKv.slice(0, eqIdx)\n const rawValue = setKv.slice(eqIdx + 1)\n\n if (!CONFIGURABLE_KEYS.has(key) && key !== 'apiKey') {\n console.error(`Unknown or non-configurable key: ${key}`)\n console.error(`Configurable keys: ${[...CONFIGURABLE_KEYS].join(', ')}`)\n process.exit(1)\n }\n\n // Parse value based on key type\n let parsedValue: unknown = rawValue\n if (key === 'port' || key === 'compressionThreshold' || key === 'latencyBudgetMs') {\n parsedValue = parseInt(rawValue, 10)\n if (isNaN(parsedValue as number)) {\n console.error(`Invalid number for ${key}: ${rawValue}`)\n process.exit(1)\n }\n } else if (key === 'learnFromResponses' || key === 'enabled') {\n parsedValue = rawValue === 'true' || rawValue === '1'\n } else if (key === 'compressRoles') {\n parsedValue = rawValue.split(',').map((s) => s.trim())\n }\n\n saveConfig({ [key]: parsedValue })\n console.log(`Set ${key} = ${key === 'apiKey' ? maskApiKey(rawValue) : rawValue}`)\n return\n }\n\n // rsc config (no flags) — show all\n if (!isConfigured()) {\n console.log(`Liminal is not configured. Run \"liminal init\" first.`)\n console.log(`Config file: ${CONFIG_FILE}`)\n return\n }\n\n const config = loadConfig()\n console.log()\n console.log(` Config: ${CONFIG_FILE}`)\n console.log()\n console.log(` apiKey: ${maskApiKey(config.apiKey)}`)\n console.log(` apiBaseUrl: ${config.apiBaseUrl}`)\n console.log(` upstreamBaseUrl: ${config.upstreamBaseUrl}`)\n console.log(` anthropicUpstreamUrl: ${config.anthropicUpstreamUrl}`)\n console.log(` tools: ${config.tools.length > 0 ? config.tools.join(', ') : '(none)'}`)\n console.log(` port: ${config.port}`)\n console.log(` compressionThreshold: ${config.compressionThreshold}`)\n console.log(` compressRoles: ${config.compressRoles.join(', ')}`)\n console.log(` learnFromResponses: ${config.learnFromResponses}`)\n console.log(` latencyBudgetMs: ${config.latencyBudgetMs || 'auto'}`)\n console.log(` enabled: ${config.enabled}`)\n console.log()\n}\n","import { readFileSync, existsSync, statSync, createReadStream } from 'node:fs'\nimport { watchFile, unwatchFile } from 'node:fs'\nimport { LOG_FILE } from '../config/paths.js'\n\nexport async function logsCommand(flags: Map<string, string | true>): Promise<void> {\n const follow = flags.has('follow') || flags.has('f')\n const linesFlag = flags.get('lines') ?? flags.get('n')\n const lines = typeof linesFlag === 'string' ? parseInt(linesFlag, 10) : 50\n\n if (!existsSync(LOG_FILE)) {\n console.log('No log file found. Start the daemon with \"liminal start\" to generate logs.')\n return\n }\n\n // Read and display last N lines\n const content = readFileSync(LOG_FILE, 'utf-8')\n const allLines = content.split('\\n')\n const tail = allLines.slice(-lines - 1) // -1 to account for trailing newline\n process.stdout.write(tail.join('\\n'))\n\n if (!follow) return\n\n // Follow mode: watch for changes and stream new content\n let lastSize = statSync(LOG_FILE).size\n\n watchFile(LOG_FILE, { interval: 500 }, (curr) => {\n if (curr.size > lastSize) {\n const stream = createReadStream(LOG_FILE, { start: lastSize, encoding: 'utf-8' })\n stream.on('data', (chunk) => process.stdout.write(chunk as string))\n stream.on('end', () => { lastSize = curr.size })\n } else if (curr.size < lastSize) {\n // File was rotated — read from beginning\n lastSize = 0\n }\n })\n\n // Keep the process alive and handle Ctrl+C\n process.on('SIGINT', () => {\n unwatchFile(LOG_FILE)\n process.exit(0)\n })\n\n // Block forever\n await new Promise(() => {})\n}\n","import { existsSync, rmSync, readFileSync } from 'node:fs'\nimport {\n detectShellProfile,\n removeLiminalFromShellProfile,\n findLiminalExportsInProfile,\n} from '../config/shell.js'\nimport { LIMINAL_DIR, CONFIG_FILE } from '../config/paths.js'\nimport { isDaemonRunning, removePidFile, isProcessAlive, sleep } from '../daemon/lifecycle.js'\nimport { CONNECTORS, getConnectors } from '../connectors/index.js'\nimport { selectPrompt } from '../ui/prompts.js'\nimport type { ConnectorId } from '../connectors/types.js'\n\n// ─── ANSI helpers ────────────────────────────────────────────────────\nconst BOLD = '\\x1b[1m'\nconst DIM = '\\x1b[2m'\nconst CYAN = '\\x1b[36m'\nconst GREEN = '\\x1b[32m'\nconst YELLOW = '\\x1b[33m'\nconst RED = '\\x1b[31m'\nconst RESET = '\\x1b[0m'\n\n/**\n * Load the list of configured tools from ~/.liminal/config.json.\n */\nfunction loadConfiguredTools(): ConnectorId[] {\n if (!existsSync(CONFIG_FILE)) return []\n try {\n const raw = readFileSync(CONFIG_FILE, 'utf-8')\n const config = JSON.parse(raw)\n if (Array.isArray(config.tools)) return config.tools as ConnectorId[]\n } catch {\n // Corrupted config — treat as empty\n }\n return []\n}\n\nexport async function uninstallCommand(): Promise<void> {\n console.log()\n console.log(` ${BOLD}Liminal Uninstall${RESET}`)\n console.log()\n\n // ── 1. Confirm ────────────────────────────────────────────────\n const confirm = await selectPrompt<boolean>({\n message: 'Remove Liminal configuration and restore tool settings?',\n options: [\n { label: 'Yes', value: true, description: 'Undo all Liminal setup' },\n { label: 'No', value: false, description: 'Cancel' },\n ],\n defaultIndex: 1, // Default to No for safety\n })\n\n if (confirm !== true) {\n console.log()\n console.log(' Cancelled.')\n console.log()\n return\n }\n\n console.log()\n\n // ── 2. Stop daemon if running ─────────────────────────────────\n const state = isDaemonRunning()\n if (state.running && state.pid) {\n console.log(` Stopping Liminal daemon (PID ${state.pid})...`)\n try {\n process.kill(state.pid, 'SIGTERM')\n // Wait up to 3 seconds for graceful shutdown\n for (let i = 0; i < 15; i++) {\n await sleep(200)\n if (!isProcessAlive(state.pid)) break\n }\n if (isProcessAlive(state.pid)) {\n process.kill(state.pid, 'SIGKILL')\n }\n } catch {\n // Already dead\n }\n removePidFile()\n console.log(` ${GREEN}✓${RESET} Daemon stopped`)\n } else {\n console.log(` ${DIM}·${RESET} Daemon not running`)\n }\n\n // ── 3. Remove shell profile exports ───────────────────────────\n const profile = detectShellProfile()\n if (profile) {\n const existing = findLiminalExportsInProfile(profile)\n if (existing.length > 0) {\n const removed = removeLiminalFromShellProfile(profile)\n if (removed.length > 0) {\n console.log(` ${GREEN}✓${RESET} Removed ${removed.length} line${removed.length > 1 ? 's' : ''} from ${profile.name}:`)\n for (const line of removed) {\n const trimmed = line.trim()\n if (trimmed && trimmed !== '# Liminal — route AI tools through compression proxy') {\n console.log(` ${DIM}${trimmed}${RESET}`)\n }\n }\n }\n } else {\n console.log(` ${DIM}·${RESET} No Liminal exports found in ${profile.name}`)\n }\n }\n\n // ── 4. Run connector-specific teardown ────────────────────────\n const configuredTools = loadConfiguredTools()\n const allTools = configuredTools.length > 0 ? configuredTools : CONNECTORS.map((c) => c.info.id)\n const connectors = getConnectors(allTools)\n\n const manualSteps: Array<{ label: string; steps: string[] }> = []\n\n for (const connector of connectors) {\n const result = await connector.teardown()\n if (result.manualSteps.length > 0 && !connector.info.automatable) {\n manualSteps.push({\n label: connector.info.label,\n steps: result.manualSteps,\n })\n }\n }\n\n if (manualSteps.length > 0) {\n console.log()\n console.log(` ${YELLOW}Manual steps needed:${RESET}`)\n for (const { label, steps } of manualSteps) {\n console.log()\n console.log(` ${BOLD}${label}:${RESET}`)\n for (const step of steps) {\n console.log(` ${step}`)\n }\n }\n }\n\n // ── 5. Optionally remove ~/.liminal/ ──────────────────────────\n if (existsSync(LIMINAL_DIR)) {\n console.log()\n const removeData = await selectPrompt<boolean>({\n message: 'Remove ~/.liminal/ directory? (config, logs, PID file)',\n options: [\n { label: 'Yes', value: true, description: 'Delete all Liminal data' },\n { label: 'No', value: false, description: 'Keep config and logs' },\n ],\n defaultIndex: 1, // Default to keep\n })\n\n if (removeData === true) {\n rmSync(LIMINAL_DIR, { recursive: true, force: true })\n console.log(` ${GREEN}✓${RESET} Removed ~/.liminal/`)\n } else {\n console.log(` ${DIM}·${RESET} Kept ~/.liminal/`)\n }\n }\n\n // ── 6. Summary ────────────────────────────────────────────────\n console.log()\n console.log(` ${GREEN}Liminal has been uninstalled.${RESET}`)\n console.log()\n console.log(` ${DIM}Your AI tools will connect directly to their APIs.${RESET}`)\n console.log(` ${DIM}Restart your terminal for shell changes to take effect.${RESET}`)\n\n if (manualSteps.length > 0) {\n console.log(` ${YELLOW}Don't forget the manual steps above for ${manualSteps.map((s) => s.label).join(', ')}.${RESET}`)\n }\n\n console.log()\n console.log(` ${DIM}To reinstall: npx @cognisos/liminal init${RESET}`)\n console.log()\n}\n","import { hasCA, ensureCA, getCAInfo, CA_CERT_PATH } from '../tls/ca.js'\nimport { installCA, isCATrusted } from '../tls/trust.js'\nimport { printBanner } from '../version.js'\n\nexport async function trustCACommand(): Promise<void> {\n printBanner()\n\n // Check if already trusted\n if (isCATrusted()) {\n console.log(' Liminal CA is already trusted.')\n const info = getCAInfo()\n if (info) {\n console.log(` Fingerprint: ${info.fingerprint}`)\n console.log(` Valid until: ${info.validTo.toLocaleDateString()}`)\n }\n return\n }\n\n // Ensure CA exists\n if (!hasCA()) {\n console.log(' Generating CA certificate...')\n ensureCA()\n console.log(' Created ~/.liminal/ca.pem')\n console.log()\n }\n\n // Explain what this does\n console.log(' Installing Liminal CA certificate')\n console.log()\n console.log(' This allows Liminal to transparently compress LLM API')\n console.log(' traffic from Cursor and other Electron-based editors.')\n console.log()\n console.log(' The certificate is scoped to your user account and only')\n console.log(' used by the local Liminal proxy on 127.0.0.1.')\n console.log()\n console.log(` Certificate: ${CA_CERT_PATH}`)\n console.log()\n\n // Install\n const result = installCA()\n\n if (result.success) {\n console.log(` ${result.message}`)\n console.log()\n const info = getCAInfo()\n if (info) {\n console.log(` Fingerprint: ${info.fingerprint}`)\n console.log(` Valid until: ${info.validTo.toLocaleDateString()}`)\n }\n console.log()\n console.log(' You can now use Liminal with Cursor:')\n console.log(' liminal start')\n console.log(' cursor --proxy-server=http://127.0.0.1:3141 --disable-http2')\n } else {\n console.error(` Failed: ${result.message}`)\n if (result.requiresSudo) {\n console.log()\n console.log(' Try running with elevated permissions:')\n console.log(' sudo liminal trust-ca')\n }\n process.exit(1)\n }\n}\n","import { removeCA as removeCAFiles, hasCA } from '../tls/ca.js'\nimport { removeCA as untrustCA, isCATrusted } from '../tls/trust.js'\nimport { printBanner } from '../version.js'\n\nexport async function untrustCACommand(): Promise<void> {\n printBanner()\n\n if (!hasCA() && !isCATrusted()) {\n console.log(' No Liminal CA found (nothing to remove).')\n return\n }\n\n // Remove from trust store first\n if (isCATrusted()) {\n console.log(' Removing CA from system trust store...')\n const result = untrustCA()\n\n if (result.success) {\n console.log(` ${result.message}`)\n } else {\n console.error(` ${result.message}`)\n if (result.requiresSudo) {\n console.log()\n console.log(' Try running with elevated permissions:')\n console.log(' sudo liminal untrust-ca')\n }\n process.exit(1)\n }\n }\n\n // Remove cert files\n if (hasCA()) {\n console.log(' Removing CA certificate files...')\n removeCAFiles()\n console.log(' Removed ~/.liminal/ca.pem and ca-key.pem')\n }\n\n console.log()\n console.log(' Liminal CA fully removed.')\n console.log(' Cursor MITM interception is no longer available.')\n}\n","/**\n * `liminal setup cursor` — install file compression hooks for Cursor.\n *\n * Uses Cursor's preToolUse hook to intercept Read tool calls, compress\n * file content via the RSC normalize API, and redirect reads to the\n * compressed cached version. No sudo, no TLS certs, no kernel hacks.\n *\n * Steps:\n * 1. Verify Cursor is installed\n * 2. Verify Liminal is configured (API key)\n * 3. Install hook script + hooks.json\n * 4. Add .fabric/ to .gitignore\n *\n * Teardown:\n * liminal setup cursor --teardown\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync, readdirSync, rmdirSync, appendFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join, dirname } from 'node:path'\nimport { isConfigured } from '../config/loader.js'\nimport { printBanner } from '../version.js'\nimport { getHookScript } from '../cursor/hook-template.js'\nimport { c, success, warn, error as fmtError, info } from '../ui/format.js'\n\nconst HOOK_SCRIPT_NAME = 'fabric-compress.js'\nconst HOOK_COMMAND = `node .cursor/hooks/${HOOK_SCRIPT_NAME}`\n\n/** Check if Cursor app is installed. */\nfunction isCursorInstalled(): boolean {\n if (process.platform === 'darwin') {\n return existsSync('/Applications/Cursor.app')\n }\n if (process.platform === 'win32') {\n const localAppData = process.env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local')\n return existsSync(join(localAppData, 'Programs', 'Cursor', 'Cursor.exe'))\n }\n return existsSync('/usr/bin/cursor')\n}\n\ninterface HooksJson {\n version?: number\n hooks?: Record<string, HookEntry[]>\n}\n\ninterface HookEntry {\n command?: string\n matcher?: string\n timeout?: number\n [key: string]: unknown\n}\n\n/** Read and parse hooks.json, or return empty structure. */\nfunction readHooksJson(workspaceRoot: string): HooksJson {\n const hooksPath = join(workspaceRoot, '.cursor', 'hooks.json')\n try {\n return JSON.parse(readFileSync(hooksPath, 'utf-8'))\n } catch {\n return {}\n }\n}\n\n/** Write hooks.json, creating .cursor/ if needed. */\nfunction writeHooksJson(workspaceRoot: string, data: HooksJson): void {\n const dir = join(workspaceRoot, '.cursor')\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true })\n writeFileSync(join(dir, 'hooks.json'), JSON.stringify(data, null, 2) + '\\n')\n}\n\n/** Check if our hook entry already exists in hooks.json. */\nfunction hasOurHook(hooks: HooksJson): boolean {\n const entries = hooks.hooks?.preToolUse ?? []\n return entries.some(e => e.command?.includes(HOOK_SCRIPT_NAME))\n}\n\n/** Add our hook entry, preserving existing user hooks. */\nfunction addOurHook(hooks: HooksJson): HooksJson {\n if (!hooks.version) hooks.version = 1\n if (!hooks.hooks) hooks.hooks = {}\n if (!hooks.hooks.preToolUse) hooks.hooks.preToolUse = []\n\n // Don't duplicate\n if (!hasOurHook(hooks)) {\n hooks.hooks.preToolUse.push({\n command: HOOK_COMMAND,\n matcher: 'Read',\n timeout: 30,\n })\n }\n\n return hooks\n}\n\n/** Remove our hook entry, preserving user hooks. */\nfunction removeOurHook(hooks: HooksJson): HooksJson {\n if (!hooks.hooks?.preToolUse) return hooks\n\n hooks.hooks.preToolUse = hooks.hooks.preToolUse.filter(\n e => !e.command?.includes(HOOK_SCRIPT_NAME)\n )\n\n // Clean up empty arrays/objects\n if (hooks.hooks.preToolUse.length === 0) {\n delete hooks.hooks.preToolUse\n }\n if (hooks.hooks && Object.keys(hooks.hooks).length === 0) {\n delete hooks.hooks\n }\n\n return hooks\n}\n\n/** Add .fabric/ to .gitignore if not already present. */\nfunction ensureGitignore(workspaceRoot: string): void {\n const gitignorePath = join(workspaceRoot, '.gitignore')\n const entry = '.fabric/'\n\n if (existsSync(gitignorePath)) {\n const content = readFileSync(gitignorePath, 'utf-8')\n if (content.includes(entry)) return\n appendFileSync(gitignorePath, `\\n# Liminal compression cache\\n${entry}\\n`)\n } else {\n writeFileSync(gitignorePath, `# Liminal compression cache\\n${entry}\\n`)\n }\n}\n\n/** Try to remove a directory if empty. */\nfunction rmdirIfEmpty(dir: string): void {\n try {\n if (existsSync(dir) && readdirSync(dir).length === 0) {\n rmdirSync(dir)\n }\n } catch { /* ok */ }\n}\n\nexport async function setupCursorCommand(flags: Map<string, string | true>): Promise<void> {\n printBanner()\n\n const workspaceRoot = process.cwd()\n\n // ── Teardown mode ──────────────────────────────────────────\n if (flags.has('teardown')) {\n console.log(` ${c.bold}Removing Cursor compression hooks...${c.reset}`)\n console.log()\n\n const hooks = readHooksJson(workspaceRoot)\n if (!hasOurHook(hooks)) {\n console.log(info('No Liminal hooks found in .cursor/hooks.json'))\n console.log(` ${c.dim}Nothing to remove.${c.reset}`)\n return\n }\n\n // Remove hook entry from hooks.json\n const updated = removeOurHook(hooks)\n if (updated.hooks || updated.version) {\n writeHooksJson(workspaceRoot, updated)\n console.log(success('Removed hook entry from .cursor/hooks.json'))\n } else {\n // hooks.json is effectively empty — delete it\n const hooksJsonPath = join(workspaceRoot, '.cursor', 'hooks.json')\n try { unlinkSync(hooksJsonPath) } catch { /* ok */ }\n console.log(success('Deleted .cursor/hooks.json', 'no remaining hooks'))\n }\n\n // Remove hook script\n const scriptPath = join(workspaceRoot, '.cursor', 'hooks', HOOK_SCRIPT_NAME)\n try {\n unlinkSync(scriptPath)\n console.log(success(`Deleted .cursor/hooks/${HOOK_SCRIPT_NAME}`))\n } catch { /* ok — may not exist */ }\n\n // Clean up empty directories\n rmdirIfEmpty(join(workspaceRoot, '.cursor', 'hooks'))\n\n console.log()\n console.log(success('Hooks removed. Reload Cursor to deactivate.'))\n console.log()\n console.log(` ${c.dim}The .fabric/ cache directory was left in place.${c.reset}`)\n console.log(` ${c.dim}To remove it: ${c.bold}rm -rf .fabric/${c.reset}`)\n return\n }\n\n // ── Setup mode ─────────────────────────────────────────────\n\n // Step 1: Check Cursor is installed\n console.log(` ${c.dim}[1/4]${c.reset} Checking Cursor installation...`)\n if (!isCursorInstalled()) {\n console.error(fmtError('Cursor not found', 'Install from https://cursor.com'))\n process.exit(1)\n }\n console.log(success('Cursor found'))\n console.log()\n\n // Step 2: Check Liminal is configured\n console.log(` ${c.dim}[2/4]${c.reset} Checking Liminal configuration...`)\n if (!isConfigured()) {\n console.error(fmtError('Liminal is not configured', `Run ${c.bold}liminal init${c.reset}${c.dim} first`))\n process.exit(1)\n }\n console.log(success('API key configured'))\n console.log()\n\n // Step 3: Install hooks\n console.log(` ${c.dim}[3/4]${c.reset} Installing compression hooks...`)\n\n // Write hook script\n const hooksDir = join(workspaceRoot, '.cursor', 'hooks')\n if (!existsSync(hooksDir)) mkdirSync(hooksDir, { recursive: true })\n const scriptPath = join(hooksDir, HOOK_SCRIPT_NAME)\n writeFileSync(scriptPath, getHookScript(), { mode: 0o755 })\n console.log(success(`Wrote .cursor/hooks/${HOOK_SCRIPT_NAME}`))\n\n // Write/merge hooks.json\n const hooks = readHooksJson(workspaceRoot)\n const updated = addOurHook(hooks)\n writeHooksJson(workspaceRoot, updated)\n console.log(success('Updated .cursor/hooks.json'))\n console.log()\n\n // Step 4: Update .gitignore\n console.log(` ${c.dim}[4/4]${c.reset} Updating .gitignore...`)\n ensureGitignore(workspaceRoot)\n console.log(success('Added .fabric/ to .gitignore'))\n console.log()\n\n // Success\n console.log(success('Setup complete! Reload Cursor to activate.'))\n console.log()\n console.log(` ${c.dim}How it works:${c.reset}`)\n console.log(` ${c.dim} When Cursor's agent reads a file, the hook compresses${c.reset}`)\n console.log(` ${c.dim} it via RSC and caches the result in .fabric/cache/.${c.reset}`)\n console.log(` ${c.dim} The agent sees the compressed version transparently.${c.reset}`)\n console.log()\n console.log(` ${c.bold}Stats:${c.reset} .fabric/compress.log`)\n console.log(` ${c.bold}Remove:${c.reset} liminal setup cursor --teardown`)\n}\n","/**\n * Self-contained Node.js hook script for Cursor's preToolUse event.\n *\n * Intercepts Read tool calls, compresses file content via RSC normalize API,\n * caches the result, and redirects Cursor to read the compressed version.\n *\n * This template is written to disk by `liminal setup cursor` as\n * `.cursor/hooks/fabric-compress.js`. It uses only Node.js built-ins\n * (no external dependencies) so it runs standalone.\n */\n\nexport function getHookScript(): string {\n return `#!/usr/bin/env node\n\"use strict\";\n\nconst fs = require(\"node:fs\");\nconst path = require(\"node:path\");\nconst os = require(\"node:os\");\nconst https = require(\"node:https\");\nconst http = require(\"node:http\");\n\n// ── Constants ────────────────────────────────────────────────────────\n\nconst MIN_COMPRESS_CHARS = 200;\nconst MAX_COMPRESS_BYTES = 100 * 1024; // 100KB\nconst API_TIMEOUT_MS = 25000;\nconst MAX_CONCURRENT = 3; // max simultaneous API calls\nconst CONFIG_PATH = path.join(os.homedir(), \".liminal\", \"config.json\");\nconst CACHE_DIR = \".fabric/cache\";\nconst LOG_FILE = \".fabric/compress.log\";\nconst LOCK_DIR = \".fabric/.locks\";\n\nconst BINARY_EXTENSIONS = new Set([\n \".png\", \".jpg\", \".jpeg\", \".gif\", \".ico\", \".bmp\", \".webp\", \".svg\",\n \".woff\", \".woff2\", \".ttf\", \".eot\", \".otf\",\n \".pdf\", \".zip\", \".gz\", \".tar\", \".bz2\", \".xz\", \".7z\",\n \".exe\", \".dll\", \".so\", \".dylib\", \".wasm\", \".bin\", \".dat\",\n \".db\", \".sqlite\", \".node\",\n \".mp3\", \".mp4\", \".avi\", \".mov\", \".wav\",\n \".lock\", \".min.js\", \".min.css\",\n \".map\",\n]);\n\n// ── Helpers ──────────────────────────────────────────────────────────\n\nfunction passthrough() {\n process.stdout.write(JSON.stringify({ permission: \"allow\" }));\n process.exit(0);\n}\n\nfunction redirect(cachePath) {\n process.stdout.write(JSON.stringify({\n permission: \"allow\",\n updated_input: { file_path: cachePath },\n }));\n process.exit(0);\n}\n\n/** Concurrency guard: limit simultaneous API calls across hook processes. */\nfunction acquireLock() {\n try {\n if (!fs.existsSync(LOCK_DIR)) fs.mkdirSync(LOCK_DIR, { recursive: true });\n const locks = fs.readdirSync(LOCK_DIR).filter(f => f.endsWith(\".lock\"));\n // Clean stale locks (>60s old)\n const now = Date.now();\n for (const lock of locks) {\n try {\n const st = fs.statSync(path.join(LOCK_DIR, lock));\n if (now - st.mtimeMs > 60000) fs.unlinkSync(path.join(LOCK_DIR, lock));\n } catch {}\n }\n const activeLocks = fs.readdirSync(LOCK_DIR).filter(f => f.endsWith(\".lock\")).length;\n if (activeLocks >= MAX_CONCURRENT) return null;\n const lockFile = path.join(LOCK_DIR, process.pid + \".lock\");\n fs.writeFileSync(lockFile, String(process.pid));\n return lockFile;\n } catch { return null; }\n}\n\nfunction releaseLock(lockFile) {\n try { if (lockFile) fs.unlinkSync(lockFile); } catch {}\n}\n\nfunction logEntry(data) {\n try {\n const dir = path.dirname(LOG_FILE);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n const entry = Object.assign({ ts: new Date().toISOString() }, data);\n fs.appendFileSync(LOG_FILE, JSON.stringify(entry) + \"\\\\n\");\n } catch { /* ignore log errors */ }\n}\n\nfunction loadConfig() {\n try {\n const raw = fs.readFileSync(CONFIG_PATH, \"utf-8\");\n const config = JSON.parse(raw);\n return {\n apiKey: process.env.LIMINAL_API_KEY || config.apiKey,\n apiBaseUrl: process.env.LIMINAL_API_URL || config.apiBaseUrl || \"https://api.cognisos.ai\",\n };\n } catch {\n return null;\n }\n}\n\n// ── RSC Normalize API call ──────────────────────────────────────────\n\nfunction normalizeText(text, config) {\n return new Promise((resolve, reject) => {\n const encoded = Buffer.from(text).toString(\"base64\");\n const body = JSON.stringify({\n data: encoded,\n format: \"text\",\n options: { enable_learning: false },\n });\n\n const url = new URL(config.apiBaseUrl + \"/api/v1/normalize\");\n const isHttps = url.protocol === \"https:\";\n const transport = isHttps ? https : http;\n\n const req = transport.request({\n hostname: url.hostname,\n port: url.port || (isHttps ? 443 : 80),\n path: url.pathname,\n method: \"POST\",\n headers: {\n \"Authorization\": \"Bearer \" + config.apiKey,\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(body),\n },\n timeout: API_TIMEOUT_MS,\n }, (res) => {\n const chunks = [];\n res.on(\"data\", (chunk) => chunks.push(chunk));\n res.on(\"end\", () => {\n try {\n const json = JSON.parse(Buffer.concat(chunks).toString(\"utf-8\"));\n if (json.normalized_text) {\n const normalized = Buffer.from(json.normalized_text, \"base64\").toString(\"utf-8\");\n const meta = json.metadata || {};\n resolve({\n text: normalized,\n inputSize: json.input_size || text.length,\n outputSize: json.output_size || normalized.length,\n inputTokens: meta.input_tokens || 0,\n outputTokens: meta.output_tokens || 0,\n ratio: json.ratio || (normalized.length / Math.max(text.length, 1)),\n processingTimeMs: meta.processing_time_ms || 0,\n });\n } else {\n reject(new Error(\"No normalized_text in response\"));\n }\n } catch (e) {\n reject(e);\n }\n });\n });\n\n req.on(\"error\", reject);\n req.on(\"timeout\", () => { req.destroy(); reject(new Error(\"API timeout\")); });\n req.write(body);\n req.end();\n });\n}\n\n// ── Main ─────────────────────────────────────────────────────────────\n\nasync function main() {\n // Read JSON from stdin\n const input = await new Promise((resolve) => {\n const chunks = [];\n process.stdin.on(\"data\", (chunk) => chunks.push(chunk));\n process.stdin.on(\"end\", () => {\n try {\n resolve(JSON.parse(Buffer.concat(chunks).toString(\"utf-8\")));\n } catch {\n resolve(null);\n }\n });\n });\n\n if (!input) return passthrough();\n\n // Only handle Read tool\n if (input.tool_name !== \"Read\") return passthrough();\n\n const filePath = input.tool_input?.file_path || input.tool_input?.path;\n if (!filePath) return passthrough();\n\n // Workspace root = cwd (Cursor runs hooks from workspace root)\n const workspaceRoot = process.cwd();\n const relativePath = path.relative(workspaceRoot, filePath);\n\n // Skip: outside workspace\n if (relativePath.startsWith(\"..\") || path.isAbsolute(relativePath)) return passthrough();\n\n // Skip: inside .fabric/ cache (avoid recursive redirect)\n if (relativePath.startsWith(\".fabric\")) return passthrough();\n\n // Skip: Cursor config and hook files\n if (relativePath.startsWith(\".cursor\")) return passthrough();\n\n // Skip: hidden directories (node_modules, .git, etc.)\n if (relativePath.startsWith(\"node_modules\")) return passthrough();\n if (relativePath.startsWith(\".git/\") || relativePath.startsWith(\".git\\\\\\\\\")) return passthrough();\n\n // Skip: binary file\n const ext = path.extname(filePath).toLowerCase();\n if (BINARY_EXTENSIONS.has(ext)) return passthrough();\n\n // Skip: file doesn't exist\n let stat;\n try {\n stat = fs.statSync(filePath);\n } catch {\n return passthrough();\n }\n\n // Skip: too large\n if (stat.size > MAX_COMPRESS_BYTES) return passthrough();\n\n // Read file content\n let content;\n try {\n content = fs.readFileSync(filePath, \"utf-8\");\n } catch {\n return passthrough();\n }\n\n // Skip: too small\n if (content.length < MIN_COMPRESS_CHARS) return passthrough();\n\n // Check cache\n const cachePath = path.join(workspaceRoot, CACHE_DIR, relativePath);\n try {\n const cacheStat = fs.statSync(cachePath);\n if (cacheStat.mtimeMs >= stat.mtimeMs) {\n // Cache is fresh — redirect without API call\n return redirect(cachePath);\n }\n } catch { /* cache miss */ }\n\n // Load config\n const config = loadConfig();\n if (!config || !config.apiKey) return passthrough();\n\n // Concurrency guard: limit simultaneous API calls\n const lockFile = acquireLock();\n if (!lockFile) return passthrough(); // too many concurrent calls, skip\n\n // Call RSC normalize API\n const startTime = Date.now();\n try {\n const result = await normalizeText(content, config);\n const elapsed = Date.now() - startTime;\n\n // Write to cache\n const cacheDir = path.dirname(cachePath);\n if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true });\n fs.writeFileSync(cachePath, result.text, \"utf-8\");\n\n // Use server-side token counts from tiktoken-rs (cl100k_base BPE tokenizer)\n // Fall back to ~3 chars/token estimate if server doesn't return counts\n const inputTokens = result.inputTokens || Math.ceil(result.inputSize / 3);\n const outputTokens = result.outputTokens || Math.ceil(result.outputSize / 3);\n const tokensSaved = Math.max(0, inputTokens - outputTokens);\n logEntry({\n type: \"compressed\",\n file: relativePath,\n inputSize: result.inputSize,\n outputSize: result.outputSize,\n inputTokens: inputTokens,\n outputTokens: outputTokens,\n tokensSaved: tokensSaved,\n savedPct: inputTokens > 0 ? +((tokensSaved / inputTokens) * 100).toFixed(1) : 0,\n apiMs: elapsed,\n });\n\n releaseLock(lockFile);\n return redirect(cachePath);\n } catch (err) {\n releaseLock(lockFile);\n logEntry({ type: \"error\", file: relativePath, error: err.message || String(err) });\n return passthrough();\n }\n}\n\nmain().catch(() => passthrough());\n`;\n}\n","/**\n * `liminal stats` — unified stats view combining session + cumulative metrics.\n *\n * Reads from:\n * - Daemon /health endpoint (if running) for live session data\n * - ~/.liminal/stats.json for cumulative all-time data\n * - .fabric/compress.log for Cursor hook stats\n *\n * Replaces both `liminal status` (metrics portion) and `liminal summary`.\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { isDaemonRunning } from '../daemon/lifecycle.js'\nimport { loadConfig, isConfigured } from '../config/loader.js'\nimport { loadStats, type PersistedStats } from '../stats/store.js'\nimport { StatsAggregator, type StatsSnapshot, type CumulativeStats, type CursorMetrics } from '../stats/aggregator.js'\nimport {\n c, success, warn, error as fmtError, info,\n sectionHeader, label, table,\n formatUptime, formatNum, formatBytes,\n} from '../ui/format.js'\nimport { getConnectors } from '../connectors/index.js'\nimport type { ConnectorId } from '../connectors/types.js'\n\n// ─── Health endpoint types (matches status.ts) ─────────────────────\n\ninterface SessionInfo {\n session_key: string\n connector: string\n circuit_state: string\n tokens_processed: number\n tokens_saved: number\n calls_total: number\n calls_compressed: number\n calls_failed: number\n p95_latency_ms: number | null\n last_active_ago_ms: number\n}\n\ninterface HealthResponse {\n status: string\n version: string\n uptime_ms: number\n concurrency: {\n active_sessions: number\n semaphore_available: number\n semaphore_waiting: number\n max_concurrent_rsc_calls: number\n }\n latency: { global_p95_ms: number | null }\n sessions: SessionInfo[]\n}\n\n// ─── Main command ───────────────────────────────────────────────────\n\nexport async function statsCommand(flags: Map<string, string | true>): Promise<void> {\n if (!isConfigured()) {\n console.log(fmtError(\n 'Liminal is not configured',\n `Run ${c.bold}liminal init${c.reset}${c.dim} to set up`,\n ))\n return\n }\n\n // Load persisted cumulative stats\n const persisted = loadStats()\n const cumulative = persisted.cumulative\n\n // Try to get live session data from daemon\n let liveSession: StatsSnapshot | null = null\n const daemonState = isDaemonRunning()\n\n if (daemonState.running && daemonState.pid) {\n const config = loadConfig()\n try {\n const res = await fetch(`http://127.0.0.1:${config.port}/health`, {\n signal: AbortSignal.timeout(3000),\n })\n const health = await res.json() as HealthResponse\n\n // Build a session snapshot from live health data\n const agg = new StatsAggregator()\n for (const s of health.sessions) {\n // Record each session's totals into the aggregator\n if (s.tokens_saved > 0) {\n agg.recordCompression(s.connector, s.tokens_processed, s.tokens_saved, 0)\n // Adjust call counts (recordCompression adds 1 call each time)\n // We need to set the actual counts by recording the remaining calls\n for (let i = 1; i < s.calls_compressed; i++) {\n agg.recordCompression(s.connector, 0, 0, 0)\n }\n }\n for (let i = 0; i < s.calls_failed; i++) {\n agg.recordFailure(s.connector)\n }\n const skipped = s.calls_total - s.calls_compressed - s.calls_failed\n for (let i = 0; i < skipped; i++) {\n agg.recordSkipped(s.connector, 0)\n }\n }\n\n // Parse Cursor hook stats\n const cursorMetrics = parseCursorHookStats()\n if (cursorMetrics) {\n agg.setCursorMetrics(cursorMetrics)\n }\n\n // Override the snapshot with accurate totals from health endpoint\n const snap = agg.snapshot()\n // Recalculate from health data directly for accuracy\n let totalProcessed = 0, totalSaved = 0, totalCalls = 0, totalCompressed = 0, totalFailed = 0\n for (const s of health.sessions) {\n totalProcessed += s.tokens_processed\n totalSaved += s.tokens_saved\n totalCalls += s.calls_total\n totalCompressed += s.calls_compressed\n totalFailed += s.calls_failed\n }\n if (cursorMetrics) {\n totalProcessed += cursorMetrics.tokensProcessed\n totalSaved += cursorMetrics.tokensSaved\n totalCalls += cursorMetrics.compressions + cursorMetrics.errors\n totalCompressed += cursorMetrics.compressions\n totalFailed += cursorMetrics.errors\n }\n\n const rate = totalProcessed > 0 ? totalSaved / totalProcessed : 0\n liveSession = {\n ...snap,\n uptimeMs: health.uptime_ms,\n calls: totalCalls,\n callsCompressed: totalCompressed,\n callsFailed: totalFailed,\n tokensProcessed: totalProcessed,\n tokensSaved: totalSaved,\n savingsRate: rate,\n contextExtension: rate < 1 ? 1 / (1 - rate) : 1,\n estimatedCostSavedUsd: (totalSaved / 1_000_000) * 5,\n cursor: cursorMetrics ?? undefined,\n }\n\n // Build per-tool breakdown from sessions\n const byTool: Record<string, typeof snap.byTool[string]> = {}\n for (const s of health.sessions) {\n if (!byTool[s.connector]) {\n byTool[s.connector] = {\n calls: 0, callsCompressed: 0, callsFailed: 0,\n tokensProcessed: 0, tokensSaved: 0,\n latencySumMs: 0, latencySamples: 0,\n }\n }\n const t = byTool[s.connector]\n t.calls += s.calls_total\n t.callsCompressed += s.calls_compressed\n t.callsFailed += s.calls_failed\n t.tokensProcessed += s.tokens_processed\n t.tokensSaved += s.tokens_saved\n if (s.p95_latency_ms !== null) {\n t.latencySumMs += s.p95_latency_ms\n t.latencySamples++\n }\n }\n liveSession.byTool = byTool\n\n } catch {\n // Daemon running but can't reach — show what we have from disk\n }\n }\n\n // ── JSON output ───────────────────────────────────────────────────\n\n if (flags.has('json')) {\n const output = {\n session: liveSession,\n cumulative,\n daemonRunning: daemonState.running,\n }\n console.log(JSON.stringify(output, null, 2))\n return\n }\n\n // ── Formatted output ──────────────────────────────────────────────\n\n console.log()\n console.log(sectionHeader('LIMINAL STATS'))\n console.log()\n\n // Build the two-column table: This Session | All Time\n const sessionUptime = liveSession ? formatUptime(liveSession.uptimeMs) : '\\u2014'\n const allTimeUptime = cumulative.totalUptimeMs > 0 ? formatUptime(cumulative.totalUptimeMs) : '\\u2014'\n\n const sessionCalls = liveSession ? String(liveSession.calls) : '\\u2014'\n const allTimeCalls = cumulative.calls > 0 ? formatNum(cumulative.calls) : '\\u2014'\n\n const sessionCompressed = liveSession && liveSession.calls > 0\n ? `${liveSession.callsCompressed} (${(liveSession.callsCompressed / liveSession.calls * 100).toFixed(1)}%)`\n : '\\u2014'\n const allTimeCompressed = cumulative.calls > 0\n ? `${formatNum(cumulative.callsCompressed)} (${(cumulative.callsCompressed / cumulative.calls * 100).toFixed(1)}%)`\n : '\\u2014'\n\n console.log(table(\n ['Session', 'This Session', 'All Time'],\n [\n ['Uptime', sessionUptime, allTimeUptime],\n ['API Calls', sessionCalls, allTimeCalls],\n ['Calls Compressed', sessionCompressed, allTimeCompressed],\n ],\n ))\n\n console.log()\n\n // Token savings table\n const sessionProcessed = liveSession ? formatNum(liveSession.tokensProcessed) : '\\u2014'\n const allTimeProcessed = cumulative.tokensProcessed > 0 ? formatNum(cumulative.tokensProcessed) : '\\u2014'\n\n const sessionSaved = liveSession ? formatNum(liveSession.tokensSaved) : '\\u2014'\n const allTimeSaved = cumulative.tokensSaved > 0 ? formatNum(cumulative.tokensSaved) : '\\u2014'\n\n const sessionRate = liveSession ? `${(liveSession.savingsRate * 100).toFixed(1)}%` : '\\u2014'\n const allTimeRate = cumulative.tokensProcessed > 0\n ? `${(cumulative.tokensSaved / cumulative.tokensProcessed * 100).toFixed(1)}%`\n : '\\u2014'\n\n const sessionExt = liveSession ? `~${liveSession.contextExtension.toFixed(2)}x` : '\\u2014'\n const allTimeExt = cumulative.tokensProcessed > 0\n ? `~${(1 / (1 - cumulative.tokensSaved / cumulative.tokensProcessed)).toFixed(2)}x`\n : '\\u2014'\n\n console.log(table(\n ['Token Savings', 'This Session', 'All Time'],\n [\n ['Tokens Processed', sessionProcessed, allTimeProcessed],\n ['Tokens Saved', sessionSaved, allTimeSaved],\n ['Savings Rate', sessionRate, allTimeRate],\n ['Context Extension', sessionExt, allTimeExt],\n ],\n ))\n\n console.log()\n\n // Cost impact table\n const sessionCost = liveSession ? `$${liveSession.estimatedCostSavedUsd.toFixed(2)}` : '\\u2014'\n const allTimeCost = cumulative.tokensSaved > 0\n ? `$${((cumulative.tokensSaved / 1_000_000) * 5).toFixed(2)}`\n : '\\u2014'\n\n const sessionOutputTokens = liveSession && liveSession.tokensSaved > 0\n ? `+${formatNum(Math.round(liveSession.tokensSaved * 0.67))} tokens`\n : '\\u2014'\n const allTimeOutputTokens = cumulative.tokensSaved > 0\n ? `+${formatNum(Math.round(cumulative.tokensSaved * 0.67))} tokens`\n : '\\u2014'\n\n console.log(table(\n ['Cost Impact', 'This Session', 'All Time'],\n [\n ['Est. Input Cost Saved', sessionCost, allTimeCost],\n ['Est. Output Preserved', sessionOutputTokens, allTimeOutputTokens],\n ],\n ))\n\n // ── Per-tool breakdown ────────────────────────────────────────────\n\n if (liveSession && Object.keys(liveSession.byTool).length > 0) {\n console.log()\n console.log(sectionHeader('BY TOOL'))\n\n for (const [toolId, metrics] of Object.entries(liveSession.byTool)) {\n const toolSavings = metrics.tokensProcessed > 0\n ? `${(metrics.tokensSaved / metrics.tokensProcessed * 100).toFixed(1)}%`\n : '0.0%'\n const avgLatency = metrics.latencySamples > 0\n ? `p95 ${Math.round(metrics.latencySumMs / metrics.latencySamples)}ms`\n : ''\n\n console.log()\n console.log(` ${c.bold}${formatToolLabel(toolId)}${c.reset}`)\n console.log(` Calls: ${metrics.calls} (${metrics.callsCompressed} compressed)${metrics.callsFailed > 0 ? ` ${c.red}${metrics.callsFailed} failed${c.reset}` : ''} | Saved: ${formatNum(metrics.tokensSaved)} tokens (${toolSavings})`)\n if (avgLatency) {\n console.log(` Latency: ${avgLatency}`)\n }\n }\n }\n\n // Cursor hook stats\n if (liveSession?.cursor) {\n const cur = liveSession.cursor\n const curSavings = cur.tokensProcessed > 0\n ? `${(cur.tokensSaved / cur.tokensProcessed * 100).toFixed(1)}%`\n : '0.0%'\n const avgApi = cur.compressions > 0\n ? `${Math.round(cur.apiMsSumMs / cur.compressions)}ms/file`\n : ''\n\n console.log()\n console.log(` ${c.bold}Cursor${c.reset}`)\n console.log(` Files: ${cur.files} unique (${cur.compressions} compressions${cur.errors > 0 ? `, ${c.red}${cur.errors} errors${c.reset}` : ''})`)\n console.log(` Saved: ${formatNum(cur.tokensSaved)} tokens (${curSavings}) | Cache: ${cur.cacheCount} files`)\n if (avgApi) {\n console.log(` Avg API: ${avgApi}`)\n }\n }\n\n // ── Footer ────────────────────────────────────────────────────────\n\n if (!daemonState.running) {\n console.log()\n console.log(` ${c.dim}Daemon not running \\u2014 showing historical data only.${c.reset}`)\n console.log(` ${c.dim}\\u2192 Run ${c.bold}liminal start${c.reset}${c.dim} for live stats${c.reset}`)\n }\n\n console.log()\n console.log(` ${c.dim}\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500${c.reset}`)\n console.log()\n}\n\n// ─── Cursor hook stats parser ───────────────────────────────────────\n\ninterface HookLogEntry {\n ts: string\n type: 'compressed' | 'error'\n file: string\n inputSize?: number\n outputSize?: number\n inputTokens?: number\n outputTokens?: number\n tokensSaved?: number\n apiMs?: number\n}\n\nfunction parseCursorHookStats(): CursorMetrics | null {\n const logPath = join(process.cwd(), '.fabric', 'compress.log')\n if (!existsSync(logPath)) return null\n\n let compressions = 0, errors = 0\n let tokensProcessed = 0, tokensSaved = 0\n let apiMsSumMs = 0\n const files = new Set<string>()\n\n const lines = readFileSync(logPath, 'utf-8').trim().split('\\n')\n for (const line of lines) {\n try {\n const entry = JSON.parse(line) as HookLogEntry\n if (entry.type === 'compressed') {\n compressions++\n tokensProcessed += entry.inputTokens ?? Math.ceil((entry.inputSize ?? 0) / 4)\n tokensSaved += entry.tokensSaved ?? 0\n apiMsSumMs += entry.apiMs ?? 0\n files.add(entry.file)\n } else if (entry.type === 'error') {\n errors++\n }\n } catch {\n if (line.includes('ERROR')) errors++\n else if (line.includes('->')) compressions++\n }\n }\n\n // Count cache files\n let cacheCount = 0\n try {\n cacheCount = countFilesRecursive(join(process.cwd(), '.fabric', 'cache'))\n } catch { /* ok */ }\n\n return {\n files: files.size,\n compressions,\n errors,\n tokensProcessed,\n tokensSaved,\n apiMsSumMs,\n cacheCount,\n }\n}\n\nfunction countFilesRecursive(dir: string): number {\n if (!existsSync(dir)) return 0\n const { readdirSync } = require('node:fs') as typeof import('node:fs')\n let count = 0\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n count += countFilesRecursive(join(dir, entry.name))\n } else {\n count++\n }\n }\n return count\n}\n\nfunction formatToolLabel(toolId: string): string {\n const map: Record<string, string> = {\n 'claude-code': 'Claude Code',\n 'codex': 'Codex CLI',\n 'cursor': 'Cursor',\n 'openai-compatible': 'OpenAI Compatible',\n 'anthropic-messages': 'Claude Code',\n 'openai-chat': 'OpenAI',\n 'openai-responses': 'Codex',\n }\n return map[toolId] ?? toolId\n}\n"],"mappings":"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","names":["label","box","stdin","stdout","readFileSync","writeFileSync","unlinkSync","existsSync","existsSync","readFileSync","writeFileSync","mkdirSync","dirname","join","c","existsSync","readFileSync","join","label","label","existsSync","statSync","existsSync","readFileSync","writeFileSync","join","homedir","c","execSync","existsSync","readFileSync","join","homedir","ENV_VAR","INFO","getCurrentBaseUrl","existsSync","readFileSync","join","homedir","INFO","ENV_VAR","INFO","getCurrentBaseUrl","c","existsSync","readFileSync","writeFileSync","mkdirSync","join","execSync","existsSync","unlinkSync","existsSync","removeCA","execSync","unlinkSync","RSCPipelineWrapper","createServer","RSCCircuitOpenError","createHash","createHash","c","tiered","lines","RSCCircuitOpenError","RSCCircuitOpenError","usage","lines","setCORSHeaders","RSCCircuitOpenError","usage","RSCCircuitOpenError","lines","setCORSHeaders","sendJSON","extractBearerToken","c","RSCCircuitOpenError","setCORSHeaders","sendJSON","appendFileSync","mkdirSync","existsSync","dirname","forge","StatsAggregator","mergeSessionIntoCumulative","incrementSessionCount","usage","parseCursorHookStats","RSCPipelineWrapper","probe","healthy","execSync","code","pid","result","existsSync","readFileSync","join","readdirSync","statSync","config","readFileSync","existsSync","statSync","existsSync","readFileSync","existsSync","readFileSync","c","label","info","removeCA","existsSync","readFileSync","writeFileSync","mkdirSync","unlinkSync","readdirSync","appendFileSync","homedir","join","isCursorInstalled","existsSync","join","homedir","readFileSync","mkdirSync","writeFileSync","appendFileSync","readdirSync","hooks","updated","unlinkSync","scriptPath","existsSync","readFileSync","join","parseCursorHookStats","countFilesRecursive","readdirSync","runHub"]}