@bman654/clodex 2.12.2 → 2.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +112 -32
- 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.
|
|
385
|
+
version: "2.13.1",
|
|
386
386
|
publishConfig: {
|
|
387
387
|
access: "public"
|
|
388
388
|
},
|
|
@@ -3895,8 +3895,8 @@ import {
|
|
|
3895
3895
|
statSync as statSync8,
|
|
3896
3896
|
unlinkSync as unlinkSync3,
|
|
3897
3897
|
writeFileSync as writeFileSync6,
|
|
3898
|
-
openSync as
|
|
3899
|
-
closeSync as
|
|
3898
|
+
openSync as openSync8,
|
|
3899
|
+
closeSync as closeSync8,
|
|
3900
3900
|
realpathSync as realpathSync2
|
|
3901
3901
|
} from "fs";
|
|
3902
3902
|
import { homedir as homedir3 } from "os";
|
|
@@ -8120,6 +8120,8 @@ import { wrapLanguageModel, extractReasoningMiddleware } from "ai";
|
|
|
8120
8120
|
|
|
8121
8121
|
// src/oauth/responses-websocket.ts
|
|
8122
8122
|
import { createHash as createHash6 } from "crypto";
|
|
8123
|
+
import { closeSync as closeSync6, openSync as openSync6 } from "fs";
|
|
8124
|
+
import { devNull } from "os";
|
|
8123
8125
|
import { AsyncLocalStorage } from "async_hooks";
|
|
8124
8126
|
|
|
8125
8127
|
// src/outbound-proxy.ts
|
|
@@ -8181,17 +8183,17 @@ function proxyUrlTargetsListener(proxyUrl, listenerHost, listenerPort, localAddr
|
|
|
8181
8183
|
return isWildcard(boundHost) && (isWildcard(proxyHost) || localAddresses.has(proxyHost));
|
|
8182
8184
|
}
|
|
8183
8185
|
var dispatcherInstalled = false;
|
|
8184
|
-
async function
|
|
8186
|
+
async function installOutboundDispatcher() {
|
|
8185
8187
|
if (dispatcherInstalled) return true;
|
|
8186
|
-
if (!hasOutboundProxyEnv()) return false;
|
|
8187
8188
|
try {
|
|
8188
|
-
const { EnvHttpProxyAgent, setGlobalDispatcher } = await import("undici");
|
|
8189
|
-
|
|
8189
|
+
const { Agent: Agent3, EnvHttpProxyAgent, setGlobalDispatcher } = await import("undici");
|
|
8190
|
+
const dispatcher = hasOutboundProxyEnv() ? new EnvHttpProxyAgent({ allowH2: false }) : new Agent3({ allowH2: false });
|
|
8191
|
+
setGlobalDispatcher(dispatcher);
|
|
8190
8192
|
dispatcherInstalled = true;
|
|
8191
8193
|
return true;
|
|
8192
8194
|
} catch (err) {
|
|
8193
8195
|
console.error(
|
|
8194
|
-
`clodex:
|
|
8196
|
+
`clodex: installing the outbound fetch dispatcher failed; continuing with Node's existing dispatcher (${err instanceof Error ? err.message : String(err)})`
|
|
8195
8197
|
);
|
|
8196
8198
|
return false;
|
|
8197
8199
|
}
|
|
@@ -8886,8 +8888,8 @@ var FAILURE_EVENT_TYPES = /* @__PURE__ */ new Set(["error", "response.failed", "
|
|
|
8886
8888
|
var RESPONSES_WS_HARD_TTL_MS = 55 * 6e4;
|
|
8887
8889
|
var RESPONSES_WS_IDLE_TTL_MS = 30 * 6e4;
|
|
8888
8890
|
var RESPONSES_WS_NURSERY_IDLE_TTL_MS = 5 * 6e4;
|
|
8889
|
-
var RESPONSES_WS_MAX_CONNECTIONS =
|
|
8890
|
-
var RESPONSES_WS_MAX_NURSERY_CONNECTIONS =
|
|
8891
|
+
var RESPONSES_WS_MAX_CONNECTIONS = Number.POSITIVE_INFINITY;
|
|
8892
|
+
var RESPONSES_WS_MAX_NURSERY_CONNECTIONS = Number.POSITIVE_INFINITY;
|
|
8891
8893
|
var diagnosticContext = new AsyncLocalStorage();
|
|
8892
8894
|
function withResponsesWebSocketDiagnosticContext(context, fn) {
|
|
8893
8895
|
return diagnosticContext.run(context, fn);
|
|
@@ -9845,6 +9847,64 @@ function evictOldestIdleGeneration(generation, maxConnections, reason) {
|
|
|
9845
9847
|
}
|
|
9846
9848
|
return evictions;
|
|
9847
9849
|
}
|
|
9850
|
+
var DESCRIPTOR_EXHAUSTION_CODES = /* @__PURE__ */ new Set(["EMFILE", "ENFILE"]);
|
|
9851
|
+
function isDescriptorExhaustion(code) {
|
|
9852
|
+
return typeof code === "string" && DESCRIPTOR_EXHAUSTION_CODES.has(code);
|
|
9853
|
+
}
|
|
9854
|
+
function descriptorExhaustionCode(error) {
|
|
9855
|
+
const code = error.code;
|
|
9856
|
+
if (isDescriptorExhaustion(code)) return code;
|
|
9857
|
+
try {
|
|
9858
|
+
closeSync6(openSync6(devNull, "r"));
|
|
9859
|
+
return void 0;
|
|
9860
|
+
} catch (probe) {
|
|
9861
|
+
const probeCode = probe.code;
|
|
9862
|
+
return isDescriptorExhaustion(probeCode) ? probeCode : void 0;
|
|
9863
|
+
}
|
|
9864
|
+
}
|
|
9865
|
+
var descriptorExhaustionNoticed = false;
|
|
9866
|
+
function shedIdleConnectionsForDescriptors(failing, ctx, code, socketErrorCode) {
|
|
9867
|
+
const registered = connectionEntries().filter((entry) => entry !== failing);
|
|
9868
|
+
const idle = registered.filter((entry) => !entry.inFlight && entry.generation !== "isolated").sort((left, right) => left.lastUsedAt - right.lastUsedAt);
|
|
9869
|
+
for (const victim of idle) {
|
|
9870
|
+
const idleMs = Math.max(0, victim.options.now() - victim.lastUsedAt);
|
|
9871
|
+
victim.debug(
|
|
9872
|
+
`shedding idle ${victim.generation} connection after ${code}: connection=${victim.debugId} idle_ms=${idleMs} reason=descriptor_exhaustion`
|
|
9873
|
+
);
|
|
9874
|
+
victim.inFlight = false;
|
|
9875
|
+
victim.current = void 0;
|
|
9876
|
+
unregisterEntry(victim);
|
|
9877
|
+
try {
|
|
9878
|
+
victim.socket.terminate();
|
|
9879
|
+
} catch {
|
|
9880
|
+
}
|
|
9881
|
+
}
|
|
9882
|
+
failing.debug(
|
|
9883
|
+
`${code} opening connection=${failing.debugId}: registered=${registered.length} shed=${idle.length}` + (socketErrorCode && socketErrorCode !== code ? ` reported_as=${socketErrorCode}` : "")
|
|
9884
|
+
);
|
|
9885
|
+
emitContextDiagnostic(failing, ctx, {
|
|
9886
|
+
event: "ws_descriptor_exhaustion",
|
|
9887
|
+
code,
|
|
9888
|
+
detectedBy: socketErrorCode === code ? "error_code" : "descriptor_probe",
|
|
9889
|
+
socketErrorCode: boundedDiagnosticIdentifier(socketErrorCode),
|
|
9890
|
+
heldConnections: registered.length,
|
|
9891
|
+
shedConnections: idle.length
|
|
9892
|
+
});
|
|
9893
|
+
if (descriptorExhaustionNoticed) return;
|
|
9894
|
+
descriptorExhaustionNoticed = true;
|
|
9895
|
+
emitParentNotice(
|
|
9896
|
+
`clodex: warning: ${descriptorLimitName(code)} was reached (${code}) while opening a ChatGPT connection. clodex had ${registered.length} pooled connection(s) registered and closed ${idle.length} idle one(s) to recover; each parallel conversation keeps one open. ${descriptorLimitRemedy(code)} Further open-file warnings suppressed.`
|
|
9897
|
+
);
|
|
9898
|
+
}
|
|
9899
|
+
function descriptorLimitName(code) {
|
|
9900
|
+
return code === "ENFILE" ? "the system-wide open-file limit" : "this process's open-file limit";
|
|
9901
|
+
}
|
|
9902
|
+
function descriptorLimitRemedy(code) {
|
|
9903
|
+
return code === "ENFILE" ? "Close other programs holding many files, or raise the system-wide file limit, if this recurs." : "Raise it with `ulimit -n` in the shell that starts clodex (or the service limit for a launchd/systemd-managed server) if this recurs.";
|
|
9904
|
+
}
|
|
9905
|
+
function descriptorExhaustionMessage(code, registered) {
|
|
9906
|
+
return `${descriptorLimitName(code)} was reached (${code}) while opening a ChatGPT connection with ${registered} pooled connection(s) registered; ${descriptorLimitRemedy(code)}`;
|
|
9907
|
+
}
|
|
9848
9908
|
function isModelDataEvent(type) {
|
|
9849
9909
|
return Boolean(type && (type.includes(".delta") || type === "response.output_item.added" || type === "response.output_item.done"));
|
|
9850
9910
|
}
|
|
@@ -10177,13 +10237,21 @@ function createConnection(WebSocket, wsUrl, headers, persistent, key, options, d
|
|
|
10177
10237
|
socket.on("error", (error) => {
|
|
10178
10238
|
const ctx = entry.current;
|
|
10179
10239
|
if (ctx) {
|
|
10240
|
+
const socketErrorCode = error.code;
|
|
10180
10241
|
const details = {
|
|
10181
10242
|
source: "socket_error",
|
|
10182
10243
|
socketErrorName: boundedDiagnosticIdentifier(error.name),
|
|
10183
|
-
socketErrorCode: boundedDiagnosticIdentifier(
|
|
10244
|
+
socketErrorCode: boundedDiagnosticIdentifier(socketErrorCode),
|
|
10184
10245
|
...diagnosticTextFingerprint("errorMessage", error.message)
|
|
10185
10246
|
};
|
|
10186
|
-
|
|
10247
|
+
let message = error.message;
|
|
10248
|
+
const exhaustion = entry.open ? void 0 : descriptorExhaustionCode(error);
|
|
10249
|
+
if (exhaustion) {
|
|
10250
|
+
const registered = connectionEntries().filter((other) => other !== entry).length;
|
|
10251
|
+
message = descriptorExhaustionMessage(exhaustion, registered);
|
|
10252
|
+
shedIdleConnectionsForDescriptors(entry, ctx, exhaustion, socketErrorCode);
|
|
10253
|
+
}
|
|
10254
|
+
handleTransportFailure(entry, ctx, message, details);
|
|
10187
10255
|
} else deleteEntry(entry);
|
|
10188
10256
|
});
|
|
10189
10257
|
socket.on("close", (code, reason) => {
|
|
@@ -10204,13 +10272,16 @@ function createConnection(WebSocket, wsUrl, headers, persistent, key, options, d
|
|
|
10204
10272
|
});
|
|
10205
10273
|
return entry;
|
|
10206
10274
|
}
|
|
10275
|
+
function diagnosticCap(cap) {
|
|
10276
|
+
return Number.isFinite(cap) ? cap : null;
|
|
10277
|
+
}
|
|
10207
10278
|
function envConnectionCap(name, log12) {
|
|
10208
10279
|
const raw = process.env[name];
|
|
10209
10280
|
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
10210
10281
|
const value = Number(raw.trim());
|
|
10211
|
-
if (!Number.isInteger(value) || value < 1
|
|
10282
|
+
if (!Number.isInteger(value) || value < 1) {
|
|
10212
10283
|
try {
|
|
10213
|
-
log12?.(`ws: ignoring ${name}=${raw} (expected
|
|
10284
|
+
log12?.(`ws: ignoring ${name}=${raw} (expected a positive integer)`);
|
|
10214
10285
|
} catch {
|
|
10215
10286
|
}
|
|
10216
10287
|
return void 0;
|
|
@@ -10510,8 +10581,10 @@ function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
|
|
|
10510
10581
|
activeConnectionCount: connectionCount(),
|
|
10511
10582
|
nurseryConnectionCount: connectionCountByGeneration("nursery"),
|
|
10512
10583
|
establishedConnectionCount: connectionCountByGeneration("established"),
|
|
10513
|
-
|
|
10514
|
-
|
|
10584
|
+
// `null` is unbounded, the shipped default. A number is a finite cap on
|
|
10585
|
+
// the idle pool from an env or programmatic override.
|
|
10586
|
+
maxConnections: diagnosticCap(resolvedOptions.maxConnections),
|
|
10587
|
+
maxNurseryConnections: diagnosticCap(resolvedOptions.maxNurseryConnections),
|
|
10515
10588
|
selectedConnectionId: selected?.debugId,
|
|
10516
10589
|
selectedGeneration: selected?.generation,
|
|
10517
10590
|
continuationMatchMode: selectedMatch?.mode,
|
|
@@ -11548,7 +11621,7 @@ function thinkingProviderOptions(npm) {
|
|
|
11548
11621
|
|
|
11549
11622
|
// src/proxy.ts
|
|
11550
11623
|
import { createServer } from "http";
|
|
11551
|
-
import { appendFileSync as appendFileSync2, openSync as
|
|
11624
|
+
import { appendFileSync as appendFileSync2, openSync as openSync7, writeSync as writeSync5, closeSync as closeSync7 } from "fs";
|
|
11552
11625
|
|
|
11553
11626
|
// src/http-utils.ts
|
|
11554
11627
|
import * as zlib from "zlib";
|
|
@@ -11831,7 +11904,13 @@ function anthropicUpstreamHeaders(apiKey, stream = false, inboundBeta, authType,
|
|
|
11831
11904
|
}
|
|
11832
11905
|
var UpstreamUnreachableError = class extends Error {
|
|
11833
11906
|
constructor(cause) {
|
|
11834
|
-
|
|
11907
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
11908
|
+
const directCode = cause !== null && typeof cause === "object" ? cause.code : void 0;
|
|
11909
|
+
const nestedCause = cause instanceof Error ? cause.cause : void 0;
|
|
11910
|
+
const nestedCode = nestedCause !== null && typeof nestedCause === "object" ? nestedCause.code : void 0;
|
|
11911
|
+
const code = typeof directCode === "string" ? directCode : typeof nestedCode === "string" ? nestedCode : void 0;
|
|
11912
|
+
const detailWithCode = code && !detail.includes(code) ? detail ? `${detail} (${code})` : code : detail;
|
|
11913
|
+
super(`Upstream unreachable: ${detailWithCode}`, { cause });
|
|
11835
11914
|
this.name = "UpstreamUnreachableError";
|
|
11836
11915
|
}
|
|
11837
11916
|
};
|
|
@@ -13346,12 +13425,12 @@ function createTranslationLifecycle(logPath, requestId, claudeSessionId, modelId
|
|
|
13346
13425
|
function appendSecureLog(logPath, line) {
|
|
13347
13426
|
const redacted = redactTraceLine(line);
|
|
13348
13427
|
try {
|
|
13349
|
-
const fd =
|
|
13428
|
+
const fd = openSync7(logPath, "a", 384);
|
|
13350
13429
|
try {
|
|
13351
13430
|
writeSync5(fd, `${(/* @__PURE__ */ new Date()).toISOString()} ${redacted}
|
|
13352
13431
|
`);
|
|
13353
13432
|
} finally {
|
|
13354
|
-
|
|
13433
|
+
closeSync7(fd);
|
|
13355
13434
|
}
|
|
13356
13435
|
} catch {
|
|
13357
13436
|
try {
|
|
@@ -14222,10 +14301,10 @@ function tryAcquirePatchLock(lockPath = getPatchLockPath(), opts = {}) {
|
|
|
14222
14301
|
mkdirSync5(join8(lockPath, ".."), { recursive: true, mode: 448 });
|
|
14223
14302
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
14224
14303
|
try {
|
|
14225
|
-
const fd =
|
|
14304
|
+
const fd = openSync8(lockPath, "wx");
|
|
14226
14305
|
const content = { pid: process.pid, startedAt: now };
|
|
14227
14306
|
writeFileSync6(fd, JSON.stringify(content));
|
|
14228
|
-
|
|
14307
|
+
closeSync8(fd);
|
|
14229
14308
|
return () => {
|
|
14230
14309
|
try {
|
|
14231
14310
|
unlinkSync3(lockPath);
|
|
@@ -15157,13 +15236,13 @@ function localProvidersToServerModels(localProviders) {
|
|
|
15157
15236
|
// src/registry/credential-cleanup-journal.ts
|
|
15158
15237
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
15159
15238
|
import {
|
|
15160
|
-
closeSync as
|
|
15239
|
+
closeSync as closeSync9,
|
|
15161
15240
|
existsSync as existsSync6,
|
|
15162
15241
|
fstatSync as fstatSync3,
|
|
15163
15242
|
fsyncSync as fsyncSync2,
|
|
15164
15243
|
lstatSync,
|
|
15165
15244
|
mkdirSync as mkdirSync6,
|
|
15166
|
-
openSync as
|
|
15245
|
+
openSync as openSync9,
|
|
15167
15246
|
readFileSync as readFileSync11,
|
|
15168
15247
|
renameSync as renameSync4,
|
|
15169
15248
|
unlinkSync as unlinkSync4,
|
|
@@ -15255,7 +15334,7 @@ function readJournalUnlocked(path) {
|
|
|
15255
15334
|
if (before.isSymbolicLink() || !before.isFile()) {
|
|
15256
15335
|
throw new Error("Credential cleanup journal must be a regular file.");
|
|
15257
15336
|
}
|
|
15258
|
-
fd =
|
|
15337
|
+
fd = openSync9(path, "r");
|
|
15259
15338
|
const opened = fstatSync3(fd);
|
|
15260
15339
|
if (before.dev !== opened.dev || before.ino !== opened.ino) {
|
|
15261
15340
|
throw new Error("Credential cleanup journal changed while opening.");
|
|
@@ -15276,19 +15355,19 @@ function readJournalUnlocked(path) {
|
|
|
15276
15355
|
const message = error instanceof Error ? error.message : String(error);
|
|
15277
15356
|
throw new Error(`Could not read credential cleanup journal: ${message}`);
|
|
15278
15357
|
} finally {
|
|
15279
|
-
if (fd !== void 0)
|
|
15358
|
+
if (fd !== void 0) closeSync9(fd);
|
|
15280
15359
|
}
|
|
15281
15360
|
}
|
|
15282
15361
|
function syncParentDirectory(path) {
|
|
15283
15362
|
let fd;
|
|
15284
15363
|
try {
|
|
15285
|
-
fd =
|
|
15364
|
+
fd = openSync9(dirname6(path), "r");
|
|
15286
15365
|
fsyncSync2(fd);
|
|
15287
15366
|
} catch (error) {
|
|
15288
15367
|
const code = error.code;
|
|
15289
15368
|
if (code !== "EINVAL" && code !== "ENOTSUP" && code !== "EPERM") throw error;
|
|
15290
15369
|
} finally {
|
|
15291
|
-
if (fd !== void 0)
|
|
15370
|
+
if (fd !== void 0) closeSync9(fd);
|
|
15292
15371
|
}
|
|
15293
15372
|
}
|
|
15294
15373
|
function writeJournalUnlocked(journal, path) {
|
|
@@ -15298,17 +15377,17 @@ function writeJournalUnlocked(journal, path) {
|
|
|
15298
15377
|
const tmp = `${path}.${process.pid}.${randomUUID5()}.tmp`;
|
|
15299
15378
|
let fd;
|
|
15300
15379
|
try {
|
|
15301
|
-
fd =
|
|
15380
|
+
fd = openSync9(tmp, "wx", FILE_MODE4);
|
|
15302
15381
|
writeFileSync7(fd, `${JSON.stringify(journal, null, 2)}
|
|
15303
15382
|
`);
|
|
15304
15383
|
fsyncSync2(fd);
|
|
15305
|
-
|
|
15384
|
+
closeSync9(fd);
|
|
15306
15385
|
fd = void 0;
|
|
15307
15386
|
assertRegistryWriteOwnership(path);
|
|
15308
15387
|
renameSync4(tmp, path);
|
|
15309
15388
|
syncParentDirectory(path);
|
|
15310
15389
|
} finally {
|
|
15311
|
-
if (fd !== void 0)
|
|
15390
|
+
if (fd !== void 0) closeSync9(fd);
|
|
15312
15391
|
try {
|
|
15313
15392
|
unlinkSync4(tmp);
|
|
15314
15393
|
} catch (error) {
|
|
@@ -20298,6 +20377,7 @@ async function startHttpProxy(options) {
|
|
|
20298
20377
|
mitmServer.emit("connection", clientSocket);
|
|
20299
20378
|
return;
|
|
20300
20379
|
}
|
|
20380
|
+
clientSocket.once("error", () => clientSocket.destroy());
|
|
20301
20381
|
const target = authorityParts(req.url ?? "");
|
|
20302
20382
|
if (!target) {
|
|
20303
20383
|
clientSocket.end("HTTP/1.1 400 Bad Request\r\n\r\n");
|
|
@@ -22533,7 +22613,7 @@ Error: ${launchPlan.error}
|
|
|
22533
22613
|
return exitCode;
|
|
22534
22614
|
}
|
|
22535
22615
|
async function main(args = process.argv.slice(2)) {
|
|
22536
|
-
await
|
|
22616
|
+
await installOutboundDispatcher();
|
|
22537
22617
|
const parsed = parseArgs(args);
|
|
22538
22618
|
if (parsed.error) {
|
|
22539
22619
|
console.error(pc13.red(`
|