skalpel 1.0.6 → 1.1.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Skalpel AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/cli/index.js CHANGED
@@ -322,7 +322,7 @@ async function runBenchmark() {
322
322
  print3("");
323
323
  const apiKey = process.env.SKALPEL_API_KEY ?? "";
324
324
  if (!validateApiKey(apiKey)) {
325
- print3(' Error: SKALPEL_API_KEY not set or invalid. Run "skalpel doctor" to diagnose.');
325
+ print3(' Error: SKALPEL_API_KEY not set or invalid. Run "npx skalpel doctor" to diagnose.');
326
326
  print3("");
327
327
  process.exit(1);
328
328
  }
@@ -409,7 +409,7 @@ async function runReplay(filePaths) {
409
409
  }
410
410
  const apiKey = process.env.SKALPEL_API_KEY ?? "";
411
411
  if (!validateApiKey(apiKey)) {
412
- print4(' Error: SKALPEL_API_KEY not set or invalid. Run "skalpel doctor" to diagnose.');
412
+ print4(' Error: SKALPEL_API_KEY not set or invalid. Run "npx skalpel doctor" to diagnose.');
413
413
  print4("");
414
414
  process.exit(1);
415
415
  }
@@ -1127,9 +1127,9 @@ async function runUpdate() {
1127
1127
 
1128
1128
  // src/cli/wizard.ts
1129
1129
  import * as readline2 from "readline";
1130
- import * as fs13 from "fs";
1131
- import * as path14 from "path";
1132
- import * as os8 from "os";
1130
+ import * as fs12 from "fs";
1131
+ import * as path13 from "path";
1132
+ import * as os7 from "os";
1133
1133
  import { execSync as execSync4 } from "child_process";
1134
1134
 
1135
1135
  // src/cli/agents/detect.ts
@@ -1205,167 +1205,45 @@ function detectAgents() {
1205
1205
  return [detectClaudeCode(), detectCodex()];
1206
1206
  }
1207
1207
 
1208
- // src/cli/agents/shell.ts
1208
+ // src/cli/agents/configure.ts
1209
1209
  import fs11 from "fs";
1210
1210
  import path12 from "path";
1211
1211
  import os6 from "os";
1212
- var BEGIN_MARKER = "# BEGIN SKALPEL PROXY - do not edit manually";
1213
- var END_MARKER = "# END SKALPEL PROXY";
1214
- var PS_BEGIN_MARKER = "# BEGIN SKALPEL PROXY - do not edit manually";
1215
- var PS_END_MARKER = "# END SKALPEL PROXY";
1216
- function getUnixProfilePaths() {
1217
- const home = os6.homedir();
1218
- const candidates = [
1219
- path12.join(home, ".bashrc"),
1220
- path12.join(home, ".zshrc"),
1221
- path12.join(home, ".bash_profile"),
1222
- path12.join(home, ".profile")
1223
- ];
1224
- return candidates.filter((p) => fs11.existsSync(p));
1225
- }
1226
- function getPowerShellProfilePath() {
1227
- if (process.platform !== "win32") return null;
1228
- if (process.env.PROFILE) return process.env.PROFILE;
1229
- const docsDir = path12.join(os6.homedir(), "Documents");
1230
- const psProfile = path12.join(docsDir, "PowerShell", "Microsoft.PowerShell_profile.ps1");
1231
- const wpProfile = path12.join(docsDir, "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
1232
- if (fs11.existsSync(psProfile)) return psProfile;
1233
- if (fs11.existsSync(wpProfile)) return wpProfile;
1234
- return psProfile;
1235
- }
1236
- function generateUnixBlock(proxyConfig) {
1237
- return [
1238
- BEGIN_MARKER,
1239
- `export ANTHROPIC_BASE_URL="http://localhost:${proxyConfig.anthropicPort}"`,
1240
- `export OPENAI_BASE_URL="http://localhost:${proxyConfig.openaiPort}"`,
1241
- END_MARKER
1242
- ].join("\n");
1243
- }
1244
- function generatePowerShellBlock(proxyConfig) {
1245
- return [
1246
- PS_BEGIN_MARKER,
1247
- `$env:ANTHROPIC_BASE_URL = "http://localhost:${proxyConfig.anthropicPort}"`,
1248
- `$env:OPENAI_BASE_URL = "http://localhost:${proxyConfig.openaiPort}"`,
1249
- PS_END_MARKER
1250
- ].join("\n");
1212
+ function ensureDir(dir) {
1213
+ fs11.mkdirSync(dir, { recursive: true });
1251
1214
  }
1252
1215
  function createBackup(filePath) {
1253
- const backupPath = `${filePath}.skalpel-backup`;
1254
- fs11.copyFileSync(filePath, backupPath);
1255
- }
1256
- function updateProfileFile(filePath, block, beginMarker, endMarker) {
1257
1216
  if (fs11.existsSync(filePath)) {
1258
- createBackup(filePath);
1259
- }
1260
- let content = fs11.existsSync(filePath) ? fs11.readFileSync(filePath, "utf-8") : "";
1261
- const beginIdx = content.indexOf(beginMarker);
1262
- const endIdx = content.indexOf(endMarker);
1263
- if (beginIdx !== -1 && endIdx !== -1) {
1264
- content = content.slice(0, beginIdx) + block + content.slice(endIdx + endMarker.length);
1265
- } else {
1266
- if (content.length > 0) {
1267
- const trimmed = content.replace(/\n+$/, "");
1268
- content = trimmed + "\n\n" + block + "\n";
1269
- } else {
1270
- content = block + "\n";
1271
- }
1272
- }
1273
- fs11.writeFileSync(filePath, content);
1274
- }
1275
- function configureShellEnvVars(_agents, proxyConfig) {
1276
- const modified = [];
1277
- if (process.platform === "win32") {
1278
- const psProfile = getPowerShellProfilePath();
1279
- if (psProfile) {
1280
- const dir = path12.dirname(psProfile);
1281
- fs11.mkdirSync(dir, { recursive: true });
1282
- const block = generatePowerShellBlock(proxyConfig);
1283
- updateProfileFile(psProfile, block, PS_BEGIN_MARKER, PS_END_MARKER);
1284
- modified.push(psProfile);
1285
- }
1286
- } else {
1287
- const profiles = getUnixProfilePaths();
1288
- const block = generateUnixBlock(proxyConfig);
1289
- for (const profilePath of profiles) {
1290
- updateProfileFile(profilePath, block, BEGIN_MARKER, END_MARKER);
1291
- modified.push(profilePath);
1292
- }
1293
- }
1294
- return modified;
1295
- }
1296
- function removeShellEnvVars() {
1297
- const restored = [];
1298
- const home = os6.homedir();
1299
- const allProfiles = [
1300
- path12.join(home, ".bashrc"),
1301
- path12.join(home, ".zshrc"),
1302
- path12.join(home, ".bash_profile"),
1303
- path12.join(home, ".profile")
1304
- ];
1305
- if (process.platform === "win32") {
1306
- const psProfile = getPowerShellProfilePath();
1307
- if (psProfile) allProfiles.push(psProfile);
1308
- }
1309
- for (const profilePath of allProfiles) {
1310
- if (!fs11.existsSync(profilePath)) continue;
1311
- const content = fs11.readFileSync(profilePath, "utf-8");
1312
- const beginIdx = content.indexOf(BEGIN_MARKER);
1313
- const endIdx = content.indexOf(END_MARKER);
1314
- if (beginIdx === -1 || endIdx === -1) continue;
1315
- const backupPath = `${profilePath}.skalpel-backup`;
1316
- if (fs11.existsSync(backupPath)) {
1317
- fs11.copyFileSync(backupPath, profilePath);
1318
- fs11.unlinkSync(backupPath);
1319
- } else {
1320
- const before = content.slice(0, beginIdx);
1321
- const after = content.slice(endIdx + END_MARKER.length);
1322
- const cleaned = (before.replace(/\n+$/, "") + after.replace(/^\n+/, "\n")).trimEnd() + "\n";
1323
- fs11.writeFileSync(profilePath, cleaned);
1324
- }
1325
- restored.push(profilePath);
1326
- }
1327
- return restored;
1328
- }
1329
-
1330
- // src/cli/agents/configure.ts
1331
- import fs12 from "fs";
1332
- import path13 from "path";
1333
- import os7 from "os";
1334
- function ensureDir(dir) {
1335
- fs12.mkdirSync(dir, { recursive: true });
1336
- }
1337
- function createBackup2(filePath) {
1338
- if (fs12.existsSync(filePath)) {
1339
- fs12.copyFileSync(filePath, `${filePath}.skalpel-backup`);
1217
+ fs11.copyFileSync(filePath, `${filePath}.skalpel-backup`);
1340
1218
  }
1341
1219
  }
1342
1220
  function readJsonFile(filePath) {
1343
1221
  try {
1344
- return JSON.parse(fs12.readFileSync(filePath, "utf-8"));
1222
+ return JSON.parse(fs11.readFileSync(filePath, "utf-8"));
1345
1223
  } catch {
1346
1224
  return {};
1347
1225
  }
1348
1226
  }
1349
1227
  function configureClaudeCode(agent, proxyConfig) {
1350
- const configPath = agent.configPath ?? path13.join(os7.homedir(), ".claude", "settings.json");
1351
- const configDir = path13.dirname(configPath);
1228
+ const configPath = agent.configPath ?? path12.join(os6.homedir(), ".claude", "settings.json");
1229
+ const configDir = path12.dirname(configPath);
1352
1230
  ensureDir(configDir);
1353
- createBackup2(configPath);
1231
+ createBackup(configPath);
1354
1232
  const config = readJsonFile(configPath);
1355
1233
  if (!config.env || typeof config.env !== "object") {
1356
1234
  config.env = {};
1357
1235
  }
1358
1236
  config.env.ANTHROPIC_BASE_URL = `http://localhost:${proxyConfig.anthropicPort}`;
1359
- fs12.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
1237
+ fs11.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
1360
1238
  }
1361
1239
  function configureCodex(agent, proxyConfig) {
1362
- const configDir = process.platform === "win32" ? path13.join(os7.homedir(), "AppData", "Roaming", "codex") : path13.join(os7.homedir(), ".codex");
1363
- const configPath = agent.configPath ?? path13.join(configDir, "config.json");
1364
- ensureDir(path13.dirname(configPath));
1365
- createBackup2(configPath);
1240
+ const configDir = process.platform === "win32" ? path12.join(os6.homedir(), "AppData", "Roaming", "codex") : path12.join(os6.homedir(), ".codex");
1241
+ const configPath = agent.configPath ?? path12.join(configDir, "config.json");
1242
+ ensureDir(path12.dirname(configPath));
1243
+ createBackup(configPath);
1366
1244
  const config = readJsonFile(configPath);
1367
1245
  config.apiBaseUrl = `http://localhost:${proxyConfig.openaiPort}`;
1368
- fs12.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
1246
+ fs11.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
1369
1247
  }
1370
1248
  function configureAgent(agent, proxyConfig) {
1371
1249
  switch (agent.name) {
@@ -1378,14 +1256,14 @@ function configureAgent(agent, proxyConfig) {
1378
1256
  }
1379
1257
  }
1380
1258
  function unconfigureClaudeCode(agent) {
1381
- const configPath = agent.configPath ?? path13.join(os7.homedir(), ".claude", "settings.json");
1259
+ const configPath = agent.configPath ?? path12.join(os6.homedir(), ".claude", "settings.json");
1382
1260
  const backupPath = `${configPath}.skalpel-backup`;
1383
- if (fs12.existsSync(backupPath)) {
1384
- fs12.copyFileSync(backupPath, configPath);
1385
- fs12.unlinkSync(backupPath);
1261
+ if (fs11.existsSync(backupPath)) {
1262
+ fs11.copyFileSync(backupPath, configPath);
1263
+ fs11.unlinkSync(backupPath);
1386
1264
  return;
1387
1265
  }
1388
- if (!fs12.existsSync(configPath)) return;
1266
+ if (!fs11.existsSync(configPath)) return;
1389
1267
  const config = readJsonFile(configPath);
1390
1268
  if (config.env && typeof config.env === "object") {
1391
1269
  delete config.env.ANTHROPIC_BASE_URL;
@@ -1393,21 +1271,21 @@ function unconfigureClaudeCode(agent) {
1393
1271
  delete config.env;
1394
1272
  }
1395
1273
  }
1396
- fs12.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
1274
+ fs11.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
1397
1275
  }
1398
1276
  function unconfigureCodex(agent) {
1399
- const configDir = process.platform === "win32" ? path13.join(os7.homedir(), "AppData", "Roaming", "codex") : path13.join(os7.homedir(), ".codex");
1400
- const configPath = agent.configPath ?? path13.join(configDir, "config.json");
1277
+ const configDir = process.platform === "win32" ? path12.join(os6.homedir(), "AppData", "Roaming", "codex") : path12.join(os6.homedir(), ".codex");
1278
+ const configPath = agent.configPath ?? path12.join(configDir, "config.json");
1401
1279
  const backupPath = `${configPath}.skalpel-backup`;
1402
- if (fs12.existsSync(backupPath)) {
1403
- fs12.copyFileSync(backupPath, configPath);
1404
- fs12.unlinkSync(backupPath);
1280
+ if (fs11.existsSync(backupPath)) {
1281
+ fs11.copyFileSync(backupPath, configPath);
1282
+ fs11.unlinkSync(backupPath);
1405
1283
  return;
1406
1284
  }
1407
- if (!fs12.existsSync(configPath)) return;
1285
+ if (!fs11.existsSync(configPath)) return;
1408
1286
  const config = readJsonFile(configPath);
1409
1287
  delete config.apiBaseUrl;
1410
- fs12.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
1288
+ fs11.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
1411
1289
  }
1412
1290
  function unconfigureAgent(agent) {
1413
1291
  switch (agent.name) {
@@ -1472,8 +1350,8 @@ async function runWizard(options) {
1472
1350
  print11(" Welcome to Skalpel! Let's optimize your coding agent costs.");
1473
1351
  print11(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
1474
1352
  print11("");
1475
- const skalpelDir = path14.join(os8.homedir(), ".skalpel");
1476
- const configPath = path14.join(skalpelDir, "config.json");
1353
+ const skalpelDir = path13.join(os7.homedir(), ".skalpel");
1354
+ const configPath = path13.join(skalpelDir, "config.json");
1477
1355
  let apiKey = "";
1478
1356
  if (isAuto && options?.apiKey) {
1479
1357
  apiKey = options.apiKey;
@@ -1486,9 +1364,9 @@ async function runWizard(options) {
1486
1364
  print11(" Error: --api-key is required when using --auto mode.");
1487
1365
  process.exit(1);
1488
1366
  } else {
1489
- if (fs13.existsSync(configPath)) {
1367
+ if (fs12.existsSync(configPath)) {
1490
1368
  try {
1491
- const existing = JSON.parse(fs13.readFileSync(configPath, "utf-8"));
1369
+ const existing = JSON.parse(fs12.readFileSync(configPath, "utf-8"));
1492
1370
  if (existing.apiKey && validateApiKey(existing.apiKey)) {
1493
1371
  const masked = existing.apiKey.slice(0, 14) + "*".repeat(Math.max(0, existing.apiKey.length - 14));
1494
1372
  const useExisting = await ask(` Found existing API key: ${masked}
@@ -1515,7 +1393,7 @@ async function runWizard(options) {
1515
1393
  }
1516
1394
  }
1517
1395
  print11("");
1518
- fs13.mkdirSync(skalpelDir, { recursive: true });
1396
+ fs12.mkdirSync(skalpelDir, { recursive: true });
1519
1397
  const proxyConfig = loadConfig(configPath);
1520
1398
  proxyConfig.apiKey = apiKey;
1521
1399
  saveConfig(proxyConfig);
@@ -1550,13 +1428,6 @@ async function runWizard(options) {
1550
1428
  print11("");
1551
1429
  if (agentsToConfigure.length > 0) {
1552
1430
  print11(" Configuring agents...");
1553
- const modifiedProfiles = configureShellEnvVars(agentsToConfigure, proxyConfig);
1554
- if (modifiedProfiles.length > 0) {
1555
- print11(" Shell profiles updated:");
1556
- for (const p of modifiedProfiles) {
1557
- print11(` - ${p}`);
1558
- }
1559
- }
1560
1431
  for (const agent of agentsToConfigure) {
1561
1432
  configureAgent(agent, proxyConfig);
1562
1433
  print11(` Configured ${agent.name}${agent.configPath ? ` (${agent.configPath})` : ""}`);
@@ -1588,8 +1459,8 @@ async function runWizard(options) {
1588
1459
  print11(` [!] Anthropic proxy (port ${proxyConfig.anthropicPort}): HTTP ${res.status}`);
1589
1460
  }
1590
1461
  } catch {
1591
- print11(` [!] Proxy not responding yet. It may need a shell restart to pick up env vars.`);
1592
- print11(' Run "skalpel status" to check later, or "skalpel start" to start manually.');
1462
+ print11(` [!] Proxy not responding yet. It may take a moment to start.`);
1463
+ print11(' Run "npx skalpel status" to check later, or "npx skalpel start" to start manually.');
1593
1464
  }
1594
1465
  try {
1595
1466
  const controller = new AbortController();
@@ -1614,9 +1485,9 @@ async function runWizard(options) {
1614
1485
  }
1615
1486
  print11(" Proxy ports: Anthropic=" + proxyConfig.anthropicPort + ", OpenAI=" + proxyConfig.openaiPort);
1616
1487
  print11("");
1617
- print11(' Run "skalpel status" to check proxy status');
1618
- print11(' Run "skalpel doctor" for a full health check');
1619
- print11(' Run "skalpel uninstall" to remove everything');
1488
+ print11(' Run "npx skalpel status" to check proxy status');
1489
+ print11(' Run "npx skalpel doctor" for a full health check');
1490
+ print11(' Run "npx skalpel uninstall" to remove everything');
1620
1491
  print11("");
1621
1492
  if (rl) rl.close();
1622
1493
  } catch (err) {
@@ -1630,6 +1501,58 @@ import * as readline3 from "readline";
1630
1501
  import * as fs14 from "fs";
1631
1502
  import * as path15 from "path";
1632
1503
  import * as os9 from "os";
1504
+
1505
+ // src/cli/agents/shell.ts
1506
+ import fs13 from "fs";
1507
+ import path14 from "path";
1508
+ import os8 from "os";
1509
+ var BEGIN_MARKER = "# BEGIN SKALPEL PROXY - do not edit manually";
1510
+ var END_MARKER = "# END SKALPEL PROXY";
1511
+ function getPowerShellProfilePath() {
1512
+ if (process.platform !== "win32") return null;
1513
+ if (process.env.PROFILE) return process.env.PROFILE;
1514
+ const docsDir = path14.join(os8.homedir(), "Documents");
1515
+ const psProfile = path14.join(docsDir, "PowerShell", "Microsoft.PowerShell_profile.ps1");
1516
+ const wpProfile = path14.join(docsDir, "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
1517
+ if (fs13.existsSync(psProfile)) return psProfile;
1518
+ if (fs13.existsSync(wpProfile)) return wpProfile;
1519
+ return psProfile;
1520
+ }
1521
+ function removeShellEnvVars() {
1522
+ const restored = [];
1523
+ const home = os8.homedir();
1524
+ const allProfiles = [
1525
+ path14.join(home, ".bashrc"),
1526
+ path14.join(home, ".zshrc"),
1527
+ path14.join(home, ".bash_profile"),
1528
+ path14.join(home, ".profile")
1529
+ ];
1530
+ if (process.platform === "win32") {
1531
+ const psProfile = getPowerShellProfilePath();
1532
+ if (psProfile) allProfiles.push(psProfile);
1533
+ }
1534
+ for (const profilePath of allProfiles) {
1535
+ if (!fs13.existsSync(profilePath)) continue;
1536
+ const content = fs13.readFileSync(profilePath, "utf-8");
1537
+ const beginIdx = content.indexOf(BEGIN_MARKER);
1538
+ const endIdx = content.indexOf(END_MARKER);
1539
+ if (beginIdx === -1 || endIdx === -1) continue;
1540
+ const backupPath = `${profilePath}.skalpel-backup`;
1541
+ if (fs13.existsSync(backupPath)) {
1542
+ fs13.copyFileSync(backupPath, profilePath);
1543
+ fs13.unlinkSync(backupPath);
1544
+ } else {
1545
+ const before = content.slice(0, beginIdx);
1546
+ const after = content.slice(endIdx + END_MARKER.length);
1547
+ const cleaned = (before.replace(/\n+$/, "") + after.replace(/^\n+/, "\n")).trimEnd() + "\n";
1548
+ fs13.writeFileSync(profilePath, cleaned);
1549
+ }
1550
+ restored.push(profilePath);
1551
+ }
1552
+ return restored;
1553
+ }
1554
+
1555
+ // src/cli/uninstall.ts
1633
1556
  function print12(msg) {
1634
1557
  console.log(msg);
1635
1558
  }
@@ -1715,7 +1638,10 @@ async function runUninstall() {
1715
1638
  } else {
1716
1639
  print12(" Nothing to remove.");
1717
1640
  }
1718
- print12(" Skalpel has been uninstalled. Restart your shell to apply env var changes.");
1641
+ print12(" Skalpel has been uninstalled.");
1642
+ if (restoredProfiles.length > 0) {
1643
+ print12(" Restart your shell to apply env var changes.");
1644
+ }
1719
1645
  print12("");
1720
1646
  rl.close();
1721
1647
  } catch (err) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/index.ts","../../src/cli/init.ts","../../src/cli/utils.ts","../../src/cli/doctor.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/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/detect.ts","../../src/cli/agents/shell.ts","../../src/cli/agents/configure.ts","../../src/cli/uninstall.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createRequire } from 'node:module';\nimport { runInit } from './init.js';\nimport { runDoctor } from './doctor.js';\nimport { runBenchmark } from './benchmark.js';\nimport { runReplay } from './replay.js';\nimport { runStart } from './start.js';\nimport { runStop } from './stop.js';\nimport { runStatus } from './status.js';\nimport { runLogs } from './logs.js';\nimport { runConfig } from './config-cmd.js';\nimport { runUpdate } from './update.js';\nimport { runWizard } from './wizard.js';\nimport { runUninstall } from './uninstall.js';\n\nconst require = createRequire(import.meta.url);\nconst pkg = require('../../package.json');\n\nconst program = new Command();\n\nprogram\n .name('skalpel')\n .description('Skalpel AI CLI — optimize your OpenAI and Anthropic API calls')\n .version(pkg.version)\n .option('--api-key <key>', 'Skalpel API key for non-interactive setup')\n .option('--auto', 'Run setup in non-interactive mode')\n .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 .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 { validateApiKey } from './utils.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\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\n const apiKey = process.env.SKALPEL_API_KEY ?? '';\n if (!apiKey) {\n checks.push({\n name: 'API Key',\n status: 'fail',\n message: 'SKALPEL_API_KEY not set in environment',\n });\n } else if (!validateApiKey(apiKey)) {\n checks.push({\n name: 'API Key',\n status: 'fail',\n message: `Invalid format — must start with \"sk-skalpel-\" and be >= 20 chars (got \"${apiKey.slice(0, 10)}...\")`,\n });\n } else {\n checks.push({\n name: 'API Key',\n status: 'ok',\n message: `Valid key: ${apiKey.slice(0, 14)}${'*'.repeat(Math.max(0, apiKey.length - 14))}`,\n });\n }\n\n // 2. Check .env file\n const envPath = path.join(process.cwd(), '.env');\n if (fs.existsSync(envPath)) {\n const content = fs.readFileSync(envPath, 'utf-8');\n if (content.includes('SKALPEL_API_KEY')) {\n checks.push({ name: '.env file', status: 'ok', message: 'Found SKALPEL_API_KEY in .env' });\n } else {\n checks.push({ name: '.env file', status: 'warn', message: '.env exists but no SKALPEL_API_KEY entry' });\n }\n } else {\n checks.push({ name: '.env file', status: 'warn', message: 'No .env file found in current directory' });\n }\n\n // 3. Check proxy endpoint reachability\n const baseURL = process.env.SKALPEL_BASE_URL ?? '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: 'Proxy endpoint', status: 'ok', message: `${baseURL} reachable (HTTP ${response.status})` });\n } else {\n checks.push({ name: 'Proxy endpoint', 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: 'Proxy endpoint', status: 'fail', message: `Cannot reach ${baseURL} — ${msg}` });\n }\n\n // 4. Check workspace config\n const skalpelDir = path.join(process.cwd(), '.skalpel');\n if (fs.existsSync(path.join(skalpelDir, 'config.json'))) {\n checks.push({ name: 'Workspace config', status: 'ok', message: '.skalpel/config.json found' });\n } else {\n checks.push({ name: 'Workspace config', status: 'warn', message: 'No .skalpel/config.json — run \"skalpel init\" first' });\n }\n\n // 5. Check project type\n const hasPackageJson = fs.existsSync(path.join(process.cwd(), 'package.json'));\n const hasPyProject = fs.existsSync(path.join(process.cwd(), 'pyproject.toml'));\n const hasRequirements = fs.existsSync(path.join(process.cwd(), 'requirements.txt'));\n if (hasPackageJson || hasPyProject || hasRequirements) {\n const types: string[] = [];\n if (hasPackageJson) types.push('Node.js');\n if (hasPyProject || hasRequirements) types.push('Python');\n checks.push({ name: 'Project detected', status: 'ok', message: types.join(', ') });\n } else {\n checks.push({ name: 'Project detected', status: 'warn', message: 'No package.json or Python config found' });\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 { 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 \"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 \"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 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 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 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 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 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 { execSync } from 'node:child_process';\nimport { detectAgents } from './agents/detect.js';\nimport type { DetectedAgent } from './agents/detect.js';\nimport { configureShellEnvVars } from './agents/shell.js';\nimport { configureAgent } from './agents/configure.js';\nimport { installService } from './service/install.js';\nimport { detectOS } from './service/detect-os.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\nfunction openUrl(url: string): void {\n const osInfo = detectOS();\n try {\n switch (osInfo.platform) {\n case 'macos':\n execSync(`open \"${url}\"`, { stdio: 'pipe' });\n break;\n case 'linux':\n execSync(`xdg-open \"${url}\"`, { stdio: 'pipe' });\n break;\n case 'windows':\n execSync(`start \"\" \"${url}\"`, { stdio: 'pipe' });\n break;\n }\n } catch {\n // Browser open failed — user will paste the URL manually\n }\n}\n\nexport async function runWizard(options?: { apiKey?: string; auto?: 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 print(' Opening Skalpel signup page...');\n openUrl('https://app.skalpel.ai/signup');\n print('');\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 // Ask which agents to configure\n let agentsToConfigure: DetectedAgent[] = installedAgents;\n if (installedAgents.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 shell env vars\n const modifiedProfiles = configureShellEnvVars(agentsToConfigure, proxyConfig);\n if (modifiedProfiles.length > 0) {\n print(' Shell profiles updated:');\n for (const p of modifiedProfiles) {\n print(` - ${p}`);\n }\n }\n\n // Configure agent-specific config files\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 need a shell restart to pick up env vars.`);\n print(' Run \"skalpel status\" to check later, or \"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 \"skalpel status\" to check proxy status');\n print(' Run \"skalpel doctor\" for a full health check');\n print(' Run \"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 { 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 config file\n const configFile = path.join(codexConfigDir, 'config.json');\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 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 // Try to restore from backup first\n const backupPath = `${profilePath}.skalpel-backup`;\n if (fs.existsSync(backupPath)) {\n fs.copyFileSync(backupPath, profilePath);\n fs.unlinkSync(backupPath);\n } else {\n // Remove the marker block manually\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\n restored.push(profilePath);\n }\n\n return restored;\n}\n\nexport function getConfiguredProfiles(): string[] {\n const configured: string[] = [];\n const home = os.homedir();\n const allProfiles = [\n path.join(home, '.bashrc'),\n path.join(home, '.zshrc'),\n path.join(home, '.bash_profile'),\n path.join(home, '.profile'),\n ];\n\n if (process.platform === 'win32') {\n const psProfile = getPowerShellProfilePath();\n if (psProfile) allProfiles.push(psProfile);\n }\n\n for (const profilePath of allProfiles) {\n if (!fs.existsSync(profilePath)) continue;\n const content = fs.readFileSync(profilePath, 'utf-8');\n if (content.includes(BEGIN_MARKER)) {\n configured.push(profilePath);\n }\n }\n\n return configured;\n}\n","import 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\nfunction readJsonFile(filePath: string): Record<string, unknown> {\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n } catch {\n return {};\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\n createBackup(configPath);\n\n const config = readJsonFile(configPath);\n\n // Claude Code uses env.ANTHROPIC_BASE_URL in settings to override the API endpoint\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 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.json');\n\n ensureDir(path.dirname(configPath));\n createBackup(configPath);\n\n const config = readJsonFile(configPath);\n\n // Codex uses OPENAI_BASE_URL for API routing\n config.apiBaseUrl = `http://localhost:${proxyConfig.openaiPort}`;\n\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\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 const backupPath = `${configPath}.skalpel-backup`;\n\n if (fs.existsSync(backupPath)) {\n fs.copyFileSync(backupPath, configPath);\n fs.unlinkSync(backupPath);\n return;\n }\n\n // No backup — remove Skalpel-specific entries\n if (!fs.existsSync(configPath)) return;\n const config = readJsonFile(configPath);\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\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.json');\n const backupPath = `${configPath}.skalpel-backup`;\n\n if (fs.existsSync(backupPath)) {\n fs.copyFileSync(backupPath, configPath);\n fs.unlinkSync(backupPath);\n return;\n }\n\n if (!fs.existsSync(configPath)) return;\n const config = readJsonFile(configPath);\n delete config.apiBaseUrl;\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\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 { 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 async function runUninstall(): 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 Uninstall');\n print(' ─────────────────');\n print('');\n\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 const config = loadConfig();\n const removed: string[] = [];\n\n // Stop the proxy if running\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 // Uninstall OS service\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 // 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 // Ask about removing ~/.skalpel/\n const skalpelDir = path.join(os.homedir(), '.skalpel');\n if (fs.existsSync(skalpelDir)) {\n const removeDir = await ask(' Remove ~/.skalpel/ directory (contains config and logs)? (y/N): ');\n if (removeDir.toLowerCase() === 'y') {\n fs.rmSync(skalpelDir, { recursive: true, force: true });\n print(' [+] Removed ~/.skalpel/');\n removed.push('~/.skalpel/ directory');\n }\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. Restart your shell to apply env var changes.');\n print('');\n\n rl.close();\n } catch (err) {\n rl.close();\n throw err;\n }\n}\n"],"mappings":"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","names":["createRequire","fs","path","pkg","resolve","fs","path","print","print","fs","path","print","path","fileURLToPath","fs","path","fs","path","fs","fs","path","os","execSync","os","os","path","path","fs","execSync","os","print","path","fileURLToPath","fs","path","print","print","fs","print","fs","print","require","print","resolve","readline","fs","path","os","execSync","execSync","fs","path","os","fs","path","os","fs","path","os","createBackup","print","execSync","resolve","readline","fs","path","os","print","resolve","require","createRequire","pkg"]}
1
+ {"version":3,"sources":["../../src/cli/index.ts","../../src/cli/init.ts","../../src/cli/utils.ts","../../src/cli/doctor.ts","../../src/cli/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/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/detect.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 .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 .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 { validateApiKey } from './utils.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\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\n const apiKey = process.env.SKALPEL_API_KEY ?? '';\n if (!apiKey) {\n checks.push({\n name: 'API Key',\n status: 'fail',\n message: 'SKALPEL_API_KEY not set in environment',\n });\n } else if (!validateApiKey(apiKey)) {\n checks.push({\n name: 'API Key',\n status: 'fail',\n message: `Invalid format — must start with \"sk-skalpel-\" and be >= 20 chars (got \"${apiKey.slice(0, 10)}...\")`,\n });\n } else {\n checks.push({\n name: 'API Key',\n status: 'ok',\n message: `Valid key: ${apiKey.slice(0, 14)}${'*'.repeat(Math.max(0, apiKey.length - 14))}`,\n });\n }\n\n // 2. Check .env file\n const envPath = path.join(process.cwd(), '.env');\n if (fs.existsSync(envPath)) {\n const content = fs.readFileSync(envPath, 'utf-8');\n if (content.includes('SKALPEL_API_KEY')) {\n checks.push({ name: '.env file', status: 'ok', message: 'Found SKALPEL_API_KEY in .env' });\n } else {\n checks.push({ name: '.env file', status: 'warn', message: '.env exists but no SKALPEL_API_KEY entry' });\n }\n } else {\n checks.push({ name: '.env file', status: 'warn', message: 'No .env file found in current directory' });\n }\n\n // 3. Check proxy endpoint reachability\n const baseURL = process.env.SKALPEL_BASE_URL ?? '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: 'Proxy endpoint', status: 'ok', message: `${baseURL} reachable (HTTP ${response.status})` });\n } else {\n checks.push({ name: 'Proxy endpoint', 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: 'Proxy endpoint', status: 'fail', message: `Cannot reach ${baseURL} — ${msg}` });\n }\n\n // 4. Check workspace config\n const skalpelDir = path.join(process.cwd(), '.skalpel');\n if (fs.existsSync(path.join(skalpelDir, 'config.json'))) {\n checks.push({ name: 'Workspace config', status: 'ok', message: '.skalpel/config.json found' });\n } else {\n checks.push({ name: 'Workspace config', status: 'warn', message: 'No .skalpel/config.json — run \"skalpel init\" first' });\n }\n\n // 5. Check project type\n const hasPackageJson = fs.existsSync(path.join(process.cwd(), 'package.json'));\n const hasPyProject = fs.existsSync(path.join(process.cwd(), 'pyproject.toml'));\n const hasRequirements = fs.existsSync(path.join(process.cwd(), 'requirements.txt'));\n if (hasPackageJson || hasPyProject || hasRequirements) {\n const types: string[] = [];\n if (hasPackageJson) types.push('Node.js');\n if (hasPyProject || hasRequirements) types.push('Python');\n checks.push({ name: 'Project detected', status: 'ok', message: types.join(', ') });\n } else {\n checks.push({ name: 'Project detected', status: 'warn', message: 'No package.json or Python config found' });\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 { 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 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 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 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 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 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 { execSync } from 'node:child_process';\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 { detectOS } from './service/detect-os.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\nfunction openUrl(url: string): void {\n const osInfo = detectOS();\n try {\n switch (osInfo.platform) {\n case 'macos':\n execSync(`open \"${url}\"`, { stdio: 'pipe' });\n break;\n case 'linux':\n execSync(`xdg-open \"${url}\"`, { stdio: 'pipe' });\n break;\n case 'windows':\n execSync(`start \"\" \"${url}\"`, { stdio: 'pipe' });\n break;\n }\n } catch {\n // Browser open failed — user will paste the URL manually\n }\n}\n\nexport async function runWizard(options?: { apiKey?: string; auto?: 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 print(' Opening Skalpel signup page...');\n openUrl('https://app.skalpel.ai/signup');\n print('');\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 // Ask which agents to configure\n let agentsToConfigure: DetectedAgent[] = installedAgents;\n if (installedAgents.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 { 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 config file\n const configFile = path.join(codexConfigDir, 'config.json');\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 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\nfunction readJsonFile(filePath: string): Record<string, unknown> {\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n } catch {\n return {};\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\n createBackup(configPath);\n\n const config = readJsonFile(configPath);\n\n // Claude Code uses env.ANTHROPIC_BASE_URL in settings to override the API endpoint\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 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.json');\n\n ensureDir(path.dirname(configPath));\n createBackup(configPath);\n\n const config = readJsonFile(configPath);\n\n // Codex uses OPENAI_BASE_URL for API routing\n config.apiBaseUrl = `http://localhost:${proxyConfig.openaiPort}`;\n\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\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 const backupPath = `${configPath}.skalpel-backup`;\n\n if (fs.existsSync(backupPath)) {\n fs.copyFileSync(backupPath, configPath);\n fs.unlinkSync(backupPath);\n return;\n }\n\n // No backup — remove Skalpel-specific entries\n if (!fs.existsSync(configPath)) return;\n const config = readJsonFile(configPath);\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\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.json');\n const backupPath = `${configPath}.skalpel-backup`;\n\n if (fs.existsSync(backupPath)) {\n fs.copyFileSync(backupPath, configPath);\n fs.unlinkSync(backupPath);\n return;\n }\n\n if (!fs.existsSync(configPath)) return;\n const config = readJsonFile(configPath);\n delete config.apiBaseUrl;\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\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 { 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 async function runUninstall(): 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 Uninstall');\n print(' ─────────────────');\n print('');\n\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 const config = loadConfig();\n const removed: string[] = [];\n\n // Stop the proxy if running\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 // Uninstall OS service\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 // 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 // Ask about removing ~/.skalpel/\n const skalpelDir = path.join(os.homedir(), '.skalpel');\n if (fs.existsSync(skalpelDir)) {\n const removeDir = await ask(' Remove ~/.skalpel/ directory (contains config and logs)? (y/N): ');\n if (removeDir.toLowerCase() === 'y') {\n fs.rmSync(skalpelDir, { recursive: true, force: true });\n print(' [+] Removed ~/.skalpel/');\n removed.push('~/.skalpel/ directory');\n }\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","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 // Try to restore from backup first\n const backupPath = `${profilePath}.skalpel-backup`;\n if (fs.existsSync(backupPath)) {\n fs.copyFileSync(backupPath, profilePath);\n fs.unlinkSync(backupPath);\n } else {\n // Remove the marker block manually\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\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","print","print","fs","path","print","path","fileURLToPath","fs","path","fs","path","fs","fs","path","os","execSync","os","os","path","path","fs","execSync","os","print","path","fileURLToPath","fs","path","print","print","fs","print","fs","print","require","print","resolve","readline","fs","path","os","execSync","execSync","fs","path","os","fs","path","os","print","execSync","resolve","readline","fs","path","os","fs","path","os","path","os","fs","os","path","fs","print","resolve","require","createRequire","pkg"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skalpel",
3
- "version": "1.0.6",
3
+ "version": "1.1.2",
4
4
  "type": "module",
5
5
  "description": "Skalpel AI SDK — optimize your OpenAI and Anthropic API calls",
6
6
  "main": "./dist/index.cjs",
@@ -17,7 +17,9 @@
17
17
  "skalpel": "./dist/cli/index.js"
18
18
  },
19
19
  "files": [
20
- "dist"
20
+ "dist",
21
+ "README.md",
22
+ "LICENSE"
21
23
  ],
22
24
  "scripts": {
23
25
  "build": "tsup",
@@ -48,6 +50,25 @@
48
50
  "typescript": "^5.4.0",
49
51
  "vitest": "^2.0.0"
50
52
  },
53
+ "keywords": [
54
+ "llm",
55
+ "openai",
56
+ "anthropic",
57
+ "api",
58
+ "gateway",
59
+ "proxy",
60
+ "cost-optimization",
61
+ "ai",
62
+ "sdk"
63
+ ],
64
+ "repository": {
65
+ "type": "git",
66
+ "url": "https://github.com/skalpelai/Skalpel_User.git"
67
+ },
68
+ "homepage": "https://skalpel.ai",
69
+ "bugs": {
70
+ "url": "https://github.com/skalpelai/Skalpel_User/issues"
71
+ },
51
72
  "license": "MIT",
52
73
  "dependencies": {
53
74
  "commander": "^14.0.3"