@bman654/clodex 2.11.7 → 2.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/cli.js +301 -44
- 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.12.1",
|
|
386
386
|
publishConfig: {
|
|
387
387
|
access: "public"
|
|
388
388
|
},
|
|
@@ -3884,16 +3884,17 @@ function applyClodexPatches(source, config) {
|
|
|
3884
3884
|
// src/patcher.ts
|
|
3885
3885
|
import { createHash as createHash9 } from "crypto";
|
|
3886
3886
|
import {
|
|
3887
|
+
chmodSync as chmodSync4,
|
|
3887
3888
|
copyFileSync,
|
|
3888
3889
|
existsSync as existsSync5,
|
|
3889
3890
|
mkdtempSync,
|
|
3890
3891
|
mkdirSync as mkdirSync5,
|
|
3891
3892
|
readFileSync as readFileSync10,
|
|
3892
|
-
renameSync as
|
|
3893
|
-
rmSync,
|
|
3893
|
+
renameSync as renameSync3,
|
|
3894
|
+
rmSync as rmSync2,
|
|
3894
3895
|
statSync as statSync8,
|
|
3895
3896
|
unlinkSync as unlinkSync3,
|
|
3896
|
-
writeFileSync as
|
|
3897
|
+
writeFileSync as writeFileSync6,
|
|
3897
3898
|
openSync as openSync7,
|
|
3898
3899
|
closeSync as closeSync7,
|
|
3899
3900
|
realpathSync as realpathSync2
|
|
@@ -7772,7 +7773,7 @@ function writeAll(fd, bytes, position, path) {
|
|
|
7772
7773
|
|
|
7773
7774
|
// src/patch-backup.ts
|
|
7774
7775
|
import { createHash as createHash5 } from "crypto";
|
|
7775
|
-
import { existsSync as existsSync4, readFileSync as readFileSync9, readdirSync, statSync as statSync7 } from "fs";
|
|
7776
|
+
import { existsSync as existsSync4, readFileSync as readFileSync9, readdirSync, renameSync as renameSync2, rmSync, statSync as statSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
7776
7777
|
import { homedir as homedir2 } from "os";
|
|
7777
7778
|
import { join as join7 } from "path";
|
|
7778
7779
|
var BACKUP_SHA_PREFIX_LENGTH = 16;
|
|
@@ -7790,9 +7791,60 @@ function backupVersionTag(version) {
|
|
|
7790
7791
|
function contentAddressedBackupPath(version, sha256, dir = backupDir()) {
|
|
7791
7792
|
return join7(dir, `claude-${backupVersionTag(version)}-${sha256.slice(0, BACKUP_SHA_PREFIX_LENGTH)}.orig`);
|
|
7792
7793
|
}
|
|
7794
|
+
function legacyBackupPath(version, dir = backupDir()) {
|
|
7795
|
+
return join7(dir, `claude-${backupVersionTag(version)}.orig`);
|
|
7796
|
+
}
|
|
7793
7797
|
function tweakccMirrorBackupPath(dir = backupDir()) {
|
|
7794
7798
|
return join7(dir, "native-binary.backup");
|
|
7795
7799
|
}
|
|
7800
|
+
function installProvenancePath(backupPath, binaryPath) {
|
|
7801
|
+
const tag = createHash5("sha256").update(binaryPath).digest("hex").slice(0, BACKUP_SHA_PREFIX_LENGTH);
|
|
7802
|
+
return `${backupPath}.for-${tag}.json`;
|
|
7803
|
+
}
|
|
7804
|
+
function installProvenancePattern(name) {
|
|
7805
|
+
return new RegExp(`^${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\.for-[0-9a-f]{${BACKUP_SHA_PREFIX_LENGTH}}\\.json$`);
|
|
7806
|
+
}
|
|
7807
|
+
function readInstallProvenance(path) {
|
|
7808
|
+
let raw;
|
|
7809
|
+
try {
|
|
7810
|
+
raw = readFileSync9(path, "utf8");
|
|
7811
|
+
} catch {
|
|
7812
|
+
return null;
|
|
7813
|
+
}
|
|
7814
|
+
let parsed;
|
|
7815
|
+
try {
|
|
7816
|
+
parsed = JSON.parse(raw);
|
|
7817
|
+
} catch {
|
|
7818
|
+
return "damaged";
|
|
7819
|
+
}
|
|
7820
|
+
if (typeof parsed !== "object" || parsed === null) return "damaged";
|
|
7821
|
+
const { install, assumed } = parsed;
|
|
7822
|
+
if (typeof install !== "string" || install === "") return "damaged";
|
|
7823
|
+
if (typeof assumed !== "boolean") return "damaged";
|
|
7824
|
+
return { install, assumed };
|
|
7825
|
+
}
|
|
7826
|
+
function recordBackupProvenance(backupPath, binaryPath, opts) {
|
|
7827
|
+
const target = installProvenancePath(backupPath, binaryPath);
|
|
7828
|
+
const existing = readInstallProvenance(target);
|
|
7829
|
+
if (existing && existing !== "damaged" && existing.install === binaryPath) {
|
|
7830
|
+
if (existing.assumed === opts.assumed) return existing.assumed ? "assumed" : "established";
|
|
7831
|
+
if (!existing.assumed) return "established";
|
|
7832
|
+
}
|
|
7833
|
+
const record = { install: binaryPath, assumed: opts.assumed };
|
|
7834
|
+
const temp = `${target}.tmp-${process.pid}-${Date.now().toString(36)}`;
|
|
7835
|
+
try {
|
|
7836
|
+
writeFileSync5(temp, `${JSON.stringify(record, null, 2)}
|
|
7837
|
+
`);
|
|
7838
|
+
renameSync2(temp, target);
|
|
7839
|
+
return opts.assumed ? "assumed" : "established";
|
|
7840
|
+
} catch (err) {
|
|
7841
|
+
try {
|
|
7842
|
+
rmSync(temp, { force: true });
|
|
7843
|
+
} catch {
|
|
7844
|
+
}
|
|
7845
|
+
throw err;
|
|
7846
|
+
}
|
|
7847
|
+
}
|
|
7796
7848
|
function scanPristineBackups(version, dir = backupDir()) {
|
|
7797
7849
|
const tag = backupVersionTag(version);
|
|
7798
7850
|
const pattern = new RegExp(`^claude-${tag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:-([0-9a-f]{${BACKUP_SHA_PREFIX_LENGTH}}))?\\.orig$`);
|
|
@@ -7802,6 +7854,27 @@ function scanPristineBackups(version, dir = backupDir()) {
|
|
|
7802
7854
|
} catch {
|
|
7803
7855
|
return { valid: [], corrupt: [] };
|
|
7804
7856
|
}
|
|
7857
|
+
const provenanceOf = (name) => {
|
|
7858
|
+
const recordPattern = installProvenancePattern(name);
|
|
7859
|
+
const installs = [];
|
|
7860
|
+
const assumedInstalls = [];
|
|
7861
|
+
const damagedProvenance = [];
|
|
7862
|
+
for (const entry of entries) {
|
|
7863
|
+
if (!recordPattern.test(entry)) continue;
|
|
7864
|
+
const path = join7(dir, entry);
|
|
7865
|
+
const record = readInstallProvenance(path);
|
|
7866
|
+
if (record === null || record === "damaged" || installProvenancePath(join7(dir, name), record.install) !== path) {
|
|
7867
|
+
damagedProvenance.push(path);
|
|
7868
|
+
continue;
|
|
7869
|
+
}
|
|
7870
|
+
(record.assumed ? assumedInstalls : installs).push(record.install);
|
|
7871
|
+
}
|
|
7872
|
+
return {
|
|
7873
|
+
installs: installs.sort(),
|
|
7874
|
+
assumedInstalls: assumedInstalls.sort(),
|
|
7875
|
+
damagedProvenance: damagedProvenance.sort()
|
|
7876
|
+
};
|
|
7877
|
+
};
|
|
7805
7878
|
const valid = [];
|
|
7806
7879
|
const corrupt = [];
|
|
7807
7880
|
for (const entry of entries.sort()) {
|
|
@@ -7822,9 +7895,9 @@ function scanPristineBackups(version, dir = backupDir()) {
|
|
|
7822
7895
|
corrupt.push(path);
|
|
7823
7896
|
continue;
|
|
7824
7897
|
}
|
|
7825
|
-
valid.push({ path, kind: "content-addressed", sha256 });
|
|
7898
|
+
valid.push({ path, kind: "content-addressed", sha256, ...provenanceOf(entry) });
|
|
7826
7899
|
} else {
|
|
7827
|
-
valid.push({ path, kind: "legacy", sha256 });
|
|
7900
|
+
valid.push({ path, kind: "legacy", sha256, ...provenanceOf(entry) });
|
|
7828
7901
|
}
|
|
7829
7902
|
}
|
|
7830
7903
|
return { valid, corrupt };
|
|
@@ -7846,7 +7919,7 @@ function looksLikeLegacyClodexPatch(source) {
|
|
|
7846
7919
|
}
|
|
7847
7920
|
function noBackupMessage(facts) {
|
|
7848
7921
|
const corrupt = facts.corruptBackups?.length ? ` (${facts.corruptBackups.length} backup file(s) for this version failed integrity checks and were ignored)` : "";
|
|
7849
|
-
return `claude ${facts.version}
|
|
7922
|
+
return `clodex holds no pristine backup of claude ${facts.version} it can attribute to ${facts.binaryPath}: none was found in ${backupDir()}${corrupt}. If that binary is patched, reinstall Claude Code to get a pristine one and run \`clodex patch\` again. If it was never patched, there is nothing to restore.`;
|
|
7850
7923
|
}
|
|
7851
7924
|
function identifiesABackup(manifest) {
|
|
7852
7925
|
return manifest.pristineSha256 !== void 0 || manifest.backupPath !== void 0;
|
|
@@ -7860,8 +7933,26 @@ function recordedBackupGoneMessage(facts, manifest) {
|
|
|
7860
7933
|
function otherInstallMessage(facts, otherBinaryPath) {
|
|
7861
7934
|
return `The patch manifest records a different Claude Code install (${otherBinaryPath}), so nothing establishes that a pristine backup tagged claude ${facts.version} in ${backupDir()} belongs to ${facts.binaryPath}. Two installs of one Claude Code version are different files, so restoring by version tag alone would overwrite this install with another one's bytes. Set TWEAKCC_CC_INSTALLATION_PATH=${otherBinaryPath} to restore that install instead, or reinstall Claude Code to make this one pristine.`;
|
|
7862
7935
|
}
|
|
7936
|
+
function otherInstallProvenanceMessage(facts, recorded) {
|
|
7937
|
+
const owners = [...new Set(recorded.flatMap((backup) => backup.installs))];
|
|
7938
|
+
return `The pristine backup(s) of claude ${facts.version} in ${backupDir()} are recorded as the pristine content of ${owners.join(", ")}, not of ${facts.binaryPath}. Two installs of one Claude Code version are different files, so restoring one of those would overwrite this install with bytes that were never its own. Set TWEAKCC_CC_INSTALLATION_PATH=${owners[0]} to restore that install instead, or reinstall Claude Code to make this one pristine.`;
|
|
7939
|
+
}
|
|
7940
|
+
function damagedProvenanceMessage(facts, damaged) {
|
|
7941
|
+
return `A pristine backup of claude ${facts.version} in ${backupDir()} carries a provenance record that clodex cannot read (${damaged.join(", ")}). Something recorded which install those bytes belong to and that record is damaged, so clodex will not fall back to matching on the claude version in the file name \u2014 on a machine with more than one install that would hand ${facts.binaryPath} bytes that were never its own. Delete the unreadable record to accept that fallback, or reinstall Claude Code to make this install pristine.`;
|
|
7942
|
+
}
|
|
7943
|
+
function contradictoryProvenanceMessage(facts, mine) {
|
|
7944
|
+
return `More than one pristine backup of claude ${facts.version} is recorded as the pristine content of ${facts.binaryPath} (${mine.map((backup) => backup.path).join(", ")}), and they do not hold the same bytes, so clodex cannot tell which one that install holds now \u2014 being snapshotted twice, at two different sets of unpatched bytes, reaches this state without either record being wrong. Delete whichever is stale to decide it: ${mine.map((backup) => installProvenancePath(backup.path, facts.binaryPath)).join(", ")}. Or reinstall the Claude Code at ${facts.binaryPath} and delete both.`;
|
|
7945
|
+
}
|
|
7946
|
+
function manifestContradictsRecordMessage(facts, manifestChoice, recorded) {
|
|
7947
|
+
return `The patch manifest names ${manifestChoice} as the pristine content of ${facts.binaryPath}, but ${recorded.map((backup) => backup.path).join(", ")} is recorded as that install's pristine content and holds different bytes. Nothing establishes which of them the install at that path is now \u2014 an executable replaced in place with a different build of the same claude version reaches exactly this state \u2014 so clodex will not pick one. Delete whichever of these records is stale to decide it: ${recorded.map((backup) => installProvenancePath(backup.path, facts.binaryPath)).join(", ")}. Or reinstall the Claude Code at ${facts.binaryPath} and delete both: a pristine install needs no backup, and \`clodex patch\` will record its own.`;
|
|
7948
|
+
}
|
|
7949
|
+
function assumedElsewhereMessage(facts, backups) {
|
|
7950
|
+
const others = [...new Set(backups.flatMap((backup) => backup.assumedInstalls))];
|
|
7951
|
+
return `The pristine backup(s) of claude ${facts.version} in ${backupDir()} have already been restored onto ${others.join(", ")} \u2014 not onto ${facts.binaryPath}. That was itself matched on the claude version in a file name, so it is not proof of ownership, but it is a reason not to hand the same bytes to a second install: two installs of one version are different files. Set TWEAKCC_CC_INSTALLATION_PATH=${others[0]} to restore that install, or reinstall Claude Code to make this one pristine.`;
|
|
7952
|
+
}
|
|
7863
7953
|
function selectRestoreSource(facts) {
|
|
7864
7954
|
const notes = [];
|
|
7955
|
+
let assumedForThisInstall = false;
|
|
7865
7956
|
const recorded = facts.manifest;
|
|
7866
7957
|
const speaksForThisVersion = !recorded?.claudeVersion || recorded.claudeVersion === facts.version;
|
|
7867
7958
|
const manifest = recorded && recorded.binaryPath === facts.binaryPath && speaksForThisVersion ? recorded : null;
|
|
@@ -7873,10 +7964,46 @@ function selectRestoreSource(facts) {
|
|
|
7873
7964
|
if (!chosen && manifest && identifiesABackup(manifest)) {
|
|
7874
7965
|
return { action: "error", message: recordedBackupGoneMessage(facts, manifest) };
|
|
7875
7966
|
}
|
|
7967
|
+
const manifestDescribesLiveBytes = !!manifest?.patchedSha256 && manifest.patchedSha256 === facts.liveSha256;
|
|
7968
|
+
if (chosen && !manifestDescribesLiveBytes) {
|
|
7969
|
+
const manifestChoice = chosen;
|
|
7970
|
+
const contradicting = facts.backups.filter(
|
|
7971
|
+
(backup) => backup.installs.includes(facts.binaryPath) && backup.sha256 !== manifestChoice.sha256
|
|
7972
|
+
);
|
|
7973
|
+
if (contradicting.length) {
|
|
7974
|
+
return {
|
|
7975
|
+
action: "error",
|
|
7976
|
+
message: manifestContradictsRecordMessage(facts, manifestChoice.path, contradicting)
|
|
7977
|
+
};
|
|
7978
|
+
}
|
|
7979
|
+
}
|
|
7980
|
+
if (!chosen) {
|
|
7981
|
+
const mine = facts.backups.filter((backup) => backup.installs.includes(facts.binaryPath));
|
|
7982
|
+
if (mine.length) {
|
|
7983
|
+
if (new Set(mine.map((backup) => backup.sha256)).size > 1) {
|
|
7984
|
+
return { action: "error", message: contradictoryProvenanceMessage(facts, mine) };
|
|
7985
|
+
}
|
|
7986
|
+
chosen = mine.find((backup) => backup.kind === "content-addressed") ?? mine[0];
|
|
7987
|
+
}
|
|
7988
|
+
}
|
|
7876
7989
|
if (!chosen) {
|
|
7877
7990
|
if (other) {
|
|
7878
7991
|
return facts.backups.length ? { action: "error", message: otherInstallMessage(facts, other.binaryPath) } : { action: "error", message: noBackupMessage(facts) };
|
|
7879
7992
|
}
|
|
7993
|
+
const recordedElsewhere = facts.backups.filter((backup) => backup.installs.length > 0);
|
|
7994
|
+
if (recordedElsewhere.length) {
|
|
7995
|
+
return { action: "error", message: otherInstallProvenanceMessage(facts, recordedElsewhere) };
|
|
7996
|
+
}
|
|
7997
|
+
const damaged = facts.backups.flatMap((backup) => backup.damagedProvenance);
|
|
7998
|
+
if (damaged.length) {
|
|
7999
|
+
return { action: "error", message: damagedProvenanceMessage(facts, damaged) };
|
|
8000
|
+
}
|
|
8001
|
+
const assumedElsewhere = facts.backups.filter(
|
|
8002
|
+
(backup) => backup.assumedInstalls.some((install) => install !== facts.binaryPath)
|
|
8003
|
+
);
|
|
8004
|
+
if (assumedElsewhere.length) {
|
|
8005
|
+
return { action: "error", message: assumedElsewhereMessage(facts, assumedElsewhere) };
|
|
8006
|
+
}
|
|
7880
8007
|
const distinct = [...new Set(facts.backups.map((backup) => backup.sha256))];
|
|
7881
8008
|
if (distinct.length > 1) {
|
|
7882
8009
|
return {
|
|
@@ -7886,12 +8013,14 @@ function selectRestoreSource(facts) {
|
|
|
7886
8013
|
}
|
|
7887
8014
|
chosen = facts.backups.find((backup) => backup.kind === "content-addressed") ?? facts.backups[0];
|
|
7888
8015
|
if (chosen) {
|
|
8016
|
+
assumedForThisInstall = true;
|
|
7889
8017
|
notes.push(
|
|
7890
|
-
`
|
|
8018
|
+
`Neither a patch manifest nor a provenance record ties ${chosen.path} to ${facts.binaryPath}, so it is being used as that install's pristine content on the strength of its claude ${facts.version} version tag alone \u2014 it predates the records clodex now writes. On a machine with more than one Claude Code install those bytes may belong to the other one, and clodex will not record this guess as provenance.`
|
|
7891
8019
|
);
|
|
7892
8020
|
}
|
|
7893
8021
|
}
|
|
7894
8022
|
if (!chosen) return { action: "error", message: noBackupMessage(facts) };
|
|
8023
|
+
if (manifest?.pristineProvenance === "assumed") assumedForThisInstall = true;
|
|
7895
8024
|
return {
|
|
7896
8025
|
action: "restore",
|
|
7897
8026
|
backupPath: chosen.path,
|
|
@@ -7900,6 +8029,7 @@ function selectRestoreSource(facts) {
|
|
|
7900
8029
|
// another version's binary, stored under a mislabeled name by an older
|
|
7901
8030
|
// clodex. Executing it is the only evidence available; require it.
|
|
7902
8031
|
probeVersion: chosen.kind === "legacy",
|
|
8032
|
+
assumedForThisInstall,
|
|
7903
8033
|
notes
|
|
7904
8034
|
};
|
|
7905
8035
|
}
|
|
@@ -8847,7 +8977,7 @@ function instructionChangeSummary(previous, current) {
|
|
|
8847
8977
|
const firstDiffLine = previous.slice(0, prefix).split("\n").length;
|
|
8848
8978
|
return `instructions changed: previous_chars=${previous.length} current_chars=${current.length} common_prefix_chars=${prefix} common_suffix_chars=${suffix} first_diff_line=${firstDiffLine}`;
|
|
8849
8979
|
}
|
|
8850
|
-
function responsesWebSocketPartitionKey(wsUrl, payload, options = {}, authorizationFingerprint = "") {
|
|
8980
|
+
function responsesWebSocketPartitionKey(wsUrl, payload, options = {}, authorizationFingerprint = "", claudeAgentId = "") {
|
|
8851
8981
|
const promptCacheKey = payload.prompt_cache_key;
|
|
8852
8982
|
const model = payload.model;
|
|
8853
8983
|
if (typeof promptCacheKey !== "string" || !promptCacheKey || typeof model !== "string" || !model) return void 0;
|
|
@@ -8860,7 +8990,8 @@ function responsesWebSocketPartitionKey(wsUrl, payload, options = {}, authorizat
|
|
|
8860
8990
|
model,
|
|
8861
8991
|
effort,
|
|
8862
8992
|
promptCacheKey,
|
|
8863
|
-
authorizationFingerprint
|
|
8993
|
+
authorizationFingerprint,
|
|
8994
|
+
claudeAgentId
|
|
8864
8995
|
].join("");
|
|
8865
8996
|
return createHash6("sha256").update(material).digest("hex");
|
|
8866
8997
|
}
|
|
@@ -10019,16 +10150,18 @@ function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
|
|
|
10019
10150
|
}
|
|
10020
10151
|
if (hasResponsesLiteHeader(headers)) payload = applyResponsesLiteShape(payload);
|
|
10021
10152
|
const authorizationFingerprint = authorizationHeaderFingerprint(headers);
|
|
10153
|
+
const diagnosticCorrelation = diagnosticContext.getStore();
|
|
10154
|
+
const claudeAgentId = diagnosticCorrelation?.claudeAgentId ?? "";
|
|
10022
10155
|
const partitionKey = responsesWebSocketPartitionKey(
|
|
10023
10156
|
wsUrl,
|
|
10024
10157
|
payload,
|
|
10025
10158
|
options,
|
|
10026
|
-
authorizationFingerprint
|
|
10159
|
+
authorizationFingerprint,
|
|
10160
|
+
claudeAgentId
|
|
10027
10161
|
);
|
|
10028
10162
|
const promptFingerprint = responsesWebSocketPromptFingerprint(payload);
|
|
10029
10163
|
const promptFieldHashes = responsesWebSocketPromptFieldHashes(payload);
|
|
10030
10164
|
const instructionsSnapshot = instructionsFromPayload(payload);
|
|
10031
|
-
const diagnosticCorrelation = diagnosticContext.getStore();
|
|
10032
10165
|
let now = resolvedOptions.now();
|
|
10033
10166
|
const evictions = cleanupExpiredConnections(now);
|
|
10034
10167
|
let canonicalClientItems;
|
|
@@ -10236,7 +10369,9 @@ function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
|
|
|
10236
10369
|
accountIdHash: options.accountId ? createHash6("sha256").update(options.accountId).digest("hex").slice(0, 16) : "",
|
|
10237
10370
|
model: typeof payload.model === "string" ? payload.model : void 0,
|
|
10238
10371
|
effort: typeof payload.reasoning?.effort === "string" ? String(payload.reasoning.effort).trim().toLowerCase() : "",
|
|
10239
|
-
promptCacheKey: typeof payload.prompt_cache_key === "string" ? payload.prompt_cache_key : void 0
|
|
10372
|
+
promptCacheKey: typeof payload.prompt_cache_key === "string" ? payload.prompt_cache_key : void 0,
|
|
10373
|
+
claudeAgentId: claudeAgentId || void 0,
|
|
10374
|
+
claudeParentAgentId: diagnosticCorrelation?.claudeParentAgentId
|
|
10240
10375
|
},
|
|
10241
10376
|
promptFingerprint,
|
|
10242
10377
|
promptFieldHashes,
|
|
@@ -12134,6 +12269,18 @@ function extractClaudeSessionId(body, headerFallback) {
|
|
|
12134
12269
|
}
|
|
12135
12270
|
return validClaudeSessionId(headerFallback);
|
|
12136
12271
|
}
|
|
12272
|
+
var CLAUDE_AGENT_ID_RE = /^[A-Za-z0-9._-]{1,128}$/;
|
|
12273
|
+
function extractClaudeAgentIds(headers) {
|
|
12274
|
+
const read = (name) => {
|
|
12275
|
+
const raw = headers[name];
|
|
12276
|
+
const value = (Array.isArray(raw) ? raw[0] : raw)?.trim();
|
|
12277
|
+
return value && CLAUDE_AGENT_ID_RE.test(value) ? value : void 0;
|
|
12278
|
+
};
|
|
12279
|
+
return {
|
|
12280
|
+
claudeAgentId: read("x-claude-code-agent-id"),
|
|
12281
|
+
claudeParentAgentId: read("x-claude-code-parent-agent-id")
|
|
12282
|
+
};
|
|
12283
|
+
}
|
|
12137
12284
|
function claudeSessionPromptCacheKey(sessionId) {
|
|
12138
12285
|
return "relay-session-" + createHash8("sha256").update(sessionId).digest("hex").slice(0, 32);
|
|
12139
12286
|
}
|
|
@@ -13345,6 +13492,7 @@ async function startProxyCatalog(routes, defaultAliasId, debug = false, inferenc
|
|
|
13345
13492
|
const openAiOAuth = isOpenAiOAuthRoute(route);
|
|
13346
13493
|
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"];
|
|
13347
13494
|
const claudeSessionId = extractClaudeSessionId(anthropicBody, claudeSessionIdHeader);
|
|
13495
|
+
const claudeAgentIds = extractClaudeAgentIds(req.headers);
|
|
13348
13496
|
const translationLifecycle = createTranslationLifecycle(
|
|
13349
13497
|
inferenceLogPath,
|
|
13350
13498
|
relayRequestId,
|
|
@@ -13418,7 +13566,7 @@ async function startProxyCatalog(routes, defaultAliasId, debug = false, inferenc
|
|
|
13418
13566
|
keepAlive.unref();
|
|
13419
13567
|
try {
|
|
13420
13568
|
await withResponsesWebSocketDiagnosticContext(
|
|
13421
|
-
{ requestId: relayRequestId, claudeSessionId },
|
|
13569
|
+
{ requestId: relayRequestId, claudeSessionId, ...claudeAgentIds },
|
|
13422
13570
|
() => streamAnthropicResponse(
|
|
13423
13571
|
model,
|
|
13424
13572
|
params,
|
|
@@ -13449,7 +13597,7 @@ async function startProxyCatalog(routes, defaultAliasId, debug = false, inferenc
|
|
|
13449
13597
|
res.end();
|
|
13450
13598
|
} else {
|
|
13451
13599
|
const anthropicResponse = await withResponsesWebSocketDiagnosticContext(
|
|
13452
|
-
{ requestId: relayRequestId, claudeSessionId },
|
|
13600
|
+
{ requestId: relayRequestId, claudeSessionId, ...claudeAgentIds },
|
|
13453
13601
|
() => generateAnthropicResponse(
|
|
13454
13602
|
model,
|
|
13455
13603
|
params,
|
|
@@ -13782,7 +13930,7 @@ function readPatchManifest(path = getPatchManifestPath()) {
|
|
|
13782
13930
|
}
|
|
13783
13931
|
function writePatchManifest(manifest, path = getPatchManifestPath()) {
|
|
13784
13932
|
mkdirSync5(getAppHome(), { recursive: true, mode: 448 });
|
|
13785
|
-
|
|
13933
|
+
writeFileSync6(path, `${JSON.stringify(manifest, null, 2)}
|
|
13786
13934
|
`, { encoding: "utf8", mode: 384 });
|
|
13787
13935
|
}
|
|
13788
13936
|
function buildPatchModelConfig(favorites, aliases, modelMetaFor) {
|
|
@@ -13940,7 +14088,7 @@ function tryAcquirePatchLock(lockPath = getPatchLockPath(), opts = {}) {
|
|
|
13940
14088
|
try {
|
|
13941
14089
|
const fd = openSync7(lockPath, "wx");
|
|
13942
14090
|
const content = { pid: process.pid, startedAt: now };
|
|
13943
|
-
|
|
14091
|
+
writeFileSync6(fd, JSON.stringify(content));
|
|
13944
14092
|
closeSync7(fd);
|
|
13945
14093
|
return () => {
|
|
13946
14094
|
try {
|
|
@@ -13965,10 +14113,19 @@ function tryAcquirePatchLock(lockPath = getPatchLockPath(), opts = {}) {
|
|
|
13965
14113
|
}
|
|
13966
14114
|
return null;
|
|
13967
14115
|
}
|
|
14116
|
+
var ignoredLaunchOverride = null;
|
|
14117
|
+
function takeIgnoredLaunchOverride() {
|
|
14118
|
+
const ignored = ignoredLaunchOverride;
|
|
14119
|
+
ignoredLaunchOverride = null;
|
|
14120
|
+
return ignored;
|
|
14121
|
+
}
|
|
13968
14122
|
function resolveClaudeBinaryForPatch() {
|
|
13969
|
-
const envOverride = process.env["TWEAKCC_CC_INSTALLATION_PATH"];
|
|
14123
|
+
const envOverride = process.env["TWEAKCC_CC_INSTALLATION_PATH"]?.trim() || null;
|
|
13970
14124
|
const nativeSymlink = join8(homedir3(), ".local", "bin", "claude");
|
|
13971
|
-
|
|
14125
|
+
if (envOverride && !existsSync5(envOverride)) {
|
|
14126
|
+
return { ok: false, reason: "patch-target-missing", declaredPath: envOverride };
|
|
14127
|
+
}
|
|
14128
|
+
const source = envOverride || (existsSync5(nativeSymlink) ? nativeSymlink : null) || findClaudeBinary();
|
|
13972
14129
|
if (!source) return { ok: false, reason: "binary-not-found" };
|
|
13973
14130
|
let resolved;
|
|
13974
14131
|
try {
|
|
@@ -13988,6 +14145,17 @@ function resolveClaudeBinaryForPatch() {
|
|
|
13988
14145
|
};
|
|
13989
14146
|
}
|
|
13990
14147
|
resolved = followed.path;
|
|
14148
|
+
const launchOverride = process.env["CLODEX_CLAUDE_PATH"]?.trim() || null;
|
|
14149
|
+
let launchOverrideResolved = null;
|
|
14150
|
+
if (launchOverride) {
|
|
14151
|
+
try {
|
|
14152
|
+
const followedOverride = resolveThroughNpmShims(realpathSync2(launchOverride));
|
|
14153
|
+
launchOverrideResolved = followedOverride.ok ? followedOverride.path : realpathSync2(launchOverride);
|
|
14154
|
+
} catch {
|
|
14155
|
+
launchOverrideResolved = launchOverride;
|
|
14156
|
+
}
|
|
14157
|
+
}
|
|
14158
|
+
ignoredLaunchOverride = launchOverrideResolved && launchOverrideResolved !== resolved ? { used: resolved, ignored: launchOverride } : null;
|
|
13991
14159
|
try {
|
|
13992
14160
|
if (!statSync8(resolved).isFile()) return { ok: false, reason: "binary-not-found" };
|
|
13993
14161
|
} catch {
|
|
@@ -14011,7 +14179,7 @@ function installScriptCommand(path) {
|
|
|
14011
14179
|
}
|
|
14012
14180
|
function describePatchTargetFailure(target, command = "patch") {
|
|
14013
14181
|
if (target.reason === "launcher-unresolved") {
|
|
14014
|
-
return `${target.shimPath} starts Claude Code but is not Claude Code itself, and clodex could not follow it: ${target.detail}. clodex will not patch a launcher script \u2014 that fails with "Unable to detect installation type". Set
|
|
14182
|
+
return `${target.shimPath} starts Claude Code but is not Claude Code itself, and clodex could not follow it: ${target.detail}. clodex will not patch a launcher script \u2014 that fails with "Unable to detect installation type". Set TWEAKCC_CC_INSTALLATION_PATH to the Claude Code program itself (for an npm install on Windows that is node_modules\\@anthropic-ai\\claude-code\\bin\\claude.exe under the directory holding the launcher), then run the command again.`;
|
|
14015
14183
|
}
|
|
14016
14184
|
if (target.reason === "native-binary-missing") {
|
|
14017
14185
|
const installer = installScriptCommand(target.installScriptPath);
|
|
@@ -14020,6 +14188,9 @@ function describePatchTargetFailure(target, command = "patch") {
|
|
|
14020
14188
|
const restore = command === "restore" ? ` If you need to restore by hand, pristine backups are in ${backupDir()}.` : "";
|
|
14021
14189
|
return `${target.binaryPath} is Claude Code's npm placeholder, not its native binary, so the npm install is incomplete. ${remedy} ${retry}${restore} If this is a custom wrapper rather than the npm placeholder, set TWEAKCC_CC_INSTALLATION_PATH to the native Claude Code binary.`;
|
|
14022
14190
|
}
|
|
14191
|
+
if (target.reason === "patch-target-missing") {
|
|
14192
|
+
return `TWEAKCC_CC_INSTALLATION_PATH is set to ${target.declaredPath}, which does not exist. clodex will not look for another Claude Code instead \u2014 patching or restoring a different install than the one you named is how one install's pristine bytes end up over another's. Point it at the Claude Code program, or unset it to let clodex find your install.`;
|
|
14193
|
+
}
|
|
14023
14194
|
return target.reason === "binary-not-found" ? "claude binary not found. Install Claude Code or set TWEAKCC_CC_INSTALLATION_PATH." : `Could not determine the version of ${target.binaryPath} (\`claude --version\` failed). clodex will not patch a binary whose version it cannot read, because the version selects the pristine backup it patches from. If a previous patch left the install broken, \`clodex patch --restore\` still works \u2014 it reads the version from the patch manifest.`;
|
|
14024
14195
|
}
|
|
14025
14196
|
function summarizePatchResults(results) {
|
|
@@ -14042,14 +14213,15 @@ function verifyPristineSource(plan, version) {
|
|
|
14042
14213
|
message: `Refusing to use ${plan.backupPath} as the pristine source for claude ${version}: it reports ${backupVersion ? `version ${backupVersion}` : "no version at all"}. That backup predates content-addressed backup names and does not hold this version's bytes. Remove it (or reinstall Claude Code), then run \`clodex patch\`.`
|
|
14043
14214
|
};
|
|
14044
14215
|
}
|
|
14045
|
-
function
|
|
14216
|
+
function publishFileByRename(from, to, mode) {
|
|
14046
14217
|
const temp = `${to}.tmp-${process.pid}-${Date.now().toString(36)}`;
|
|
14047
14218
|
try {
|
|
14048
14219
|
copyFileSync(from, temp);
|
|
14049
|
-
|
|
14220
|
+
if (mode !== void 0) chmodSync4(temp, mode);
|
|
14221
|
+
renameSync3(temp, to);
|
|
14050
14222
|
} catch (err) {
|
|
14051
14223
|
try {
|
|
14052
|
-
|
|
14224
|
+
rmSync2(temp, { force: true });
|
|
14053
14225
|
} catch {
|
|
14054
14226
|
}
|
|
14055
14227
|
throw err;
|
|
@@ -14113,6 +14285,7 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14113
14285
|
let patchedSha256;
|
|
14114
14286
|
let backup;
|
|
14115
14287
|
let pristineSha256;
|
|
14288
|
+
const pristine = { provenance: "established" };
|
|
14116
14289
|
try {
|
|
14117
14290
|
mkdirSync5(backupDir(), { recursive: true });
|
|
14118
14291
|
const { tryDetectInstallation, readContent, writeContent } = await import("tweakcc");
|
|
@@ -14161,6 +14334,18 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14161
14334
|
}
|
|
14162
14335
|
pristineSha256 = plan.pristineSha256;
|
|
14163
14336
|
backup = plan.backupPath;
|
|
14337
|
+
const inheritsAGuess = (path) => {
|
|
14338
|
+
const existing = readInstallProvenance(installProvenancePath(path, binaryPath));
|
|
14339
|
+
return existing === "damaged" || existing !== null && existing.assumed;
|
|
14340
|
+
};
|
|
14341
|
+
const provenanceAssumed = plan.action === "restore" && plan.assumedForThisInstall || inheritsAGuess(plan.backupPath) || inheritsAGuess(contentAddressedBackupPath(version, plan.pristineSha256)) || inheritsAGuess(legacyBackupPath(version)) || facts.backups.some(
|
|
14342
|
+
(candidate) => candidate.sha256 === plan.pristineSha256 && candidate.assumedInstalls.includes(binaryPath)
|
|
14343
|
+
);
|
|
14344
|
+
const recordProvenance = (path) => {
|
|
14345
|
+
if (recordBackupProvenance(path, binaryPath, { assumed: provenanceAssumed }) === "assumed") {
|
|
14346
|
+
pristine.provenance = "assumed";
|
|
14347
|
+
}
|
|
14348
|
+
};
|
|
14164
14349
|
if (!loaded) {
|
|
14165
14350
|
loaded = await seedCandidate(backup);
|
|
14166
14351
|
if (isPatchedClaudeSource(loaded.source)) {
|
|
@@ -14172,17 +14357,22 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14172
14357
|
`the patch candidate no longer matches the pristine bytes it was seeded from; refusing to publish it as ${plan.backupPath}`
|
|
14173
14358
|
);
|
|
14174
14359
|
}
|
|
14175
|
-
|
|
14360
|
+
recordProvenance(plan.backupPath);
|
|
14361
|
+
publishFileByRename(candidatePath, plan.backupPath);
|
|
14176
14362
|
}
|
|
14177
14363
|
const canonical = contentAddressedBackupPath(version, pristineSha256);
|
|
14178
14364
|
if (canonical !== backup) {
|
|
14365
|
+
recordProvenance(backup);
|
|
14366
|
+
recordProvenance(canonical);
|
|
14179
14367
|
const alreadyStored = facts.backups.some(
|
|
14180
14368
|
(candidate) => candidate.path === canonical && candidate.sha256 === pristineSha256
|
|
14181
14369
|
);
|
|
14182
|
-
if (!alreadyStored)
|
|
14370
|
+
if (!alreadyStored) publishFileByRename(backup, canonical);
|
|
14183
14371
|
backup = canonical;
|
|
14184
14372
|
}
|
|
14185
|
-
|
|
14373
|
+
publishFileByRename(backup, tweakccMirrorBackupPath());
|
|
14374
|
+
recordProvenance(backup);
|
|
14375
|
+
if (plan.backupPath !== backup) recordProvenance(plan.backupPath);
|
|
14186
14376
|
const builtIn = applyClodexPatches(loaded.source, desired.config);
|
|
14187
14377
|
results = builtIn.results;
|
|
14188
14378
|
const failedEffortPatches = requiredEffortPatchFailures(results);
|
|
@@ -14249,7 +14439,7 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14249
14439
|
else if (publishedBlob) resignMachOBinary(candidatePath);
|
|
14250
14440
|
patchedSize = statSync8(candidatePath).size;
|
|
14251
14441
|
patchedSha256 = sha256File(candidatePath);
|
|
14252
|
-
|
|
14442
|
+
renameSync3(candidatePath, binaryPath);
|
|
14253
14443
|
} catch (err) {
|
|
14254
14444
|
const detailLines = err instanceof PatchApplyError ? summarizePatchResults(err.results) : [];
|
|
14255
14445
|
if (opts.trace && detailLines.length) {
|
|
@@ -14264,7 +14454,7 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14264
14454
|
} finally {
|
|
14265
14455
|
if (candidateDir !== void 0) {
|
|
14266
14456
|
try {
|
|
14267
|
-
|
|
14457
|
+
rmSync2(candidateDir, { recursive: true, force: true });
|
|
14268
14458
|
} catch (err) {
|
|
14269
14459
|
if (opts.trace) {
|
|
14270
14460
|
process.stderr.write(
|
|
@@ -14287,6 +14477,7 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14287
14477
|
patchedSha256,
|
|
14288
14478
|
backupPath: backup,
|
|
14289
14479
|
pristineSha256,
|
|
14480
|
+
...pristine.provenance === "assumed" ? { pristineProvenance: "assumed" } : {},
|
|
14290
14481
|
patchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
14291
14482
|
};
|
|
14292
14483
|
writePatchManifest(manifest);
|
|
@@ -14300,7 +14491,7 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14300
14491
|
};
|
|
14301
14492
|
}
|
|
14302
14493
|
function runRestoreCommand(target) {
|
|
14303
|
-
if (!target.ok && (target.reason === "binary-not-found" || target.reason === "native-binary-missing")) {
|
|
14494
|
+
if (!target.ok && (target.reason === "binary-not-found" || target.reason === "patch-target-missing" || target.reason === "native-binary-missing")) {
|
|
14304
14495
|
p2.log.error(describePatchTargetFailure(target, "restore"));
|
|
14305
14496
|
return 1;
|
|
14306
14497
|
}
|
|
@@ -14335,16 +14526,65 @@ function runRestoreCommand(target) {
|
|
|
14335
14526
|
p2.log.error(verified.message);
|
|
14336
14527
|
return 1;
|
|
14337
14528
|
}
|
|
14338
|
-
|
|
14529
|
+
if (manifest && manifest.backupPath && manifest.binaryPath === binaryPath && manifest.claudeVersion !== version && manifest.backupPath !== plan.backupPath) {
|
|
14530
|
+
try {
|
|
14531
|
+
if (existsSync5(manifest.backupPath)) {
|
|
14532
|
+
recordBackupProvenance(manifest.backupPath, manifest.binaryPath, {
|
|
14533
|
+
assumed: manifest.pristineProvenance === "assumed"
|
|
14534
|
+
});
|
|
14535
|
+
}
|
|
14536
|
+
} catch (err) {
|
|
14537
|
+
p2.log.warn(
|
|
14538
|
+
`Could not record in ${backupDir()} that ${manifest.backupPath} holds the pristine bytes of claude ${manifest.claudeVersion} at ${manifest.binaryPath} (${err instanceof Error ? err.message : String(err)}). That version may need to be reinstalled rather than restored.`
|
|
14539
|
+
);
|
|
14540
|
+
}
|
|
14541
|
+
}
|
|
14542
|
+
let recorded;
|
|
14543
|
+
try {
|
|
14544
|
+
recorded = recordBackupProvenance(plan.backupPath, binaryPath, { assumed: plan.assumedForThisInstall });
|
|
14545
|
+
} catch (err) {
|
|
14546
|
+
recorded = "failed";
|
|
14547
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
14548
|
+
if (plan.assumedForThisInstall) {
|
|
14549
|
+
p2.log.error(
|
|
14550
|
+
`Refusing to restore ${binaryPath} from ${plan.backupPath}: nothing but the claude ${version} version tag ties those bytes to this install, and clodex cannot record that in ${backupDir()} (${detail}). Writing them without that record would leave the machine unable to tell afterwards that the match was a guess. Fix the backup directory, or reinstall Claude Code to make this install pristine.`
|
|
14551
|
+
);
|
|
14552
|
+
return 1;
|
|
14553
|
+
}
|
|
14554
|
+
p2.log.warn(
|
|
14555
|
+
`Could not record in ${backupDir()} that ${plan.backupPath} holds the pristine bytes of ${binaryPath} (${detail}). Restoring anyway and keeping the patch manifest, so that record is not lost \u2014 a later restore would otherwise have nothing tying that backup to this install.`
|
|
14556
|
+
);
|
|
14557
|
+
}
|
|
14558
|
+
let publishedMode;
|
|
14339
14559
|
try {
|
|
14340
|
-
|
|
14560
|
+
publishedMode = statSync8(binaryPath).mode;
|
|
14341
14561
|
} catch {
|
|
14342
14562
|
}
|
|
14563
|
+
try {
|
|
14564
|
+
publishFileByRename(plan.backupPath, binaryPath, publishedMode);
|
|
14565
|
+
} catch (err) {
|
|
14566
|
+
p2.log.warn(
|
|
14567
|
+
`Could not replace ${binaryPath} through a new file (${err instanceof Error ? err.message : String(err)}); writing the pristine bytes in place instead. If claude then fails to start with a code-signing error, copy the backup to a new file and move it over the binary by hand.`
|
|
14568
|
+
);
|
|
14569
|
+
copyFileSync(plan.backupPath, binaryPath);
|
|
14570
|
+
}
|
|
14571
|
+
if (recorded === "established" && (!manifest || manifest.binaryPath === binaryPath)) {
|
|
14572
|
+
try {
|
|
14573
|
+
unlinkSync3(getPatchManifestPath());
|
|
14574
|
+
} catch {
|
|
14575
|
+
}
|
|
14576
|
+
}
|
|
14343
14577
|
p2.log.success(`Restored pristine claude ${version} from ${plan.backupPath}.`);
|
|
14344
14578
|
return 0;
|
|
14345
14579
|
}
|
|
14346
14580
|
async function runPatchCommand(opts = {}) {
|
|
14347
14581
|
const target = resolveClaudeBinaryForPatch();
|
|
14582
|
+
const ignoredOverride = takeIgnoredLaunchOverride();
|
|
14583
|
+
if (ignoredOverride) {
|
|
14584
|
+
p2.log.warn(
|
|
14585
|
+
`CLODEX_CLAUDE_PATH is set to ${ignoredOverride.ignored}, but it does not choose what gets patched \u2014 ${ignoredOverride.used} does. CLODEX_CLAUDE_PATH selects the claude that gets LAUNCHED; set TWEAKCC_CC_INSTALLATION_PATH to patch a specific install.`
|
|
14586
|
+
);
|
|
14587
|
+
}
|
|
14348
14588
|
if (opts.restore) return runRestoreCommand(target);
|
|
14349
14589
|
if (!target.ok) {
|
|
14350
14590
|
p2.log.error(describePatchTargetFailure(target));
|
|
@@ -14387,6 +14627,19 @@ async function runPatchCommand(opts = {}) {
|
|
|
14387
14627
|
p2.log.warn("Another clodex process is patching the claude binary right now \u2014 skipped.");
|
|
14388
14628
|
return 1;
|
|
14389
14629
|
}
|
|
14630
|
+
if (manifest && manifest.backupPath && (manifest.binaryPath !== binaryPath || manifest.claudeVersion !== version)) {
|
|
14631
|
+
try {
|
|
14632
|
+
if (existsSync5(manifest.backupPath)) {
|
|
14633
|
+
recordBackupProvenance(manifest.backupPath, manifest.binaryPath, {
|
|
14634
|
+
assumed: manifest.pristineProvenance === "assumed"
|
|
14635
|
+
});
|
|
14636
|
+
}
|
|
14637
|
+
} catch (err) {
|
|
14638
|
+
p2.log.warn(
|
|
14639
|
+
`Could not record in ${backupDir()} that ${manifest.backupPath} holds the pristine bytes of ${manifest.binaryPath} before replacing the patch manifest (${err instanceof Error ? err.message : String(err)}). That install may need to be reinstalled rather than restored.`
|
|
14640
|
+
);
|
|
14641
|
+
}
|
|
14642
|
+
}
|
|
14390
14643
|
try {
|
|
14391
14644
|
const outcome = await applyPatch(binaryPath, version, desired, configHash, {
|
|
14392
14645
|
trace: opts.trace ?? false,
|
|
@@ -14776,9 +15029,9 @@ import {
|
|
|
14776
15029
|
mkdirSync as mkdirSync6,
|
|
14777
15030
|
openSync as openSync8,
|
|
14778
15031
|
readFileSync as readFileSync11,
|
|
14779
|
-
renameSync as
|
|
15032
|
+
renameSync as renameSync4,
|
|
14780
15033
|
unlinkSync as unlinkSync4,
|
|
14781
|
-
writeFileSync as
|
|
15034
|
+
writeFileSync as writeFileSync7
|
|
14782
15035
|
} from "fs";
|
|
14783
15036
|
import { dirname as dirname6 } from "path";
|
|
14784
15037
|
var JOURNAL_SCHEMA_VERSION = 1;
|
|
@@ -14910,13 +15163,13 @@ function writeJournalUnlocked(journal, path) {
|
|
|
14910
15163
|
let fd;
|
|
14911
15164
|
try {
|
|
14912
15165
|
fd = openSync8(tmp, "wx", FILE_MODE4);
|
|
14913
|
-
|
|
15166
|
+
writeFileSync7(fd, `${JSON.stringify(journal, null, 2)}
|
|
14914
15167
|
`);
|
|
14915
15168
|
fsyncSync2(fd);
|
|
14916
15169
|
closeSync8(fd);
|
|
14917
15170
|
fd = void 0;
|
|
14918
15171
|
assertRegistryWriteOwnership(path);
|
|
14919
|
-
|
|
15172
|
+
renameSync4(tmp, path);
|
|
14920
15173
|
syncParentDirectory(path);
|
|
14921
15174
|
} finally {
|
|
14922
15175
|
if (fd !== void 0) closeSync8(fd);
|
|
@@ -18218,6 +18471,7 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
|
18218
18471
|
const requestId = randomUUID5();
|
|
18219
18472
|
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"];
|
|
18220
18473
|
const claudeSessionId = extractClaudeSessionId(body, claudeSessionIdHeader);
|
|
18474
|
+
const claudeAgentIds = extractClaudeAgentIds(req.headers);
|
|
18221
18475
|
if (options.webSocketDiagnosticsLogPath) {
|
|
18222
18476
|
writeWebSocketDiagnosticRequestLog(options.webSocketDiagnosticsLogPath, {
|
|
18223
18477
|
requestId,
|
|
@@ -18382,7 +18636,7 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
|
18382
18636
|
res.write(chunk);
|
|
18383
18637
|
};
|
|
18384
18638
|
await withResponsesWebSocketDiagnosticContext(
|
|
18385
|
-
{ requestId, claudeSessionId },
|
|
18639
|
+
{ requestId, claudeSessionId, ...claudeAgentIds },
|
|
18386
18640
|
() => streamAnthropicResponse(languageModel, params, responseModelId, writeStreamChunk, void 0, {
|
|
18387
18641
|
abortSignal: clientAbort.signal,
|
|
18388
18642
|
initialInputTokens: estimateAnthropicInputTokens(body),
|
|
@@ -18398,7 +18652,7 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
|
18398
18652
|
res.end();
|
|
18399
18653
|
} else {
|
|
18400
18654
|
const anthropicResponse = await withResponsesWebSocketDiagnosticContext(
|
|
18401
|
-
{ requestId, claudeSessionId },
|
|
18655
|
+
{ requestId, claudeSessionId, ...claudeAgentIds },
|
|
18402
18656
|
() => generateAnthropicResponse(languageModel, params, responseModelId, {
|
|
18403
18657
|
forceStream: openAiOAuth,
|
|
18404
18658
|
abortSignal: clientAbort.signal,
|
|
@@ -18888,7 +19142,7 @@ import { createBrotliDecompress, createGunzip, createInflate } from "zlib";
|
|
|
18888
19142
|
|
|
18889
19143
|
// src/http-proxy/ca.ts
|
|
18890
19144
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
18891
|
-
import { chmodSync as
|
|
19145
|
+
import { chmodSync as chmodSync5, existsSync as existsSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "fs";
|
|
18892
19146
|
import { dirname as dirname7, join as join9, resolve as resolve3 } from "path";
|
|
18893
19147
|
import forge from "node-forge";
|
|
18894
19148
|
var CERT_DIR = "http-proxy";
|
|
@@ -18915,16 +19169,16 @@ function certPaths() {
|
|
|
18915
19169
|
};
|
|
18916
19170
|
}
|
|
18917
19171
|
function writePrivate(path, value) {
|
|
18918
|
-
|
|
18919
|
-
|
|
19172
|
+
writeFileSync8(path, value, { encoding: "utf8", mode: 384 });
|
|
19173
|
+
chmodSync5(path, 384);
|
|
18920
19174
|
}
|
|
18921
19175
|
function writePublic(path, value) {
|
|
18922
|
-
|
|
18923
|
-
|
|
19176
|
+
writeFileSync8(path, value, { encoding: "utf8", mode: 420 });
|
|
19177
|
+
chmodSync5(path, 420);
|
|
18924
19178
|
}
|
|
18925
19179
|
function generateCertificates(paths) {
|
|
18926
19180
|
mkdirSync7(paths.dir, { recursive: true, mode: 448 });
|
|
18927
|
-
|
|
19181
|
+
chmodSync5(paths.dir, 448);
|
|
18928
19182
|
const caKeys = forge.pki.rsa.generateKeyPair(2048);
|
|
18929
19183
|
const caCert = forge.pki.createCertificate();
|
|
18930
19184
|
caCert.publicKey = caKeys.publicKey;
|
|
@@ -19491,6 +19745,9 @@ function forwardToAdapter(req, res, rawBody, adapter, adapterRequest = http2.req
|
|
|
19491
19745
|
"Content-Length": String(rawBody.length),
|
|
19492
19746
|
"x-api-key": adapter.token,
|
|
19493
19747
|
...typeof req.headers["x-claude-code-session-id"] === "string" ? { "x-claude-code-session-id": req.headers["x-claude-code-session-id"] } : {},
|
|
19748
|
+
// Subagent identity: the relay partitions ChatGPT WebSocket heads by it.
|
|
19749
|
+
...typeof req.headers["x-claude-code-agent-id"] === "string" ? { "x-claude-code-agent-id": req.headers["x-claude-code-agent-id"] } : {},
|
|
19750
|
+
...typeof req.headers["x-claude-code-parent-agent-id"] === "string" ? { "x-claude-code-parent-agent-id": req.headers["x-claude-code-parent-agent-id"] } : {},
|
|
19494
19751
|
...lifecycle ? { "x-relay-request-id": lifecycle.requestId } : {}
|
|
19495
19752
|
}
|
|
19496
19753
|
}, (upstreamRes) => {
|