@bman654/clodex 2.7.0 → 2.8.1
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/README.md +6 -2
- package/dist/{chunk-WZXTVKFX.js → chunk-J7WXOD2K.js} +2 -1
- package/dist/claude-wrapper.js +1 -1
- package/dist/cli.js +487 -25
- package/dist/cli.js.map +1 -1
- package/docs/credential-helpers.md +50 -2
- package/package.json +1 -1
- /package/dist/{chunk-WZXTVKFX.js.map → chunk-J7WXOD2K.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -47,11 +47,12 @@ import {
|
|
|
47
47
|
storeActiveOAuthAccount,
|
|
48
48
|
tcpListenerUrlHost,
|
|
49
49
|
unregisterServerRuntimeState,
|
|
50
|
+
waitForTcpListener,
|
|
50
51
|
withCredentialMutationLock,
|
|
51
52
|
withProviderMutationLock,
|
|
52
53
|
withRegistryWriteLock,
|
|
53
54
|
withRegistryWriteLockSync
|
|
54
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-J7WXOD2K.js";
|
|
55
56
|
|
|
56
57
|
// src/cli.ts
|
|
57
58
|
import pc13 from "picocolors";
|
|
@@ -204,6 +205,13 @@ function printOAuthStepsPanel(title, providerLabel2) {
|
|
|
204
205
|
`${pc.white("3. Approve access for ")}${fmtProvider(providerLabel2)}`
|
|
205
206
|
]);
|
|
206
207
|
}
|
|
208
|
+
function printOAuthBrowserPanel(title, providerLabel2) {
|
|
209
|
+
printPanel(pc.cyan(title), [
|
|
210
|
+
`${pc.white("1. Sign in on the page that opens in your browser")}`,
|
|
211
|
+
`${pc.white("2. Approve access for ")}${fmtProvider(providerLabel2)}`,
|
|
212
|
+
`${pc.white("3. Return to this terminal")}`
|
|
213
|
+
]);
|
|
214
|
+
}
|
|
207
215
|
function printNetworkWarningPanel() {
|
|
208
216
|
printPanel(pc.yellow("Network mode"), [
|
|
209
217
|
`${pc.yellow(pc.bold("Anyone on your network"))}${pc.white(" who knows the password can use this server through your account.")}`
|
|
@@ -374,7 +382,7 @@ import { join } from "path";
|
|
|
374
382
|
// package.json
|
|
375
383
|
var package_default = {
|
|
376
384
|
name: "@bman654/clodex",
|
|
377
|
-
version: "2.
|
|
385
|
+
version: "2.8.1",
|
|
378
386
|
publishConfig: {
|
|
379
387
|
access: "public"
|
|
380
388
|
},
|
|
@@ -821,6 +829,24 @@ function supportsNativeOAuth(providerId) {
|
|
|
821
829
|
}
|
|
822
830
|
|
|
823
831
|
// src/oauth/pkce.ts
|
|
832
|
+
function generateRandomString(length) {
|
|
833
|
+
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
|
|
834
|
+
return Array.from(crypto.getRandomValues(new Uint8Array(length))).map((b) => chars[b % chars.length]).join("");
|
|
835
|
+
}
|
|
836
|
+
function base64UrlEncode(buffer) {
|
|
837
|
+
const binary = String.fromCharCode(...new Uint8Array(buffer));
|
|
838
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
839
|
+
}
|
|
840
|
+
async function generatePkce() {
|
|
841
|
+
const verifier = generateRandomString(64);
|
|
842
|
+
const hash = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
|
|
843
|
+
return { verifier, challenge: base64UrlEncode(hash) };
|
|
844
|
+
}
|
|
845
|
+
function generateOAuthState() {
|
|
846
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
847
|
+
const binary = String.fromCharCode(...bytes);
|
|
848
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
849
|
+
}
|
|
824
850
|
function positiveSecondsToMs(value, defaultMs) {
|
|
825
851
|
const seconds = Number(value);
|
|
826
852
|
return Number.isFinite(seconds) && seconds > 0 ? seconds * 1e3 : defaultMs;
|
|
@@ -871,11 +897,112 @@ async function postOAuthRefresh(url, body, options) {
|
|
|
871
897
|
}
|
|
872
898
|
}
|
|
873
899
|
|
|
900
|
+
// src/oauth/callback-server.ts
|
|
901
|
+
import http from "http";
|
|
902
|
+
var SUCCESS_HTML = `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Authorized</title></head>
|
|
903
|
+
<body style="font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0">
|
|
904
|
+
<div style="text-align:center;padding:2rem;background:#fff;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,.1)">
|
|
905
|
+
<div style="color:#22c55e;font-size:2.5rem">✓</div>
|
|
906
|
+
<h1 style="margin:.5rem 0">Authentication successful</h1>
|
|
907
|
+
<p style="color:#666">You can close this tab and return to the terminal.</p>
|
|
908
|
+
</div></body></html>`;
|
|
909
|
+
var FAILURE_HTML = `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Sign-in failed</title></head>
|
|
910
|
+
<body style="font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0">
|
|
911
|
+
<div style="text-align:center;padding:2rem;background:#fff;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,.1)">
|
|
912
|
+
<div style="color:#ef4444;font-size:2.5rem">✗</div>
|
|
913
|
+
<h1 style="margin:.5rem 0">Sign-in failed</h1>
|
|
914
|
+
<p style="color:#666">Return to the terminal for details.</p>
|
|
915
|
+
</div></body></html>`;
|
|
916
|
+
var LOOPBACK_PROBE_TIMEOUT_MS = 250;
|
|
917
|
+
async function isLoopbackPortTaken(port) {
|
|
918
|
+
const probes = await Promise.all(["127.0.0.1", "::1"].map(
|
|
919
|
+
(host) => waitForTcpListener(host, port, LOOPBACK_PROBE_TIMEOUT_MS).catch(() => false)
|
|
920
|
+
));
|
|
921
|
+
return probes.some(Boolean);
|
|
922
|
+
}
|
|
923
|
+
async function startCallbackServer(options) {
|
|
924
|
+
let codeResolve;
|
|
925
|
+
let codeReject;
|
|
926
|
+
let buffered;
|
|
927
|
+
const { path, redirectHost } = options;
|
|
928
|
+
const server = http.createServer((req, res) => {
|
|
929
|
+
const u = new URL(req.url ?? "/", "http://localhost");
|
|
930
|
+
if (u.pathname !== path) {
|
|
931
|
+
res.writeHead(404);
|
|
932
|
+
res.end();
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
const code = u.searchParams.get("code") ?? "";
|
|
936
|
+
const state = u.searchParams.get("state") ?? "";
|
|
937
|
+
const error = u.searchParams.get("error") ?? "";
|
|
938
|
+
if (options.expectedState !== void 0 && state !== options.expectedState) {
|
|
939
|
+
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
940
|
+
res.end("Invalid OAuth state");
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
const failed = Boolean(error) || !code;
|
|
944
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
945
|
+
res.end(failed ? FAILURE_HTML : SUCCESS_HTML);
|
|
946
|
+
const params = { code, state, error: error || void 0 };
|
|
947
|
+
if (codeResolve) codeResolve(params);
|
|
948
|
+
else buffered ??= params;
|
|
949
|
+
});
|
|
950
|
+
const ports = options.ports?.length ? options.ports : [0];
|
|
951
|
+
let address;
|
|
952
|
+
let lastError;
|
|
953
|
+
for (const port of ports) {
|
|
954
|
+
if (port !== 0 && redirectHost === "localhost" && await isLoopbackPortTaken(port)) {
|
|
955
|
+
const busy = new Error(`listen EADDRINUSE: address already in use localhost:${port}`);
|
|
956
|
+
busy.code = "EADDRINUSE";
|
|
957
|
+
lastError = busy;
|
|
958
|
+
continue;
|
|
959
|
+
}
|
|
960
|
+
try {
|
|
961
|
+
address = await listenTcpServer(server, port, redirectHost);
|
|
962
|
+
break;
|
|
963
|
+
} catch (error) {
|
|
964
|
+
lastError = error;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
if (!address) throw lastError ?? new Error("OAuth callback server could not bind");
|
|
968
|
+
return {
|
|
969
|
+
port: address.port,
|
|
970
|
+
redirectUri: `http://${redirectHost}:${address.port}${path}`,
|
|
971
|
+
waitForCallback(timeoutMs = 3e5) {
|
|
972
|
+
return new Promise((resolve3, reject) => {
|
|
973
|
+
if (buffered) {
|
|
974
|
+
resolve3(buffered);
|
|
975
|
+
buffered = void 0;
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
const timer = setTimeout(
|
|
979
|
+
() => reject(new Error("OAuth timeout \u2014 browser closed without completing sign-in")),
|
|
980
|
+
timeoutMs
|
|
981
|
+
);
|
|
982
|
+
codeResolve = (params) => {
|
|
983
|
+
clearTimeout(timer);
|
|
984
|
+
resolve3(params);
|
|
985
|
+
};
|
|
986
|
+
codeReject = (err) => {
|
|
987
|
+
clearTimeout(timer);
|
|
988
|
+
reject(err);
|
|
989
|
+
};
|
|
990
|
+
});
|
|
991
|
+
},
|
|
992
|
+
close() {
|
|
993
|
+
server.close();
|
|
994
|
+
codeReject?.(new Error("Server closed"));
|
|
995
|
+
}
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
|
|
874
999
|
// src/oauth/openai.ts
|
|
875
1000
|
var CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
876
1001
|
var ISSUER = "https://auth.openai.com";
|
|
877
1002
|
var OAUTH_POLLING_SAFETY_MARGIN_MS = 3e3;
|
|
878
1003
|
var DEVICE_CODE_DEFAULT_EXPIRES_MS = 5 * 60 * 1e3;
|
|
1004
|
+
var BROWSER_CALLBACK_PORTS = [1455, 1457];
|
|
1005
|
+
var BROWSER_CALLBACK_PATH = "/auth/callback";
|
|
879
1006
|
function extractOpenAiAccountId(tokens) {
|
|
880
1007
|
const token = tokens.id_token ?? tokens.access_token;
|
|
881
1008
|
if (!token) return void 0;
|
|
@@ -963,6 +1090,74 @@ async function refreshOpenAiAccessToken(refreshToken) {
|
|
|
963
1090
|
}
|
|
964
1091
|
);
|
|
965
1092
|
}
|
|
1093
|
+
function buildOpenAiAuthorizeUrl(redirectUri, challenge, state) {
|
|
1094
|
+
const qs = new URLSearchParams({
|
|
1095
|
+
response_type: "code",
|
|
1096
|
+
client_id: CLIENT_ID,
|
|
1097
|
+
redirect_uri: redirectUri,
|
|
1098
|
+
scope: "openid profile email offline_access",
|
|
1099
|
+
code_challenge: challenge,
|
|
1100
|
+
code_challenge_method: "S256",
|
|
1101
|
+
id_token_add_organizations: "true",
|
|
1102
|
+
codex_cli_simplified_flow: "true",
|
|
1103
|
+
state
|
|
1104
|
+
});
|
|
1105
|
+
return `${ISSUER}/oauth/authorize?${qs.toString()}`;
|
|
1106
|
+
}
|
|
1107
|
+
async function exchangeOpenAiAuthorizationCode(code, redirectUri, codeVerifier) {
|
|
1108
|
+
return postOAuthRefresh(
|
|
1109
|
+
`${ISSUER}/oauth/token`,
|
|
1110
|
+
new URLSearchParams({
|
|
1111
|
+
grant_type: "authorization_code",
|
|
1112
|
+
code,
|
|
1113
|
+
redirect_uri: redirectUri,
|
|
1114
|
+
client_id: CLIENT_ID,
|
|
1115
|
+
code_verifier: codeVerifier
|
|
1116
|
+
}),
|
|
1117
|
+
{
|
|
1118
|
+
contentType: "form",
|
|
1119
|
+
errorPrefix: "OpenAI token exchange failed",
|
|
1120
|
+
includeStatus: true
|
|
1121
|
+
}
|
|
1122
|
+
);
|
|
1123
|
+
}
|
|
1124
|
+
async function runOpenAiBrowserFlow(onAuthorizeUrl, opts) {
|
|
1125
|
+
const { verifier, challenge } = await generatePkce();
|
|
1126
|
+
const state = generateOAuthState();
|
|
1127
|
+
const ports = opts?.ports ?? BROWSER_CALLBACK_PORTS;
|
|
1128
|
+
let server;
|
|
1129
|
+
try {
|
|
1130
|
+
server = await startCallbackServer({
|
|
1131
|
+
ports,
|
|
1132
|
+
path: BROWSER_CALLBACK_PATH,
|
|
1133
|
+
redirectHost: "localhost",
|
|
1134
|
+
expectedState: state
|
|
1135
|
+
});
|
|
1136
|
+
} catch (error) {
|
|
1137
|
+
if (error.code === "EADDRINUSE") {
|
|
1138
|
+
throw new Error(
|
|
1139
|
+
`Ports ${ports.join(" and ")} are in use \u2014 close any other OpenAI sign-in (e.g. codex login) and try again.`
|
|
1140
|
+
);
|
|
1141
|
+
}
|
|
1142
|
+
throw new Error(
|
|
1143
|
+
`Could not start the OAuth callback listener: ${error instanceof Error ? error.message : String(error)}`,
|
|
1144
|
+
{ cause: error }
|
|
1145
|
+
);
|
|
1146
|
+
}
|
|
1147
|
+
try {
|
|
1148
|
+
onAuthorizeUrl({ url: buildOpenAiAuthorizeUrl(server.redirectUri, challenge, state) });
|
|
1149
|
+
const params = await server.waitForCallback(opts?.timeoutMs);
|
|
1150
|
+
if (params.error) throw new Error(`OpenAI sign-in failed: ${params.error}`);
|
|
1151
|
+
if (!params.code) throw new Error("OpenAI sign-in returned no authorization code");
|
|
1152
|
+
if (params.state !== state) {
|
|
1153
|
+
throw new Error("OpenAI sign-in returned a mismatched state \u2014 try again");
|
|
1154
|
+
}
|
|
1155
|
+
const tokens = await exchangeOpenAiAuthorizationCode(params.code, server.redirectUri, verifier);
|
|
1156
|
+
return { tokens, accountId: extractOpenAiAccountId(tokens) };
|
|
1157
|
+
} finally {
|
|
1158
|
+
server.close();
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
966
1161
|
async function runOpenAiDeviceCodeFlow(onDeviceCode, opts) {
|
|
967
1162
|
const deviceData = await requestOpenAiDeviceCode();
|
|
968
1163
|
onDeviceCode({ url: openAiDeviceCodeUrl(), userCode: deviceData.user_code });
|
|
@@ -3224,7 +3419,7 @@ function savedStopsAfter(current, assignments) {
|
|
|
3224
3419
|
}
|
|
3225
3420
|
|
|
3226
3421
|
// src/patch-transforms.ts
|
|
3227
|
-
var PATCH_TRANSFORMS_VERSION =
|
|
3422
|
+
var PATCH_TRANSFORMS_VERSION = 9;
|
|
3228
3423
|
var NATIVE_EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
|
|
3229
3424
|
var BASE_EFFORT_LEVELS = ["low", "medium", "high"];
|
|
3230
3425
|
function projectNativeEffort(effort) {
|
|
@@ -3427,7 +3622,7 @@ function applyClodexPatches(source, config) {
|
|
|
3427
3622
|
}).join("; ");
|
|
3428
3623
|
applyOnce(
|
|
3429
3624
|
"PATCH 4: Agent tool model description",
|
|
3430
|
-
/(describe\(`Optional model override for this agent[
|
|
3625
|
+
/(describe\(`Optional model override for this agent(?:[^`\\]|\\.)*?)(`)/,
|
|
3431
3626
|
(_m, body, close) => body.includes("Additional custom models") ? body + close : body + " Additional custom models: " + listing + "." + close,
|
|
3432
3627
|
{ required: false, noopIsSkip: true }
|
|
3433
3628
|
);
|
|
@@ -3974,7 +4169,7 @@ function captureBuiltInPatchProofs(source, config, results) {
|
|
|
3974
4169
|
);
|
|
3975
4170
|
addPattern(
|
|
3976
4171
|
"PATCH 4: Agent tool model description",
|
|
3977
|
-
/describe\(`Optional model override for this agent[
|
|
4172
|
+
/describe\(`Optional model override for this agent(?:[^`\\]|\\.)*?`/
|
|
3978
4173
|
);
|
|
3979
4174
|
const aliases = configuredAliases(config);
|
|
3980
4175
|
if (protectsResult(results, "PATCH 6: alias resolver switch")) {
|
|
@@ -6605,6 +6800,9 @@ var BUN_OFFSETS_BYTES = 32;
|
|
|
6605
6800
|
var TAIL_SCAN_BYTES = 16 * 1024 * 1024;
|
|
6606
6801
|
var MODULE_STRUCT_BYTES_CURRENT = 52;
|
|
6607
6802
|
var MODULE_STRUCT_BYTES_LEGACY = 36;
|
|
6803
|
+
var CONTENTS_FIELD_AT = 8;
|
|
6804
|
+
var LOADER_FROM_END = 3;
|
|
6805
|
+
var BUN_JAVASCRIPT_LOADER = 1;
|
|
6608
6806
|
var MAX_MODULE_NAME_BYTES = 4096;
|
|
6609
6807
|
var MIN_SHIMMABLE_NAME_BYTES = 7;
|
|
6610
6808
|
function tweakccRecognizesModuleName(name) {
|
|
@@ -6659,6 +6857,8 @@ function parseBunModuleNamesAtUnchecked(fd, offsetsAt) {
|
|
|
6659
6857
|
if (!modules) return null;
|
|
6660
6858
|
const names = [];
|
|
6661
6859
|
const nameOffsets = [];
|
|
6860
|
+
const contents = [];
|
|
6861
|
+
const loaders = [];
|
|
6662
6862
|
for (let index = 0; index < moduleCount; index++) {
|
|
6663
6863
|
const nameOffset = modules.readUInt32LE(index * structBytes);
|
|
6664
6864
|
const nameLength = modules.readUInt32LE(index * structBytes + 4);
|
|
@@ -6670,8 +6870,23 @@ function parseBunModuleNamesAtUnchecked(fd, offsetsAt) {
|
|
|
6670
6870
|
if (!/^[\x20-\x7e]+$/.test(name)) return null;
|
|
6671
6871
|
names.push(name);
|
|
6672
6872
|
nameOffsets.push(blobAt + nameOffset);
|
|
6873
|
+
contents.push({
|
|
6874
|
+
offset: modules.readUInt32LE(index * structBytes + CONTENTS_FIELD_AT),
|
|
6875
|
+
length: modules.readUInt32LE(index * structBytes + CONTENTS_FIELD_AT + 4)
|
|
6876
|
+
});
|
|
6877
|
+
loaders.push(modules.readUInt8(index * structBytes + structBytes - LOADER_FROM_END));
|
|
6673
6878
|
}
|
|
6674
|
-
return {
|
|
6879
|
+
return {
|
|
6880
|
+
names,
|
|
6881
|
+
entryPointId,
|
|
6882
|
+
offsets: nameOffsets,
|
|
6883
|
+
contents,
|
|
6884
|
+
loaders,
|
|
6885
|
+
blobAt,
|
|
6886
|
+
modulesAt: blobAt + modulesOffset,
|
|
6887
|
+
structBytes,
|
|
6888
|
+
byteCount: Number(byteCount)
|
|
6889
|
+
};
|
|
6675
6890
|
}
|
|
6676
6891
|
function findStandIn(fd, fileSize, marker) {
|
|
6677
6892
|
const needle = Buffer.from(marker);
|
|
@@ -6717,6 +6932,70 @@ function isMachO(fd) {
|
|
|
6717
6932
|
const value = magic.readUInt32BE(0);
|
|
6718
6933
|
return value === 4277009102 || value === 4277009103 || value === 3472551422 || value === 3489328638 || value === 3405691582 || value === 3405691583;
|
|
6719
6934
|
}
|
|
6935
|
+
function readBunModuleTable(path) {
|
|
6936
|
+
const fd = openSync2(path, "r");
|
|
6937
|
+
try {
|
|
6938
|
+
const parsed = readBunModuleNames(fd, statSync4(path).size);
|
|
6939
|
+
if (!parsed) return null;
|
|
6940
|
+
const { names, loaders, contents, entryPointId, blobAt, modulesAt, structBytes, byteCount } = parsed;
|
|
6941
|
+
return { names, loaders, contents, entryPointId, blobAt, modulesAt, structBytes, byteCount };
|
|
6942
|
+
} finally {
|
|
6943
|
+
closeSync2(fd);
|
|
6944
|
+
}
|
|
6945
|
+
}
|
|
6946
|
+
function readBunJavaScriptModules(path) {
|
|
6947
|
+
const fd = openSync2(path, "r");
|
|
6948
|
+
try {
|
|
6949
|
+
const parsed = readBunModuleNames(fd, statSync4(path).size);
|
|
6950
|
+
if (!parsed) return null;
|
|
6951
|
+
const modules = [];
|
|
6952
|
+
for (let index = 0; index < parsed.names.length; index++) {
|
|
6953
|
+
if (parsed.loaders[index] !== BUN_JAVASCRIPT_LOADER) continue;
|
|
6954
|
+
const range = parsed.contents[index];
|
|
6955
|
+
if (range.offset < 0 || range.length < 0 || range.offset + range.length > parsed.byteCount) {
|
|
6956
|
+
return null;
|
|
6957
|
+
}
|
|
6958
|
+
const bytes = range.length === 0 ? Buffer.alloc(0) : readAt(fd, range.length, parsed.blobAt + range.offset);
|
|
6959
|
+
if (!bytes) return null;
|
|
6960
|
+
modules.push({
|
|
6961
|
+
index,
|
|
6962
|
+
name: parsed.names[index],
|
|
6963
|
+
source: bytes.toString("utf8"),
|
|
6964
|
+
byteLength: bytes.length
|
|
6965
|
+
});
|
|
6966
|
+
}
|
|
6967
|
+
return modules;
|
|
6968
|
+
} finally {
|
|
6969
|
+
closeSync2(fd);
|
|
6970
|
+
}
|
|
6971
|
+
}
|
|
6972
|
+
function repointBunModuleContents(path, edits) {
|
|
6973
|
+
if (edits.length === 0) return;
|
|
6974
|
+
const fd = openSync2(path, "r+");
|
|
6975
|
+
try {
|
|
6976
|
+
const parsed = readBunModuleNames(fd, statSync4(path).size);
|
|
6977
|
+
if (!parsed) throw new Error(`cannot read the Bun module table of ${path}`);
|
|
6978
|
+
for (const { index, range } of edits) {
|
|
6979
|
+
if (index < 0 || index >= parsed.names.length) {
|
|
6980
|
+
throw new Error(`module ${index} is outside the ${parsed.names.length}-module table of ${path}`);
|
|
6981
|
+
}
|
|
6982
|
+
if (range.offset < 0 || range.length < 0 || range.offset + range.length > parsed.byteCount) {
|
|
6983
|
+
throw new Error(
|
|
6984
|
+
`module ${index} would point at ${range.offset}+${range.length}, outside the ${parsed.byteCount}-byte blob of ${path}`
|
|
6985
|
+
);
|
|
6986
|
+
}
|
|
6987
|
+
const at = parsed.modulesAt + index * parsed.structBytes + CONTENTS_FIELD_AT;
|
|
6988
|
+
const pair = Buffer.alloc(8);
|
|
6989
|
+
pair.writeUInt32LE(range.offset, 0);
|
|
6990
|
+
pair.writeUInt32LE(range.length, 4);
|
|
6991
|
+
if (writeSync2(fd, pair, 0, pair.length, at) !== pair.length) {
|
|
6992
|
+
throw new Error(`short write repointing module ${index} of ${path}`);
|
|
6993
|
+
}
|
|
6994
|
+
}
|
|
6995
|
+
} finally {
|
|
6996
|
+
closeSync2(fd);
|
|
6997
|
+
}
|
|
6998
|
+
}
|
|
6720
6999
|
function shimEntryModuleName(path) {
|
|
6721
7000
|
const fd = openSync2(path, "r+");
|
|
6722
7001
|
try {
|
|
@@ -6749,7 +7028,17 @@ function restoreEntryModuleName(path, shim, { resign }) {
|
|
|
6749
7028
|
}
|
|
6750
7029
|
writeNameBytes(fd, shim.original, offset);
|
|
6751
7030
|
restoreEveryStandIn(fd, statSync4(path).size, shim);
|
|
6752
|
-
machO = resign
|
|
7031
|
+
machO = resign;
|
|
7032
|
+
} finally {
|
|
7033
|
+
closeSync2(fd);
|
|
7034
|
+
}
|
|
7035
|
+
if (machO) resignMachOBinary(path);
|
|
7036
|
+
}
|
|
7037
|
+
function resignMachOBinary(path) {
|
|
7038
|
+
const fd = openSync2(path, "r");
|
|
7039
|
+
let machO;
|
|
7040
|
+
try {
|
|
7041
|
+
machO = isMachO(fd);
|
|
6753
7042
|
} finally {
|
|
6754
7043
|
closeSync2(fd);
|
|
6755
7044
|
}
|
|
@@ -6758,6 +7047,99 @@ function restoreEntryModuleName(path, shim, { resign }) {
|
|
|
6758
7047
|
}
|
|
6759
7048
|
}
|
|
6760
7049
|
|
|
7050
|
+
// src/bun-bundle.ts
|
|
7051
|
+
function writableModuleIndex(path) {
|
|
7052
|
+
const table = readBunModuleTable(path);
|
|
7053
|
+
if (!table) return null;
|
|
7054
|
+
const index = table.names.findIndex(tweakccRecognizesModuleName);
|
|
7055
|
+
return index < 0 ? null : index;
|
|
7056
|
+
}
|
|
7057
|
+
var BUNDLE_MODULE_SEPARATOR = '\n/*clodex:module-boundary`;{}"]*/\n';
|
|
7058
|
+
function readClaudeBundle(path) {
|
|
7059
|
+
const modules = readBunJavaScriptModules(path);
|
|
7060
|
+
if (!modules || modules.length === 0) return null;
|
|
7061
|
+
if (modules.some((module) => module.source.includes(BUNDLE_MODULE_SEPARATOR))) return null;
|
|
7062
|
+
if (modules.some((module) => !roundTripsAsUtf8(module.source, module.byteLength))) return null;
|
|
7063
|
+
return { modules, source: modules.map((module) => module.source).join(BUNDLE_MODULE_SEPARATOR) };
|
|
7064
|
+
}
|
|
7065
|
+
function roundTripsAsUtf8(source, byteLength) {
|
|
7066
|
+
return Buffer.byteLength(source, "utf8") === byteLength && !source.includes("\uFFFD");
|
|
7067
|
+
}
|
|
7068
|
+
function splitBundleSource(bundle, patched) {
|
|
7069
|
+
const parts = patched.split(BUNDLE_MODULE_SEPARATOR);
|
|
7070
|
+
if (parts.length !== bundle.modules.length) {
|
|
7071
|
+
throw new Error(
|
|
7072
|
+
`the patched bundle has ${parts.length} module boundaries, expected ${bundle.modules.length}`
|
|
7073
|
+
);
|
|
7074
|
+
}
|
|
7075
|
+
return parts;
|
|
7076
|
+
}
|
|
7077
|
+
function planBundleWrite(bundle, patchedSources, writableIndex) {
|
|
7078
|
+
if (patchedSources.length !== bundle.modules.length) {
|
|
7079
|
+
throw new Error(
|
|
7080
|
+
`expected ${bundle.modules.length} patched module sources, got ${patchedSources.length}`
|
|
7081
|
+
);
|
|
7082
|
+
}
|
|
7083
|
+
const writable = bundle.modules.findIndex((module) => module.index === writableIndex);
|
|
7084
|
+
if (writable < 0) {
|
|
7085
|
+
throw new Error(`module ${writableIndex} is not one of this binary's JavaScript modules`);
|
|
7086
|
+
}
|
|
7087
|
+
const changed = bundle.modules.map((module, at) => at).filter((at) => at !== writable && patchedSources[at] !== bundle.modules[at].source);
|
|
7088
|
+
if (changed.length === 0) return { content: patchedSources[writable], repoints: [] };
|
|
7089
|
+
const order = [writable, ...changed];
|
|
7090
|
+
const repoints = [];
|
|
7091
|
+
let content = "";
|
|
7092
|
+
let start = 0;
|
|
7093
|
+
for (const at of order) {
|
|
7094
|
+
const source = patchedSources[at];
|
|
7095
|
+
const length = Buffer.byteLength(source, "utf8");
|
|
7096
|
+
repoints.push({ index: bundle.modules[at].index, start, length, expected: source });
|
|
7097
|
+
content += source + "\0";
|
|
7098
|
+
start += length + 1;
|
|
7099
|
+
}
|
|
7100
|
+
return { content, repoints };
|
|
7101
|
+
}
|
|
7102
|
+
function applyBundleWritePlan(path, plan) {
|
|
7103
|
+
const table = readBunModuleTable(path);
|
|
7104
|
+
if (!table) {
|
|
7105
|
+
if (plan.repoints.length === 0) return;
|
|
7106
|
+
throw new Error(`cannot read the Bun module table of ${path} after repacking`);
|
|
7107
|
+
}
|
|
7108
|
+
const recognized = table.names.filter(tweakccRecognizesModuleName);
|
|
7109
|
+
if (recognized.length !== 1) {
|
|
7110
|
+
throw new Error(
|
|
7111
|
+
`${path} has ${recognized.length} modules tweakcc would write to; the patch was planned around exactly one`
|
|
7112
|
+
);
|
|
7113
|
+
}
|
|
7114
|
+
if (plan.repoints.length === 0) return;
|
|
7115
|
+
const writable = table.names.findIndex(tweakccRecognizesModuleName);
|
|
7116
|
+
if (writable !== plan.repoints[0].index) {
|
|
7117
|
+
throw new Error(
|
|
7118
|
+
`${path} exposes module ${writable} to tweakcc, but the patch was planned around module ${plan.repoints[0].index}`
|
|
7119
|
+
);
|
|
7120
|
+
}
|
|
7121
|
+
const written = table.contents[writable];
|
|
7122
|
+
const expectedBytes = Buffer.byteLength(plan.content, "utf8");
|
|
7123
|
+
if (written.length !== expectedBytes) {
|
|
7124
|
+
throw new Error(
|
|
7125
|
+
`${path} holds ${written.length} bytes where the ${expectedBytes} bytes clodex wrote should be; refusing to repoint its modules`
|
|
7126
|
+
);
|
|
7127
|
+
}
|
|
7128
|
+
const edits = plan.repoints.map((repoint) => ({
|
|
7129
|
+
index: repoint.index,
|
|
7130
|
+
range: { offset: written.offset + repoint.start, length: repoint.length }
|
|
7131
|
+
}));
|
|
7132
|
+
repointBunModuleContents(path, edits);
|
|
7133
|
+
const after = readBunJavaScriptModules(path);
|
|
7134
|
+
if (!after) throw new Error(`cannot re-read the modules of ${path} after repointing them`);
|
|
7135
|
+
const byIndex = new Map(after.map((module) => [module.index, module.source]));
|
|
7136
|
+
for (const repoint of plan.repoints) {
|
|
7137
|
+
if (byIndex.get(repoint.index) !== repoint.expected) {
|
|
7138
|
+
throw new Error(`module ${repoint.index} of ${path} did not read back as the patched source`);
|
|
7139
|
+
}
|
|
7140
|
+
}
|
|
7141
|
+
}
|
|
7142
|
+
|
|
6761
7143
|
// src/patch-backup.ts
|
|
6762
7144
|
import { createHash as createHash5 } from "crypto";
|
|
6763
7145
|
import { existsSync as existsSync4, readFileSync as readFileSync7, readdirSync, statSync as statSync5 } from "fs";
|
|
@@ -12109,9 +12491,15 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
12109
12491
|
copyFileSync(from, candidatePath);
|
|
12110
12492
|
const shim = shimEntryModuleName(candidatePath);
|
|
12111
12493
|
const installation = await tryDetectInstallation({ path: candidatePath });
|
|
12112
|
-
const
|
|
12494
|
+
const bundle = readClaudeBundle(candidatePath);
|
|
12495
|
+
if (!bundle && installation.kind === "native") {
|
|
12496
|
+
p2.log.warn(
|
|
12497
|
+
`Could not read ${candidatePath} as a Bun module table, so only the module tweakcc names is being patched. On Claude Code 2.1.242 and later that module is a stub holding none of the code clodex patches, and the patch below will fail at its first required site \u2014 the cause is this read, not a changed anchor.`
|
|
12498
|
+
);
|
|
12499
|
+
}
|
|
12500
|
+
const source = bundle ? bundle.source : await readContent(installation);
|
|
12113
12501
|
if (shim) restoreEntryModuleName(candidatePath, shim, { resign: false });
|
|
12114
|
-
return { installation, source };
|
|
12502
|
+
return { installation, source, bundle };
|
|
12115
12503
|
};
|
|
12116
12504
|
const facts = collectPristineFacts({
|
|
12117
12505
|
version,
|
|
@@ -12204,8 +12592,25 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
12204
12592
|
}
|
|
12205
12593
|
results = [...results, ...local.results];
|
|
12206
12594
|
const writeShim = shimEntryModuleName(candidatePath);
|
|
12207
|
-
|
|
12595
|
+
let repointed = false;
|
|
12596
|
+
if (loaded.bundle) {
|
|
12597
|
+
const writable = writableModuleIndex(candidatePath);
|
|
12598
|
+
if (writable === null) {
|
|
12599
|
+
throw new Error("no module of the patch candidate carries a name tweakcc can write to");
|
|
12600
|
+
}
|
|
12601
|
+
const plan2 = planBundleWrite(
|
|
12602
|
+
loaded.bundle,
|
|
12603
|
+
splitBundleSource(loaded.bundle, local.content),
|
|
12604
|
+
writable
|
|
12605
|
+
);
|
|
12606
|
+
await writeContent(loaded.installation, plan2.content);
|
|
12607
|
+
applyBundleWritePlan(candidatePath, plan2);
|
|
12608
|
+
repointed = plan2.repoints.length > 0;
|
|
12609
|
+
} else {
|
|
12610
|
+
await writeContent(loaded.installation, local.content);
|
|
12611
|
+
}
|
|
12208
12612
|
if (writeShim) restoreEntryModuleName(candidatePath, writeShim, { resign: true });
|
|
12613
|
+
else if (repointed) resignMachOBinary(candidatePath);
|
|
12209
12614
|
patchedSize = statSync6(candidatePath).size;
|
|
12210
12615
|
patchedSha256 = sha256File(candidatePath);
|
|
12211
12616
|
renameSync2(candidatePath, binaryPath);
|
|
@@ -14226,6 +14631,25 @@ async function runNativeDeviceCode(providerId) {
|
|
|
14226
14631
|
throw err;
|
|
14227
14632
|
}
|
|
14228
14633
|
}
|
|
14634
|
+
async function runNativeBrowserSignIn(providerId) {
|
|
14635
|
+
const label = PROVIDER_DISPLAY[providerId];
|
|
14636
|
+
printOAuthBrowserPanel(`${label} \u2014 Sign in`, label);
|
|
14637
|
+
const spinner5 = p3.spinner();
|
|
14638
|
+
spinner5.start("Opening your browser...");
|
|
14639
|
+
try {
|
|
14640
|
+
const { tokens, accountId } = await runOpenAiBrowserFlow(({ url }) => {
|
|
14641
|
+
spinner5.stop("");
|
|
14642
|
+
p3.log.info(`If the browser did not open, visit: ${pc4.cyan(url)}`);
|
|
14643
|
+
openBrowser(url);
|
|
14644
|
+
spinner5.start("Waiting for sign-in in your browser...");
|
|
14645
|
+
});
|
|
14646
|
+
spinner5.stop(pc4.green("Signed in to OpenAI ChatGPT"));
|
|
14647
|
+
return tokensToStoredCredential(tokens, void 0, accountId);
|
|
14648
|
+
} catch (err) {
|
|
14649
|
+
spinner5.stop("");
|
|
14650
|
+
throw err;
|
|
14651
|
+
}
|
|
14652
|
+
}
|
|
14229
14653
|
async function upsertOAuthAccountSlot(registryId, account, authRef, expectedAuthRef) {
|
|
14230
14654
|
return withRegistryWriteLock(async () => {
|
|
14231
14655
|
const registry = loadRegistryStrict();
|
|
@@ -14429,7 +14853,7 @@ async function authenticateProvider(providerId, options = {}) {
|
|
|
14429
14853
|
`Credential store is unavailable${storeDiagMsg ? `: ${storeDiagMsg}` : ""}. Set CLODEX_CREDENTIAL_HELPER to an absolute path to an external credential helper and try again.`
|
|
14430
14854
|
);
|
|
14431
14855
|
}
|
|
14432
|
-
const cred = await runNativeDeviceCode(providerId);
|
|
14856
|
+
const cred = options.method === "browser" ? await runNativeBrowserSignIn(providerId) : await runNativeDeviceCode(providerId);
|
|
14433
14857
|
const persisted = await persistNativeOAuthCredential(providerId, cred, accountName);
|
|
14434
14858
|
const refreshSpinner = p3.spinner();
|
|
14435
14859
|
refreshSpinner.start("Refreshing model list...");
|
|
@@ -14468,11 +14892,17 @@ function providerAuthHelpText() {
|
|
|
14468
14892
|
|
|
14469
14893
|
${pc4.bold("Usage:")}
|
|
14470
14894
|
clodex providers auth openai
|
|
14895
|
+
clodex providers auth openai --browser
|
|
14471
14896
|
clodex providers auth openai --account work
|
|
14472
14897
|
|
|
14473
14898
|
${pc4.bold("Device code (works on SSH/VPS):")}
|
|
14474
14899
|
openai ChatGPT Plus/Pro (device code at auth.openai.com/codex/device)
|
|
14475
14900
|
|
|
14901
|
+
${pc4.bold("Browser sign-in:")}
|
|
14902
|
+
--browser sign in through your browser instead of a device code \u2014 use this
|
|
14903
|
+
when your workspace admin has disabled device code authorization.
|
|
14904
|
+
Needs a local browser, so it does not work over plain SSH.
|
|
14905
|
+
|
|
14476
14906
|
${pc4.bold("Named accounts:")}
|
|
14477
14907
|
--account <name> store an additional ChatGPT account under a named slot
|
|
14478
14908
|
(the default sign-in is untouched). Select one at launch:
|
|
@@ -14830,6 +15260,7 @@ function parseProvidersArgs(args) {
|
|
|
14830
15260
|
for (let i = 0; i < rest.length; i++) {
|
|
14831
15261
|
const arg = rest[i];
|
|
14832
15262
|
if (arg === "--native") authMethod = "native";
|
|
15263
|
+
else if (arg === "--browser") authMethod = "browser";
|
|
14833
15264
|
else if (arg === "--account") {
|
|
14834
15265
|
const value = rest[i + 1];
|
|
14835
15266
|
if (!value || value.startsWith("-")) {
|
|
@@ -14870,11 +15301,12 @@ ${pc6.bold("Usage:")}
|
|
|
14870
15301
|
clodex providers remove <id>
|
|
14871
15302
|
clodex providers refresh-models [id]
|
|
14872
15303
|
clodex providers auth openai
|
|
15304
|
+
clodex providers auth openai --browser
|
|
14873
15305
|
|
|
14874
15306
|
${pc6.bold("Subcommands:")}
|
|
14875
15307
|
(none) Provider hub wizard
|
|
14876
15308
|
add Add a built-in provider or sign in with ChatGPT
|
|
14877
|
-
auth Sign in with ChatGPT/Codex-plan OAuth (device code)
|
|
15309
|
+
auth Sign in with ChatGPT/Codex-plan OAuth (device code, or --browser)
|
|
14878
15310
|
list Show configured providers
|
|
14879
15311
|
remove Remove a provider by id
|
|
14880
15312
|
refresh-models Update cached model lists`;
|
|
@@ -14999,6 +15431,21 @@ function shouldOfferAccountSwitch(provider) {
|
|
|
14999
15431
|
function providerLabel(name, modelCount, enabled) {
|
|
15000
15432
|
return `${fmtEnabledStar(enabled)} ${fmtProvider(name)} ${pc6.dim(`(${modelCount} model${modelCount === 1 ? "" : "s"})`)}`;
|
|
15001
15433
|
}
|
|
15434
|
+
async function promptOAuthMethod() {
|
|
15435
|
+
const choice = await p5.select({
|
|
15436
|
+
message: "How do you want to sign in?",
|
|
15437
|
+
initialValue: "native",
|
|
15438
|
+
options: [
|
|
15439
|
+
{ value: "native", label: "Device code", hint: "works everywhere, including SSH/VPS" },
|
|
15440
|
+
{ value: "browser", label: "Browser", hint: "for workspaces that disable device code authorization" }
|
|
15441
|
+
]
|
|
15442
|
+
});
|
|
15443
|
+
if (p5.isCancel(choice)) {
|
|
15444
|
+
p5.cancel("Cancelled.");
|
|
15445
|
+
return null;
|
|
15446
|
+
}
|
|
15447
|
+
return choice;
|
|
15448
|
+
}
|
|
15002
15449
|
async function runProvidersAuthWithCleanupState(providerId, method, cleanupState, account) {
|
|
15003
15450
|
try {
|
|
15004
15451
|
const result = await authenticateProvider(providerId, { method, account });
|
|
@@ -15161,7 +15608,7 @@ async function runProvidersAddWithCleanupState(cleanupState) {
|
|
|
15161
15608
|
options.push({
|
|
15162
15609
|
value: "oauth",
|
|
15163
15610
|
label: "Sign in with ChatGPT (Plus/Pro plan)",
|
|
15164
|
-
hint: "OAuth device code \u2014 no API key needed"
|
|
15611
|
+
hint: "OAuth (device code or browser) \u2014 no API key needed"
|
|
15165
15612
|
});
|
|
15166
15613
|
}
|
|
15167
15614
|
for (const template of listRegistryAddableTemplates(providers)) {
|
|
@@ -15184,7 +15631,9 @@ async function runProvidersAddWithCleanupState(cleanupState) {
|
|
|
15184
15631
|
return 0;
|
|
15185
15632
|
}
|
|
15186
15633
|
if (choice === "oauth") {
|
|
15187
|
-
|
|
15634
|
+
const method = await promptOAuthMethod();
|
|
15635
|
+
if (method === null) return 0;
|
|
15636
|
+
return runProvidersAuthWithCleanupState("openai", method, cleanupState);
|
|
15188
15637
|
}
|
|
15189
15638
|
if (typeof choice === "string" && choice.startsWith("api:")) {
|
|
15190
15639
|
return runTemplateAddFlow(choice.slice("api:".length), cleanupState);
|
|
@@ -15324,7 +15773,9 @@ async function runProviderDetail(id) {
|
|
|
15324
15773
|
return "back";
|
|
15325
15774
|
}
|
|
15326
15775
|
if (action === "auth") {
|
|
15327
|
-
|
|
15776
|
+
const method = await promptOAuthMethod();
|
|
15777
|
+
if (method === null) return "back";
|
|
15778
|
+
await runWithCredentialCleanup((state) => runProvidersAuthWithCleanupState(id, method, state));
|
|
15328
15779
|
return "back";
|
|
15329
15780
|
}
|
|
15330
15781
|
if (action === "account") {
|
|
@@ -15419,7 +15870,7 @@ async function runProvidersHub() {
|
|
|
15419
15870
|
}
|
|
15420
15871
|
const configuredIds = new Set(entries.map((entry) => entry.id));
|
|
15421
15872
|
if (listVisibleOAuthTemplates(configuredIds).length > 0) {
|
|
15422
|
-
options.push({ value: "auth-menu", label: "\u2192 Sign in with ChatGPT (OAuth)", hint: "device code" });
|
|
15873
|
+
options.push({ value: "auth-menu", label: "\u2192 Sign in with ChatGPT (OAuth)", hint: "device code or browser" });
|
|
15423
15874
|
} else if (configuredIds.has("openai-oauth")) {
|
|
15424
15875
|
options.push({
|
|
15425
15876
|
value: "auth-account",
|
|
@@ -15447,7 +15898,9 @@ async function runProvidersHub() {
|
|
|
15447
15898
|
continue;
|
|
15448
15899
|
}
|
|
15449
15900
|
if (choice === "auth-menu") {
|
|
15450
|
-
|
|
15901
|
+
const method = await promptOAuthMethod();
|
|
15902
|
+
if (method === null) continue;
|
|
15903
|
+
await runWithCredentialCleanup((state) => runProvidersAuthWithCleanupState("openai", method, state));
|
|
15451
15904
|
continue;
|
|
15452
15905
|
}
|
|
15453
15906
|
if (choice === "auth-account") {
|
|
@@ -15464,7 +15917,9 @@ async function runProvidersHub() {
|
|
|
15464
15917
|
}
|
|
15465
15918
|
});
|
|
15466
15919
|
if (p5.isCancel(name)) continue;
|
|
15467
|
-
|
|
15920
|
+
const accountMethod = await promptOAuthMethod();
|
|
15921
|
+
if (accountMethod === null) continue;
|
|
15922
|
+
await runWithCredentialCleanup((state) => runProvidersAuthWithCleanupState("openai", accountMethod, state, String(name)));
|
|
15468
15923
|
continue;
|
|
15469
15924
|
}
|
|
15470
15925
|
if (typeof choice === "string" && choice.startsWith("provider:")) {
|
|
@@ -15520,7 +15975,7 @@ async function runFirstRunWizard(_trace = false) {
|
|
|
15520
15975
|
{
|
|
15521
15976
|
value: "oauth",
|
|
15522
15977
|
label: pc7.cyan("Sign in with ChatGPT (Plus/Pro plan)"),
|
|
15523
|
-
hint: "OAuth device code \u2014 uses your ChatGPT/Codex plan"
|
|
15978
|
+
hint: "OAuth (device code or browser) \u2014 uses your ChatGPT/Codex plan"
|
|
15524
15979
|
},
|
|
15525
15980
|
{
|
|
15526
15981
|
value: "apikey",
|
|
@@ -15533,7 +15988,14 @@ async function runFirstRunWizard(_trace = false) {
|
|
|
15533
15988
|
p6.cancel("Cancelled.");
|
|
15534
15989
|
return "cancel";
|
|
15535
15990
|
}
|
|
15536
|
-
|
|
15991
|
+
let code;
|
|
15992
|
+
if (choice === "oauth") {
|
|
15993
|
+
const method = await promptOAuthMethod();
|
|
15994
|
+
if (method === null) return "cancel";
|
|
15995
|
+
code = await runProvidersAuth("openai", method);
|
|
15996
|
+
} else {
|
|
15997
|
+
code = await runProvidersAdd();
|
|
15998
|
+
}
|
|
15537
15999
|
if (code !== 0) return "cancel";
|
|
15538
16000
|
if (await needsFirstRunSetup()) return "cancel";
|
|
15539
16001
|
p6.log.success("OpenAI provider ready \u2014 picking a model next.");
|
|
@@ -16660,7 +17122,7 @@ import pc10 from "picocolors";
|
|
|
16660
17122
|
import * as p9 from "@clack/prompts";
|
|
16661
17123
|
|
|
16662
17124
|
// src/http-proxy/server.ts
|
|
16663
|
-
import * as
|
|
17125
|
+
import * as http2 from "http";
|
|
16664
17126
|
import * as https from "https";
|
|
16665
17127
|
import * as net from "net";
|
|
16666
17128
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
@@ -17097,7 +17559,7 @@ function forwardRawAnthropicRequest(req, res, rawBody, origin, rejectUnauthorize
|
|
|
17097
17559
|
upstream.end(rawBody);
|
|
17098
17560
|
});
|
|
17099
17561
|
}
|
|
17100
|
-
function forwardToAdapter(req, res, rawBody, adapter, adapterRequest =
|
|
17562
|
+
function forwardToAdapter(req, res, rawBody, adapter, adapterRequest = http2.request, adapterAgent, lifecycle, isLocalShutdown = () => false) {
|
|
17101
17563
|
return new Promise((resolve3) => {
|
|
17102
17564
|
const startedAt = Date.now();
|
|
17103
17565
|
let lastActivityAt = startedAt;
|
|
@@ -17298,7 +17760,7 @@ function forwardPlainHttp(req, res) {
|
|
|
17298
17760
|
res.end("HTTP proxy requests must use an absolute URL");
|
|
17299
17761
|
return;
|
|
17300
17762
|
}
|
|
17301
|
-
const transport = target.protocol === "https:" ? https :
|
|
17763
|
+
const transport = target.protocol === "https:" ? https : http2;
|
|
17302
17764
|
const upstream = transport.request({
|
|
17303
17765
|
protocol: target.protocol,
|
|
17304
17766
|
hostname: target.hostname,
|
|
@@ -17349,7 +17811,7 @@ async function startHttpProxy(options) {
|
|
|
17349
17811
|
options.modelAliases
|
|
17350
17812
|
);
|
|
17351
17813
|
}
|
|
17352
|
-
const adapterAgent = adapter ? new
|
|
17814
|
+
const adapterAgent = adapter ? new http2.Agent({ keepAlive: true }) : void 0;
|
|
17353
17815
|
let shuttingDown = false;
|
|
17354
17816
|
const mitmServer = https.createServer({
|
|
17355
17817
|
key: certificates.serverKey,
|
|
@@ -17505,7 +17967,7 @@ async function startHttpProxy(options) {
|
|
|
17505
17967
|
);
|
|
17506
17968
|
});
|
|
17507
17969
|
const sockets = /* @__PURE__ */ new Set();
|
|
17508
|
-
const proxyServer =
|
|
17970
|
+
const proxyServer = http2.createServer(forwardPlainHttp);
|
|
17509
17971
|
proxyServer.on("connection", (socket) => {
|
|
17510
17972
|
sockets.add(socket);
|
|
17511
17973
|
socket.once("close", () => sockets.delete(socket));
|