skalpel 2.0.17 → 2.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -4,6 +4,54 @@ var __esm = (fn, res) => function __init() {
4
4
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
5
  };
6
6
 
7
+ // src/proxy/codex-oauth.ts
8
+ import { readFileSync } from "fs";
9
+ import { homedir } from "os";
10
+ import { join } from "path";
11
+ function authFilePath() {
12
+ return join(homedir(), ".codex", "auth.json");
13
+ }
14
+ function readCodexAuth() {
15
+ const path17 = authFilePath();
16
+ let raw;
17
+ try {
18
+ raw = readFileSync(path17, "utf-8");
19
+ } catch (err) {
20
+ const code = err?.code;
21
+ if (code !== "ENOENT") {
22
+ process.stderr.write(`skalpel: codex-oauth: cannot read auth file (${code ?? "unknown"})
23
+ `);
24
+ }
25
+ return null;
26
+ }
27
+ let parsed;
28
+ try {
29
+ parsed = JSON.parse(raw);
30
+ } catch {
31
+ process.stderr.write("skalpel: codex-oauth: auth file is not valid JSON\n");
32
+ return null;
33
+ }
34
+ if (parsed === null || typeof parsed !== "object" || typeof parsed.access_token !== "string" || typeof parsed.refresh_token !== "string" || typeof parsed.expires_at !== "string") {
35
+ process.stderr.write("skalpel: codex-oauth: auth file missing required fields\n");
36
+ return null;
37
+ }
38
+ const obj = parsed;
39
+ const auth = {
40
+ access_token: obj.access_token,
41
+ refresh_token: obj.refresh_token,
42
+ expires_at: obj.expires_at
43
+ };
44
+ if (typeof obj.account_id === "string") {
45
+ auth.account_id = obj.account_id;
46
+ }
47
+ return auth;
48
+ }
49
+ var init_codex_oauth = __esm({
50
+ "src/proxy/codex-oauth.ts"() {
51
+ "use strict";
52
+ }
53
+ });
54
+
7
55
  // src/proxy/dispatcher.ts
8
56
  import { Agent } from "undici";
9
57
  var skalpelDispatcher;
@@ -85,10 +133,19 @@ var init_streaming = __esm({
85
133
 
86
134
  // src/proxy/ws-client.ts
87
135
  import { EventEmitter } from "events";
136
+ import https from "https";
137
+ import http from "http";
88
138
  import WebSocket2 from "ws";
139
+ var H1_HTTPS_AGENT, H1_HTTP_AGENT;
89
140
  var init_ws_client = __esm({
90
141
  "src/proxy/ws-client.ts"() {
91
142
  "use strict";
143
+ init_codex_oauth();
144
+ H1_HTTPS_AGENT = new https.Agent({
145
+ ALPNProtocols: ["http/1.1"],
146
+ keepAlive: true
147
+ });
148
+ H1_HTTP_AGENT = new http.Agent({ keepAlive: true });
92
149
  }
93
150
  });
94
151
 
@@ -100,6 +157,7 @@ var init_handler = __esm({
100
157
  init_dispatcher();
101
158
  init_envelope();
102
159
  init_ws_client();
160
+ init_codex_oauth();
103
161
  init_recovery();
104
162
  init_fetch_error();
105
163
  }
@@ -115,6 +173,7 @@ import * as fs2 from "fs";
115
173
  import * as path2 from "path";
116
174
 
117
175
  // src/cli/utils.ts
176
+ init_codex_oauth();
118
177
  import * as fs from "fs";
119
178
  import * as path from "path";
120
179
  function detectProjectType() {
@@ -157,6 +216,25 @@ function detectAiSdks(projectType) {
157
216
  function validateApiKey(key) {
158
217
  return key.startsWith("sk-skalpel-") && key.length >= 20;
159
218
  }
219
+ function validateCodexOAuth() {
220
+ try {
221
+ const auth = readCodexAuth();
222
+ if (auth !== null) {
223
+ return { present: true };
224
+ }
225
+ } catch (err) {
226
+ return { present: false, reason: `other: ${err.message}` };
227
+ }
228
+ const candidatePath = path.join(
229
+ process.env.HOME ?? process.env.USERPROFILE ?? "",
230
+ ".codex",
231
+ "auth.json"
232
+ );
233
+ if (!fs.existsSync(candidatePath)) {
234
+ return { present: false, reason: "file missing" };
235
+ }
236
+ return { present: false, reason: "malformed JSON" };
237
+ }
160
238
  function generateCodeSample(config) {
161
239
  if (config.integrationMethod === "wrapper") {
162
240
  if (config.providers.includes("openai")) {
@@ -1525,6 +1603,12 @@ function configureCodex(agent, proxyConfig, direct = false) {
1525
1603
  content = removeCodexDirectProvider(content);
1526
1604
  }
1527
1605
  fs9.writeFileSync(configPath, content);
1606
+ const oauth = validateCodexOAuth();
1607
+ if (!oauth.present) {
1608
+ process.stderr.write("OAuth not configured. Run: codex login\n");
1609
+ process.stderr.write(" Then re-run: skalpel configure\n");
1610
+ process.stderr.write(" (Skalpel will fall back to OPENAI_API_KEY env var if OAuth missing.)\n");
1611
+ }
1528
1612
  }
1529
1613
  function getCursorConfigDir() {
1530
1614
  if (process.platform === "darwin") {
@@ -1817,7 +1901,7 @@ import { execSync as execSync5 } from "child_process";
1817
1901
 
1818
1902
  // src/proxy/server.ts
1819
1903
  init_handler();
1820
- import http from "http";
1904
+ import http2 from "http";
1821
1905
 
1822
1906
  // src/proxy/logger.ts
1823
1907
  import fs11 from "fs";
@@ -1833,6 +1917,7 @@ var wss = new WebSocketServer({
1833
1917
  });
1834
1918
 
1835
1919
  // src/proxy/server.ts
1920
+ init_codex_oauth();
1836
1921
  var proxyStartTime = 0;
1837
1922
  function stopProxy(config) {
1838
1923
  const pid = readPid(config.pidFile);
@@ -2240,10 +2325,13 @@ async function runWizard(options) {
2240
2325
  }
2241
2326
  print11("");
2242
2327
  const codexConfigured = agentsToConfigure.some((a) => a.name === "codex");
2243
- if (codexConfigured && !process.env.OPENAI_API_KEY) {
2244
- print11(" [!] Codex expects OPENAI_API_KEY to be set. The Skalpel proxy ignores the value,");
2245
- print11(" so any non-empty string works, e.g.:");
2246
- print11(" export OPENAI_API_KEY=sk-codex-placeholder-skalpel");
2328
+ if (codexConfigured) {
2329
+ print11(" [!] Codex auth: recommended -> run 'codex login' first to enable ChatGPT plan billing.");
2330
+ print11(" The OPENAI_API_KEY env var (placeholder OK) is still required for Codex startup");
2331
+ print11(" but is ignored by Skalpel when OAuth is present.");
2332
+ if (!process.env.OPENAI_API_KEY) {
2333
+ print11(" example: export OPENAI_API_KEY=sk-codex-placeholder-skalpel");
2334
+ }
2247
2335
  print11("");
2248
2336
  }
2249
2337
  }
@@ -2462,7 +2550,7 @@ function clearNpxCache() {
2462
2550
  }
2463
2551
 
2464
2552
  // src/cli/auth/callback-server.ts
2465
- import * as http2 from "http";
2553
+ import * as http3 from "http";
2466
2554
  import * as net2 from "net";
2467
2555
 
2468
2556
  // src/cli/auth/session-storage.ts
@@ -2591,7 +2679,7 @@ async function startCallbackServer(port, timeoutMsOrOptions = DEFAULT_TIMEOUT_MS
2591
2679
  return new Promise((resolve2, reject) => {
2592
2680
  let settled = false;
2593
2681
  let timer;
2594
- const server = http2.createServer((req, res) => {
2682
+ const server = http3.createServer((req, res) => {
2595
2683
  const origin = req.headers.origin;
2596
2684
  const corsHeaders = buildCorsHeaders(origin);
2597
2685
  if (req.method === "OPTIONS") {