skalpel 2.0.7 → 2.0.8
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.map +1 -1
- package/dist/cli/proxy-runner.js +31 -3
- package/dist/cli/proxy-runner.js.map +1 -1
- package/dist/index.cjs +31 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +31 -3
- package/dist/index.js.map +1 -1
- package/dist/proxy/index.cjs +31 -3
- package/dist/proxy/index.cjs.map +1 -1
- package/dist/proxy/index.js +31 -3
- package/dist/proxy/index.js.map +1 -1
- package/package.json +1 -1
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/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/agents/configure.ts","../../src/cli/uninstall.ts","../../src/cli/agents/shell.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 { 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} and ${config.openaiPort}`);\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}\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 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;\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\n const anthropicServer = http.createServer((req, res) => {\n if (req.url === '/health' && req.method === 'GET') {\n handleHealthRequest(res, config, startTime);\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);\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 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 { 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(` 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 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 * 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","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"],"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","fs","fs","path","os","execSync","os","execSync","os","path","path","fs","execSync","os","print","path","fileURLToPath","fs","path","print","print","fs","print","fs","print","require","print","resolve","readline","fs","path","os","fs","path","os","print","resolve","readline","fs","path","os","fs","path","os","path","os","fs","os","path","fs","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/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/agents/configure.ts","../../src/cli/uninstall.ts","../../src/cli/agents/shell.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 { 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} and ${config.openaiPort}`);\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}\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 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;\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\n const anthropicServer = http.createServer((req, res) => {\n if (req.url === '/health' && req.method === 'GET') {\n handleHealthRequest(res, config, startTime);\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);\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// Status codes that only the Skalpel backend returns — Anthropic never\n// uses these, so receiving one means the Skalpel middleware rejected the\n// request and we should bypass it and go direct to Anthropic.\nconst SKALPEL_ONLY_STATUS_CODES = new Set([\n 402, // Payment Required — Skalpel billing gate\n 409, // Conflict — Skalpel duplicate-request lock\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 if (SKALPEL_ONLY_STATUS_CODES.has(response.status)) return true;\n // 429 from Skalpel may be its own rate limit (not Anthropic's).\n // Falling back is harmless: if Anthropic also rate-limits, Claude Code\n // sees Anthropic's properly-formatted 429 instead of Skalpel's.\n if (response.status === 429) 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 const errorPayload = {\n type: 'error',\n error: { type: 'proxy_error', message: errMsg },\n };\n res.write(`event: error\\ndata: ${JSON.stringify(errorPayload)}\\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 const noBodyError = {\n type: 'error',\n error: { type: 'proxy_error', message: 'no response body' },\n };\n res.write(`event: error\\ndata: ${JSON.stringify(noBodyError)}\\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 // Use Anthropic-compatible error event format so Claude Code's SDK\n // can parse it and handle the interrupted stream properly.\n const errorPayload = {\n type: 'error',\n error: { type: 'proxy_error', message: (err as Error).message },\n };\n res.write(`event: error\\ndata: ${JSON.stringify(errorPayload)}\\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 { 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(` 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 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 * 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","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"],"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","fs","fs","path","os","execSync","os","execSync","os","path","path","fs","execSync","os","print","path","fileURLToPath","fs","path","print","print","fs","print","fs","print","require","print","resolve","readline","fs","path","os","fs","path","os","print","resolve","readline","fs","path","os","fs","path","os","path","os","fs","os","path","fs","print","resolve","require","createRequire","pkg"]}
|