@bman654/clodex 2.8.2 → 2.8.4
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 +8 -1
- package/dist/cli.js +435 -116
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -382,7 +382,7 @@ import { join } from "path";
|
|
|
382
382
|
// package.json
|
|
383
383
|
var package_default = {
|
|
384
384
|
name: "@bman654/clodex",
|
|
385
|
-
version: "2.8.
|
|
385
|
+
version: "2.8.4",
|
|
386
386
|
publishConfig: {
|
|
387
387
|
access: "public"
|
|
388
388
|
},
|
|
@@ -3423,7 +3423,7 @@ function savedStopsAfter(current, assignments) {
|
|
|
3423
3423
|
}
|
|
3424
3424
|
|
|
3425
3425
|
// src/patch-transforms.ts
|
|
3426
|
-
var PATCH_TRANSFORMS_VERSION =
|
|
3426
|
+
var PATCH_TRANSFORMS_VERSION = 11;
|
|
3427
3427
|
var NATIVE_EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
|
|
3428
3428
|
var BASE_EFFORT_LEVELS = ["low", "medium", "high"];
|
|
3429
3429
|
function projectNativeEffort(effort) {
|
|
@@ -3633,19 +3633,19 @@ function applyClodexPatches(source, config) {
|
|
|
3633
3633
|
}
|
|
3634
3634
|
if (Object.keys(CONTEXT_BY_KEY).length) {
|
|
3635
3635
|
const MARKER = "/*ccpatch:ctx*/";
|
|
3636
|
-
const
|
|
3636
|
+
const snippetFor = (modelParam) => MARKER + "var _ccw=(" + JSON.stringify(CONTEXT_BY_KEY) + ")[String(" + modelParam + '||"").trim().toLowerCase()];if(_ccw!==void 0)return _ccw;';
|
|
3637
3637
|
if (js.includes(MARKER)) {
|
|
3638
3638
|
applyOnce(
|
|
3639
3639
|
"PATCH 7: per-model context window (refresh)",
|
|
3640
|
-
/\/\*ccpatch:ctx\*\/var _ccw=\(\{[^{}]*\}\)\[[
|
|
3641
|
-
() =>
|
|
3640
|
+
/\/\*ccpatch:ctx\*\/var _ccw=\(\{[^{}]*\}\)\[String\(([\w$]+)\|\|""\)\.trim\(\)\.toLowerCase\(\)\];if\(_ccw!==void 0\)return _ccw;/,
|
|
3641
|
+
(_m, modelParam) => snippetFor(modelParam),
|
|
3642
3642
|
{ required: true, noopIsSkip: true }
|
|
3643
3643
|
);
|
|
3644
3644
|
} else {
|
|
3645
3645
|
applyOnce(
|
|
3646
3646
|
"PATCH 7: per-model context window",
|
|
3647
|
-
/(function [\w$]+\(
|
|
3648
|
-
(_m, head, body) => head +
|
|
3647
|
+
/(function [\w$]+\(([\w$]+),([\w$]+)\)\{)(let [\w$]+=[\w$]+\(\);if\([\w$]+!==void 0\)return [\w$]+;if\([\w$]+\(\2,\3\)\)return [\w$]+;return [\w$]+\(\2,\3\)\})/,
|
|
3648
|
+
(_m, head, modelParam, _windowParam, body) => head + snippetFor(modelParam) + body,
|
|
3649
3649
|
{ required: true }
|
|
3650
3650
|
);
|
|
3651
3651
|
}
|
|
@@ -3727,15 +3727,15 @@ function applyClodexPatches(source, config) {
|
|
|
3727
3727
|
const marker = "/*ccpatch:child-network-env*/";
|
|
3728
3728
|
const contractVar = q(NETWORK_ENV_CONTRACT_VAR);
|
|
3729
3729
|
const networkVars = JSON.stringify(CHILD_NETWORK_ENV_VARS);
|
|
3730
|
-
const requiredBodyLiterals = [
|
|
3731
|
-
|
|
3732
|
-
"CLAUDE_CODE_REMOTE",
|
|
3730
|
+
const requiredBodyLiterals = ["{...process.env"];
|
|
3731
|
+
const scrubbedEnvNames = [
|
|
3733
3732
|
"CLAUDE_CODE_OAUTH_TOKEN",
|
|
3734
3733
|
"CLAUDE_CODE_SUBSCRIPTION_TYPE",
|
|
3735
3734
|
"CLAUDE_BG_PTY_AUTH",
|
|
3736
3735
|
'"OTEL_"',
|
|
3737
3736
|
"CLAUDE_CODE_OTEL_DIAG_STDERR"
|
|
3738
3737
|
];
|
|
3738
|
+
const MIN_SCRUBBED_ENV_NAMES = 1;
|
|
3739
3739
|
const blockEndIndex = (text5, open2) => {
|
|
3740
3740
|
const depths = [0];
|
|
3741
3741
|
const templates = [false];
|
|
@@ -3815,11 +3815,15 @@ function applyClodexPatches(source, config) {
|
|
|
3815
3815
|
/(function [\w$]+\(\)\{)(let (?:[^;{}]|\{[^;{}]*\})*?[\w$]+\(process\.env\.CLAUDE_CODE_REMOTE\)\?(?:(?!\}\s*function )[\s\S])*?\)return process\.env;let ([\w$]+)=\{(?:(?!\}\s*function )[\s\S])*?return \3)(\})/,
|
|
3816
3816
|
(match, head, body, _copyVar, tail) => {
|
|
3817
3817
|
const at = js.indexOf(match);
|
|
3818
|
-
const
|
|
3819
|
-
const
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3818
|
+
const closingBrace = at < 0 ? -1 : blockEndIndex(js, at + head.length - 1);
|
|
3819
|
+
const braceScanFailed = at < 0 || closingBrace < 0;
|
|
3820
|
+
const bound = braceScanFailed ? 0 : closingBrace - at - (match.length - 1);
|
|
3821
|
+
const missingLiteral = requiredBodyLiterals.find((literal) => !body.includes(literal));
|
|
3822
|
+
const scrubbedSeen = scrubbedEnvNames.filter((name) => body.includes(name));
|
|
3823
|
+
const why = missingLiteral !== void 0 ? "body does not contain " + missingLiteral : scrubbedSeen.length < MIN_SCRUBBED_ENV_NAMES ? "body scrubs only " + scrubbedSeen.length + " of the " + scrubbedEnvNames.length + " known child-env names (expected at least " + MIN_SCRUBBED_ENV_NAMES + ")" : /\bfunction\s*[\w$]*\(/.test(body) ? "body declares a nested function" : braceScanFailed ? "the brace walk never reached the function's closing brace" : bound !== 0 ? "match ends " + bound + " characters from the function it started in" : void 0;
|
|
3824
|
+
if (why !== void 0) {
|
|
3825
|
+
log12("FAIL", patchName, "target validation failed: " + why);
|
|
3826
|
+
fail("clodex patch: child network environment target validation failed: " + why);
|
|
3823
3827
|
}
|
|
3824
3828
|
const restoredBody = body.replace(/process\.env/g, "_clodexChildEnv");
|
|
3825
3829
|
const restore = marker + "let _clodexChildEnv=process.env,_clodexNetworkRaw=_clodexChildEnv[" + contractVar + "];if(_clodexNetworkRaw!==void 0){_clodexChildEnv={..._clodexChildEnv};delete _clodexChildEnv[" + contractVar + '];try{let _clodexNetwork=JSON.parse(_clodexNetworkRaw);if(_clodexNetwork&&typeof _clodexNetwork==="object"&&!Array.isArray(_clodexNetwork)&&_clodexNetwork.version===1&&_clodexNetwork.original&&typeof _clodexNetwork.original==="object"&&!Array.isArray(_clodexNetwork.original)&&_clodexNetwork.injected&&typeof _clodexNetwork.injected==="object"&&!Array.isArray(_clodexNetwork.injected)&&Object.keys(_clodexNetwork.original).every(_clodexKey=>' + networkVars + '.includes(_clodexKey)&&(typeof _clodexNetwork.original[_clodexKey]==="string"||_clodexNetwork.original[_clodexKey]===null)&&Object.prototype.hasOwnProperty.call(_clodexNetwork.injected,_clodexKey))&&Object.keys(_clodexNetwork.injected).every(_clodexKey=>' + networkVars + '.includes(_clodexKey)&&(typeof _clodexNetwork.injected[_clodexKey]==="string"||_clodexNetwork.injected[_clodexKey]===null)&&Object.prototype.hasOwnProperty.call(_clodexNetwork.original,_clodexKey)))for(let _clodexKey of ' + networkVars + '){if(Object.prototype.hasOwnProperty.call(_clodexNetwork.original,_clodexKey)&&Object.prototype.hasOwnProperty.call(_clodexNetwork.injected,_clodexKey)){let _clodexOriginal=_clodexNetwork.original[_clodexKey],_clodexInjected=_clodexNetwork.injected[_clodexKey],_clodexCurrent=_clodexChildEnv[_clodexKey]===void 0?null:_clodexChildEnv[_clodexKey];if((typeof _clodexOriginal==="string"||_clodexOriginal===null)&&(typeof _clodexInjected==="string"||_clodexInjected===null)&&_clodexCurrent===_clodexInjected){if(_clodexOriginal===null)delete _clodexChildEnv[_clodexKey];else _clodexChildEnv[_clodexKey]=_clodexOriginal}}}}catch(_clodexError){}}';
|
|
@@ -3844,8 +3848,8 @@ import {
|
|
|
3844
3848
|
statSync as statSync6,
|
|
3845
3849
|
unlinkSync as unlinkSync3,
|
|
3846
3850
|
writeFileSync as writeFileSync5,
|
|
3847
|
-
openSync as
|
|
3848
|
-
closeSync as
|
|
3851
|
+
openSync as openSync6,
|
|
3852
|
+
closeSync as closeSync6,
|
|
3849
3853
|
realpathSync
|
|
3850
3854
|
} from "fs";
|
|
3851
3855
|
import { homedir as homedir3 } from "os";
|
|
@@ -6201,6 +6205,7 @@ function writeInferenceResponseLifecycleLog(path, entry) {
|
|
|
6201
6205
|
const outputTokens = nonNegativeInteger(entry.outputTokens);
|
|
6202
6206
|
const cacheCreationInputTokens = nonNegativeInteger(entry.cacheCreationInputTokens);
|
|
6203
6207
|
const cacheReadInputTokens = nonNegativeInteger(entry.cacheReadInputTokens);
|
|
6208
|
+
const attempt = nonNegativeInteger(entry.attempt);
|
|
6204
6209
|
writeSecureLogLine(path, JSON.stringify({
|
|
6205
6210
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6206
6211
|
event: entry.event,
|
|
@@ -6231,7 +6236,9 @@ function writeInferenceResponseLifecycleLog(path, entry) {
|
|
|
6231
6236
|
...entry.errorCode ? { errorCode: compactLogValue(entry.errorCode, 100) } : {},
|
|
6232
6237
|
...entry.errorSignature ? { errorSignature: compactLogValue(entry.errorSignature, 100) } : {},
|
|
6233
6238
|
...entry.failureSource ? { failureSource: entry.failureSource } : {},
|
|
6234
|
-
...entry.terminationSource ? { terminationSource: entry.terminationSource } : {}
|
|
6239
|
+
...entry.terminationSource ? { terminationSource: entry.terminationSource } : {},
|
|
6240
|
+
...attempt !== void 0 ? { attempt } : {},
|
|
6241
|
+
...entry.reusedSocket !== void 0 ? { reusedSocket: entry.reusedSocket } : {}
|
|
6235
6242
|
}));
|
|
6236
6243
|
}
|
|
6237
6244
|
function writeProxyLifecycleLog(path, entry) {
|
|
@@ -7058,8 +7065,208 @@ function resignMachOBinary(path) {
|
|
|
7058
7065
|
}
|
|
7059
7066
|
}
|
|
7060
7067
|
|
|
7061
|
-
// src/bun-
|
|
7068
|
+
// src/bun-compiled-pointer.ts
|
|
7062
7069
|
import { closeSync as closeSync3, openSync as openSync3, readSync as readSync2, writeSync as writeSync3 } from "fs";
|
|
7070
|
+
var TWEAKCC_SCAN_STRIDE = 16384n;
|
|
7071
|
+
var SCAN_CHUNK = 1 << 20;
|
|
7072
|
+
var ELF_MAGIC = 1179403647;
|
|
7073
|
+
var ELFCLASS64 = 2;
|
|
7074
|
+
var ELFDATA2LSB = 1;
|
|
7075
|
+
var PT_LOAD = 1;
|
|
7076
|
+
var PF_W = 2;
|
|
7077
|
+
function readAt2(fd, length, position) {
|
|
7078
|
+
const buf = Buffer.alloc(length);
|
|
7079
|
+
let read = 0;
|
|
7080
|
+
while (read < length) {
|
|
7081
|
+
const n = readSync2(fd, buf, read, length - read, position + read);
|
|
7082
|
+
if (n <= 0) break;
|
|
7083
|
+
read += n;
|
|
7084
|
+
}
|
|
7085
|
+
return read === length ? buf : buf.subarray(0, read);
|
|
7086
|
+
}
|
|
7087
|
+
function readElfLayout(fd) {
|
|
7088
|
+
const ident = readAt2(fd, 64, 0);
|
|
7089
|
+
if (ident.length < 64) return null;
|
|
7090
|
+
if (ident.readUInt32LE(0) !== ELF_MAGIC) return null;
|
|
7091
|
+
if (ident[4] !== ELFCLASS64 || ident[5] !== ELFDATA2LSB) return null;
|
|
7092
|
+
const phoff = ident.readBigUInt64LE(32);
|
|
7093
|
+
const shoff = ident.readBigUInt64LE(40);
|
|
7094
|
+
const phentsize = ident.readUInt16LE(54);
|
|
7095
|
+
const phnum = ident.readUInt16LE(56);
|
|
7096
|
+
const shentsize = ident.readUInt16LE(58);
|
|
7097
|
+
const shnum = ident.readUInt16LE(60);
|
|
7098
|
+
const shstrndx = ident.readUInt16LE(62);
|
|
7099
|
+
if (shnum === 0 || phnum === 65535) return null;
|
|
7100
|
+
if (shstrndx >= shnum || shentsize < 64 || phentsize < 56) return null;
|
|
7101
|
+
const shTable = readAt2(fd, shnum * shentsize, Number(shoff));
|
|
7102
|
+
if (shTable.length !== shnum * shentsize) return null;
|
|
7103
|
+
const raw = [];
|
|
7104
|
+
for (let i = 0; i < shnum; i++) {
|
|
7105
|
+
const at = i * shentsize;
|
|
7106
|
+
raw.push({
|
|
7107
|
+
nameOffset: shTable.readUInt32LE(at),
|
|
7108
|
+
addr: shTable.readBigUInt64LE(at + 16),
|
|
7109
|
+
offset: shTable.readBigUInt64LE(at + 24),
|
|
7110
|
+
size: shTable.readBigUInt64LE(at + 32)
|
|
7111
|
+
});
|
|
7112
|
+
}
|
|
7113
|
+
const strtab = raw[shstrndx];
|
|
7114
|
+
const names = readAt2(fd, Number(strtab.size), Number(strtab.offset));
|
|
7115
|
+
const sections = raw.map((section) => {
|
|
7116
|
+
const start = section.nameOffset;
|
|
7117
|
+
let end = start;
|
|
7118
|
+
while (end < names.length && names[end] !== 0) end++;
|
|
7119
|
+
return {
|
|
7120
|
+
name: names.toString("utf8", start, end),
|
|
7121
|
+
addr: section.addr,
|
|
7122
|
+
offset: section.offset,
|
|
7123
|
+
size: section.size
|
|
7124
|
+
};
|
|
7125
|
+
});
|
|
7126
|
+
const phTable = readAt2(fd, phnum * phentsize, Number(phoff));
|
|
7127
|
+
if (phTable.length !== phnum * phentsize) return null;
|
|
7128
|
+
const segments = [];
|
|
7129
|
+
for (let i = 0; i < phnum; i++) {
|
|
7130
|
+
const at = i * phentsize;
|
|
7131
|
+
segments.push({
|
|
7132
|
+
type: phTable.readUInt32LE(at),
|
|
7133
|
+
flags: phTable.readUInt32LE(at + 4),
|
|
7134
|
+
offset: phTable.readBigUInt64LE(at + 8),
|
|
7135
|
+
vaddr: phTable.readBigUInt64LE(at + 16),
|
|
7136
|
+
filesz: phTable.readBigUInt64LE(at + 32)
|
|
7137
|
+
});
|
|
7138
|
+
}
|
|
7139
|
+
return { sections, segments };
|
|
7140
|
+
}
|
|
7141
|
+
function alignUp(value, to) {
|
|
7142
|
+
return (value + to - 1n) / to * to;
|
|
7143
|
+
}
|
|
7144
|
+
function writableLoad(layout) {
|
|
7145
|
+
return layout.segments.find((segment) => segment.type === PT_LOAD && (segment.flags & PF_W) !== 0);
|
|
7146
|
+
}
|
|
7147
|
+
function fileOffsetOf(layout, vaddr, length) {
|
|
7148
|
+
let found = null;
|
|
7149
|
+
for (const segment of layout.segments) {
|
|
7150
|
+
if (segment.type !== PT_LOAD) continue;
|
|
7151
|
+
if (vaddr < segment.vaddr) continue;
|
|
7152
|
+
if (vaddr + length > segment.vaddr + segment.filesz) continue;
|
|
7153
|
+
if (found !== null) return null;
|
|
7154
|
+
found = Number(segment.offset + (vaddr - segment.vaddr));
|
|
7155
|
+
}
|
|
7156
|
+
return found;
|
|
7157
|
+
}
|
|
7158
|
+
function tweakccWouldFind(fd, segment, needle) {
|
|
7159
|
+
const first = alignUp(segment.vaddr, TWEAKCC_SCAN_STRIDE);
|
|
7160
|
+
const last = segment.vaddr + segment.filesz - 8n;
|
|
7161
|
+
for (let vaddr = first; vaddr <= last; vaddr += TWEAKCC_SCAN_STRIDE) {
|
|
7162
|
+
const at = Number(segment.offset + (vaddr - segment.vaddr));
|
|
7163
|
+
if (readAt2(fd, 8, at).equals(needle)) return vaddr;
|
|
7164
|
+
}
|
|
7165
|
+
return null;
|
|
7166
|
+
}
|
|
7167
|
+
function scanForNeedle(fd, from, to, needle, skipFrom, skipTo) {
|
|
7168
|
+
const hits = [];
|
|
7169
|
+
for (let start = from; start < to; start += SCAN_CHUNK - 7) {
|
|
7170
|
+
const length = Math.min(SCAN_CHUNK, to - start);
|
|
7171
|
+
if (length < 8) break;
|
|
7172
|
+
const chunk = readAt2(fd, length, start);
|
|
7173
|
+
let at = 0;
|
|
7174
|
+
for (; ; ) {
|
|
7175
|
+
const found = chunk.indexOf(needle, at);
|
|
7176
|
+
if (found < 0) break;
|
|
7177
|
+
const offset = start + found;
|
|
7178
|
+
if (offset < skipFrom || offset >= skipTo) hits.push(offset);
|
|
7179
|
+
at = found + 1;
|
|
7180
|
+
}
|
|
7181
|
+
}
|
|
7182
|
+
return hits;
|
|
7183
|
+
}
|
|
7184
|
+
function shimBunCompiledPointer(path) {
|
|
7185
|
+
const fd = openSync3(path, "r+");
|
|
7186
|
+
try {
|
|
7187
|
+
const layout = readElfLayout(fd);
|
|
7188
|
+
if (!layout) return null;
|
|
7189
|
+
const bun = layout.sections.find((section) => section.name === ".bun");
|
|
7190
|
+
if (!bun || bun.size === 0n) return null;
|
|
7191
|
+
const segment = writableLoad(layout);
|
|
7192
|
+
if (!segment) return null;
|
|
7193
|
+
const needle = Buffer.alloc(8);
|
|
7194
|
+
needle.writeBigUInt64LE(bun.addr);
|
|
7195
|
+
if (tweakccWouldFind(fd, segment, needle) !== null) return null;
|
|
7196
|
+
const segmentStart = Number(segment.offset);
|
|
7197
|
+
const segmentEnd = Number(segment.offset + segment.filesz);
|
|
7198
|
+
const bunStart = Number(bun.offset);
|
|
7199
|
+
const bunEnd = Number(bun.offset + bun.size);
|
|
7200
|
+
const candidates = scanForNeedle(fd, segmentStart, segmentEnd, needle, bunStart, bunEnd);
|
|
7201
|
+
if (candidates.length !== 1) {
|
|
7202
|
+
throw new Error(
|
|
7203
|
+
`cannot locate Bun's blob pointer: ${candidates.length} candidates in the writable segment (expected 1). Refusing to repack a binary whose Bun global would be left stale.`
|
|
7204
|
+
);
|
|
7205
|
+
}
|
|
7206
|
+
const pointerOffset = candidates[0];
|
|
7207
|
+
const pointerVaddr = segment.vaddr + BigInt(pointerOffset) - segment.offset;
|
|
7208
|
+
const first = alignUp(segment.vaddr, TWEAKCC_SCAN_STRIDE);
|
|
7209
|
+
const last = segment.vaddr + segment.filesz - 8n;
|
|
7210
|
+
let standInVaddr = null;
|
|
7211
|
+
for (let vaddr = first; vaddr <= last; vaddr += TWEAKCC_SCAN_STRIDE) {
|
|
7212
|
+
const at = Number(segment.offset + (vaddr - segment.vaddr));
|
|
7213
|
+
if (at + 8 > bunStart && at < bunEnd) continue;
|
|
7214
|
+
if (at + 8 > pointerOffset && at < pointerOffset + 8) continue;
|
|
7215
|
+
standInVaddr = vaddr;
|
|
7216
|
+
break;
|
|
7217
|
+
}
|
|
7218
|
+
if (standInVaddr === null) {
|
|
7219
|
+
throw new Error("no address tweakcc's ELF repack scans is usable for Bun's blob pointer");
|
|
7220
|
+
}
|
|
7221
|
+
const standInOffset = Number(segment.offset + (standInVaddr - segment.vaddr));
|
|
7222
|
+
const displaced = readAt2(fd, 8, standInOffset);
|
|
7223
|
+
if (displaced.length !== 8) throw new Error("could not read the bytes Bun's blob pointer displaces");
|
|
7224
|
+
writeSync3(fd, needle, 0, 8, standInOffset);
|
|
7225
|
+
return { pointerVaddr, standInVaddr, displaced, bunVaddr: bun.addr };
|
|
7226
|
+
} finally {
|
|
7227
|
+
closeSync3(fd);
|
|
7228
|
+
}
|
|
7229
|
+
}
|
|
7230
|
+
function restoreBunCompiledPointer(path, shim) {
|
|
7231
|
+
const fd = openSync3(path, "r+");
|
|
7232
|
+
try {
|
|
7233
|
+
const layout = readElfLayout(fd);
|
|
7234
|
+
if (!layout) throw new Error("the repacked binary is no longer a 64-bit little-endian ELF");
|
|
7235
|
+
const bun = layout.sections.find((section) => section.name === ".bun");
|
|
7236
|
+
if (!bun) throw new Error("the repacked binary has no .bun section");
|
|
7237
|
+
const standInOffset = fileOffsetOf(layout, shim.standInVaddr, 8n);
|
|
7238
|
+
const pointerOffset = fileOffsetOf(layout, shim.pointerVaddr, 8n);
|
|
7239
|
+
if (standInOffset === null || pointerOffset === null) {
|
|
7240
|
+
throw new Error(
|
|
7241
|
+
"the repack left Bun's blob pointer outside the loaded image, or in more than one segment of it"
|
|
7242
|
+
);
|
|
7243
|
+
}
|
|
7244
|
+
const written = readAt2(fd, 8, standInOffset).readBigUInt64LE(0);
|
|
7245
|
+
if (written === shim.bunVaddr) {
|
|
7246
|
+
throw new Error("the repack did not rewrite Bun's blob pointer \u2014 the stand-in was not used");
|
|
7247
|
+
}
|
|
7248
|
+
if (written !== bun.addr) {
|
|
7249
|
+
throw new Error(
|
|
7250
|
+
`the repack pointed Bun at 0x${written.toString(16)} but put .bun at 0x${bun.addr.toString(16)}`
|
|
7251
|
+
);
|
|
7252
|
+
}
|
|
7253
|
+
const value = Buffer.alloc(8);
|
|
7254
|
+
value.writeBigUInt64LE(written);
|
|
7255
|
+
writeSync3(fd, value, 0, 8, pointerOffset);
|
|
7256
|
+
writeSync3(fd, shim.displaced, 0, 8, standInOffset);
|
|
7257
|
+
if (!readAt2(fd, 8, pointerOffset).equals(value)) {
|
|
7258
|
+
throw new Error("Bun's blob pointer did not take the repacked address");
|
|
7259
|
+
}
|
|
7260
|
+
if (!readAt2(fd, 8, standInOffset).equals(shim.displaced)) {
|
|
7261
|
+
throw new Error("the bytes the stand-in displaced were not restored");
|
|
7262
|
+
}
|
|
7263
|
+
} finally {
|
|
7264
|
+
closeSync3(fd);
|
|
7265
|
+
}
|
|
7266
|
+
}
|
|
7267
|
+
|
|
7268
|
+
// src/bun-bundle.ts
|
|
7269
|
+
import { closeSync as closeSync4, openSync as openSync4, readSync as readSync3, writeSync as writeSync4 } from "fs";
|
|
7063
7270
|
function writableModuleIndex(path) {
|
|
7064
7271
|
const table = readBunModuleTable(path);
|
|
7065
7272
|
if (!table) return null;
|
|
@@ -7175,18 +7382,18 @@ function placeholderOf(byteLength) {
|
|
|
7175
7382
|
return PLACEHOLDER_TEXT.repeat(Math.ceil(byteLength / PLACEHOLDER_TEXT.length)).slice(0, byteLength);
|
|
7176
7383
|
}
|
|
7177
7384
|
function readBlobData(path, table, into) {
|
|
7178
|
-
const fd =
|
|
7385
|
+
const fd = openSync4(path, "r");
|
|
7179
7386
|
try {
|
|
7180
7387
|
let read = 0;
|
|
7181
7388
|
while (read < table.byteCount) {
|
|
7182
|
-
const got =
|
|
7389
|
+
const got = readSync3(fd, into, read, table.byteCount - read, table.blobAt + read);
|
|
7183
7390
|
if (got <= 0) {
|
|
7184
7391
|
throw new Error(`read ${read} of the ${table.byteCount} blob bytes of ${path}`);
|
|
7185
7392
|
}
|
|
7186
7393
|
read += got;
|
|
7187
7394
|
}
|
|
7188
7395
|
} finally {
|
|
7189
|
-
|
|
7396
|
+
closeSync4(fd);
|
|
7190
7397
|
}
|
|
7191
7398
|
}
|
|
7192
7399
|
function repointModule(data, table, append) {
|
|
@@ -7238,7 +7445,7 @@ function applyBundleWritePlan(path, plan) {
|
|
|
7238
7445
|
}
|
|
7239
7446
|
const offsets = Buffer.from(plan.offsets);
|
|
7240
7447
|
offsets.writeBigUInt64LE(BigInt(byteCount), 0);
|
|
7241
|
-
const fd =
|
|
7448
|
+
const fd = openSync4(path, "r+");
|
|
7242
7449
|
try {
|
|
7243
7450
|
writeAll(fd, plan.data, repacked.blobAt, path);
|
|
7244
7451
|
const padding = byteCount - plan.data.length;
|
|
@@ -7246,7 +7453,7 @@ function applyBundleWritePlan(path, plan) {
|
|
|
7246
7453
|
writeAll(fd, offsets, repacked.blobAt + byteCount, path);
|
|
7247
7454
|
writeAll(fd, BUN_TRAILER2, repacked.blobAt + byteCount + BUN_OFFSETS_BYTES2, path);
|
|
7248
7455
|
} finally {
|
|
7249
|
-
|
|
7456
|
+
closeSync4(fd);
|
|
7250
7457
|
}
|
|
7251
7458
|
const published = readBunModuleTable(path);
|
|
7252
7459
|
if (!published) throw new Error(`cannot re-read the Bun module table of ${path} after publishing its blob`);
|
|
@@ -7274,7 +7481,7 @@ function applyBundleWritePlan(path, plan) {
|
|
|
7274
7481
|
function writeAll(fd, bytes, position, path) {
|
|
7275
7482
|
let written = 0;
|
|
7276
7483
|
while (written < bytes.length) {
|
|
7277
|
-
const wrote =
|
|
7484
|
+
const wrote = writeSync4(fd, bytes, written, bytes.length - written, position + written);
|
|
7278
7485
|
if (wrote <= 0) throw new Error(`wrote ${written} of ${bytes.length} blob bytes to ${path}`);
|
|
7279
7486
|
written += wrote;
|
|
7280
7487
|
}
|
|
@@ -7775,6 +7982,7 @@ function sanitizeMessage(message) {
|
|
|
7775
7982
|
|
|
7776
7983
|
// src/tool-input-sanitize.ts
|
|
7777
7984
|
function sanitizeToolInput(input, requiredProps) {
|
|
7985
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) return input;
|
|
7778
7986
|
const out = /* @__PURE__ */ Object.create(null);
|
|
7779
7987
|
for (const [k, v] of Object.entries(input)) {
|
|
7780
7988
|
if (v === null) continue;
|
|
@@ -10159,7 +10367,7 @@ function thinkingProviderOptions(npm) {
|
|
|
10159
10367
|
|
|
10160
10368
|
// src/proxy.ts
|
|
10161
10369
|
import { createServer } from "http";
|
|
10162
|
-
import { appendFileSync as appendFileSync2, openSync as
|
|
10370
|
+
import { appendFileSync as appendFileSync2, openSync as openSync5, writeSync as writeSync5, closeSync as closeSync5 } from "fs";
|
|
10163
10371
|
|
|
10164
10372
|
// src/http-utils.ts
|
|
10165
10373
|
import * as zlib from "zlib";
|
|
@@ -10735,6 +10943,18 @@ function upstreamMaxRetries(env = process.env, warn = (message) => emitParentNot
|
|
|
10735
10943
|
}
|
|
10736
10944
|
return value;
|
|
10737
10945
|
}
|
|
10946
|
+
var CLIENT_MAX_RETRIES_ENV = "CLAUDE_CODE_MAX_RETRIES";
|
|
10947
|
+
var DEFAULT_PASSTHROUGH_RETRIES = 1;
|
|
10948
|
+
function passthroughUpstreamRetries(env = process.env) {
|
|
10949
|
+
const explicit = upstreamMaxRetries(env);
|
|
10950
|
+
if (explicit !== void 0) return explicit;
|
|
10951
|
+
const raw = env[CLIENT_MAX_RETRIES_ENV]?.trim();
|
|
10952
|
+
if (raw !== void 0 && raw !== "") {
|
|
10953
|
+
const clientRetries = Number(raw);
|
|
10954
|
+
if (Number.isFinite(clientRetries) && clientRetries === 0) return 0;
|
|
10955
|
+
}
|
|
10956
|
+
return DEFAULT_PASSTHROUGH_RETRIES;
|
|
10957
|
+
}
|
|
10738
10958
|
|
|
10739
10959
|
// src/sdk-adapter.ts
|
|
10740
10960
|
function sdkTranslationErrorSignature(error) {
|
|
@@ -10959,6 +11179,22 @@ function translateMessages(messages, npm, openAiPromptCacheBreakpoints = false)
|
|
|
10959
11179
|
}
|
|
10960
11180
|
return out;
|
|
10961
11181
|
}
|
|
11182
|
+
function isPlainObject(value) {
|
|
11183
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
11184
|
+
}
|
|
11185
|
+
function parsesAsJson(text5) {
|
|
11186
|
+
if (text5.trim() === "") return true;
|
|
11187
|
+
try {
|
|
11188
|
+
JSON.parse(text5);
|
|
11189
|
+
return true;
|
|
11190
|
+
} catch {
|
|
11191
|
+
return false;
|
|
11192
|
+
}
|
|
11193
|
+
}
|
|
11194
|
+
function representableToolInput(input) {
|
|
11195
|
+
if (typeof input === "string") return input;
|
|
11196
|
+
return isPlainObject(input) || Array.isArray(input) ? input : {};
|
|
11197
|
+
}
|
|
10962
11198
|
function toolRequiredProps(tools) {
|
|
10963
11199
|
const map = /* @__PURE__ */ new Map();
|
|
10964
11200
|
for (const [name, t] of Object.entries(tools ?? {})) {
|
|
@@ -10968,12 +11204,16 @@ function toolRequiredProps(tools) {
|
|
|
10968
11204
|
}
|
|
10969
11205
|
return map;
|
|
10970
11206
|
}
|
|
10971
|
-
function translateTools(anthropicTools) {
|
|
11207
|
+
function translateTools(anthropicTools, npm) {
|
|
10972
11208
|
if (!anthropicTools?.length) return void 0;
|
|
10973
11209
|
const tools = {};
|
|
10974
11210
|
for (const t of anthropicTools) {
|
|
10975
11211
|
if (!t.name || !t.input_schema) continue;
|
|
10976
|
-
tools[t.name] = tool({
|
|
11212
|
+
tools[t.name] = tool({
|
|
11213
|
+
description: t.description ?? "",
|
|
11214
|
+
inputSchema: jsonSchema(t.input_schema),
|
|
11215
|
+
strict: npm === "@ai-sdk/openai" ? false : void 0
|
|
11216
|
+
});
|
|
10977
11217
|
}
|
|
10978
11218
|
return Object.keys(tools).length ? tools : void 0;
|
|
10979
11219
|
}
|
|
@@ -11037,7 +11277,7 @@ function translateRequest(body, npm, options) {
|
|
|
11037
11277
|
...translateMessages(messages, npm, supportsExplicitOpenAiCaching)
|
|
11038
11278
|
],
|
|
11039
11279
|
allowSystemInMessages: true,
|
|
11040
|
-
tools: translateTools(upstreamTools.length ? upstreamTools : void 0),
|
|
11280
|
+
tools: translateTools(upstreamTools.length ? upstreamTools : void 0, npm),
|
|
11041
11281
|
toolChoice: compactRequest ? "none" : translateToolChoice(body.tool_choice),
|
|
11042
11282
|
maxOutputTokens: options?.openAiOAuth ? void 0 : body.max_tokens,
|
|
11043
11283
|
temperature: body.temperature,
|
|
@@ -11254,7 +11494,8 @@ async function writeAnthropicStream(stream, modelId, write, log12, observer, too
|
|
|
11254
11494
|
const id = part.toolCallId ?? "";
|
|
11255
11495
|
if (idToBlock.has(id)) {
|
|
11256
11496
|
if (!flushedTools.has(id)) {
|
|
11257
|
-
const
|
|
11497
|
+
const buffered = toolJsonBuffer.get(id);
|
|
11498
|
+
const json = buffered !== void 0 && !isPlainObject(part.input) && !parsesAsJson(buffered) ? buffered : part.input !== void 0 && part.input !== null ? JSON.stringify(sanitizeToolInput(part.input, requiredProps.get(part.toolName ?? ""))) : buffered ?? "";
|
|
11258
11499
|
if (json) {
|
|
11259
11500
|
emit("content_block_delta", {
|
|
11260
11501
|
type: "content_block_delta",
|
|
@@ -11459,7 +11700,7 @@ async function generateAnthropicResponse(model, params, modelId, options) {
|
|
|
11459
11700
|
type: "tool_use",
|
|
11460
11701
|
id: encodeToolUseId(tc.toolCallId, grabRoundTripSignature(tc)),
|
|
11461
11702
|
name: tc.toolName,
|
|
11462
|
-
input: sanitizeToolInput(tc.input ?? {}, requiredProps.get(tc.toolName))
|
|
11703
|
+
input: representableToolInput(sanitizeToolInput(tc.input ?? {}, requiredProps.get(tc.toolName)))
|
|
11463
11704
|
}))
|
|
11464
11705
|
],
|
|
11465
11706
|
stop_reason: finishReason === "tool-calls" ? "tool_use" : "end_turn",
|
|
@@ -11613,12 +11854,12 @@ function createTranslationLifecycle(logPath, requestId, claudeSessionId, modelId
|
|
|
11613
11854
|
function appendSecureLog(logPath, line) {
|
|
11614
11855
|
const redacted = redactTraceLine(line);
|
|
11615
11856
|
try {
|
|
11616
|
-
const fd =
|
|
11857
|
+
const fd = openSync5(logPath, "a", 384);
|
|
11617
11858
|
try {
|
|
11618
|
-
|
|
11859
|
+
writeSync5(fd, `${(/* @__PURE__ */ new Date()).toISOString()} ${redacted}
|
|
11619
11860
|
`);
|
|
11620
11861
|
} finally {
|
|
11621
|
-
|
|
11862
|
+
closeSync5(fd);
|
|
11622
11863
|
}
|
|
11623
11864
|
} catch {
|
|
11624
11865
|
try {
|
|
@@ -12481,10 +12722,10 @@ function tryAcquirePatchLock(lockPath = getPatchLockPath(), opts = {}) {
|
|
|
12481
12722
|
mkdirSync5(join7(lockPath, ".."), { recursive: true, mode: 448 });
|
|
12482
12723
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
12483
12724
|
try {
|
|
12484
|
-
const fd =
|
|
12725
|
+
const fd = openSync6(lockPath, "wx");
|
|
12485
12726
|
const content = { pid: process.pid, startedAt: now };
|
|
12486
12727
|
writeFileSync5(fd, JSON.stringify(content));
|
|
12487
|
-
|
|
12728
|
+
closeSync6(fd);
|
|
12488
12729
|
return () => {
|
|
12489
12730
|
try {
|
|
12490
12731
|
unlinkSync3(lockPath);
|
|
@@ -12744,11 +12985,15 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
12744
12985
|
splitBundleSource(loaded.bundle, local.content),
|
|
12745
12986
|
writable
|
|
12746
12987
|
);
|
|
12988
|
+
const bunPointerShim = shimBunCompiledPointer(candidatePath);
|
|
12747
12989
|
await writeContent(loaded.installation, plan2.content);
|
|
12990
|
+
if (bunPointerShim) restoreBunCompiledPointer(candidatePath, bunPointerShim);
|
|
12748
12991
|
applyBundleWritePlan(candidatePath, plan2);
|
|
12749
12992
|
publishedBlob = true;
|
|
12750
12993
|
} else {
|
|
12994
|
+
const bunPointerShim = shimBunCompiledPointer(candidatePath);
|
|
12751
12995
|
await writeContent(loaded.installation, local.content);
|
|
12996
|
+
if (bunPointerShim) restoreBunCompiledPointer(candidatePath, bunPointerShim);
|
|
12752
12997
|
}
|
|
12753
12998
|
if (writeShim) restoreEntryModuleName(candidatePath, writeShim, { resign: true });
|
|
12754
12999
|
else if (publishedBlob) resignMachOBinary(candidatePath);
|
|
@@ -13269,13 +13514,13 @@ function localProvidersToServerModels(localProviders) {
|
|
|
13269
13514
|
// src/registry/credential-cleanup-journal.ts
|
|
13270
13515
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
13271
13516
|
import {
|
|
13272
|
-
closeSync as
|
|
13517
|
+
closeSync as closeSync7,
|
|
13273
13518
|
existsSync as existsSync6,
|
|
13274
13519
|
fstatSync,
|
|
13275
13520
|
fsyncSync as fsyncSync2,
|
|
13276
13521
|
lstatSync,
|
|
13277
13522
|
mkdirSync as mkdirSync6,
|
|
13278
|
-
openSync as
|
|
13523
|
+
openSync as openSync7,
|
|
13279
13524
|
readFileSync as readFileSync9,
|
|
13280
13525
|
renameSync as renameSync3,
|
|
13281
13526
|
unlinkSync as unlinkSync4,
|
|
@@ -13367,7 +13612,7 @@ function readJournalUnlocked(path) {
|
|
|
13367
13612
|
if (before.isSymbolicLink() || !before.isFile()) {
|
|
13368
13613
|
throw new Error("Credential cleanup journal must be a regular file.");
|
|
13369
13614
|
}
|
|
13370
|
-
fd =
|
|
13615
|
+
fd = openSync7(path, "r");
|
|
13371
13616
|
const opened = fstatSync(fd);
|
|
13372
13617
|
if (before.dev !== opened.dev || before.ino !== opened.ino) {
|
|
13373
13618
|
throw new Error("Credential cleanup journal changed while opening.");
|
|
@@ -13388,19 +13633,19 @@ function readJournalUnlocked(path) {
|
|
|
13388
13633
|
const message = error instanceof Error ? error.message : String(error);
|
|
13389
13634
|
throw new Error(`Could not read credential cleanup journal: ${message}`);
|
|
13390
13635
|
} finally {
|
|
13391
|
-
if (fd !== void 0)
|
|
13636
|
+
if (fd !== void 0) closeSync7(fd);
|
|
13392
13637
|
}
|
|
13393
13638
|
}
|
|
13394
13639
|
function syncParentDirectory(path) {
|
|
13395
13640
|
let fd;
|
|
13396
13641
|
try {
|
|
13397
|
-
fd =
|
|
13642
|
+
fd = openSync7(dirname4(path), "r");
|
|
13398
13643
|
fsyncSync2(fd);
|
|
13399
13644
|
} catch (error) {
|
|
13400
13645
|
const code = error.code;
|
|
13401
13646
|
if (code !== "EINVAL" && code !== "ENOTSUP" && code !== "EPERM") throw error;
|
|
13402
13647
|
} finally {
|
|
13403
|
-
if (fd !== void 0)
|
|
13648
|
+
if (fd !== void 0) closeSync7(fd);
|
|
13404
13649
|
}
|
|
13405
13650
|
}
|
|
13406
13651
|
function writeJournalUnlocked(journal, path) {
|
|
@@ -13410,17 +13655,17 @@ function writeJournalUnlocked(journal, path) {
|
|
|
13410
13655
|
const tmp = `${path}.${process.pid}.${randomUUID4()}.tmp`;
|
|
13411
13656
|
let fd;
|
|
13412
13657
|
try {
|
|
13413
|
-
fd =
|
|
13658
|
+
fd = openSync7(tmp, "wx", FILE_MODE4);
|
|
13414
13659
|
writeFileSync6(fd, `${JSON.stringify(journal, null, 2)}
|
|
13415
13660
|
`);
|
|
13416
13661
|
fsyncSync2(fd);
|
|
13417
|
-
|
|
13662
|
+
closeSync7(fd);
|
|
13418
13663
|
fd = void 0;
|
|
13419
13664
|
assertRegistryWriteOwnership(path);
|
|
13420
13665
|
renameSync3(tmp, path);
|
|
13421
13666
|
syncParentDirectory(path);
|
|
13422
13667
|
} finally {
|
|
13423
|
-
if (fd !== void 0)
|
|
13668
|
+
if (fd !== void 0) closeSync7(fd);
|
|
13424
13669
|
try {
|
|
13425
13670
|
unlinkSync4(tmp);
|
|
13426
13671
|
} catch (error) {
|
|
@@ -17369,20 +17614,37 @@ function ensureHttpProxyCertificates() {
|
|
|
17369
17614
|
serverKey: readFileSync10(paths.serverKey, "utf8")
|
|
17370
17615
|
};
|
|
17371
17616
|
}
|
|
17372
|
-
function ensureHttpProxyCaBundle(relayCaCertPath, additionalCaCertPath) {
|
|
17617
|
+
function ensureHttpProxyCaBundle(relayCaCertPath, additionalCaCertPath, onWarning) {
|
|
17373
17618
|
if (!additionalCaCertPath?.trim()) return relayCaCertPath;
|
|
17619
|
+
const warn = (detail) => {
|
|
17620
|
+
onWarning?.(
|
|
17621
|
+
`${detail} The CA bundle handed to the child is ${relayCaCertPath}; node's built-in roots are unaffected.`
|
|
17622
|
+
);
|
|
17623
|
+
return relayCaCertPath;
|
|
17624
|
+
};
|
|
17625
|
+
let additionalCa;
|
|
17374
17626
|
try {
|
|
17375
17627
|
if (resolve2(additionalCaCertPath) === resolve2(relayCaCertPath)) return relayCaCertPath;
|
|
17628
|
+
additionalCa = readFileSync10(additionalCaCertPath, "utf8").trim();
|
|
17629
|
+
} catch (err) {
|
|
17630
|
+
return warn(
|
|
17631
|
+
`NODE_EXTRA_CA_CERTS=${additionalCaCertPath} cannot be read (${err instanceof Error ? err.message : String(err)}), so it is not part of the proxy CA bundle. Where node reports this itself it says only "Ignoring extra certs ... load failed", without naming the variable. Clear or correct it.`
|
|
17632
|
+
);
|
|
17633
|
+
}
|
|
17634
|
+
if (!additionalCa) {
|
|
17635
|
+
return warn(`NODE_EXTRA_CA_CERTS=${additionalCaCertPath} is empty, so it adds nothing.`);
|
|
17636
|
+
}
|
|
17637
|
+
try {
|
|
17376
17638
|
const relayCa = readFileSync10(relayCaCertPath, "utf8").trimEnd();
|
|
17377
|
-
const additionalCa = readFileSync10(additionalCaCertPath, "utf8").trim();
|
|
17378
|
-
if (!additionalCa) return relayCaCertPath;
|
|
17379
17639
|
const combinedPath = join8(dirname5(relayCaCertPath), "combined-ca.pem");
|
|
17380
17640
|
writePublic(combinedPath, `${relayCa}
|
|
17381
17641
|
${additionalCa}
|
|
17382
17642
|
`);
|
|
17383
17643
|
return combinedPath;
|
|
17384
|
-
} catch {
|
|
17385
|
-
return
|
|
17644
|
+
} catch (err) {
|
|
17645
|
+
return warn(
|
|
17646
|
+
`clodex could not build the combined CA bundle in ${dirname5(relayCaCertPath)} (${err instanceof Error ? err.message : String(err)}), so the readable, non-empty NODE_EXTRA_CA_CERTS=${additionalCaCertPath} was left out of it. Fix the reported error and restart clodex.`
|
|
17647
|
+
);
|
|
17386
17648
|
}
|
|
17387
17649
|
}
|
|
17388
17650
|
|
|
@@ -17391,6 +17653,16 @@ var ANTHROPIC_HOST = "api.anthropic.com";
|
|
|
17391
17653
|
var MAX_BODY_BYTES = 50 * 1024 * 1024;
|
|
17392
17654
|
var MAX_ERROR_BODY_BYTES = 64 * 1024;
|
|
17393
17655
|
var MAX_USAGE_SSE_BLOCK_BYTES = 64 * 1024;
|
|
17656
|
+
var RETRYABLE_PASSTHROUGH_CODE = "ECONNRESET";
|
|
17657
|
+
function upstreamUnreachableDetail(err) {
|
|
17658
|
+
return err.message || err.code || err.name || "connection failed";
|
|
17659
|
+
}
|
|
17660
|
+
function createPassthroughAgent() {
|
|
17661
|
+
return new https.Agent({
|
|
17662
|
+
keepAlive: true,
|
|
17663
|
+
timeout: https.globalAgent.options.timeout ?? 5e3
|
|
17664
|
+
});
|
|
17665
|
+
}
|
|
17394
17666
|
function numericUsage(value) {
|
|
17395
17667
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
17396
17668
|
}
|
|
@@ -17539,6 +17811,7 @@ function requestHeadersWithoutProxyHeaders(req) {
|
|
|
17539
17811
|
function forwardRawAnthropicRequest(req, res, rawBody, origin, rejectUnauthorized, agent, onErrorResponse, onResponseUsage, lifecycle, isLocalShutdown = () => false) {
|
|
17540
17812
|
return new Promise((resolve3) => {
|
|
17541
17813
|
const startedAt = Date.now();
|
|
17814
|
+
const retryBudget = passthroughUpstreamRetries();
|
|
17542
17815
|
let lastActivityAt = startedAt;
|
|
17543
17816
|
let headersReceived = false;
|
|
17544
17817
|
let firstByteAt;
|
|
@@ -17588,42 +17861,91 @@ function forwardRawAnthropicRequest(req, res, rawBody, origin, rejectUnauthorize
|
|
|
17588
17861
|
resolve3();
|
|
17589
17862
|
};
|
|
17590
17863
|
const errorType = (err) => err.code ?? err.name;
|
|
17591
|
-
|
|
17592
|
-
|
|
17593
|
-
|
|
17594
|
-
|
|
17595
|
-
|
|
17596
|
-
|
|
17597
|
-
|
|
17598
|
-
|
|
17599
|
-
|
|
17600
|
-
|
|
17601
|
-
|
|
17602
|
-
|
|
17603
|
-
|
|
17604
|
-
|
|
17605
|
-
|
|
17606
|
-
|
|
17607
|
-
|
|
17608
|
-
|
|
17609
|
-
|
|
17864
|
+
let upstream;
|
|
17865
|
+
let attempt = 0;
|
|
17866
|
+
const isRetryableUpstreamFailure = (err, request3) => attempt <= retryBudget && !headersReceived && !failed && !clientDisconnected && !isLocalShutdown() && request3.reusedSocket === true && err.code === RETRYABLE_PASSTHROUGH_CODE;
|
|
17867
|
+
const sendAttempt = () => {
|
|
17868
|
+
attempt += 1;
|
|
17869
|
+
const request3 = https.request({
|
|
17870
|
+
protocol: "https:",
|
|
17871
|
+
hostname: origin.hostname,
|
|
17872
|
+
port: origin.port || 443,
|
|
17873
|
+
method: req.method,
|
|
17874
|
+
path: req.url,
|
|
17875
|
+
headers: requestHeadersWithoutProxyHeaders(req),
|
|
17876
|
+
servername: net.isIP(origin.hostname) ? void 0 : origin.hostname,
|
|
17877
|
+
rejectUnauthorized,
|
|
17878
|
+
agent
|
|
17879
|
+
}, (upstreamRes) => {
|
|
17880
|
+
headersReceived = true;
|
|
17881
|
+
statusCode = upstreamRes.statusCode ?? 502;
|
|
17882
|
+
lastActivityAt = Date.now();
|
|
17883
|
+
upstreamRes.on("data", (chunk) => {
|
|
17884
|
+
const now = Date.now();
|
|
17885
|
+
if (firstByteAt === void 0) {
|
|
17886
|
+
firstByteAt = now;
|
|
17887
|
+
writeLifecycle("response_started", {
|
|
17888
|
+
statusCode,
|
|
17889
|
+
durationMs: now - startedAt,
|
|
17890
|
+
timeToFirstByteMs: now - startedAt,
|
|
17891
|
+
...attempt > 1 ? { attempt } : {}
|
|
17892
|
+
});
|
|
17893
|
+
}
|
|
17894
|
+
lastActivityAt = now;
|
|
17895
|
+
bytes += chunk.length;
|
|
17896
|
+
chunks += 1;
|
|
17897
|
+
});
|
|
17898
|
+
copyResponse(upstreamRes, res, onErrorResponse, onResponseUsage);
|
|
17899
|
+
upstreamRes.once("end", () => {
|
|
17900
|
+
responseEnded = true;
|
|
17901
|
+
lastActivityAt = Date.now();
|
|
17902
|
+
done();
|
|
17903
|
+
});
|
|
17904
|
+
upstreamRes.once("error", (err) => {
|
|
17905
|
+
if (clientDisconnected || failed) {
|
|
17906
|
+
done();
|
|
17907
|
+
return;
|
|
17908
|
+
}
|
|
17909
|
+
failed = true;
|
|
17910
|
+
stopProgress();
|
|
17911
|
+
const now = Date.now();
|
|
17912
|
+
writeLifecycle("response_failed", {
|
|
17610
17913
|
statusCode,
|
|
17914
|
+
phase: responsePhase(),
|
|
17611
17915
|
durationMs: now - startedAt,
|
|
17612
|
-
timeToFirstByteMs:
|
|
17916
|
+
...firstByteAt !== void 0 ? { timeToFirstByteMs: firstByteAt - startedAt } : {},
|
|
17917
|
+
idleMs: now - lastActivityAt,
|
|
17918
|
+
bytes,
|
|
17919
|
+
chunks,
|
|
17920
|
+
errorType: errorType(err),
|
|
17921
|
+
terminationSource: "upstream_failure",
|
|
17922
|
+
attempt
|
|
17613
17923
|
});
|
|
17614
|
-
|
|
17615
|
-
|
|
17616
|
-
bytes += chunk.length;
|
|
17617
|
-
chunks += 1;
|
|
17618
|
-
});
|
|
17619
|
-
copyResponse(upstreamRes, res, onErrorResponse, onResponseUsage);
|
|
17620
|
-
upstreamRes.once("end", () => {
|
|
17621
|
-
responseEnded = true;
|
|
17622
|
-
lastActivityAt = Date.now();
|
|
17623
|
-
done();
|
|
17924
|
+
done();
|
|
17925
|
+
});
|
|
17624
17926
|
});
|
|
17625
|
-
|
|
17626
|
-
|
|
17927
|
+
upstream = request3;
|
|
17928
|
+
request3.once("error", (err) => {
|
|
17929
|
+
if (clientDisconnected) {
|
|
17930
|
+
done();
|
|
17931
|
+
return;
|
|
17932
|
+
}
|
|
17933
|
+
if (isRetryableUpstreamFailure(err, request3)) {
|
|
17934
|
+
const retriedAt = Date.now();
|
|
17935
|
+
writeLifecycle("response_retried", {
|
|
17936
|
+
phase: responsePhase(),
|
|
17937
|
+
durationMs: retriedAt - startedAt,
|
|
17938
|
+
idleMs: retriedAt - lastActivityAt,
|
|
17939
|
+
errorType: errorType(err),
|
|
17940
|
+
terminationSource: "upstream_failure",
|
|
17941
|
+
attempt,
|
|
17942
|
+
reusedSocket: true
|
|
17943
|
+
});
|
|
17944
|
+
lastActivityAt = retriedAt;
|
|
17945
|
+
sendAttempt();
|
|
17946
|
+
return;
|
|
17947
|
+
}
|
|
17948
|
+
if (failed) {
|
|
17627
17949
|
done();
|
|
17628
17950
|
return;
|
|
17629
17951
|
}
|
|
@@ -17631,19 +17953,25 @@ function forwardRawAnthropicRequest(req, res, rawBody, origin, rejectUnauthorize
|
|
|
17631
17953
|
stopProgress();
|
|
17632
17954
|
const now = Date.now();
|
|
17633
17955
|
writeLifecycle("response_failed", {
|
|
17634
|
-
statusCode,
|
|
17956
|
+
statusCode: 502,
|
|
17635
17957
|
phase: responsePhase(),
|
|
17636
17958
|
durationMs: now - startedAt,
|
|
17637
|
-
...firstByteAt !== void 0 ? { timeToFirstByteMs: firstByteAt - startedAt } : {},
|
|
17638
17959
|
idleMs: now - lastActivityAt,
|
|
17639
17960
|
bytes,
|
|
17640
17961
|
chunks,
|
|
17641
17962
|
errorType: errorType(err),
|
|
17642
|
-
terminationSource: "upstream_failure"
|
|
17963
|
+
terminationSource: isLocalShutdown() ? "local_shutdown" : "upstream_failure",
|
|
17964
|
+
attempt,
|
|
17965
|
+
reusedSocket: request3.reusedSocket === true
|
|
17643
17966
|
});
|
|
17967
|
+
const detail = upstreamUnreachableDetail(err);
|
|
17968
|
+
onErrorResponse?.(502, `Anthropic upstream unreachable: ${detail}`);
|
|
17969
|
+
if (!res.headersSent) res.writeHead(502, { "Content-Type": "text/plain" });
|
|
17970
|
+
res.end(`Anthropic upstream unreachable: ${detail}`);
|
|
17644
17971
|
done();
|
|
17645
17972
|
});
|
|
17646
|
-
|
|
17973
|
+
request3.end(rawBody);
|
|
17974
|
+
};
|
|
17647
17975
|
res.once("finish", () => {
|
|
17648
17976
|
stopProgress();
|
|
17649
17977
|
if (failed || clientDisconnected) return;
|
|
@@ -17653,7 +17981,8 @@ function forwardRawAnthropicRequest(req, res, rawBody, origin, rejectUnauthorize
|
|
|
17653
17981
|
durationMs: now - startedAt,
|
|
17654
17982
|
...firstByteAt !== void 0 ? { timeToFirstByteMs: firstByteAt - startedAt } : {},
|
|
17655
17983
|
bytes,
|
|
17656
|
-
chunks
|
|
17984
|
+
chunks,
|
|
17985
|
+
...attempt > 1 ? { attempt } : {}
|
|
17657
17986
|
});
|
|
17658
17987
|
});
|
|
17659
17988
|
res.once("close", () => {
|
|
@@ -17671,33 +18000,10 @@ function forwardRawAnthropicRequest(req, res, rawBody, origin, rejectUnauthorize
|
|
|
17671
18000
|
chunks,
|
|
17672
18001
|
terminationSource: isLocalShutdown() ? "local_shutdown" : "downstream_client"
|
|
17673
18002
|
});
|
|
17674
|
-
upstream
|
|
17675
|
-
done();
|
|
17676
|
-
});
|
|
17677
|
-
upstream.once("error", (err) => {
|
|
17678
|
-
if (clientDisconnected) {
|
|
17679
|
-
done();
|
|
17680
|
-
return;
|
|
17681
|
-
}
|
|
17682
|
-
failed = true;
|
|
17683
|
-
stopProgress();
|
|
17684
|
-
const now = Date.now();
|
|
17685
|
-
writeLifecycle("response_failed", {
|
|
17686
|
-
statusCode: 502,
|
|
17687
|
-
phase: responsePhase(),
|
|
17688
|
-
durationMs: now - startedAt,
|
|
17689
|
-
idleMs: now - lastActivityAt,
|
|
17690
|
-
bytes,
|
|
17691
|
-
chunks,
|
|
17692
|
-
errorType: errorType(err),
|
|
17693
|
-
terminationSource: "upstream_failure"
|
|
17694
|
-
});
|
|
17695
|
-
onErrorResponse?.(502, `Anthropic upstream unreachable: ${err.message}`);
|
|
17696
|
-
if (!res.headersSent) res.writeHead(502, { "Content-Type": "text/plain" });
|
|
17697
|
-
res.end(`Anthropic upstream unreachable: ${err.message}`);
|
|
18003
|
+
upstream?.destroy(new Error("Client disconnected"));
|
|
17698
18004
|
done();
|
|
17699
18005
|
});
|
|
17700
|
-
|
|
18006
|
+
sendAttempt();
|
|
17701
18007
|
});
|
|
17702
18008
|
}
|
|
17703
18009
|
function forwardToAdapter(req, res, rawBody, adapter, adapterRequest = http2.request, adapterAgent, lifecycle, isLocalShutdown = () => false) {
|
|
@@ -18174,6 +18480,7 @@ async function startHttpProxy(options) {
|
|
|
18174
18480
|
} else {
|
|
18175
18481
|
anthropicAgent = outboundHttpProxyAgent(anthropicOrigin.href);
|
|
18176
18482
|
}
|
|
18483
|
+
anthropicAgent ??= createPassthroughAgent();
|
|
18177
18484
|
return {
|
|
18178
18485
|
host: options.host ?? "127.0.0.1",
|
|
18179
18486
|
port: address.port,
|
|
@@ -18307,11 +18614,15 @@ async function startConfiguredHttpProxy(port, debug = false, inferenceLogPath =
|
|
|
18307
18614
|
debugLogPath,
|
|
18308
18615
|
webSocketDiagnosticsLogPath
|
|
18309
18616
|
));
|
|
18617
|
+
let caWarning;
|
|
18310
18618
|
handle.caCertPath = ensureHttpProxyCaBundle(
|
|
18311
18619
|
handle.caCertPath,
|
|
18312
|
-
process.env["NODE_EXTRA_CA_CERTS"]
|
|
18620
|
+
process.env["NODE_EXTRA_CA_CERTS"],
|
|
18621
|
+
(message) => {
|
|
18622
|
+
caWarning = message;
|
|
18623
|
+
}
|
|
18313
18624
|
);
|
|
18314
|
-
return { handle, loaded };
|
|
18625
|
+
return { handle, loaded, ...caWarning ? { caWarning } : {} };
|
|
18315
18626
|
}
|
|
18316
18627
|
function waitForShutdown() {
|
|
18317
18628
|
return new Promise((resolve3) => {
|
|
@@ -18340,7 +18651,7 @@ async function runHttpProxyServerCommand(debug = false, webSocketDiagnostics = f
|
|
|
18340
18651
|
p9.log.error(`Failed to start HTTP proxy: ${err instanceof Error ? err.message : String(err)}`);
|
|
18341
18652
|
return 1;
|
|
18342
18653
|
}
|
|
18343
|
-
const { handle, loaded } = started;
|
|
18654
|
+
const { handle, loaded, caWarning } = started;
|
|
18344
18655
|
writeProxyLifecycleLog(inferenceLogPath, {
|
|
18345
18656
|
event: "proxy_started",
|
|
18346
18657
|
pid: process.pid,
|
|
@@ -18352,6 +18663,10 @@ async function runHttpProxyServerCommand(debug = false, webSocketDiagnostics = f
|
|
|
18352
18663
|
console.log(pc10.bold(pc10.green("clodex proxy-mode server running")));
|
|
18353
18664
|
for (const line of formatHttpProxyEnvironmentLines(handle)) console.log(line);
|
|
18354
18665
|
console.log(` Request log: ${handle.inferenceLogPath}`);
|
|
18666
|
+
if (caWarning) {
|
|
18667
|
+
console.log("");
|
|
18668
|
+
console.log(pc10.yellow(` clodex: ${caWarning}`));
|
|
18669
|
+
}
|
|
18355
18670
|
if (handle.webSocketDiagnosticsLogPath) {
|
|
18356
18671
|
console.log(` WebSocket diagnostics: ${handle.webSocketDiagnosticsLogPath}`);
|
|
18357
18672
|
console.log(pc10.yellow(" Diagnostic mode records request headers and metadata; credential headers are redacted."));
|
|
@@ -19937,7 +20252,11 @@ async function runClaudeHttpProxyCommand(parsed, claudeArgs, agentStdout) {
|
|
|
19937
20252
|
p12.log.error(`Failed to start proxy: ${err instanceof Error ? err.message : String(err)}`);
|
|
19938
20253
|
return 1;
|
|
19939
20254
|
}
|
|
19940
|
-
const { handle, loaded } = started;
|
|
20255
|
+
const { handle, loaded, caWarning } = started;
|
|
20256
|
+
if (caWarning) {
|
|
20257
|
+
if (agentStdout) emitParentNotice(`clodex: ${caWarning}`);
|
|
20258
|
+
else p12.log.warn(caWarning);
|
|
20259
|
+
}
|
|
19941
20260
|
const inheritedProxyPort = (() => {
|
|
19942
20261
|
const value = process.env["HTTPS_PROXY"] ?? process.env["HTTP_PROXY"] ?? process.env["https_proxy"] ?? process.env["http_proxy"];
|
|
19943
20262
|
if (!value) return void 0;
|