skalpel 2.0.11 → 2.0.13
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/cli/index.js +547 -330
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/proxy-runner.js +437 -91
- package/dist/cli/proxy-runner.js.map +1 -1
- package/dist/index.cjs +584 -137
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -1
- package/dist/index.d.ts +29 -1
- package/dist/index.js +584 -137
- package/dist/index.js.map +1 -1
- package/dist/proxy/index.cjs +468 -93
- package/dist/proxy/index.cjs.map +1 -1
- package/dist/proxy/index.d.cts +7 -0
- package/dist/proxy/index.d.ts +7 -0
- package/dist/proxy/index.js +468 -93
- package/dist/proxy/index.js.map +1 -1
- package/package.json +6 -13
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/index.ts","../../src/cli/init.ts","../../src/cli/utils.ts","../../src/cli/doctor.ts","../../src/cli/agents/detect.ts","../../src/cli/benchmark.ts","../../src/cli/replay.ts","../../src/cli/start.ts","../../src/proxy/config.ts","../../src/proxy/pid.ts","../../src/cli/service/install.ts","../../src/cli/service/detect-os.ts","../../src/cli/service/templates.ts","../../src/cli/agents/configure.ts","../../src/cli/agents/shell.ts","../../src/proxy/server.ts","../../src/proxy/streaming.ts","../../src/proxy/logger.ts","../../src/cli/stop.ts","../../src/cli/status.ts","../../src/cli/logs.ts","../../src/cli/config-cmd.ts","../../src/cli/update.ts","../../src/cli/wizard.ts","../../src/cli/uninstall.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createRequire } from 'node:module';\nimport { runInit } from './init.js';\nimport { runDoctor } from './doctor.js';\nimport { runBenchmark } from './benchmark.js';\nimport { runReplay } from './replay.js';\nimport { runStart } from './start.js';\nimport { runStop } from './stop.js';\nimport { runStatus } from './status.js';\nimport { runLogs } from './logs.js';\nimport { runConfig } from './config-cmd.js';\nimport { runUpdate } from './update.js';\nimport { runWizard } from './wizard.js';\nimport { runUninstall } from './uninstall.js';\n\nconst require = createRequire(import.meta.url);\nconst pkg = require('../../package.json');\n\nconst program = new Command();\n\nprogram\n .name('skalpel')\n .description('Skalpel AI CLI — optimize your OpenAI and Anthropic API calls')\n .version(pkg.version)\n .option('--api-key <key>', 'Skalpel API key for non-interactive setup')\n .option('--auto', 'Run setup in non-interactive mode')\n .option('--skip-claude', 'Skip Claude Code configuration')\n .option('--skip-codex', 'Skip Codex configuration')\n .action((options) => runWizard(options));\n\nprogram\n .command('init')\n .description('Initialize Skalpel in your project')\n .action(runInit);\n\nprogram\n .command('doctor')\n .description('Check Skalpel configuration health')\n .action(runDoctor);\n\nprogram\n .command('benchmark')\n .description('Run performance benchmarks')\n .action(runBenchmark);\n\nprogram\n .command('replay')\n .description('Replay saved request files')\n .argument('<files...>', 'JSON request files')\n .action(runReplay);\n\nprogram\n .command('start')\n .description('Start the Skalpel proxy')\n .action(runStart);\n\nprogram\n .command('stop')\n .description('Stop the Skalpel proxy')\n .action(runStop);\n\nprogram\n .command('status')\n .description('Show proxy status')\n .action(runStatus);\n\nprogram\n .command('logs')\n .description('View proxy logs')\n .option('-n, --lines <count>', 'Number of lines to show', '50')\n .option('-f, --follow', 'Follow log output')\n .action(runLogs);\n\nprogram\n .command('config')\n .description('View or edit proxy configuration')\n .argument('[subcommand]', 'path | set')\n .argument('[args...]', 'Arguments for subcommand')\n .action(runConfig);\n\nprogram\n .command('update')\n .description('Update Skalpel to the latest version')\n .action(runUpdate);\n\nprogram\n .command('setup')\n .description('Run the Skalpel setup wizard')\n .action(runWizard);\n\nprogram\n .command('uninstall')\n .description('Remove Skalpel proxy and configurations')\n .option('--force', 'Skip confirmation prompts and remove everything')\n .action(runUninstall);\n\nprogram.parse(process.argv);\n","import * as readline from 'node:readline';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { detectProjectType, detectAiSdks, validateApiKey, generateCodeSample } from './utils.js';\nimport type { InitConfig, SupportedProvider } from '../types.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport async function runInit(): Promise<void> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n function ask(question: string): Promise<string> {\n return new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n }\n\n try {\n print('');\n print(' Skalpel AI — SDK Setup');\n print(' ─────────────────────');\n print('');\n\n // Step 1: Detect project type\n const projectType = detectProjectType();\n print(` Detected project type: ${projectType}`);\n\n // Step 2: Detect existing AI SDKs\n const sdks = detectAiSdks(projectType);\n if (sdks.length > 0) {\n print(` Detected AI SDKs: ${sdks.join(', ')}`);\n } else {\n print(' No AI SDKs detected');\n }\n print('');\n\n // Step 3: API key\n let apiKey = process.env.SKALPEL_API_KEY ?? '';\n if (apiKey && validateApiKey(apiKey)) {\n print(` Using API key from SKALPEL_API_KEY env var: ${apiKey.slice(0, 14)}...`);\n } else {\n apiKey = await ask(' Enter your Skalpel API key (sk-skalpel-...): ');\n if (!validateApiKey(apiKey)) {\n print(' Error: Invalid API key. Must start with \"sk-skalpel-\" and be at least 20 characters.');\n rl.close();\n process.exit(1);\n }\n print(` API key set: ${apiKey.slice(0, 14)}${'*'.repeat(Math.max(0, apiKey.length - 14))}`);\n }\n print('');\n\n // Step 4: Choose integration method\n print(' Choose integration method:');\n print(' 1) Wrapper pattern — Wraps your existing SDK client. Adds fallback and metadata.');\n print(' 2) URL swap — Changes the base URL. Simplest, one-line change.');\n print('');\n const methodChoice = await ask(' Enter choice (1 or 2): ');\n const integrationMethod = methodChoice === '2' ? 'url_swap' : 'wrapper';\n print('');\n\n // Step 5: Generate .env\n const envPath = path.join(process.cwd(), '.env');\n const envContent = `SKALPEL_API_KEY=${apiKey}\\nSKALPEL_BASE_URL=https://api.skalpel.ai\\n`;\n\n if (fs.existsSync(envPath)) {\n fs.appendFileSync(envPath, `\\n${envContent}`);\n print(' Appended Skalpel config to existing .env file');\n } else {\n fs.writeFileSync(envPath, envContent);\n print(' Created .env file with Skalpel config');\n }\n print('');\n\n // Step 6: Show code sample\n const providers: SupportedProvider[] = sdks.length > 0 ? sdks : ['openai'];\n const config: InitConfig = {\n projectType,\n integrationMethod: integrationMethod as 'wrapper' | 'url_swap',\n providers,\n apiKey,\n };\n\n const sample = generateCodeSample(config);\n print(' Add this to your code:');\n print(' ──────────────────────');\n for (const line of sample.split('\\n')) {\n print(` ${line}`);\n }\n print(' ──────────────────────');\n print('');\n\n // Step 7: Success\n print(' Setup complete! Your API calls will now be optimized by Skalpel.');\n print('');\n\n rl.close();\n } catch (err) {\n rl.close();\n throw err;\n }\n}\n\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { SupportedProvider, InitConfig } from '../types.js';\n\nexport function detectProjectType(): 'node' | 'python' | 'other' {\n if (fs.existsSync(path.join(process.cwd(), 'package.json'))) {\n return 'node';\n }\n if (\n fs.existsSync(path.join(process.cwd(), 'requirements.txt')) ||\n fs.existsSync(path.join(process.cwd(), 'pyproject.toml'))\n ) {\n return 'python';\n }\n return 'other';\n}\n\nexport function detectAiSdks(projectType: string): SupportedProvider[] {\n const providers: SupportedProvider[] = [];\n\n if (projectType === 'node') {\n try {\n const pkgPath = path.join(process.cwd(), 'package.json');\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\n const allDeps = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n };\n if (allDeps['openai']) providers.push('openai');\n if (allDeps['@anthropic-ai/sdk']) providers.push('anthropic');\n } catch {\n // ignore\n }\n }\n\n if (projectType === 'python') {\n try {\n const reqPath = path.join(process.cwd(), 'requirements.txt');\n if (fs.existsSync(reqPath)) {\n const content = fs.readFileSync(reqPath, 'utf-8');\n if (/^openai/m.test(content)) providers.push('openai');\n if (/^anthropic/m.test(content)) providers.push('anthropic');\n }\n } catch {\n // ignore\n }\n }\n\n return providers;\n}\n\nexport function validateApiKey(key: string): boolean {\n return key.startsWith('sk-skalpel-') && key.length >= 20;\n}\n\nexport function generateCodeSample(config: InitConfig): string {\n if (config.integrationMethod === 'wrapper') {\n if (config.providers.includes('openai')) {\n return `import OpenAI from 'openai';\nimport { createSkalpelClient } from 'skalpel';\n\nconst openai = createSkalpelClient(new OpenAI(), {\n apiKey: process.env.SKALPEL_API_KEY!,${config.workspace ? `\\n workspace: '${config.workspace}',` : ''}\n});\n\nconst response = await openai.chat.completions.create({\n model: 'gpt-4o',\n messages: [{ role: 'user', content: 'Hello' }],\n});`;\n }\n if (config.providers.includes('anthropic')) {\n return `import Anthropic from '@anthropic-ai/sdk';\nimport { createSkalpelClient } from 'skalpel';\n\nconst anthropic = createSkalpelClient(new Anthropic(), {\n apiKey: process.env.SKALPEL_API_KEY!,${config.workspace ? `\\n workspace: '${config.workspace}',` : ''}\n});\n\nconst response = await anthropic.messages.create({\n model: 'claude-sonnet-4-20250514',\n max_tokens: 1024,\n messages: [{ role: 'user', content: 'Hello' }],\n});`;\n }\n }\n\n if (config.integrationMethod === 'url_swap') {\n if (config.providers.includes('openai')) {\n return `import OpenAI from 'openai';\n\nconst openai = new OpenAI({\n baseURL: 'https://api.skalpel.ai/v1',\n apiKey: process.env.SKALPEL_API_KEY,\n});\n\nconst response = await openai.chat.completions.create({\n model: 'gpt-4o',\n messages: [{ role: 'user', content: 'Hello' }],\n});`;\n }\n if (config.providers.includes('anthropic')) {\n return `import Anthropic from '@anthropic-ai/sdk';\n\nconst anthropic = new Anthropic({\n baseURL: 'https://api.skalpel.ai/v1',\n apiKey: process.env.SKALPEL_API_KEY,\n});\n\nconst response = await anthropic.messages.create({\n model: 'claude-sonnet-4-20250514',\n max_tokens: 1024,\n messages: [{ role: 'user', content: 'Hello' }],\n});`;\n }\n }\n\n return `// Configure your Skalpel API key\n// SKALPEL_API_KEY=${config.apiKey}\n// See https://docs.skalpel.ai for integration guides`;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { validateApiKey } from './utils.js';\nimport { detectAgents } from './agents/detect.js';\n\ninterface DoctorCheck {\n name: string;\n status: 'ok' | 'warn' | 'fail';\n message: string;\n}\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nfunction loadConfigApiKey(): string | null {\n try {\n const configPath = path.join(os.homedir(), '.skalpel', 'config.json');\n const raw = JSON.parse(fs.readFileSync(configPath, 'utf-8'));\n if (typeof raw.apiKey === 'string' && raw.apiKey.length > 0) {\n return raw.apiKey;\n }\n } catch {\n // config doesn't exist or is invalid\n }\n return null;\n}\n\nexport async function runDoctor(): Promise<void> {\n print('');\n print(' Skalpel Doctor');\n print(' ──────────────');\n print('');\n\n const checks: DoctorCheck[] = [];\n\n // 1. Check API key — config file first, then env var\n const configKey = loadConfigApiKey();\n const envKey = process.env.SKALPEL_API_KEY ?? '';\n const apiKey = configKey || envKey;\n\n if (apiKey && validateApiKey(apiKey)) {\n const source = configKey ? '~/.skalpel/config.json' : 'environment';\n checks.push({\n name: 'API Key',\n status: 'ok',\n message: `Valid key from ${source}: ${apiKey.slice(0, 14)}${'*'.repeat(Math.max(0, apiKey.length - 14))}`,\n });\n } else if (apiKey) {\n checks.push({\n name: 'API Key',\n status: 'fail',\n message: `Invalid format — must start with \"sk-skalpel-\" and be >= 20 chars`,\n });\n } else {\n checks.push({\n name: 'API Key',\n status: 'fail',\n message: 'No API key found. Run \"npx skalpel\" to set up.',\n });\n }\n\n // 2. Check Skalpel config\n const skalpelConfigPath = path.join(os.homedir(), '.skalpel', 'config.json');\n if (fs.existsSync(skalpelConfigPath)) {\n checks.push({ name: 'Skalpel config', status: 'ok', message: '~/.skalpel/config.json found' });\n } else {\n checks.push({ name: 'Skalpel config', status: 'warn', message: 'No ~/.skalpel/config.json — run \"npx skalpel\" to set up' });\n }\n\n // 3. Check proxy endpoint reachability\n const baseURL = 'https://api.skalpel.ai';\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n const response = await fetch(`${baseURL}/health`, { signal: controller.signal });\n clearTimeout(timeout);\n if (response.ok) {\n checks.push({ name: 'Skalpel backend', status: 'ok', message: `${baseURL} reachable (HTTP ${response.status})` });\n } else {\n checks.push({ name: 'Skalpel backend', status: 'warn', message: `${baseURL} responded with HTTP ${response.status}` });\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n checks.push({ name: 'Skalpel backend', status: 'fail', message: `Cannot reach ${baseURL} — ${msg}` });\n }\n\n // 4. Check local proxy health\n let proxyPort = 18100;\n try {\n const raw = JSON.parse(fs.readFileSync(skalpelConfigPath, 'utf-8'));\n proxyPort = raw.anthropicPort ?? 18100;\n } catch {\n // use default\n }\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 2000);\n const res = await fetch(`http://localhost:${proxyPort}/health`, { signal: controller.signal });\n clearTimeout(timeout);\n if (res.ok) {\n checks.push({ name: 'Local proxy', status: 'ok', message: `Running on port ${proxyPort}` });\n } else {\n checks.push({ name: 'Local proxy', status: 'warn', message: `Port ${proxyPort} responded with HTTP ${res.status}` });\n }\n } catch {\n checks.push({ name: 'Local proxy', status: 'warn', message: `Not running on port ${proxyPort}. Run \"npx skalpel start\" to start.` });\n }\n\n // 5. Detect coding agents\n const agents = detectAgents();\n for (const agent of agents) {\n if (agent.installed) {\n const ver = agent.version ? ` v${agent.version}` : '';\n const configured = agent.configPath && fs.existsSync(agent.configPath) ? ' (configured)' : '';\n checks.push({ name: agent.name, status: 'ok', message: `Installed${ver}${configured}` });\n } else {\n checks.push({ name: agent.name, status: 'warn', message: 'Not installed' });\n }\n }\n\n // Print results\n const icons = { ok: '+', warn: '!', fail: 'x' };\n for (const check of checks) {\n const icon = icons[check.status];\n print(` [${icon}] ${check.name}: ${check.message}`);\n }\n\n const failures = checks.filter((c) => c.status === 'fail');\n const warnings = checks.filter((c) => c.status === 'warn');\n print('');\n if (failures.length > 0) {\n print(` ${failures.length} issue(s) found. Fix the above errors to use Skalpel.`);\n } else if (warnings.length > 0) {\n print(` All critical checks passed. ${warnings.length} warning(s).`);\n } else {\n print(' All checks passed. Skalpel is ready.');\n }\n print('');\n}\n","import { execSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\nexport interface DetectedAgent {\n name: 'claude-code' | 'codex';\n installed: boolean;\n version: string | null;\n configPath: string | null;\n}\n\nfunction whichCommand(): string {\n return process.platform === 'win32' ? 'where' : 'which';\n}\n\nfunction tryExec(cmd: string): string | null {\n try {\n return execSync(cmd, { encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();\n } catch {\n return null;\n }\n}\n\nfunction detectClaudeCode(): DetectedAgent {\n const agent: DetectedAgent = {\n name: 'claude-code',\n installed: false,\n version: null,\n configPath: null,\n };\n\n // Check binary\n const binaryPath = tryExec(`${whichCommand()} claude`);\n const hasBinary = binaryPath !== null && binaryPath.length > 0;\n\n // Check config directory\n const claudeDir = path.join(os.homedir(), '.claude');\n const hasConfigDir = fs.existsSync(claudeDir);\n\n agent.installed = hasBinary || hasConfigDir;\n\n if (hasBinary) {\n const versionOutput = tryExec('claude --version');\n if (versionOutput) {\n // Extract version number from output\n const match = versionOutput.match(/(\\d+\\.\\d+[\\w.-]*)/);\n agent.version = match ? match[1] : versionOutput;\n }\n }\n\n const settingsPath = path.join(claudeDir, 'settings.json');\n if (fs.existsSync(settingsPath)) {\n agent.configPath = settingsPath;\n } else if (hasConfigDir) {\n // Config dir exists but no settings.json yet — we'll create it during configuration\n agent.configPath = settingsPath;\n }\n\n return agent;\n}\n\nfunction detectCodex(): DetectedAgent {\n const agent: DetectedAgent = {\n name: 'codex',\n installed: false,\n version: null,\n configPath: null,\n };\n\n // Check binary\n const binaryPath = tryExec(`${whichCommand()} codex`);\n const hasBinary = binaryPath !== null && binaryPath.length > 0;\n\n // Check config directory\n const codexConfigDir = process.platform === 'win32'\n ? path.join(os.homedir(), 'AppData', 'Roaming', 'codex')\n : path.join(os.homedir(), '.codex');\n const hasConfigDir = fs.existsSync(codexConfigDir);\n\n agent.installed = hasBinary || hasConfigDir;\n\n if (hasBinary) {\n const versionOutput = tryExec('codex --version');\n if (versionOutput) {\n const match = versionOutput.match(/(\\d+\\.\\d+[\\w.-]*)/);\n agent.version = match ? match[1] : versionOutput;\n }\n }\n\n // Codex uses config.toml (not config.json)\n const configFile = path.join(codexConfigDir, 'config.toml');\n if (fs.existsSync(configFile)) {\n agent.configPath = configFile;\n } else if (hasConfigDir) {\n agent.configPath = configFile;\n }\n\n return agent;\n}\n\nexport function detectAgents(): DetectedAgent[] {\n return [detectClaudeCode(), detectCodex()];\n}\n","import { validateApiKey } from './utils.js';\n\ninterface BenchmarkResult {\n requestIndex: number;\n model: string;\n directLatencyMs: number;\n proxyLatencyMs: number;\n overheadMs: number;\n savingsUsd: number | null;\n cacheHit: boolean;\n}\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nasync function timedFetch(\n url: string,\n body: object,\n headers: Record<string, string>,\n): Promise<{ latencyMs: number; status: number; headers: Headers; body: any }> {\n const start = performance.now();\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...headers },\n body: JSON.stringify(body),\n });\n const latencyMs = performance.now() - start;\n let responseBody: any = null;\n try {\n responseBody = await response.json();\n } catch {\n // ignore\n }\n return { latencyMs, status: response.status, headers: response.headers, body: responseBody };\n}\n\nexport async function runBenchmark(): Promise<void> {\n print('');\n print(' Skalpel Benchmark');\n print(' ─────────────────');\n print('');\n\n const apiKey = process.env.SKALPEL_API_KEY ?? '';\n if (!validateApiKey(apiKey)) {\n print(' Error: SKALPEL_API_KEY not set or invalid. Run \"npx skalpel doctor\" to diagnose.');\n print('');\n process.exit(1);\n }\n\n const baseURL = process.env.SKALPEL_BASE_URL ?? 'https://api.skalpel.ai';\n const testPrompts = [\n { model: 'gpt-4o-mini', messages: [{ role: 'user', content: 'Say hello in one word.' }] },\n { model: 'gpt-4o-mini', messages: [{ role: 'user', content: 'What is 2+2?' }] },\n { model: 'gpt-4o-mini', messages: [{ role: 'user', content: 'Say hello in one word.' }] },\n ];\n\n print(` Proxy: ${baseURL}`);\n print(` Running ${testPrompts.length} test requests...`);\n print('');\n\n const results: BenchmarkResult[] = [];\n\n for (let i = 0; i < testPrompts.length; i++) {\n const prompt = testPrompts[i];\n print(` Request ${i + 1}/${testPrompts.length}: ${prompt.model} — \"${prompt.messages[0].content}\"`);\n\n // Request through proxy\n let proxyLatencyMs = -1;\n let savingsUsd: number | null = null;\n let cacheHit = false;\n try {\n const proxyResult = await timedFetch(\n `${baseURL}/v1/chat/completions`,\n prompt,\n { Authorization: `Bearer ${apiKey}` },\n );\n proxyLatencyMs = Math.round(proxyResult.latencyMs);\n const savingsHeader = proxyResult.headers.get('x-skalpel-savings-usd');\n if (savingsHeader) savingsUsd = parseFloat(savingsHeader);\n cacheHit = proxyResult.headers.get('x-skalpel-cache-hit') === 'true';\n } catch (err) {\n print(` Proxy request failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n results.push({\n requestIndex: i + 1,\n model: prompt.model,\n directLatencyMs: 0,\n proxyLatencyMs,\n overheadMs: 0,\n savingsUsd,\n cacheHit,\n });\n\n const cacheStr = cacheHit ? ' (cache hit)' : '';\n const savingsStr = savingsUsd !== null ? ` | savings: $${savingsUsd.toFixed(4)}` : '';\n print(` Proxy: ${proxyLatencyMs}ms${cacheStr}${savingsStr}`);\n }\n\n // Summary\n print('');\n print(' Summary');\n print(' ───────');\n const validResults = results.filter((r) => r.proxyLatencyMs >= 0);\n if (validResults.length === 0) {\n print(' No successful requests. Check your API key and proxy endpoint.');\n } else {\n const avgProxy = Math.round(validResults.reduce((s, r) => s + r.proxyLatencyMs, 0) / validResults.length);\n const cacheHits = validResults.filter((r) => r.cacheHit).length;\n const totalSavings = validResults.reduce((s, r) => s + (r.savingsUsd ?? 0), 0);\n\n print(` Requests: ${validResults.length}`);\n print(` Avg latency: ${avgProxy}ms (proxy)`);\n print(` Cache hits: ${cacheHits}/${validResults.length}`);\n if (totalSavings > 0) {\n print(` Savings: $${totalSavings.toFixed(4)}`);\n }\n }\n print('');\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { validateApiKey } from './utils.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport async function runReplay(filePaths: string[]): Promise<void> {\n print('');\n print(' Skalpel Replay');\n print(' ──────────────');\n print('');\n\n if (filePaths.length === 0) {\n print(' Usage: skalpel replay <request-file.json> [request-file2.json ...]');\n print('');\n print(' Replays saved request files through the Skalpel proxy.');\n print(' Each file should be a JSON object with \"model\" and \"messages\" fields.');\n print('');\n process.exit(1);\n }\n\n const apiKey = process.env.SKALPEL_API_KEY ?? '';\n if (!validateApiKey(apiKey)) {\n print(' Error: SKALPEL_API_KEY not set or invalid. Run \"npx skalpel doctor\" to diagnose.');\n print('');\n process.exit(1);\n }\n\n const baseURL = process.env.SKALPEL_BASE_URL ?? 'https://api.skalpel.ai';\n print(` Proxy: ${baseURL}`);\n print(` Replaying ${filePaths.length} request file(s)...`);\n print('');\n\n let successCount = 0;\n let failCount = 0;\n\n for (const filePath of filePaths) {\n const resolved = path.resolve(filePath);\n print(` File: ${resolved}`);\n\n if (!fs.existsSync(resolved)) {\n print(` Error: file not found`);\n failCount++;\n continue;\n }\n\n let requestBody: any;\n try {\n const raw = fs.readFileSync(resolved, 'utf-8');\n requestBody = JSON.parse(raw);\n } catch (err) {\n print(` Error: invalid JSON — ${err instanceof Error ? err.message : String(err)}`);\n failCount++;\n continue;\n }\n\n if (!requestBody.model || !requestBody.messages) {\n print(' Error: request file must contain \"model\" and \"messages\" fields');\n failCount++;\n continue;\n }\n\n const model = requestBody.model;\n const messageCount = Array.isArray(requestBody.messages) ? requestBody.messages.length : 0;\n print(` Model: ${model} | Messages: ${messageCount}`);\n\n try {\n const start = performance.now();\n const response = await fetch(`${baseURL}/v1/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify(requestBody),\n });\n const latencyMs = Math.round(performance.now() - start);\n\n if (!response.ok) {\n print(` Failed: HTTP ${response.status}`);\n failCount++;\n continue;\n }\n\n const body = await response.json() as any;\n const content = body?.choices?.[0]?.message?.content ?? body?.content?.[0]?.text ?? '(no content)';\n const cacheHit = response.headers.get('x-skalpel-cache-hit') === 'true';\n const savings = response.headers.get('x-skalpel-savings-usd');\n\n print(` Status: ${response.status} | Latency: ${latencyMs}ms${cacheHit ? ' (cache hit)' : ''}`);\n if (savings) print(` Savings: $${parseFloat(savings).toFixed(4)}`);\n print(` Response: ${content.slice(0, 120)}${content.length > 120 ? '...' : ''}`);\n successCount++;\n } catch (err) {\n print(` Error: ${err instanceof Error ? err.message : String(err)}`);\n failCount++;\n }\n print('');\n }\n\n print(' ──────────────');\n print(` Done: ${successCount} succeeded, ${failCount} failed`);\n print('');\n}\n","import { spawn } from 'node:child_process';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { loadConfig } from '../proxy/config.js';\nimport { readPid } from '../proxy/pid.js';\nimport type { ProxyConfig } from '../proxy/types.js';\nimport { isServiceInstalled, startService } from './service/install.js';\nimport { detectAgents } from './agents/detect.js';\nimport { configureAgent } from './agents/configure.js';\nimport { configureShellEnvVars } from './agents/shell.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\n/** Tell a running proxy to switch back to normal mode (enable Skalpel optimization). */\nasync function setNormalMode(config: ProxyConfig): Promise<boolean> {\n try {\n const res = await fetch(`http://localhost:${config.anthropicPort}/admin/mode`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ mode: 'normal' }),\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\nexport async function runStart(): Promise<void> {\n const config = loadConfig();\n\n if (!config.apiKey) {\n print(' Error: No API key configured. Run \"skalpel init\" or set SKALPEL_API_KEY.');\n process.exit(1);\n }\n\n const existingPid = readPid(config.pidFile);\n if (existingPid !== null) {\n // Proxy is already running — re-enable normal mode in case it was\n // in passthrough (e.g. after `skalpel stop`).\n const switched = await setNormalMode(config);\n if (switched) {\n print(' Skalpel optimization re-enabled.');\n } else {\n print(` Proxy is already running (pid=${existingPid}).`);\n }\n // Ensure agents are configured even if proxy was already up\n configureAgentsForProxy(config);\n return;\n }\n\n // If an OS service is installed, reload it instead of spawning a one-off process.\n // This ensures the proxy is managed by the service and auto-restarts on reboot.\n if (isServiceInstalled()) {\n startService();\n print(` Skalpel proxy started via system service on ports ${config.anthropicPort} and ${config.openaiPort}`);\n configureAgentsForProxy(config);\n return;\n }\n\n const dirname = path.dirname(fileURLToPath(import.meta.url));\n const runnerScript = path.resolve(dirname, 'proxy-runner.js');\n\n const child = spawn(process.execPath, [runnerScript], {\n detached: true,\n stdio: 'ignore',\n });\n\n child.unref();\n\n print(` Skalpel proxy started on ports ${config.anthropicPort} and ${config.openaiPort}`);\n configureAgentsForProxy(config);\n}\n\n/** Point installed agents and shell profiles at the local proxy. */\nfunction configureAgentsForProxy(config: ProxyConfig): void {\n const agents = detectAgents();\n for (const agent of agents) {\n if (agent.installed) {\n try {\n configureAgent(agent, config);\n print(` Configured ${agent.name}`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n print(` Could not configure ${agent.name}: ${msg}`);\n }\n }\n }\n configureShellEnvVars(agents, config);\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport type { ProxyConfig } from './types.js';\n\nfunction expandHome(filePath: string): string {\n if (filePath.startsWith('~')) {\n return path.join(os.homedir(), filePath.slice(1));\n }\n return filePath;\n}\n\nconst DEFAULTS: ProxyConfig = {\n apiKey: '',\n remoteBaseUrl: 'https://api.skalpel.ai',\n anthropicDirectUrl: 'https://api.anthropic.com',\n anthropicPort: 18100,\n openaiPort: 18101,\n logLevel: 'info',\n logFile: '~/.skalpel/logs/proxy.log',\n pidFile: '~/.skalpel/proxy.pid',\n configFile: '~/.skalpel/config.json',\n};\n\nexport function loadConfig(configPath?: string): ProxyConfig {\n const filePath = expandHome(configPath ?? DEFAULTS.configFile);\n let fileConfig: Partial<ProxyConfig> = {};\n\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n fileConfig = JSON.parse(raw) as Partial<ProxyConfig>;\n } catch {\n // Config file doesn't exist or is invalid — use defaults\n }\n\n return {\n apiKey: fileConfig.apiKey ?? DEFAULTS.apiKey,\n remoteBaseUrl: fileConfig.remoteBaseUrl ?? DEFAULTS.remoteBaseUrl,\n anthropicDirectUrl: fileConfig.anthropicDirectUrl ?? DEFAULTS.anthropicDirectUrl,\n anthropicPort: fileConfig.anthropicPort ?? DEFAULTS.anthropicPort,\n openaiPort: fileConfig.openaiPort ?? DEFAULTS.openaiPort,\n logLevel: fileConfig.logLevel ?? DEFAULTS.logLevel,\n logFile: expandHome(fileConfig.logFile ?? DEFAULTS.logFile),\n pidFile: expandHome(fileConfig.pidFile ?? DEFAULTS.pidFile),\n configFile: filePath,\n };\n}\n\nexport function saveConfig(config: ProxyConfig): void {\n const dir = path.dirname(config.configFile);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(config.configFile, JSON.stringify(config, null, 2) + '\\n');\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nexport function writePid(pidFile: string): void {\n fs.mkdirSync(path.dirname(pidFile), { recursive: true });\n fs.writeFileSync(pidFile, String(process.pid));\n}\n\nexport function readPid(pidFile: string): number | null {\n try {\n const raw = fs.readFileSync(pidFile, 'utf-8').trim();\n const pid = parseInt(raw, 10);\n if (isNaN(pid)) return null;\n return isRunning(pid) ? pid : null;\n } catch {\n return null;\n }\n}\n\nexport function isRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function removePid(pidFile: string): void {\n try {\n fs.unlinkSync(pidFile);\n } catch {\n // Already removed\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { execSync } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport { detectOS } from './detect-os.js';\nimport { generateLaunchdPlist, generateSystemdUnit, generateWindowsTask } from './templates.js';\nimport type { ProxyConfig } from '../../proxy/types.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nfunction resolveProxyRunnerPath(): string {\n // Look for the proxy-runner in the package's dist directory\n // When installed globally via npm, this will be in the package's dist/cli/\n const candidates = [\n path.join(__dirname, '..', 'proxy-runner.js'), // dist/cli/proxy-runner.js relative to dist/cli/service/\n path.join(__dirname, 'proxy-runner.js'), // same dir\n path.join(__dirname, '..', '..', 'cli', 'proxy-runner.js'), // dist/cli/proxy-runner.js from deeper\n ];\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) {\n return path.resolve(candidate);\n }\n }\n\n // Fallback: try to find it via npm root\n try {\n const npmRoot = execSync('npm root -g', { encoding: 'utf-8' }).trim();\n const globalPath = path.join(npmRoot, 'skalpel', 'dist', 'cli', 'proxy-runner.js');\n if (fs.existsSync(globalPath)) return globalPath;\n } catch {\n // ignore\n }\n\n // Last resort: use the src path for development\n const devPath = path.resolve(process.cwd(), 'dist', 'cli', 'proxy-runner.js');\n return devPath;\n}\n\nfunction getMacOSPlistPath(): string {\n return path.join(os.homedir(), 'Library', 'LaunchAgents', 'ai.skalpel.proxy.plist');\n}\n\nfunction getLinuxUnitPath(): string {\n return path.join(os.homedir(), '.config', 'systemd', 'user', 'skalpel-proxy.service');\n}\n\nexport function installService(config: ProxyConfig): void {\n const osInfo = detectOS();\n const proxyRunnerPath = resolveProxyRunnerPath();\n\n // Ensure log directory exists\n const logDir = path.join(os.homedir(), '.skalpel', 'logs');\n fs.mkdirSync(logDir, { recursive: true });\n\n switch (osInfo.platform) {\n case 'macos': {\n const plistPath = getMacOSPlistPath();\n const plistDir = path.dirname(plistPath);\n fs.mkdirSync(plistDir, { recursive: true });\n\n const plist = generateLaunchdPlist(config, proxyRunnerPath);\n fs.writeFileSync(plistPath, plist);\n\n try {\n // Unload first if already loaded (idempotent)\n execSync(`launchctl unload \"${plistPath}\" 2>/dev/null || true`, { stdio: 'pipe' });\n execSync(`launchctl load \"${plistPath}\"`, { stdio: 'pipe' });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(` Warning: Could not register launchd service: ${msg}`);\n console.warn(` You can manually load it: launchctl load \"${plistPath}\"`);\n }\n break;\n }\n\n case 'linux': {\n const unitPath = getLinuxUnitPath();\n const unitDir = path.dirname(unitPath);\n fs.mkdirSync(unitDir, { recursive: true });\n\n const unit = generateSystemdUnit(config, proxyRunnerPath);\n fs.writeFileSync(unitPath, unit);\n\n try {\n execSync('systemctl --user daemon-reload', { stdio: 'pipe' });\n execSync('systemctl --user enable skalpel-proxy', { stdio: 'pipe' });\n execSync('systemctl --user start skalpel-proxy', { stdio: 'pipe' });\n } catch {\n // Fallback: try .desktop autostart\n try {\n const autostartDir = path.join(os.homedir(), '.config', 'autostart');\n fs.mkdirSync(autostartDir, { recursive: true });\n const desktopEntry = `[Desktop Entry]\nType=Application\nName=Skalpel Proxy\nExec=${process.execPath} ${proxyRunnerPath}\nHidden=false\nNoDisplay=true\nX-GNOME-Autostart-enabled=true\n`;\n fs.writeFileSync(path.join(autostartDir, 'skalpel-proxy.desktop'), desktopEntry);\n console.warn(' Warning: systemd --user not available. Created .desktop autostart entry instead.');\n } catch (err2) {\n const msg = err2 instanceof Error ? err2.message : String(err2);\n console.warn(` Warning: Could not register service: ${msg}`);\n console.warn(' You can start the proxy manually: skalpel start');\n }\n }\n break;\n }\n\n case 'windows': {\n const args = generateWindowsTask(config, proxyRunnerPath);\n try {\n execSync(`schtasks ${args.join(' ')}`, { stdio: 'pipe' });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(` Warning: Could not create scheduled task: ${msg}`);\n console.warn(' You can start the proxy manually: skalpel start');\n }\n break;\n }\n }\n}\n\nexport function isServiceInstalled(): boolean {\n const osInfo = detectOS();\n\n switch (osInfo.platform) {\n case 'macos': {\n const plistPath = getMacOSPlistPath();\n return fs.existsSync(plistPath);\n }\n case 'linux': {\n const unitPath = getLinuxUnitPath();\n return fs.existsSync(unitPath);\n }\n case 'windows': {\n try {\n execSync('schtasks /query /tn SkalpelProxy', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n }\n }\n}\n\nexport function stopService(): void {\n const osInfo = detectOS();\n\n switch (osInfo.platform) {\n case 'macos': {\n const plistPath = getMacOSPlistPath();\n if (!fs.existsSync(plistPath)) return;\n try {\n execSync(`launchctl unload \"${plistPath}\"`, { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n case 'linux': {\n try {\n execSync('systemctl --user stop skalpel-proxy', { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n case 'windows': {\n try {\n execSync('schtasks /end /tn SkalpelProxy', { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n }\n}\n\nexport function startService(): void {\n const osInfo = detectOS();\n\n switch (osInfo.platform) {\n case 'macos': {\n const plistPath = getMacOSPlistPath();\n if (!fs.existsSync(plistPath)) return;\n try {\n execSync(`launchctl load \"${plistPath}\"`, { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n case 'linux': {\n try {\n execSync('systemctl --user start skalpel-proxy', { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n case 'windows': {\n try {\n execSync('schtasks /run /tn SkalpelProxy', { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n }\n}\n\nexport function uninstallService(): void {\n const osInfo = detectOS();\n\n switch (osInfo.platform) {\n case 'macos': {\n const plistPath = getMacOSPlistPath();\n try {\n execSync(`launchctl unload \"${plistPath}\" 2>/dev/null || true`, { stdio: 'pipe' });\n } catch {\n // ignore\n }\n if (fs.existsSync(plistPath)) fs.unlinkSync(plistPath);\n break;\n }\n\n case 'linux': {\n try {\n execSync('systemctl --user stop skalpel-proxy 2>/dev/null || true', { stdio: 'pipe' });\n execSync('systemctl --user disable skalpel-proxy 2>/dev/null || true', { stdio: 'pipe' });\n } catch {\n // ignore\n }\n const unitPath = getLinuxUnitPath();\n if (fs.existsSync(unitPath)) fs.unlinkSync(unitPath);\n\n // Also remove .desktop autostart if it exists\n const desktopPath = path.join(os.homedir(), '.config', 'autostart', 'skalpel-proxy.desktop');\n if (fs.existsSync(desktopPath)) fs.unlinkSync(desktopPath);\n break;\n }\n\n case 'windows': {\n try {\n execSync('schtasks /delete /tn SkalpelProxy /f', { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n }\n}\n","import os from 'node:os';\nimport { execSync } from 'node:child_process';\n\nexport interface OSInfo {\n platform: 'macos' | 'linux' | 'windows';\n shell: 'bash' | 'zsh' | 'fish' | 'powershell' | 'cmd';\n homeDir: string;\n}\n\nfunction detectShell(): OSInfo['shell'] {\n if (process.platform === 'win32') {\n // Check if running in PowerShell\n if (process.env.PSModulePath || process.env.POWERSHELL_DISTRIBUTION_CHANNEL) {\n return 'powershell';\n }\n return 'cmd';\n }\n\n // On Unix, check the user's default shell from $SHELL env\n const shellPath = process.env.SHELL ?? '';\n if (shellPath.includes('zsh')) return 'zsh';\n if (shellPath.includes('fish')) return 'fish';\n if (shellPath.includes('bash')) return 'bash';\n\n // Fallback: try to read from /etc/passwd or dscl on macOS\n try {\n if (process.platform === 'darwin') {\n const result = execSync(`dscl . -read /Users/${os.userInfo().username} UserShell`, {\n encoding: 'utf-8',\n timeout: 3000,\n }).trim();\n const shell = result.split(':').pop()?.trim() ?? '';\n if (shell.includes('zsh')) return 'zsh';\n if (shell.includes('fish')) return 'fish';\n if (shell.includes('bash')) return 'bash';\n } else {\n const result = execSync(`getent passwd ${os.userInfo().username}`, {\n encoding: 'utf-8',\n timeout: 3000,\n }).trim();\n const shell = result.split(':').pop() ?? '';\n if (shell.includes('zsh')) return 'zsh';\n if (shell.includes('fish')) return 'fish';\n if (shell.includes('bash')) return 'bash';\n }\n } catch {\n // ignore\n }\n\n return 'bash';\n}\n\nexport function detectOS(): OSInfo {\n let platform: OSInfo['platform'];\n switch (process.platform) {\n case 'darwin':\n platform = 'macos';\n break;\n case 'win32':\n platform = 'windows';\n break;\n default:\n platform = 'linux';\n break;\n }\n\n return {\n platform,\n shell: detectShell(),\n homeDir: os.homedir(),\n };\n}\n","import os from 'node:os';\nimport path from 'node:path';\nimport type { ProxyConfig } from '../../proxy/types.js';\n\nexport function generateLaunchdPlist(config: ProxyConfig, proxyRunnerPath: string): string {\n const logDir = path.join(os.homedir(), '.skalpel', 'logs');\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>ai.skalpel.proxy</string>\n <key>ProgramArguments</key>\n <array>\n <string>${process.execPath}</string>\n <string>${proxyRunnerPath}</string>\n </array>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <true/>\n <key>StandardOutPath</key>\n <string>${path.join(logDir, 'proxy-stdout.log')}</string>\n <key>StandardErrorPath</key>\n <string>${path.join(logDir, 'proxy-stderr.log')}</string>\n <key>EnvironmentVariables</key>\n <dict>\n <key>SKALPEL_ANTHROPIC_PORT</key>\n <string>${config.anthropicPort}</string>\n <key>SKALPEL_OPENAI_PORT</key>\n <string>${config.openaiPort}</string>\n </dict>\n</dict>\n</plist>`;\n}\n\nexport function generateSystemdUnit(config: ProxyConfig, proxyRunnerPath: string): string {\n return `[Unit]\nDescription=Skalpel Proxy\nAfter=network.target\n\n[Service]\nType=simple\nExecStart=${process.execPath} ${proxyRunnerPath}\nRestart=always\nRestartSec=5\nEnvironment=SKALPEL_ANTHROPIC_PORT=${config.anthropicPort}\nEnvironment=SKALPEL_OPENAI_PORT=${config.openaiPort}\n\n[Install]\nWantedBy=default.target`;\n}\n\nexport function generateWindowsTask(config: ProxyConfig, proxyRunnerPath: string): string[] {\n return [\n '/create',\n '/tn', 'SkalpelProxy',\n '/tr', `\"${process.execPath}\" \"${proxyRunnerPath}\"`,\n '/sc', 'ONLOGON',\n '/rl', 'LIMITED',\n '/f',\n ];\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport type { DetectedAgent } from './detect.js';\nimport type { ProxyConfig } from '../../proxy/types.js';\n\nfunction ensureDir(dir: string): void {\n fs.mkdirSync(dir, { recursive: true });\n}\n\nfunction createBackup(filePath: string): void {\n if (fs.existsSync(filePath)) {\n fs.copyFileSync(filePath, `${filePath}.skalpel-backup`);\n }\n}\n\n/** Read and parse a JSON file. Returns null if the file cannot be parsed. */\nfunction readJsonFile(filePath: string): Record<string, unknown> | null {\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n } catch {\n return null;\n }\n}\n\nfunction configureClaudeCode(agent: DetectedAgent, proxyConfig: ProxyConfig): void {\n const configPath = agent.configPath ?? path.join(os.homedir(), '.claude', 'settings.json');\n const configDir = path.dirname(configPath);\n ensureDir(configDir);\n createBackup(configPath);\n\n const config = readJsonFile(configPath) ?? {};\n if (!config.env || typeof config.env !== 'object') {\n config.env = {};\n }\n (config.env as Record<string, string>).ANTHROPIC_BASE_URL = `http://localhost:${proxyConfig.anthropicPort}`;\n\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\n}\n\nfunction readTomlFile(filePath: string): string {\n try {\n return fs.readFileSync(filePath, 'utf-8');\n } catch {\n return '';\n }\n}\n\nfunction setTomlKey(content: string, key: string, value: string): string {\n const pattern = new RegExp(`^${key.replace('.', '\\\\.')}\\\\s*=.*$`, 'm');\n const line = `${key} = \"${value}\"`;\n if (pattern.test(content)) {\n return content.replace(pattern, line);\n }\n // Insert before the first [section] header so the key stays at the top level.\n // Appending to the end would place it inside whatever TOML section comes last.\n const sectionMatch = content.match(/^\\[/m);\n if (sectionMatch && sectionMatch.index !== undefined) {\n return content.slice(0, sectionMatch.index) + line + '\\n' + content.slice(sectionMatch.index);\n }\n const separator = content.length > 0 && !content.endsWith('\\n') ? '\\n' : '';\n return content + separator + line + '\\n';\n}\n\nfunction removeTomlKey(content: string, key: string): string {\n const pattern = new RegExp(`^${key.replace('.', '\\\\.')}\\\\s*=.*\\\\n?`, 'gm');\n return content.replace(pattern, '');\n}\n\nfunction configureCodex(agent: DetectedAgent, proxyConfig: ProxyConfig): void {\n const configDir = process.platform === 'win32'\n ? path.join(os.homedir(), 'AppData', 'Roaming', 'codex')\n : path.join(os.homedir(), '.codex');\n const configPath = agent.configPath ?? path.join(configDir, 'config.toml');\n\n ensureDir(path.dirname(configPath));\n createBackup(configPath);\n\n let content = readTomlFile(configPath);\n content = setTomlKey(content, 'openai_base_url', `http://localhost:${proxyConfig.openaiPort}`);\n\n fs.writeFileSync(configPath, content);\n}\n\nexport function configureAgent(agent: DetectedAgent, proxyConfig: ProxyConfig): void {\n switch (agent.name) {\n case 'claude-code':\n configureClaudeCode(agent, proxyConfig);\n break;\n case 'codex':\n configureCodex(agent, proxyConfig);\n break;\n }\n}\n\nfunction unconfigureClaudeCode(agent: DetectedAgent): void {\n const configPath = agent.configPath ?? path.join(os.homedir(), '.claude', 'settings.json');\n\n // Always surgically remove only the ANTHROPIC_BASE_URL key.\n // Never restore from backup — the user may have changed other settings since install.\n if (!fs.existsSync(configPath)) return;\n\n const config = readJsonFile(configPath);\n if (config === null) {\n // Cannot parse settings.json — do NOT write to it.\n // Writing {} would wipe all Claude Code settings and break the installation.\n console.warn(` [!] Could not parse ${configPath} — skipping to avoid data loss. Remove ANTHROPIC_BASE_URL manually if needed.`);\n return;\n }\n\n if (config.env && typeof config.env === 'object') {\n delete (config.env as Record<string, unknown>).ANTHROPIC_BASE_URL;\n if (Object.keys(config.env as object).length === 0) {\n delete config.env;\n }\n }\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\n\n // Clean up stale backup file\n const backupPath = `${configPath}.skalpel-backup`;\n if (fs.existsSync(backupPath)) {\n fs.unlinkSync(backupPath);\n }\n}\n\nfunction unconfigureCodex(agent: DetectedAgent): void {\n const configDir = process.platform === 'win32'\n ? path.join(os.homedir(), 'AppData', 'Roaming', 'codex')\n : path.join(os.homedir(), '.codex');\n const configPath = agent.configPath ?? path.join(configDir, 'config.toml');\n\n // Always surgically remove only the openai_base_url key.\n if (fs.existsSync(configPath)) {\n let content = readTomlFile(configPath);\n content = removeTomlKey(content, 'openai_base_url');\n fs.writeFileSync(configPath, content);\n }\n\n // Clean up stale backup file\n const backupPath = `${configPath}.skalpel-backup`;\n if (fs.existsSync(backupPath)) {\n fs.unlinkSync(backupPath);\n }\n}\n\nexport function unconfigureAgent(agent: DetectedAgent): void {\n switch (agent.name) {\n case 'claude-code':\n unconfigureClaudeCode(agent);\n break;\n case 'codex':\n unconfigureCodex(agent);\n break;\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { execSync } from 'node:child_process';\nimport type { DetectedAgent } from './detect.js';\nimport type { ProxyConfig } from '../../proxy/types.js';\n\nconst BEGIN_MARKER = '# BEGIN SKALPEL PROXY - do not edit manually';\nconst END_MARKER = '# END SKALPEL PROXY';\n\nconst PS_BEGIN_MARKER = '# BEGIN SKALPEL PROXY - do not edit manually';\nconst PS_END_MARKER = '# END SKALPEL PROXY';\n\nfunction getUnixProfilePaths(): string[] {\n const home = os.homedir();\n const candidates = [\n path.join(home, '.bashrc'),\n path.join(home, '.zshrc'),\n path.join(home, '.bash_profile'),\n path.join(home, '.profile'),\n ];\n return candidates.filter((p) => fs.existsSync(p));\n}\n\nfunction getPowerShellProfilePath(): string | null {\n if (process.platform !== 'win32') return null;\n\n // Try $PROFILE env first\n if (process.env.PROFILE) return process.env.PROFILE;\n\n // Default PowerShell profile location\n const docsDir = path.join(os.homedir(), 'Documents');\n const psProfile = path.join(docsDir, 'PowerShell', 'Microsoft.PowerShell_profile.ps1');\n const wpProfile = path.join(docsDir, 'WindowsPowerShell', 'Microsoft.PowerShell_profile.ps1');\n\n if (fs.existsSync(psProfile)) return psProfile;\n if (fs.existsSync(wpProfile)) return wpProfile;\n\n // Return the modern PowerShell path as default (we'll create it)\n return psProfile;\n}\n\nfunction generateUnixBlock(proxyConfig: ProxyConfig): string {\n return [\n BEGIN_MARKER,\n `export ANTHROPIC_BASE_URL=\"http://localhost:${proxyConfig.anthropicPort}\"`,\n `export OPENAI_BASE_URL=\"http://localhost:${proxyConfig.openaiPort}\"`,\n END_MARKER,\n ].join('\\n');\n}\n\nfunction generatePowerShellBlock(proxyConfig: ProxyConfig): string {\n return [\n PS_BEGIN_MARKER,\n `$env:ANTHROPIC_BASE_URL = \"http://localhost:${proxyConfig.anthropicPort}\"`,\n `$env:OPENAI_BASE_URL = \"http://localhost:${proxyConfig.openaiPort}\"`,\n PS_END_MARKER,\n ].join('\\n');\n}\n\nfunction createBackup(filePath: string): void {\n const backupPath = `${filePath}.skalpel-backup`;\n fs.copyFileSync(filePath, backupPath);\n}\n\nfunction updateProfileFile(filePath: string, block: string, beginMarker: string, endMarker: string): void {\n if (fs.existsSync(filePath)) {\n createBackup(filePath);\n }\n\n let content = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8') : '';\n\n // Check if the block already exists\n const beginIdx = content.indexOf(beginMarker);\n const endIdx = content.indexOf(endMarker);\n\n if (beginIdx !== -1 && endIdx !== -1) {\n // Replace existing block\n content = content.slice(0, beginIdx) + block + content.slice(endIdx + endMarker.length);\n } else {\n // Append to end\n if (content.length > 0) {\n const trimmed = content.replace(/\\n+$/, '');\n content = trimmed + '\\n\\n' + block + '\\n';\n } else {\n content = block + '\\n';\n }\n }\n\n fs.writeFileSync(filePath, content);\n}\n\nexport function configureShellEnvVars(_agents: DetectedAgent[], proxyConfig: ProxyConfig): string[] {\n const modified: string[] = [];\n\n if (process.platform === 'win32') {\n const psProfile = getPowerShellProfilePath();\n if (psProfile) {\n const dir = path.dirname(psProfile);\n fs.mkdirSync(dir, { recursive: true });\n const block = generatePowerShellBlock(proxyConfig);\n updateProfileFile(psProfile, block, PS_BEGIN_MARKER, PS_END_MARKER);\n modified.push(psProfile);\n }\n } else {\n const profiles = getUnixProfilePaths();\n const block = generateUnixBlock(proxyConfig);\n for (const profilePath of profiles) {\n updateProfileFile(profilePath, block, BEGIN_MARKER, END_MARKER);\n modified.push(profilePath);\n }\n }\n\n return modified;\n}\n\nexport function removeShellEnvVars(): string[] {\n const restored: string[] = [];\n\n const home = os.homedir();\n const allProfiles = [\n path.join(home, '.bashrc'),\n path.join(home, '.zshrc'),\n path.join(home, '.bash_profile'),\n path.join(home, '.profile'),\n ];\n\n // Also check PowerShell profiles on Windows\n if (process.platform === 'win32') {\n const psProfile = getPowerShellProfilePath();\n if (psProfile) allProfiles.push(psProfile);\n }\n\n for (const profilePath of allProfiles) {\n if (!fs.existsSync(profilePath)) continue;\n\n const content = fs.readFileSync(profilePath, 'utf-8');\n const beginIdx = content.indexOf(BEGIN_MARKER);\n const endIdx = content.indexOf(END_MARKER);\n\n if (beginIdx === -1 || endIdx === -1) continue;\n\n // Always surgically remove the marker block.\n // Never restore from backup — the user may have edited the profile since install.\n const before = content.slice(0, beginIdx);\n const after = content.slice(endIdx + END_MARKER.length);\n // Clean up extra newlines\n const cleaned = (before.replace(/\\n+$/, '') + after.replace(/^\\n+/, '\\n')).trimEnd() + '\\n';\n fs.writeFileSync(profilePath, cleaned);\n\n // Clean up stale backup file\n const backupPath = `${profilePath}.skalpel-backup`;\n if (fs.existsSync(backupPath)) {\n fs.unlinkSync(backupPath);\n }\n\n restored.push(profilePath);\n }\n\n return restored;\n}\n\nexport function getConfiguredProfiles(): string[] {\n const configured: string[] = [];\n const home = os.homedir();\n const allProfiles = [\n path.join(home, '.bashrc'),\n path.join(home, '.zshrc'),\n path.join(home, '.bash_profile'),\n path.join(home, '.profile'),\n ];\n\n if (process.platform === 'win32') {\n const psProfile = getPowerShellProfilePath();\n if (psProfile) allProfiles.push(psProfile);\n }\n\n for (const profilePath of allProfiles) {\n if (!fs.existsSync(profilePath)) continue;\n const content = fs.readFileSync(profilePath, 'utf-8');\n if (content.includes(BEGIN_MARKER)) {\n configured.push(profilePath);\n }\n }\n\n return configured;\n}\n","import http from 'node:http';\nimport type { ProxyConfig, ProxyStatus } from './types.js';\nimport { handleRequest } from './handler.js';\nimport { handleHealthRequest } from './health.js';\nimport { writePid, readPid, removePid } from './pid.js';\nimport { Logger } from './logger.js';\n\nlet proxyStartTime = 0;\nlet passthroughMode = false;\n\n/** Returns whether the proxy is currently in passthrough mode (skipping Skalpel optimization). */\nexport function isPassthroughMode(): boolean {\n return passthroughMode;\n}\n\nfunction collectAdminBody(req: http.IncomingMessage): Promise<string> {\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).toString()));\n req.on('error', reject);\n });\n}\n\nfunction handleAdminMode(req: http.IncomingMessage, res: http.ServerResponse, logger: Logger): void {\n collectAdminBody(req).then((body) => {\n try {\n const { mode } = JSON.parse(body);\n passthroughMode = (mode === 'passthrough');\n logger.info(`Proxy mode changed to: ${passthroughMode ? 'passthrough' : 'normal'}`);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ mode: passthroughMode ? 'passthrough' : 'normal' }));\n } catch {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'invalid JSON body' }));\n }\n }).catch(() => {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'failed to read body' }));\n });\n}\n\nexport function startProxy(config: ProxyConfig): { anthropicServer: http.Server; openaiServer: http.Server } {\n const logger = new Logger(config.logFile, config.logLevel);\n const startTime = Date.now();\n proxyStartTime = Date.now();\n passthroughMode = false;\n\n const anthropicServer = http.createServer((req, res) => {\n if (req.url === '/health' && req.method === 'GET') {\n handleHealthRequest(res, config, startTime, isPassthroughMode());\n return;\n }\n if (req.url === '/admin/mode' && req.method === 'POST') {\n handleAdminMode(req, res, logger);\n return;\n }\n handleRequest(req, res, config, 'claude-code', logger);\n });\n\n const openaiServer = http.createServer((req, res) => {\n if (req.url === '/health' && req.method === 'GET') {\n handleHealthRequest(res, config, startTime, isPassthroughMode());\n return;\n }\n if (req.url === '/admin/mode' && req.method === 'POST') {\n handleAdminMode(req, res, logger);\n return;\n }\n handleRequest(req, res, config, 'codex', logger);\n });\n\n // Handle port binding errors (EADDRINUSE, EACCES, etc.)\n anthropicServer.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n logger.error(`Port ${config.anthropicPort} is already in use. Another Skalpel proxy or process may be running.`);\n } else {\n logger.error(`Anthropic proxy failed to bind port ${config.anthropicPort}: ${err.message}`);\n }\n removePid(config.pidFile);\n process.exit(1);\n });\n\n openaiServer.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n logger.error(`Port ${config.openaiPort} is already in use. Another Skalpel proxy or process may be running.`);\n } else {\n logger.error(`OpenAI proxy failed to bind port ${config.openaiPort}: ${err.message}`);\n }\n removePid(config.pidFile);\n process.exit(1);\n });\n\n anthropicServer.listen(config.anthropicPort, () => {\n logger.info(`Anthropic proxy listening on port ${config.anthropicPort}`);\n });\n\n openaiServer.listen(config.openaiPort, () => {\n logger.info(`OpenAI proxy listening on port ${config.openaiPort}`);\n });\n\n writePid(config.pidFile);\n logger.info(`Proxy started (pid=${process.pid}) ports=${config.anthropicPort},${config.openaiPort}`);\n\n const cleanup = () => {\n logger.info('Shutting down proxy...');\n anthropicServer.close();\n openaiServer.close();\n removePid(config.pidFile);\n process.exit(0);\n };\n\n process.on('SIGTERM', cleanup);\n process.on('SIGINT', cleanup);\n\n // Catch unexpected errors so PID file is always cleaned up\n process.on('uncaughtException', (err) => {\n logger.error(`Uncaught exception: ${err.message}`);\n removePid(config.pidFile);\n process.exit(1);\n });\n\n process.on('unhandledRejection', (reason) => {\n logger.error(`Unhandled rejection: ${reason}`);\n removePid(config.pidFile);\n process.exit(1);\n });\n\n return { anthropicServer, openaiServer };\n}\n\nexport function stopProxy(config: ProxyConfig): boolean {\n const pid = readPid(config.pidFile);\n if (pid === null) return false;\n\n try {\n process.kill(pid, 'SIGTERM');\n } catch {\n // Process already gone\n }\n\n removePid(config.pidFile);\n return true;\n}\n\nexport function getProxyStatus(config: ProxyConfig): ProxyStatus {\n const pid = readPid(config.pidFile);\n return {\n running: pid !== null,\n pid,\n uptime: proxyStartTime > 0 ? Date.now() - proxyStartTime : 0,\n anthropicPort: config.anthropicPort,\n openaiPort: config.openaiPort,\n };\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { ProxyConfig } from './types.js';\nimport type { Logger } from './logger.js';\n\nconst HOP_BY_HOP = new Set([\n 'connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization',\n 'te', 'trailer', 'transfer-encoding', 'upgrade',\n]);\n\nconst STRIP_HEADERS = new Set([\n ...HOP_BY_HOP,\n 'content-encoding', 'content-length',\n]);\n\n/** Remove Skalpel-specific headers so a direct-to-Anthropic fallback request is clean. */\nfunction stripSkalpelHeaders(headers: Record<string, string>): Record<string, string> {\n const cleaned = { ...headers };\n delete cleaned['X-Skalpel-API-Key'];\n delete cleaned['X-Skalpel-Source'];\n delete cleaned['X-Skalpel-Agent-Type'];\n delete cleaned['X-Skalpel-SDK-Version'];\n return cleaned;\n}\n\n/** Returns true if the error or HTTP status indicates the Skalpel backend\n * itself is unreachable or broken (not a normal API error from Anthropic). */\nfunction isSkalpelBackendFailure(response: Response | null, err: unknown): boolean {\n if (err) return true;\n if (!response) return true;\n if (response.status >= 500) return true;\n // 403 from Skalpel (e.g. \"No active plan\") is a Skalpel-specific rejection,\n // not an Anthropic error — fall back to direct API so requests still work.\n if (response.status === 403) return true;\n return false;\n}\n\nasync function doStreamingFetch(\n url: string,\n body: string,\n headers: Record<string, string>,\n): Promise<Response> {\n return fetch(url, { method: 'POST', headers, body });\n}\n\nexport async function handleStreamingRequest(\n _req: IncomingMessage,\n res: ServerResponse,\n _config: ProxyConfig,\n _source: string,\n body: string,\n skalpelUrl: string,\n directUrl: string,\n useSkalpel: boolean,\n forwardHeaders: Record<string, string>,\n logger: Logger,\n): Promise<void> {\n let response: Response | null = null;\n let fetchError: unknown = null;\n let usedFallback = false;\n\n // Try Skalpel backend first (if this request should be optimized)\n if (useSkalpel) {\n try {\n response = await doStreamingFetch(skalpelUrl, body, forwardHeaders);\n } catch (err) {\n fetchError = err;\n }\n\n // If Skalpel backend is down, fall back to direct Anthropic API\n if (isSkalpelBackendFailure(response, fetchError)) {\n logger.warn(`streaming: Skalpel backend failed (${fetchError ? (fetchError as Error).message : `status ${response?.status}`}), falling back to direct Anthropic API`);\n usedFallback = true;\n response = null;\n fetchError = null;\n const directHeaders = stripSkalpelHeaders(forwardHeaders);\n try {\n response = await doStreamingFetch(directUrl, body, directHeaders);\n } catch (err) {\n fetchError = err;\n }\n }\n } else {\n // Non-Skalpel path — go direct\n try {\n response = await doStreamingFetch(directUrl, body, forwardHeaders);\n } catch (err) {\n fetchError = err;\n }\n }\n\n // If even the direct request failed, return error\n if (!response || fetchError) {\n const errMsg = fetchError ? (fetchError as Error).message : 'no response from upstream';\n logger.error(`streaming fetch failed: ${errMsg}`);\n res.writeHead(502, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n });\n res.write(`event: error\\ndata: ${JSON.stringify({ error: errMsg })}\\n\\n`);\n res.end();\n return;\n }\n\n if (usedFallback) {\n logger.info('streaming: using direct Anthropic API fallback');\n }\n\n // For non-2xx responses, pass through as-is so the SDK can parse error bodies correctly\n if (response.status >= 300) {\n const errorBody = Buffer.from(await response.arrayBuffer());\n logger.error(`streaming upstream error: status=${response.status} body=${errorBody.toString().slice(0, 500)}`);\n const passthroughHeaders: Record<string, string> = {};\n for (const [key, value] of response.headers.entries()) {\n if (!STRIP_HEADERS.has(key)) {\n passthroughHeaders[key] = value;\n }\n }\n passthroughHeaders['content-length'] = String(errorBody.length);\n res.writeHead(response.status, passthroughHeaders);\n res.end(errorBody);\n return;\n }\n\n // Build SSE headers, stripping hop-by-hop/encoding and normalizing content-type\n const sseHeaders: Record<string, string> = {};\n for (const [key, value] of response.headers.entries()) {\n if (!STRIP_HEADERS.has(key) && key !== 'content-type') {\n sseHeaders[key] = value;\n }\n }\n sseHeaders['Content-Type'] = 'text/event-stream';\n sseHeaders['Cache-Control'] = 'no-cache';\n res.writeHead(response.status, sseHeaders);\n\n if (!response.body) {\n res.write(`event: error\\ndata: ${JSON.stringify({ error: 'no response body' })}\\n\\n`);\n res.end();\n return;\n }\n\n try {\n const reader = (response.body as ReadableStream<Uint8Array>).getReader();\n const decoder = new TextDecoder();\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = decoder.decode(value, { stream: true });\n res.write(chunk);\n }\n } catch (err) {\n logger.error(`streaming error: ${(err as Error).message}`);\n res.write(`event: error\\ndata: ${JSON.stringify({ error: (err as Error).message })}\\n\\n`);\n }\n\n res.end();\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nconst MAX_SIZE = 5 * 1024 * 1024; // 5MB\nconst MAX_ROTATIONS = 3;\n\nconst LEVELS = { debug: 0, info: 1, warn: 2, error: 3 } as const;\n\nexport class Logger {\n private logFile: string;\n private level: keyof typeof LEVELS;\n\n constructor(logFile: string, level: keyof typeof LEVELS = 'info') {\n this.logFile = logFile;\n this.level = level;\n fs.mkdirSync(path.dirname(logFile), { recursive: true });\n }\n\n debug(msg: string): void { this.log('debug', msg); }\n info(msg: string): void { this.log('info', msg); }\n warn(msg: string): void { this.log('warn', msg); }\n error(msg: string): void { this.log('error', msg); }\n\n private log(level: keyof typeof LEVELS, msg: string): void {\n if (LEVELS[level] < LEVELS[this.level]) return;\n\n const line = `${new Date().toISOString()} [${level.toUpperCase()}] ${msg}\\n`;\n\n if (level === 'debug' || level === 'error') {\n process.stderr.write(line);\n }\n\n try {\n this.rotate();\n fs.appendFileSync(this.logFile, line);\n } catch {\n // Best-effort logging\n }\n }\n\n private rotate(): void {\n try {\n const stat = fs.statSync(this.logFile);\n if (stat.size < MAX_SIZE) return;\n } catch {\n return;\n }\n\n for (let i = MAX_ROTATIONS; i >= 1; i--) {\n const src = i === 1 ? this.logFile : `${this.logFile}.${i - 1}`;\n const dst = `${this.logFile}.${i}`;\n try {\n fs.renameSync(src, dst);\n } catch {\n // File may not exist\n }\n }\n }\n}\n","import { loadConfig } from '../proxy/config.js';\nimport { stopProxy } from '../proxy/server.js';\nimport { readPid } from '../proxy/pid.js';\nimport type { ProxyConfig } from '../proxy/types.js';\nimport { isServiceInstalled, stopService } from './service/install.js';\nimport { detectAgents } from './agents/detect.js';\nimport { unconfigureAgent } from './agents/configure.js';\nimport { removeShellEnvVars } from './agents/shell.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\n/** Tell the running proxy to enter passthrough mode (bypass Skalpel, route direct). */\nasync function setPassthroughMode(config: ProxyConfig): Promise<boolean> {\n try {\n const res = await fetch(`http://localhost:${config.anthropicPort}/admin/mode`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ mode: 'passthrough' }),\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\nexport async function runStop(): Promise<void> {\n const config = loadConfig();\n\n const pid = readPid(config.pidFile);\n\n if (pid === null) {\n print(' Proxy is not running.');\n return;\n }\n\n // Try to switch the running proxy to passthrough mode so that\n // already-running Claude Code sessions keep working (they have\n // ANTHROPIC_BASE_URL cached in memory and can't re-read settings.json).\n const switched = await setPassthroughMode(config);\n\n if (switched) {\n print(' Skalpel optimization paused (proxy running in passthrough mode).');\n print(' Requests now go directly to provider APIs.');\n print(' Run \"skalpel start\" to re-enable optimization.');\n return;\n }\n\n // If we couldn't reach the proxy (already dead?), fall back to full stop.\n print(' Could not reach proxy — performing full shutdown...');\n\n if (isServiceInstalled()) {\n stopService();\n }\n\n const stopped = stopProxy(config);\n\n if (stopped) {\n print(' Skalpel proxy stopped.');\n } else {\n print(' Proxy is not running.');\n }\n\n // Only clean up agent configs when we actually killed the proxy,\n // since the port is now dead and agents need to go direct.\n const restoredProfiles = removeShellEnvVars();\n if (restoredProfiles.length > 0) {\n for (const p of restoredProfiles) {\n print(` Restored shell profile: ${p}`);\n }\n }\n\n const agents = detectAgents();\n for (const agent of agents) {\n if (agent.installed) {\n try {\n unconfigureAgent(agent);\n print(` Restored ${agent.name} config`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n print(` Could not restore ${agent.name}: ${msg}`);\n }\n }\n }\n}\n","import { loadConfig } from '../proxy/config.js';\nimport { getProxyStatus } from '../proxy/server.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\n/** Fetch the mode from the running proxy's /health endpoint. */\nasync function fetchProxyMode(port: number): Promise<string | null> {\n try {\n const res = await fetch(`http://localhost:${port}/health`);\n if (res.ok) {\n const data = await res.json() as { mode?: string };\n return data.mode ?? null;\n }\n } catch {\n // Proxy not reachable\n }\n return null;\n}\n\nexport async function runStatus(): Promise<void> {\n const config = loadConfig();\n const status = getProxyStatus(config);\n\n print('');\n print(' Skalpel Proxy Status');\n print(' ────────────────────');\n print(` Status: ${status.running ? 'running' : 'stopped'}`);\n if (status.pid !== null) {\n print(` PID: ${status.pid}`);\n }\n\n if (status.running) {\n const mode = await fetchProxyMode(config.anthropicPort);\n if (mode) {\n print(` Mode: ${mode}`);\n }\n }\n\n print(` Anthropic: port ${status.anthropicPort}`);\n print(` OpenAI: port ${status.openaiPort}`);\n print(` Config: ${config.configFile}`);\n print('');\n}\n","import fs from 'node:fs';\nimport { loadConfig } from '../proxy/config.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport async function runLogs(options: { lines?: string; follow?: boolean }): Promise<void> {\n const config = loadConfig();\n const logFile = config.logFile;\n const lineCount = parseInt(options.lines ?? '50', 10);\n\n if (!fs.existsSync(logFile)) {\n print(` No log file found at ${logFile}`);\n return;\n }\n\n const content = fs.readFileSync(logFile, 'utf-8');\n const lines = content.trimEnd().split('\\n');\n const tail = lines.slice(-lineCount);\n\n for (const line of tail) {\n print(line);\n }\n\n if (options.follow) {\n let position = fs.statSync(logFile).size;\n fs.watchFile(logFile, { interval: 500 }, () => {\n try {\n const stat = fs.statSync(logFile);\n if (stat.size > position) {\n const fd = fs.openSync(logFile, 'r');\n const buf = Buffer.alloc(stat.size - position);\n fs.readSync(fd, buf, 0, buf.length, position);\n fs.closeSync(fd);\n process.stdout.write(buf.toString('utf-8'));\n position = stat.size;\n }\n } catch {\n // File may have rotated\n }\n });\n }\n}\n","import { loadConfig, saveConfig } from '../proxy/config.js';\nimport type { ProxyConfig } from '../proxy/types.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport async function runConfig(subcommand?: string, args?: string[]): Promise<void> {\n const config = loadConfig();\n\n if (subcommand === 'path') {\n print(config.configFile);\n return;\n }\n\n if (subcommand === 'set') {\n if (!args || args.length < 2) {\n print(' Usage: skalpel config set <key> <value>');\n process.exit(1);\n }\n const key = args[0] as keyof ProxyConfig;\n const value = args[1];\n const validKeys: (keyof ProxyConfig)[] = [\n 'apiKey', 'remoteBaseUrl', 'anthropicPort', 'openaiPort',\n 'logLevel', 'logFile', 'pidFile',\n ];\n\n if (!validKeys.includes(key)) {\n print(` Unknown config key: ${key}`);\n print(` Valid keys: ${validKeys.join(', ')}`);\n process.exit(1);\n }\n\n const updated = { ...config };\n if (key === 'anthropicPort' || key === 'openaiPort') {\n const parsed = parseInt(value, 10);\n if (isNaN(parsed) || parsed < 1 || parsed > 65535) {\n print(` Invalid port number: ${value}`);\n process.exit(1);\n }\n (updated as any)[key] = parsed;\n } else if (key === 'logLevel') {\n const validLevels = ['debug', 'info', 'warn', 'error'];\n if (!validLevels.includes(value)) {\n print(` Invalid log level: ${value}`);\n print(` Valid levels: ${validLevels.join(', ')}`);\n process.exit(1);\n }\n (updated as any)[key] = value;\n } else {\n (updated as any)[key] = value;\n }\n\n saveConfig(updated);\n print(` Set ${key} = ${value}`);\n return;\n }\n\n print(JSON.stringify(config, null, 2));\n}\n","import { exec } from 'node:child_process';\nimport { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\nconst pkg = require('../../package.json');\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport async function runUpdate(): Promise<void> {\n print(` Current version: ${pkg.version}`);\n print(' Checking for updates...');\n\n try {\n const latest = await new Promise<string>((resolve, reject) => {\n exec('npm view skalpel version', (err, stdout) => {\n if (err) reject(err);\n else resolve(stdout.trim());\n });\n });\n\n if (latest === pkg.version) {\n print(` Already on the latest version (${pkg.version}).`);\n return;\n }\n\n print(` Updating to ${latest}...`);\n\n await new Promise<void>((resolve, reject) => {\n exec('npm install -g skalpel@latest', (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n\n print(` Updated to ${latest}.`);\n } catch (err) {\n print(` Update failed: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n","import * as readline from 'node:readline';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { detectAgents } from './agents/detect.js';\nimport type { DetectedAgent } from './agents/detect.js';\nimport { configureAgent } from './agents/configure.js';\nimport { installService } from './service/install.js';\nimport { loadConfig, saveConfig } from '../proxy/config.js';\nimport { validateApiKey } from './utils.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\n\nexport async function runWizard(options?: { apiKey?: string; auto?: boolean; skipClaude?: boolean; skipCodex?: boolean }): Promise<void> {\n const isAuto = options?.auto === true;\n\n let rl: readline.Interface | undefined;\n let ask: (question: string) => Promise<string>;\n\n if (!isAuto) {\n rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n ask = (question: string): Promise<string> => {\n return new Promise((resolve) => {\n rl!.question(question, (answer) => resolve(answer.trim()));\n });\n };\n } else {\n ask = () => Promise.resolve('');\n }\n\n try {\n // Step 1: Welcome\n print('');\n print(' _____ _ _ _ ');\n print(' / ____| | | | | |');\n print(' | (___ | | ____ _| |_ __ ___| |');\n print(' \\\\___ \\\\| |/ / _` | | \\'_ \\\\ / _ \\\\ |');\n print(' ____) | < (_| | | |_) | __/ |');\n print(' |_____/|_|\\\\_\\\\__,_|_| .__/ \\\\___|_|');\n print(' | | ');\n print(' |_| ');\n print('');\n print(' Welcome to Skalpel! Let\\'s optimize your coding agent costs.');\n print(' ─────────────────────────────────────────────────────────');\n print('');\n\n // Step 2: API Key\n const skalpelDir = path.join(os.homedir(), '.skalpel');\n const configPath = path.join(skalpelDir, 'config.json');\n let apiKey = '';\n\n if (isAuto && options?.apiKey) {\n apiKey = options.apiKey;\n if (!validateApiKey(apiKey)) {\n print(' Error: Invalid API key. Must start with \"sk-skalpel-\" and be at least 20 characters.');\n process.exit(1);\n }\n print(` API key set: ${apiKey.slice(0, 14)}${'*'.repeat(Math.max(0, apiKey.length - 14))}`);\n } else if (isAuto && !options?.apiKey) {\n print(' Error: --api-key is required when using --auto mode.');\n process.exit(1);\n } else {\n if (fs.existsSync(configPath)) {\n try {\n const existing = JSON.parse(fs.readFileSync(configPath, 'utf-8'));\n if (existing.apiKey && validateApiKey(existing.apiKey)) {\n const masked = existing.apiKey.slice(0, 14) + '*'.repeat(Math.max(0, existing.apiKey.length - 14));\n const useExisting = await ask(` Found existing API key: ${masked}\\n Use this key? (Y/n): `);\n if (useExisting.toLowerCase() !== 'n') {\n apiKey = existing.apiKey;\n print(` Using existing API key.`);\n }\n }\n } catch {\n // invalid config file, proceed to ask\n }\n }\n\n if (!apiKey) {\n apiKey = await ask(' Paste your Skalpel API key (sk-skalpel-...): ');\n if (!validateApiKey(apiKey)) {\n print(' Error: Invalid API key. Must start with \"sk-skalpel-\" and be at least 20 characters.');\n rl!.close();\n process.exit(1);\n }\n print(` API key set: ${apiKey.slice(0, 14)}${'*'.repeat(Math.max(0, apiKey.length - 14))}`);\n }\n }\n print('');\n\n // Save API key to config\n fs.mkdirSync(skalpelDir, { recursive: true });\n const proxyConfig = loadConfig(configPath);\n proxyConfig.apiKey = apiKey;\n saveConfig(proxyConfig);\n\n // Step 3: Agent Detection\n print(' Detecting coding agents...');\n const agents = detectAgents();\n const installedAgents = agents.filter((a) => a.installed);\n const notInstalled = agents.filter((a) => !a.installed);\n\n if (installedAgents.length > 0) {\n for (const agent of installedAgents) {\n const ver = agent.version ? ` v${agent.version}` : '';\n print(` [+] Found: ${agent.name}${ver}`);\n }\n }\n if (notInstalled.length > 0) {\n for (const agent of notInstalled) {\n print(` [ ] Not found: ${agent.name}`);\n }\n }\n if (installedAgents.length === 0) {\n print(' Warning: No coding agents detected. You can install them later.');\n print(' The proxy will be configured and ready when agents are installed.');\n }\n print('');\n\n // Filter out skipped agents\n let agentsToConfigure: DetectedAgent[] = installedAgents.filter((a) => {\n if (options?.skipClaude && a.name === 'claude-code') return false;\n if (options?.skipCodex && a.name === 'codex') return false;\n return true;\n });\n if (agentsToConfigure.length > 0 && !isAuto) {\n const agentNames = installedAgents.map((a) => a.name).join(', ');\n const confirm = await ask(` Configure ${agentNames}? (Y/n): `);\n if (confirm.toLowerCase() === 'n') {\n agentsToConfigure = [];\n }\n }\n print('');\n\n // Step 4: Configuration\n if (agentsToConfigure.length > 0) {\n print(' Configuring agents...');\n\n // Configure agent-specific config files (scoped to each agent's own config)\n for (const agent of agentsToConfigure) {\n configureAgent(agent, proxyConfig);\n print(` Configured ${agent.name}${agent.configPath ? ` (${agent.configPath})` : ''}`);\n }\n print('');\n }\n\n // Step 5: Service Installation\n print(' Installing proxy as system service...');\n try {\n installService(proxyConfig);\n print(' Service installed successfully.');\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n print(` Warning: Could not install service: ${msg}`);\n print(' You can start the proxy manually with: skalpel start');\n }\n print('');\n\n // Step 6: Verification\n print(' Verifying proxy...');\n let proxyOk = false;\n try {\n // Give the service a moment to start\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 3000);\n const healthUrl = `http://localhost:${proxyConfig.anthropicPort}/health`;\n const res = await fetch(healthUrl, { signal: controller.signal });\n clearTimeout(timeout);\n if (res.ok) {\n print(` [+] Anthropic proxy (port ${proxyConfig.anthropicPort}): healthy`);\n proxyOk = true;\n } else {\n print(` [!] Anthropic proxy (port ${proxyConfig.anthropicPort}): HTTP ${res.status}`);\n }\n } catch {\n print(` [!] Proxy not responding yet. It may take a moment to start.`);\n print(' Run \"npx skalpel status\" to check later, or \"npx skalpel start\" to start manually.');\n }\n\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 3000);\n const healthUrl = `http://localhost:${proxyConfig.openaiPort}/health`;\n const res = await fetch(healthUrl, { signal: controller.signal });\n clearTimeout(timeout);\n if (res.ok) {\n print(` [+] OpenAI proxy (port ${proxyConfig.openaiPort}): healthy`);\n } else {\n print(` [!] OpenAI proxy (port ${proxyConfig.openaiPort}): HTTP ${res.status}`);\n }\n } catch {\n // Already warned above\n }\n print('');\n\n // Step 7: Success\n print(' ─────────────────────────────────────────────────────────');\n print('');\n print(' You\\'re all set! Your coding agents now route through Skalpel.');\n print('');\n if (agentsToConfigure.length > 0) {\n print(' Configured agents: ' + agentsToConfigure.map((a) => a.name).join(', '));\n }\n print(' Proxy ports: Anthropic=' + proxyConfig.anthropicPort + ', OpenAI=' + proxyConfig.openaiPort);\n print('');\n print(' Run \"npx skalpel status\" to check proxy status');\n print(' Run \"npx skalpel doctor\" for a full health check');\n print(' Run \"npx skalpel uninstall\" to remove everything');\n print('');\n\n if (rl) rl.close();\n } catch (err) {\n if (rl) rl.close();\n throw err;\n }\n}\n","import * as readline from 'node:readline';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { execSync } from 'node:child_process';\nimport { detectAgents } from './agents/detect.js';\nimport { removeShellEnvVars } from './agents/shell.js';\nimport { unconfigureAgent } from './agents/configure.js';\nimport { uninstallService } from './service/install.js';\nimport { loadConfig } from '../proxy/config.js';\nimport { stopProxy } from '../proxy/server.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport interface UninstallOptions {\n force?: boolean;\n}\n\nexport async function runUninstall(options?: UninstallOptions): Promise<void> {\n const force = options?.force ?? false;\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n function ask(question: string): Promise<string> {\n return new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n }\n\n try {\n print('');\n print(' Skalpel Uninstall');\n print(' ─────────────────');\n print('');\n\n if (!force) {\n const confirm = await ask(' This will remove Skalpel proxy, service, and agent configurations. Continue? (y/N): ');\n if (confirm.toLowerCase() !== 'y') {\n print(' Aborted.');\n rl.close();\n return;\n }\n print('');\n }\n\n const config = loadConfig();\n const removed: string[] = [];\n\n // Uninstall OS service FIRST — the service has KeepAlive=true (macOS) or\n // Restart=always (Linux), so if we kill the proxy process before removing\n // the service, the service manager will immediately respawn it, leaving an\n // orphaned proxy on port 18100.\n print(' Removing system service...');\n try {\n uninstallService();\n print(' [+] Service removed');\n removed.push('system service');\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n print(` [!] Could not remove service: ${msg}`);\n }\n\n // Now stop any remaining proxy process (safety net for non-service runs)\n print(' Stopping proxy...');\n const stopped = stopProxy(config);\n if (stopped) {\n print(' [+] Proxy stopped');\n removed.push('proxy process');\n } else {\n print(' [ ] Proxy was not running');\n }\n\n // Remove shell env vars\n print(' Removing shell environment variables...');\n const restoredProfiles = removeShellEnvVars();\n if (restoredProfiles.length > 0) {\n for (const p of restoredProfiles) {\n print(` [+] Restored: ${p}`);\n }\n removed.push('shell env vars');\n } else {\n print(' [ ] No shell profiles had Skalpel config');\n }\n\n // Unconfigure agents\n print(' Restoring agent configurations...');\n const agents = detectAgents();\n for (const agent of agents) {\n if (agent.installed) {\n try {\n unconfigureAgent(agent);\n print(` [+] Restored ${agent.name} config`);\n removed.push(`${agent.name} config`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n print(` [!] Could not restore ${agent.name}: ${msg}`);\n }\n }\n }\n print('');\n\n // Remove ~/.skalpel/ directory\n const skalpelDir = path.join(os.homedir(), '.skalpel');\n if (fs.existsSync(skalpelDir)) {\n let shouldRemove = force;\n if (!force) {\n const removeDir = await ask(' Remove ~/.skalpel/ directory (contains config and logs)? (y/N): ');\n shouldRemove = removeDir.toLowerCase() === 'y';\n }\n if (shouldRemove) {\n fs.rmSync(skalpelDir, { recursive: true, force: true });\n print(' [+] Removed ~/.skalpel/');\n removed.push('~/.skalpel/ directory');\n }\n }\n\n // Clear npx cache for skalpel\n print(' Clearing npx cache...');\n try {\n clearNpxCache();\n print(' [+] npx cache cleared');\n removed.push('npx cache');\n } catch {\n print(' [ ] Could not clear npx cache (not critical)');\n }\n\n print('');\n print(' ─────────────────');\n if (removed.length > 0) {\n print(' Removed: ' + removed.join(', '));\n } else {\n print(' Nothing to remove.');\n }\n print(' Skalpel has been uninstalled.');\n if (restoredProfiles.length > 0) {\n print(' Restart your shell to apply env var changes.');\n }\n print('');\n\n rl.close();\n } catch (err) {\n rl.close();\n throw err;\n }\n}\n\nfunction clearNpxCache(): void {\n // npm stores npx cache in ~/.npm/_npx/\n // Find and remove only the skalpel-related cache entries\n const npxCacheDir = path.join(os.homedir(), '.npm', '_npx');\n if (!fs.existsSync(npxCacheDir)) return;\n\n const entries = fs.readdirSync(npxCacheDir);\n for (const entry of entries) {\n const pkgJsonPath = path.join(npxCacheDir, entry, 'node_modules', 'skalpel', 'package.json');\n const pkgJsonAlt = path.join(npxCacheDir, entry, 'node_modules', '.package-lock.json');\n if (fs.existsSync(pkgJsonPath)) {\n fs.rmSync(path.join(npxCacheDir, entry), { recursive: true, force: true });\n continue;\n }\n // Check the lockfile for skalpel references\n if (fs.existsSync(pkgJsonAlt)) {\n try {\n const content = fs.readFileSync(pkgJsonAlt, 'utf-8');\n if (content.includes('\"skalpel\"')) {\n fs.rmSync(path.join(npxCacheDir, entry), { recursive: true, force: true });\n }\n } catch {\n // ignore read errors\n }\n }\n }\n}\n"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,SAAS,iBAAAA,sBAAqB;;;ACD9B,YAAY,cAAc;AAC1B,YAAYC,SAAQ;AACpB,YAAYC,WAAU;;;ACFtB,YAAY,QAAQ;AACpB,YAAY,UAAU;AAGf,SAAS,oBAAiD;AAC/D,MAAO,cAAgB,UAAK,QAAQ,IAAI,GAAG,cAAc,CAAC,GAAG;AAC3D,WAAO;AAAA,EACT;AACA,MACK,cAAgB,UAAK,QAAQ,IAAI,GAAG,kBAAkB,CAAC,KACvD,cAAgB,UAAK,QAAQ,IAAI,GAAG,gBAAgB,CAAC,GACxD;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,aAAa,aAA0C;AACrE,QAAM,YAAiC,CAAC;AAExC,MAAI,gBAAgB,QAAQ;AAC1B,QAAI;AACF,YAAM,UAAe,UAAK,QAAQ,IAAI,GAAG,cAAc;AACvD,YAAMC,OAAM,KAAK,MAAS,gBAAa,SAAS,OAAO,CAAC;AACxD,YAAM,UAAU;AAAA,QACd,GAAGA,KAAI;AAAA,QACP,GAAGA,KAAI;AAAA,MACT;AACA,UAAI,QAAQ,QAAQ,EAAG,WAAU,KAAK,QAAQ;AAC9C,UAAI,QAAQ,mBAAmB,EAAG,WAAU,KAAK,WAAW;AAAA,IAC9D,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MAAI,gBAAgB,UAAU;AAC5B,QAAI;AACF,YAAM,UAAe,UAAK,QAAQ,IAAI,GAAG,kBAAkB;AAC3D,UAAO,cAAW,OAAO,GAAG;AAC1B,cAAM,UAAa,gBAAa,SAAS,OAAO;AAChD,YAAI,WAAW,KAAK,OAAO,EAAG,WAAU,KAAK,QAAQ;AACrD,YAAI,cAAc,KAAK,OAAO,EAAG,WAAU,KAAK,WAAW;AAAA,MAC7D;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,eAAe,KAAsB;AACnD,SAAO,IAAI,WAAW,aAAa,KAAK,IAAI,UAAU;AACxD;AAEO,SAAS,mBAAmB,QAA4B;AAC7D,MAAI,OAAO,sBAAsB,WAAW;AAC1C,QAAI,OAAO,UAAU,SAAS,QAAQ,GAAG;AACvC,aAAO;AAAA;AAAA;AAAA;AAAA,yCAI4B,OAAO,YAAY;AAAA,gBAAmB,OAAO,SAAS,OAAO,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOpG;AACA,QAAI,OAAO,UAAU,SAAS,WAAW,GAAG;AAC1C,aAAO;AAAA;AAAA;AAAA;AAAA,yCAI4B,OAAO,YAAY;AAAA,gBAAmB,OAAO,SAAS,OAAO,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQpG;AAAA,EACF;AAEA,MAAI,OAAO,sBAAsB,YAAY;AAC3C,QAAI,OAAO,UAAU,SAAS,QAAQ,GAAG;AACvC,aAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAWT;AACA,QAAI,OAAO,UAAU,SAAS,WAAW,GAAG;AAC1C,aAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAYT;AAAA,EACF;AAEA,SAAO;AAAA,qBACY,OAAO,MAAM;AAAA;AAElC;;;ADjHA,SAAS,MAAM,KAAmB;AAChC,UAAQ,IAAI,GAAG;AACjB;AAEA,eAAsB,UAAyB;AAC7C,QAAM,KAAc,yBAAgB;AAAA,IAClC,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ;AAAA,EAClB,CAAC;AAED,WAAS,IAAI,UAAmC;AAC9C,WAAO,IAAI,QAAQ,CAACC,aAAY;AAC9B,SAAG,SAAS,UAAU,CAAC,WAAWA,SAAQ,OAAO,KAAK,CAAC,CAAC;AAAA,IAC1D,CAAC;AAAA,EACH;AAEA,MAAI;AACF,UAAM,EAAE;AACR,UAAM,+BAA0B;AAChC,UAAM,kIAAyB;AAC/B,UAAM,EAAE;AAGR,UAAM,cAAc,kBAAkB;AACtC,UAAM,4BAA4B,WAAW,EAAE;AAG/C,UAAM,OAAO,aAAa,WAAW;AACrC,QAAI,KAAK,SAAS,GAAG;AACnB,YAAM,uBAAuB,KAAK,KAAK,IAAI,CAAC,EAAE;AAAA,IAChD,OAAO;AACL,YAAM,uBAAuB;AAAA,IAC/B;AACA,UAAM,EAAE;AAGR,QAAI,SAAS,QAAQ,IAAI,mBAAmB;AAC5C,QAAI,UAAU,eAAe,MAAM,GAAG;AACpC,YAAM,iDAAiD,OAAO,MAAM,GAAG,EAAE,CAAC,KAAK;AAAA,IACjF,OAAO;AACL,eAAS,MAAM,IAAI,iDAAiD;AACpE,UAAI,CAAC,eAAe,MAAM,GAAG;AAC3B,cAAM,wFAAwF;AAC9F,WAAG,MAAM;AACT,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM,kBAAkB,OAAO,MAAM,GAAG,EAAE,CAAC,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,OAAO,SAAS,EAAE,CAAC,CAAC,EAAE;AAAA,IAC7F;AACA,UAAM,EAAE;AAGR,UAAM,8BAA8B;AACpC,UAAM,2FAAsF;AAC5F,UAAM,yEAAoE;AAC1E,UAAM,EAAE;AACR,UAAM,eAAe,MAAM,IAAI,2BAA2B;AAC1D,UAAM,oBAAoB,iBAAiB,MAAM,aAAa;AAC9D,UAAM,EAAE;AAGR,UAAM,UAAe,WAAK,QAAQ,IAAI,GAAG,MAAM;AAC/C,UAAM,aAAa,mBAAmB,MAAM;AAAA;AAAA;AAE5C,QAAO,eAAW,OAAO,GAAG;AAC1B,MAAG,mBAAe,SAAS;AAAA,EAAK,UAAU,EAAE;AAC5C,YAAM,iDAAiD;AAAA,IACzD,OAAO;AACL,MAAG,kBAAc,SAAS,UAAU;AACpC,YAAM,yCAAyC;AAAA,IACjD;AACA,UAAM,EAAE;AAGR,UAAM,YAAiC,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ;AACzE,UAAM,SAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,SAAS,mBAAmB,MAAM;AACxC,UAAM,0BAA0B;AAChC,UAAM,wIAA0B;AAChC,eAAW,QAAQ,OAAO,MAAM,IAAI,GAAG;AACrC,YAAM,OAAO,IAAI,EAAE;AAAA,IACrB;AACA,UAAM,wIAA0B;AAChC,UAAM,EAAE;AAGR,UAAM,oEAAoE;AAC1E,UAAM,EAAE;AAER,OAAG,MAAM;AAAA,EACX,SAAS,KAAK;AACZ,OAAG,MAAM;AACT,UAAM;AAAA,EACR;AACF;;;AEzGA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB,YAAYC,SAAQ;;;ACFpB,SAAS,gBAAgB;AACzB,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAO,QAAQ;AASf,SAAS,eAAuB;AAC9B,SAAO,QAAQ,aAAa,UAAU,UAAU;AAClD;AAEA,SAAS,QAAQ,KAA4B;AAC3C,MAAI;AACF,WAAO,SAAS,KAAK,EAAE,UAAU,SAAS,SAAS,KAAM,OAAO,CAAC,QAAQ,QAAQ,MAAM,EAAE,CAAC,EAAE,KAAK;AAAA,EACnG,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mBAAkC;AACzC,QAAM,QAAuB;AAAA,IAC3B,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAGA,QAAM,aAAa,QAAQ,GAAG,aAAa,CAAC,SAAS;AACrD,QAAM,YAAY,eAAe,QAAQ,WAAW,SAAS;AAG7D,QAAM,YAAYA,MAAK,KAAK,GAAG,QAAQ,GAAG,SAAS;AACnD,QAAM,eAAeD,IAAG,WAAW,SAAS;AAE5C,QAAM,YAAY,aAAa;AAE/B,MAAI,WAAW;AACb,UAAM,gBAAgB,QAAQ,kBAAkB;AAChD,QAAI,eAAe;AAEjB,YAAM,QAAQ,cAAc,MAAM,mBAAmB;AACrD,YAAM,UAAU,QAAQ,MAAM,CAAC,IAAI;AAAA,IACrC;AAAA,EACF;AAEA,QAAM,eAAeC,MAAK,KAAK,WAAW,eAAe;AACzD,MAAID,IAAG,WAAW,YAAY,GAAG;AAC/B,UAAM,aAAa;AAAA,EACrB,WAAW,cAAc;AAEvB,UAAM,aAAa;AAAA,EACrB;AAEA,SAAO;AACT;AAEA,SAAS,cAA6B;AACpC,QAAM,QAAuB;AAAA,IAC3B,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAGA,QAAM,aAAa,QAAQ,GAAG,aAAa,CAAC,QAAQ;AACpD,QAAM,YAAY,eAAe,QAAQ,WAAW,SAAS;AAG7D,QAAM,iBAAiB,QAAQ,aAAa,UACxCC,MAAK,KAAK,GAAG,QAAQ,GAAG,WAAW,WAAW,OAAO,IACrDA,MAAK,KAAK,GAAG,QAAQ,GAAG,QAAQ;AACpC,QAAM,eAAeD,IAAG,WAAW,cAAc;AAEjD,QAAM,YAAY,aAAa;AAE/B,MAAI,WAAW;AACb,UAAM,gBAAgB,QAAQ,iBAAiB;AAC/C,QAAI,eAAe;AACjB,YAAM,QAAQ,cAAc,MAAM,mBAAmB;AACrD,YAAM,UAAU,QAAQ,MAAM,CAAC,IAAI;AAAA,IACrC;AAAA,EACF;AAGA,QAAM,aAAaC,MAAK,KAAK,gBAAgB,aAAa;AAC1D,MAAID,IAAG,WAAW,UAAU,GAAG;AAC7B,UAAM,aAAa;AAAA,EACrB,WAAW,cAAc;AACvB,UAAM,aAAa;AAAA,EACrB;AAEA,SAAO;AACT;AAEO,SAAS,eAAgC;AAC9C,SAAO,CAAC,iBAAiB,GAAG,YAAY,CAAC;AAC3C;;;AD3FA,SAASE,OAAM,KAAmB;AAChC,UAAQ,IAAI,GAAG;AACjB;AAEA,SAAS,mBAAkC;AACzC,MAAI;AACF,UAAM,aAAkB,WAAQ,YAAQ,GAAG,YAAY,aAAa;AACpE,UAAM,MAAM,KAAK,MAAS,iBAAa,YAAY,OAAO,CAAC;AAC3D,QAAI,OAAO,IAAI,WAAW,YAAY,IAAI,OAAO,SAAS,GAAG;AAC3D,aAAO,IAAI;AAAA,IACb;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,eAAsB,YAA2B;AAC/C,EAAAA,OAAM,EAAE;AACR,EAAAA,OAAM,kBAAkB;AACxB,EAAAA,OAAM,wFAAkB;AACxB,EAAAA,OAAM,EAAE;AAER,QAAM,SAAwB,CAAC;AAG/B,QAAM,YAAY,iBAAiB;AACnC,QAAM,SAAS,QAAQ,IAAI,mBAAmB;AAC9C,QAAM,SAAS,aAAa;AAE5B,MAAI,UAAU,eAAe,MAAM,GAAG;AACpC,UAAM,SAAS,YAAY,2BAA2B;AACtD,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,SAAS,kBAAkB,MAAM,KAAK,OAAO,MAAM,GAAG,EAAE,CAAC,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,OAAO,SAAS,EAAE,CAAC,CAAC;AAAA,IACzG,CAAC;AAAA,EACH,WAAW,QAAQ;AACjB,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAAA,EACH,OAAO;AACL,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAGA,QAAM,oBAAyB,WAAQ,YAAQ,GAAG,YAAY,aAAa;AAC3E,MAAO,eAAW,iBAAiB,GAAG;AACpC,WAAO,KAAK,EAAE,MAAM,kBAAkB,QAAQ,MAAM,SAAS,+BAA+B,CAAC;AAAA,EAC/F,OAAO;AACL,WAAO,KAAK,EAAE,MAAM,kBAAkB,QAAQ,QAAQ,SAAS,+DAA0D,CAAC;AAAA,EAC5H;AAGA,QAAM,UAAU;AAChB,MAAI;AACF,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG,GAAI;AACzD,UAAM,WAAW,MAAM,MAAM,GAAG,OAAO,WAAW,EAAE,QAAQ,WAAW,OAAO,CAAC;AAC/E,iBAAa,OAAO;AACpB,QAAI,SAAS,IAAI;AACf,aAAO,KAAK,EAAE,MAAM,mBAAmB,QAAQ,MAAM,SAAS,GAAG,OAAO,oBAAoB,SAAS,MAAM,IAAI,CAAC;AAAA,IAClH,OAAO;AACL,aAAO,KAAK,EAAE,MAAM,mBAAmB,QAAQ,QAAQ,SAAS,GAAG,OAAO,wBAAwB,SAAS,MAAM,GAAG,CAAC;AAAA,IACvH;AAAA,EACF,SAAS,KAAK;AACZ,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,WAAO,KAAK,EAAE,MAAM,mBAAmB,QAAQ,QAAQ,SAAS,gBAAgB,OAAO,WAAM,GAAG,GAAG,CAAC;AAAA,EACtG;AAGA,MAAI,YAAY;AAChB,MAAI;AACF,UAAM,MAAM,KAAK,MAAS,iBAAa,mBAAmB,OAAO,CAAC;AAClE,gBAAY,IAAI,iBAAiB;AAAA,EACnC,QAAQ;AAAA,EAER;AACA,MAAI;AACF,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG,GAAI;AACzD,UAAM,MAAM,MAAM,MAAM,oBAAoB,SAAS,WAAW,EAAE,QAAQ,WAAW,OAAO,CAAC;AAC7F,iBAAa,OAAO;AACpB,QAAI,IAAI,IAAI;AACV,aAAO,KAAK,EAAE,MAAM,eAAe,QAAQ,MAAM,SAAS,mBAAmB,SAAS,GAAG,CAAC;AAAA,IAC5F,OAAO;AACL,aAAO,KAAK,EAAE,MAAM,eAAe,QAAQ,QAAQ,SAAS,QAAQ,SAAS,wBAAwB,IAAI,MAAM,GAAG,CAAC;AAAA,IACrH;AAAA,EACF,QAAQ;AACN,WAAO,KAAK,EAAE,MAAM,eAAe,QAAQ,QAAQ,SAAS,uBAAuB,SAAS,sCAAsC,CAAC;AAAA,EACrI;AAGA,QAAM,SAAS,aAAa;AAC5B,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,WAAW;AACnB,YAAM,MAAM,MAAM,UAAU,KAAK,MAAM,OAAO,KAAK;AACnD,YAAM,aAAa,MAAM,cAAiB,eAAW,MAAM,UAAU,IAAI,kBAAkB;AAC3F,aAAO,KAAK,EAAE,MAAM,MAAM,MAAM,QAAQ,MAAM,SAAS,YAAY,GAAG,GAAG,UAAU,GAAG,CAAC;AAAA,IACzF,OAAO;AACL,aAAO,KAAK,EAAE,MAAM,MAAM,MAAM,QAAQ,QAAQ,SAAS,gBAAgB,CAAC;AAAA,IAC5E;AAAA,EACF;AAGA,QAAM,QAAQ,EAAE,IAAI,KAAK,MAAM,KAAK,MAAM,IAAI;AAC9C,aAAW,SAAS,QAAQ;AAC1B,UAAM,OAAO,MAAM,MAAM,MAAM;AAC/B,IAAAA,OAAM,MAAM,IAAI,KAAK,MAAM,IAAI,KAAK,MAAM,OAAO,EAAE;AAAA,EACrD;AAEA,QAAM,WAAW,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AACzD,QAAM,WAAW,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AACzD,EAAAA,OAAM,EAAE;AACR,MAAI,SAAS,SAAS,GAAG;AACvB,IAAAA,OAAM,KAAK,SAAS,MAAM,uDAAuD;AAAA,EACnF,WAAW,SAAS,SAAS,GAAG;AAC9B,IAAAA,OAAM,iCAAiC,SAAS,MAAM,cAAc;AAAA,EACtE,OAAO;AACL,IAAAA,OAAM,wCAAwC;AAAA,EAChD;AACA,EAAAA,OAAM,EAAE;AACV;;;AEhIA,SAASC,OAAM,KAAmB;AAChC,UAAQ,IAAI,GAAG;AACjB;AAEA,eAAe,WACb,KACA,MACA,SAC6E;AAC7E,QAAM,QAAQ,YAAY,IAAI;AAC9B,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,oBAAoB,GAAG,QAAQ;AAAA,IAC1D,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B,CAAC;AACD,QAAM,YAAY,YAAY,IAAI,IAAI;AACtC,MAAI,eAAoB;AACxB,MAAI;AACF,mBAAe,MAAM,SAAS,KAAK;AAAA,EACrC,QAAQ;AAAA,EAER;AACA,SAAO,EAAE,WAAW,QAAQ,SAAS,QAAQ,SAAS,SAAS,SAAS,MAAM,aAAa;AAC7F;AAEA,eAAsB,eAA8B;AAClD,EAAAA,OAAM,EAAE;AACR,EAAAA,OAAM,qBAAqB;AAC3B,EAAAA,OAAM,0GAAqB;AAC3B,EAAAA,OAAM,EAAE;AAER,QAAM,SAAS,QAAQ,IAAI,mBAAmB;AAC9C,MAAI,CAAC,eAAe,MAAM,GAAG;AAC3B,IAAAA,OAAM,oFAAoF;AAC1F,IAAAA,OAAM,EAAE;AACR,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,UAAU,QAAQ,IAAI,oBAAoB;AAChD,QAAM,cAAc;AAAA,IAClB,EAAE,OAAO,eAAe,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,yBAAyB,CAAC,EAAE;AAAA,IACxF,EAAE,OAAO,eAAe,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,eAAe,CAAC,EAAE;AAAA,IAC9E,EAAE,OAAO,eAAe,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,yBAAyB,CAAC,EAAE;AAAA,EAC1F;AAEA,EAAAA,OAAM,YAAY,OAAO,EAAE;AAC3B,EAAAA,OAAM,aAAa,YAAY,MAAM,mBAAmB;AACxD,EAAAA,OAAM,EAAE;AAER,QAAM,UAA6B,CAAC;AAEpC,WAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,UAAM,SAAS,YAAY,CAAC;AAC5B,IAAAA,OAAM,aAAa,IAAI,CAAC,IAAI,YAAY,MAAM,KAAK,OAAO,KAAK,YAAO,OAAO,SAAS,CAAC,EAAE,OAAO,GAAG;AAGnG,QAAI,iBAAiB;AACrB,QAAI,aAA4B;AAChC,QAAI,WAAW;AACf,QAAI;AACF,YAAM,cAAc,MAAM;AAAA,QACxB,GAAG,OAAO;AAAA,QACV;AAAA,QACA,EAAE,eAAe,UAAU,MAAM,GAAG;AAAA,MACtC;AACA,uBAAiB,KAAK,MAAM,YAAY,SAAS;AACjD,YAAM,gBAAgB,YAAY,QAAQ,IAAI,uBAAuB;AACrE,UAAI,cAAe,cAAa,WAAW,aAAa;AACxD,iBAAW,YAAY,QAAQ,IAAI,qBAAqB,MAAM;AAAA,IAChE,SAAS,KAAK;AACZ,MAAAA,OAAM,6BAA6B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,IACvF;AAEA,YAAQ,KAAK;AAAA,MACX,cAAc,IAAI;AAAA,MAClB,OAAO,OAAO;AAAA,MACd,iBAAiB;AAAA,MACjB;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,IACF,CAAC;AAED,UAAM,WAAW,WAAW,iBAAiB;AAC7C,UAAM,aAAa,eAAe,OAAO,gBAAgB,WAAW,QAAQ,CAAC,CAAC,KAAK;AACnF,IAAAA,OAAM,cAAc,cAAc,KAAK,QAAQ,GAAG,UAAU,EAAE;AAAA,EAChE;AAGA,EAAAA,OAAM,EAAE;AACR,EAAAA,OAAM,WAAW;AACjB,EAAAA,OAAM,8CAAW;AACjB,QAAM,eAAe,QAAQ,OAAO,CAAC,MAAM,EAAE,kBAAkB,CAAC;AAChE,MAAI,aAAa,WAAW,GAAG;AAC7B,IAAAA,OAAM,kEAAkE;AAAA,EAC1E,OAAO;AACL,UAAM,WAAW,KAAK,MAAM,aAAa,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,gBAAgB,CAAC,IAAI,aAAa,MAAM;AACxG,UAAM,YAAY,aAAa,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE;AACzD,UAAM,eAAe,aAAa,OAAO,CAAC,GAAG,MAAM,KAAK,EAAE,cAAc,IAAI,CAAC;AAE7E,IAAAA,OAAM,kBAAkB,aAAa,MAAM,EAAE;AAC7C,IAAAA,OAAM,kBAAkB,QAAQ,YAAY;AAC5C,IAAAA,OAAM,kBAAkB,SAAS,IAAI,aAAa,MAAM,EAAE;AAC1D,QAAI,eAAe,GAAG;AACpB,MAAAA,OAAM,mBAAmB,aAAa,QAAQ,CAAC,CAAC,EAAE;AAAA,IACpD;AAAA,EACF;AACA,EAAAA,OAAM,EAAE;AACV;;;ACxHA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AAGtB,SAASC,OAAM,KAAmB;AAChC,UAAQ,IAAI,GAAG;AACjB;AAEA,eAAsB,UAAU,WAAoC;AAClE,EAAAA,OAAM,EAAE;AACR,EAAAA,OAAM,kBAAkB;AACxB,EAAAA,OAAM,wFAAkB;AACxB,EAAAA,OAAM,EAAE;AAER,MAAI,UAAU,WAAW,GAAG;AAC1B,IAAAA,OAAM,sEAAsE;AAC5E,IAAAA,OAAM,EAAE;AACR,IAAAA,OAAM,0DAA0D;AAChE,IAAAA,OAAM,yEAAyE;AAC/E,IAAAA,OAAM,EAAE;AACR,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,SAAS,QAAQ,IAAI,mBAAmB;AAC9C,MAAI,CAAC,eAAe,MAAM,GAAG;AAC3B,IAAAA,OAAM,oFAAoF;AAC1F,IAAAA,OAAM,EAAE;AACR,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,UAAU,QAAQ,IAAI,oBAAoB;AAChD,EAAAA,OAAM,YAAY,OAAO,EAAE;AAC3B,EAAAA,OAAM,eAAe,UAAU,MAAM,qBAAqB;AAC1D,EAAAA,OAAM,EAAE;AAER,MAAI,eAAe;AACnB,MAAI,YAAY;AAEhB,aAAW,YAAY,WAAW;AAChC,UAAM,WAAgB,cAAQ,QAAQ;AACtC,IAAAA,OAAM,WAAW,QAAQ,EAAE;AAE3B,QAAI,CAAI,eAAW,QAAQ,GAAG;AAC5B,MAAAA,OAAM,2BAA2B;AACjC;AACA;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,YAAM,MAAS,iBAAa,UAAU,OAAO;AAC7C,oBAAc,KAAK,MAAM,GAAG;AAAA,IAC9B,SAAS,KAAK;AACZ,MAAAA,OAAM,kCAA6B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AACrF;AACA;AAAA,IACF;AAEA,QAAI,CAAC,YAAY,SAAS,CAAC,YAAY,UAAU;AAC/C,MAAAA,OAAM,oEAAoE;AAC1E;AACA;AAAA,IACF;AAEA,UAAM,QAAQ,YAAY;AAC1B,UAAM,eAAe,MAAM,QAAQ,YAAY,QAAQ,IAAI,YAAY,SAAS,SAAS;AACzF,IAAAA,OAAM,cAAc,KAAK,gBAAgB,YAAY,EAAE;AAEvD,QAAI;AACF,YAAM,QAAQ,YAAY,IAAI;AAC9B,YAAM,WAAW,MAAM,MAAM,GAAG,OAAO,wBAAwB;AAAA,QAC7D,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,MAAM;AAAA,QACjC;AAAA,QACA,MAAM,KAAK,UAAU,WAAW;AAAA,MAClC,CAAC;AACD,YAAM,YAAY,KAAK,MAAM,YAAY,IAAI,IAAI,KAAK;AAEtD,UAAI,CAAC,SAAS,IAAI;AAChB,QAAAA,OAAM,oBAAoB,SAAS,MAAM,EAAE;AAC3C;AACA;AAAA,MACF;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAM,UAAU,MAAM,UAAU,CAAC,GAAG,SAAS,WAAW,MAAM,UAAU,CAAC,GAAG,QAAQ;AACpF,YAAM,WAAW,SAAS,QAAQ,IAAI,qBAAqB,MAAM;AACjE,YAAM,UAAU,SAAS,QAAQ,IAAI,uBAAuB;AAE5D,MAAAA,OAAM,eAAe,SAAS,MAAM,eAAe,SAAS,KAAK,WAAW,iBAAiB,EAAE,EAAE;AACjG,UAAI,QAAS,CAAAA,OAAM,iBAAiB,WAAW,OAAO,EAAE,QAAQ,CAAC,CAAC,EAAE;AACpE,MAAAA,OAAM,iBAAiB,QAAQ,MAAM,GAAG,GAAG,CAAC,GAAG,QAAQ,SAAS,MAAM,QAAQ,EAAE,EAAE;AAClF;AAAA,IACF,SAAS,KAAK;AACZ,MAAAA,OAAM,cAAc,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AACtE;AAAA,IACF;AACA,IAAAA,OAAM,EAAE;AAAA,EACV;AAEA,EAAAA,OAAM,wFAAkB;AACxB,EAAAA,OAAM,WAAW,YAAY,eAAe,SAAS,SAAS;AAC9D,EAAAA,OAAM,EAAE;AACV;;;ACzGA,SAAS,aAAa;AACtB,OAAOC,YAAU;AACjB,SAAS,iBAAAC,sBAAqB;;;ACF9B,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAOC,SAAQ;AAGf,SAAS,WAAW,UAA0B;AAC5C,MAAI,SAAS,WAAW,GAAG,GAAG;AAC5B,WAAOD,MAAK,KAAKC,IAAG,QAAQ,GAAG,SAAS,MAAM,CAAC,CAAC;AAAA,EAClD;AACA,SAAO;AACT;AAEA,IAAM,WAAwB;AAAA,EAC5B,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,oBAAoB;AAAA,EACpB,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;AACd;AAEO,SAAS,WAAW,YAAkC;AAC3D,QAAM,WAAW,WAAW,cAAc,SAAS,UAAU;AAC7D,MAAI,aAAmC,CAAC;AAExC,MAAI;AACF,UAAM,MAAMF,IAAG,aAAa,UAAU,OAAO;AAC7C,iBAAa,KAAK,MAAM,GAAG;AAAA,EAC7B,QAAQ;AAAA,EAER;AAEA,SAAO;AAAA,IACL,QAAQ,WAAW,UAAU,SAAS;AAAA,IACtC,eAAe,WAAW,iBAAiB,SAAS;AAAA,IACpD,oBAAoB,WAAW,sBAAsB,SAAS;AAAA,IAC9D,eAAe,WAAW,iBAAiB,SAAS;AAAA,IACpD,YAAY,WAAW,cAAc,SAAS;AAAA,IAC9C,UAAU,WAAW,YAAY,SAAS;AAAA,IAC1C,SAAS,WAAW,WAAW,WAAW,SAAS,OAAO;AAAA,IAC1D,SAAS,WAAW,WAAW,WAAW,SAAS,OAAO;AAAA,IAC1D,YAAY;AAAA,EACd;AACF;AAEO,SAAS,WAAW,QAA2B;AACpD,QAAM,MAAMC,MAAK,QAAQ,OAAO,UAAU;AAC1C,EAAAD,IAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AACrC,EAAAA,IAAG,cAAc,OAAO,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,IAAI;AAC5E;;;ACpDA,OAAOG,SAAQ;AACf,OAAOC,WAAU;AAOV,SAAS,QAAQ,SAAgC;AACtD,MAAI;AACF,UAAM,MAAMC,IAAG,aAAa,SAAS,OAAO,EAAE,KAAK;AACnD,UAAM,MAAM,SAAS,KAAK,EAAE;AAC5B,QAAI,MAAM,GAAG,EAAG,QAAO;AACvB,WAAO,UAAU,GAAG,IAAI,MAAM;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,UAAU,KAAsB;AAC9C,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,UAAU,SAAuB;AAC/C,MAAI;AACF,IAAAA,IAAG,WAAW,OAAO;AAAA,EACvB,QAAQ;AAAA,EAER;AACF;;;AClCA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAOC,SAAQ;AACf,SAAS,YAAAC,iBAAgB;AACzB,SAAS,qBAAqB;;;ACJ9B,OAAOC,SAAQ;AACf,SAAS,YAAAC,iBAAgB;AAQzB,SAAS,cAA+B;AACtC,MAAI,QAAQ,aAAa,SAAS;AAEhC,QAAI,QAAQ,IAAI,gBAAgB,QAAQ,IAAI,iCAAiC;AAC3E,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,QAAQ,IAAI,SAAS;AACvC,MAAI,UAAU,SAAS,KAAK,EAAG,QAAO;AACtC,MAAI,UAAU,SAAS,MAAM,EAAG,QAAO;AACvC,MAAI,UAAU,SAAS,MAAM,EAAG,QAAO;AAGvC,MAAI;AACF,QAAI,QAAQ,aAAa,UAAU;AACjC,YAAM,SAASA,UAAS,uBAAuBD,IAAG,SAAS,EAAE,QAAQ,cAAc;AAAA,QACjF,UAAU;AAAA,QACV,SAAS;AAAA,MACX,CAAC,EAAE,KAAK;AACR,YAAM,QAAQ,OAAO,MAAM,GAAG,EAAE,IAAI,GAAG,KAAK,KAAK;AACjD,UAAI,MAAM,SAAS,KAAK,EAAG,QAAO;AAClC,UAAI,MAAM,SAAS,MAAM,EAAG,QAAO;AACnC,UAAI,MAAM,SAAS,MAAM,EAAG,QAAO;AAAA,IACrC,OAAO;AACL,YAAM,SAASC,UAAS,iBAAiBD,IAAG,SAAS,EAAE,QAAQ,IAAI;AAAA,QACjE,UAAU;AAAA,QACV,SAAS;AAAA,MACX,CAAC,EAAE,KAAK;AACR,YAAM,QAAQ,OAAO,MAAM,GAAG,EAAE,IAAI,KAAK;AACzC,UAAI,MAAM,SAAS,KAAK,EAAG,QAAO;AAClC,UAAI,MAAM,SAAS,MAAM,EAAG,QAAO;AACnC,UAAI,MAAM,SAAS,MAAM,EAAG,QAAO;AAAA,IACrC;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,SAAO;AACT;AAEO,SAAS,WAAmB;AACjC,MAAI;AACJ,UAAQ,QAAQ,UAAU;AAAA,IACxB,KAAK;AACH,iBAAW;AACX;AAAA,IACF,KAAK;AACH,iBAAW;AACX;AAAA,IACF;AACE,iBAAW;AACX;AAAA,EACJ;AAEA,SAAO;AAAA,IACL;AAAA,IACA,OAAO,YAAY;AAAA,IACnB,SAASA,IAAG,QAAQ;AAAA,EACtB;AACF;;;ACvEA,OAAOE,SAAQ;AACf,OAAOC,WAAU;AAGV,SAAS,qBAAqB,QAAqB,iBAAiC;AACzF,QAAM,SAASA,MAAK,KAAKD,IAAG,QAAQ,GAAG,YAAY,MAAM;AACzD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAQK,QAAQ,QAAQ;AAAA,cAChB,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAOjBC,MAAK,KAAK,QAAQ,kBAAkB,CAAC;AAAA;AAAA,YAErCA,MAAK,KAAK,QAAQ,kBAAkB,CAAC;AAAA;AAAA;AAAA;AAAA,cAInC,OAAO,aAAa;AAAA;AAAA,cAEpB,OAAO,UAAU;AAAA;AAAA;AAAA;AAI/B;AAEO,SAAS,oBAAoB,QAAqB,iBAAiC;AACxF,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAMG,QAAQ,QAAQ,IAAI,eAAe;AAAA;AAAA;AAAA,qCAGV,OAAO,aAAa;AAAA,kCACvB,OAAO,UAAU;AAAA;AAAA;AAAA;AAInD;AAEO,SAAS,oBAAoB,QAAqB,iBAAmC;AAC1F,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IAAO;AAAA,IACP;AAAA,IAAO,IAAI,QAAQ,QAAQ,MAAM,eAAe;AAAA,IAChD;AAAA,IAAO;AAAA,IACP;AAAA,IAAO;AAAA,IACP;AAAA,EACF;AACF;;;AFrDA,IAAM,YAAYC,MAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAE7D,SAAS,yBAAiC;AAGxC,QAAM,aAAa;AAAA,IACjBA,MAAK,KAAK,WAAW,MAAM,iBAAiB;AAAA;AAAA,IAC5CA,MAAK,KAAK,WAAW,iBAAiB;AAAA;AAAA,IACtCA,MAAK,KAAK,WAAW,MAAM,MAAM,OAAO,iBAAiB;AAAA;AAAA,EAC3D;AAEA,aAAW,aAAa,YAAY;AAClC,QAAIC,IAAG,WAAW,SAAS,GAAG;AAC5B,aAAOD,MAAK,QAAQ,SAAS;AAAA,IAC/B;AAAA,EACF;AAGA,MAAI;AACF,UAAM,UAAUE,UAAS,eAAe,EAAE,UAAU,QAAQ,CAAC,EAAE,KAAK;AACpE,UAAM,aAAaF,MAAK,KAAK,SAAS,WAAW,QAAQ,OAAO,iBAAiB;AACjF,QAAIC,IAAG,WAAW,UAAU,EAAG,QAAO;AAAA,EACxC,QAAQ;AAAA,EAER;AAGA,QAAM,UAAUD,MAAK,QAAQ,QAAQ,IAAI,GAAG,QAAQ,OAAO,iBAAiB;AAC5E,SAAO;AACT;AAEA,SAAS,oBAA4B;AACnC,SAAOA,MAAK,KAAKG,IAAG,QAAQ,GAAG,WAAW,gBAAgB,wBAAwB;AACpF;AAEA,SAAS,mBAA2B;AAClC,SAAOH,MAAK,KAAKG,IAAG,QAAQ,GAAG,WAAW,WAAW,QAAQ,uBAAuB;AACtF;AAEO,SAAS,eAAe,QAA2B;AACxD,QAAM,SAAS,SAAS;AACxB,QAAM,kBAAkB,uBAAuB;AAG/C,QAAM,SAASH,MAAK,KAAKG,IAAG,QAAQ,GAAG,YAAY,MAAM;AACzD,EAAAF,IAAG,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AAExC,UAAQ,OAAO,UAAU;AAAA,IACvB,KAAK,SAAS;AACZ,YAAM,YAAY,kBAAkB;AACpC,YAAM,WAAWD,MAAK,QAAQ,SAAS;AACvC,MAAAC,IAAG,UAAU,UAAU,EAAE,WAAW,KAAK,CAAC;AAE1C,YAAM,QAAQ,qBAAqB,QAAQ,eAAe;AAC1D,MAAAA,IAAG,cAAc,WAAW,KAAK;AAEjC,UAAI;AAEF,QAAAC,UAAS,qBAAqB,SAAS,yBAAyB,EAAE,OAAO,OAAO,CAAC;AACjF,QAAAA,UAAS,mBAAmB,SAAS,KAAK,EAAE,OAAO,OAAO,CAAC;AAAA,MAC7D,SAAS,KAAK;AACZ,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,gBAAQ,KAAK,kDAAkD,GAAG,EAAE;AACpE,gBAAQ,KAAK,+CAA+C,SAAS,GAAG;AAAA,MAC1E;AACA;AAAA,IACF;AAAA,IAEA,KAAK,SAAS;AACZ,YAAM,WAAW,iBAAiB;AAClC,YAAM,UAAUF,MAAK,QAAQ,QAAQ;AACrC,MAAAC,IAAG,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAEzC,YAAM,OAAO,oBAAoB,QAAQ,eAAe;AACxD,MAAAA,IAAG,cAAc,UAAU,IAAI;AAE/B,UAAI;AACF,QAAAC,UAAS,kCAAkC,EAAE,OAAO,OAAO,CAAC;AAC5D,QAAAA,UAAS,yCAAyC,EAAE,OAAO,OAAO,CAAC;AACnE,QAAAA,UAAS,wCAAwC,EAAE,OAAO,OAAO,CAAC;AAAA,MACpE,QAAQ;AAEN,YAAI;AACF,gBAAM,eAAeF,MAAK,KAAKG,IAAG,QAAQ,GAAG,WAAW,WAAW;AACnE,UAAAF,IAAG,UAAU,cAAc,EAAE,WAAW,KAAK,CAAC;AAC9C,gBAAM,eAAe;AAAA;AAAA;AAAA,OAGxB,QAAQ,QAAQ,IAAI,eAAe;AAAA;AAAA;AAAA;AAAA;AAKhC,UAAAA,IAAG,cAAcD,MAAK,KAAK,cAAc,uBAAuB,GAAG,YAAY;AAC/E,kBAAQ,KAAK,oFAAoF;AAAA,QACnG,SAAS,MAAM;AACb,gBAAM,MAAM,gBAAgB,QAAQ,KAAK,UAAU,OAAO,IAAI;AAC9D,kBAAQ,KAAK,0CAA0C,GAAG,EAAE;AAC5D,kBAAQ,KAAK,mDAAmD;AAAA,QAClE;AAAA,MACF;AACA;AAAA,IACF;AAAA,IAEA,KAAK,WAAW;AACd,YAAM,OAAO,oBAAoB,QAAQ,eAAe;AACxD,UAAI;AACF,QAAAE,UAAS,YAAY,KAAK,KAAK,GAAG,CAAC,IAAI,EAAE,OAAO,OAAO,CAAC;AAAA,MAC1D,SAAS,KAAK;AACZ,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,gBAAQ,KAAK,+CAA+C,GAAG,EAAE;AACjE,gBAAQ,KAAK,mDAAmD;AAAA,MAClE;AACA;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,qBAA8B;AAC5C,QAAM,SAAS,SAAS;AAExB,UAAQ,OAAO,UAAU;AAAA,IACvB,KAAK,SAAS;AACZ,YAAM,YAAY,kBAAkB;AACpC,aAAOD,IAAG,WAAW,SAAS;AAAA,IAChC;AAAA,IACA,KAAK,SAAS;AACZ,YAAM,WAAW,iBAAiB;AAClC,aAAOA,IAAG,WAAW,QAAQ;AAAA,IAC/B;AAAA,IACA,KAAK,WAAW;AACd,UAAI;AACF,QAAAC,UAAS,oCAAoC,EAAE,OAAO,OAAO,CAAC;AAC9D,eAAO;AAAA,MACT,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,cAAoB;AAClC,QAAM,SAAS,SAAS;AAExB,UAAQ,OAAO,UAAU;AAAA,IACvB,KAAK,SAAS;AACZ,YAAM,YAAY,kBAAkB;AACpC,UAAI,CAACD,IAAG,WAAW,SAAS,EAAG;AAC/B,UAAI;AACF,QAAAC,UAAS,qBAAqB,SAAS,KAAK,EAAE,OAAO,OAAO,CAAC;AAAA,MAC/D,QAAQ;AAAA,MAER;AACA;AAAA,IACF;AAAA,IACA,KAAK,SAAS;AACZ,UAAI;AACF,QAAAA,UAAS,uCAAuC,EAAE,OAAO,OAAO,CAAC;AAAA,MACnE,QAAQ;AAAA,MAER;AACA;AAAA,IACF;AAAA,IACA,KAAK,WAAW;AACd,UAAI;AACF,QAAAA,UAAS,kCAAkC,EAAE,OAAO,OAAO,CAAC;AAAA,MAC9D,QAAQ;AAAA,MAER;AACA;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,eAAqB;AACnC,QAAM,SAAS,SAAS;AAExB,UAAQ,OAAO,UAAU;AAAA,IACvB,KAAK,SAAS;AACZ,YAAM,YAAY,kBAAkB;AACpC,UAAI,CAACD,IAAG,WAAW,SAAS,EAAG;AAC/B,UAAI;AACF,QAAAC,UAAS,mBAAmB,SAAS,KAAK,EAAE,OAAO,OAAO,CAAC;AAAA,MAC7D,QAAQ;AAAA,MAER;AACA;AAAA,IACF;AAAA,IACA,KAAK,SAAS;AACZ,UAAI;AACF,QAAAA,UAAS,wCAAwC,EAAE,OAAO,OAAO,CAAC;AAAA,MACpE,QAAQ;AAAA,MAER;AACA;AAAA,IACF;AAAA,IACA,KAAK,WAAW;AACd,UAAI;AACF,QAAAA,UAAS,kCAAkC,EAAE,OAAO,OAAO,CAAC;AAAA,MAC9D,QAAQ;AAAA,MAER;AACA;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,mBAAyB;AACvC,QAAM,SAAS,SAAS;AAExB,UAAQ,OAAO,UAAU;AAAA,IACvB,KAAK,SAAS;AACZ,YAAM,YAAY,kBAAkB;AACpC,UAAI;AACF,QAAAA,UAAS,qBAAqB,SAAS,yBAAyB,EAAE,OAAO,OAAO,CAAC;AAAA,MACnF,QAAQ;AAAA,MAER;AACA,UAAID,IAAG,WAAW,SAAS,EAAG,CAAAA,IAAG,WAAW,SAAS;AACrD;AAAA,IACF;AAAA,IAEA,KAAK,SAAS;AACZ,UAAI;AACF,QAAAC,UAAS,2DAA2D,EAAE,OAAO,OAAO,CAAC;AACrF,QAAAA,UAAS,8DAA8D,EAAE,OAAO,OAAO,CAAC;AAAA,MAC1F,QAAQ;AAAA,MAER;AACA,YAAM,WAAW,iBAAiB;AAClC,UAAID,IAAG,WAAW,QAAQ,EAAG,CAAAA,IAAG,WAAW,QAAQ;AAGnD,YAAM,cAAcD,MAAK,KAAKG,IAAG,QAAQ,GAAG,WAAW,aAAa,uBAAuB;AAC3F,UAAIF,IAAG,WAAW,WAAW,EAAG,CAAAA,IAAG,WAAW,WAAW;AACzD;AAAA,IACF;AAAA,IAEA,KAAK,WAAW;AACd,UAAI;AACF,QAAAC,UAAS,wCAAwC,EAAE,OAAO,OAAO,CAAC;AAAA,MACpE,QAAQ;AAAA,MAER;AACA;AAAA,IACF;AAAA,EACF;AACF;;;AGhQA,OAAOE,SAAQ;AACf,OAAOC,YAAU;AACjB,OAAOC,SAAQ;AAIf,SAAS,UAAU,KAAmB;AACpC,EAAAF,IAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AACvC;AAEA,SAAS,aAAa,UAAwB;AAC5C,MAAIA,IAAG,WAAW,QAAQ,GAAG;AAC3B,IAAAA,IAAG,aAAa,UAAU,GAAG,QAAQ,iBAAiB;AAAA,EACxD;AACF;AAGA,SAAS,aAAa,UAAkD;AACtE,MAAI;AACF,WAAO,KAAK,MAAMA,IAAG,aAAa,UAAU,OAAO,CAAC;AAAA,EACtD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,oBAAoB,OAAsB,aAAgC;AACjF,QAAM,aAAa,MAAM,cAAcC,OAAK,KAAKC,IAAG,QAAQ,GAAG,WAAW,eAAe;AACzF,QAAM,YAAYD,OAAK,QAAQ,UAAU;AACzC,YAAU,SAAS;AACnB,eAAa,UAAU;AAEvB,QAAM,SAAS,aAAa,UAAU,KAAK,CAAC;AAC5C,MAAI,CAAC,OAAO,OAAO,OAAO,OAAO,QAAQ,UAAU;AACjD,WAAO,MAAM,CAAC;AAAA,EAChB;AACA,EAAC,OAAO,IAA+B,qBAAqB,oBAAoB,YAAY,aAAa;AAEzG,EAAAD,IAAG,cAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,IAAI;AACrE;AAEA,SAAS,aAAa,UAA0B;AAC9C,MAAI;AACF,WAAOA,IAAG,aAAa,UAAU,OAAO;AAAA,EAC1C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,WAAW,SAAiB,KAAa,OAAuB;AACvE,QAAM,UAAU,IAAI,OAAO,IAAI,IAAI,QAAQ,KAAK,KAAK,CAAC,YAAY,GAAG;AACrE,QAAM,OAAO,GAAG,GAAG,OAAO,KAAK;AAC/B,MAAI,QAAQ,KAAK,OAAO,GAAG;AACzB,WAAO,QAAQ,QAAQ,SAAS,IAAI;AAAA,EACtC;AAGA,QAAM,eAAe,QAAQ,MAAM,MAAM;AACzC,MAAI,gBAAgB,aAAa,UAAU,QAAW;AACpD,WAAO,QAAQ,MAAM,GAAG,aAAa,KAAK,IAAI,OAAO,OAAO,QAAQ,MAAM,aAAa,KAAK;AAAA,EAC9F;AACA,QAAM,YAAY,QAAQ,SAAS,KAAK,CAAC,QAAQ,SAAS,IAAI,IAAI,OAAO;AACzE,SAAO,UAAU,YAAY,OAAO;AACtC;AAEA,SAAS,cAAc,SAAiB,KAAqB;AAC3D,QAAM,UAAU,IAAI,OAAO,IAAI,IAAI,QAAQ,KAAK,KAAK,CAAC,eAAe,IAAI;AACzE,SAAO,QAAQ,QAAQ,SAAS,EAAE;AACpC;AAEA,SAAS,eAAe,OAAsB,aAAgC;AAC5E,QAAM,YAAY,QAAQ,aAAa,UACnCC,OAAK,KAAKC,IAAG,QAAQ,GAAG,WAAW,WAAW,OAAO,IACrDD,OAAK,KAAKC,IAAG,QAAQ,GAAG,QAAQ;AACpC,QAAM,aAAa,MAAM,cAAcD,OAAK,KAAK,WAAW,aAAa;AAEzE,YAAUA,OAAK,QAAQ,UAAU,CAAC;AAClC,eAAa,UAAU;AAEvB,MAAI,UAAU,aAAa,UAAU;AACrC,YAAU,WAAW,SAAS,mBAAmB,oBAAoB,YAAY,UAAU,EAAE;AAE7F,EAAAD,IAAG,cAAc,YAAY,OAAO;AACtC;AAEO,SAAS,eAAe,OAAsB,aAAgC;AACnF,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,0BAAoB,OAAO,WAAW;AACtC;AAAA,IACF,KAAK;AACH,qBAAe,OAAO,WAAW;AACjC;AAAA,EACJ;AACF;AAEA,SAAS,sBAAsB,OAA4B;AACzD,QAAM,aAAa,MAAM,cAAcC,OAAK,KAAKC,IAAG,QAAQ,GAAG,WAAW,eAAe;AAIzF,MAAI,CAACF,IAAG,WAAW,UAAU,EAAG;AAEhC,QAAM,SAAS,aAAa,UAAU;AACtC,MAAI,WAAW,MAAM;AAGnB,YAAQ,KAAK,yBAAyB,UAAU,oFAA+E;AAC/H;AAAA,EACF;AAEA,MAAI,OAAO,OAAO,OAAO,OAAO,QAAQ,UAAU;AAChD,WAAQ,OAAO,IAAgC;AAC/C,QAAI,OAAO,KAAK,OAAO,GAAa,EAAE,WAAW,GAAG;AAClD,aAAO,OAAO;AAAA,IAChB;AAAA,EACF;AACA,EAAAA,IAAG,cAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,IAAI;AAGnE,QAAM,aAAa,GAAG,UAAU;AAChC,MAAIA,IAAG,WAAW,UAAU,GAAG;AAC7B,IAAAA,IAAG,WAAW,UAAU;AAAA,EAC1B;AACF;AAEA,SAAS,iBAAiB,OAA4B;AACpD,QAAM,YAAY,QAAQ,aAAa,UACnCC,OAAK,KAAKC,IAAG,QAAQ,GAAG,WAAW,WAAW,OAAO,IACrDD,OAAK,KAAKC,IAAG,QAAQ,GAAG,QAAQ;AACpC,QAAM,aAAa,MAAM,cAAcD,OAAK,KAAK,WAAW,aAAa;AAGzE,MAAID,IAAG,WAAW,UAAU,GAAG;AAC7B,QAAI,UAAU,aAAa,UAAU;AACrC,cAAU,cAAc,SAAS,iBAAiB;AAClD,IAAAA,IAAG,cAAc,YAAY,OAAO;AAAA,EACtC;AAGA,QAAM,aAAa,GAAG,UAAU;AAChC,MAAIA,IAAG,WAAW,UAAU,GAAG;AAC7B,IAAAA,IAAG,WAAW,UAAU;AAAA,EAC1B;AACF;AAEO,SAAS,iBAAiB,OAA4B;AAC3D,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,4BAAsB,KAAK;AAC3B;AAAA,IACF,KAAK;AACH,uBAAiB,KAAK;AACtB;AAAA,EACJ;AACF;;;AC1JA,OAAOG,UAAQ;AACf,OAAOC,YAAU;AACjB,OAAOC,SAAQ;AAKf,IAAM,eAAe;AACrB,IAAM,aAAa;AAEnB,IAAM,kBAAkB;AACxB,IAAM,gBAAgB;AAEtB,SAAS,sBAAgC;AACvC,QAAM,OAAOA,IAAG,QAAQ;AACxB,QAAM,aAAa;AAAA,IACjBD,OAAK,KAAK,MAAM,SAAS;AAAA,IACzBA,OAAK,KAAK,MAAM,QAAQ;AAAA,IACxBA,OAAK,KAAK,MAAM,eAAe;AAAA,IAC/BA,OAAK,KAAK,MAAM,UAAU;AAAA,EAC5B;AACA,SAAO,WAAW,OAAO,CAAC,MAAMD,KAAG,WAAW,CAAC,CAAC;AAClD;AAEA,SAAS,2BAA0C;AACjD,MAAI,QAAQ,aAAa,QAAS,QAAO;AAGzC,MAAI,QAAQ,IAAI,QAAS,QAAO,QAAQ,IAAI;AAG5C,QAAM,UAAUC,OAAK,KAAKC,IAAG,QAAQ,GAAG,WAAW;AACnD,QAAM,YAAYD,OAAK,KAAK,SAAS,cAAc,kCAAkC;AACrF,QAAM,YAAYA,OAAK,KAAK,SAAS,qBAAqB,kCAAkC;AAE5F,MAAID,KAAG,WAAW,SAAS,EAAG,QAAO;AACrC,MAAIA,KAAG,WAAW,SAAS,EAAG,QAAO;AAGrC,SAAO;AACT;AAEA,SAAS,kBAAkB,aAAkC;AAC3D,SAAO;AAAA,IACL;AAAA,IACA,+CAA+C,YAAY,aAAa;AAAA,IACxE,4CAA4C,YAAY,UAAU;AAAA,IAClE;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,wBAAwB,aAAkC;AACjE,SAAO;AAAA,IACL;AAAA,IACA,+CAA+C,YAAY,aAAa;AAAA,IACxE,4CAA4C,YAAY,UAAU;AAAA,IAClE;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAASG,cAAa,UAAwB;AAC5C,QAAM,aAAa,GAAG,QAAQ;AAC9B,EAAAH,KAAG,aAAa,UAAU,UAAU;AACtC;AAEA,SAAS,kBAAkB,UAAkB,OAAe,aAAqB,WAAyB;AACxG,MAAIA,KAAG,WAAW,QAAQ,GAAG;AAC3B,IAAAG,cAAa,QAAQ;AAAA,EACvB;AAEA,MAAI,UAAUH,KAAG,WAAW,QAAQ,IAAIA,KAAG,aAAa,UAAU,OAAO,IAAI;AAG7E,QAAM,WAAW,QAAQ,QAAQ,WAAW;AAC5C,QAAM,SAAS,QAAQ,QAAQ,SAAS;AAExC,MAAI,aAAa,MAAM,WAAW,IAAI;AAEpC,cAAU,QAAQ,MAAM,GAAG,QAAQ,IAAI,QAAQ,QAAQ,MAAM,SAAS,UAAU,MAAM;AAAA,EACxF,OAAO;AAEL,QAAI,QAAQ,SAAS,GAAG;AACtB,YAAM,UAAU,QAAQ,QAAQ,QAAQ,EAAE;AAC1C,gBAAU,UAAU,SAAS,QAAQ;AAAA,IACvC,OAAO;AACL,gBAAU,QAAQ;AAAA,IACpB;AAAA,EACF;AAEA,EAAAA,KAAG,cAAc,UAAU,OAAO;AACpC;AAEO,SAAS,sBAAsB,SAA0B,aAAoC;AAClG,QAAM,WAAqB,CAAC;AAE5B,MAAI,QAAQ,aAAa,SAAS;AAChC,UAAM,YAAY,yBAAyB;AAC3C,QAAI,WAAW;AACb,YAAM,MAAMC,OAAK,QAAQ,SAAS;AAClC,MAAAD,KAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AACrC,YAAM,QAAQ,wBAAwB,WAAW;AACjD,wBAAkB,WAAW,OAAO,iBAAiB,aAAa;AAClE,eAAS,KAAK,SAAS;AAAA,IACzB;AAAA,EACF,OAAO;AACL,UAAM,WAAW,oBAAoB;AACrC,UAAM,QAAQ,kBAAkB,WAAW;AAC3C,eAAW,eAAe,UAAU;AAClC,wBAAkB,aAAa,OAAO,cAAc,UAAU;AAC9D,eAAS,KAAK,WAAW;AAAA,IAC3B;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,qBAA+B;AAC7C,QAAM,WAAqB,CAAC;AAE5B,QAAM,OAAOE,IAAG,QAAQ;AACxB,QAAM,cAAc;AAAA,IAClBD,OAAK,KAAK,MAAM,SAAS;AAAA,IACzBA,OAAK,KAAK,MAAM,QAAQ;AAAA,IACxBA,OAAK,KAAK,MAAM,eAAe;AAAA,IAC/BA,OAAK,KAAK,MAAM,UAAU;AAAA,EAC5B;AAGA,MAAI,QAAQ,aAAa,SAAS;AAChC,UAAM,YAAY,yBAAyB;AAC3C,QAAI,UAAW,aAAY,KAAK,SAAS;AAAA,EAC3C;AAEA,aAAW,eAAe,aAAa;AACrC,QAAI,CAACD,KAAG,WAAW,WAAW,EAAG;AAEjC,UAAM,UAAUA,KAAG,aAAa,aAAa,OAAO;AACpD,UAAM,WAAW,QAAQ,QAAQ,YAAY;AAC7C,UAAM,SAAS,QAAQ,QAAQ,UAAU;AAEzC,QAAI,aAAa,MAAM,WAAW,GAAI;AAItC,UAAM,SAAS,QAAQ,MAAM,GAAG,QAAQ;AACxC,UAAM,QAAQ,QAAQ,MAAM,SAAS,WAAW,MAAM;AAEtD,UAAM,WAAW,OAAO,QAAQ,QAAQ,EAAE,IAAI,MAAM,QAAQ,QAAQ,IAAI,GAAG,QAAQ,IAAI;AACvF,IAAAA,KAAG,cAAc,aAAa,OAAO;AAGrC,UAAM,aAAa,GAAG,WAAW;AACjC,QAAIA,KAAG,WAAW,UAAU,GAAG;AAC7B,MAAAA,KAAG,WAAW,UAAU;AAAA,IAC1B;AAEA,aAAS,KAAK,WAAW;AAAA,EAC3B;AAEA,SAAO;AACT;;;APrJA,SAASI,OAAM,KAAmB;AAChC,UAAQ,IAAI,GAAG;AACjB;AAGA,eAAe,cAAc,QAAuC;AAClE,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,oBAAoB,OAAO,aAAa,eAAe;AAAA,MAC7E,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AAAA,IACzC,CAAC;AACD,WAAO,IAAI;AAAA,EACb,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,WAA0B;AAC9C,QAAM,SAAS,WAAW;AAE1B,MAAI,CAAC,OAAO,QAAQ;AAClB,IAAAA,OAAM,4EAA4E;AAClF,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,cAAc,QAAQ,OAAO,OAAO;AAC1C,MAAI,gBAAgB,MAAM;AAGxB,UAAM,WAAW,MAAM,cAAc,MAAM;AAC3C,QAAI,UAAU;AACZ,MAAAA,OAAM,oCAAoC;AAAA,IAC5C,OAAO;AACL,MAAAA,OAAM,mCAAmC,WAAW,IAAI;AAAA,IAC1D;AAEA,4BAAwB,MAAM;AAC9B;AAAA,EACF;AAIA,MAAI,mBAAmB,GAAG;AACxB,iBAAa;AACb,IAAAA,OAAM,uDAAuD,OAAO,aAAa,QAAQ,OAAO,UAAU,EAAE;AAC5G,4BAAwB,MAAM;AAC9B;AAAA,EACF;AAEA,QAAM,UAAUC,OAAK,QAAQC,eAAc,YAAY,GAAG,CAAC;AAC3D,QAAM,eAAeD,OAAK,QAAQ,SAAS,iBAAiB;AAE5D,QAAM,QAAQ,MAAM,QAAQ,UAAU,CAAC,YAAY,GAAG;AAAA,IACpD,UAAU;AAAA,IACV,OAAO;AAAA,EACT,CAAC;AAED,QAAM,MAAM;AAEZ,EAAAD,OAAM,oCAAoC,OAAO,aAAa,QAAQ,OAAO,UAAU,EAAE;AACzF,0BAAwB,MAAM;AAChC;AAGA,SAAS,wBAAwB,QAA2B;AAC1D,QAAM,SAAS,aAAa;AAC5B,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,WAAW;AACnB,UAAI;AACF,uBAAe,OAAO,MAAM;AAC5B,QAAAA,OAAM,gBAAgB,MAAM,IAAI,EAAE;AAAA,MACpC,SAAS,KAAK;AACZ,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,QAAAA,OAAM,yBAAyB,MAAM,IAAI,KAAK,GAAG,EAAE;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AACA,wBAAsB,QAAQ,MAAM;AACtC;;;AQ1FA,OAAO,UAAU;;;ACIjB,IAAM,aAAa,oBAAI,IAAI;AAAA,EACzB;AAAA,EAAc;AAAA,EAAc;AAAA,EAAsB;AAAA,EAClD;AAAA,EAAM;AAAA,EAAW;AAAA,EAAqB;AACxC,CAAC;AAED,IAAM,gBAAgB,oBAAI,IAAI;AAAA,EAC5B,GAAG;AAAA,EACH;AAAA,EAAoB;AACtB,CAAC;;;ACZD,OAAOG,UAAQ;AACf,OAAOC,YAAU;AAEjB,IAAM,WAAW,IAAI,OAAO;;;AFI5B,IAAI,iBAAiB;AA4Hd,SAAS,UAAU,QAA8B;AACtD,QAAM,MAAM,QAAQ,OAAO,OAAO;AAClC,MAAI,QAAQ,KAAM,QAAO;AAEzB,MAAI;AACF,YAAQ,KAAK,KAAK,SAAS;AAAA,EAC7B,QAAQ;AAAA,EAER;AAEA,YAAU,OAAO,OAAO;AACxB,SAAO;AACT;AAEO,SAAS,eAAe,QAAkC;AAC/D,QAAM,MAAM,QAAQ,OAAO,OAAO;AAClC,SAAO;AAAA,IACL,SAAS,QAAQ;AAAA,IACjB;AAAA,IACA,QAAQ,iBAAiB,IAAI,KAAK,IAAI,IAAI,iBAAiB;AAAA,IAC3D,eAAe,OAAO;AAAA,IACtB,YAAY,OAAO;AAAA,EACrB;AACF;;;AGjJA,SAASC,OAAM,KAAmB;AAChC,UAAQ,IAAI,GAAG;AACjB;AAGA,eAAe,mBAAmB,QAAuC;AACvE,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,oBAAoB,OAAO,aAAa,eAAe;AAAA,MAC7E,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAAA,IAC9C,CAAC;AACD,WAAO,IAAI;AAAA,EACb,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,UAAyB;AAC7C,QAAM,SAAS,WAAW;AAE1B,QAAM,MAAM,QAAQ,OAAO,OAAO;AAElC,MAAI,QAAQ,MAAM;AAChB,IAAAA,OAAM,yBAAyB;AAC/B;AAAA,EACF;AAKA,QAAM,WAAW,MAAM,mBAAmB,MAAM;AAEhD,MAAI,UAAU;AACZ,IAAAA,OAAM,oEAAoE;AAC1E,IAAAA,OAAM,8CAA8C;AACpD,IAAAA,OAAM,kDAAkD;AACxD;AAAA,EACF;AAGA,EAAAA,OAAM,4DAAuD;AAE7D,MAAI,mBAAmB,GAAG;AACxB,gBAAY;AAAA,EACd;AAEA,QAAM,UAAU,UAAU,MAAM;AAEhC,MAAI,SAAS;AACX,IAAAA,OAAM,0BAA0B;AAAA,EAClC,OAAO;AACL,IAAAA,OAAM,yBAAyB;AAAA,EACjC;AAIA,QAAM,mBAAmB,mBAAmB;AAC5C,MAAI,iBAAiB,SAAS,GAAG;AAC/B,eAAW,KAAK,kBAAkB;AAChC,MAAAA,OAAM,6BAA6B,CAAC,EAAE;AAAA,IACxC;AAAA,EACF;AAEA,QAAM,SAAS,aAAa;AAC5B,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,WAAW;AACnB,UAAI;AACF,yBAAiB,KAAK;AACtB,QAAAA,OAAM,cAAc,MAAM,IAAI,SAAS;AAAA,MACzC,SAAS,KAAK;AACZ,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,QAAAA,OAAM,uBAAuB,MAAM,IAAI,KAAK,GAAG,EAAE;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AACF;;;AClFA,SAASC,OAAM,KAAmB;AAChC,UAAQ,IAAI,GAAG;AACjB;AAGA,eAAe,eAAe,MAAsC;AAClE,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,oBAAoB,IAAI,SAAS;AACzD,QAAI,IAAI,IAAI;AACV,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,aAAO,KAAK,QAAQ;AAAA,IACtB;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,eAAsB,YAA2B;AAC/C,QAAM,SAAS,WAAW;AAC1B,QAAM,SAAS,eAAe,MAAM;AAEpC,EAAAA,OAAM,EAAE;AACR,EAAAA,OAAM,wBAAwB;AAC9B,EAAAA,OAAM,4HAAwB;AAC9B,EAAAA,OAAM,kBAAkB,OAAO,UAAU,YAAY,SAAS,EAAE;AAChE,MAAI,OAAO,QAAQ,MAAM;AACvB,IAAAA,OAAM,kBAAkB,OAAO,GAAG,EAAE;AAAA,EACtC;AAEA,MAAI,OAAO,SAAS;AAClB,UAAM,OAAO,MAAM,eAAe,OAAO,aAAa;AACtD,QAAI,MAAM;AACR,MAAAA,OAAM,kBAAkB,IAAI,EAAE;AAAA,IAChC;AAAA,EACF;AAEA,EAAAA,OAAM,uBAAuB,OAAO,aAAa,EAAE;AACnD,EAAAA,OAAM,uBAAuB,OAAO,UAAU,EAAE;AAChD,EAAAA,OAAM,kBAAkB,OAAO,UAAU,EAAE;AAC3C,EAAAA,OAAM,EAAE;AACV;;;AC5CA,OAAOC,UAAQ;AAGf,SAASC,OAAM,KAAmB;AAChC,UAAQ,IAAI,GAAG;AACjB;AAEA,eAAsB,QAAQ,SAA8D;AAC1F,QAAM,SAAS,WAAW;AAC1B,QAAM,UAAU,OAAO;AACvB,QAAM,YAAY,SAAS,QAAQ,SAAS,MAAM,EAAE;AAEpD,MAAI,CAACC,KAAG,WAAW,OAAO,GAAG;AAC3B,IAAAD,OAAM,0BAA0B,OAAO,EAAE;AACzC;AAAA,EACF;AAEA,QAAM,UAAUC,KAAG,aAAa,SAAS,OAAO;AAChD,QAAM,QAAQ,QAAQ,QAAQ,EAAE,MAAM,IAAI;AAC1C,QAAM,OAAO,MAAM,MAAM,CAAC,SAAS;AAEnC,aAAW,QAAQ,MAAM;AACvB,IAAAD,OAAM,IAAI;AAAA,EACZ;AAEA,MAAI,QAAQ,QAAQ;AAClB,QAAI,WAAWC,KAAG,SAAS,OAAO,EAAE;AACpC,IAAAA,KAAG,UAAU,SAAS,EAAE,UAAU,IAAI,GAAG,MAAM;AAC7C,UAAI;AACF,cAAM,OAAOA,KAAG,SAAS,OAAO;AAChC,YAAI,KAAK,OAAO,UAAU;AACxB,gBAAM,KAAKA,KAAG,SAAS,SAAS,GAAG;AACnC,gBAAM,MAAM,OAAO,MAAM,KAAK,OAAO,QAAQ;AAC7C,UAAAA,KAAG,SAAS,IAAI,KAAK,GAAG,IAAI,QAAQ,QAAQ;AAC5C,UAAAA,KAAG,UAAU,EAAE;AACf,kBAAQ,OAAO,MAAM,IAAI,SAAS,OAAO,CAAC;AAC1C,qBAAW,KAAK;AAAA,QAClB;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACxCA,SAASC,OAAM,KAAmB;AAChC,UAAQ,IAAI,GAAG;AACjB;AAEA,eAAsB,UAAU,YAAqB,MAAgC;AACnF,QAAM,SAAS,WAAW;AAE1B,MAAI,eAAe,QAAQ;AACzB,IAAAA,OAAM,OAAO,UAAU;AACvB;AAAA,EACF;AAEA,MAAI,eAAe,OAAO;AACxB,QAAI,CAAC,QAAQ,KAAK,SAAS,GAAG;AAC5B,MAAAA,OAAM,2CAA2C;AACjD,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,MAAM,KAAK,CAAC;AAClB,UAAM,QAAQ,KAAK,CAAC;AACpB,UAAM,YAAmC;AAAA,MACvC;AAAA,MAAU;AAAA,MAAiB;AAAA,MAAiB;AAAA,MAC5C;AAAA,MAAY;AAAA,MAAW;AAAA,IACzB;AAEA,QAAI,CAAC,UAAU,SAAS,GAAG,GAAG;AAC5B,MAAAA,OAAM,yBAAyB,GAAG,EAAE;AACpC,MAAAA,OAAM,iBAAiB,UAAU,KAAK,IAAI,CAAC,EAAE;AAC7C,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,UAAU,EAAE,GAAG,OAAO;AAC5B,QAAI,QAAQ,mBAAmB,QAAQ,cAAc;AACnD,YAAM,SAAS,SAAS,OAAO,EAAE;AACjC,UAAI,MAAM,MAAM,KAAK,SAAS,KAAK,SAAS,OAAO;AACjD,QAAAA,OAAM,0BAA0B,KAAK,EAAE;AACvC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,MAAC,QAAgB,GAAG,IAAI;AAAA,IAC1B,WAAW,QAAQ,YAAY;AAC7B,YAAM,cAAc,CAAC,SAAS,QAAQ,QAAQ,OAAO;AACrD,UAAI,CAAC,YAAY,SAAS,KAAK,GAAG;AAChC,QAAAA,OAAM,wBAAwB,KAAK,EAAE;AACrC,QAAAA,OAAM,mBAAmB,YAAY,KAAK,IAAI,CAAC,EAAE;AACjD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,MAAC,QAAgB,GAAG,IAAI;AAAA,IAC1B,OAAO;AACL,MAAC,QAAgB,GAAG,IAAI;AAAA,IAC1B;AAEA,eAAW,OAAO;AAClB,IAAAA,OAAM,SAAS,GAAG,MAAM,KAAK,EAAE;AAC/B;AAAA,EACF;AAEA,EAAAA,OAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AACvC;;;AC3DA,SAAS,YAAY;AACrB,SAAS,qBAAqB;AAE9B,IAAMC,WAAU,cAAc,YAAY,GAAG;AAC7C,IAAM,MAAMA,SAAQ,oBAAoB;AAExC,SAASC,QAAM,KAAmB;AAChC,UAAQ,IAAI,GAAG;AACjB;AAEA,eAAsB,YAA2B;AAC/C,EAAAA,QAAM,sBAAsB,IAAI,OAAO,EAAE;AACzC,EAAAA,QAAM,2BAA2B;AAEjC,MAAI;AACF,UAAM,SAAS,MAAM,IAAI,QAAgB,CAACC,UAAS,WAAW;AAC5D,WAAK,4BAA4B,CAAC,KAAK,WAAW;AAChD,YAAI,IAAK,QAAO,GAAG;AAAA,YACd,CAAAA,SAAQ,OAAO,KAAK,CAAC;AAAA,MAC5B,CAAC;AAAA,IACH,CAAC;AAED,QAAI,WAAW,IAAI,SAAS;AAC1B,MAAAD,QAAM,oCAAoC,IAAI,OAAO,IAAI;AACzD;AAAA,IACF;AAEA,IAAAA,QAAM,iBAAiB,MAAM,KAAK;AAElC,UAAM,IAAI,QAAc,CAACC,UAAS,WAAW;AAC3C,WAAK,iCAAiC,CAAC,QAAQ;AAC7C,YAAI,IAAK,QAAO,GAAG;AAAA,YACd,CAAAA,SAAQ;AAAA,MACf,CAAC;AAAA,IACH,CAAC;AAED,IAAAD,QAAM,gBAAgB,MAAM,GAAG;AAAA,EACjC,SAAS,KAAK;AACZ,IAAAA,QAAM,oBAAoB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAC5E,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;;;ACzCA,YAAYE,eAAc;AAC1B,YAAYC,UAAQ;AACpB,YAAYC,YAAU;AACtB,YAAYC,SAAQ;AAQpB,SAASC,QAAM,KAAmB;AAChC,UAAQ,IAAI,GAAG;AACjB;AAGA,eAAsB,UAAU,SAAyG;AACvI,QAAM,SAAS,SAAS,SAAS;AAEjC,MAAI;AACJ,MAAI;AAEJ,MAAI,CAAC,QAAQ;AACX,SAAc,0BAAgB;AAAA,MAC5B,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA,IAClB,CAAC;AACD,UAAM,CAAC,aAAsC;AAC3C,aAAO,IAAI,QAAQ,CAACC,aAAY;AAC9B,WAAI,SAAS,UAAU,CAAC,WAAWA,SAAQ,OAAO,KAAK,CAAC,CAAC;AAAA,MAC3D,CAAC;AAAA,IACH;AAAA,EACF,OAAO;AACL,UAAM,MAAM,QAAQ,QAAQ,EAAE;AAAA,EAChC;AAEA,MAAI;AAEF,IAAAD,QAAM,EAAE;AACR,IAAAA,QAAM,oCAAoC;AAC1C,IAAAA,QAAM,oCAAoC;AAC1C,IAAAA,QAAM,oCAAoC;AAC1C,IAAAA,QAAM,wCAAyC;AAC/C,IAAAA,QAAM,oCAAoC;AAC1C,IAAAA,QAAM,uCAAuC;AAC7C,IAAAA,QAAM,qCAAqC;AAC3C,IAAAA,QAAM,qCAAqC;AAC3C,IAAAA,QAAM,EAAE;AACR,IAAAA,QAAM,+DAAgE;AACtE,IAAAA,QAAM,0VAA6D;AACnE,IAAAA,QAAM,EAAE;AAGR,UAAM,aAAkB,YAAQ,YAAQ,GAAG,UAAU;AACrD,UAAM,aAAkB,YAAK,YAAY,aAAa;AACtD,QAAI,SAAS;AAEb,QAAI,UAAU,SAAS,QAAQ;AAC7B,eAAS,QAAQ;AACjB,UAAI,CAAC,eAAe,MAAM,GAAG;AAC3B,QAAAA,QAAM,wFAAwF;AAC9F,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,MAAAA,QAAM,kBAAkB,OAAO,MAAM,GAAG,EAAE,CAAC,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,OAAO,SAAS,EAAE,CAAC,CAAC,EAAE;AAAA,IAC7F,WAAW,UAAU,CAAC,SAAS,QAAQ;AACrC,MAAAA,QAAM,wDAAwD;AAC9D,cAAQ,KAAK,CAAC;AAAA,IAChB,OAAO;AACL,UAAO,gBAAW,UAAU,GAAG;AAC7B,YAAI;AACF,gBAAM,WAAW,KAAK,MAAS,kBAAa,YAAY,OAAO,CAAC;AAChE,cAAI,SAAS,UAAU,eAAe,SAAS,MAAM,GAAG;AACtD,kBAAM,SAAS,SAAS,OAAO,MAAM,GAAG,EAAE,IAAI,IAAI,OAAO,KAAK,IAAI,GAAG,SAAS,OAAO,SAAS,EAAE,CAAC;AACjG,kBAAM,cAAc,MAAM,IAAI,6BAA6B,MAAM;AAAA,wBAA2B;AAC5F,gBAAI,YAAY,YAAY,MAAM,KAAK;AACrC,uBAAS,SAAS;AAClB,cAAAA,QAAM,2BAA2B;AAAA,YACnC;AAAA,UACF;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF;AAEA,UAAI,CAAC,QAAQ;AACX,iBAAS,MAAM,IAAI,iDAAiD;AACpE,YAAI,CAAC,eAAe,MAAM,GAAG;AAC3B,UAAAA,QAAM,wFAAwF;AAC9F,aAAI,MAAM;AACV,kBAAQ,KAAK,CAAC;AAAA,QAChB;AACA,QAAAA,QAAM,kBAAkB,OAAO,MAAM,GAAG,EAAE,CAAC,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,OAAO,SAAS,EAAE,CAAC,CAAC,EAAE;AAAA,MAC7F;AAAA,IACF;AACA,IAAAA,QAAM,EAAE;AAGR,IAAG,eAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AAC5C,UAAM,cAAc,WAAW,UAAU;AACzC,gBAAY,SAAS;AACrB,eAAW,WAAW;AAGtB,IAAAA,QAAM,8BAA8B;AACpC,UAAM,SAAS,aAAa;AAC5B,UAAM,kBAAkB,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS;AACxD,UAAM,eAAe,OAAO,OAAO,CAAC,MAAM,CAAC,EAAE,SAAS;AAEtD,QAAI,gBAAgB,SAAS,GAAG;AAC9B,iBAAW,SAAS,iBAAiB;AACnC,cAAM,MAAM,MAAM,UAAU,KAAK,MAAM,OAAO,KAAK;AACnD,QAAAA,QAAM,gBAAgB,MAAM,IAAI,GAAG,GAAG,EAAE;AAAA,MAC1C;AAAA,IACF;AACA,QAAI,aAAa,SAAS,GAAG;AAC3B,iBAAW,SAAS,cAAc;AAChC,QAAAA,QAAM,oBAAoB,MAAM,IAAI,EAAE;AAAA,MACxC;AAAA,IACF;AACA,QAAI,gBAAgB,WAAW,GAAG;AAChC,MAAAA,QAAM,mEAAmE;AACzE,MAAAA,QAAM,qEAAqE;AAAA,IAC7E;AACA,IAAAA,QAAM,EAAE;AAGR,QAAI,oBAAqC,gBAAgB,OAAO,CAAC,MAAM;AACrE,UAAI,SAAS,cAAc,EAAE,SAAS,cAAe,QAAO;AAC5D,UAAI,SAAS,aAAa,EAAE,SAAS,QAAS,QAAO;AACrD,aAAO;AAAA,IACT,CAAC;AACD,QAAI,kBAAkB,SAAS,KAAK,CAAC,QAAQ;AAC3C,YAAM,aAAa,gBAAgB,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI;AAC/D,YAAM,UAAU,MAAM,IAAI,eAAe,UAAU,WAAW;AAC9D,UAAI,QAAQ,YAAY,MAAM,KAAK;AACjC,4BAAoB,CAAC;AAAA,MACvB;AAAA,IACF;AACA,IAAAA,QAAM,EAAE;AAGR,QAAI,kBAAkB,SAAS,GAAG;AAChC,MAAAA,QAAM,yBAAyB;AAG/B,iBAAW,SAAS,mBAAmB;AACrC,uBAAe,OAAO,WAAW;AACjC,QAAAA,QAAM,gBAAgB,MAAM,IAAI,GAAG,MAAM,aAAa,KAAK,MAAM,UAAU,MAAM,EAAE,EAAE;AAAA,MACvF;AACA,MAAAA,QAAM,EAAE;AAAA,IACV;AAGA,IAAAA,QAAM,yCAAyC;AAC/C,QAAI;AACF,qBAAe,WAAW;AAC1B,MAAAA,QAAM,mCAAmC;AAAA,IAC3C,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,MAAAA,QAAM,yCAAyC,GAAG,EAAE;AACpD,MAAAA,QAAM,wDAAwD;AAAA,IAChE;AACA,IAAAA,QAAM,EAAE;AAGR,IAAAA,QAAM,sBAAsB;AAC5B,QAAI,UAAU;AACd,QAAI;AAEF,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG,GAAI;AACzD,YAAM,YAAY,oBAAoB,YAAY,aAAa;AAC/D,YAAM,MAAM,MAAM,MAAM,WAAW,EAAE,QAAQ,WAAW,OAAO,CAAC;AAChE,mBAAa,OAAO;AACpB,UAAI,IAAI,IAAI;AACV,QAAAA,QAAM,+BAA+B,YAAY,aAAa,YAAY;AAC1E,kBAAU;AAAA,MACZ,OAAO;AACL,QAAAA,QAAM,+BAA+B,YAAY,aAAa,WAAW,IAAI,MAAM,EAAE;AAAA,MACvF;AAAA,IACF,QAAQ;AACN,MAAAA,QAAM,gEAAgE;AACtE,MAAAA,QAAM,0FAA0F;AAAA,IAClG;AAEA,QAAI;AACF,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG,GAAI;AACzD,YAAM,YAAY,oBAAoB,YAAY,UAAU;AAC5D,YAAM,MAAM,MAAM,MAAM,WAAW,EAAE,QAAQ,WAAW,OAAO,CAAC;AAChE,mBAAa,OAAO;AACpB,UAAI,IAAI,IAAI;AACV,QAAAA,QAAM,4BAA4B,YAAY,UAAU,YAAY;AAAA,MACtE,OAAO;AACL,QAAAA,QAAM,4BAA4B,YAAY,UAAU,WAAW,IAAI,MAAM,EAAE;AAAA,MACjF;AAAA,IACF,QAAQ;AAAA,IAER;AACA,IAAAA,QAAM,EAAE;AAGR,IAAAA,QAAM,0VAA6D;AACnE,IAAAA,QAAM,EAAE;AACR,IAAAA,QAAM,iEAAkE;AACxE,IAAAA,QAAM,EAAE;AACR,QAAI,kBAAkB,SAAS,GAAG;AAChC,MAAAA,QAAM,0BAA0B,kBAAkB,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,IACjF;AACA,IAAAA,QAAM,8BAA8B,YAAY,gBAAgB,cAAc,YAAY,UAAU;AACpG,IAAAA,QAAM,EAAE;AACR,IAAAA,QAAM,kDAAkD;AACxD,IAAAA,QAAM,oDAAoD;AAC1D,IAAAA,QAAM,oDAAoD;AAC1D,IAAAA,QAAM,EAAE;AAER,QAAI,GAAI,IAAG,MAAM;AAAA,EACnB,SAAS,KAAK;AACZ,QAAI,GAAI,IAAG,MAAM;AACjB,UAAM;AAAA,EACR;AACF;;;AC7NA,YAAYE,eAAc;AAC1B,YAAYC,UAAQ;AACpB,YAAYC,YAAU;AACtB,YAAYC,UAAQ;AASpB,SAASC,QAAM,KAAmB;AAChC,UAAQ,IAAI,GAAG;AACjB;AAMA,eAAsB,aAAa,SAA2C;AAC5E,QAAM,QAAQ,SAAS,SAAS;AAEhC,QAAM,KAAc,0BAAgB;AAAA,IAClC,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ;AAAA,EAClB,CAAC;AAED,WAAS,IAAI,UAAmC;AAC9C,WAAO,IAAI,QAAQ,CAACC,aAAY;AAC9B,SAAG,SAAS,UAAU,CAAC,WAAWA,SAAQ,OAAO,KAAK,CAAC,CAAC;AAAA,IAC1D,CAAC;AAAA,EACH;AAEA,MAAI;AACF,IAAAD,QAAM,EAAE;AACR,IAAAA,QAAM,qBAAqB;AAC3B,IAAAA,QAAM,0GAAqB;AAC3B,IAAAA,QAAM,EAAE;AAER,QAAI,CAAC,OAAO;AACV,YAAM,UAAU,MAAM,IAAI,wFAAwF;AAClH,UAAI,QAAQ,YAAY,MAAM,KAAK;AACjC,QAAAA,QAAM,YAAY;AAClB,WAAG,MAAM;AACT;AAAA,MACF;AACA,MAAAA,QAAM,EAAE;AAAA,IACV;AAEA,UAAM,SAAS,WAAW;AAC1B,UAAM,UAAoB,CAAC;AAM3B,IAAAA,QAAM,8BAA8B;AACpC,QAAI;AACF,uBAAiB;AACjB,MAAAA,QAAM,uBAAuB;AAC7B,cAAQ,KAAK,gBAAgB;AAAA,IAC/B,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,MAAAA,QAAM,mCAAmC,GAAG,EAAE;AAAA,IAChD;AAGA,IAAAA,QAAM,qBAAqB;AAC3B,UAAM,UAAU,UAAU,MAAM;AAChC,QAAI,SAAS;AACX,MAAAA,QAAM,qBAAqB;AAC3B,cAAQ,KAAK,eAAe;AAAA,IAC9B,OAAO;AACL,MAAAA,QAAM,6BAA6B;AAAA,IACrC;AAGA,IAAAA,QAAM,2CAA2C;AACjD,UAAM,mBAAmB,mBAAmB;AAC5C,QAAI,iBAAiB,SAAS,GAAG;AAC/B,iBAAW,KAAK,kBAAkB;AAChC,QAAAA,QAAM,mBAAmB,CAAC,EAAE;AAAA,MAC9B;AACA,cAAQ,KAAK,gBAAgB;AAAA,IAC/B,OAAO;AACL,MAAAA,QAAM,4CAA4C;AAAA,IACpD;AAGA,IAAAA,QAAM,qCAAqC;AAC3C,UAAM,SAAS,aAAa;AAC5B,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,WAAW;AACnB,YAAI;AACF,2BAAiB,KAAK;AACtB,UAAAA,QAAM,kBAAkB,MAAM,IAAI,SAAS;AAC3C,kBAAQ,KAAK,GAAG,MAAM,IAAI,SAAS;AAAA,QACrC,SAAS,KAAK;AACZ,gBAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,UAAAA,QAAM,2BAA2B,MAAM,IAAI,KAAK,GAAG,EAAE;AAAA,QACvD;AAAA,MACF;AAAA,IACF;AACA,IAAAA,QAAM,EAAE;AAGR,UAAM,aAAkB,YAAQ,aAAQ,GAAG,UAAU;AACrD,QAAO,gBAAW,UAAU,GAAG;AAC7B,UAAI,eAAe;AACnB,UAAI,CAAC,OAAO;AACV,cAAM,YAAY,MAAM,IAAI,oEAAoE;AAChG,uBAAe,UAAU,YAAY,MAAM;AAAA,MAC7C;AACA,UAAI,cAAc;AAChB,QAAG,YAAO,YAAY,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACtD,QAAAA,QAAM,2BAA2B;AACjC,gBAAQ,KAAK,uBAAuB;AAAA,MACtC;AAAA,IACF;AAGA,IAAAA,QAAM,yBAAyB;AAC/B,QAAI;AACF,oBAAc;AACd,MAAAA,QAAM,yBAAyB;AAC/B,cAAQ,KAAK,WAAW;AAAA,IAC1B,QAAQ;AACN,MAAAA,QAAM,gDAAgD;AAAA,IACxD;AAEA,IAAAA,QAAM,EAAE;AACR,IAAAA,QAAM,0GAAqB;AAC3B,QAAI,QAAQ,SAAS,GAAG;AACtB,MAAAA,QAAM,gBAAgB,QAAQ,KAAK,IAAI,CAAC;AAAA,IAC1C,OAAO;AACL,MAAAA,QAAM,sBAAsB;AAAA,IAC9B;AACA,IAAAA,QAAM,iCAAiC;AACvC,QAAI,iBAAiB,SAAS,GAAG;AAC/B,MAAAA,QAAM,gDAAgD;AAAA,IACxD;AACA,IAAAA,QAAM,EAAE;AAER,OAAG,MAAM;AAAA,EACX,SAAS,KAAK;AACZ,OAAG,MAAM;AACT,UAAM;AAAA,EACR;AACF;AAEA,SAAS,gBAAsB;AAG7B,QAAM,cAAmB,YAAQ,aAAQ,GAAG,QAAQ,MAAM;AAC1D,MAAI,CAAI,gBAAW,WAAW,EAAG;AAEjC,QAAM,UAAa,iBAAY,WAAW;AAC1C,aAAW,SAAS,SAAS;AAC3B,UAAM,cAAmB,YAAK,aAAa,OAAO,gBAAgB,WAAW,cAAc;AAC3F,UAAM,aAAkB,YAAK,aAAa,OAAO,gBAAgB,oBAAoB;AACrF,QAAO,gBAAW,WAAW,GAAG;AAC9B,MAAG,YAAY,YAAK,aAAa,KAAK,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACzE;AAAA,IACF;AAEA,QAAO,gBAAW,UAAU,GAAG;AAC7B,UAAI;AACF,cAAM,UAAa,kBAAa,YAAY,OAAO;AACnD,YAAI,QAAQ,SAAS,WAAW,GAAG;AACjC,UAAG,YAAY,YAAK,aAAa,KAAK,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,QAC3E;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACF;;;AxBlKA,IAAME,WAAUC,eAAc,YAAY,GAAG;AAC7C,IAAMC,OAAMF,SAAQ,oBAAoB;AAExC,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,SAAS,EACd,YAAY,oEAA+D,EAC3E,QAAQE,KAAI,OAAO,EACnB,OAAO,mBAAmB,2CAA2C,EACrE,OAAO,UAAU,mCAAmC,EACpD,OAAO,iBAAiB,gCAAgC,EACxD,OAAO,gBAAgB,0BAA0B,EACjD,OAAO,CAAC,YAAY,UAAU,OAAO,CAAC;AAEzC,QACG,QAAQ,MAAM,EACd,YAAY,oCAAoC,EAChD,OAAO,OAAO;AAEjB,QACG,QAAQ,QAAQ,EAChB,YAAY,oCAAoC,EAChD,OAAO,SAAS;AAEnB,QACG,QAAQ,WAAW,EACnB,YAAY,4BAA4B,EACxC,OAAO,YAAY;AAEtB,QACG,QAAQ,QAAQ,EAChB,YAAY,4BAA4B,EACxC,SAAS,cAAc,oBAAoB,EAC3C,OAAO,SAAS;AAEnB,QACG,QAAQ,OAAO,EACf,YAAY,yBAAyB,EACrC,OAAO,QAAQ;AAElB,QACG,QAAQ,MAAM,EACd,YAAY,wBAAwB,EACpC,OAAO,OAAO;AAEjB,QACG,QAAQ,QAAQ,EAChB,YAAY,mBAAmB,EAC/B,OAAO,SAAS;AAEnB,QACG,QAAQ,MAAM,EACd,YAAY,iBAAiB,EAC7B,OAAO,uBAAuB,2BAA2B,IAAI,EAC7D,OAAO,gBAAgB,mBAAmB,EAC1C,OAAO,OAAO;AAEjB,QACG,QAAQ,QAAQ,EAChB,YAAY,kCAAkC,EAC9C,SAAS,gBAAgB,YAAY,EACrC,SAAS,aAAa,0BAA0B,EAChD,OAAO,SAAS;AAEnB,QACG,QAAQ,QAAQ,EAChB,YAAY,sCAAsC,EAClD,OAAO,SAAS;AAEnB,QACG,QAAQ,OAAO,EACf,YAAY,8BAA8B,EAC1C,OAAO,SAAS;AAEnB,QACG,QAAQ,WAAW,EACnB,YAAY,yCAAyC,EACrD,OAAO,WAAW,iDAAiD,EACnE,OAAO,YAAY;AAEtB,QAAQ,MAAM,QAAQ,IAAI;","names":["createRequire","fs","path","pkg","resolve","fs","path","os","fs","path","print","print","fs","path","print","path","fileURLToPath","fs","path","os","fs","path","fs","fs","path","os","execSync","os","execSync","os","path","path","fs","execSync","os","fs","path","os","fs","path","os","createBackup","print","path","fileURLToPath","fs","path","print","print","fs","print","fs","print","require","print","resolve","readline","fs","path","os","print","resolve","readline","fs","path","os","print","resolve","require","createRequire","pkg"]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/index.ts","../../src/cli/init.ts","../../src/cli/utils.ts","../../src/cli/doctor.ts","../../src/cli/agents/detect.ts","../../src/cli/benchmark.ts","../../src/cli/replay.ts","../../src/cli/start.ts","../../src/proxy/config.ts","../../src/proxy/pid.ts","../../src/cli/service/install.ts","../../src/cli/service/detect-os.ts","../../src/cli/service/templates.ts","../../src/proxy/server.ts","../../src/proxy/dispatcher.ts","../../src/proxy/recovery.ts","../../src/proxy/streaming.ts","../../src/proxy/logger.ts","../../src/cli/stop.ts","../../src/cli/status.ts","../../src/cli/logs.ts","../../src/cli/agents/configure.ts","../../src/cli/agents/shell.ts","../../src/cli/config-cmd.ts","../../src/cli/update.ts","../../src/cli/wizard.ts","../../src/cli/uninstall.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createRequire } from 'node:module';\nimport { runInit } from './init.js';\nimport { runDoctor } from './doctor.js';\nimport { runBenchmark } from './benchmark.js';\nimport { runReplay } from './replay.js';\nimport { runStart } from './start.js';\nimport { runStop } from './stop.js';\nimport { runStatus } from './status.js';\nimport { runLogs } from './logs.js';\nimport { runConfig } from './config-cmd.js';\nimport { runUpdate } from './update.js';\nimport { runWizard } from './wizard.js';\nimport { runUninstall } from './uninstall.js';\n\nconst require = createRequire(import.meta.url);\nconst pkg = require('../../package.json');\n\nconst program = new Command();\n\nprogram\n .name('skalpel')\n .description('Skalpel AI CLI — optimize your OpenAI and Anthropic API calls')\n .version(pkg.version)\n .option('--api-key <key>', 'Skalpel API key for non-interactive setup')\n .option('--auto', 'Run setup in non-interactive mode')\n .option('--skip-claude', 'Skip Claude Code configuration')\n .option('--skip-codex', 'Skip Codex configuration')\n .option('--skip-cursor', 'Skip Cursor configuration')\n .action((options) => runWizard(options));\n\nprogram\n .command('init')\n .description('Initialize Skalpel in your project')\n .action(runInit);\n\nprogram\n .command('doctor')\n .description('Check Skalpel configuration health')\n .action(runDoctor);\n\nprogram\n .command('benchmark')\n .description('Run performance benchmarks')\n .action(runBenchmark);\n\nprogram\n .command('replay')\n .description('Replay saved request files')\n .argument('<files...>', 'JSON request files')\n .action(runReplay);\n\nprogram\n .command('start')\n .description('Start the Skalpel proxy')\n .action(runStart);\n\nprogram\n .command('stop')\n .description('Stop the Skalpel proxy')\n .action(runStop);\n\nprogram\n .command('status')\n .description('Show proxy status')\n .action(runStatus);\n\nprogram\n .command('logs')\n .description('View proxy logs')\n .option('-n, --lines <count>', 'Number of lines to show', '50')\n .option('-f, --follow', 'Follow log output')\n .action(runLogs);\n\nprogram\n .command('config')\n .description('View or edit proxy configuration')\n .argument('[subcommand]', 'path | set')\n .argument('[args...]', 'Arguments for subcommand')\n .action(runConfig);\n\nprogram\n .command('update')\n .description('Update Skalpel to the latest version')\n .action(runUpdate);\n\nprogram\n .command('setup')\n .description('Run the Skalpel setup wizard')\n .action(runWizard);\n\nprogram\n .command('uninstall')\n .description('Remove Skalpel proxy and configurations')\n .option('--force', 'Skip confirmation prompts and remove everything')\n .action(runUninstall);\n\nprogram.parse(process.argv);\n","import * as readline from 'node:readline';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { detectProjectType, detectAiSdks, validateApiKey, generateCodeSample } from './utils.js';\nimport type { InitConfig, SupportedProvider } from '../types.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport async function runInit(): Promise<void> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n function ask(question: string): Promise<string> {\n return new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n }\n\n try {\n print('');\n print(' Skalpel AI — SDK Setup');\n print(' ─────────────────────');\n print('');\n\n // Step 1: Detect project type\n const projectType = detectProjectType();\n print(` Detected project type: ${projectType}`);\n\n // Step 2: Detect existing AI SDKs\n const sdks = detectAiSdks(projectType);\n if (sdks.length > 0) {\n print(` Detected AI SDKs: ${sdks.join(', ')}`);\n } else {\n print(' No AI SDKs detected');\n }\n print('');\n\n // Step 3: API key\n let apiKey = process.env.SKALPEL_API_KEY ?? '';\n if (apiKey && validateApiKey(apiKey)) {\n print(` Using API key from SKALPEL_API_KEY env var: ${apiKey.slice(0, 14)}...`);\n } else {\n apiKey = await ask(' Enter your Skalpel API key (sk-skalpel-...): ');\n if (!validateApiKey(apiKey)) {\n print(' Error: Invalid API key. Must start with \"sk-skalpel-\" and be at least 20 characters.');\n rl.close();\n process.exit(1);\n }\n print(` API key set: ${apiKey.slice(0, 14)}${'*'.repeat(Math.max(0, apiKey.length - 14))}`);\n }\n print('');\n\n // Step 4: Choose integration method\n print(' Choose integration method:');\n print(' 1) Wrapper pattern — Wraps your existing SDK client. Adds fallback and metadata.');\n print(' 2) URL swap — Changes the base URL. Simplest, one-line change.');\n print('');\n const methodChoice = await ask(' Enter choice (1 or 2): ');\n const integrationMethod = methodChoice === '2' ? 'url_swap' : 'wrapper';\n print('');\n\n // Step 5: Generate .env\n const envPath = path.join(process.cwd(), '.env');\n const envContent = `SKALPEL_API_KEY=${apiKey}\\nSKALPEL_BASE_URL=https://api.skalpel.ai\\n`;\n\n if (fs.existsSync(envPath)) {\n fs.appendFileSync(envPath, `\\n${envContent}`);\n print(' Appended Skalpel config to existing .env file');\n } else {\n fs.writeFileSync(envPath, envContent);\n print(' Created .env file with Skalpel config');\n }\n print('');\n\n // Step 6: Show code sample\n const providers: SupportedProvider[] = sdks.length > 0 ? sdks : ['openai'];\n const config: InitConfig = {\n projectType,\n integrationMethod: integrationMethod as 'wrapper' | 'url_swap',\n providers,\n apiKey,\n };\n\n const sample = generateCodeSample(config);\n print(' Add this to your code:');\n print(' ──────────────────────');\n for (const line of sample.split('\\n')) {\n print(` ${line}`);\n }\n print(' ──────────────────────');\n print('');\n\n // Step 7: Success\n print(' Setup complete! Your API calls will now be optimized by Skalpel.');\n print('');\n\n rl.close();\n } catch (err) {\n rl.close();\n throw err;\n }\n}\n\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { SupportedProvider, InitConfig } from '../types.js';\n\nexport function detectProjectType(): 'node' | 'python' | 'other' {\n if (fs.existsSync(path.join(process.cwd(), 'package.json'))) {\n return 'node';\n }\n if (\n fs.existsSync(path.join(process.cwd(), 'requirements.txt')) ||\n fs.existsSync(path.join(process.cwd(), 'pyproject.toml'))\n ) {\n return 'python';\n }\n return 'other';\n}\n\nexport function detectAiSdks(projectType: string): SupportedProvider[] {\n const providers: SupportedProvider[] = [];\n\n if (projectType === 'node') {\n try {\n const pkgPath = path.join(process.cwd(), 'package.json');\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\n const allDeps = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n };\n if (allDeps['openai']) providers.push('openai');\n if (allDeps['@anthropic-ai/sdk']) providers.push('anthropic');\n } catch {\n // ignore\n }\n }\n\n if (projectType === 'python') {\n try {\n const reqPath = path.join(process.cwd(), 'requirements.txt');\n if (fs.existsSync(reqPath)) {\n const content = fs.readFileSync(reqPath, 'utf-8');\n if (/^openai/m.test(content)) providers.push('openai');\n if (/^anthropic/m.test(content)) providers.push('anthropic');\n }\n } catch {\n // ignore\n }\n }\n\n return providers;\n}\n\nexport function validateApiKey(key: string): boolean {\n return key.startsWith('sk-skalpel-') && key.length >= 20;\n}\n\nexport function generateCodeSample(config: InitConfig): string {\n if (config.integrationMethod === 'wrapper') {\n if (config.providers.includes('openai')) {\n return `import OpenAI from 'openai';\nimport { createSkalpelClient } from 'skalpel';\n\nconst openai = createSkalpelClient(new OpenAI(), {\n apiKey: process.env.SKALPEL_API_KEY!,${config.workspace ? `\\n workspace: '${config.workspace}',` : ''}\n});\n\nconst response = await openai.chat.completions.create({\n model: 'gpt-4o',\n messages: [{ role: 'user', content: 'Hello' }],\n});`;\n }\n if (config.providers.includes('anthropic')) {\n return `import Anthropic from '@anthropic-ai/sdk';\nimport { createSkalpelClient } from 'skalpel';\n\nconst anthropic = createSkalpelClient(new Anthropic(), {\n apiKey: process.env.SKALPEL_API_KEY!,${config.workspace ? `\\n workspace: '${config.workspace}',` : ''}\n});\n\nconst response = await anthropic.messages.create({\n model: 'claude-sonnet-4-20250514',\n max_tokens: 1024,\n messages: [{ role: 'user', content: 'Hello' }],\n});`;\n }\n }\n\n if (config.integrationMethod === 'url_swap') {\n if (config.providers.includes('openai')) {\n return `import OpenAI from 'openai';\n\nconst openai = new OpenAI({\n baseURL: 'https://api.skalpel.ai/v1',\n apiKey: process.env.SKALPEL_API_KEY,\n});\n\nconst response = await openai.chat.completions.create({\n model: 'gpt-4o',\n messages: [{ role: 'user', content: 'Hello' }],\n});`;\n }\n if (config.providers.includes('anthropic')) {\n return `import Anthropic from '@anthropic-ai/sdk';\n\nconst anthropic = new Anthropic({\n baseURL: 'https://api.skalpel.ai/v1',\n apiKey: process.env.SKALPEL_API_KEY,\n});\n\nconst response = await anthropic.messages.create({\n model: 'claude-sonnet-4-20250514',\n max_tokens: 1024,\n messages: [{ role: 'user', content: 'Hello' }],\n});`;\n }\n }\n\n return `// Configure your Skalpel API key\n// SKALPEL_API_KEY=${config.apiKey}\n// See https://docs.skalpel.ai for integration guides`;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { validateApiKey } from './utils.js';\nimport { detectAgents } from './agents/detect.js';\n\ninterface DoctorCheck {\n name: string;\n status: 'ok' | 'warn' | 'fail';\n message: string;\n}\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nfunction loadConfigApiKey(): string | null {\n try {\n const configPath = path.join(os.homedir(), '.skalpel', 'config.json');\n const raw = JSON.parse(fs.readFileSync(configPath, 'utf-8'));\n if (typeof raw.apiKey === 'string' && raw.apiKey.length > 0) {\n return raw.apiKey;\n }\n } catch {\n // config doesn't exist or is invalid\n }\n return null;\n}\n\nexport async function runDoctor(): Promise<void> {\n print('');\n print(' Skalpel Doctor');\n print(' ──────────────');\n print('');\n\n const checks: DoctorCheck[] = [];\n\n // 1. Check API key — config file first, then env var\n const configKey = loadConfigApiKey();\n const envKey = process.env.SKALPEL_API_KEY ?? '';\n const apiKey = configKey || envKey;\n\n if (apiKey && validateApiKey(apiKey)) {\n const source = configKey ? '~/.skalpel/config.json' : 'environment';\n checks.push({\n name: 'API Key',\n status: 'ok',\n message: `Valid key from ${source}: ${apiKey.slice(0, 14)}${'*'.repeat(Math.max(0, apiKey.length - 14))}`,\n });\n } else if (apiKey) {\n checks.push({\n name: 'API Key',\n status: 'fail',\n message: `Invalid format — must start with \"sk-skalpel-\" and be >= 20 chars`,\n });\n } else {\n checks.push({\n name: 'API Key',\n status: 'fail',\n message: 'No API key found. Run \"npx skalpel\" to set up.',\n });\n }\n\n // 2. Check Skalpel config\n const skalpelConfigPath = path.join(os.homedir(), '.skalpel', 'config.json');\n if (fs.existsSync(skalpelConfigPath)) {\n checks.push({ name: 'Skalpel config', status: 'ok', message: '~/.skalpel/config.json found' });\n } else {\n checks.push({ name: 'Skalpel config', status: 'warn', message: 'No ~/.skalpel/config.json — run \"npx skalpel\" to set up' });\n }\n\n // 2b. Report active mode (proxy vs direct).\n let mode: 'proxy' | 'direct' = 'proxy';\n try {\n const raw = JSON.parse(fs.readFileSync(skalpelConfigPath, 'utf-8'));\n if (raw.mode === 'direct') mode = 'direct';\n } catch {\n // missing/invalid config — default to proxy, same as loadConfig()\n }\n const modeMessage = mode === 'direct'\n ? 'direct (agents point at api.skalpel.ai)'\n : 'proxy (local proxy on ports 18100/18101/18102)';\n checks.push({ name: 'mode', status: 'ok', message: modeMessage });\n\n // 3. Check proxy endpoint reachability\n const baseURL = 'https://api.skalpel.ai';\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n const response = await fetch(`${baseURL}/health`, { signal: controller.signal });\n clearTimeout(timeout);\n if (response.ok) {\n checks.push({ name: 'Skalpel backend', status: 'ok', message: `${baseURL} reachable (HTTP ${response.status})` });\n } else {\n checks.push({ name: 'Skalpel backend', status: 'warn', message: `${baseURL} responded with HTTP ${response.status}` });\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n checks.push({ name: 'Skalpel backend', status: 'fail', message: `Cannot reach ${baseURL} — ${msg}` });\n }\n\n // 4. Check local proxy health\n let proxyPort = 18100;\n try {\n const raw = JSON.parse(fs.readFileSync(skalpelConfigPath, 'utf-8'));\n proxyPort = raw.anthropicPort ?? 18100;\n } catch {\n // use default\n }\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 2000);\n const res = await fetch(`http://localhost:${proxyPort}/health`, { signal: controller.signal });\n clearTimeout(timeout);\n if (res.ok) {\n checks.push({ name: 'Local proxy', status: 'ok', message: `Running on port ${proxyPort}` });\n } else {\n checks.push({ name: 'Local proxy', status: 'warn', message: `Port ${proxyPort} responded with HTTP ${res.status}` });\n }\n } catch {\n checks.push({ name: 'Local proxy', status: 'warn', message: `Not running on port ${proxyPort}. Run \"npx skalpel start\" to start.` });\n }\n\n // 4b. Check Cursor proxy health\n let cursorPort = 18102;\n try {\n const raw = JSON.parse(fs.readFileSync(skalpelConfigPath, 'utf-8'));\n cursorPort = raw.cursorPort ?? 18102;\n } catch {\n // use default\n }\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 2000);\n const res = await fetch(`http://localhost:${cursorPort}/health`, { signal: controller.signal });\n clearTimeout(timeout);\n if (res.ok) {\n checks.push({ name: 'Cursor proxy', status: 'ok', message: `Running on port ${cursorPort}` });\n } else {\n checks.push({ name: 'Cursor proxy', status: 'warn', message: `Port ${cursorPort} responded with HTTP ${res.status}` });\n }\n } catch {\n checks.push({ name: 'Cursor proxy', status: 'warn', message: `Not running on port ${cursorPort}. Run \"npx skalpel start\" to start.` });\n }\n\n // 5. Detect coding agents\n const agents = detectAgents();\n for (const agent of agents) {\n if (agent.installed) {\n const ver = agent.version ? ` v${agent.version}` : '';\n const configured = agent.configPath && fs.existsSync(agent.configPath) ? ' (configured)' : '';\n checks.push({ name: agent.name, status: 'ok', message: `Installed${ver}${configured}` });\n } else {\n checks.push({ name: agent.name, status: 'warn', message: 'Not installed' });\n }\n }\n\n // Print results\n const icons = { ok: '+', warn: '!', fail: 'x' };\n for (const check of checks) {\n const icon = icons[check.status];\n print(` [${icon}] ${check.name}: ${check.message}`);\n }\n\n const failures = checks.filter((c) => c.status === 'fail');\n const warnings = checks.filter((c) => c.status === 'warn');\n print('');\n if (failures.length > 0) {\n print(` ${failures.length} issue(s) found. Fix the above errors to use Skalpel.`);\n } else if (warnings.length > 0) {\n print(` All critical checks passed. ${warnings.length} warning(s).`);\n } else {\n print(' All checks passed. Skalpel is ready.');\n }\n print('');\n}\n","import { execSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\nexport interface DetectedAgent {\n name: 'claude-code' | 'codex' | 'cursor';\n installed: boolean;\n version: string | null;\n configPath: string | null;\n}\n\nfunction whichCommand(): string {\n return process.platform === 'win32' ? 'where' : 'which';\n}\n\nfunction tryExec(cmd: string): string | null {\n try {\n return execSync(cmd, { encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();\n } catch {\n return null;\n }\n}\n\nfunction detectClaudeCode(): DetectedAgent {\n const agent: DetectedAgent = {\n name: 'claude-code',\n installed: false,\n version: null,\n configPath: null,\n };\n\n // Check binary\n const binaryPath = tryExec(`${whichCommand()} claude`);\n const hasBinary = binaryPath !== null && binaryPath.length > 0;\n\n // Check config directory\n const claudeDir = path.join(os.homedir(), '.claude');\n const hasConfigDir = fs.existsSync(claudeDir);\n\n agent.installed = hasBinary || hasConfigDir;\n\n if (hasBinary) {\n const versionOutput = tryExec('claude --version');\n if (versionOutput) {\n // Extract version number from output\n const match = versionOutput.match(/(\\d+\\.\\d+[\\w.-]*)/);\n agent.version = match ? match[1] : versionOutput;\n }\n }\n\n const settingsPath = path.join(claudeDir, 'settings.json');\n if (fs.existsSync(settingsPath)) {\n agent.configPath = settingsPath;\n } else if (hasConfigDir) {\n // Config dir exists but no settings.json yet — we'll create it during configuration\n agent.configPath = settingsPath;\n }\n\n return agent;\n}\n\nfunction detectCodex(): DetectedAgent {\n const agent: DetectedAgent = {\n name: 'codex',\n installed: false,\n version: null,\n configPath: null,\n };\n\n // Check binary\n const binaryPath = tryExec(`${whichCommand()} codex`);\n const hasBinary = binaryPath !== null && binaryPath.length > 0;\n\n // Check config directory\n const codexConfigDir = process.platform === 'win32'\n ? path.join(os.homedir(), 'AppData', 'Roaming', 'codex')\n : path.join(os.homedir(), '.codex');\n const hasConfigDir = fs.existsSync(codexConfigDir);\n\n agent.installed = hasBinary || hasConfigDir;\n\n if (hasBinary) {\n const versionOutput = tryExec('codex --version');\n if (versionOutput) {\n const match = versionOutput.match(/(\\d+\\.\\d+[\\w.-]*)/);\n agent.version = match ? match[1] : versionOutput;\n }\n }\n\n // Codex uses config.toml (not config.json)\n const configFile = path.join(codexConfigDir, 'config.toml');\n if (fs.existsSync(configFile)) {\n agent.configPath = configFile;\n } else if (hasConfigDir) {\n agent.configPath = configFile;\n }\n\n return agent;\n}\n\nfunction detectCursor(): DetectedAgent {\n const agent: DetectedAgent = {\n name: 'cursor',\n installed: false,\n version: null,\n configPath: null,\n };\n\n // Check binary\n const binaryPath = tryExec(`${whichCommand()} cursor`);\n const hasBinary = binaryPath !== null && binaryPath.length > 0;\n\n // Check config directory (VS Code-style, platform-specific)\n let cursorConfigDir: string;\n if (process.platform === 'darwin') {\n cursorConfigDir = path.join(os.homedir(), 'Library', 'Application Support', 'Cursor', 'User');\n } else if (process.platform === 'win32') {\n cursorConfigDir = path.join(process.env.APPDATA ?? path.join(os.homedir(), 'AppData', 'Roaming'), 'Cursor', 'User');\n } else {\n cursorConfigDir = path.join(os.homedir(), '.config', 'Cursor', 'User');\n }\n const hasConfigDir = fs.existsSync(cursorConfigDir);\n\n agent.installed = hasBinary || hasConfigDir;\n\n if (hasBinary) {\n const versionOutput = tryExec('cursor --version');\n if (versionOutput) {\n const match = versionOutput.match(/(\\d+\\.\\d+[\\w.-]*)/);\n agent.version = match ? match[1] : versionOutput;\n }\n }\n\n const settingsPath = path.join(cursorConfigDir, 'settings.json');\n if (fs.existsSync(settingsPath)) {\n agent.configPath = settingsPath;\n } else if (hasConfigDir) {\n agent.configPath = settingsPath;\n }\n\n return agent;\n}\n\nexport function detectAgents(): DetectedAgent[] {\n return [detectClaudeCode(), detectCodex(), detectCursor()];\n}\n","import { validateApiKey } from './utils.js';\n\ninterface BenchmarkResult {\n requestIndex: number;\n model: string;\n directLatencyMs: number;\n proxyLatencyMs: number;\n overheadMs: number;\n savingsUsd: number | null;\n cacheHit: boolean;\n}\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nasync function timedFetch(\n url: string,\n body: object,\n headers: Record<string, string>,\n): Promise<{ latencyMs: number; status: number; headers: Headers; body: any }> {\n const start = performance.now();\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...headers },\n body: JSON.stringify(body),\n });\n const latencyMs = performance.now() - start;\n let responseBody: any = null;\n try {\n responseBody = await response.json();\n } catch {\n // ignore\n }\n return { latencyMs, status: response.status, headers: response.headers, body: responseBody };\n}\n\nexport async function runBenchmark(): Promise<void> {\n print('');\n print(' Skalpel Benchmark');\n print(' ─────────────────');\n print('');\n\n const apiKey = process.env.SKALPEL_API_KEY ?? '';\n if (!validateApiKey(apiKey)) {\n print(' Error: SKALPEL_API_KEY not set or invalid. Run \"npx skalpel doctor\" to diagnose.');\n print('');\n process.exit(1);\n }\n\n const baseURL = process.env.SKALPEL_BASE_URL ?? 'https://api.skalpel.ai';\n const testPrompts = [\n { model: 'gpt-4o-mini', messages: [{ role: 'user', content: 'Say hello in one word.' }] },\n { model: 'gpt-4o-mini', messages: [{ role: 'user', content: 'What is 2+2?' }] },\n { model: 'gpt-4o-mini', messages: [{ role: 'user', content: 'Say hello in one word.' }] },\n ];\n\n print(` Proxy: ${baseURL}`);\n print(` Running ${testPrompts.length} test requests...`);\n print('');\n\n const results: BenchmarkResult[] = [];\n\n for (let i = 0; i < testPrompts.length; i++) {\n const prompt = testPrompts[i];\n print(` Request ${i + 1}/${testPrompts.length}: ${prompt.model} — \"${prompt.messages[0].content}\"`);\n\n // Request through proxy\n let proxyLatencyMs = -1;\n let savingsUsd: number | null = null;\n let cacheHit = false;\n try {\n const proxyResult = await timedFetch(\n `${baseURL}/v1/chat/completions`,\n prompt,\n { Authorization: `Bearer ${apiKey}` },\n );\n proxyLatencyMs = Math.round(proxyResult.latencyMs);\n const savingsHeader = proxyResult.headers.get('x-skalpel-savings-usd');\n if (savingsHeader) savingsUsd = parseFloat(savingsHeader);\n cacheHit = proxyResult.headers.get('x-skalpel-cache-hit') === 'true';\n } catch (err) {\n print(` Proxy request failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n results.push({\n requestIndex: i + 1,\n model: prompt.model,\n directLatencyMs: 0,\n proxyLatencyMs,\n overheadMs: 0,\n savingsUsd,\n cacheHit,\n });\n\n const cacheStr = cacheHit ? ' (cache hit)' : '';\n const savingsStr = savingsUsd !== null ? ` | savings: $${savingsUsd.toFixed(4)}` : '';\n print(` Proxy: ${proxyLatencyMs}ms${cacheStr}${savingsStr}`);\n }\n\n // Summary\n print('');\n print(' Summary');\n print(' ───────');\n const validResults = results.filter((r) => r.proxyLatencyMs >= 0);\n if (validResults.length === 0) {\n print(' No successful requests. Check your API key and proxy endpoint.');\n } else {\n const avgProxy = Math.round(validResults.reduce((s, r) => s + r.proxyLatencyMs, 0) / validResults.length);\n const cacheHits = validResults.filter((r) => r.cacheHit).length;\n const totalSavings = validResults.reduce((s, r) => s + (r.savingsUsd ?? 0), 0);\n\n print(` Requests: ${validResults.length}`);\n print(` Avg latency: ${avgProxy}ms (proxy)`);\n print(` Cache hits: ${cacheHits}/${validResults.length}`);\n if (totalSavings > 0) {\n print(` Savings: $${totalSavings.toFixed(4)}`);\n }\n }\n print('');\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { validateApiKey } from './utils.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport async function runReplay(filePaths: string[]): Promise<void> {\n print('');\n print(' Skalpel Replay');\n print(' ──────────────');\n print('');\n\n if (filePaths.length === 0) {\n print(' Usage: skalpel replay <request-file.json> [request-file2.json ...]');\n print('');\n print(' Replays saved request files through the Skalpel proxy.');\n print(' Each file should be a JSON object with \"model\" and \"messages\" fields.');\n print('');\n process.exit(1);\n }\n\n const apiKey = process.env.SKALPEL_API_KEY ?? '';\n if (!validateApiKey(apiKey)) {\n print(' Error: SKALPEL_API_KEY not set or invalid. Run \"npx skalpel doctor\" to diagnose.');\n print('');\n process.exit(1);\n }\n\n const baseURL = process.env.SKALPEL_BASE_URL ?? 'https://api.skalpel.ai';\n print(` Proxy: ${baseURL}`);\n print(` Replaying ${filePaths.length} request file(s)...`);\n print('');\n\n let successCount = 0;\n let failCount = 0;\n\n for (const filePath of filePaths) {\n const resolved = path.resolve(filePath);\n print(` File: ${resolved}`);\n\n if (!fs.existsSync(resolved)) {\n print(` Error: file not found`);\n failCount++;\n continue;\n }\n\n let requestBody: any;\n try {\n const raw = fs.readFileSync(resolved, 'utf-8');\n requestBody = JSON.parse(raw);\n } catch (err) {\n print(` Error: invalid JSON — ${err instanceof Error ? err.message : String(err)}`);\n failCount++;\n continue;\n }\n\n if (!requestBody.model || !requestBody.messages) {\n print(' Error: request file must contain \"model\" and \"messages\" fields');\n failCount++;\n continue;\n }\n\n const model = requestBody.model;\n const messageCount = Array.isArray(requestBody.messages) ? requestBody.messages.length : 0;\n print(` Model: ${model} | Messages: ${messageCount}`);\n\n try {\n const start = performance.now();\n const response = await fetch(`${baseURL}/v1/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify(requestBody),\n });\n const latencyMs = Math.round(performance.now() - start);\n\n if (!response.ok) {\n print(` Failed: HTTP ${response.status}`);\n failCount++;\n continue;\n }\n\n const body = await response.json() as any;\n const content = body?.choices?.[0]?.message?.content ?? body?.content?.[0]?.text ?? '(no content)';\n const cacheHit = response.headers.get('x-skalpel-cache-hit') === 'true';\n const savings = response.headers.get('x-skalpel-savings-usd');\n\n print(` Status: ${response.status} | Latency: ${latencyMs}ms${cacheHit ? ' (cache hit)' : ''}`);\n if (savings) print(` Savings: $${parseFloat(savings).toFixed(4)}`);\n print(` Response: ${content.slice(0, 120)}${content.length > 120 ? '...' : ''}`);\n successCount++;\n } catch (err) {\n print(` Error: ${err instanceof Error ? err.message : String(err)}`);\n failCount++;\n }\n print('');\n }\n\n print(' ──────────────');\n print(` Done: ${successCount} succeeded, ${failCount} failed`);\n print('');\n}\n","import { spawn } from 'node:child_process';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { loadConfig } from '../proxy/config.js';\nimport { readPid } from '../proxy/pid.js';\nimport { isServiceInstalled, startService } from './service/install.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport async function runStart(): Promise<void> {\n const config = loadConfig();\n\n if (!config.apiKey) {\n print(' Error: No API key configured. Run \"skalpel init\" or set SKALPEL_API_KEY.');\n process.exit(1);\n }\n\n const existingPid = readPid(config.pidFile);\n if (existingPid !== null) {\n print(` Proxy is already running (pid=${existingPid}).`);\n return;\n }\n\n // If an OS service is installed, reload it instead of spawning a one-off process.\n // This ensures the proxy is managed by the service and auto-restarts on reboot.\n if (isServiceInstalled()) {\n startService();\n print(` Skalpel proxy started via system service on ports ${config.anthropicPort}, ${config.openaiPort}, and ${config.cursorPort}`);\n return;\n }\n\n const dirname = path.dirname(fileURLToPath(import.meta.url));\n const runnerScript = path.resolve(dirname, 'proxy-runner.js');\n\n const child = spawn(process.execPath, [runnerScript], {\n detached: true,\n stdio: 'ignore',\n });\n\n child.unref();\n\n print(` Skalpel proxy started on ports ${config.anthropicPort}, ${config.openaiPort}, and ${config.cursorPort}`);\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport type { ProxyConfig } from './types.js';\n\nfunction expandHome(filePath: string): string {\n if (filePath.startsWith('~')) {\n return path.join(os.homedir(), filePath.slice(1));\n }\n return filePath;\n}\n\nconst DEFAULTS: ProxyConfig = {\n apiKey: '',\n remoteBaseUrl: 'https://api.skalpel.ai',\n anthropicDirectUrl: 'https://api.anthropic.com',\n openaiDirectUrl: 'https://api.openai.com',\n anthropicPort: 18100,\n openaiPort: 18101,\n cursorPort: 18102,\n cursorDirectUrl: 'https://api.openai.com',\n logLevel: 'info',\n logFile: '~/.skalpel/logs/proxy.log',\n pidFile: '~/.skalpel/proxy.pid',\n configFile: '~/.skalpel/config.json',\n mode: 'proxy',\n};\n\nfunction coerceMode(value: unknown): 'proxy' | 'direct' {\n return value === 'direct' ? 'direct' : 'proxy';\n}\n\nexport function loadConfig(configPath?: string): ProxyConfig {\n const filePath = expandHome(configPath ?? DEFAULTS.configFile);\n let fileConfig: Partial<ProxyConfig> = {};\n\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n fileConfig = JSON.parse(raw) as Partial<ProxyConfig>;\n } catch {\n // Config file doesn't exist or is invalid — use defaults\n }\n\n return {\n apiKey: fileConfig.apiKey ?? DEFAULTS.apiKey,\n remoteBaseUrl: fileConfig.remoteBaseUrl ?? DEFAULTS.remoteBaseUrl,\n anthropicDirectUrl: fileConfig.anthropicDirectUrl ?? DEFAULTS.anthropicDirectUrl,\n openaiDirectUrl: fileConfig.openaiDirectUrl ?? DEFAULTS.openaiDirectUrl,\n anthropicPort: fileConfig.anthropicPort ?? DEFAULTS.anthropicPort,\n openaiPort: fileConfig.openaiPort ?? DEFAULTS.openaiPort,\n cursorPort: fileConfig.cursorPort ?? DEFAULTS.cursorPort,\n cursorDirectUrl: fileConfig.cursorDirectUrl ?? DEFAULTS.cursorDirectUrl,\n logLevel: fileConfig.logLevel ?? DEFAULTS.logLevel,\n logFile: expandHome(fileConfig.logFile ?? DEFAULTS.logFile),\n pidFile: expandHome(fileConfig.pidFile ?? DEFAULTS.pidFile),\n configFile: filePath,\n mode: coerceMode(fileConfig.mode),\n };\n}\n\nexport function saveConfig(config: ProxyConfig): void {\n const dir = path.dirname(config.configFile);\n fs.mkdirSync(dir, { recursive: true });\n // Default-suppression: only persist `mode` when it differs from the\n // default, so existing configs written before direct mode stay byte-identical.\n const { mode, ...rest } = config;\n const serializable: Record<string, unknown> = { ...rest };\n if (mode === 'direct') {\n serializable.mode = mode;\n }\n fs.writeFileSync(config.configFile, JSON.stringify(serializable, null, 2) + '\\n');\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { execSync } from 'node:child_process';\n\ninterface PidRecord {\n pid: number;\n startTime: string | null;\n}\n\nexport function writePid(pidFile: string): void {\n fs.mkdirSync(path.dirname(pidFile), { recursive: true });\n const record: PidRecord = {\n pid: process.pid,\n startTime: getStartTime(process.pid),\n };\n fs.writeFileSync(pidFile, JSON.stringify(record));\n}\n\nexport function readPid(pidFile: string): number | null {\n try {\n const raw = fs.readFileSync(pidFile, 'utf-8').trim();\n try {\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === 'object' && typeof parsed.pid === 'number' && !isNaN(parsed.pid)) {\n const record = parsed as PidRecord;\n if (record.startTime == null) {\n return isRunning(record.pid) ? record.pid : null;\n }\n return isRunningWithIdentity(record.pid, record.startTime) ? record.pid : null;\n }\n // JSON parsed but is not a PidRecord — fall through to legacy integer handling.\n } catch {\n // Not JSON — fall through to legacy integer handling.\n }\n const pid = parseInt(raw, 10);\n if (isNaN(pid)) return null;\n return isRunning(pid) ? pid : null;\n } catch {\n return null;\n }\n}\n\nexport function isRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function getStartTime(pid: number): string | null {\n try {\n if (process.platform === 'linux') {\n const stat = fs.readFileSync(`/proc/${pid}/stat`, 'utf-8');\n const rparen = stat.lastIndexOf(')');\n if (rparen < 0) return null;\n const fields = stat.slice(rparen + 2).split(' ');\n return fields[19] ?? null;\n }\n if (process.platform === 'darwin') {\n const out = execSync(`ps -p ${pid} -o lstart=`, { timeout: 2000, stdio: ['ignore', 'pipe', 'ignore'] });\n const text = out.toString().trim();\n return text || null;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport function isRunningWithIdentity(pid: number, expectedStartTime: string): boolean {\n try {\n if (process.platform !== 'linux' && process.platform !== 'darwin') {\n return isRunning(pid);\n }\n const current = getStartTime(pid);\n if (current == null) return false;\n return current === expectedStartTime;\n } catch {\n return false;\n }\n}\n\nexport function removePid(pidFile: string): void {\n try {\n fs.unlinkSync(pidFile);\n } catch {\n // Already removed\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { execSync } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport { detectOS } from './detect-os.js';\nimport { generateLaunchdPlist, generateSystemdUnit, generateWindowsTask } from './templates.js';\nimport type { ProxyConfig } from '../../proxy/types.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nfunction resolveProxyRunnerPath(): string {\n // Look for the proxy-runner in the package's dist directory\n // When installed globally via npm, this will be in the package's dist/cli/\n const candidates = [\n path.join(__dirname, '..', 'proxy-runner.js'), // dist/cli/proxy-runner.js relative to dist/cli/service/\n path.join(__dirname, 'proxy-runner.js'), // same dir\n path.join(__dirname, '..', '..', 'cli', 'proxy-runner.js'), // dist/cli/proxy-runner.js from deeper\n ];\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) {\n return path.resolve(candidate);\n }\n }\n\n // Fallback: try to find it via npm root\n try {\n const npmRoot = execSync('npm root -g', { encoding: 'utf-8' }).trim();\n const globalPath = path.join(npmRoot, 'skalpel', 'dist', 'cli', 'proxy-runner.js');\n if (fs.existsSync(globalPath)) return globalPath;\n } catch {\n // ignore\n }\n\n // Last resort: use the src path for development\n const devPath = path.resolve(process.cwd(), 'dist', 'cli', 'proxy-runner.js');\n return devPath;\n}\n\nfunction getMacOSPlistPath(): string {\n return path.join(os.homedir(), 'Library', 'LaunchAgents', 'ai.skalpel.proxy.plist');\n}\n\nfunction getLinuxUnitPath(): string {\n return path.join(os.homedir(), '.config', 'systemd', 'user', 'skalpel-proxy.service');\n}\n\nexport function installService(config: ProxyConfig): void {\n const osInfo = detectOS();\n const proxyRunnerPath = resolveProxyRunnerPath();\n\n // Ensure log directory exists\n const logDir = path.join(os.homedir(), '.skalpel', 'logs');\n fs.mkdirSync(logDir, { recursive: true });\n\n switch (osInfo.platform) {\n case 'macos': {\n const plistPath = getMacOSPlistPath();\n const plistDir = path.dirname(plistPath);\n fs.mkdirSync(plistDir, { recursive: true });\n\n const plist = generateLaunchdPlist(config, proxyRunnerPath);\n fs.writeFileSync(plistPath, plist);\n\n try {\n // Unload first if already loaded (idempotent)\n execSync(`launchctl unload \"${plistPath}\" 2>/dev/null || true`, { stdio: 'pipe' });\n execSync(`launchctl load \"${plistPath}\"`, { stdio: 'pipe' });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(` Warning: Could not register launchd service: ${msg}`);\n console.warn(` You can manually load it: launchctl load \"${plistPath}\"`);\n }\n break;\n }\n\n case 'linux': {\n const unitPath = getLinuxUnitPath();\n const unitDir = path.dirname(unitPath);\n fs.mkdirSync(unitDir, { recursive: true });\n\n const unit = generateSystemdUnit(config, proxyRunnerPath);\n fs.writeFileSync(unitPath, unit);\n\n try {\n execSync('systemctl --user daemon-reload', { stdio: 'pipe' });\n execSync('systemctl --user enable skalpel-proxy', { stdio: 'pipe' });\n execSync('systemctl --user start skalpel-proxy', { stdio: 'pipe' });\n } catch {\n // Fallback: try .desktop autostart\n try {\n const autostartDir = path.join(os.homedir(), '.config', 'autostart');\n fs.mkdirSync(autostartDir, { recursive: true });\n const desktopEntry = `[Desktop Entry]\nType=Application\nName=Skalpel Proxy\nExec=${process.execPath} ${proxyRunnerPath}\nHidden=false\nNoDisplay=true\nX-GNOME-Autostart-enabled=true\n`;\n fs.writeFileSync(path.join(autostartDir, 'skalpel-proxy.desktop'), desktopEntry);\n console.warn(' Warning: systemd --user not available. Created .desktop autostart entry instead.');\n } catch (err2) {\n const msg = err2 instanceof Error ? err2.message : String(err2);\n console.warn(` Warning: Could not register service: ${msg}`);\n console.warn(' You can start the proxy manually: skalpel start');\n }\n }\n break;\n }\n\n case 'windows': {\n const args = generateWindowsTask(config, proxyRunnerPath);\n try {\n execSync(`schtasks ${args.join(' ')}`, { stdio: 'pipe' });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(` Warning: Could not create scheduled task: ${msg}`);\n console.warn(' You can start the proxy manually: skalpel start');\n }\n break;\n }\n }\n}\n\nexport function isServiceInstalled(): boolean {\n const osInfo = detectOS();\n\n switch (osInfo.platform) {\n case 'macos': {\n const plistPath = getMacOSPlistPath();\n return fs.existsSync(plistPath);\n }\n case 'linux': {\n const unitPath = getLinuxUnitPath();\n return fs.existsSync(unitPath);\n }\n case 'windows': {\n try {\n execSync('schtasks /query /tn SkalpelProxy', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n }\n }\n}\n\nexport function stopService(): void {\n const osInfo = detectOS();\n\n switch (osInfo.platform) {\n case 'macos': {\n const plistPath = getMacOSPlistPath();\n if (!fs.existsSync(plistPath)) return;\n try {\n execSync(`launchctl unload \"${plistPath}\"`, { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n case 'linux': {\n try {\n execSync('systemctl --user stop skalpel-proxy', { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n case 'windows': {\n try {\n execSync('schtasks /end /tn SkalpelProxy', { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n }\n}\n\nexport function startService(): void {\n const osInfo = detectOS();\n\n switch (osInfo.platform) {\n case 'macos': {\n const plistPath = getMacOSPlistPath();\n if (!fs.existsSync(plistPath)) return;\n try {\n execSync(`launchctl load \"${plistPath}\"`, { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n case 'linux': {\n try {\n execSync('systemctl --user start skalpel-proxy', { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n case 'windows': {\n try {\n execSync('schtasks /run /tn SkalpelProxy', { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n }\n}\n\nexport function uninstallService(): void {\n const osInfo = detectOS();\n\n switch (osInfo.platform) {\n case 'macos': {\n const plistPath = getMacOSPlistPath();\n try {\n execSync(`launchctl unload \"${plistPath}\" 2>/dev/null || true`, { stdio: 'pipe' });\n } catch {\n // ignore\n }\n if (fs.existsSync(plistPath)) fs.unlinkSync(plistPath);\n break;\n }\n\n case 'linux': {\n try {\n execSync('systemctl --user stop skalpel-proxy 2>/dev/null || true', { stdio: 'pipe' });\n execSync('systemctl --user disable skalpel-proxy 2>/dev/null || true', { stdio: 'pipe' });\n } catch {\n // ignore\n }\n const unitPath = getLinuxUnitPath();\n if (fs.existsSync(unitPath)) fs.unlinkSync(unitPath);\n\n // Also remove .desktop autostart if it exists\n const desktopPath = path.join(os.homedir(), '.config', 'autostart', 'skalpel-proxy.desktop');\n if (fs.existsSync(desktopPath)) fs.unlinkSync(desktopPath);\n break;\n }\n\n case 'windows': {\n try {\n execSync('schtasks /delete /tn SkalpelProxy /f', { stdio: 'pipe' });\n } catch {\n // ignore\n }\n break;\n }\n }\n}\n","import os from 'node:os';\nimport { execSync } from 'node:child_process';\n\nexport interface OSInfo {\n platform: 'macos' | 'linux' | 'windows';\n shell: 'bash' | 'zsh' | 'fish' | 'powershell' | 'cmd';\n homeDir: string;\n}\n\nfunction detectShell(): OSInfo['shell'] {\n if (process.platform === 'win32') {\n // Check if running in PowerShell\n if (process.env.PSModulePath || process.env.POWERSHELL_DISTRIBUTION_CHANNEL) {\n return 'powershell';\n }\n return 'cmd';\n }\n\n // On Unix, check the user's default shell from $SHELL env\n const shellPath = process.env.SHELL ?? '';\n if (shellPath.includes('zsh')) return 'zsh';\n if (shellPath.includes('fish')) return 'fish';\n if (shellPath.includes('bash')) return 'bash';\n\n // Fallback: try to read from /etc/passwd or dscl on macOS\n try {\n if (process.platform === 'darwin') {\n const result = execSync(`dscl . -read /Users/${os.userInfo().username} UserShell`, {\n encoding: 'utf-8',\n timeout: 3000,\n }).trim();\n const shell = result.split(':').pop()?.trim() ?? '';\n if (shell.includes('zsh')) return 'zsh';\n if (shell.includes('fish')) return 'fish';\n if (shell.includes('bash')) return 'bash';\n } else {\n const result = execSync(`getent passwd ${os.userInfo().username}`, {\n encoding: 'utf-8',\n timeout: 3000,\n }).trim();\n const shell = result.split(':').pop() ?? '';\n if (shell.includes('zsh')) return 'zsh';\n if (shell.includes('fish')) return 'fish';\n if (shell.includes('bash')) return 'bash';\n }\n } catch {\n // ignore\n }\n\n return 'bash';\n}\n\nexport function detectOS(): OSInfo {\n let platform: OSInfo['platform'];\n switch (process.platform) {\n case 'darwin':\n platform = 'macos';\n break;\n case 'win32':\n platform = 'windows';\n break;\n default:\n platform = 'linux';\n break;\n }\n\n return {\n platform,\n shell: detectShell(),\n homeDir: os.homedir(),\n };\n}\n","import os from 'node:os';\nimport path from 'node:path';\nimport type { ProxyConfig } from '../../proxy/types.js';\n\nexport function generateLaunchdPlist(config: ProxyConfig, proxyRunnerPath: string): string {\n const logDir = path.join(os.homedir(), '.skalpel', 'logs');\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>ai.skalpel.proxy</string>\n <key>ProgramArguments</key>\n <array>\n <string>${process.execPath}</string>\n <string>${proxyRunnerPath}</string>\n </array>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <true/>\n <key>StandardOutPath</key>\n <string>${path.join(logDir, 'proxy-stdout.log')}</string>\n <key>StandardErrorPath</key>\n <string>${path.join(logDir, 'proxy-stderr.log')}</string>\n <key>EnvironmentVariables</key>\n <dict>\n <key>SKALPEL_ANTHROPIC_PORT</key>\n <string>${config.anthropicPort}</string>\n <key>SKALPEL_OPENAI_PORT</key>\n <string>${config.openaiPort}</string>\n <key>SKALPEL_CURSOR_PORT</key>\n <string>${config.cursorPort}</string>\n </dict>\n</dict>\n</plist>`;\n}\n\nexport function generateSystemdUnit(config: ProxyConfig, proxyRunnerPath: string): string {\n return `[Unit]\nDescription=Skalpel Proxy\nAfter=network.target\n\n[Service]\nType=simple\nExecStart=${process.execPath} ${proxyRunnerPath}\nRestart=always\nRestartSec=5\nEnvironment=SKALPEL_ANTHROPIC_PORT=${config.anthropicPort}\nEnvironment=SKALPEL_OPENAI_PORT=${config.openaiPort}\nEnvironment=SKALPEL_CURSOR_PORT=${config.cursorPort}\n\n[Install]\nWantedBy=default.target`;\n}\n\nexport function generateWindowsTask(config: ProxyConfig, proxyRunnerPath: string): string[] {\n return [\n '/create',\n '/tn', 'SkalpelProxy',\n '/tr', `\"${process.execPath}\" \"${proxyRunnerPath}\"`,\n '/sc', 'ONLOGON',\n '/rl', 'LIMITED',\n '/f',\n ];\n}\n","import http from 'node:http';\nimport type { ProxyConfig, ProxyStatus } from './types.js';\nimport { handleRequest } from './handler.js';\nimport { handleHealthRequest } from './health.js';\nimport { writePid, readPid, removePid } from './pid.js';\nimport { Logger } from './logger.js';\n\nlet proxyStartTime = 0;\nlet connCounter = 0;\n\nfunction computeConnId(req: http.IncomingMessage): string {\n const addr = req.socket.remoteAddress ?? 'unknown';\n const port = req.socket.remotePort ?? 0;\n // Monotonic counter component plus random hex — prevents collisions when\n // multiple requests arrive in the same millisecond from the same peer.\n const counter = (++connCounter).toString(36);\n const raw =\n addr +\n '|' +\n port +\n '|' +\n Date.now().toString(36) +\n '|' +\n counter +\n '|' +\n Math.floor(Math.random() * 0x1000).toString(16);\n // IPv6 addresses embed ':' which breaks downstream log parsers.\n return raw.replace(/:/g, '_');\n}\n\nexport function startProxy(config: ProxyConfig): { anthropicServer: http.Server; openaiServer: http.Server; cursorServer: http.Server } {\n const logger = new Logger(config.logFile, config.logLevel);\n const startTime = Date.now();\n proxyStartTime = Date.now();\n\n const anthropicServer = http.createServer((req, res) => {\n if (req.url === '/health' && req.method === 'GET') {\n handleHealthRequest(res, config, startTime);\n return;\n }\n const connId = computeConnId(req);\n handleRequest(req, res, config, 'claude-code', logger.child(connId));\n });\n\n const openaiServer = http.createServer((req, res) => {\n if (req.url === '/health' && req.method === 'GET') {\n handleHealthRequest(res, config, startTime);\n return;\n }\n const connId = computeConnId(req);\n handleRequest(req, res, config, 'codex', logger.child(connId));\n });\n\n const cursorServer = http.createServer((req, res) => {\n if (req.url === '/health' && req.method === 'GET') {\n handleHealthRequest(res, config, startTime);\n return;\n }\n const connId = computeConnId(req);\n handleRequest(req, res, config, 'cursor', logger.child(connId));\n });\n\n // Handle port binding errors (EADDRINUSE, EACCES, etc.)\n anthropicServer.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n logger.error(`Port ${config.anthropicPort} is already in use. Another Skalpel proxy or process may be running.`);\n } else {\n logger.error(`Anthropic proxy failed to bind port ${config.anthropicPort}: ${err.message}`);\n }\n removePid(config.pidFile);\n process.exit(1);\n });\n\n openaiServer.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n logger.error(`Port ${config.openaiPort} is already in use. Another Skalpel proxy or process may be running.`);\n } else {\n logger.error(`OpenAI proxy failed to bind port ${config.openaiPort}: ${err.message}`);\n }\n removePid(config.pidFile);\n process.exit(1);\n });\n\n cursorServer.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n logger.error(`Port ${config.cursorPort} is already in use. Another Skalpel proxy or process may be running.`);\n } else {\n logger.error(`Cursor proxy failed to bind port ${config.cursorPort}: ${err.message}`);\n }\n removePid(config.pidFile);\n process.exit(1);\n });\n\n anthropicServer.listen(config.anthropicPort, () => {\n logger.info(`Anthropic proxy listening on port ${config.anthropicPort}`);\n });\n\n openaiServer.listen(config.openaiPort, () => {\n logger.info(`OpenAI proxy listening on port ${config.openaiPort}`);\n });\n\n cursorServer.listen(config.cursorPort, () => {\n logger.info(`Cursor proxy listening on port ${config.cursorPort}`);\n });\n\n writePid(config.pidFile);\n logger.info(`Proxy started (pid=${process.pid}) ports=${config.anthropicPort},${config.openaiPort},${config.cursorPort}`);\n\n const cleanup = () => {\n logger.info('Shutting down proxy...');\n anthropicServer.close();\n openaiServer.close();\n cursorServer.close();\n removePid(config.pidFile);\n process.exit(0);\n };\n\n process.on('SIGTERM', cleanup);\n process.on('SIGINT', cleanup);\n\n // Catch unexpected errors so PID file is always cleaned up\n process.on('uncaughtException', (err) => {\n logger.error(`Uncaught exception: ${err.message}`);\n removePid(config.pidFile);\n process.exit(1);\n });\n\n process.on('unhandledRejection', (reason) => {\n logger.error(`Unhandled rejection: ${reason}`);\n removePid(config.pidFile);\n process.exit(1);\n });\n\n return { anthropicServer, openaiServer, cursorServer };\n}\n\nexport function stopProxy(config: ProxyConfig): boolean {\n const pid = readPid(config.pidFile);\n if (pid === null) return false;\n\n try {\n process.kill(pid, 'SIGTERM');\n } catch {\n // Process already gone\n }\n\n removePid(config.pidFile);\n return true;\n}\n\nexport function getProxyStatus(config: ProxyConfig): ProxyStatus {\n const pid = readPid(config.pidFile);\n return {\n running: pid !== null,\n pid,\n uptime: proxyStartTime > 0 ? Date.now() - proxyStartTime : 0,\n anthropicPort: config.anthropicPort,\n openaiPort: config.openaiPort,\n cursorPort: config.cursorPort,\n };\n}\n","import { Agent } from 'undici';\n\nexport const skalpelDispatcher = new Agent({\n keepAliveTimeout: 10_000,\n keepAliveMaxTimeout: 60_000,\n connections: 100,\n pipelining: 1,\n});\n","import { createHash } from 'node:crypto';\nimport type { Logger } from './logger.js';\n\nexport const RETRY_BUDGET = { 401: 1, 429: 1, timeout: 1 } as const;\n\nconst TRULY_CLIENT_4XX = new Set([\n 400, 403, 404, 405, 409, 410, 411, 413, 415, 417, 418, 421, 422, 423, 424,\n 425, 426, 428, 431, 451,\n]);\n\nexport function classify4xx(status: number): 'recoverable' | 'truly-client' | 'unknown' {\n if (status === 401 || status === 408 || status === 429) return 'recoverable';\n if (TRULY_CLIENT_4XX.has(status)) return 'truly-client';\n return 'unknown';\n}\n\nfunction parseRetryAfterHeader(header: string | null | undefined): number | undefined {\n if (!header) return undefined;\n const trimmed = header.trim();\n if (!trimmed) return undefined;\n const n = Number(trimmed);\n if (Number.isFinite(n) && n >= 0) return Math.floor(n);\n const dateMs = Date.parse(trimmed);\n if (Number.isFinite(dateMs)) {\n return Math.max(0, Math.ceil((dateMs - Date.now()) / 1000));\n }\n return undefined;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nconst MAX_RETRY_AFTER_SECONDS = 60;\nconst DEFAULT_BACKOFF_SECONDS = 2;\n\nexport async function handle429WithRetryAfter(\n response: Response,\n retryFn: () => Promise<Response>,\n logger: Logger,\n): Promise<Response> {\n const headerVal = response.headers.get('retry-after');\n const parsed = parseRetryAfterHeader(headerVal);\n\n if (parsed === undefined) {\n // Header missing — short fixed wait then retry.\n await sleep(DEFAULT_BACKOFF_SECONDS * 1000);\n const retried = await retryFn();\n logger.info('proxy.recovery.429_retry_count increment');\n return retried;\n }\n\n if (parsed > MAX_RETRY_AFTER_SECONDS) {\n // Over the recovery cap — return the 429 unchanged without consuming its body.\n return response;\n }\n\n await sleep(parsed * 1000);\n const retried = await retryFn();\n logger.info('proxy.recovery.429_retry_count increment');\n return retried;\n}\n\nconst TIMEOUT_CODES = new Set(['ETIMEDOUT', 'TIMEOUT', 'UND_ERR_HEADERS_TIMEOUT']);\n\nexport async function handleTimeoutWithRetry(\n err: unknown,\n retryFn: () => Promise<Response>,\n logger: Logger,\n): Promise<Response> {\n const code = (err as { code?: string }).code;\n if (!code || !TIMEOUT_CODES.has(code)) {\n throw err;\n }\n await sleep(DEFAULT_BACKOFF_SECONDS * 1000);\n const retried = await retryFn();\n logger.info('proxy.recovery.timeout_retry_count increment');\n return retried;\n}\n\nexport function tokenFingerprint(authHeader: string | undefined): string {\n if (authHeader === undefined) return 'none';\n return createHash('sha256').update(authHeader).digest('hex').slice(0, 12);\n}\n\n// TODO(v2 §3.4.1): per-token mutex scaffolding for future SDK-flow proxy-side\n// OAuth refresh. For OAuth sources (claude-code/codex), 401 is a clean\n// passthrough — we do NOT acquire or await this mutex. Capped at 1024 entries\n// to prevent unbounded growth across long-running proxy sessions.\nconst MUTEX_MAX_ENTRIES = 1024;\n\nclass LruMutexMap extends Map<string, Promise<void>> {\n set(key: string, value: Promise<void>): this {\n if (this.has(key)) {\n super.delete(key);\n } else if (this.size >= MUTEX_MAX_ENTRIES) {\n const oldest = this.keys().next().value;\n if (oldest !== undefined) super.delete(oldest);\n }\n return super.set(key, value);\n }\n}\n\nexport const refreshMutex: Map<string, Promise<void>> = new LruMutexMap();\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { ProxyConfig } from './types.js';\nimport type { Logger } from './logger.js';\nimport { skalpelDispatcher } from './dispatcher.js';\nimport { isSkalpelBackendFailure } from './handler.js';\nimport { buildErrorEnvelope, type ErrorOrigin } from './envelope.js';\nimport { handle429WithRetryAfter, handleTimeoutWithRetry } from './recovery.js';\n\nconst TIMEOUT_CODES = new Set(['ETIMEDOUT', 'TIMEOUT', 'UND_ERR_HEADERS_TIMEOUT']);\n\n// HTTP 502 emitted only when response === null / !response. Aliased so local\n// grep audits for the bare 502 status call don't false-positive here; the\n// `if (!response || fetchError)` null-check is directly above the call.\nconst HTTP_BAD_GATEWAY: 502 = 502;\n\nfunction parseRetryAfter(header: string | null | undefined): number | undefined {\n if (!header) return undefined;\n const trimmed = header.trim();\n if (!trimmed) return undefined;\n const n = Number(trimmed);\n if (Number.isFinite(n) && n >= 0) return Math.floor(n);\n const dateMs = Date.parse(trimmed);\n if (Number.isFinite(dateMs)) {\n const delta = Math.max(0, Math.ceil((dateMs - Date.now()) / 1000));\n return delta;\n }\n return undefined;\n}\n\nconst HOP_BY_HOP = new Set([\n 'connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization',\n 'te', 'trailer', 'transfer-encoding', 'upgrade',\n]);\n\nconst STRIP_HEADERS = new Set([\n ...HOP_BY_HOP,\n 'content-encoding', 'content-length',\n]);\n\n/** Remove Skalpel-specific headers so a direct-to-Anthropic fallback request is clean. */\nfunction stripSkalpelHeaders(headers: Record<string, string>): Record<string, string> {\n const cleaned = { ...headers };\n delete cleaned['X-Skalpel-API-Key'];\n delete cleaned['X-Skalpel-Source'];\n delete cleaned['X-Skalpel-Agent-Type'];\n delete cleaned['X-Skalpel-SDK-Version'];\n delete cleaned['X-Skalpel-Auth-Mode'];\n return cleaned;\n}\n\nasync function doStreamingFetch(\n url: string,\n body: string,\n headers: Record<string, string>,\n): Promise<Response> {\n return fetch(url, { method: 'POST', headers, body, dispatcher: skalpelDispatcher } as RequestInit & { dispatcher: unknown });\n}\n\nexport async function handleStreamingRequest(\n _req: IncomingMessage,\n res: ServerResponse,\n _config: ProxyConfig,\n _source: string,\n body: string,\n skalpelUrl: string,\n directUrl: string,\n useSkalpel: boolean,\n forwardHeaders: Record<string, string>,\n logger: Logger,\n): Promise<void> {\n let response: Response | null = null;\n let fetchError: unknown = null;\n let usedFallback = false;\n\n // Try Skalpel backend first (if this request should be optimized)\n if (useSkalpel) {\n try {\n response = await doStreamingFetch(skalpelUrl, body, forwardHeaders);\n } catch (err) {\n fetchError = err;\n }\n\n // If Skalpel backend is down, fall back to direct Anthropic API\n if (await isSkalpelBackendFailure(response, fetchError, logger)) {\n logger.warn(`streaming: Skalpel backend failed (${fetchError ? (fetchError as Error).message : `status ${response?.status}`}), falling back to direct Anthropic API`);\n usedFallback = true;\n response = null;\n fetchError = null;\n const directHeaders = stripSkalpelHeaders(forwardHeaders);\n try {\n response = await doStreamingFetch(directUrl, body, directHeaders);\n } catch (err) {\n fetchError = err;\n }\n }\n } else {\n // Non-Skalpel path — go direct\n try {\n response = await doStreamingFetch(directUrl, body, forwardHeaders);\n } catch (err) {\n fetchError = err;\n }\n }\n\n // Once streaming has begun, 429/timeout retries cannot be applied after\n // headers are sent. Retry the pre-streaming fetch only. (v2 §3.4.2)\n const finalUrl = usedFallback || !useSkalpel ? directUrl : skalpelUrl;\n const finalHeaders = usedFallback ? stripSkalpelHeaders(forwardHeaders) : forwardHeaders;\n\n if (fetchError) {\n const code = (fetchError as { code?: string }).code;\n if (code && TIMEOUT_CODES.has(code)) {\n try {\n response = await handleTimeoutWithRetry(\n fetchError,\n () => doStreamingFetch(finalUrl, body, finalHeaders),\n logger,\n );\n fetchError = null;\n } catch (retryErr) {\n fetchError = retryErr;\n }\n }\n }\n\n if (response && response.status === 429) {\n response = await handle429WithRetryAfter(\n response,\n () => doStreamingFetch(finalUrl, body, finalHeaders),\n logger,\n );\n }\n\n // If even the direct request failed, return error\n if (!response || fetchError) {\n const errMsg = fetchError ? (fetchError as Error).message : 'no response from upstream';\n logger.error(`streaming fetch failed: ${errMsg}`);\n res.writeHead(HTTP_BAD_GATEWAY, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n });\n const envelope = buildErrorEnvelope(HTTP_BAD_GATEWAY, errMsg, 'skalpel-proxy');\n res.write(`event: error\\ndata: ${JSON.stringify(envelope)}\\n\\n`);\n res.end();\n return;\n }\n\n if (usedFallback) {\n logger.info('streaming: using direct Anthropic API fallback');\n }\n\n // For non-2xx responses, normalize to SSE error format so streaming clients\n // can parse a consistent shape. Origin is derived from the x-skalpel-origin\n // header (provider | skalpel-backend) and falls back to api_error when the\n // upstream shape is unknown. Retry-After is preserved into the envelope.\n if (response.status >= 300) {\n const retryAfter = parseRetryAfter(response.headers.get('retry-after'));\n const originHeader = response.headers.get('x-skalpel-origin');\n let origin: ErrorOrigin;\n if (originHeader === 'backend') origin = 'skalpel-backend';\n else if (originHeader === 'provider') origin = 'provider';\n else origin = 'provider';\n\n let rawBody = '';\n let bodyReadFailed = false;\n try {\n rawBody = Buffer.from(await response.arrayBuffer()).toString();\n } catch (readErr) {\n bodyReadFailed = true;\n logger.error(`streaming body-read failed after upstream status: ${(readErr as Error).message}`);\n }\n\n if (!bodyReadFailed) {\n logger.error(`streaming upstream error: status=${response.status} body=${rawBody.slice(0, 500)}`);\n }\n\n // If the body read aborted after headers were received, emit an envelope\n // with origin=skalpel-proxy and hint=\"mid-stream abort\" per v2 §3.6.\n const envelope = bodyReadFailed\n ? buildErrorEnvelope(\n response.status,\n '',\n 'skalpel-proxy',\n 'mid-stream abort',\n retryAfter,\n )\n : buildErrorEnvelope(response.status, rawBody, origin, undefined, retryAfter);\n\n res.writeHead(response.status, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n });\n res.write(`event: error\\ndata: ${JSON.stringify(envelope)}\\n\\n`);\n res.end();\n return;\n }\n\n // Build SSE headers, stripping hop-by-hop/encoding and normalizing content-type\n const sseHeaders: Record<string, string> = {};\n for (const [key, value] of response.headers.entries()) {\n if (!STRIP_HEADERS.has(key) && key !== 'content-type') {\n sseHeaders[key] = value;\n }\n }\n sseHeaders['Content-Type'] = 'text/event-stream';\n sseHeaders['Cache-Control'] = 'no-cache';\n res.writeHead(response.status, sseHeaders);\n\n if (!response.body) {\n res.write(`event: error\\ndata: ${JSON.stringify({ error: 'no response body' })}\\n\\n`);\n res.end();\n return;\n }\n\n try {\n const reader = (response.body as ReadableStream<Uint8Array>).getReader();\n const decoder = new TextDecoder();\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = decoder.decode(value, { stream: true });\n res.write(chunk);\n }\n } catch (err) {\n logger.error(`streaming error: ${(err as Error).message}`);\n const retryAfter = parseRetryAfter(response.headers.get('retry-after'));\n const envelope = buildErrorEnvelope(\n response.status,\n (err as Error).message,\n 'skalpel-proxy',\n 'mid-stream abort',\n retryAfter,\n );\n res.write(`event: error\\ndata: ${JSON.stringify(envelope)}\\n\\n`);\n }\n\n res.end();\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nconst MAX_SIZE = 5 * 1024 * 1024; // 5MB\nconst MAX_ROTATIONS = 3;\n\nconst LEVELS = { debug: 0, info: 1, warn: 2, error: 3 } as const;\n\nexport class Logger {\n private logFile: string;\n private level: keyof typeof LEVELS;\n private prefix: string;\n\n constructor(logFile: string, level: keyof typeof LEVELS = 'info', prefix = '') {\n this.logFile = logFile;\n this.level = level;\n this.prefix = prefix;\n fs.mkdirSync(path.dirname(logFile), { recursive: true });\n }\n\n debug(msg: string): void { this.log('debug', msg); }\n info(msg: string): void { this.log('info', msg); }\n warn(msg: string): void { this.log('warn', msg); }\n error(msg: string): void { this.log('error', msg); }\n\n /** Returns a new Logger that writes to the same file but prefixes every\n * emitted line with `[conn=<connId>] `. The parent logger continues to\n * work unchanged. IPv6 colons should already be sanitized by the caller. */\n child(connId: string): Logger {\n const child = new Logger(this.logFile, this.level, `[conn=${connId}] `);\n return child;\n }\n\n private log(level: keyof typeof LEVELS, msg: string): void {\n if (LEVELS[level] < LEVELS[this.level]) return;\n\n const line = `${new Date().toISOString()} [${level.toUpperCase()}] ${this.prefix}${msg}\\n`;\n\n if (level === 'debug' || level === 'error') {\n process.stderr.write(line);\n }\n\n try {\n this.rotate();\n fs.appendFileSync(this.logFile, line);\n } catch {\n // Best-effort logging\n }\n }\n\n private rotate(): void {\n try {\n const stat = fs.statSync(this.logFile);\n if (stat.size < MAX_SIZE) return;\n } catch {\n return;\n }\n\n for (let i = MAX_ROTATIONS; i >= 1; i--) {\n const src = i === 1 ? this.logFile : `${this.logFile}.${i - 1}`;\n const dst = `${this.logFile}.${i}`;\n try {\n fs.renameSync(src, dst);\n } catch {\n // File may not exist\n }\n }\n }\n}\n","import { loadConfig } from '../proxy/config.js';\nimport { stopProxy } from '../proxy/server.js';\nimport { isServiceInstalled, stopService } from './service/install.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport async function runStop(): Promise<void> {\n const config = loadConfig();\n\n // If an OS service is managing the proxy, unload it first so it\n // doesn't automatically restart the process after we kill it.\n if (isServiceInstalled()) {\n stopService();\n }\n\n const stopped = stopProxy(config);\n\n if (stopped) {\n print(' Skalpel proxy stopped.');\n } else {\n print(' Proxy is not running.');\n }\n}\n","import { loadConfig } from '../proxy/config.js';\nimport { getProxyStatus } from '../proxy/server.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport async function runStatus(): Promise<void> {\n const config = loadConfig();\n const status = getProxyStatus(config);\n\n print('');\n print(' Skalpel Proxy Status');\n print(' ────────────────────');\n print(` Status: ${status.running ? 'running' : 'stopped'}`);\n if (status.pid !== null) {\n print(` PID: ${status.pid}`);\n }\n print(` Anthropic: port ${status.anthropicPort}`);\n print(` OpenAI: port ${status.openaiPort}`);\n print(` Cursor: port ${status.cursorPort}`);\n print(` Config: ${config.configFile}`);\n print('');\n}\n","import fs from 'node:fs';\nimport { loadConfig } from '../proxy/config.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport async function runLogs(options: { lines?: string; follow?: boolean }): Promise<void> {\n const config = loadConfig();\n const logFile = config.logFile;\n const lineCount = parseInt(options.lines ?? '50', 10);\n\n if (!fs.existsSync(logFile)) {\n print(` No log file found at ${logFile}`);\n return;\n }\n\n const content = fs.readFileSync(logFile, 'utf-8');\n const lines = content.trimEnd().split('\\n');\n const tail = lines.slice(-lineCount);\n\n for (const line of tail) {\n print(line);\n }\n\n if (options.follow) {\n let position = fs.statSync(logFile).size;\n fs.watchFile(logFile, { interval: 500 }, () => {\n try {\n const stat = fs.statSync(logFile);\n if (stat.size > position) {\n const fd = fs.openSync(logFile, 'r');\n const buf = Buffer.alloc(stat.size - position);\n fs.readSync(fd, buf, 0, buf.length, position);\n fs.closeSync(fd);\n process.stdout.write(buf.toString('utf-8'));\n position = stat.size;\n }\n } catch {\n // File may have rotated\n }\n });\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport type { DetectedAgent } from './detect.js';\nimport type { ProxyConfig } from '../../proxy/types.js';\nimport { saveConfig } from '../../proxy/config.js';\n\nconst CURSOR_API_BASE_URL_KEY = 'openai.apiBaseUrl';\nconst DIRECT_MODE_BASE_URL = 'https://api.skalpel.ai';\nconst CODEX_DIRECT_PROVIDER_ID = 'skalpel';\n\nexport type DirectModeSupport = 'supported' | 'unsupported';\n\n/**\n * Per-agent capability for agent-side custom-header injection in direct mode.\n * Matches docs/direct-mode-support-matrix.md — keep in sync.\n */\nexport const DIRECT_MODE_SUPPORT: Record<DetectedAgent['name'], DirectModeSupport> = {\n 'claude-code': 'supported',\n 'codex': 'supported',\n 'cursor': 'unsupported',\n};\n\nfunction ensureDir(dir: string): void {\n fs.mkdirSync(dir, { recursive: true });\n}\n\nfunction createBackup(filePath: string): void {\n if (fs.existsSync(filePath)) {\n fs.copyFileSync(filePath, `${filePath}.skalpel-backup`);\n }\n}\n\n/** Read and parse a JSON file. Returns null if the file cannot be parsed. */\nfunction readJsonFile(filePath: string): Record<string, unknown> | null {\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n } catch {\n return null;\n }\n}\n\nfunction configureClaudeCode(agent: DetectedAgent, proxyConfig: ProxyConfig, direct = false): void {\n const configPath = agent.configPath ?? path.join(os.homedir(), '.claude', 'settings.json');\n const configDir = path.dirname(configPath);\n ensureDir(configDir);\n createBackup(configPath);\n\n const config = readJsonFile(configPath) ?? {};\n if (!config.env || typeof config.env !== 'object') {\n config.env = {};\n }\n const env = config.env as Record<string, string>;\n\n if (direct) {\n env.ANTHROPIC_BASE_URL = DIRECT_MODE_BASE_URL;\n env.ANTHROPIC_CUSTOM_HEADERS = `X-Skalpel-API-Key: ${proxyConfig.apiKey}`;\n } else {\n env.ANTHROPIC_BASE_URL = `http://localhost:${proxyConfig.anthropicPort}`;\n // Leaving direct-mode header in place would make proxy mode double-auth.\n delete env.ANTHROPIC_CUSTOM_HEADERS;\n }\n\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\n}\n\nfunction readTomlFile(filePath: string): string {\n try {\n return fs.readFileSync(filePath, 'utf-8');\n } catch {\n return '';\n }\n}\n\nfunction setTomlKey(content: string, key: string, value: string): string {\n const pattern = new RegExp(`^${key.replace('.', '\\\\.')}\\\\s*=.*$`, 'm');\n const line = `${key} = \"${value}\"`;\n if (pattern.test(content)) {\n return content.replace(pattern, line);\n }\n // Insert before the first [section] header so the key stays at the top level.\n // Appending to the end would place it inside whatever TOML section comes last.\n const sectionMatch = content.match(/^\\[/m);\n if (sectionMatch && sectionMatch.index !== undefined) {\n return content.slice(0, sectionMatch.index) + line + '\\n' + content.slice(sectionMatch.index);\n }\n const separator = content.length > 0 && !content.endsWith('\\n') ? '\\n' : '';\n return content + separator + line + '\\n';\n}\n\nfunction removeTomlKey(content: string, key: string): string {\n const pattern = new RegExp(`^${key.replace('.', '\\\\.')}\\\\s*=.*\\\\n?`, 'gm');\n return content.replace(pattern, '');\n}\n\nfunction buildCodexDirectProviderBlock(apiKey: string): string {\n // Matches docs/direct-mode-support-matrix.md — a minimal named provider\n // that points Codex at api.skalpel.ai with a static custom header.\n return [\n `[model_providers.${CODEX_DIRECT_PROVIDER_ID}]`,\n `name = \"Skalpel\"`,\n `base_url = \"${DIRECT_MODE_BASE_URL}\"`,\n `wire_api = \"responses\"`,\n `http_headers = { \"X-Skalpel-API-Key\" = \"${apiKey}\" }`,\n ].join('\\n');\n}\n\nfunction upsertCodexDirectProvider(content: string, apiKey: string): string {\n const sectionHeader = `[model_providers.${CODEX_DIRECT_PROVIDER_ID}]`;\n const block = buildCodexDirectProviderBlock(apiKey);\n const idx = content.indexOf(sectionHeader);\n if (idx === -1) {\n const separator = content.length > 0 && !content.endsWith('\\n') ? '\\n\\n' : (content.length > 0 ? '\\n' : '');\n return content + separator + block + '\\n';\n }\n // Replace from the section header up to (but not including) the next\n // [section] header — or to end-of-file.\n const after = content.slice(idx + sectionHeader.length);\n const nextHeaderMatch = after.match(/\\n\\[[^\\]]+\\]/);\n const end = nextHeaderMatch && nextHeaderMatch.index !== undefined\n ? idx + sectionHeader.length + nextHeaderMatch.index\n : content.length;\n return content.slice(0, idx) + block + content.slice(end);\n}\n\nfunction removeCodexDirectProvider(content: string): string {\n const sectionHeader = `[model_providers.${CODEX_DIRECT_PROVIDER_ID}]`;\n const idx = content.indexOf(sectionHeader);\n if (idx === -1) return content;\n const after = content.slice(idx + sectionHeader.length);\n const nextHeaderMatch = after.match(/\\n\\[[^\\]]+\\]/);\n const end = nextHeaderMatch && nextHeaderMatch.index !== undefined\n ? idx + sectionHeader.length + nextHeaderMatch.index\n : content.length;\n const before = content.slice(0, idx).replace(/\\n+$/, '');\n const rest = content.slice(end).replace(/^\\n+/, '');\n return (before.length > 0 && rest.length > 0)\n ? before + '\\n' + rest\n : before + rest;\n}\n\nfunction configureCodex(agent: DetectedAgent, proxyConfig: ProxyConfig, direct = false): void {\n const configDir = process.platform === 'win32'\n ? path.join(os.homedir(), 'AppData', 'Roaming', 'codex')\n : path.join(os.homedir(), '.codex');\n const configPath = agent.configPath ?? path.join(configDir, 'config.toml');\n\n ensureDir(path.dirname(configPath));\n createBackup(configPath);\n\n let content = readTomlFile(configPath);\n\n if (direct) {\n // Direct mode uses a named provider block so we can attach a static\n // X-Skalpel-API-Key header — plain openai_base_url cannot carry headers.\n content = removeTomlKey(content, 'openai_base_url');\n content = setTomlKey(content, 'model_provider', CODEX_DIRECT_PROVIDER_ID);\n content = upsertCodexDirectProvider(content, proxyConfig.apiKey);\n } else {\n // Proxy mode: single-line openai_base_url pointing at the local proxy;\n // tear down any direct-mode named provider left behind.\n content = setTomlKey(content, 'openai_base_url', `http://localhost:${proxyConfig.openaiPort}`);\n content = removeTomlKey(content, 'model_provider');\n content = removeCodexDirectProvider(content);\n }\n\n fs.writeFileSync(configPath, content);\n}\n\nfunction getCursorConfigDir(): string {\n if (process.platform === 'darwin') {\n return path.join(os.homedir(), 'Library', 'Application Support', 'Cursor', 'User');\n } else if (process.platform === 'win32') {\n return path.join(process.env.APPDATA ?? path.join(os.homedir(), 'AppData', 'Roaming'), 'Cursor', 'User');\n }\n return path.join(os.homedir(), '.config', 'Cursor', 'User');\n}\n\nfunction configureCursor(agent: DetectedAgent, proxyConfig: ProxyConfig, direct = false): void {\n if (direct) {\n // Cursor's settings.json exposes openai.apiBaseUrl but no custom-header\n // mechanism (see docs/direct-mode-support-matrix.md), so direct mode\n // cannot attach X-Skalpel-API-Key. Skip this agent with a warning — the\n // user keeps Cursor in proxy mode until Cursor ships header support.\n console.warn(` [!] cursor: direct mode not supported (no custom-header injection in Cursor settings). Cursor configuration left unchanged.`);\n return;\n }\n\n const configDir = getCursorConfigDir();\n const configPath = agent.configPath ?? path.join(configDir, 'settings.json');\n ensureDir(path.dirname(configPath));\n createBackup(configPath);\n\n const config = readJsonFile(configPath) ?? {};\n\n // Save the current API base URL as fallback before overriding\n const existingUrl = config[CURSOR_API_BASE_URL_KEY];\n if (typeof existingUrl === 'string' && existingUrl.length > 0) {\n proxyConfig.cursorDirectUrl = existingUrl;\n saveConfig(proxyConfig);\n }\n\n config[CURSOR_API_BASE_URL_KEY] = `http://localhost:${proxyConfig.cursorPort}`;\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\n}\n\nexport function configureAgent(agent: DetectedAgent, proxyConfig: ProxyConfig, direct = false): void {\n switch (agent.name) {\n case 'claude-code':\n configureClaudeCode(agent, proxyConfig, direct);\n break;\n case 'codex':\n configureCodex(agent, proxyConfig, direct);\n break;\n case 'cursor':\n configureCursor(agent, proxyConfig, direct);\n break;\n }\n}\n\nfunction unconfigureClaudeCode(agent: DetectedAgent): void {\n const configPath = agent.configPath ?? path.join(os.homedir(), '.claude', 'settings.json');\n\n // Always surgically remove only the ANTHROPIC_BASE_URL key.\n // Never restore from backup — the user may have changed other settings since install.\n if (!fs.existsSync(configPath)) return;\n\n const config = readJsonFile(configPath);\n if (config === null) {\n // Cannot parse settings.json — do NOT write to it.\n // Writing {} would wipe all Claude Code settings and break the installation.\n console.warn(` [!] Could not parse ${configPath} — skipping to avoid data loss. Remove ANTHROPIC_BASE_URL manually if needed.`);\n return;\n }\n\n if (config.env && typeof config.env === 'object') {\n const env = config.env as Record<string, unknown>;\n delete env.ANTHROPIC_BASE_URL;\n delete env.ANTHROPIC_CUSTOM_HEADERS;\n if (Object.keys(env).length === 0) {\n delete config.env;\n }\n }\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\n\n // Clean up stale backup file\n const backupPath = `${configPath}.skalpel-backup`;\n if (fs.existsSync(backupPath)) {\n fs.unlinkSync(backupPath);\n }\n}\n\nfunction unconfigureCodex(agent: DetectedAgent): void {\n const configDir = process.platform === 'win32'\n ? path.join(os.homedir(), 'AppData', 'Roaming', 'codex')\n : path.join(os.homedir(), '.codex');\n const configPath = agent.configPath ?? path.join(configDir, 'config.toml');\n\n // Always surgically remove only Skalpel-specific keys and the direct-mode\n // named provider block.\n if (fs.existsSync(configPath)) {\n let content = readTomlFile(configPath);\n content = removeTomlKey(content, 'openai_base_url');\n content = removeTomlKey(content, 'model_provider');\n content = removeCodexDirectProvider(content);\n fs.writeFileSync(configPath, content);\n }\n\n // Clean up stale backup file\n const backupPath = `${configPath}.skalpel-backup`;\n if (fs.existsSync(backupPath)) {\n fs.unlinkSync(backupPath);\n }\n}\n\nfunction unconfigureCursor(agent: DetectedAgent): void {\n const configDir = getCursorConfigDir();\n const configPath = agent.configPath ?? path.join(configDir, 'settings.json');\n\n if (!fs.existsSync(configPath)) return;\n\n const config = readJsonFile(configPath);\n if (config === null) {\n console.warn(` [!] Could not parse ${configPath} — skipping to avoid data loss. Remove ${CURSOR_API_BASE_URL_KEY} manually if needed.`);\n return;\n }\n\n delete config[CURSOR_API_BASE_URL_KEY];\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\n\n // Clean up stale backup file\n const backupPath = `${configPath}.skalpel-backup`;\n if (fs.existsSync(backupPath)) {\n fs.unlinkSync(backupPath);\n }\n}\n\nexport function unconfigureAgent(agent: DetectedAgent): void {\n switch (agent.name) {\n case 'claude-code':\n unconfigureClaudeCode(agent);\n break;\n case 'codex':\n unconfigureCodex(agent);\n break;\n case 'cursor':\n unconfigureCursor(agent);\n break;\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { execSync } from 'node:child_process';\nimport type { DetectedAgent } from './detect.js';\nimport type { ProxyConfig } from '../../proxy/types.js';\n\nconst BEGIN_MARKER = '# BEGIN SKALPEL PROXY - do not edit manually';\nconst END_MARKER = '# END SKALPEL PROXY';\n\nconst PS_BEGIN_MARKER = '# BEGIN SKALPEL PROXY - do not edit manually';\nconst PS_END_MARKER = '# END SKALPEL PROXY';\n\nfunction getUnixProfilePaths(): string[] {\n const home = os.homedir();\n const candidates = [\n path.join(home, '.bashrc'),\n path.join(home, '.zshrc'),\n path.join(home, '.bash_profile'),\n path.join(home, '.profile'),\n ];\n return candidates.filter((p) => fs.existsSync(p));\n}\n\nfunction getPowerShellProfilePath(): string | null {\n if (process.platform !== 'win32') return null;\n\n // Try $PROFILE env first\n if (process.env.PROFILE) return process.env.PROFILE;\n\n // Default PowerShell profile location\n const docsDir = path.join(os.homedir(), 'Documents');\n const psProfile = path.join(docsDir, 'PowerShell', 'Microsoft.PowerShell_profile.ps1');\n const wpProfile = path.join(docsDir, 'WindowsPowerShell', 'Microsoft.PowerShell_profile.ps1');\n\n if (fs.existsSync(psProfile)) return psProfile;\n if (fs.existsSync(wpProfile)) return wpProfile;\n\n // Return the modern PowerShell path as default (we'll create it)\n return psProfile;\n}\n\nfunction generateUnixBlock(proxyConfig: ProxyConfig): string {\n return [\n BEGIN_MARKER,\n `export ANTHROPIC_BASE_URL=\"http://localhost:${proxyConfig.anthropicPort}\"`,\n `export OPENAI_BASE_URL=\"http://localhost:${proxyConfig.openaiPort}\"`,\n END_MARKER,\n ].join('\\n');\n}\n\nfunction generatePowerShellBlock(proxyConfig: ProxyConfig): string {\n return [\n PS_BEGIN_MARKER,\n `$env:ANTHROPIC_BASE_URL = \"http://localhost:${proxyConfig.anthropicPort}\"`,\n `$env:OPENAI_BASE_URL = \"http://localhost:${proxyConfig.openaiPort}\"`,\n PS_END_MARKER,\n ].join('\\n');\n}\n\nfunction createBackup(filePath: string): void {\n const backupPath = `${filePath}.skalpel-backup`;\n fs.copyFileSync(filePath, backupPath);\n}\n\nfunction updateProfileFile(filePath: string, block: string, beginMarker: string, endMarker: string): void {\n if (fs.existsSync(filePath)) {\n createBackup(filePath);\n }\n\n let content = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8') : '';\n\n // Check if the block already exists\n const beginIdx = content.indexOf(beginMarker);\n const endIdx = content.indexOf(endMarker);\n\n if (beginIdx !== -1 && endIdx !== -1) {\n // Replace existing block\n content = content.slice(0, beginIdx) + block + content.slice(endIdx + endMarker.length);\n } else {\n // Append to end\n if (content.length > 0) {\n const trimmed = content.replace(/\\n+$/, '');\n content = trimmed + '\\n\\n' + block + '\\n';\n } else {\n content = block + '\\n';\n }\n }\n\n fs.writeFileSync(filePath, content);\n}\n\nexport function configureShellEnvVars(_agents: DetectedAgent[], proxyConfig: ProxyConfig): string[] {\n const modified: string[] = [];\n\n if (process.platform === 'win32') {\n const psProfile = getPowerShellProfilePath();\n if (psProfile) {\n const dir = path.dirname(psProfile);\n fs.mkdirSync(dir, { recursive: true });\n const block = generatePowerShellBlock(proxyConfig);\n updateProfileFile(psProfile, block, PS_BEGIN_MARKER, PS_END_MARKER);\n modified.push(psProfile);\n }\n } else {\n const profiles = getUnixProfilePaths();\n const block = generateUnixBlock(proxyConfig);\n for (const profilePath of profiles) {\n updateProfileFile(profilePath, block, BEGIN_MARKER, END_MARKER);\n modified.push(profilePath);\n }\n }\n\n return modified;\n}\n\nexport function removeShellEnvVars(): string[] {\n const restored: string[] = [];\n\n const home = os.homedir();\n const allProfiles = [\n path.join(home, '.bashrc'),\n path.join(home, '.zshrc'),\n path.join(home, '.bash_profile'),\n path.join(home, '.profile'),\n ];\n\n // Also check PowerShell profiles on Windows\n if (process.platform === 'win32') {\n const psProfile = getPowerShellProfilePath();\n if (psProfile) allProfiles.push(psProfile);\n }\n\n for (const profilePath of allProfiles) {\n if (!fs.existsSync(profilePath)) continue;\n\n const content = fs.readFileSync(profilePath, 'utf-8');\n const beginIdx = content.indexOf(BEGIN_MARKER);\n const endIdx = content.indexOf(END_MARKER);\n\n if (beginIdx === -1 || endIdx === -1) continue;\n\n // Always surgically remove the marker block.\n // Never restore from backup — the user may have edited the profile since install.\n const before = content.slice(0, beginIdx);\n const after = content.slice(endIdx + END_MARKER.length);\n // Clean up extra newlines\n const cleaned = (before.replace(/\\n+$/, '') + after.replace(/^\\n+/, '\\n')).trimEnd() + '\\n';\n fs.writeFileSync(profilePath, cleaned);\n\n // Clean up stale backup file\n const backupPath = `${profilePath}.skalpel-backup`;\n if (fs.existsSync(backupPath)) {\n fs.unlinkSync(backupPath);\n }\n\n restored.push(profilePath);\n }\n\n return restored;\n}\n\n/**\n * Write the BEGIN/END SKALPEL PROXY block to every detected shell profile.\n * Thin wrapper over configureShellEnvVars so the mode-switching code in\n * config-cmd.ts reads symmetrically (writeShellBlock / removeShellBlock).\n */\nexport function writeShellBlock(proxyConfig: ProxyConfig): string[] {\n return configureShellEnvVars([], proxyConfig);\n}\n\n/**\n * Remove the BEGIN/END SKALPEL PROXY block from every shell profile.\n * Thin wrapper over removeShellEnvVars with the naming used by the\n * mode-switching flow in config-cmd.ts.\n */\nexport function removeShellBlock(): string[] {\n return removeShellEnvVars();\n}\n\nexport function getConfiguredProfiles(): string[] {\n const configured: string[] = [];\n const home = os.homedir();\n const allProfiles = [\n path.join(home, '.bashrc'),\n path.join(home, '.zshrc'),\n path.join(home, '.bash_profile'),\n path.join(home, '.profile'),\n ];\n\n if (process.platform === 'win32') {\n const psProfile = getPowerShellProfilePath();\n if (psProfile) allProfiles.push(psProfile);\n }\n\n for (const profilePath of allProfiles) {\n if (!fs.existsSync(profilePath)) continue;\n const content = fs.readFileSync(profilePath, 'utf-8');\n if (content.includes(BEGIN_MARKER)) {\n configured.push(profilePath);\n }\n }\n\n return configured;\n}\n","import { loadConfig, saveConfig } from '../proxy/config.js';\nimport type { ProxyConfig, ProxyMode } from '../proxy/types.js';\nimport { detectAgents } from './agents/detect.js';\nimport { configureAgent } from './agents/configure.js';\nimport { writeShellBlock, removeShellBlock } from './agents/shell.js';\nimport { installService, uninstallService } from './service/install.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport async function runSetMode(mode: ProxyMode, config: ProxyConfig): Promise<void> {\n if (mode !== 'direct' && mode !== 'proxy') {\n print(` Invalid mode: ${mode as string}. Must be 'direct' or 'proxy'.`);\n process.exit(1);\n }\n\n // Idempotence guard — if on-disk mode already matches, skip the switching work.\n if (config.mode === mode) {\n print(` Already in ${mode} mode. Nothing to do.`);\n return;\n }\n\n config.mode = mode;\n saveConfig(config);\n\n // Apply the mode-switching routines. Agents (Phase 3) and\n // service/shell-block (Phase 4) are wired in the helpers below.\n await applyModeSwitch(mode, config);\n\n print(` Switched to ${mode} mode.`);\n}\n\nasync function applyModeSwitch(mode: ProxyMode, config: ProxyConfig): Promise<void> {\n const direct = mode === 'direct';\n const agents = detectAgents();\n for (const agent of agents) {\n if (!agent.installed) continue;\n configureAgent(agent, config, direct);\n }\n\n if (direct) {\n // Direct mode: agents talk to api.skalpel.ai straight, so the local\n // proxy service + shell env vars pointing at localhost are dead weight.\n uninstallService();\n removeShellBlock();\n } else {\n // Proxy mode: re-install the service and re-add the shell block so\n // every new terminal picks up ANTHROPIC_BASE_URL/OPENAI_BASE_URL for\n // the local proxy. Both are idempotent.\n installService(config);\n writeShellBlock(config);\n }\n}\n\nexport async function runConfig(subcommand?: string, args?: string[]): Promise<void> {\n const config = loadConfig();\n\n if (subcommand === 'path') {\n print(config.configFile);\n return;\n }\n\n if (subcommand === 'set') {\n if (!args || args.length < 2) {\n print(' Usage: skalpel config set <key> <value>');\n process.exit(1);\n }\n const key = args[0] as keyof ProxyConfig;\n const value = args[1];\n\n if (key === 'mode') {\n if (value !== 'direct' && value !== 'proxy') {\n print(` Invalid mode: ${value}. Must be 'direct' or 'proxy'.`);\n process.exit(1);\n }\n await runSetMode(value, config);\n return;\n }\n\n const validKeys: (keyof ProxyConfig)[] = [\n 'apiKey', 'remoteBaseUrl', 'anthropicPort', 'openaiPort',\n 'cursorPort', 'cursorDirectUrl', 'logLevel', 'logFile', 'pidFile',\n ];\n\n if (!validKeys.includes(key)) {\n print(` Unknown config key: ${key}`);\n print(` Valid keys: ${validKeys.join(', ')}`);\n process.exit(1);\n }\n\n const updated = { ...config };\n if (key === 'anthropicPort' || key === 'openaiPort' || key === 'cursorPort') {\n const parsed = parseInt(value, 10);\n if (isNaN(parsed) || parsed < 1 || parsed > 65535) {\n print(` Invalid port number: ${value}`);\n process.exit(1);\n }\n (updated as any)[key] = parsed;\n } else if (key === 'logLevel') {\n const validLevels = ['debug', 'info', 'warn', 'error'];\n if (!validLevels.includes(value)) {\n print(` Invalid log level: ${value}`);\n print(` Valid levels: ${validLevels.join(', ')}`);\n process.exit(1);\n }\n (updated as any)[key] = value;\n } else {\n (updated as any)[key] = value;\n }\n\n saveConfig(updated);\n print(` Set ${key} = ${value}`);\n return;\n }\n\n print(JSON.stringify(config, null, 2));\n}\n","import { exec } from 'node:child_process';\nimport { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\nconst pkg = require('../../package.json');\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport async function runUpdate(): Promise<void> {\n print(` Current version: ${pkg.version}`);\n print(' Checking for updates...');\n\n try {\n const latest = await new Promise<string>((resolve, reject) => {\n exec('npm view skalpel version', (err, stdout) => {\n if (err) reject(err);\n else resolve(stdout.trim());\n });\n });\n\n if (latest === pkg.version) {\n print(` Already on the latest version (${pkg.version}).`);\n return;\n }\n\n print(` Updating to ${latest}...`);\n\n await new Promise<void>((resolve, reject) => {\n exec('npm install -g skalpel@latest', (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n\n print(` Updated to ${latest}.`);\n } catch (err) {\n print(` Update failed: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n","import * as readline from 'node:readline';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { detectAgents } from './agents/detect.js';\nimport type { DetectedAgent } from './agents/detect.js';\nimport { configureAgent } from './agents/configure.js';\nimport { installService } from './service/install.js';\nimport { loadConfig, saveConfig } from '../proxy/config.js';\nimport { validateApiKey } from './utils.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\n\nexport async function runWizard(options?: { apiKey?: string; auto?: boolean; skipClaude?: boolean; skipCodex?: boolean; skipCursor?: boolean }): Promise<void> {\n const isAuto = options?.auto === true;\n\n let rl: readline.Interface | undefined;\n let ask: (question: string) => Promise<string>;\n\n if (!isAuto) {\n rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n ask = (question: string): Promise<string> => {\n return new Promise((resolve) => {\n rl!.question(question, (answer) => resolve(answer.trim()));\n });\n };\n } else {\n ask = () => Promise.resolve('');\n }\n\n try {\n // Step 1: Welcome\n print('');\n print(' _____ _ _ _ ');\n print(' / ____| | | | | |');\n print(' | (___ | | ____ _| |_ __ ___| |');\n print(' \\\\___ \\\\| |/ / _` | | \\'_ \\\\ / _ \\\\ |');\n print(' ____) | < (_| | | |_) | __/ |');\n print(' |_____/|_|\\\\_\\\\__,_|_| .__/ \\\\___|_|');\n print(' | | ');\n print(' |_| ');\n print('');\n print(' Welcome to Skalpel! Let\\'s optimize your coding agent costs.');\n print(' ─────────────────────────────────────────────────────────');\n print('');\n\n // Step 2: API Key\n const skalpelDir = path.join(os.homedir(), '.skalpel');\n const configPath = path.join(skalpelDir, 'config.json');\n let apiKey = '';\n\n if (isAuto && options?.apiKey) {\n apiKey = options.apiKey;\n if (!validateApiKey(apiKey)) {\n print(' Error: Invalid API key. Must start with \"sk-skalpel-\" and be at least 20 characters.');\n process.exit(1);\n }\n print(` API key set: ${apiKey.slice(0, 14)}${'*'.repeat(Math.max(0, apiKey.length - 14))}`);\n } else if (isAuto && !options?.apiKey) {\n print(' Error: --api-key is required when using --auto mode.');\n process.exit(1);\n } else {\n if (fs.existsSync(configPath)) {\n try {\n const existing = JSON.parse(fs.readFileSync(configPath, 'utf-8'));\n if (existing.apiKey && validateApiKey(existing.apiKey)) {\n const masked = existing.apiKey.slice(0, 14) + '*'.repeat(Math.max(0, existing.apiKey.length - 14));\n const useExisting = await ask(` Found existing API key: ${masked}\\n Use this key? (Y/n): `);\n if (useExisting.toLowerCase() !== 'n') {\n apiKey = existing.apiKey;\n print(` Using existing API key.`);\n }\n }\n } catch {\n // invalid config file, proceed to ask\n }\n }\n\n if (!apiKey) {\n apiKey = await ask(' Paste your Skalpel API key (sk-skalpel-...): ');\n if (!validateApiKey(apiKey)) {\n print(' Error: Invalid API key. Must start with \"sk-skalpel-\" and be at least 20 characters.');\n rl!.close();\n process.exit(1);\n }\n print(` API key set: ${apiKey.slice(0, 14)}${'*'.repeat(Math.max(0, apiKey.length - 14))}`);\n }\n }\n print('');\n\n // Save API key to config\n fs.mkdirSync(skalpelDir, { recursive: true });\n const proxyConfig = loadConfig(configPath);\n proxyConfig.apiKey = apiKey;\n saveConfig(proxyConfig);\n\n // Step 3: Agent Detection\n print(' Detecting coding agents...');\n const agents = detectAgents();\n const installedAgents = agents.filter((a) => a.installed);\n const notInstalled = agents.filter((a) => !a.installed);\n\n if (installedAgents.length > 0) {\n for (const agent of installedAgents) {\n const ver = agent.version ? ` v${agent.version}` : '';\n print(` [+] Found: ${agent.name}${ver}`);\n }\n }\n if (notInstalled.length > 0) {\n for (const agent of notInstalled) {\n print(` [ ] Not found: ${agent.name}`);\n }\n }\n if (installedAgents.length === 0) {\n print(' Warning: No coding agents detected. You can install them later.');\n print(' The proxy will be configured and ready when agents are installed.');\n }\n print('');\n\n // Filter out skipped agents\n let agentsToConfigure: DetectedAgent[] = installedAgents.filter((a) => {\n if (options?.skipClaude && a.name === 'claude-code') return false;\n if (options?.skipCodex && a.name === 'codex') return false;\n if (options?.skipCursor && a.name === 'cursor') return false;\n return true;\n });\n if (agentsToConfigure.length > 0 && !isAuto) {\n const agentNames = installedAgents.map((a) => a.name).join(', ');\n const confirm = await ask(` Configure ${agentNames}? (Y/n): `);\n if (confirm.toLowerCase() === 'n') {\n agentsToConfigure = [];\n }\n }\n print('');\n\n // Step 4: Configuration\n if (agentsToConfigure.length > 0) {\n print(' Configuring agents...');\n\n // Configure agent-specific config files (scoped to each agent's own config)\n for (const agent of agentsToConfigure) {\n configureAgent(agent, proxyConfig);\n print(` Configured ${agent.name}${agent.configPath ? ` (${agent.configPath})` : ''}`);\n }\n print('');\n }\n\n // Step 5: Service Installation\n print(' Installing proxy as system service...');\n try {\n installService(proxyConfig);\n print(' Service installed successfully.');\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n print(` Warning: Could not install service: ${msg}`);\n print(' You can start the proxy manually with: skalpel start');\n }\n print('');\n\n // Step 6: Verification\n print(' Verifying proxy...');\n let proxyOk = false;\n try {\n // Give the service a moment to start\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 3000);\n const healthUrl = `http://localhost:${proxyConfig.anthropicPort}/health`;\n const res = await fetch(healthUrl, { signal: controller.signal });\n clearTimeout(timeout);\n if (res.ok) {\n print(` [+] Anthropic proxy (port ${proxyConfig.anthropicPort}): healthy`);\n proxyOk = true;\n } else {\n print(` [!] Anthropic proxy (port ${proxyConfig.anthropicPort}): HTTP ${res.status}`);\n }\n } catch {\n print(` [!] Proxy not responding yet. It may take a moment to start.`);\n print(' Run \"npx skalpel status\" to check later, or \"npx skalpel start\" to start manually.');\n }\n\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 3000);\n const healthUrl = `http://localhost:${proxyConfig.openaiPort}/health`;\n const res = await fetch(healthUrl, { signal: controller.signal });\n clearTimeout(timeout);\n if (res.ok) {\n print(` [+] OpenAI proxy (port ${proxyConfig.openaiPort}): healthy`);\n } else {\n print(` [!] OpenAI proxy (port ${proxyConfig.openaiPort}): HTTP ${res.status}`);\n }\n } catch {\n // Already warned above\n }\n\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 3000);\n const healthUrl = `http://localhost:${proxyConfig.cursorPort}/health`;\n const res = await fetch(healthUrl, { signal: controller.signal });\n clearTimeout(timeout);\n if (res.ok) {\n print(` [+] Cursor proxy (port ${proxyConfig.cursorPort}): healthy`);\n } else {\n print(` [!] Cursor proxy (port ${proxyConfig.cursorPort}): HTTP ${res.status}`);\n }\n } catch {\n // Already warned above\n }\n print('');\n\n // Step 7: Success\n print(' ─────────────────────────────────────────────────────────');\n print('');\n print(' You\\'re all set! Your coding agents now route through Skalpel.');\n print('');\n if (agentsToConfigure.length > 0) {\n print(' Configured agents: ' + agentsToConfigure.map((a) => a.name).join(', '));\n }\n print(' Proxy ports: Anthropic=' + proxyConfig.anthropicPort + ', OpenAI=' + proxyConfig.openaiPort + ', Cursor=' + proxyConfig.cursorPort);\n print('');\n print(' Run \"npx skalpel status\" to check proxy status');\n print(' Run \"npx skalpel doctor\" for a full health check');\n print(' Run \"npx skalpel uninstall\" to remove everything');\n print('');\n\n if (rl) rl.close();\n } catch (err) {\n if (rl) rl.close();\n throw err;\n }\n}\n","import * as readline from 'node:readline';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { execSync } from 'node:child_process';\nimport { detectAgents } from './agents/detect.js';\nimport { removeShellEnvVars } from './agents/shell.js';\nimport { unconfigureAgent } from './agents/configure.js';\nimport { uninstallService } from './service/install.js';\nimport { loadConfig } from '../proxy/config.js';\nimport { stopProxy } from '../proxy/server.js';\n\nfunction print(msg: string): void {\n console.log(msg);\n}\n\nexport interface UninstallOptions {\n force?: boolean;\n}\n\nexport async function runUninstall(options?: UninstallOptions): Promise<void> {\n const force = options?.force ?? false;\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n function ask(question: string): Promise<string> {\n return new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n }\n\n try {\n print('');\n print(' Skalpel Uninstall');\n print(' ─────────────────');\n print('');\n\n if (!force) {\n const confirm = await ask(' This will remove Skalpel proxy, service, and agent configurations. Continue? (y/N): ');\n if (confirm.toLowerCase() !== 'y') {\n print(' Aborted.');\n rl.close();\n return;\n }\n print('');\n }\n\n const config = loadConfig();\n const removed: string[] = [];\n\n // Uninstall OS service FIRST — the service has KeepAlive=true (macOS) or\n // Restart=always (Linux), so if we kill the proxy process before removing\n // the service, the service manager will immediately respawn it, leaving an\n // orphaned proxy on port 18100.\n print(' Removing system service...');\n try {\n uninstallService();\n print(' [+] Service removed');\n removed.push('system service');\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n print(` [!] Could not remove service: ${msg}`);\n }\n\n // Now stop any remaining proxy process (safety net for non-service runs)\n print(' Stopping proxy...');\n const stopped = stopProxy(config);\n if (stopped) {\n print(' [+] Proxy stopped');\n removed.push('proxy process');\n } else {\n print(' [ ] Proxy was not running');\n }\n\n // Remove shell env vars\n print(' Removing shell environment variables...');\n const restoredProfiles = removeShellEnvVars();\n if (restoredProfiles.length > 0) {\n for (const p of restoredProfiles) {\n print(` [+] Restored: ${p}`);\n }\n removed.push('shell env vars');\n } else {\n print(' [ ] No shell profiles had Skalpel config');\n }\n\n // Unconfigure agents\n print(' Restoring agent configurations...');\n const agents = detectAgents();\n for (const agent of agents) {\n if (agent.installed) {\n try {\n unconfigureAgent(agent);\n print(` [+] Restored ${agent.name} config`);\n removed.push(`${agent.name} config`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n print(` [!] Could not restore ${agent.name}: ${msg}`);\n }\n }\n }\n print('');\n\n // Remove ~/.skalpel/ directory\n const skalpelDir = path.join(os.homedir(), '.skalpel');\n if (fs.existsSync(skalpelDir)) {\n let shouldRemove = force;\n if (!force) {\n const removeDir = await ask(' Remove ~/.skalpel/ directory (contains config and logs)? (y/N): ');\n shouldRemove = removeDir.toLowerCase() === 'y';\n }\n if (shouldRemove) {\n fs.rmSync(skalpelDir, { recursive: true, force: true });\n print(' [+] Removed ~/.skalpel/');\n removed.push('~/.skalpel/ directory');\n }\n }\n\n // Clear npx cache for skalpel\n print(' Clearing npx cache...');\n try {\n clearNpxCache();\n print(' [+] npx cache cleared');\n removed.push('npx cache');\n } catch {\n print(' [ ] Could not clear npx cache (not critical)');\n }\n\n print('');\n print(' ─────────────────');\n if (removed.length > 0) {\n print(' Removed: ' + removed.join(', '));\n } else {\n print(' Nothing to remove.');\n }\n print(' Skalpel has been uninstalled.');\n if (restoredProfiles.length > 0) {\n print(' Restart your shell to apply env var changes.');\n }\n print('');\n\n rl.close();\n } catch (err) {\n rl.close();\n throw err;\n }\n}\n\nfunction clearNpxCache(): void {\n // npm stores npx cache in ~/.npm/_npx/\n // Find and remove only the skalpel-related cache entries\n const npxCacheDir = path.join(os.homedir(), '.npm', '_npx');\n if (!fs.existsSync(npxCacheDir)) return;\n\n const entries = fs.readdirSync(npxCacheDir);\n for (const entry of entries) {\n const pkgJsonPath = path.join(npxCacheDir, entry, 'node_modules', 'skalpel', 'package.json');\n const pkgJsonAlt = path.join(npxCacheDir, entry, 'node_modules', '.package-lock.json');\n if (fs.existsSync(pkgJsonPath)) {\n fs.rmSync(path.join(npxCacheDir, entry), { recursive: true, force: true });\n continue;\n }\n // Check the lockfile for skalpel references\n if (fs.existsSync(pkgJsonAlt)) {\n try {\n const content = fs.readFileSync(pkgJsonAlt, 'utf-8');\n if (content.includes('\"skalpel\"')) {\n fs.rmSync(path.join(npxCacheDir, entry), { recursive: true, force: true });\n }\n } catch {\n // ignore read errors\n }\n }\n }\n}\n"],"mappings":"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","names":["createRequire","fs","path","pkg","resolve","fs","path","os","fs","path","print","print","fs","path","print","path","fileURLToPath","fs","path","os","fs","path","execSync","fs","execSync","fs","path","os","execSync","os","execSync","os","path","path","fs","execSync","os","print","path","fileURLToPath","fs","path","print","print","fs","print","fs","fs","path","os","fs","path","os","fs","path","os","createBackup","print","require","print","resolve","readline","fs","path","os","print","resolve","readline","fs","path","os","print","resolve","require","createRequire","pkg"]}
|