@bman654/clodex 2.18.0 → 2.18.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/README.md +1 -1
- package/dist/cli.js +374 -340
- package/dist/cli.js.map +1 -1
- package/package.json +2 -3
package/dist/cli.js
CHANGED
|
@@ -346,7 +346,7 @@ import { join } from "path";
|
|
|
346
346
|
// package.json
|
|
347
347
|
var package_default = {
|
|
348
348
|
name: "@bman654/clodex",
|
|
349
|
-
version: "2.18.
|
|
349
|
+
version: "2.18.2",
|
|
350
350
|
publishConfig: {
|
|
351
351
|
access: "public"
|
|
352
352
|
},
|
|
@@ -401,10 +401,9 @@ var package_default = {
|
|
|
401
401
|
"https-proxy-agent": "9.1.0",
|
|
402
402
|
"ipaddr.js": "2.4.0",
|
|
403
403
|
"node-forge": "1.4.0",
|
|
404
|
-
"node-gyp-build": "4.8.4",
|
|
405
404
|
open: "11.0.0",
|
|
406
405
|
picocolors: "1.1.1",
|
|
407
|
-
tweakcc: "4.3.
|
|
406
|
+
tweakcc: "4.3.3",
|
|
408
407
|
undici: "7.29.0",
|
|
409
408
|
ws: "8.21.0"
|
|
410
409
|
},
|
|
@@ -3439,7 +3438,7 @@ function savedStopsAfter(current, assignments) {
|
|
|
3439
3438
|
}
|
|
3440
3439
|
|
|
3441
3440
|
// src/patch-transforms.ts
|
|
3442
|
-
var PATCH_TRANSFORMS_VERSION =
|
|
3441
|
+
var PATCH_TRANSFORMS_VERSION = 14;
|
|
3443
3442
|
var NATIVE_EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
|
|
3444
3443
|
var BASE_EFFORT_LEVELS = ["low", "medium", "high"];
|
|
3445
3444
|
function projectNativeEffort(effort) {
|
|
@@ -3617,15 +3616,10 @@ function applyClodexPatches(source, config) {
|
|
|
3617
3616
|
);
|
|
3618
3617
|
}
|
|
3619
3618
|
}
|
|
3619
|
+
const pickerRow = (a) => "{value:" + q(a) + ",label:" + q(a.charAt(0).toUpperCase() + a.slice(1)) + ",description:" + q(displayFor(a, ALIAS_TO_ID[a])) + "}";
|
|
3620
3620
|
{
|
|
3621
3621
|
const missing = ALIASES.filter((a) => !new RegExp("value:" + reEsc(q(a))).test(js));
|
|
3622
|
-
const entries = missing.map(
|
|
3623
|
-
// value = the alias (the name the user types and the binary sends);
|
|
3624
|
-
// description = the real model label, e.g. "GPT-5.6 Sol (OpenAI (ChatGPT))".
|
|
3625
|
-
// (tweakcc's writeContent round-trips utf8 faithfully — verified — so the
|
|
3626
|
-
// old adhoc-patch ASCII-only constraint no longer applies.)
|
|
3627
|
-
(a) => "{value:" + q(a) + ",label:" + q(a.charAt(0).toUpperCase() + a.slice(1)) + ",description:" + q(displayFor(a, ALIAS_TO_ID[a])) + "}"
|
|
3628
|
-
).join(",");
|
|
3622
|
+
const entries = missing.map(pickerRow).join(",");
|
|
3629
3623
|
const injectInto = (options) => missing.length ? "[" + entries + "].forEach(function(_o){if(!" + options + ".some(function(_i){return _i.value===_o.value}))" + options + ".push(_o)});" : "";
|
|
3630
3624
|
const pickerSite = "PATCH 5: model picker options";
|
|
3631
3625
|
const modelSelections = [...js.matchAll(/\(([\w$]+)==="opus"\|\|\1==="sonnet"\)/g)];
|
|
@@ -3642,6 +3636,25 @@ function applyClodexPatches(source, config) {
|
|
|
3642
3636
|
);
|
|
3643
3637
|
}
|
|
3644
3638
|
}
|
|
3639
|
+
{
|
|
3640
|
+
const catalogSite = "PATCH 11: catalog picker options";
|
|
3641
|
+
const catalogMarker = "/*ccpatch:picker*/";
|
|
3642
|
+
const catalogAnchor = /function [\w$]+\(([\w$]+),([\w$]+)\)\{let ([\w$]+)=[\w$]+\(\1,\2\),([\w$]+)=\3\?\?[\w$]+\(\1\)(?=[,;])(?=[\s\S]{0,400}ANTHROPIC_CUSTOM_MODEL_OPTION)/;
|
|
3643
|
+
const entryPoints = source.match(new RegExp(catalogAnchor.source, "g"))?.length ?? 0;
|
|
3644
|
+
const rows = ALIASES.map(pickerRow).join(",");
|
|
3645
|
+
if (ALIASES.length === 0) {
|
|
3646
|
+
log13("SKIP", catalogSite, "no aliases configured");
|
|
3647
|
+
} else if (entryPoints !== 1 && !js.includes(catalogMarker)) {
|
|
3648
|
+
log13("FAIL", catalogSite, entryPoints === 0 ? "anchor not found" : "anchor matched " + entryPoints + " times (expected 1)");
|
|
3649
|
+
} else {
|
|
3650
|
+
applyOnce(
|
|
3651
|
+
catalogSite,
|
|
3652
|
+
catalogAnchor,
|
|
3653
|
+
(m, _first, _second, _catalog, options) => m + ",_ccpick=" + catalogMarker + "[" + rows + "].forEach(function(_o){if(!" + options + ".some(function(_i){return _i.value===_o.value}))" + options + ".push(_o)})",
|
|
3654
|
+
{ marker: catalogMarker, required: false }
|
|
3655
|
+
);
|
|
3656
|
+
}
|
|
3657
|
+
}
|
|
3645
3658
|
{
|
|
3646
3659
|
const safe = (s) => String(s).replace(/`/g, "'").replace(/\$\{/g, "(");
|
|
3647
3660
|
const listing = IDENTITIES.map(function(i) {
|
|
@@ -3873,8 +3886,8 @@ import {
|
|
|
3873
3886
|
statSync as statSync7,
|
|
3874
3887
|
unlinkSync as unlinkSync3,
|
|
3875
3888
|
writeFileSync as writeFileSync5,
|
|
3876
|
-
openSync as
|
|
3877
|
-
closeSync as
|
|
3889
|
+
openSync as openSync9,
|
|
3890
|
+
closeSync as closeSync9,
|
|
3878
3891
|
realpathSync as realpathSync3
|
|
3879
3892
|
} from "fs";
|
|
3880
3893
|
import { homedir as homedir3 } from "os";
|
|
@@ -4148,14 +4161,14 @@ function uniqueMatch(source, name, pattern) {
|
|
|
4148
4161
|
}
|
|
4149
4162
|
return match[0];
|
|
4150
4163
|
}
|
|
4151
|
-
function captureNeedle(source, name, needle) {
|
|
4152
|
-
if (countExactOccurrences(source, needle) !==
|
|
4164
|
+
function captureNeedle(source, name, needle, expected = 1) {
|
|
4165
|
+
if (countExactOccurrences(source, needle) !== expected) {
|
|
4153
4166
|
throw new Error(`clodex patch: could not capture built-in postcondition: ${name}`);
|
|
4154
4167
|
}
|
|
4155
4168
|
return {
|
|
4156
4169
|
name,
|
|
4157
4170
|
protectedText: needle,
|
|
4158
|
-
occurrences:
|
|
4171
|
+
occurrences: expected
|
|
4159
4172
|
};
|
|
4160
4173
|
}
|
|
4161
4174
|
function capturePattern(source, name, pattern) {
|
|
@@ -4215,16 +4228,25 @@ function captureBuiltInPatchProofs(source, config, results) {
|
|
|
4215
4228
|
));
|
|
4216
4229
|
}
|
|
4217
4230
|
}
|
|
4218
|
-
|
|
4231
|
+
const pickerSites = [
|
|
4232
|
+
"PATCH 5: model picker options",
|
|
4233
|
+
"PATCH 11: catalog picker options"
|
|
4234
|
+
].filter((name) => protectsResult(results, name));
|
|
4235
|
+
if (pickerSites.length > 0) {
|
|
4219
4236
|
for (const { alias, id, display } of aliases) {
|
|
4220
4237
|
const entry = "{value:" + JSON.stringify(alias) + ",label:" + JSON.stringify(alias.charAt(0).toUpperCase() + alias.slice(1)) + ",description:" + JSON.stringify(display ?? `Custom model (${id})`) + "}";
|
|
4221
4238
|
proofs.push(captureNeedle(
|
|
4222
4239
|
source,
|
|
4223
|
-
`
|
|
4224
|
-
entry
|
|
4240
|
+
`model picker options (${alias})`,
|
|
4241
|
+
entry,
|
|
4242
|
+
pickerSites.length
|
|
4225
4243
|
));
|
|
4226
4244
|
}
|
|
4227
4245
|
}
|
|
4246
|
+
addPattern(
|
|
4247
|
+
"PATCH 11: catalog picker options",
|
|
4248
|
+
/,_ccpick=\/\*ccpatch:picker\*\/\[[\s\S]*?\]\.forEach\(function\(_o\)\{if\(![\w$]+\.some\(function\(_i\)\{return _i\.value===_o\.value\}\)\)[\w$]+\.push\(_o\)\}\)/
|
|
4249
|
+
);
|
|
4228
4250
|
addPattern(
|
|
4229
4251
|
"PATCH 7: per-model context window",
|
|
4230
4252
|
/\/\*ccpatch:ctx\*\/var _ccw=\(\{[^{}]*\}\)\[[^\]]*\];if\(_ccw!==void 0\)return _ccw;/
|
|
@@ -6064,11 +6086,11 @@ var OPENAI_OAUTH_MODEL_SEEDS = [
|
|
|
6064
6086
|
// program, so most installs will never see this id in their catalog.
|
|
6065
6087
|
{ id: "gpt-daybreak-blue-latest", name: "GPT Daybreak Blue", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true, minimalClientVersion: "0.144.0" },
|
|
6066
6088
|
// GPT-5.6 family (Sol / Terra / Luna)
|
|
6067
|
-
{ id: "gpt-5.6-sol", name: "GPT-5.6 Sol", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, minimalClientVersion: "0.144.0" },
|
|
6068
|
-
{ id: "gpt-5.6-terra", name: "GPT-5.6 Terra", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, minimalClientVersion: "0.144.0" },
|
|
6089
|
+
{ id: "gpt-5.6-sol", name: "GPT-5.6 Sol", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true, minimalClientVersion: "0.144.0" },
|
|
6090
|
+
{ id: "gpt-5.6-terra", name: "GPT-5.6 Terra", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true, minimalClientVersion: "0.144.0" },
|
|
6069
6091
|
{ id: "gpt-5.6-luna", name: "GPT-5.6 Luna", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true, minimalClientVersion: "0.144.0" },
|
|
6070
6092
|
// GPT-5.5 family (Pro)
|
|
6071
|
-
{ id: "gpt-5.5", name: "GPT-5.5", contextWindow: 272e3, maxOutputTokens: 128e3, reasoning: true },
|
|
6093
|
+
{ id: "gpt-5.5", name: "GPT-5.5", contextWindow: 272e3, maxContextWindow: 272e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: false, preferWebSockets: true, minimalClientVersion: "0.124.0" },
|
|
6072
6094
|
// GPT-5.4 family
|
|
6073
6095
|
{ id: "gpt-5.4", name: "GPT-5.4", contextWindow: 272e3, maxContextWindow: 1e6 },
|
|
6074
6096
|
{ id: "gpt-5.4-mini", name: "GPT-5.4 Mini", contextWindow: 272e3 },
|
|
@@ -7380,270 +7402,44 @@ function inspectClaudeNativeBinaryPlaceholder(path) {
|
|
|
7380
7402
|
}
|
|
7381
7403
|
}
|
|
7382
7404
|
|
|
7383
|
-
// src/
|
|
7384
|
-
import { closeSync as closeSync3, openSync as openSync3, readSync as readSync2, statSync as statSync6, writeSync } from "fs";
|
|
7405
|
+
// src/patch-signature.ts
|
|
7385
7406
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
var MODULE_STRUCT_BYTES_CURRENT = 52;
|
|
7390
|
-
var MODULE_STRUCT_BYTES_LEGACY = 36;
|
|
7391
|
-
var CONTENTS_FIELD_AT = 8;
|
|
7392
|
-
var SOURCEMAP_FIELD_AT = 16;
|
|
7393
|
-
var BYTECODE_FIELD_AT = 24;
|
|
7394
|
-
var MODULE_INFO_FIELD_AT = 32;
|
|
7395
|
-
var BYTECODE_ORIGIN_PATH_FIELD_AT = 40;
|
|
7396
|
-
var BUN_BLOB_FLAGS = {
|
|
7397
|
-
/** Every module's source text lies in one run no other region falls inside. */
|
|
7398
|
-
SOURCE_TEXT_CONTIGUOUS: 1 << 4,
|
|
7399
|
-
/** A `[u32; modules]` of each module's source hash follows the module table. */
|
|
7400
|
-
HAS_SOURCE_HASHES: 1 << 5,
|
|
7401
|
-
/** After the source hashes: `u32 count`, then `count` x `{ u32 id, offset, length }`. */
|
|
7402
|
-
HAS_BUILTIN_BYTECODE: 1 << 6,
|
|
7403
|
-
/** After the builtin-bytecode table: one `{ offset, length }` for the shared string table. */
|
|
7404
|
-
HAS_BYTECODE_STRING_TABLE: 1 << 7
|
|
7405
|
-
};
|
|
7406
|
-
var LOADER_FROM_END = 3;
|
|
7407
|
-
var BUN_JAVASCRIPT_LOADER = 1;
|
|
7408
|
-
var MAX_MODULE_NAME_BYTES = 4096;
|
|
7409
|
-
var MIN_SHIMMABLE_NAME_BYTES = 7;
|
|
7410
|
-
function tweakccRecognizesModuleName(name) {
|
|
7411
|
-
return name.endsWith("/claude") || name === "claude" || name.endsWith("/claude.exe") || name === "claude.exe" || name.endsWith("/src/entrypoints/cli.js") || name === "src/entrypoints/cli.js";
|
|
7412
|
-
}
|
|
7413
|
-
function entryModuleShimName(byteLength) {
|
|
7414
|
-
if (byteLength < MIN_SHIMMABLE_NAME_BYTES) return null;
|
|
7415
|
-
const padding = byteLength - MIN_SHIMMABLE_NAME_BYTES;
|
|
7416
|
-
return "/clodex".padEnd(padding, "-").slice(0, padding) + "/claude";
|
|
7417
|
-
}
|
|
7418
|
-
function readAt(fd, length, position) {
|
|
7419
|
-
if (length <= 0 || position < 0) return null;
|
|
7420
|
-
const buffer = Buffer.alloc(length);
|
|
7421
|
-
const read = readSync2(fd, buffer, 0, length, position);
|
|
7422
|
-
return read === length ? buffer : null;
|
|
7423
|
-
}
|
|
7424
|
-
function readBunModuleNames(fd, fileSize) {
|
|
7425
|
-
const tailLength = Math.min(fileSize, TAIL_SCAN_BYTES);
|
|
7426
|
-
const tail = readAt(fd, tailLength, fileSize - tailLength);
|
|
7427
|
-
if (!tail) return null;
|
|
7428
|
-
const tailAt = fileSize - tailLength;
|
|
7429
|
-
for (let searchFrom = tail.length - 1; searchFrom >= 0; ) {
|
|
7430
|
-
const trailerInTail = tail.lastIndexOf(BUN_TRAILER, searchFrom);
|
|
7431
|
-
if (trailerInTail < 0) return null;
|
|
7432
|
-
const parsed = parseBunModuleNamesAt(fd, tailAt + trailerInTail - BUN_OFFSETS_BYTES);
|
|
7433
|
-
if (parsed) return parsed;
|
|
7434
|
-
searchFrom = trailerInTail - 1;
|
|
7435
|
-
}
|
|
7436
|
-
return null;
|
|
7437
|
-
}
|
|
7438
|
-
function parseBunModuleNamesAt(fd, offsetsAt) {
|
|
7439
|
-
try {
|
|
7440
|
-
return parseBunModuleNamesAtUnchecked(fd, offsetsAt);
|
|
7441
|
-
} catch {
|
|
7442
|
-
return null;
|
|
7443
|
-
}
|
|
7444
|
-
}
|
|
7445
|
-
function parseBunModuleNamesAtUnchecked(fd, offsetsAt) {
|
|
7446
|
-
const offsets = readAt(fd, BUN_OFFSETS_BYTES, offsetsAt);
|
|
7447
|
-
if (!offsets) return null;
|
|
7448
|
-
const byteCount = offsets.readBigUInt64LE(0);
|
|
7449
|
-
const modulesOffset = offsets.readUInt32LE(8);
|
|
7450
|
-
const modulesLength = offsets.readUInt32LE(12);
|
|
7451
|
-
const entryPointId = offsets.readUInt32LE(16);
|
|
7452
|
-
const compileExecArgvOffset = offsets.readUInt32LE(20);
|
|
7453
|
-
const compileExecArgvLength = offsets.readUInt32LE(24);
|
|
7454
|
-
const flags = offsets.readUInt32LE(28);
|
|
7455
|
-
if (byteCount <= 0n || byteCount > BigInt(offsetsAt)) return null;
|
|
7456
|
-
const blobAt = offsetsAt - Number(byteCount);
|
|
7457
|
-
if (modulesLength <= 0 || BigInt(modulesOffset) + BigInt(modulesLength) > byteCount) return null;
|
|
7458
|
-
const structBytes = modulesLength % MODULE_STRUCT_BYTES_LEGACY === 0 && modulesLength % MODULE_STRUCT_BYTES_CURRENT !== 0 ? MODULE_STRUCT_BYTES_LEGACY : MODULE_STRUCT_BYTES_CURRENT;
|
|
7459
|
-
const moduleCount = Math.floor(modulesLength / structBytes);
|
|
7460
|
-
if (moduleCount <= 0 || entryPointId >= moduleCount) return null;
|
|
7461
|
-
const modules = readAt(fd, moduleCount * structBytes, blobAt + modulesOffset);
|
|
7462
|
-
if (!modules) return null;
|
|
7463
|
-
const names = [];
|
|
7464
|
-
const nameOffsets = [];
|
|
7465
|
-
const contents = [];
|
|
7466
|
-
const sourcemap = [];
|
|
7467
|
-
const bytecode = [];
|
|
7468
|
-
const moduleInfo = [];
|
|
7469
|
-
const bytecodeOriginPath = [];
|
|
7470
|
-
const loaders = [];
|
|
7471
|
-
for (let index = 0; index < moduleCount; index++) {
|
|
7472
|
-
const nameOffset = modules.readUInt32LE(index * structBytes);
|
|
7473
|
-
const nameLength = modules.readUInt32LE(index * structBytes + 4);
|
|
7474
|
-
if (nameLength <= 0 || nameLength > MAX_MODULE_NAME_BYTES) return null;
|
|
7475
|
-
if (BigInt(nameOffset) + BigInt(nameLength) > byteCount) return null;
|
|
7476
|
-
const bytes = readAt(fd, nameLength + 1, blobAt + nameOffset);
|
|
7477
|
-
if (!bytes || bytes[nameLength] !== 0) return null;
|
|
7478
|
-
const name = bytes.subarray(0, nameLength).toString("utf8");
|
|
7479
|
-
if (!/^[\x20-\x7e]+$/.test(name)) return null;
|
|
7480
|
-
names.push(name);
|
|
7481
|
-
nameOffsets.push(blobAt + nameOffset);
|
|
7482
|
-
const pairAt = (field) => ({
|
|
7483
|
-
offset: modules.readUInt32LE(index * structBytes + field),
|
|
7484
|
-
length: modules.readUInt32LE(index * structBytes + field + 4)
|
|
7485
|
-
});
|
|
7486
|
-
contents.push(pairAt(CONTENTS_FIELD_AT));
|
|
7487
|
-
sourcemap.push(pairAt(SOURCEMAP_FIELD_AT));
|
|
7488
|
-
bytecode.push(pairAt(BYTECODE_FIELD_AT));
|
|
7489
|
-
const current = structBytes === MODULE_STRUCT_BYTES_CURRENT;
|
|
7490
|
-
moduleInfo.push(current ? pairAt(MODULE_INFO_FIELD_AT) : { offset: 0, length: 0 });
|
|
7491
|
-
bytecodeOriginPath.push(
|
|
7492
|
-
current ? pairAt(BYTECODE_ORIGIN_PATH_FIELD_AT) : { offset: 0, length: 0 }
|
|
7493
|
-
);
|
|
7494
|
-
loaders.push(modules.readUInt8(index * structBytes + structBytes - LOADER_FROM_END));
|
|
7495
|
-
}
|
|
7496
|
-
return {
|
|
7497
|
-
names,
|
|
7498
|
-
entryPointId,
|
|
7499
|
-
offsets: nameOffsets,
|
|
7500
|
-
contents,
|
|
7501
|
-
sourcemap,
|
|
7502
|
-
bytecode,
|
|
7503
|
-
moduleInfo,
|
|
7504
|
-
bytecodeOriginPath,
|
|
7505
|
-
loaders,
|
|
7506
|
-
blobAt,
|
|
7507
|
-
modulesAt: blobAt + modulesOffset,
|
|
7508
|
-
modulesOffset,
|
|
7509
|
-
modulesLength,
|
|
7510
|
-
structBytes,
|
|
7511
|
-
byteCount: Number(byteCount),
|
|
7512
|
-
compileExecArgv: { offset: compileExecArgvOffset, length: compileExecArgvLength },
|
|
7513
|
-
flags
|
|
7514
|
-
};
|
|
7515
|
-
}
|
|
7516
|
-
function findStandIn(fd, fileSize, marker) {
|
|
7517
|
-
const needle = Buffer.from(marker);
|
|
7518
|
-
const chunkBytes = 8 * 1024 * 1024;
|
|
7519
|
-
const offsets = [];
|
|
7520
|
-
let carry = Buffer.alloc(0);
|
|
7521
|
-
for (let position = 0; position < fileSize; ) {
|
|
7522
|
-
const length = Math.min(chunkBytes, fileSize - position);
|
|
7523
|
-
const chunk = readAt(fd, length, position);
|
|
7524
|
-
if (!chunk) throw new Error("could not re-read the candidate to verify the entry-module name");
|
|
7525
|
-
const window = carry.length > 0 ? Buffer.concat([carry, chunk]) : chunk;
|
|
7526
|
-
const windowAt = position - carry.length;
|
|
7527
|
-
for (let at = window.indexOf(needle); at >= 0; at = window.indexOf(needle, at + 1)) {
|
|
7528
|
-
offsets.push(windowAt + at);
|
|
7529
|
-
}
|
|
7530
|
-
carry = Buffer.from(window.subarray(Math.max(0, window.length - (needle.length - 1))));
|
|
7531
|
-
position += length;
|
|
7532
|
-
}
|
|
7533
|
-
return offsets;
|
|
7534
|
-
}
|
|
7535
|
-
function restoreEveryStandIn(fd, fileSize, shim) {
|
|
7536
|
-
const moduleNameCopies = () => findStandIn(fd, fileSize, shim.marker).filter((offset) => isModuleNameAt(fd, offset, shim.marker));
|
|
7537
|
-
const found = moduleNameCopies();
|
|
7538
|
-
for (const offset of found) writeNameBytes(fd, shim.original, offset);
|
|
7539
|
-
if (found.length > 0 && moduleNameCopies().length > 0) {
|
|
7540
|
-
throw new Error(`the entry-module stand-in ${shim.marker} survived restoration`);
|
|
7541
|
-
}
|
|
7542
|
-
}
|
|
7543
|
-
function isModuleNameAt(fd, offset, marker) {
|
|
7544
|
-
const after = readAt(fd, 1, offset + Buffer.byteLength(marker));
|
|
7545
|
-
return after !== null && after[0] === 0;
|
|
7546
|
-
}
|
|
7547
|
-
function writeNameBytes(fd, name, offset) {
|
|
7548
|
-
const bytes = Buffer.from(name);
|
|
7549
|
-
const written = writeSync(fd, bytes, 0, bytes.length, offset);
|
|
7550
|
-
if (written !== bytes.length) {
|
|
7551
|
-
throw new Error(`wrote ${written} of ${bytes.length} entry-module name bytes at ${offset}`);
|
|
7552
|
-
}
|
|
7553
|
-
}
|
|
7554
|
-
function isMachO(fd) {
|
|
7555
|
-
const magic = readAt(fd, 4, 0);
|
|
7556
|
-
if (!magic) return false;
|
|
7557
|
-
const value = magic.readUInt32BE(0);
|
|
7558
|
-
return value === 4277009102 || value === 4277009103 || value === 3472551422 || value === 3489328638 || value === 3405691582 || value === 3405691583;
|
|
7559
|
-
}
|
|
7560
|
-
function readBunModuleTable(path) {
|
|
7407
|
+
import { closeSync as closeSync3, openSync as openSync3, readSync as readSync2 } from "fs";
|
|
7408
|
+
function signAndVerifyMachOCandidate(path, installPath = path) {
|
|
7409
|
+
if (process.platform !== "darwin") return;
|
|
7561
7410
|
const fd = openSync3(path, "r");
|
|
7411
|
+
let machO = false;
|
|
7562
7412
|
try {
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
for (let index = 0; index < parsed.names.length; index++) {
|
|
7575
|
-
if (parsed.loaders[index] !== BUN_JAVASCRIPT_LOADER) continue;
|
|
7576
|
-
const range = parsed.contents[index];
|
|
7577
|
-
if (range.offset < 0 || range.length < 0 || range.offset + range.length > parsed.byteCount) {
|
|
7578
|
-
return null;
|
|
7579
|
-
}
|
|
7580
|
-
const bytes = range.length === 0 ? Buffer.alloc(0) : readAt(fd, range.length, parsed.blobAt + range.offset);
|
|
7581
|
-
if (!bytes) return null;
|
|
7582
|
-
modules.push({
|
|
7583
|
-
index,
|
|
7584
|
-
name: parsed.names[index],
|
|
7585
|
-
source: bytes.toString("utf8"),
|
|
7586
|
-
byteLength: bytes.length
|
|
7587
|
-
});
|
|
7588
|
-
}
|
|
7589
|
-
return modules;
|
|
7590
|
-
} finally {
|
|
7591
|
-
closeSync3(fd);
|
|
7592
|
-
}
|
|
7593
|
-
}
|
|
7594
|
-
function shimEntryModuleName(path) {
|
|
7595
|
-
const fd = openSync3(path, "r+");
|
|
7596
|
-
try {
|
|
7597
|
-
const parsed = readBunModuleNames(fd, statSync6(path).size);
|
|
7598
|
-
if (!parsed) return null;
|
|
7599
|
-
if (parsed.names.some(tweakccRecognizesModuleName)) return null;
|
|
7600
|
-
const original = parsed.names[parsed.entryPointId];
|
|
7601
|
-
const offset = parsed.offsets[parsed.entryPointId];
|
|
7602
|
-
const marker = entryModuleShimName(Buffer.byteLength(original));
|
|
7603
|
-
if (marker === null) return null;
|
|
7604
|
-
if (findStandIn(fd, statSync6(path).size, marker).some((offset2) => isModuleNameAt(fd, offset2, marker))) {
|
|
7605
|
-
return null;
|
|
7413
|
+
const magic = Buffer.alloc(4);
|
|
7414
|
+
if (readSync2(fd, magic, 0, 4, 0) === 4) {
|
|
7415
|
+
machO = [
|
|
7416
|
+
4277009102,
|
|
7417
|
+
4277009103,
|
|
7418
|
+
3472551422,
|
|
7419
|
+
3489328638,
|
|
7420
|
+
3405691582,
|
|
7421
|
+
3405691583,
|
|
7422
|
+
3199925962
|
|
7423
|
+
].includes(magic.readUInt32BE(0));
|
|
7606
7424
|
}
|
|
7607
|
-
writeNameBytes(fd, marker, offset);
|
|
7608
|
-
return { offset, original, marker };
|
|
7609
7425
|
} finally {
|
|
7610
7426
|
closeSync3(fd);
|
|
7611
7427
|
}
|
|
7612
|
-
|
|
7613
|
-
function restoreEntryModuleName(path, shim, { resign }) {
|
|
7614
|
-
const fd = openSync3(path, "r+");
|
|
7615
|
-
let machO;
|
|
7428
|
+
if (!machO) return;
|
|
7616
7429
|
try {
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
restoreEveryStandIn(fd, statSync6(path).size, shim);
|
|
7626
|
-
machO = resign;
|
|
7627
|
-
} finally {
|
|
7628
|
-
closeSync3(fd);
|
|
7629
|
-
}
|
|
7630
|
-
if (machO) resignMachOBinary(path);
|
|
7631
|
-
}
|
|
7632
|
-
function resignMachOBinary(path) {
|
|
7633
|
-
const fd = openSync3(path, "r");
|
|
7634
|
-
let machO;
|
|
7635
|
-
try {
|
|
7636
|
-
machO = isMachO(fd);
|
|
7637
|
-
} finally {
|
|
7638
|
-
closeSync3(fd);
|
|
7639
|
-
}
|
|
7640
|
-
if (machO && process.platform === "darwin") {
|
|
7641
|
-
execFileSync2("codesign", ["-s", "-", "-f", path], { stdio: "ignore" });
|
|
7430
|
+
execFileSync2("codesign", ["-s", "-", "-f", path], { stdio: "pipe" });
|
|
7431
|
+
execFileSync2("codesign", ["--verify", "--strict", path], { stdio: "pipe" });
|
|
7432
|
+
} catch (error) {
|
|
7433
|
+
const stderr = error?.stderr;
|
|
7434
|
+
const detail = String(stderr ?? "").trim().split(`${path}: `).join("").split(/\r?\n/).filter((line) => line !== "replacing existing signature").join("\n").trim() || (error instanceof Error ? error.message.trimEnd() : String(error).trimEnd());
|
|
7435
|
+
throw new Error(
|
|
7436
|
+
`Mach-O signing or verification failed for ${installPath}: ${detail}. Claude Code was left unchanged.`
|
|
7437
|
+
);
|
|
7642
7438
|
}
|
|
7643
7439
|
}
|
|
7644
7440
|
|
|
7645
7441
|
// src/bun-compiled-pointer.ts
|
|
7646
|
-
import { closeSync as closeSync4, fstatSync as fstatSync2, openSync as openSync4, readSync as readSync3, writeSync
|
|
7442
|
+
import { closeSync as closeSync4, fstatSync as fstatSync2, openSync as openSync4, readSync as readSync3, writeSync } from "fs";
|
|
7647
7443
|
var TWEAKCC_SCAN_STRIDE = 16384n;
|
|
7648
7444
|
var SCAN_CHUNK = 1 << 20;
|
|
7649
7445
|
var ELF_MAGIC = 1179403647;
|
|
@@ -7651,7 +7447,7 @@ var ELFCLASS64 = 2;
|
|
|
7651
7447
|
var ELFDATA2LSB = 1;
|
|
7652
7448
|
var PT_LOAD = 1;
|
|
7653
7449
|
var PF_W = 2;
|
|
7654
|
-
function
|
|
7450
|
+
function readAt(fd, length, position) {
|
|
7655
7451
|
const buf = Buffer.alloc(length);
|
|
7656
7452
|
let read = 0;
|
|
7657
7453
|
while (read < length) {
|
|
@@ -7662,7 +7458,7 @@ function readAt2(fd, length, position) {
|
|
|
7662
7458
|
return read === length ? buf : buf.subarray(0, read);
|
|
7663
7459
|
}
|
|
7664
7460
|
function readElfLayout(fd) {
|
|
7665
|
-
const ident =
|
|
7461
|
+
const ident = readAt(fd, 64, 0);
|
|
7666
7462
|
if (ident.length < 64) return null;
|
|
7667
7463
|
if (ident.readUInt32LE(0) !== ELF_MAGIC) return null;
|
|
7668
7464
|
if (ident[4] !== ELFCLASS64 || ident[5] !== ELFDATA2LSB) return null;
|
|
@@ -7678,7 +7474,7 @@ function readElfLayout(fd) {
|
|
|
7678
7474
|
const fileSize = fstatSync2(fd).size;
|
|
7679
7475
|
const fits = (offset, length) => Number.isSafeInteger(offset) && offset >= 0 && length >= 0 && offset + length <= fileSize;
|
|
7680
7476
|
if (!fits(Number(shoff), shnum * shentsize)) return null;
|
|
7681
|
-
const shTable =
|
|
7477
|
+
const shTable = readAt(fd, shnum * shentsize, Number(shoff));
|
|
7682
7478
|
if (shTable.length !== shnum * shentsize) return null;
|
|
7683
7479
|
const raw = [];
|
|
7684
7480
|
for (let i = 0; i < shnum; i++) {
|
|
@@ -7692,7 +7488,7 @@ function readElfLayout(fd) {
|
|
|
7692
7488
|
}
|
|
7693
7489
|
const strtab = raw[shstrndx];
|
|
7694
7490
|
if (!fits(Number(strtab.offset), Number(strtab.size))) return null;
|
|
7695
|
-
const names =
|
|
7491
|
+
const names = readAt(fd, Number(strtab.size), Number(strtab.offset));
|
|
7696
7492
|
const sections = raw.map((section) => {
|
|
7697
7493
|
const start = section.nameOffset;
|
|
7698
7494
|
let end = start;
|
|
@@ -7705,7 +7501,7 @@ function readElfLayout(fd) {
|
|
|
7705
7501
|
};
|
|
7706
7502
|
});
|
|
7707
7503
|
if (!fits(Number(phoff), phnum * phentsize)) return null;
|
|
7708
|
-
const phTable =
|
|
7504
|
+
const phTable = readAt(fd, phnum * phentsize, Number(phoff));
|
|
7709
7505
|
if (phTable.length !== phnum * phentsize) return null;
|
|
7710
7506
|
const segments = [];
|
|
7711
7507
|
for (let i = 0; i < phnum; i++) {
|
|
@@ -7742,7 +7538,7 @@ function tweakccWouldFind(fd, segment, needle) {
|
|
|
7742
7538
|
const last = segment.vaddr + segment.filesz - 8n;
|
|
7743
7539
|
for (let vaddr = first; vaddr <= last; vaddr += TWEAKCC_SCAN_STRIDE) {
|
|
7744
7540
|
const at = Number(segment.offset + (vaddr - segment.vaddr));
|
|
7745
|
-
if (
|
|
7541
|
+
if (readAt(fd, 8, at).equals(needle)) return vaddr;
|
|
7746
7542
|
}
|
|
7747
7543
|
return null;
|
|
7748
7544
|
}
|
|
@@ -7751,7 +7547,7 @@ function scanForNeedle(fd, from, to, needle, skipFrom, skipTo) {
|
|
|
7751
7547
|
for (let start = from; start < to; start += SCAN_CHUNK - 7) {
|
|
7752
7548
|
const length = Math.min(SCAN_CHUNK, to - start);
|
|
7753
7549
|
if (length < 8) break;
|
|
7754
|
-
const chunk =
|
|
7550
|
+
const chunk = readAt(fd, length, start);
|
|
7755
7551
|
let at = 0;
|
|
7756
7552
|
for (; ; ) {
|
|
7757
7553
|
const found = chunk.indexOf(needle, at);
|
|
@@ -7809,9 +7605,9 @@ function shimBunCompiledPointer(path) {
|
|
|
7809
7605
|
throw new Error("no address tweakcc's ELF repack scans is usable for Bun's blob pointer");
|
|
7810
7606
|
}
|
|
7811
7607
|
const standInOffset = Number(segment.offset + (standInVaddr - segment.vaddr));
|
|
7812
|
-
const displaced =
|
|
7608
|
+
const displaced = readAt(fd, 8, standInOffset);
|
|
7813
7609
|
if (displaced.length !== 8) throw new Error("could not read the bytes Bun's blob pointer displaces");
|
|
7814
|
-
|
|
7610
|
+
writeSync(fd, needle, 0, 8, standInOffset);
|
|
7815
7611
|
return { pointerVaddr, standInVaddr, displaced, bunVaddr: bun.addr };
|
|
7816
7612
|
} finally {
|
|
7817
7613
|
closeSync4(fd);
|
|
@@ -7831,7 +7627,7 @@ function restoreBunCompiledPointer(path, shim) {
|
|
|
7831
7627
|
"the repack left Bun's blob pointer outside the loaded image, or in more than one segment of it"
|
|
7832
7628
|
);
|
|
7833
7629
|
}
|
|
7834
|
-
const standIn =
|
|
7630
|
+
const standIn = readAt(fd, 8, standInOffset);
|
|
7835
7631
|
if (standIn.length !== 8) {
|
|
7836
7632
|
throw new Error("the repacked binary ends before the stand-in for Bun's blob pointer");
|
|
7837
7633
|
}
|
|
@@ -7846,12 +7642,12 @@ function restoreBunCompiledPointer(path, shim) {
|
|
|
7846
7642
|
}
|
|
7847
7643
|
const value = Buffer.alloc(8);
|
|
7848
7644
|
value.writeBigUInt64LE(written);
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
if (!
|
|
7645
|
+
writeSync(fd, value, 0, 8, pointerOffset);
|
|
7646
|
+
writeSync(fd, shim.displaced, 0, 8, standInOffset);
|
|
7647
|
+
if (!readAt(fd, 8, pointerOffset).equals(value)) {
|
|
7852
7648
|
throw new Error("Bun's blob pointer did not take the repacked address");
|
|
7853
7649
|
}
|
|
7854
|
-
if (!
|
|
7650
|
+
if (!readAt(fd, 8, standInOffset).equals(shim.displaced)) {
|
|
7855
7651
|
throw new Error("the bytes the stand-in displaced were not restored");
|
|
7856
7652
|
}
|
|
7857
7653
|
} finally {
|
|
@@ -7860,13 +7656,185 @@ function restoreBunCompiledPointer(path, shim) {
|
|
|
7860
7656
|
}
|
|
7861
7657
|
|
|
7862
7658
|
// src/bun-bundle.ts
|
|
7863
|
-
import { closeSync as
|
|
7659
|
+
import { closeSync as closeSync6, openSync as openSync6, readSync as readSync5, writeSync as writeSync2 } from "fs";
|
|
7660
|
+
|
|
7661
|
+
// src/bun-module-table.ts
|
|
7662
|
+
import { closeSync as closeSync5, openSync as openSync5, readSync as readSync4, statSync as statSync6 } from "fs";
|
|
7663
|
+
var BUN_TRAILER = Buffer.from("\n---- Bun! ----\n");
|
|
7664
|
+
var BUN_OFFSETS_BYTES = 32;
|
|
7665
|
+
var TAIL_SCAN_BYTES = 16 * 1024 * 1024;
|
|
7666
|
+
var MODULE_STRUCT_BYTES_CURRENT = 52;
|
|
7667
|
+
var MODULE_STRUCT_BYTES_LEGACY = 36;
|
|
7668
|
+
var CONTENTS_FIELD_AT = 8;
|
|
7669
|
+
var SOURCEMAP_FIELD_AT = 16;
|
|
7670
|
+
var BYTECODE_FIELD_AT = 24;
|
|
7671
|
+
var MODULE_INFO_FIELD_AT = 32;
|
|
7672
|
+
var BYTECODE_ORIGIN_PATH_FIELD_AT = 40;
|
|
7673
|
+
var BUN_BLOB_FLAGS = {
|
|
7674
|
+
/** Every module's source text lies in one run no other region falls inside. */
|
|
7675
|
+
SOURCE_TEXT_CONTIGUOUS: 1 << 4,
|
|
7676
|
+
/** A `[u32; modules]` of each module's source hash follows the module table. */
|
|
7677
|
+
HAS_SOURCE_HASHES: 1 << 5,
|
|
7678
|
+
/** After the source hashes: `u32 count`, then `count` x `{ u32 id, offset, length }`. */
|
|
7679
|
+
HAS_BUILTIN_BYTECODE: 1 << 6,
|
|
7680
|
+
/** After the builtin-bytecode table: one `{ offset, length }` for the shared string table. */
|
|
7681
|
+
HAS_BYTECODE_STRING_TABLE: 1 << 7
|
|
7682
|
+
};
|
|
7683
|
+
var LOADER_FROM_END = 3;
|
|
7684
|
+
var BUN_JAVASCRIPT_LOADER = 1;
|
|
7685
|
+
var MAX_MODULE_NAME_BYTES = 4096;
|
|
7686
|
+
function tweakccRecognizesModuleName(name) {
|
|
7687
|
+
return name.endsWith("/claude") || name === "claude" || name.endsWith("/claude.exe") || name === "claude.exe" || name.endsWith("/src/entrypoints/cli.js") || name === "src/entrypoints/cli.js" || name.endsWith("/cli") || name === "cli";
|
|
7688
|
+
}
|
|
7689
|
+
function readAt2(fd, length, position) {
|
|
7690
|
+
if (length <= 0 || position < 0) return null;
|
|
7691
|
+
const buffer = Buffer.alloc(length);
|
|
7692
|
+
const read = readSync4(fd, buffer, 0, length, position);
|
|
7693
|
+
return read === length ? buffer : null;
|
|
7694
|
+
}
|
|
7695
|
+
function readBunModuleNames(fd, fileSize) {
|
|
7696
|
+
const tailLength = Math.min(fileSize, TAIL_SCAN_BYTES);
|
|
7697
|
+
const tail = readAt2(fd, tailLength, fileSize - tailLength);
|
|
7698
|
+
if (!tail) return null;
|
|
7699
|
+
const tailAt = fileSize - tailLength;
|
|
7700
|
+
for (let searchFrom = tail.length - 1; searchFrom >= 0; ) {
|
|
7701
|
+
const trailerInTail = tail.lastIndexOf(BUN_TRAILER, searchFrom);
|
|
7702
|
+
if (trailerInTail < 0) return null;
|
|
7703
|
+
const parsed = parseBunModuleNamesAt(fd, tailAt + trailerInTail - BUN_OFFSETS_BYTES);
|
|
7704
|
+
if (parsed) return parsed;
|
|
7705
|
+
searchFrom = trailerInTail - 1;
|
|
7706
|
+
}
|
|
7707
|
+
return null;
|
|
7708
|
+
}
|
|
7709
|
+
function parseBunModuleNamesAt(fd, offsetsAt) {
|
|
7710
|
+
try {
|
|
7711
|
+
return parseBunModuleNamesAtUnchecked(fd, offsetsAt);
|
|
7712
|
+
} catch {
|
|
7713
|
+
return null;
|
|
7714
|
+
}
|
|
7715
|
+
}
|
|
7716
|
+
function parseBunModuleNamesAtUnchecked(fd, offsetsAt) {
|
|
7717
|
+
const offsets = readAt2(fd, BUN_OFFSETS_BYTES, offsetsAt);
|
|
7718
|
+
if (!offsets) return null;
|
|
7719
|
+
const byteCount = offsets.readBigUInt64LE(0);
|
|
7720
|
+
const modulesOffset = offsets.readUInt32LE(8);
|
|
7721
|
+
const modulesLength = offsets.readUInt32LE(12);
|
|
7722
|
+
const entryPointId = offsets.readUInt32LE(16);
|
|
7723
|
+
const compileExecArgvOffset = offsets.readUInt32LE(20);
|
|
7724
|
+
const compileExecArgvLength = offsets.readUInt32LE(24);
|
|
7725
|
+
const flags = offsets.readUInt32LE(28);
|
|
7726
|
+
if (byteCount <= 0n || byteCount > BigInt(offsetsAt)) return null;
|
|
7727
|
+
const blobAt = offsetsAt - Number(byteCount);
|
|
7728
|
+
if (modulesLength <= 0 || BigInt(modulesOffset) + BigInt(modulesLength) > byteCount) return null;
|
|
7729
|
+
const structBytes = modulesLength % MODULE_STRUCT_BYTES_LEGACY === 0 && modulesLength % MODULE_STRUCT_BYTES_CURRENT !== 0 ? MODULE_STRUCT_BYTES_LEGACY : MODULE_STRUCT_BYTES_CURRENT;
|
|
7730
|
+
const moduleCount = Math.floor(modulesLength / structBytes);
|
|
7731
|
+
if (moduleCount <= 0 || entryPointId >= moduleCount) return null;
|
|
7732
|
+
const modules = readAt2(fd, moduleCount * structBytes, blobAt + modulesOffset);
|
|
7733
|
+
if (!modules) return null;
|
|
7734
|
+
const names = [];
|
|
7735
|
+
const nameOffsets = [];
|
|
7736
|
+
const contents = [];
|
|
7737
|
+
const sourcemap = [];
|
|
7738
|
+
const bytecode = [];
|
|
7739
|
+
const moduleInfo = [];
|
|
7740
|
+
const bytecodeOriginPath = [];
|
|
7741
|
+
const loaders = [];
|
|
7742
|
+
for (let index = 0; index < moduleCount; index++) {
|
|
7743
|
+
const nameOffset = modules.readUInt32LE(index * structBytes);
|
|
7744
|
+
const nameLength = modules.readUInt32LE(index * structBytes + 4);
|
|
7745
|
+
if (nameLength <= 0 || nameLength > MAX_MODULE_NAME_BYTES) return null;
|
|
7746
|
+
if (BigInt(nameOffset) + BigInt(nameLength) > byteCount) return null;
|
|
7747
|
+
const bytes = readAt2(fd, nameLength + 1, blobAt + nameOffset);
|
|
7748
|
+
if (!bytes || bytes[nameLength] !== 0) return null;
|
|
7749
|
+
const name = bytes.subarray(0, nameLength).toString("utf8");
|
|
7750
|
+
if (!/^[\x20-\x7e]+$/.test(name)) return null;
|
|
7751
|
+
names.push(name);
|
|
7752
|
+
nameOffsets.push(blobAt + nameOffset);
|
|
7753
|
+
const pairAt = (field) => ({
|
|
7754
|
+
offset: modules.readUInt32LE(index * structBytes + field),
|
|
7755
|
+
length: modules.readUInt32LE(index * structBytes + field + 4)
|
|
7756
|
+
});
|
|
7757
|
+
contents.push(pairAt(CONTENTS_FIELD_AT));
|
|
7758
|
+
sourcemap.push(pairAt(SOURCEMAP_FIELD_AT));
|
|
7759
|
+
bytecode.push(pairAt(BYTECODE_FIELD_AT));
|
|
7760
|
+
const current = structBytes === MODULE_STRUCT_BYTES_CURRENT;
|
|
7761
|
+
moduleInfo.push(current ? pairAt(MODULE_INFO_FIELD_AT) : { offset: 0, length: 0 });
|
|
7762
|
+
bytecodeOriginPath.push(
|
|
7763
|
+
current ? pairAt(BYTECODE_ORIGIN_PATH_FIELD_AT) : { offset: 0, length: 0 }
|
|
7764
|
+
);
|
|
7765
|
+
loaders.push(modules.readUInt8(index * structBytes + structBytes - LOADER_FROM_END));
|
|
7766
|
+
}
|
|
7767
|
+
return {
|
|
7768
|
+
names,
|
|
7769
|
+
entryPointId,
|
|
7770
|
+
offsets: nameOffsets,
|
|
7771
|
+
contents,
|
|
7772
|
+
sourcemap,
|
|
7773
|
+
bytecode,
|
|
7774
|
+
moduleInfo,
|
|
7775
|
+
bytecodeOriginPath,
|
|
7776
|
+
loaders,
|
|
7777
|
+
blobAt,
|
|
7778
|
+
modulesAt: blobAt + modulesOffset,
|
|
7779
|
+
modulesOffset,
|
|
7780
|
+
modulesLength,
|
|
7781
|
+
structBytes,
|
|
7782
|
+
byteCount: Number(byteCount),
|
|
7783
|
+
compileExecArgv: { offset: compileExecArgvOffset, length: compileExecArgvLength },
|
|
7784
|
+
flags
|
|
7785
|
+
};
|
|
7786
|
+
}
|
|
7787
|
+
function readBunModuleTable(path) {
|
|
7788
|
+
const fd = openSync5(path, "r");
|
|
7789
|
+
try {
|
|
7790
|
+
return readBunModuleNames(fd, statSync6(path).size);
|
|
7791
|
+
} finally {
|
|
7792
|
+
closeSync5(fd);
|
|
7793
|
+
}
|
|
7794
|
+
}
|
|
7795
|
+
function readBunJavaScriptModules(path) {
|
|
7796
|
+
const fd = openSync5(path, "r");
|
|
7797
|
+
try {
|
|
7798
|
+
const parsed = readBunModuleNames(fd, statSync6(path).size);
|
|
7799
|
+
if (!parsed) return null;
|
|
7800
|
+
const modules = [];
|
|
7801
|
+
for (let index = 0; index < parsed.names.length; index++) {
|
|
7802
|
+
if (parsed.loaders[index] !== BUN_JAVASCRIPT_LOADER) continue;
|
|
7803
|
+
const range = parsed.contents[index];
|
|
7804
|
+
if (range.offset < 0 || range.length < 0 || range.offset + range.length > parsed.byteCount) {
|
|
7805
|
+
return null;
|
|
7806
|
+
}
|
|
7807
|
+
const bytes = range.length === 0 ? Buffer.alloc(0) : readAt2(fd, range.length, parsed.blobAt + range.offset);
|
|
7808
|
+
if (!bytes) return null;
|
|
7809
|
+
modules.push({
|
|
7810
|
+
index,
|
|
7811
|
+
name: parsed.names[index],
|
|
7812
|
+
source: bytes.toString("utf8"),
|
|
7813
|
+
byteLength: bytes.length
|
|
7814
|
+
});
|
|
7815
|
+
}
|
|
7816
|
+
return modules;
|
|
7817
|
+
} finally {
|
|
7818
|
+
closeSync5(fd);
|
|
7819
|
+
}
|
|
7820
|
+
}
|
|
7821
|
+
|
|
7822
|
+
// src/bun-bundle.ts
|
|
7864
7823
|
function writableModuleIndex(path) {
|
|
7865
7824
|
const table = readBunModuleTable(path);
|
|
7866
7825
|
if (!table) return null;
|
|
7867
7826
|
const index = table.names.findIndex(tweakccRecognizesModuleName);
|
|
7868
7827
|
return index < 0 ? null : index;
|
|
7869
7828
|
}
|
|
7829
|
+
function assertRecognizedEntryModule(path) {
|
|
7830
|
+
const table = readBunModuleTable(path);
|
|
7831
|
+
if (table && !table.names.some(tweakccRecognizesModuleName)) {
|
|
7832
|
+
const entry = table.names[table.entryPointId];
|
|
7833
|
+
throw new Error(
|
|
7834
|
+
`Claude Code entry module ${JSON.stringify(entry)} is not recognized by tweakcc. Update clodex and try again. Claude Code was left unchanged.`
|
|
7835
|
+
);
|
|
7836
|
+
}
|
|
7837
|
+
}
|
|
7870
7838
|
var BUNDLE_MODULE_SEPARATOR = '\n/*clodex:module-boundary`;{}"]*/\n';
|
|
7871
7839
|
function readClaudeBundle(path) {
|
|
7872
7840
|
const modules = readBunJavaScriptModules(path);
|
|
@@ -7976,18 +7944,18 @@ function placeholderOf(byteLength) {
|
|
|
7976
7944
|
return PLACEHOLDER_TEXT.repeat(Math.ceil(byteLength / PLACEHOLDER_TEXT.length)).slice(0, byteLength);
|
|
7977
7945
|
}
|
|
7978
7946
|
function readBlobData(path, table, into) {
|
|
7979
|
-
const fd =
|
|
7947
|
+
const fd = openSync6(path, "r");
|
|
7980
7948
|
try {
|
|
7981
7949
|
let read = 0;
|
|
7982
7950
|
while (read < table.byteCount) {
|
|
7983
|
-
const got =
|
|
7951
|
+
const got = readSync5(fd, into, read, table.byteCount - read, table.blobAt + read);
|
|
7984
7952
|
if (got <= 0) {
|
|
7985
7953
|
throw new Error(`read ${read} of the ${table.byteCount} blob bytes of ${path}`);
|
|
7986
7954
|
}
|
|
7987
7955
|
read += got;
|
|
7988
7956
|
}
|
|
7989
7957
|
} finally {
|
|
7990
|
-
|
|
7958
|
+
closeSync6(fd);
|
|
7991
7959
|
}
|
|
7992
7960
|
}
|
|
7993
7961
|
function repointModule(data, table, append) {
|
|
@@ -8039,7 +8007,7 @@ function applyBundleWritePlan(path, plan) {
|
|
|
8039
8007
|
}
|
|
8040
8008
|
const offsets = Buffer.from(plan.offsets);
|
|
8041
8009
|
offsets.writeBigUInt64LE(BigInt(byteCount), 0);
|
|
8042
|
-
const fd =
|
|
8010
|
+
const fd = openSync6(path, "r+");
|
|
8043
8011
|
try {
|
|
8044
8012
|
writeAll(fd, plan.data, repacked.blobAt, path);
|
|
8045
8013
|
const padding = byteCount - plan.data.length;
|
|
@@ -8047,7 +8015,7 @@ function applyBundleWritePlan(path, plan) {
|
|
|
8047
8015
|
writeAll(fd, offsets, repacked.blobAt + byteCount, path);
|
|
8048
8016
|
writeAll(fd, BUN_TRAILER2, repacked.blobAt + byteCount + BUN_OFFSETS_BYTES2, path);
|
|
8049
8017
|
} finally {
|
|
8050
|
-
|
|
8018
|
+
closeSync6(fd);
|
|
8051
8019
|
}
|
|
8052
8020
|
const published = readBunModuleTable(path);
|
|
8053
8021
|
if (!published) throw new Error(`cannot re-read the Bun module table of ${path} after publishing its blob`);
|
|
@@ -8075,7 +8043,7 @@ function applyBundleWritePlan(path, plan) {
|
|
|
8075
8043
|
function writeAll(fd, bytes, position, path) {
|
|
8076
8044
|
let written = 0;
|
|
8077
8045
|
while (written < bytes.length) {
|
|
8078
|
-
const wrote =
|
|
8046
|
+
const wrote = writeSync2(fd, bytes, written, bytes.length - written, position + written);
|
|
8079
8047
|
if (wrote <= 0) throw new Error(`wrote ${written} of ${bytes.length} blob bytes to ${path}`);
|
|
8080
8048
|
written += wrote;
|
|
8081
8049
|
}
|
|
@@ -8086,13 +8054,20 @@ import { wrapLanguageModel, extractReasoningMiddleware } from "ai";
|
|
|
8086
8054
|
|
|
8087
8055
|
// src/oauth/responses-websocket.ts
|
|
8088
8056
|
import { createHash as createHash5 } from "crypto";
|
|
8089
|
-
import { closeSync as
|
|
8057
|
+
import { closeSync as closeSync7, openSync as openSync7 } from "fs";
|
|
8090
8058
|
import { devNull } from "os";
|
|
8091
8059
|
import { AsyncLocalStorage } from "async_hooks";
|
|
8092
8060
|
|
|
8093
8061
|
// src/outbound-proxy.ts
|
|
8062
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
8094
8063
|
import { networkInterfaces } from "os";
|
|
8095
8064
|
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
8065
|
+
var OUTBOUND_PROXY_HOP_HEADER = "x-clodex-proxy-hop";
|
|
8066
|
+
var outboundProxyHopNonce = randomUUID3();
|
|
8067
|
+
function isOwnOutboundProxyHop(value) {
|
|
8068
|
+
return (Array.isArray(value) ? value : [value]).some((entry) => entry?.split(",").some((part) => part.trim() === outboundProxyHopNonce));
|
|
8069
|
+
}
|
|
8070
|
+
var proxyHopHeaders = { [OUTBOUND_PROXY_HOP_HEADER]: outboundProxyHopNonce };
|
|
8096
8071
|
function hasOutboundProxyEnv(env = process.env) {
|
|
8097
8072
|
return Boolean(
|
|
8098
8073
|
env["HTTPS_PROXY"]?.trim() || env["https_proxy"]?.trim() || env["HTTP_PROXY"]?.trim() || env["http_proxy"]?.trim()
|
|
@@ -8139,7 +8114,16 @@ function proxyUrlTargetsListener(proxyUrl, listenerHost, listenerPort, localAddr
|
|
|
8139
8114
|
}
|
|
8140
8115
|
const proxyPort = parsed.port ? Number(parsed.port) : parsed.protocol === "https:" ? 443 : parsed.protocol === "http:" ? 80 : void 0;
|
|
8141
8116
|
if (proxyPort !== listenerPort) return false;
|
|
8142
|
-
const normalizeHost = (host) =>
|
|
8117
|
+
const normalizeHost = (host) => {
|
|
8118
|
+
const plain = host.toLowerCase().replace(/^\[|\]$/g, "");
|
|
8119
|
+
const mapped = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(plain);
|
|
8120
|
+
if (mapped) {
|
|
8121
|
+
const high = parseInt(mapped[1], 16);
|
|
8122
|
+
const low = parseInt(mapped[2], 16);
|
|
8123
|
+
return `${high >> 8}.${high & 255}.${low >> 8}.${low & 255}`;
|
|
8124
|
+
}
|
|
8125
|
+
return plain.replace(/^::ffff:(?=\d+\.)/, "").replace(/^localhost\.$/, "localhost");
|
|
8126
|
+
};
|
|
8143
8127
|
const proxyHost = normalizeHost(parsed.hostname);
|
|
8144
8128
|
const boundHost = normalizeHost(listenerHost);
|
|
8145
8129
|
if (proxyHost === boundHost) return true;
|
|
@@ -8172,7 +8156,7 @@ function outboundHttpProxyAgent(targetUrl, env = process.env) {
|
|
|
8172
8156
|
if (!parsedProxy.hostname || !["http:", "https:"].includes(parsedProxy.protocol)) {
|
|
8173
8157
|
throw new TypeError("Invalid proxy URL");
|
|
8174
8158
|
}
|
|
8175
|
-
return new HttpsProxyAgent(parsedProxy, { keepAlive: true });
|
|
8159
|
+
return new HttpsProxyAgent(parsedProxy, { keepAlive: true, headers: { ...proxyHopHeaders } });
|
|
8176
8160
|
} catch (err) {
|
|
8177
8161
|
emitParentNotice(
|
|
8178
8162
|
`clodex: HTTP(S)_PROXY cannot be used for a CONNECT tunnel; using a direct connection (${err instanceof Error ? err.message : String(err)})`
|
|
@@ -9888,7 +9872,7 @@ function descriptorExhaustionCode(error) {
|
|
|
9888
9872
|
const code = error.code;
|
|
9889
9873
|
if (isDescriptorExhaustion(code)) return code;
|
|
9890
9874
|
try {
|
|
9891
|
-
|
|
9875
|
+
closeSync7(openSync7(devNull, "r"));
|
|
9892
9876
|
return void 0;
|
|
9893
9877
|
} catch (probe) {
|
|
9894
9878
|
const probeCode = probe.code;
|
|
@@ -10784,7 +10768,7 @@ function createResponsesWebSocketFetch(wsUrl, log13, options = {}) {
|
|
|
10784
10768
|
}
|
|
10785
10769
|
|
|
10786
10770
|
// src/oauth/claude-identity.ts
|
|
10787
|
-
import { createHash as createHash6, randomUUID as
|
|
10771
|
+
import { createHash as createHash6, randomUUID as randomUUID4 } from "crypto";
|
|
10788
10772
|
var CLAUDE_CODE_CLI_VERSION = "2.1.195";
|
|
10789
10773
|
var CLAUDE_CODE_USER_AGENT = `claude-cli/${CLAUDE_CODE_CLI_VERSION} (external, cli)`;
|
|
10790
10774
|
var CLAUDE_CODE_ENTRYPOINT = process.env.CLAUDE_CODE_ENTRYPOINT ?? "cli";
|
|
@@ -10793,7 +10777,7 @@ var sessionCache = /* @__PURE__ */ new Map();
|
|
|
10793
10777
|
function getOrCreateSessionId(seed) {
|
|
10794
10778
|
let id = sessionCache.get(seed);
|
|
10795
10779
|
if (!id) {
|
|
10796
|
-
id =
|
|
10780
|
+
id = randomUUID4();
|
|
10797
10781
|
sessionCache.set(seed, id);
|
|
10798
10782
|
}
|
|
10799
10783
|
return id;
|
|
@@ -11717,7 +11701,7 @@ function thinkingProviderOptions(npm) {
|
|
|
11717
11701
|
|
|
11718
11702
|
// src/proxy.ts
|
|
11719
11703
|
import { createServer } from "http";
|
|
11720
|
-
import { appendFileSync as appendFileSync2, openSync as
|
|
11704
|
+
import { appendFileSync as appendFileSync2, openSync as openSync8, writeSync as writeSync3, closeSync as closeSync8 } from "fs";
|
|
11721
11705
|
|
|
11722
11706
|
// src/http-utils.ts
|
|
11723
11707
|
import * as zlib from "zlib";
|
|
@@ -11949,7 +11933,7 @@ function routeUnavailableMessage(modelId, reason) {
|
|
|
11949
11933
|
}
|
|
11950
11934
|
|
|
11951
11935
|
// src/upstream-forward.ts
|
|
11952
|
-
import { randomUUID as
|
|
11936
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
11953
11937
|
import { Readable, Transform } from "stream";
|
|
11954
11938
|
import { StringDecoder } from "string_decoder";
|
|
11955
11939
|
|
|
@@ -12046,7 +12030,7 @@ function upstreamHoldsThreads(url) {
|
|
|
12046
12030
|
}
|
|
12047
12031
|
}
|
|
12048
12032
|
function anchorSafeMessageId(id) {
|
|
12049
|
-
return typeof id === "string" && id.startsWith("msg_") ? "clodex_" +
|
|
12033
|
+
return typeof id === "string" && id.startsWith("msg_") ? "clodex_" + randomUUID5().replace(/-/g, "") : id;
|
|
12050
12034
|
}
|
|
12051
12035
|
function isThreadContinuation(body) {
|
|
12052
12036
|
const thread = body.thread;
|
|
@@ -12195,10 +12179,10 @@ async function relayAnthropicMessages(res, messagesUrl, body, apiKey, clientWant
|
|
|
12195
12179
|
}
|
|
12196
12180
|
|
|
12197
12181
|
// src/proxy.ts
|
|
12198
|
-
import { randomUUID as
|
|
12182
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
12199
12183
|
|
|
12200
12184
|
// src/sdk-adapter.ts
|
|
12201
|
-
import { createHash as createHash7, randomUUID as
|
|
12185
|
+
import { createHash as createHash7, randomUUID as randomUUID6 } from "crypto";
|
|
12202
12186
|
import { streamText, generateText, tool, jsonSchema } from "ai";
|
|
12203
12187
|
|
|
12204
12188
|
// src/proxy-shared.ts
|
|
@@ -13042,7 +13026,7 @@ function forwardAbortSignal(source, target) {
|
|
|
13042
13026
|
return () => source.removeEventListener("abort", forward);
|
|
13043
13027
|
}
|
|
13044
13028
|
function translatedMessageId() {
|
|
13045
|
-
return "clodex_" +
|
|
13029
|
+
return "clodex_" + randomUUID6().replace(/-/g, "");
|
|
13046
13030
|
}
|
|
13047
13031
|
async function writeAnthropicStream(stream, modelId, write, log13, observer, tools) {
|
|
13048
13032
|
const messageId = translatedMessageId();
|
|
@@ -13567,12 +13551,12 @@ function createTranslationLifecycle(logPath, requestId, claudeSessionId, modelId
|
|
|
13567
13551
|
function appendSecureLog(logPath, line) {
|
|
13568
13552
|
const redacted = redactTraceLine(line);
|
|
13569
13553
|
try {
|
|
13570
|
-
const fd =
|
|
13554
|
+
const fd = openSync8(logPath, "a", 384);
|
|
13571
13555
|
try {
|
|
13572
|
-
|
|
13556
|
+
writeSync3(fd, `${(/* @__PURE__ */ new Date()).toISOString()} ${redacted}
|
|
13573
13557
|
`);
|
|
13574
13558
|
} finally {
|
|
13575
|
-
|
|
13559
|
+
closeSync8(fd);
|
|
13576
13560
|
}
|
|
13577
13561
|
} catch {
|
|
13578
13562
|
try {
|
|
@@ -13619,7 +13603,7 @@ function configuredAliasLookupNames(alias) {
|
|
|
13619
13603
|
}))].map(normalizeRouteLookupId);
|
|
13620
13604
|
}
|
|
13621
13605
|
async function startProxyCatalog(routes, defaultAliasId, debug = false, inferenceLogPath, debugLogPath, webSocketDiagnosticsLogPath, modelAliases) {
|
|
13622
|
-
const proxyToken =
|
|
13606
|
+
const proxyToken = randomUUID7();
|
|
13623
13607
|
silenceSdkWarnings();
|
|
13624
13608
|
if (routes.length === 0) {
|
|
13625
13609
|
throw new Error("Proxy catalog requires at least one route");
|
|
@@ -14042,7 +14026,7 @@ async function startProxyCatalog(routes, defaultAliasId, debug = false, inferenc
|
|
|
14042
14026
|
res,
|
|
14043
14027
|
upstreamStatus === 500 ? 502 : upstreamStatus,
|
|
14044
14028
|
clientMessage,
|
|
14045
|
-
contextLengthExceeded ? relayRequestId ??
|
|
14029
|
+
contextLengthExceeded ? relayRequestId ?? randomUUID7() : void 0
|
|
14046
14030
|
);
|
|
14047
14031
|
} else {
|
|
14048
14032
|
const errorType = anthropicErrorType(upstreamStatus, details?.transportCode);
|
|
@@ -14050,7 +14034,7 @@ async function startProxyCatalog(routes, defaultAliasId, debug = false, inferenc
|
|
|
14050
14034
|
data: ${JSON.stringify({
|
|
14051
14035
|
type: "error",
|
|
14052
14036
|
error: { type: errorType, message: clientMessage },
|
|
14053
|
-
...contextLengthExceeded ? { request_id: relayRequestId ??
|
|
14037
|
+
...contextLengthExceeded ? { request_id: relayRequestId ?? randomUUID7() } : {}
|
|
14054
14038
|
})}
|
|
14055
14039
|
|
|
14056
14040
|
`);
|
|
@@ -14440,10 +14424,10 @@ function tryAcquirePatchLock(lockPath = getPatchLockPath(), opts = {}) {
|
|
|
14440
14424
|
mkdirSync5(join8(lockPath, ".."), { recursive: true, mode: 448 });
|
|
14441
14425
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
14442
14426
|
try {
|
|
14443
|
-
const fd =
|
|
14427
|
+
const fd = openSync9(lockPath, "wx");
|
|
14444
14428
|
const content = { pid: process.pid, startedAt: now };
|
|
14445
14429
|
writeFileSync5(fd, JSON.stringify(content));
|
|
14446
|
-
|
|
14430
|
+
closeSync9(fd);
|
|
14447
14431
|
return () => {
|
|
14448
14432
|
try {
|
|
14449
14433
|
unlinkSync3(lockPath);
|
|
@@ -14647,7 +14631,7 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14647
14631
|
const candidatePath = join8(candidateDir, basename(binaryPath));
|
|
14648
14632
|
const seedCandidate = async (from) => {
|
|
14649
14633
|
copyFileSync(from, candidatePath);
|
|
14650
|
-
|
|
14634
|
+
assertRecognizedEntryModule(candidatePath);
|
|
14651
14635
|
const installation = await tryDetectInstallation({ path: candidatePath });
|
|
14652
14636
|
const bundle = readClaudeBundle(candidatePath);
|
|
14653
14637
|
if (!bundle && installation.kind === "native") {
|
|
@@ -14656,7 +14640,6 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14656
14640
|
);
|
|
14657
14641
|
}
|
|
14658
14642
|
const source = bundle ? bundle.source : await readContent(installation);
|
|
14659
|
-
if (shim) restoreEntryModuleName(candidatePath, shim, { resign: false });
|
|
14660
14643
|
return { installation, source, bundle };
|
|
14661
14644
|
};
|
|
14662
14645
|
const facts = collectPristineFacts({
|
|
@@ -14766,8 +14749,6 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14766
14749
|
local = discardLocalPatchOutcome(builtIn.content, local.results);
|
|
14767
14750
|
}
|
|
14768
14751
|
results = [...results, ...local.results];
|
|
14769
|
-
const writeShim = shimEntryModuleName(candidatePath);
|
|
14770
|
-
let publishedBlob = false;
|
|
14771
14752
|
if (loaded.bundle) {
|
|
14772
14753
|
const writable = writableModuleIndex(candidatePath);
|
|
14773
14754
|
if (writable === null) {
|
|
@@ -14783,14 +14764,12 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14783
14764
|
await writeContent(loaded.installation, plan2.content);
|
|
14784
14765
|
if (bunPointerShim) restoreBunCompiledPointer(candidatePath, bunPointerShim);
|
|
14785
14766
|
applyBundleWritePlan(candidatePath, plan2);
|
|
14786
|
-
publishedBlob = true;
|
|
14787
14767
|
} else {
|
|
14788
14768
|
const bunPointerShim = shimBunCompiledPointer(candidatePath);
|
|
14789
14769
|
await writeContent(loaded.installation, local.content);
|
|
14790
14770
|
if (bunPointerShim) restoreBunCompiledPointer(candidatePath, bunPointerShim);
|
|
14791
14771
|
}
|
|
14792
|
-
|
|
14793
|
-
else if (publishedBlob) resignMachOBinary(candidatePath);
|
|
14772
|
+
signAndVerifyMachOCandidate(candidatePath, binaryPath);
|
|
14794
14773
|
patchedSize = statSync7(candidatePath).size;
|
|
14795
14774
|
patchedSha256 = sha256File(candidatePath);
|
|
14796
14775
|
renameSync2(candidatePath, binaryPath);
|
|
@@ -15380,15 +15359,15 @@ function localProvidersToServerModels(localProviders) {
|
|
|
15380
15359
|
}
|
|
15381
15360
|
|
|
15382
15361
|
// src/registry/credential-cleanup-journal.ts
|
|
15383
|
-
import { randomUUID as
|
|
15362
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
15384
15363
|
import {
|
|
15385
|
-
closeSync as
|
|
15364
|
+
closeSync as closeSync10,
|
|
15386
15365
|
existsSync as existsSync5,
|
|
15387
15366
|
fstatSync as fstatSync3,
|
|
15388
15367
|
fsyncSync as fsyncSync2,
|
|
15389
15368
|
lstatSync,
|
|
15390
15369
|
mkdirSync as mkdirSync6,
|
|
15391
|
-
openSync as
|
|
15370
|
+
openSync as openSync10,
|
|
15392
15371
|
readFileSync as readFileSync11,
|
|
15393
15372
|
renameSync as renameSync3,
|
|
15394
15373
|
unlinkSync as unlinkSync4,
|
|
@@ -15480,7 +15459,7 @@ function readJournalUnlocked(path) {
|
|
|
15480
15459
|
if (before.isSymbolicLink() || !before.isFile()) {
|
|
15481
15460
|
throw new Error("Credential cleanup journal must be a regular file.");
|
|
15482
15461
|
}
|
|
15483
|
-
fd =
|
|
15462
|
+
fd = openSync10(path, "r");
|
|
15484
15463
|
const opened = fstatSync3(fd);
|
|
15485
15464
|
if (before.dev !== opened.dev || before.ino !== opened.ino) {
|
|
15486
15465
|
throw new Error("Credential cleanup journal changed while opening.");
|
|
@@ -15501,39 +15480,39 @@ function readJournalUnlocked(path) {
|
|
|
15501
15480
|
const message = error instanceof Error ? error.message : String(error);
|
|
15502
15481
|
throw new Error(`Could not read credential cleanup journal: ${message}`);
|
|
15503
15482
|
} finally {
|
|
15504
|
-
if (fd !== void 0)
|
|
15483
|
+
if (fd !== void 0) closeSync10(fd);
|
|
15505
15484
|
}
|
|
15506
15485
|
}
|
|
15507
15486
|
function syncParentDirectory(path) {
|
|
15508
15487
|
let fd;
|
|
15509
15488
|
try {
|
|
15510
|
-
fd =
|
|
15489
|
+
fd = openSync10(dirname6(path), "r");
|
|
15511
15490
|
fsyncSync2(fd);
|
|
15512
15491
|
} catch (error) {
|
|
15513
15492
|
const code = error.code;
|
|
15514
15493
|
if (code !== "EINVAL" && code !== "ENOTSUP" && code !== "EPERM") throw error;
|
|
15515
15494
|
} finally {
|
|
15516
|
-
if (fd !== void 0)
|
|
15495
|
+
if (fd !== void 0) closeSync10(fd);
|
|
15517
15496
|
}
|
|
15518
15497
|
}
|
|
15519
15498
|
function writeJournalUnlocked(journal, path) {
|
|
15520
15499
|
assertRegistryWriteOwnership(path);
|
|
15521
15500
|
ensureSecureAppHome();
|
|
15522
15501
|
mkdirSync6(dirname6(path), { recursive: true, mode: DIR_MODE2 });
|
|
15523
|
-
const tmp = `${path}.${process.pid}.${
|
|
15502
|
+
const tmp = `${path}.${process.pid}.${randomUUID8()}.tmp`;
|
|
15524
15503
|
let fd;
|
|
15525
15504
|
try {
|
|
15526
|
-
fd =
|
|
15505
|
+
fd = openSync10(tmp, "wx", FILE_MODE4);
|
|
15527
15506
|
writeFileSync6(fd, `${JSON.stringify(journal, null, 2)}
|
|
15528
15507
|
`);
|
|
15529
15508
|
fsyncSync2(fd);
|
|
15530
|
-
|
|
15509
|
+
closeSync10(fd);
|
|
15531
15510
|
fd = void 0;
|
|
15532
15511
|
assertRegistryWriteOwnership(path);
|
|
15533
15512
|
renameSync3(tmp, path);
|
|
15534
15513
|
syncParentDirectory(path);
|
|
15535
15514
|
} finally {
|
|
15536
|
-
if (fd !== void 0)
|
|
15515
|
+
if (fd !== void 0) closeSync10(fd);
|
|
15537
15516
|
try {
|
|
15538
15517
|
unlinkSync4(tmp);
|
|
15539
15518
|
} catch (error) {
|
|
@@ -18637,7 +18616,7 @@ async function askSaveServerPassword() {
|
|
|
18637
18616
|
|
|
18638
18617
|
// src/server/router.ts
|
|
18639
18618
|
import { createServer as createServer2 } from "http";
|
|
18640
|
-
import { randomUUID as
|
|
18619
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
18641
18620
|
|
|
18642
18621
|
// src/openai-adapter.ts
|
|
18643
18622
|
import { tool as tool2, jsonSchema as jsonSchema2, streamText as streamText2, generateText as generateText2 } from "ai";
|
|
@@ -19053,7 +19032,7 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
|
19053
19032
|
plog(`model not found: ${body.model}`);
|
|
19054
19033
|
return;
|
|
19055
19034
|
}
|
|
19056
|
-
const requestId =
|
|
19035
|
+
const requestId = randomUUID9();
|
|
19057
19036
|
const claudeSessionIdHeader = Array.isArray(req.headers["x-claude-code-session-id"]) ? req.headers["x-claude-code-session-id"][0] : req.headers["x-claude-code-session-id"];
|
|
19058
19037
|
const claudeSessionId = extractClaudeSessionId(body, claudeSessionIdHeader);
|
|
19059
19038
|
const claudeAgentIds = extractClaudeAgentIds(req.headers);
|
|
@@ -19727,7 +19706,7 @@ import * as http2 from "http";
|
|
|
19727
19706
|
import * as https from "https";
|
|
19728
19707
|
import * as net from "net";
|
|
19729
19708
|
import { PassThrough } from "stream";
|
|
19730
|
-
import { randomUUID as
|
|
19709
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
19731
19710
|
import { URL as URL2 } from "url";
|
|
19732
19711
|
import { createBrotliDecompress, createGunzip, createInflate } from "zlib";
|
|
19733
19712
|
|
|
@@ -20019,7 +19998,7 @@ function requestHeadersWithoutProxyHeaders(req) {
|
|
|
20019
19998
|
const headers = [];
|
|
20020
19999
|
for (let i = 0; i < req.rawHeaders.length; i += 2) {
|
|
20021
20000
|
const name = req.rawHeaders[i];
|
|
20022
|
-
if (/^proxy-(authorization|connection)$/i.test(name)) continue;
|
|
20001
|
+
if (/^proxy-(authorization|connection)$/i.test(name) || name.toLowerCase() === OUTBOUND_PROXY_HOP_HEADER) continue;
|
|
20023
20002
|
headers.push(name, req.rawHeaders[i + 1] ?? "");
|
|
20024
20003
|
}
|
|
20025
20004
|
return headers;
|
|
@@ -20556,6 +20535,7 @@ async function startHttpProxy(options) {
|
|
|
20556
20535
|
const anthropicOrigin = new URL2(options.anthropicOrigin ?? "https://api.anthropic.com");
|
|
20557
20536
|
const anthropicProxyUrl = outboundProxyUrlForTarget(anthropicOrigin.href);
|
|
20558
20537
|
let anthropicAgent;
|
|
20538
|
+
let anthropicViaProxy = false;
|
|
20559
20539
|
let adapter = options.adapterHandle ?? null;
|
|
20560
20540
|
if (options.routes.length > 0) {
|
|
20561
20541
|
adapter ??= await startProxyCatalog(
|
|
@@ -20570,11 +20550,27 @@ async function startHttpProxy(options) {
|
|
|
20570
20550
|
}
|
|
20571
20551
|
const adapterAgent = adapter ? new http2.Agent({ keepAlive: true }) : void 0;
|
|
20572
20552
|
let shuttingDown = false;
|
|
20553
|
+
let warnedProxyLoop = false;
|
|
20554
|
+
const rejectProxyLoop = (target) => {
|
|
20555
|
+
if (warnedProxyLoop) return;
|
|
20556
|
+
warnedProxyLoop = true;
|
|
20557
|
+
const secure = target.startsWith("https:");
|
|
20558
|
+
const candidates = secure ? ["HTTPS_PROXY", "https_proxy"] : ["HTTP_PROXY", "http_proxy"];
|
|
20559
|
+
const name = candidates.find((key) => process.env[key]?.trim()) ?? candidates[0];
|
|
20560
|
+
emitParentNotice(`clodex: outbound proxy loop detected; check ${name} (request returned to this proxy)`);
|
|
20561
|
+
};
|
|
20573
20562
|
const mitmServer = https.createServer({
|
|
20574
20563
|
key: certificates.serverKey,
|
|
20575
20564
|
cert: certificates.serverCert,
|
|
20576
20565
|
minVersion: "TLSv1.2"
|
|
20577
20566
|
}, async (req, res) => {
|
|
20567
|
+
if (isOwnOutboundProxyHop(req.headers[OUTBOUND_PROXY_HOP_HEADER])) {
|
|
20568
|
+
rejectProxyLoop("https://api.anthropic.com");
|
|
20569
|
+
res.writeHead(508, { "Content-Type": "text/plain" });
|
|
20570
|
+
res.end("Outbound proxy loop detected");
|
|
20571
|
+
return;
|
|
20572
|
+
}
|
|
20573
|
+
delete req.headers[OUTBOUND_PROXY_HOP_HEADER];
|
|
20578
20574
|
let rawBody;
|
|
20579
20575
|
try {
|
|
20580
20576
|
rawBody = await readRawBody(req);
|
|
@@ -20585,7 +20581,7 @@ async function startHttpProxy(options) {
|
|
|
20585
20581
|
}
|
|
20586
20582
|
const messagesEndpoint = anthropicMessagesEndpoint(req.url);
|
|
20587
20583
|
if (req.method === "POST" && messagesEndpoint) {
|
|
20588
|
-
const requestId =
|
|
20584
|
+
const requestId = randomUUID10();
|
|
20589
20585
|
let parsed = null;
|
|
20590
20586
|
let route;
|
|
20591
20587
|
let adapterBody = rawBody;
|
|
@@ -20733,6 +20729,12 @@ async function startHttpProxy(options) {
|
|
|
20733
20729
|
return connectTunnelAgents.get(proxyUrl);
|
|
20734
20730
|
};
|
|
20735
20731
|
mitmServer.on("upgrade", (req, socket, head) => {
|
|
20732
|
+
if (isOwnOutboundProxyHop(req.headers[OUTBOUND_PROXY_HOP_HEADER])) {
|
|
20733
|
+
rejectProxyLoop("https://api.anthropic.com");
|
|
20734
|
+
socket.once("error", () => socket.destroy());
|
|
20735
|
+
socket.end("HTTP/1.1 508 Loop Detected\r\nConnection: close\r\n\r\n", () => socket.destroy());
|
|
20736
|
+
return;
|
|
20737
|
+
}
|
|
20736
20738
|
forwardAnthropicUpgrade(
|
|
20737
20739
|
req,
|
|
20738
20740
|
socket,
|
|
@@ -20743,13 +20745,40 @@ async function startHttpProxy(options) {
|
|
|
20743
20745
|
sockets
|
|
20744
20746
|
);
|
|
20745
20747
|
});
|
|
20746
|
-
const proxyServer = http2.createServer(
|
|
20748
|
+
const proxyServer = http2.createServer((req, res) => {
|
|
20749
|
+
if (isOwnOutboundProxyHop(req.headers[OUTBOUND_PROXY_HOP_HEADER])) {
|
|
20750
|
+
rejectProxyLoop(req.url ?? "");
|
|
20751
|
+
res.writeHead(508, { "Content-Type": "text/plain" });
|
|
20752
|
+
res.end("Outbound proxy loop detected");
|
|
20753
|
+
return;
|
|
20754
|
+
}
|
|
20755
|
+
forwardPlainHttp(req, res);
|
|
20756
|
+
});
|
|
20747
20757
|
proxyServer.on("connection", (socket) => {
|
|
20748
20758
|
sockets.add(socket);
|
|
20749
20759
|
socket.once("close", () => sockets.delete(socket));
|
|
20750
20760
|
});
|
|
20751
20761
|
proxyServer.on("connect", (req, clientSocket, head) => {
|
|
20762
|
+
const ownHop = isOwnOutboundProxyHop(req.headers[OUTBOUND_PROXY_HOP_HEADER]);
|
|
20763
|
+
const rejectOwnHop = () => {
|
|
20764
|
+
rejectProxyLoop(`https://${req.url ?? ""}`);
|
|
20765
|
+
clientSocket.once("error", () => clientSocket.destroy());
|
|
20766
|
+
const body = "Outbound proxy loop detected";
|
|
20767
|
+
clientSocket.end(
|
|
20768
|
+
`HTTP/1.1 508 Loop Detected\r
|
|
20769
|
+
Content-Type: text/plain\r
|
|
20770
|
+
Content-Length: ${Buffer.byteLength(body)}\r
|
|
20771
|
+
Connection: close\r
|
|
20772
|
+
\r
|
|
20773
|
+
${body}`,
|
|
20774
|
+
() => clientSocket.destroy()
|
|
20775
|
+
);
|
|
20776
|
+
};
|
|
20752
20777
|
if (shouldInterceptConnect(req.url ?? "")) {
|
|
20778
|
+
if (ownHop && anthropicViaProxy) {
|
|
20779
|
+
rejectOwnHop();
|
|
20780
|
+
return;
|
|
20781
|
+
}
|
|
20753
20782
|
clientSocket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
|
|
20754
20783
|
if (head.length > 0) clientSocket.unshift(head);
|
|
20755
20784
|
mitmServer.emit("connection", clientSocket);
|
|
@@ -20772,6 +20801,10 @@ async function startHttpProxy(options) {
|
|
|
20772
20801
|
);
|
|
20773
20802
|
}
|
|
20774
20803
|
const outboundAgent = outboundProxyUrl !== void 0 && !selfTargeting ? connectTunnelAgent(outboundProxyUrl, targetUrl) : void 0;
|
|
20804
|
+
if (ownHop && outboundAgent) {
|
|
20805
|
+
rejectOwnHop();
|
|
20806
|
+
return;
|
|
20807
|
+
}
|
|
20775
20808
|
if (outboundAgent) {
|
|
20776
20809
|
let upstream2;
|
|
20777
20810
|
let proxyConnectStatus;
|
|
@@ -20790,7 +20823,7 @@ async function startHttpProxy(options) {
|
|
|
20790
20823
|
if (proxyConnectStatus !== 200 || clientSocket.destroyed) {
|
|
20791
20824
|
connected.destroy();
|
|
20792
20825
|
if (!clientSocket.destroyed) {
|
|
20793
|
-
clientSocket.end("HTTP/1.1 502 Bad Gateway\r\n\r\n", () => clientSocket.destroy());
|
|
20826
|
+
clientSocket.end(proxyConnectStatus === 508 ? "HTTP/1.1 508 Loop Detected\r\n\r\n" : "HTTP/1.1 502 Bad Gateway\r\n\r\n", () => clientSocket.destroy());
|
|
20794
20827
|
}
|
|
20795
20828
|
return;
|
|
20796
20829
|
}
|
|
@@ -20868,6 +20901,7 @@ async function startHttpProxy(options) {
|
|
|
20868
20901
|
);
|
|
20869
20902
|
} else {
|
|
20870
20903
|
anthropicAgent = outboundHttpProxyAgent(anthropicOrigin.href);
|
|
20904
|
+
anthropicViaProxy = anthropicAgent !== void 0;
|
|
20871
20905
|
}
|
|
20872
20906
|
anthropicAgent ??= createPassthroughAgent();
|
|
20873
20907
|
return {
|