@bman654/clodex 2.12.0 → 2.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/cli.js +509 -132
- package/dist/cli.js.map +1 -1
- package/docs/opencode-go.md +2 -0
- 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.12.
|
|
385
|
+
version: "2.12.2",
|
|
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
|
|
@@ -4820,16 +4821,19 @@ var pricing_cache_default = {
|
|
|
4820
4821
|
]
|
|
4821
4822
|
};
|
|
4822
4823
|
|
|
4824
|
+
// src/data/opencode-go-models.ts
|
|
4825
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
4826
|
+
|
|
4823
4827
|
// src/data/opencode-go-models.json
|
|
4824
4828
|
var opencode_go_models_default = [
|
|
4825
4829
|
{
|
|
4826
4830
|
id: "deepseek-v4-flash",
|
|
4827
|
-
name: "DeepSeek V4 Flash
|
|
4831
|
+
name: "DeepSeek V4 Flash",
|
|
4828
4832
|
contextWindow: 1e6,
|
|
4829
4833
|
cost: {
|
|
4830
|
-
input: 0.
|
|
4831
|
-
output: 0.
|
|
4832
|
-
cache_read:
|
|
4834
|
+
input: 0.15,
|
|
4835
|
+
output: 0.6,
|
|
4836
|
+
cache_read: 3e-3
|
|
4833
4837
|
},
|
|
4834
4838
|
modelFormat: "openai",
|
|
4835
4839
|
npm: "@ai-sdk/openai-compatible",
|
|
@@ -4857,12 +4861,12 @@ var opencode_go_models_default = [
|
|
|
4857
4861
|
},
|
|
4858
4862
|
{
|
|
4859
4863
|
id: "deepseek-v4-pro",
|
|
4860
|
-
name: "DeepSeek V4 Pro",
|
|
4864
|
+
name: "DeepSeek V4 Pro (New)",
|
|
4861
4865
|
contextWindow: 1e6,
|
|
4862
4866
|
cost: {
|
|
4863
|
-
input: 0.
|
|
4864
|
-
output:
|
|
4865
|
-
cache_read:
|
|
4867
|
+
input: 0.66,
|
|
4868
|
+
output: 1.98,
|
|
4869
|
+
cache_read: 0.022
|
|
4866
4870
|
},
|
|
4867
4871
|
modelFormat: "openai",
|
|
4868
4872
|
npm: "@ai-sdk/openai-compatible",
|
|
@@ -4888,6 +4892,30 @@ var opencode_go_models_default = [
|
|
|
4888
4892
|
upstreamModelId: "deepseek-v4-pro",
|
|
4889
4893
|
family: "deepseek"
|
|
4890
4894
|
},
|
|
4895
|
+
{
|
|
4896
|
+
id: "deepseek-v4.1-flash",
|
|
4897
|
+
name: "DeepSeek V4.1 Flash",
|
|
4898
|
+
contextWindow: 1e6,
|
|
4899
|
+
cost: {
|
|
4900
|
+
input: 0.15,
|
|
4901
|
+
output: 0.6,
|
|
4902
|
+
cache_read: 3e-3
|
|
4903
|
+
},
|
|
4904
|
+
modelFormat: "anthropic",
|
|
4905
|
+
npm: "@ai-sdk/anthropic",
|
|
4906
|
+
apiUrl: "https://opencode.ai/zen/go",
|
|
4907
|
+
reasoning: true,
|
|
4908
|
+
modalities: [
|
|
4909
|
+
"text",
|
|
4910
|
+
"image"
|
|
4911
|
+
],
|
|
4912
|
+
compatibility: {
|
|
4913
|
+
supportsCountTokens: false,
|
|
4914
|
+
supportsReasoningEffort: false
|
|
4915
|
+
},
|
|
4916
|
+
upstreamModelId: "deepseek-v4.1-flash",
|
|
4917
|
+
family: "deepseek"
|
|
4918
|
+
},
|
|
4891
4919
|
{
|
|
4892
4920
|
id: "glm-5.1",
|
|
4893
4921
|
name: "GLM-5.1",
|
|
@@ -4905,10 +4933,10 @@ var opencode_go_models_default = [
|
|
|
4905
4933
|
"text"
|
|
4906
4934
|
],
|
|
4907
4935
|
compatibility: {
|
|
4936
|
+
supportsReasoningEffort: false,
|
|
4908
4937
|
supportsStore: false,
|
|
4909
4938
|
supportsDeveloperRole: false,
|
|
4910
|
-
maxTokensField: "max_tokens"
|
|
4911
|
-
supportsReasoningEffort: false
|
|
4939
|
+
maxTokensField: "max_tokens"
|
|
4912
4940
|
},
|
|
4913
4941
|
upstreamModelId: "glm-5.1",
|
|
4914
4942
|
family: "glm"
|
|
@@ -4948,13 +4976,13 @@ var opencode_go_models_default = [
|
|
|
4948
4976
|
},
|
|
4949
4977
|
{
|
|
4950
4978
|
id: "gpt-5.6-luna",
|
|
4951
|
-
name: "GPT-5.6 Luna
|
|
4979
|
+
name: "GPT-5.6 Luna",
|
|
4952
4980
|
contextWindow: 105e4,
|
|
4953
4981
|
cost: {
|
|
4954
|
-
input: 0.
|
|
4955
|
-
output:
|
|
4956
|
-
cache_read: 0.
|
|
4957
|
-
cache_write: 0.
|
|
4982
|
+
input: 0.2,
|
|
4983
|
+
output: 1.2,
|
|
4984
|
+
cache_read: 0.02,
|
|
4985
|
+
cache_write: 0.25
|
|
4958
4986
|
},
|
|
4959
4987
|
modelFormat: "openai",
|
|
4960
4988
|
npm: "@ai-sdk/openai-compatible",
|
|
@@ -4964,8 +4992,6 @@ var opencode_go_models_default = [
|
|
|
4964
4992
|
"text",
|
|
4965
4993
|
"image"
|
|
4966
4994
|
],
|
|
4967
|
-
upstreamModelId: "gpt-5.6-luna",
|
|
4968
|
-
family: "gpt",
|
|
4969
4995
|
compatibility: {
|
|
4970
4996
|
reasoningEffortMap: {
|
|
4971
4997
|
off: "none",
|
|
@@ -4979,7 +5005,9 @@ var opencode_go_models_default = [
|
|
|
4979
5005
|
supportsStore: false,
|
|
4980
5006
|
supportsDeveloperRole: false,
|
|
4981
5007
|
maxTokensField: "max_tokens"
|
|
4982
|
-
}
|
|
5008
|
+
},
|
|
5009
|
+
upstreamModelId: "gpt-5.6-luna",
|
|
5010
|
+
family: "gpt"
|
|
4983
5011
|
},
|
|
4984
5012
|
{
|
|
4985
5013
|
id: "hy3",
|
|
@@ -5065,10 +5093,10 @@ var opencode_go_models_default = [
|
|
|
5065
5093
|
"image"
|
|
5066
5094
|
],
|
|
5067
5095
|
compatibility: {
|
|
5096
|
+
supportsReasoningEffort: false,
|
|
5068
5097
|
supportsStore: false,
|
|
5069
5098
|
supportsDeveloperRole: false,
|
|
5070
|
-
maxTokensField: "max_tokens"
|
|
5071
|
-
supportsReasoningEffort: false
|
|
5099
|
+
maxTokensField: "max_tokens"
|
|
5072
5100
|
},
|
|
5073
5101
|
upstreamModelId: "kimi-k2.7-code",
|
|
5074
5102
|
family: "kimi"
|
|
@@ -5125,10 +5153,10 @@ var opencode_go_models_default = [
|
|
|
5125
5153
|
"image"
|
|
5126
5154
|
],
|
|
5127
5155
|
compatibility: {
|
|
5156
|
+
supportsReasoningEffort: false,
|
|
5128
5157
|
supportsStore: false,
|
|
5129
5158
|
supportsDeveloperRole: false,
|
|
5130
|
-
maxTokensField: "max_tokens"
|
|
5131
|
-
supportsReasoningEffort: false
|
|
5159
|
+
maxTokensField: "max_tokens"
|
|
5132
5160
|
},
|
|
5133
5161
|
upstreamModelId: "mimo-v2.5",
|
|
5134
5162
|
family: "mimo"
|
|
@@ -5150,10 +5178,10 @@ var opencode_go_models_default = [
|
|
|
5150
5178
|
"text"
|
|
5151
5179
|
],
|
|
5152
5180
|
compatibility: {
|
|
5181
|
+
supportsReasoningEffort: false,
|
|
5153
5182
|
supportsStore: false,
|
|
5154
5183
|
supportsDeveloperRole: false,
|
|
5155
|
-
maxTokensField: "max_tokens"
|
|
5156
|
-
supportsReasoningEffort: false
|
|
5184
|
+
maxTokensField: "max_tokens"
|
|
5157
5185
|
},
|
|
5158
5186
|
upstreamModelId: "mimo-v2.5-pro",
|
|
5159
5187
|
family: "mimo"
|
|
@@ -5175,10 +5203,10 @@ var opencode_go_models_default = [
|
|
|
5175
5203
|
"text"
|
|
5176
5204
|
],
|
|
5177
5205
|
compatibility: {
|
|
5206
|
+
supportsReasoningEffort: false,
|
|
5178
5207
|
supportsStore: false,
|
|
5179
5208
|
supportsDeveloperRole: false,
|
|
5180
|
-
maxTokensField: "max_tokens"
|
|
5181
|
-
supportsReasoningEffort: false
|
|
5209
|
+
maxTokensField: "max_tokens"
|
|
5182
5210
|
},
|
|
5183
5211
|
upstreamModelId: "minimax-m2.7",
|
|
5184
5212
|
family: "minimax"
|
|
@@ -5200,12 +5228,12 @@ var opencode_go_models_default = [
|
|
|
5200
5228
|
"text",
|
|
5201
5229
|
"image"
|
|
5202
5230
|
],
|
|
5203
|
-
upstreamModelId: "minimax-m3",
|
|
5204
|
-
family: "minimax",
|
|
5205
5231
|
compatibility: {
|
|
5206
5232
|
supportsCountTokens: false,
|
|
5207
5233
|
supportsReasoningEffort: false
|
|
5208
|
-
}
|
|
5234
|
+
},
|
|
5235
|
+
upstreamModelId: "minimax-m3",
|
|
5236
|
+
family: "minimax"
|
|
5209
5237
|
},
|
|
5210
5238
|
{
|
|
5211
5239
|
id: "qwen3.6-plus",
|
|
@@ -5226,10 +5254,6 @@ var opencode_go_models_default = [
|
|
|
5226
5254
|
"image"
|
|
5227
5255
|
],
|
|
5228
5256
|
compatibility: {
|
|
5229
|
-
supportsStore: false,
|
|
5230
|
-
supportsDeveloperRole: false,
|
|
5231
|
-
thinkingFormat: "qwen",
|
|
5232
|
-
maxTokensField: "max_tokens",
|
|
5233
5257
|
reasoningEffortMap: {
|
|
5234
5258
|
low: "low",
|
|
5235
5259
|
medium: "medium",
|
|
@@ -5238,7 +5262,11 @@ var opencode_go_models_default = [
|
|
|
5238
5262
|
max: "max",
|
|
5239
5263
|
minimal: null,
|
|
5240
5264
|
off: null
|
|
5241
|
-
}
|
|
5265
|
+
},
|
|
5266
|
+
supportsStore: false,
|
|
5267
|
+
supportsDeveloperRole: false,
|
|
5268
|
+
thinkingFormat: "qwen",
|
|
5269
|
+
maxTokensField: "max_tokens"
|
|
5242
5270
|
},
|
|
5243
5271
|
upstreamModelId: "qwen3.6-plus",
|
|
5244
5272
|
family: "qwen3.6"
|
|
@@ -5260,12 +5288,12 @@ var opencode_go_models_default = [
|
|
|
5260
5288
|
modalities: [
|
|
5261
5289
|
"text"
|
|
5262
5290
|
],
|
|
5263
|
-
upstreamModelId: "qwen3.7-max",
|
|
5264
|
-
family: "qwen3.7",
|
|
5265
5291
|
compatibility: {
|
|
5266
5292
|
supportsCountTokens: false,
|
|
5267
5293
|
supportsReasoningEffort: false
|
|
5268
|
-
}
|
|
5294
|
+
},
|
|
5295
|
+
upstreamModelId: "qwen3.7-max",
|
|
5296
|
+
family: "qwen3.7"
|
|
5269
5297
|
},
|
|
5270
5298
|
{
|
|
5271
5299
|
id: "qwen3.7-plus",
|
|
@@ -5285,12 +5313,12 @@ var opencode_go_models_default = [
|
|
|
5285
5313
|
"text",
|
|
5286
5314
|
"image"
|
|
5287
5315
|
],
|
|
5288
|
-
upstreamModelId: "qwen3.7-plus",
|
|
5289
|
-
family: "qwen3.7",
|
|
5290
5316
|
compatibility: {
|
|
5291
5317
|
supportsCountTokens: false,
|
|
5292
5318
|
supportsReasoningEffort: false
|
|
5293
|
-
}
|
|
5319
|
+
},
|
|
5320
|
+
upstreamModelId: "qwen3.7-plus",
|
|
5321
|
+
family: "qwen3.7"
|
|
5294
5322
|
},
|
|
5295
5323
|
{
|
|
5296
5324
|
id: "qwen3.8-max",
|
|
@@ -5310,12 +5338,12 @@ var opencode_go_models_default = [
|
|
|
5310
5338
|
"text",
|
|
5311
5339
|
"image"
|
|
5312
5340
|
],
|
|
5313
|
-
upstreamModelId: "qwen3.8-max",
|
|
5314
|
-
family: "qwen3.8",
|
|
5315
5341
|
compatibility: {
|
|
5316
5342
|
supportsCountTokens: false,
|
|
5317
5343
|
supportsReasoningEffort: false
|
|
5318
|
-
}
|
|
5344
|
+
},
|
|
5345
|
+
upstreamModelId: "qwen3.8-max",
|
|
5346
|
+
family: "qwen3.8"
|
|
5319
5347
|
}
|
|
5320
5348
|
];
|
|
5321
5349
|
|
|
@@ -5327,6 +5355,13 @@ var OPENCODE_GO_ANTHROPIC_BASE_URL = "https://opencode.ai/zen/go";
|
|
|
5327
5355
|
function buildOpenCodeGoModels() {
|
|
5328
5356
|
return structuredClone(opencode_go_models_default);
|
|
5329
5357
|
}
|
|
5358
|
+
var OPENCODE_GO_FALLBACK_SESSION_ID = randomUUID2();
|
|
5359
|
+
function openCodeGoSessionHeaders(model, claudeSessionId) {
|
|
5360
|
+
const url = String(model.apiBaseUrl ?? model.baseUrl ?? model.apiUrl ?? "");
|
|
5361
|
+
const isGo = model.providerId === OPENCODE_GO_PROVIDER_ID || /^https:\/\/opencode\.ai\/zen\/go(\/|$)/.test(url);
|
|
5362
|
+
if (!isGo) return void 0;
|
|
5363
|
+
return { "x-opencode-session": claudeSessionId ?? OPENCODE_GO_FALLBACK_SESSION_ID };
|
|
5364
|
+
}
|
|
5330
5365
|
|
|
5331
5366
|
// src/provider-templates.ts
|
|
5332
5367
|
async function verifyOpenCodeGoCredential(apiKey) {
|
|
@@ -5337,7 +5372,12 @@ async function verifyOpenCodeGoCredential(apiKey) {
|
|
|
5337
5372
|
method: "POST",
|
|
5338
5373
|
headers: {
|
|
5339
5374
|
"Content-Type": "application/json",
|
|
5340
|
-
Authorization: `Bearer ${apiKey}
|
|
5375
|
+
Authorization: `Bearer ${apiKey}`,
|
|
5376
|
+
// Go answers `MissingSessionID` to any request without a session header,
|
|
5377
|
+
// and whether it validates the key BEFORE that check is not something we
|
|
5378
|
+
// have observed. Sending the header removes the question: the probe then
|
|
5379
|
+
// cannot mistake a missing-session rejection for a verdict on the key.
|
|
5380
|
+
...openCodeGoSessionHeaders({ providerId: OPENCODE_GO_PROVIDER_ID }, void 0)
|
|
5341
5381
|
},
|
|
5342
5382
|
body: JSON.stringify({ model: model.upstreamModelId ?? model.id }),
|
|
5343
5383
|
// This is the FIRST thing a user hits after pasting a key, and it runs
|
|
@@ -7772,7 +7812,7 @@ function writeAll(fd, bytes, position, path) {
|
|
|
7772
7812
|
|
|
7773
7813
|
// src/patch-backup.ts
|
|
7774
7814
|
import { createHash as createHash5 } from "crypto";
|
|
7775
|
-
import { existsSync as existsSync4, readFileSync as readFileSync9, readdirSync, statSync as statSync7 } from "fs";
|
|
7815
|
+
import { existsSync as existsSync4, readFileSync as readFileSync9, readdirSync, renameSync as renameSync2, rmSync, statSync as statSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
7776
7816
|
import { homedir as homedir2 } from "os";
|
|
7777
7817
|
import { join as join7 } from "path";
|
|
7778
7818
|
var BACKUP_SHA_PREFIX_LENGTH = 16;
|
|
@@ -7790,9 +7830,60 @@ function backupVersionTag(version) {
|
|
|
7790
7830
|
function contentAddressedBackupPath(version, sha256, dir = backupDir()) {
|
|
7791
7831
|
return join7(dir, `claude-${backupVersionTag(version)}-${sha256.slice(0, BACKUP_SHA_PREFIX_LENGTH)}.orig`);
|
|
7792
7832
|
}
|
|
7833
|
+
function legacyBackupPath(version, dir = backupDir()) {
|
|
7834
|
+
return join7(dir, `claude-${backupVersionTag(version)}.orig`);
|
|
7835
|
+
}
|
|
7793
7836
|
function tweakccMirrorBackupPath(dir = backupDir()) {
|
|
7794
7837
|
return join7(dir, "native-binary.backup");
|
|
7795
7838
|
}
|
|
7839
|
+
function installProvenancePath(backupPath, binaryPath) {
|
|
7840
|
+
const tag = createHash5("sha256").update(binaryPath).digest("hex").slice(0, BACKUP_SHA_PREFIX_LENGTH);
|
|
7841
|
+
return `${backupPath}.for-${tag}.json`;
|
|
7842
|
+
}
|
|
7843
|
+
function installProvenancePattern(name) {
|
|
7844
|
+
return new RegExp(`^${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\.for-[0-9a-f]{${BACKUP_SHA_PREFIX_LENGTH}}\\.json$`);
|
|
7845
|
+
}
|
|
7846
|
+
function readInstallProvenance(path) {
|
|
7847
|
+
let raw;
|
|
7848
|
+
try {
|
|
7849
|
+
raw = readFileSync9(path, "utf8");
|
|
7850
|
+
} catch {
|
|
7851
|
+
return null;
|
|
7852
|
+
}
|
|
7853
|
+
let parsed;
|
|
7854
|
+
try {
|
|
7855
|
+
parsed = JSON.parse(raw);
|
|
7856
|
+
} catch {
|
|
7857
|
+
return "damaged";
|
|
7858
|
+
}
|
|
7859
|
+
if (typeof parsed !== "object" || parsed === null) return "damaged";
|
|
7860
|
+
const { install, assumed } = parsed;
|
|
7861
|
+
if (typeof install !== "string" || install === "") return "damaged";
|
|
7862
|
+
if (typeof assumed !== "boolean") return "damaged";
|
|
7863
|
+
return { install, assumed };
|
|
7864
|
+
}
|
|
7865
|
+
function recordBackupProvenance(backupPath, binaryPath, opts) {
|
|
7866
|
+
const target = installProvenancePath(backupPath, binaryPath);
|
|
7867
|
+
const existing = readInstallProvenance(target);
|
|
7868
|
+
if (existing && existing !== "damaged" && existing.install === binaryPath) {
|
|
7869
|
+
if (existing.assumed === opts.assumed) return existing.assumed ? "assumed" : "established";
|
|
7870
|
+
if (!existing.assumed) return "established";
|
|
7871
|
+
}
|
|
7872
|
+
const record = { install: binaryPath, assumed: opts.assumed };
|
|
7873
|
+
const temp = `${target}.tmp-${process.pid}-${Date.now().toString(36)}`;
|
|
7874
|
+
try {
|
|
7875
|
+
writeFileSync5(temp, `${JSON.stringify(record, null, 2)}
|
|
7876
|
+
`);
|
|
7877
|
+
renameSync2(temp, target);
|
|
7878
|
+
return opts.assumed ? "assumed" : "established";
|
|
7879
|
+
} catch (err) {
|
|
7880
|
+
try {
|
|
7881
|
+
rmSync(temp, { force: true });
|
|
7882
|
+
} catch {
|
|
7883
|
+
}
|
|
7884
|
+
throw err;
|
|
7885
|
+
}
|
|
7886
|
+
}
|
|
7796
7887
|
function scanPristineBackups(version, dir = backupDir()) {
|
|
7797
7888
|
const tag = backupVersionTag(version);
|
|
7798
7889
|
const pattern = new RegExp(`^claude-${tag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:-([0-9a-f]{${BACKUP_SHA_PREFIX_LENGTH}}))?\\.orig$`);
|
|
@@ -7802,6 +7893,27 @@ function scanPristineBackups(version, dir = backupDir()) {
|
|
|
7802
7893
|
} catch {
|
|
7803
7894
|
return { valid: [], corrupt: [] };
|
|
7804
7895
|
}
|
|
7896
|
+
const provenanceOf = (name) => {
|
|
7897
|
+
const recordPattern = installProvenancePattern(name);
|
|
7898
|
+
const installs = [];
|
|
7899
|
+
const assumedInstalls = [];
|
|
7900
|
+
const damagedProvenance = [];
|
|
7901
|
+
for (const entry of entries) {
|
|
7902
|
+
if (!recordPattern.test(entry)) continue;
|
|
7903
|
+
const path = join7(dir, entry);
|
|
7904
|
+
const record = readInstallProvenance(path);
|
|
7905
|
+
if (record === null || record === "damaged" || installProvenancePath(join7(dir, name), record.install) !== path) {
|
|
7906
|
+
damagedProvenance.push(path);
|
|
7907
|
+
continue;
|
|
7908
|
+
}
|
|
7909
|
+
(record.assumed ? assumedInstalls : installs).push(record.install);
|
|
7910
|
+
}
|
|
7911
|
+
return {
|
|
7912
|
+
installs: installs.sort(),
|
|
7913
|
+
assumedInstalls: assumedInstalls.sort(),
|
|
7914
|
+
damagedProvenance: damagedProvenance.sort()
|
|
7915
|
+
};
|
|
7916
|
+
};
|
|
7805
7917
|
const valid = [];
|
|
7806
7918
|
const corrupt = [];
|
|
7807
7919
|
for (const entry of entries.sort()) {
|
|
@@ -7822,9 +7934,9 @@ function scanPristineBackups(version, dir = backupDir()) {
|
|
|
7822
7934
|
corrupt.push(path);
|
|
7823
7935
|
continue;
|
|
7824
7936
|
}
|
|
7825
|
-
valid.push({ path, kind: "content-addressed", sha256 });
|
|
7937
|
+
valid.push({ path, kind: "content-addressed", sha256, ...provenanceOf(entry) });
|
|
7826
7938
|
} else {
|
|
7827
|
-
valid.push({ path, kind: "legacy", sha256 });
|
|
7939
|
+
valid.push({ path, kind: "legacy", sha256, ...provenanceOf(entry) });
|
|
7828
7940
|
}
|
|
7829
7941
|
}
|
|
7830
7942
|
return { valid, corrupt };
|
|
@@ -7846,7 +7958,7 @@ function looksLikeLegacyClodexPatch(source) {
|
|
|
7846
7958
|
}
|
|
7847
7959
|
function noBackupMessage(facts) {
|
|
7848
7960
|
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}
|
|
7961
|
+
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
7962
|
}
|
|
7851
7963
|
function identifiesABackup(manifest) {
|
|
7852
7964
|
return manifest.pristineSha256 !== void 0 || manifest.backupPath !== void 0;
|
|
@@ -7860,8 +7972,26 @@ function recordedBackupGoneMessage(facts, manifest) {
|
|
|
7860
7972
|
function otherInstallMessage(facts, otherBinaryPath) {
|
|
7861
7973
|
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
7974
|
}
|
|
7975
|
+
function otherInstallProvenanceMessage(facts, recorded) {
|
|
7976
|
+
const owners = [...new Set(recorded.flatMap((backup) => backup.installs))];
|
|
7977
|
+
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.`;
|
|
7978
|
+
}
|
|
7979
|
+
function damagedProvenanceMessage(facts, damaged) {
|
|
7980
|
+
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.`;
|
|
7981
|
+
}
|
|
7982
|
+
function contradictoryProvenanceMessage(facts, mine) {
|
|
7983
|
+
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.`;
|
|
7984
|
+
}
|
|
7985
|
+
function manifestContradictsRecordMessage(facts, manifestChoice, recorded) {
|
|
7986
|
+
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.`;
|
|
7987
|
+
}
|
|
7988
|
+
function assumedElsewhereMessage(facts, backups) {
|
|
7989
|
+
const others = [...new Set(backups.flatMap((backup) => backup.assumedInstalls))];
|
|
7990
|
+
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.`;
|
|
7991
|
+
}
|
|
7863
7992
|
function selectRestoreSource(facts) {
|
|
7864
7993
|
const notes = [];
|
|
7994
|
+
let assumedForThisInstall = false;
|
|
7865
7995
|
const recorded = facts.manifest;
|
|
7866
7996
|
const speaksForThisVersion = !recorded?.claudeVersion || recorded.claudeVersion === facts.version;
|
|
7867
7997
|
const manifest = recorded && recorded.binaryPath === facts.binaryPath && speaksForThisVersion ? recorded : null;
|
|
@@ -7873,10 +8003,46 @@ function selectRestoreSource(facts) {
|
|
|
7873
8003
|
if (!chosen && manifest && identifiesABackup(manifest)) {
|
|
7874
8004
|
return { action: "error", message: recordedBackupGoneMessage(facts, manifest) };
|
|
7875
8005
|
}
|
|
8006
|
+
const manifestDescribesLiveBytes = !!manifest?.patchedSha256 && manifest.patchedSha256 === facts.liveSha256;
|
|
8007
|
+
if (chosen && !manifestDescribesLiveBytes) {
|
|
8008
|
+
const manifestChoice = chosen;
|
|
8009
|
+
const contradicting = facts.backups.filter(
|
|
8010
|
+
(backup) => backup.installs.includes(facts.binaryPath) && backup.sha256 !== manifestChoice.sha256
|
|
8011
|
+
);
|
|
8012
|
+
if (contradicting.length) {
|
|
8013
|
+
return {
|
|
8014
|
+
action: "error",
|
|
8015
|
+
message: manifestContradictsRecordMessage(facts, manifestChoice.path, contradicting)
|
|
8016
|
+
};
|
|
8017
|
+
}
|
|
8018
|
+
}
|
|
8019
|
+
if (!chosen) {
|
|
8020
|
+
const mine = facts.backups.filter((backup) => backup.installs.includes(facts.binaryPath));
|
|
8021
|
+
if (mine.length) {
|
|
8022
|
+
if (new Set(mine.map((backup) => backup.sha256)).size > 1) {
|
|
8023
|
+
return { action: "error", message: contradictoryProvenanceMessage(facts, mine) };
|
|
8024
|
+
}
|
|
8025
|
+
chosen = mine.find((backup) => backup.kind === "content-addressed") ?? mine[0];
|
|
8026
|
+
}
|
|
8027
|
+
}
|
|
7876
8028
|
if (!chosen) {
|
|
7877
8029
|
if (other) {
|
|
7878
8030
|
return facts.backups.length ? { action: "error", message: otherInstallMessage(facts, other.binaryPath) } : { action: "error", message: noBackupMessage(facts) };
|
|
7879
8031
|
}
|
|
8032
|
+
const recordedElsewhere = facts.backups.filter((backup) => backup.installs.length > 0);
|
|
8033
|
+
if (recordedElsewhere.length) {
|
|
8034
|
+
return { action: "error", message: otherInstallProvenanceMessage(facts, recordedElsewhere) };
|
|
8035
|
+
}
|
|
8036
|
+
const damaged = facts.backups.flatMap((backup) => backup.damagedProvenance);
|
|
8037
|
+
if (damaged.length) {
|
|
8038
|
+
return { action: "error", message: damagedProvenanceMessage(facts, damaged) };
|
|
8039
|
+
}
|
|
8040
|
+
const assumedElsewhere = facts.backups.filter(
|
|
8041
|
+
(backup) => backup.assumedInstalls.some((install) => install !== facts.binaryPath)
|
|
8042
|
+
);
|
|
8043
|
+
if (assumedElsewhere.length) {
|
|
8044
|
+
return { action: "error", message: assumedElsewhereMessage(facts, assumedElsewhere) };
|
|
8045
|
+
}
|
|
7880
8046
|
const distinct = [...new Set(facts.backups.map((backup) => backup.sha256))];
|
|
7881
8047
|
if (distinct.length > 1) {
|
|
7882
8048
|
return {
|
|
@@ -7886,12 +8052,14 @@ function selectRestoreSource(facts) {
|
|
|
7886
8052
|
}
|
|
7887
8053
|
chosen = facts.backups.find((backup) => backup.kind === "content-addressed") ?? facts.backups[0];
|
|
7888
8054
|
if (chosen) {
|
|
8055
|
+
assumedForThisInstall = true;
|
|
7889
8056
|
notes.push(
|
|
7890
|
-
`
|
|
8057
|
+
`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
8058
|
);
|
|
7892
8059
|
}
|
|
7893
8060
|
}
|
|
7894
8061
|
if (!chosen) return { action: "error", message: noBackupMessage(facts) };
|
|
8062
|
+
if (manifest?.pristineProvenance === "assumed") assumedForThisInstall = true;
|
|
7895
8063
|
return {
|
|
7896
8064
|
action: "restore",
|
|
7897
8065
|
backupPath: chosen.path,
|
|
@@ -7900,6 +8068,7 @@ function selectRestoreSource(facts) {
|
|
|
7900
8068
|
// another version's binary, stored under a mislabeled name by an older
|
|
7901
8069
|
// clodex. Executing it is the only evidence available; require it.
|
|
7902
8070
|
probeVersion: chosen.kind === "legacy",
|
|
8071
|
+
assumedForThisInstall,
|
|
7903
8072
|
notes
|
|
7904
8073
|
};
|
|
7905
8074
|
}
|
|
@@ -8868,16 +9037,64 @@ function responsesWebSocketPartitionKey(wsUrl, payload, options = {}, authorizat
|
|
|
8868
9037
|
function inputArray(payload) {
|
|
8869
9038
|
return Array.isArray(payload.input) ? payload.input : [];
|
|
8870
9039
|
}
|
|
8871
|
-
function
|
|
8872
|
-
|
|
9040
|
+
function toolSchemaDefaults(payload) {
|
|
9041
|
+
const defaults = /* @__PURE__ */ new Map();
|
|
9042
|
+
const add = (tool3) => {
|
|
9043
|
+
if (!tool3 || typeof tool3 !== "object") return;
|
|
9044
|
+
const record = tool3;
|
|
9045
|
+
if (record.type === "namespace" && Array.isArray(record.tools)) {
|
|
9046
|
+
for (const nested of record.tools) add(nested);
|
|
9047
|
+
return;
|
|
9048
|
+
}
|
|
9049
|
+
if (record.type !== "function" || typeof record.name !== "string") return;
|
|
9050
|
+
const parameters = record.parameters;
|
|
9051
|
+
const properties = parameters && typeof parameters === "object" ? parameters.properties : void 0;
|
|
9052
|
+
if (!properties || typeof properties !== "object") return;
|
|
9053
|
+
const perTool = /* @__PURE__ */ new Map();
|
|
9054
|
+
for (const [prop, schema] of Object.entries(properties)) {
|
|
9055
|
+
if (schema && typeof schema === "object" && "default" in schema) {
|
|
9056
|
+
perTool.set(prop, canonicalJson(schema.default));
|
|
9057
|
+
}
|
|
9058
|
+
}
|
|
9059
|
+
if (perTool.size) defaults.set(record.name, perTool);
|
|
9060
|
+
};
|
|
9061
|
+
if (Array.isArray(payload.tools)) for (const tool3 of payload.tools) add(tool3);
|
|
9062
|
+
return defaults;
|
|
9063
|
+
}
|
|
9064
|
+
function toolSchemaDefaultsFingerprint(defaults) {
|
|
9065
|
+
if (!defaults.size) return "none";
|
|
9066
|
+
const tuples = [...defaults.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([name, perTool]) => [
|
|
9067
|
+
name,
|
|
9068
|
+
[...perTool.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)
|
|
9069
|
+
]);
|
|
9070
|
+
return createHash6("sha256").update(JSON.stringify(tuples)).digest("hex").slice(0, 16);
|
|
9071
|
+
}
|
|
9072
|
+
function stripSchemaDefaults(name, args, defaults) {
|
|
9073
|
+
if (!defaults) return args;
|
|
9074
|
+
if (typeof name !== "string" || !args || typeof args !== "object" || Array.isArray(args)) return args;
|
|
9075
|
+
const perTool = defaults.get(name);
|
|
9076
|
+
if (!perTool) return args;
|
|
9077
|
+
const out = {};
|
|
9078
|
+
for (const [key, value] of Object.entries(args)) {
|
|
9079
|
+
const expected = perTool.get(key);
|
|
9080
|
+
if (expected !== void 0 && canonicalJson(value) === expected) continue;
|
|
9081
|
+
out[key] = value;
|
|
9082
|
+
}
|
|
9083
|
+
return out;
|
|
9084
|
+
}
|
|
9085
|
+
function normalizeToolCallJson(value, defaults) {
|
|
9086
|
+
if (Array.isArray(value)) return value.map((item) => normalizeToolCallJson(item, defaults));
|
|
8873
9087
|
if (!value || typeof value !== "object") return value;
|
|
8874
9088
|
const record = value;
|
|
8875
9089
|
const out = {};
|
|
8876
|
-
for (const [key, child] of Object.entries(record)) out[key] = normalizeToolCallJson(child);
|
|
9090
|
+
for (const [key, child] of Object.entries(record)) out[key] = normalizeToolCallJson(child, defaults);
|
|
8877
9091
|
const jsonField = record.type === "function_call" ? "arguments" : record.type === "custom_tool_call" ? "input" : void 0;
|
|
8878
9092
|
if (jsonField && typeof record[jsonField] === "string") {
|
|
8879
9093
|
try {
|
|
8880
|
-
|
|
9094
|
+
const parsed = JSON.parse(record[jsonField]);
|
|
9095
|
+
out[jsonField] = canonicalJson(
|
|
9096
|
+
jsonField === "arguments" ? stripSchemaDefaults(record.name, parsed, defaults) : parsed
|
|
9097
|
+
);
|
|
8881
9098
|
} catch {
|
|
8882
9099
|
}
|
|
8883
9100
|
}
|
|
@@ -8888,8 +9105,8 @@ function normalizeToolCallJson(value) {
|
|
|
8888
9105
|
}
|
|
8889
9106
|
return out;
|
|
8890
9107
|
}
|
|
8891
|
-
function arraysEqual(left, right) {
|
|
8892
|
-
return canonicalJson(normalizeToolCallJson(left)) === canonicalJson(normalizeToolCallJson(right));
|
|
9108
|
+
function arraysEqual(left, right, defaults) {
|
|
9109
|
+
return canonicalJson(normalizeToolCallJson(left, defaults)) === canonicalJson(normalizeToolCallJson(right, defaults));
|
|
8893
9110
|
}
|
|
8894
9111
|
function conversationItemKind(value) {
|
|
8895
9112
|
if (!value || typeof value !== "object") return typeof value;
|
|
@@ -8898,17 +9115,17 @@ function conversationItemKind(value) {
|
|
|
8898
9115
|
if (typeof record.role === "string") return record.role;
|
|
8899
9116
|
return "object";
|
|
8900
9117
|
}
|
|
8901
|
-
function conversationItemHash(value) {
|
|
8902
|
-
return createHash6("sha256").update(canonicalJson(normalizeToolCallJson(value))).digest("hex").slice(0, 16);
|
|
9118
|
+
function conversationItemHash(value, defaults) {
|
|
9119
|
+
return createHash6("sha256").update(canonicalJson(normalizeToolCallJson(value, defaults))).digest("hex").slice(0, 16);
|
|
8903
9120
|
}
|
|
8904
|
-
function reasoningNormalizationGap(expected, actual) {
|
|
9121
|
+
function reasoningNormalizationGap(expected, actual, defaults) {
|
|
8905
9122
|
if (conversationItemKind(expected) !== "reasoning" || conversationItemKind(actual) !== "reasoning") return void 0;
|
|
8906
9123
|
const left = expected;
|
|
8907
9124
|
const right = actual;
|
|
8908
9125
|
const blob = left.encrypted_content;
|
|
8909
9126
|
if (typeof blob !== "string" || !blob || blob !== right.encrypted_content) return void 0;
|
|
8910
|
-
const normalizedLeft = normalizeToolCallJson(left);
|
|
8911
|
-
const normalizedRight = normalizeToolCallJson(right);
|
|
9127
|
+
const normalizedLeft = normalizeToolCallJson(left, defaults);
|
|
9128
|
+
const normalizedRight = normalizeToolCallJson(right, defaults);
|
|
8912
9129
|
const fields = [.../* @__PURE__ */ new Set([...Object.keys(normalizedLeft), ...Object.keys(normalizedRight)])].sort().filter((key) => canonicalJson(normalizedLeft[key]) !== canonicalJson(normalizedRight[key]));
|
|
8913
9130
|
return fields.length ? fields : void 0;
|
|
8914
9131
|
}
|
|
@@ -8956,7 +9173,7 @@ function warnReasoningNormalizationGap(fields, log12) {
|
|
|
8956
9173
|
emitParentNotice("clodex: warning: further reasoning-normalization warnings suppressed.");
|
|
8957
9174
|
}
|
|
8958
9175
|
}
|
|
8959
|
-
function toolArgumentNormalizationGap(expected, actual, requiredProps) {
|
|
9176
|
+
function toolArgumentNormalizationGap(expected, actual, defaults, requiredProps) {
|
|
8960
9177
|
if (conversationItemKind(expected) !== "function_call") return void 0;
|
|
8961
9178
|
if (conversationItemKind(actual) !== "function_call") return void 0;
|
|
8962
9179
|
const left = expected;
|
|
@@ -8964,7 +9181,7 @@ function toolArgumentNormalizationGap(expected, actual, requiredProps) {
|
|
|
8964
9181
|
const callId = left.call_id;
|
|
8965
9182
|
if (typeof callId !== "string" || !callId || callId !== right.call_id) return void 0;
|
|
8966
9183
|
if (typeof left.name !== "string" || left.name !== right.name) return void 0;
|
|
8967
|
-
if (canonicalJson(normalizeToolCallJson(left)) === canonicalJson(normalizeToolCallJson(right))) {
|
|
9184
|
+
if (canonicalJson(normalizeToolCallJson(left, defaults)) === canonicalJson(normalizeToolCallJson(right, defaults))) {
|
|
8968
9185
|
return void 0;
|
|
8969
9186
|
}
|
|
8970
9187
|
const required = requiredProps().get(left.name);
|
|
@@ -8975,8 +9192,8 @@ function toolArgumentNormalizationGap(expected, actual, requiredProps) {
|
|
|
8975
9192
|
const parsed = raw === "" ? {} : JSON.parse(raw);
|
|
8976
9193
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
8977
9194
|
return canonicalJson({
|
|
8978
|
-
...normalizeToolCallJson(item),
|
|
8979
|
-
arguments: canonicalJson(sanitizeToolInput(parsed, required))
|
|
9195
|
+
...normalizeToolCallJson(item, defaults),
|
|
9196
|
+
arguments: canonicalJson(stripSchemaDefaults(item.name, sanitizeToolInput(parsed, required), defaults))
|
|
8980
9197
|
});
|
|
8981
9198
|
} catch {
|
|
8982
9199
|
return void 0;
|
|
@@ -9007,7 +9224,7 @@ function warnToolArgumentNormalizationGap(gap, log12) {
|
|
|
9007
9224
|
emitParentNotice("clodex: warning: further tool-argument normalization warnings suppressed.");
|
|
9008
9225
|
}
|
|
9009
9226
|
}
|
|
9010
|
-
function continuationMismatchDetails(entry, payload, log12, warnOnGap = false, deferWarnings) {
|
|
9227
|
+
function continuationMismatchDetails(entry, payload, defaults, log12, warnOnGap = false, deferWarnings) {
|
|
9011
9228
|
const raise = (warn) => {
|
|
9012
9229
|
if (deferWarnings) deferWarnings.push(warn);
|
|
9013
9230
|
else warn();
|
|
@@ -9017,14 +9234,14 @@ function continuationMismatchDetails(entry, payload, log12, warnOnGap = false, d
|
|
|
9017
9234
|
const comparable = Math.min(full.length, prefix.length);
|
|
9018
9235
|
let mismatch = comparable;
|
|
9019
9236
|
for (let index = 0; index < comparable; index += 1) {
|
|
9020
|
-
if (!arraysEqual([full[index]], [prefix[index]])) {
|
|
9237
|
+
if (!arraysEqual([full[index]], [prefix[index]], defaults)) {
|
|
9021
9238
|
mismatch = index;
|
|
9022
9239
|
break;
|
|
9023
9240
|
}
|
|
9024
9241
|
}
|
|
9025
9242
|
const expected = mismatch < prefix.length ? prefix[mismatch] : void 0;
|
|
9026
9243
|
const actual = mismatch < full.length ? full[mismatch] : void 0;
|
|
9027
|
-
const reasoningGap = reasoningNormalizationGap(expected, actual);
|
|
9244
|
+
const reasoningGap = reasoningNormalizationGap(expected, actual, defaults);
|
|
9028
9245
|
if (reasoningGap && warnOnGap) raise(() => warnReasoningNormalizationGap(reasoningGap, log12));
|
|
9029
9246
|
let gapExpected = expected;
|
|
9030
9247
|
if (conversationItemKind(expected) === "reasoning" && conversationItemKind(actual) === "function_call") {
|
|
@@ -9040,6 +9257,7 @@ function continuationMismatchDetails(entry, payload, log12, warnOnGap = false, d
|
|
|
9040
9257
|
toolArgumentGap = toolArgumentNormalizationGap(
|
|
9041
9258
|
gapExpected,
|
|
9042
9259
|
actual,
|
|
9260
|
+
defaults,
|
|
9043
9261
|
// The head's own schema when it has one; the current turn's tools are only a
|
|
9044
9262
|
// fallback for a head that predates the snapshot (see headRequiredToolProps).
|
|
9045
9263
|
() => entry.headRequiredToolProps ?? requiredToolProps(payload)
|
|
@@ -9061,8 +9279,8 @@ function continuationMismatchDetails(entry, payload, log12, warnOnGap = false, d
|
|
|
9061
9279
|
firstMismatch: mismatch,
|
|
9062
9280
|
expectedKind: expected === void 0 ? "none" : conversationItemKind(expected),
|
|
9063
9281
|
actualKind: actual === void 0 ? "none" : conversationItemKind(actual),
|
|
9064
|
-
...expected !== void 0 ? { expectedHash: conversationItemHash(expected) } : {},
|
|
9065
|
-
...actual !== void 0 ? { actualHash: conversationItemHash(actual) } : {},
|
|
9282
|
+
...expected !== void 0 ? { expectedHash: conversationItemHash(expected, defaults) } : {},
|
|
9283
|
+
...actual !== void 0 ? { actualHash: conversationItemHash(actual, defaults) } : {},
|
|
9066
9284
|
...reasoningGap ? {
|
|
9067
9285
|
reasoningNormalizationGap: reasoningGap,
|
|
9068
9286
|
reasoningGapShape: reasoningGapShape(
|
|
@@ -9076,8 +9294,8 @@ function continuationMismatchDetails(entry, payload, log12, warnOnGap = false, d
|
|
|
9076
9294
|
...toolArgumentGap ? { toolArgumentNormalizationGap: toolArgumentGap } : {}
|
|
9077
9295
|
};
|
|
9078
9296
|
}
|
|
9079
|
-
function continuationMismatchSummary(entry, payload, log12, mismatchDump = false, precomputedDetails) {
|
|
9080
|
-
const details = precomputedDetails ?? continuationMismatchDetails(entry, payload, log12, true);
|
|
9297
|
+
function continuationMismatchSummary(entry, payload, defaults, log12, mismatchDump = false, precomputedDetails) {
|
|
9298
|
+
const details = precomputedDetails ?? continuationMismatchDetails(entry, payload, defaults, log12, true);
|
|
9081
9299
|
let summary = `full_items=${details.fullItems} expected_prefix_items=${details.expectedPrefixItems} first_mismatch=${details.firstMismatch} expected=${details.expectedKind} actual=${details.actualKind}`;
|
|
9082
9300
|
if (details.expectedHash || details.actualHash) {
|
|
9083
9301
|
summary += ` expected_hash=${details.expectedHash ?? "none"} actual_hash=${details.actualHash ?? "none"}`;
|
|
@@ -9085,21 +9303,21 @@ function continuationMismatchSummary(entry, payload, log12, mismatchDump = false
|
|
|
9085
9303
|
const full = inputArray(payload);
|
|
9086
9304
|
const prefix = [...entry.requestInput ?? [], ...entry.expectedAssistant ?? []];
|
|
9087
9305
|
const index = details.firstMismatch;
|
|
9088
|
-
log12(`mismatch dump expected[${index}]: ${mismatchDumpLine(prefix, index)}`);
|
|
9089
|
-
log12(`mismatch dump actual[${index}]: ${mismatchDumpLine(full, index)}`);
|
|
9306
|
+
log12(`mismatch dump expected[${index}]: ${mismatchDumpLine(prefix, index, defaults)}`);
|
|
9307
|
+
log12(`mismatch dump actual[${index}]: ${mismatchDumpLine(full, index, defaults)}`);
|
|
9090
9308
|
}
|
|
9091
9309
|
}
|
|
9092
9310
|
return summary;
|
|
9093
9311
|
}
|
|
9094
|
-
function mismatchDumpLine(items, index) {
|
|
9312
|
+
function mismatchDumpLine(items, index, defaults) {
|
|
9095
9313
|
if (index >= items.length) return "(absent)";
|
|
9096
|
-
const line = canonicalJson(normalizeToolCallJson(items[index]));
|
|
9314
|
+
const line = canonicalJson(normalizeToolCallJson(items[index], defaults));
|
|
9097
9315
|
const max = 2e3;
|
|
9098
9316
|
const marker = " [truncated]";
|
|
9099
9317
|
return line.length <= max ? line : line.slice(0, max - marker.length) + marker;
|
|
9100
9318
|
}
|
|
9101
|
-
function canonicalItemStrings(items) {
|
|
9102
|
-
return items.map((item) => canonicalJson(normalizeToolCallJson([item])));
|
|
9319
|
+
function canonicalItemStrings(items, defaults) {
|
|
9320
|
+
return items.map((item) => canonicalJson(normalizeToolCallJson([item], defaults)));
|
|
9103
9321
|
}
|
|
9104
9322
|
function isPrefixOrEqual(head, client) {
|
|
9105
9323
|
if (client.length < head.length) return false;
|
|
@@ -9111,16 +9329,24 @@ function isPrefixOrEqual(head, client) {
|
|
|
9111
9329
|
function isStrictPrefix(head, client) {
|
|
9112
9330
|
return client.length > head.length && isPrefixOrEqual(head, client);
|
|
9113
9331
|
}
|
|
9114
|
-
function continuationMatch(entry, payload, clientItems) {
|
|
9332
|
+
function continuationMatch(entry, payload, clientItems, defaults, defaultsId) {
|
|
9115
9333
|
if (!entry.responseId || !entry.requestInput || !entry.expectedAssistant) return void 0;
|
|
9116
9334
|
const full = inputArray(payload);
|
|
9117
|
-
|
|
9335
|
+
if (entry.canonicalToolDefaultsId !== defaultsId) {
|
|
9336
|
+
entry.canonicalPrefix = void 0;
|
|
9337
|
+
entry.canonicalEchoablePrefix = void 0;
|
|
9338
|
+
entry.canonicalToolDefaultsId = defaultsId;
|
|
9339
|
+
}
|
|
9340
|
+
entry.canonicalPrefix ??= canonicalItemStrings(
|
|
9341
|
+
[...entry.requestInput, ...entry.expectedAssistant],
|
|
9342
|
+
defaults
|
|
9343
|
+
);
|
|
9118
9344
|
if (isStrictPrefix(entry.canonicalPrefix, clientItems)) {
|
|
9119
9345
|
return { delta: full.slice(entry.canonicalPrefix.length), mode: "exact" };
|
|
9120
9346
|
}
|
|
9121
9347
|
const echoedAssistant = entry.expectedAssistant.filter((item) => conversationItemKind(item) !== "reasoning");
|
|
9122
9348
|
if (echoedAssistant.length === entry.expectedAssistant.length) return void 0;
|
|
9123
|
-
entry.canonicalEchoablePrefix ??= canonicalItemStrings([...entry.requestInput, ...echoedAssistant]);
|
|
9349
|
+
entry.canonicalEchoablePrefix ??= canonicalItemStrings([...entry.requestInput, ...echoedAssistant], defaults);
|
|
9124
9350
|
if (!isStrictPrefix(entry.canonicalEchoablePrefix, clientItems)) return void 0;
|
|
9125
9351
|
return { delta: full.slice(entry.canonicalEchoablePrefix.length), mode: "omitted_reasoning" };
|
|
9126
9352
|
}
|
|
@@ -10029,13 +10255,15 @@ function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
|
|
|
10029
10255
|
authorizationFingerprint,
|
|
10030
10256
|
claudeAgentId
|
|
10031
10257
|
);
|
|
10258
|
+
const requestToolDefaults = toolSchemaDefaults(payload);
|
|
10259
|
+
const requestToolDefaultsId = toolSchemaDefaultsFingerprint(requestToolDefaults);
|
|
10032
10260
|
const promptFingerprint = responsesWebSocketPromptFingerprint(payload);
|
|
10033
10261
|
const promptFieldHashes = responsesWebSocketPromptFieldHashes(payload);
|
|
10034
10262
|
const instructionsSnapshot = instructionsFromPayload(payload);
|
|
10035
10263
|
let now = resolvedOptions.now();
|
|
10036
10264
|
const evictions = cleanupExpiredConnections(now);
|
|
10037
10265
|
let canonicalClientItems;
|
|
10038
|
-
const clientItems = () => canonicalClientItems ??= canonicalItemStrings(inputArray(payload));
|
|
10266
|
+
const clientItems = () => canonicalClientItems ??= canonicalItemStrings(inputArray(payload), requestToolDefaults);
|
|
10039
10267
|
const scanForHeads = () => {
|
|
10040
10268
|
const scanned = partitionKey ? connectionEntries(partitionKey) : [];
|
|
10041
10269
|
const idle = scanned.filter((entry) => !entry.inFlight);
|
|
@@ -10043,16 +10271,32 @@ function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
|
|
|
10043
10271
|
return {
|
|
10044
10272
|
candidates: scanned,
|
|
10045
10273
|
idleCandidates: idle,
|
|
10046
|
-
matches: idle.map((entry) => ({
|
|
10274
|
+
matches: idle.map((entry) => ({
|
|
10275
|
+
entry,
|
|
10276
|
+
match: continuationMatch(entry, payload, canonical, requestToolDefaults, requestToolDefaultsId)
|
|
10277
|
+
})).filter((candidate) => candidate.match !== void 0).sort((left, right) => left.match.delta.length - right.match.delta.length || (left.match.mode === right.match.mode ? 0 : left.match.mode === "exact" ? -1 : 1))
|
|
10047
10278
|
};
|
|
10048
10279
|
};
|
|
10049
10280
|
const couldPrecedeThisRequest = (entry) => {
|
|
10050
10281
|
if (entry.responseId && entry.requestInput && entry.expectedAssistant) {
|
|
10051
|
-
return continuationMatch(
|
|
10282
|
+
return continuationMatch(
|
|
10283
|
+
entry,
|
|
10284
|
+
payload,
|
|
10285
|
+
clientItems(),
|
|
10286
|
+
requestToolDefaults,
|
|
10287
|
+
requestToolDefaultsId
|
|
10288
|
+
) !== void 0;
|
|
10052
10289
|
}
|
|
10053
10290
|
const streaming = entry.current;
|
|
10054
10291
|
if (!streaming) return true;
|
|
10055
|
-
streaming.
|
|
10292
|
+
if (streaming.canonicalInputToolDefaultsId !== requestToolDefaultsId) {
|
|
10293
|
+
streaming.canonicalInput = void 0;
|
|
10294
|
+
streaming.canonicalInputToolDefaultsId = requestToolDefaultsId;
|
|
10295
|
+
}
|
|
10296
|
+
streaming.canonicalInput ??= canonicalItemStrings(
|
|
10297
|
+
inputArray(streaming.originalPayload),
|
|
10298
|
+
requestToolDefaults
|
|
10299
|
+
);
|
|
10056
10300
|
return isPrefixOrEqual(streaming.canonicalInput, clientItems());
|
|
10057
10301
|
};
|
|
10058
10302
|
const blockingHead = (entries) => entries.find((entry) => entry.inFlight && couldPrecedeThisRequest(entry));
|
|
@@ -10110,6 +10354,7 @@ function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
|
|
|
10110
10354
|
const diagnosticMismatch = continuationMismatchDetails(
|
|
10111
10355
|
diagnosticEntry,
|
|
10112
10356
|
payload,
|
|
10357
|
+
requestToolDefaults,
|
|
10113
10358
|
debug,
|
|
10114
10359
|
true,
|
|
10115
10360
|
deferredMismatchWarnings
|
|
@@ -10119,13 +10364,21 @@ function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
|
|
|
10119
10364
|
if (candidate === diagnosticEntry) continue;
|
|
10120
10365
|
candidateMismatchDetails.set(
|
|
10121
10366
|
candidate,
|
|
10122
|
-
continuationMismatchDetails(
|
|
10367
|
+
continuationMismatchDetails(
|
|
10368
|
+
candidate,
|
|
10369
|
+
payload,
|
|
10370
|
+
requestToolDefaults,
|
|
10371
|
+
debug,
|
|
10372
|
+
true,
|
|
10373
|
+
deferredMismatchWarnings
|
|
10374
|
+
)
|
|
10123
10375
|
);
|
|
10124
10376
|
}
|
|
10125
10377
|
debug(
|
|
10126
10378
|
`history mismatch starting an additional chain; retained ${candidates.length} existing head(s) (${continuationMismatchSummary(
|
|
10127
10379
|
diagnosticEntry,
|
|
10128
10380
|
payload,
|
|
10381
|
+
requestToolDefaults,
|
|
10129
10382
|
debug,
|
|
10130
10383
|
mismatchDump,
|
|
10131
10384
|
diagnosticMismatch
|
|
@@ -10249,7 +10502,7 @@ function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
|
|
|
10249
10502
|
input: {
|
|
10250
10503
|
count: requestInput.length,
|
|
10251
10504
|
kinds: requestInput.map(conversationItemKind),
|
|
10252
|
-
hashes: requestInput.map(conversationItemHash)
|
|
10505
|
+
hashes: requestInput.map((item) => conversationItemHash(item, requestToolDefaults))
|
|
10253
10506
|
},
|
|
10254
10507
|
candidateCount: candidates.length,
|
|
10255
10508
|
idleCandidateCount: idleCandidates.length,
|
|
@@ -10282,7 +10535,7 @@ function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
|
|
|
10282
10535
|
ttlPausedMs: entry.ttlPausedMs,
|
|
10283
10536
|
idleMs: Math.max(0, now - entry.lastUsedAt),
|
|
10284
10537
|
promptChanges: changedPromptFields(entry.promptFieldHashes, promptFieldHashes),
|
|
10285
|
-
mismatch: candidateMismatchDetails?.get(entry) ?? continuationMismatchDetails(entry, payload, debug)
|
|
10538
|
+
mismatch: candidateMismatchDetails?.get(entry) ?? continuationMismatchDetails(entry, payload, requestToolDefaults, debug)
|
|
10286
10539
|
})),
|
|
10287
10540
|
evictions
|
|
10288
10541
|
}, diagnosticCorrelation);
|
|
@@ -10362,7 +10615,7 @@ function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
|
|
|
10362
10615
|
}
|
|
10363
10616
|
|
|
10364
10617
|
// src/oauth/claude-identity.ts
|
|
10365
|
-
import { createHash as createHash7, randomUUID as
|
|
10618
|
+
import { createHash as createHash7, randomUUID as randomUUID3 } from "crypto";
|
|
10366
10619
|
var CLAUDE_CODE_CLI_VERSION = "2.1.195";
|
|
10367
10620
|
var CLAUDE_CODE_USER_AGENT = `claude-cli/${CLAUDE_CODE_CLI_VERSION} (external, cli)`;
|
|
10368
10621
|
var CLAUDE_CODE_ENTRYPOINT = process.env.CLAUDE_CODE_ENTRYPOINT ?? "cli";
|
|
@@ -10371,7 +10624,7 @@ var sessionCache = /* @__PURE__ */ new Map();
|
|
|
10371
10624
|
function getOrCreateSessionId(seed) {
|
|
10372
10625
|
let id = sessionCache.get(seed);
|
|
10373
10626
|
if (!id) {
|
|
10374
|
-
id =
|
|
10627
|
+
id = randomUUID3();
|
|
10375
10628
|
sessionCache.set(seed, id);
|
|
10376
10629
|
}
|
|
10377
10630
|
return id;
|
|
@@ -11719,7 +11972,7 @@ async function relayAnthropicMessages(res, messagesUrl, body, apiKey, clientWant
|
|
|
11719
11972
|
}
|
|
11720
11973
|
|
|
11721
11974
|
// src/proxy.ts
|
|
11722
|
-
import { randomUUID as
|
|
11975
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
11723
11976
|
|
|
11724
11977
|
// src/sdk-adapter.ts
|
|
11725
11978
|
import { createHash as createHash8 } from "crypto";
|
|
@@ -13145,7 +13398,7 @@ function configuredAliasLookupNames(alias) {
|
|
|
13145
13398
|
}))].map(normalizeRouteLookupId);
|
|
13146
13399
|
}
|
|
13147
13400
|
async function startProxyCatalog(routes, defaultAliasId, debug = false, inferenceLogPath, debugLogPath, webSocketDiagnosticsLogPath, modelAliases) {
|
|
13148
|
-
const proxyToken =
|
|
13401
|
+
const proxyToken = randomUUID4();
|
|
13149
13402
|
silenceSdkWarnings();
|
|
13150
13403
|
if (routes.length === 0) {
|
|
13151
13404
|
throw new Error("Proxy catalog requires at least one route");
|
|
@@ -13309,6 +13562,14 @@ async function startProxyCatalog(routes, defaultAliasId, debug = false, inferenc
|
|
|
13309
13562
|
const isOAuth = routeAuthType === "oauth";
|
|
13310
13563
|
let effectiveBeta = inboundBeta;
|
|
13311
13564
|
let claudeCodeSessionId;
|
|
13565
|
+
const inboundSessionRaw = req.headers["x-claude-code-session-id"];
|
|
13566
|
+
const goSessionHeaders = openCodeGoSessionHeaders(
|
|
13567
|
+
{ providerId: route.providerId, baseUrl: upstreamUrl },
|
|
13568
|
+
extractClaudeSessionId(
|
|
13569
|
+
anthropicBody,
|
|
13570
|
+
Array.isArray(inboundSessionRaw) ? inboundSessionRaw[0] : inboundSessionRaw
|
|
13571
|
+
)
|
|
13572
|
+
);
|
|
13312
13573
|
if (isOAuth) {
|
|
13313
13574
|
const seed = route.providerId ?? route.realModelId;
|
|
13314
13575
|
const identity = injectClaudeIdentity(forwardBody, route.providerData, seed);
|
|
@@ -13326,7 +13587,7 @@ async function startProxyCatalog(routes, defaultAliasId, debug = false, inferenc
|
|
|
13326
13587
|
authType: routeAuthType,
|
|
13327
13588
|
log: (message) => plog(message),
|
|
13328
13589
|
claudeCodeSessionId,
|
|
13329
|
-
extraHeaders: route.headers,
|
|
13590
|
+
extraHeaders: { ...route.headers, ...goSessionHeaders },
|
|
13330
13591
|
refreshToken: route.refreshToken,
|
|
13331
13592
|
onTokenRefreshed: (refreshed) => {
|
|
13332
13593
|
route.apiKey = refreshed;
|
|
@@ -13386,6 +13647,11 @@ async function startProxyCatalog(routes, defaultAliasId, debug = false, inferenc
|
|
|
13386
13647
|
upstreamModelId: route.realModelId
|
|
13387
13648
|
}
|
|
13388
13649
|
});
|
|
13650
|
+
const goSdkSessionHeaders = openCodeGoSessionHeaders(
|
|
13651
|
+
{ providerId: route.providerId, baseUrl: route.baseURL },
|
|
13652
|
+
claudeSessionId
|
|
13653
|
+
);
|
|
13654
|
+
if (goSdkSessionHeaders) params.headers = { ...params.headers, ...goSdkSessionHeaders };
|
|
13389
13655
|
plog(
|
|
13390
13656
|
() => `sdk: npm=${route.npm} model=${route.realModelId}, stream=${clientWantsStream}, tools=${anthropicBody.tools?.length ?? 0}, msgs=${params.messages.length}`
|
|
13391
13657
|
);
|
|
@@ -13545,7 +13811,7 @@ async function startProxyCatalog(routes, defaultAliasId, debug = false, inferenc
|
|
|
13545
13811
|
res,
|
|
13546
13812
|
upstreamStatus === 500 ? 502 : upstreamStatus,
|
|
13547
13813
|
clientMessage,
|
|
13548
|
-
contextLengthExceeded ? relayRequestId ??
|
|
13814
|
+
contextLengthExceeded ? relayRequestId ?? randomUUID4() : void 0
|
|
13549
13815
|
);
|
|
13550
13816
|
} else {
|
|
13551
13817
|
const errorType = anthropicErrorType(upstreamStatus, details?.transportCode);
|
|
@@ -13553,7 +13819,7 @@ async function startProxyCatalog(routes, defaultAliasId, debug = false, inferenc
|
|
|
13553
13819
|
data: ${JSON.stringify({
|
|
13554
13820
|
type: "error",
|
|
13555
13821
|
error: { type: errorType, message: clientMessage },
|
|
13556
|
-
...contextLengthExceeded ? { request_id: relayRequestId ??
|
|
13822
|
+
...contextLengthExceeded ? { request_id: relayRequestId ?? randomUUID4() } : {}
|
|
13557
13823
|
})}
|
|
13558
13824
|
|
|
13559
13825
|
`);
|
|
@@ -13800,7 +14066,7 @@ function readPatchManifest(path = getPatchManifestPath()) {
|
|
|
13800
14066
|
}
|
|
13801
14067
|
function writePatchManifest(manifest, path = getPatchManifestPath()) {
|
|
13802
14068
|
mkdirSync5(getAppHome(), { recursive: true, mode: 448 });
|
|
13803
|
-
|
|
14069
|
+
writeFileSync6(path, `${JSON.stringify(manifest, null, 2)}
|
|
13804
14070
|
`, { encoding: "utf8", mode: 384 });
|
|
13805
14071
|
}
|
|
13806
14072
|
function buildPatchModelConfig(favorites, aliases, modelMetaFor) {
|
|
@@ -13958,7 +14224,7 @@ function tryAcquirePatchLock(lockPath = getPatchLockPath(), opts = {}) {
|
|
|
13958
14224
|
try {
|
|
13959
14225
|
const fd = openSync7(lockPath, "wx");
|
|
13960
14226
|
const content = { pid: process.pid, startedAt: now };
|
|
13961
|
-
|
|
14227
|
+
writeFileSync6(fd, JSON.stringify(content));
|
|
13962
14228
|
closeSync7(fd);
|
|
13963
14229
|
return () => {
|
|
13964
14230
|
try {
|
|
@@ -13983,10 +14249,19 @@ function tryAcquirePatchLock(lockPath = getPatchLockPath(), opts = {}) {
|
|
|
13983
14249
|
}
|
|
13984
14250
|
return null;
|
|
13985
14251
|
}
|
|
14252
|
+
var ignoredLaunchOverride = null;
|
|
14253
|
+
function takeIgnoredLaunchOverride() {
|
|
14254
|
+
const ignored = ignoredLaunchOverride;
|
|
14255
|
+
ignoredLaunchOverride = null;
|
|
14256
|
+
return ignored;
|
|
14257
|
+
}
|
|
13986
14258
|
function resolveClaudeBinaryForPatch() {
|
|
13987
|
-
const envOverride = process.env["TWEAKCC_CC_INSTALLATION_PATH"];
|
|
14259
|
+
const envOverride = process.env["TWEAKCC_CC_INSTALLATION_PATH"]?.trim() || null;
|
|
13988
14260
|
const nativeSymlink = join8(homedir3(), ".local", "bin", "claude");
|
|
13989
|
-
|
|
14261
|
+
if (envOverride && !existsSync5(envOverride)) {
|
|
14262
|
+
return { ok: false, reason: "patch-target-missing", declaredPath: envOverride };
|
|
14263
|
+
}
|
|
14264
|
+
const source = envOverride || (existsSync5(nativeSymlink) ? nativeSymlink : null) || findClaudeBinary();
|
|
13990
14265
|
if (!source) return { ok: false, reason: "binary-not-found" };
|
|
13991
14266
|
let resolved;
|
|
13992
14267
|
try {
|
|
@@ -14006,6 +14281,17 @@ function resolveClaudeBinaryForPatch() {
|
|
|
14006
14281
|
};
|
|
14007
14282
|
}
|
|
14008
14283
|
resolved = followed.path;
|
|
14284
|
+
const launchOverride = process.env["CLODEX_CLAUDE_PATH"]?.trim() || null;
|
|
14285
|
+
let launchOverrideResolved = null;
|
|
14286
|
+
if (launchOverride) {
|
|
14287
|
+
try {
|
|
14288
|
+
const followedOverride = resolveThroughNpmShims(realpathSync2(launchOverride));
|
|
14289
|
+
launchOverrideResolved = followedOverride.ok ? followedOverride.path : realpathSync2(launchOverride);
|
|
14290
|
+
} catch {
|
|
14291
|
+
launchOverrideResolved = launchOverride;
|
|
14292
|
+
}
|
|
14293
|
+
}
|
|
14294
|
+
ignoredLaunchOverride = launchOverrideResolved && launchOverrideResolved !== resolved ? { used: resolved, ignored: launchOverride } : null;
|
|
14009
14295
|
try {
|
|
14010
14296
|
if (!statSync8(resolved).isFile()) return { ok: false, reason: "binary-not-found" };
|
|
14011
14297
|
} catch {
|
|
@@ -14029,7 +14315,7 @@ function installScriptCommand(path) {
|
|
|
14029
14315
|
}
|
|
14030
14316
|
function describePatchTargetFailure(target, command = "patch") {
|
|
14031
14317
|
if (target.reason === "launcher-unresolved") {
|
|
14032
|
-
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
|
|
14318
|
+
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.`;
|
|
14033
14319
|
}
|
|
14034
14320
|
if (target.reason === "native-binary-missing") {
|
|
14035
14321
|
const installer = installScriptCommand(target.installScriptPath);
|
|
@@ -14038,6 +14324,9 @@ function describePatchTargetFailure(target, command = "patch") {
|
|
|
14038
14324
|
const restore = command === "restore" ? ` If you need to restore by hand, pristine backups are in ${backupDir()}.` : "";
|
|
14039
14325
|
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.`;
|
|
14040
14326
|
}
|
|
14327
|
+
if (target.reason === "patch-target-missing") {
|
|
14328
|
+
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.`;
|
|
14329
|
+
}
|
|
14041
14330
|
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.`;
|
|
14042
14331
|
}
|
|
14043
14332
|
function summarizePatchResults(results) {
|
|
@@ -14060,14 +14349,15 @@ function verifyPristineSource(plan, version) {
|
|
|
14060
14349
|
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\`.`
|
|
14061
14350
|
};
|
|
14062
14351
|
}
|
|
14063
|
-
function
|
|
14352
|
+
function publishFileByRename(from, to, mode) {
|
|
14064
14353
|
const temp = `${to}.tmp-${process.pid}-${Date.now().toString(36)}`;
|
|
14065
14354
|
try {
|
|
14066
14355
|
copyFileSync(from, temp);
|
|
14067
|
-
|
|
14356
|
+
if (mode !== void 0) chmodSync4(temp, mode);
|
|
14357
|
+
renameSync3(temp, to);
|
|
14068
14358
|
} catch (err) {
|
|
14069
14359
|
try {
|
|
14070
|
-
|
|
14360
|
+
rmSync2(temp, { force: true });
|
|
14071
14361
|
} catch {
|
|
14072
14362
|
}
|
|
14073
14363
|
throw err;
|
|
@@ -14131,6 +14421,7 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14131
14421
|
let patchedSha256;
|
|
14132
14422
|
let backup;
|
|
14133
14423
|
let pristineSha256;
|
|
14424
|
+
const pristine = { provenance: "established" };
|
|
14134
14425
|
try {
|
|
14135
14426
|
mkdirSync5(backupDir(), { recursive: true });
|
|
14136
14427
|
const { tryDetectInstallation, readContent, writeContent } = await import("tweakcc");
|
|
@@ -14179,6 +14470,18 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14179
14470
|
}
|
|
14180
14471
|
pristineSha256 = plan.pristineSha256;
|
|
14181
14472
|
backup = plan.backupPath;
|
|
14473
|
+
const inheritsAGuess = (path) => {
|
|
14474
|
+
const existing = readInstallProvenance(installProvenancePath(path, binaryPath));
|
|
14475
|
+
return existing === "damaged" || existing !== null && existing.assumed;
|
|
14476
|
+
};
|
|
14477
|
+
const provenanceAssumed = plan.action === "restore" && plan.assumedForThisInstall || inheritsAGuess(plan.backupPath) || inheritsAGuess(contentAddressedBackupPath(version, plan.pristineSha256)) || inheritsAGuess(legacyBackupPath(version)) || facts.backups.some(
|
|
14478
|
+
(candidate) => candidate.sha256 === plan.pristineSha256 && candidate.assumedInstalls.includes(binaryPath)
|
|
14479
|
+
);
|
|
14480
|
+
const recordProvenance = (path) => {
|
|
14481
|
+
if (recordBackupProvenance(path, binaryPath, { assumed: provenanceAssumed }) === "assumed") {
|
|
14482
|
+
pristine.provenance = "assumed";
|
|
14483
|
+
}
|
|
14484
|
+
};
|
|
14182
14485
|
if (!loaded) {
|
|
14183
14486
|
loaded = await seedCandidate(backup);
|
|
14184
14487
|
if (isPatchedClaudeSource(loaded.source)) {
|
|
@@ -14190,17 +14493,22 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14190
14493
|
`the patch candidate no longer matches the pristine bytes it was seeded from; refusing to publish it as ${plan.backupPath}`
|
|
14191
14494
|
);
|
|
14192
14495
|
}
|
|
14193
|
-
|
|
14496
|
+
recordProvenance(plan.backupPath);
|
|
14497
|
+
publishFileByRename(candidatePath, plan.backupPath);
|
|
14194
14498
|
}
|
|
14195
14499
|
const canonical = contentAddressedBackupPath(version, pristineSha256);
|
|
14196
14500
|
if (canonical !== backup) {
|
|
14501
|
+
recordProvenance(backup);
|
|
14502
|
+
recordProvenance(canonical);
|
|
14197
14503
|
const alreadyStored = facts.backups.some(
|
|
14198
14504
|
(candidate) => candidate.path === canonical && candidate.sha256 === pristineSha256
|
|
14199
14505
|
);
|
|
14200
|
-
if (!alreadyStored)
|
|
14506
|
+
if (!alreadyStored) publishFileByRename(backup, canonical);
|
|
14201
14507
|
backup = canonical;
|
|
14202
14508
|
}
|
|
14203
|
-
|
|
14509
|
+
publishFileByRename(backup, tweakccMirrorBackupPath());
|
|
14510
|
+
recordProvenance(backup);
|
|
14511
|
+
if (plan.backupPath !== backup) recordProvenance(plan.backupPath);
|
|
14204
14512
|
const builtIn = applyClodexPatches(loaded.source, desired.config);
|
|
14205
14513
|
results = builtIn.results;
|
|
14206
14514
|
const failedEffortPatches = requiredEffortPatchFailures(results);
|
|
@@ -14267,7 +14575,7 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14267
14575
|
else if (publishedBlob) resignMachOBinary(candidatePath);
|
|
14268
14576
|
patchedSize = statSync8(candidatePath).size;
|
|
14269
14577
|
patchedSha256 = sha256File(candidatePath);
|
|
14270
|
-
|
|
14578
|
+
renameSync3(candidatePath, binaryPath);
|
|
14271
14579
|
} catch (err) {
|
|
14272
14580
|
const detailLines = err instanceof PatchApplyError ? summarizePatchResults(err.results) : [];
|
|
14273
14581
|
if (opts.trace && detailLines.length) {
|
|
@@ -14282,7 +14590,7 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14282
14590
|
} finally {
|
|
14283
14591
|
if (candidateDir !== void 0) {
|
|
14284
14592
|
try {
|
|
14285
|
-
|
|
14593
|
+
rmSync2(candidateDir, { recursive: true, force: true });
|
|
14286
14594
|
} catch (err) {
|
|
14287
14595
|
if (opts.trace) {
|
|
14288
14596
|
process.stderr.write(
|
|
@@ -14305,6 +14613,7 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14305
14613
|
patchedSha256,
|
|
14306
14614
|
backupPath: backup,
|
|
14307
14615
|
pristineSha256,
|
|
14616
|
+
...pristine.provenance === "assumed" ? { pristineProvenance: "assumed" } : {},
|
|
14308
14617
|
patchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
14309
14618
|
};
|
|
14310
14619
|
writePatchManifest(manifest);
|
|
@@ -14318,7 +14627,7 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14318
14627
|
};
|
|
14319
14628
|
}
|
|
14320
14629
|
function runRestoreCommand(target) {
|
|
14321
|
-
if (!target.ok && (target.reason === "binary-not-found" || target.reason === "native-binary-missing")) {
|
|
14630
|
+
if (!target.ok && (target.reason === "binary-not-found" || target.reason === "patch-target-missing" || target.reason === "native-binary-missing")) {
|
|
14322
14631
|
p2.log.error(describePatchTargetFailure(target, "restore"));
|
|
14323
14632
|
return 1;
|
|
14324
14633
|
}
|
|
@@ -14353,16 +14662,65 @@ function runRestoreCommand(target) {
|
|
|
14353
14662
|
p2.log.error(verified.message);
|
|
14354
14663
|
return 1;
|
|
14355
14664
|
}
|
|
14356
|
-
|
|
14665
|
+
if (manifest && manifest.backupPath && manifest.binaryPath === binaryPath && manifest.claudeVersion !== version && manifest.backupPath !== plan.backupPath) {
|
|
14666
|
+
try {
|
|
14667
|
+
if (existsSync5(manifest.backupPath)) {
|
|
14668
|
+
recordBackupProvenance(manifest.backupPath, manifest.binaryPath, {
|
|
14669
|
+
assumed: manifest.pristineProvenance === "assumed"
|
|
14670
|
+
});
|
|
14671
|
+
}
|
|
14672
|
+
} catch (err) {
|
|
14673
|
+
p2.log.warn(
|
|
14674
|
+
`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.`
|
|
14675
|
+
);
|
|
14676
|
+
}
|
|
14677
|
+
}
|
|
14678
|
+
let recorded;
|
|
14357
14679
|
try {
|
|
14358
|
-
|
|
14680
|
+
recorded = recordBackupProvenance(plan.backupPath, binaryPath, { assumed: plan.assumedForThisInstall });
|
|
14681
|
+
} catch (err) {
|
|
14682
|
+
recorded = "failed";
|
|
14683
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
14684
|
+
if (plan.assumedForThisInstall) {
|
|
14685
|
+
p2.log.error(
|
|
14686
|
+
`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.`
|
|
14687
|
+
);
|
|
14688
|
+
return 1;
|
|
14689
|
+
}
|
|
14690
|
+
p2.log.warn(
|
|
14691
|
+
`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.`
|
|
14692
|
+
);
|
|
14693
|
+
}
|
|
14694
|
+
let publishedMode;
|
|
14695
|
+
try {
|
|
14696
|
+
publishedMode = statSync8(binaryPath).mode;
|
|
14359
14697
|
} catch {
|
|
14360
14698
|
}
|
|
14699
|
+
try {
|
|
14700
|
+
publishFileByRename(plan.backupPath, binaryPath, publishedMode);
|
|
14701
|
+
} catch (err) {
|
|
14702
|
+
p2.log.warn(
|
|
14703
|
+
`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.`
|
|
14704
|
+
);
|
|
14705
|
+
copyFileSync(plan.backupPath, binaryPath);
|
|
14706
|
+
}
|
|
14707
|
+
if (recorded === "established" && (!manifest || manifest.binaryPath === binaryPath)) {
|
|
14708
|
+
try {
|
|
14709
|
+
unlinkSync3(getPatchManifestPath());
|
|
14710
|
+
} catch {
|
|
14711
|
+
}
|
|
14712
|
+
}
|
|
14361
14713
|
p2.log.success(`Restored pristine claude ${version} from ${plan.backupPath}.`);
|
|
14362
14714
|
return 0;
|
|
14363
14715
|
}
|
|
14364
14716
|
async function runPatchCommand(opts = {}) {
|
|
14365
14717
|
const target = resolveClaudeBinaryForPatch();
|
|
14718
|
+
const ignoredOverride = takeIgnoredLaunchOverride();
|
|
14719
|
+
if (ignoredOverride) {
|
|
14720
|
+
p2.log.warn(
|
|
14721
|
+
`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.`
|
|
14722
|
+
);
|
|
14723
|
+
}
|
|
14366
14724
|
if (opts.restore) return runRestoreCommand(target);
|
|
14367
14725
|
if (!target.ok) {
|
|
14368
14726
|
p2.log.error(describePatchTargetFailure(target));
|
|
@@ -14405,6 +14763,19 @@ async function runPatchCommand(opts = {}) {
|
|
|
14405
14763
|
p2.log.warn("Another clodex process is patching the claude binary right now \u2014 skipped.");
|
|
14406
14764
|
return 1;
|
|
14407
14765
|
}
|
|
14766
|
+
if (manifest && manifest.backupPath && (manifest.binaryPath !== binaryPath || manifest.claudeVersion !== version)) {
|
|
14767
|
+
try {
|
|
14768
|
+
if (existsSync5(manifest.backupPath)) {
|
|
14769
|
+
recordBackupProvenance(manifest.backupPath, manifest.binaryPath, {
|
|
14770
|
+
assumed: manifest.pristineProvenance === "assumed"
|
|
14771
|
+
});
|
|
14772
|
+
}
|
|
14773
|
+
} catch (err) {
|
|
14774
|
+
p2.log.warn(
|
|
14775
|
+
`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.`
|
|
14776
|
+
);
|
|
14777
|
+
}
|
|
14778
|
+
}
|
|
14408
14779
|
try {
|
|
14409
14780
|
const outcome = await applyPatch(binaryPath, version, desired, configHash, {
|
|
14410
14781
|
trace: opts.trace ?? false,
|
|
@@ -14784,7 +15155,7 @@ function localProvidersToServerModels(localProviders) {
|
|
|
14784
15155
|
}
|
|
14785
15156
|
|
|
14786
15157
|
// src/registry/credential-cleanup-journal.ts
|
|
14787
|
-
import { randomUUID as
|
|
15158
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
14788
15159
|
import {
|
|
14789
15160
|
closeSync as closeSync8,
|
|
14790
15161
|
existsSync as existsSync6,
|
|
@@ -14794,9 +15165,9 @@ import {
|
|
|
14794
15165
|
mkdirSync as mkdirSync6,
|
|
14795
15166
|
openSync as openSync8,
|
|
14796
15167
|
readFileSync as readFileSync11,
|
|
14797
|
-
renameSync as
|
|
15168
|
+
renameSync as renameSync4,
|
|
14798
15169
|
unlinkSync as unlinkSync4,
|
|
14799
|
-
writeFileSync as
|
|
15170
|
+
writeFileSync as writeFileSync7
|
|
14800
15171
|
} from "fs";
|
|
14801
15172
|
import { dirname as dirname6 } from "path";
|
|
14802
15173
|
var JOURNAL_SCHEMA_VERSION = 1;
|
|
@@ -14924,17 +15295,17 @@ function writeJournalUnlocked(journal, path) {
|
|
|
14924
15295
|
assertRegistryWriteOwnership(path);
|
|
14925
15296
|
ensureSecureAppHome();
|
|
14926
15297
|
mkdirSync6(dirname6(path), { recursive: true, mode: DIR_MODE2 });
|
|
14927
|
-
const tmp = `${path}.${process.pid}.${
|
|
15298
|
+
const tmp = `${path}.${process.pid}.${randomUUID5()}.tmp`;
|
|
14928
15299
|
let fd;
|
|
14929
15300
|
try {
|
|
14930
15301
|
fd = openSync8(tmp, "wx", FILE_MODE4);
|
|
14931
|
-
|
|
15302
|
+
writeFileSync7(fd, `${JSON.stringify(journal, null, 2)}
|
|
14932
15303
|
`);
|
|
14933
15304
|
fsyncSync2(fd);
|
|
14934
15305
|
closeSync8(fd);
|
|
14935
15306
|
fd = void 0;
|
|
14936
15307
|
assertRegistryWriteOwnership(path);
|
|
14937
|
-
|
|
15308
|
+
renameSync4(tmp, path);
|
|
14938
15309
|
syncParentDirectory(path);
|
|
14939
15310
|
} finally {
|
|
14940
15311
|
if (fd !== void 0) closeSync8(fd);
|
|
@@ -17817,7 +18188,7 @@ async function askSaveServerPassword() {
|
|
|
17817
18188
|
|
|
17818
18189
|
// src/server/router.ts
|
|
17819
18190
|
import { createServer as createServer2 } from "http";
|
|
17820
|
-
import { randomUUID as
|
|
18191
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
17821
18192
|
|
|
17822
18193
|
// src/openai-adapter.ts
|
|
17823
18194
|
import { tool as tool2, jsonSchema as jsonSchema2, streamText as streamText2, generateText as generateText2 } from "ai";
|
|
@@ -18233,7 +18604,7 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
|
18233
18604
|
plog(`model not found: ${body.model}`);
|
|
18234
18605
|
return;
|
|
18235
18606
|
}
|
|
18236
|
-
const requestId =
|
|
18607
|
+
const requestId = randomUUID6();
|
|
18237
18608
|
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"];
|
|
18238
18609
|
const claudeSessionId = extractClaudeSessionId(body, claudeSessionIdHeader);
|
|
18239
18610
|
const claudeAgentIds = extractClaudeAgentIds(req.headers);
|
|
@@ -18273,6 +18644,7 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
|
18273
18644
|
const forwardBody = { ...body, model: upstreamModelId(model) };
|
|
18274
18645
|
const authType = model.authType ?? "api";
|
|
18275
18646
|
const isOAuth = authType === "oauth";
|
|
18647
|
+
const goSessionHeaders = openCodeGoSessionHeaders(model, claudeSessionId);
|
|
18276
18648
|
auditInference(options, {
|
|
18277
18649
|
requestId,
|
|
18278
18650
|
modelId: body.model,
|
|
@@ -18303,7 +18675,7 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
|
18303
18675
|
authType,
|
|
18304
18676
|
log: (message) => plog(message),
|
|
18305
18677
|
claudeCodeSessionId,
|
|
18306
|
-
extraHeaders: model.headers,
|
|
18678
|
+
extraHeaders: { ...model.headers, ...goSessionHeaders },
|
|
18307
18679
|
refreshToken,
|
|
18308
18680
|
onTokenRefreshed: (refreshed) => {
|
|
18309
18681
|
model.apiKey = refreshed;
|
|
@@ -18375,6 +18747,8 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
|
18375
18747
|
maxTools: npmMaxTools,
|
|
18376
18748
|
log: plog
|
|
18377
18749
|
});
|
|
18750
|
+
const goSdkSessionHeaders = openCodeGoSessionHeaders(model, claudeSessionId);
|
|
18751
|
+
if (goSdkSessionHeaders) params.headers = { ...params.headers, ...goSdkSessionHeaders };
|
|
18378
18752
|
const clientWantsStream = Boolean(body.stream);
|
|
18379
18753
|
const responseModelId = getResponseModelId(body.model, model, options);
|
|
18380
18754
|
plog(() => `sdk npm=${model.npm} upstream=${upstreamModelId(model)} responseModel=${responseModelId} stream=${clientWantsStream}`);
|
|
@@ -18566,6 +18940,8 @@ async function handleOpenAIChatCompletions(req, res, options, modelCache, plog)
|
|
|
18566
18940
|
}
|
|
18567
18941
|
const model = lookupModel(res, options.catalog, body.model);
|
|
18568
18942
|
if (!model) return;
|
|
18943
|
+
const openAiSessionIdHeader = Array.isArray(req.headers["x-claude-code-session-id"]) ? req.headers["x-claude-code-session-id"][0] : req.headers["x-claude-code-session-id"];
|
|
18944
|
+
const goSessionHeaders = openCodeGoSessionHeaders(model, openAiSessionIdHeader);
|
|
18569
18945
|
if (supportsDirectOpenAIChatCompletions(model)) {
|
|
18570
18946
|
if (model.completionsUrl && !/^https?:\/\//i.test(model.completionsUrl)) {
|
|
18571
18947
|
sendJson(res, 400, { error: { message: `Invalid provider completionsUrl: must be http:// or https://` } });
|
|
@@ -18602,7 +18978,7 @@ async function handleOpenAIChatCompletions(req, res, options, modelCache, plog)
|
|
|
18602
18978
|
try {
|
|
18603
18979
|
await relayAnthropicMessages(res, completionsUrl, forwardBody, apiKey2, Boolean(body.stream), {
|
|
18604
18980
|
authType: model.authType ?? "api",
|
|
18605
|
-
extraHeaders: model.headers,
|
|
18981
|
+
extraHeaders: { ...model.headers, ...goSessionHeaders },
|
|
18606
18982
|
refreshToken,
|
|
18607
18983
|
onTokenRefreshed: (refreshed) => {
|
|
18608
18984
|
model.apiKey = refreshed;
|
|
@@ -18647,6 +19023,7 @@ async function handleOpenAIChatCompletions(req, res, options, modelCache, plog)
|
|
|
18647
19023
|
const baseURL = model.modelFormat === "anthropic" ? model.baseUrl : model.apiBaseUrl;
|
|
18648
19024
|
const openAiOAuth = isOpenAiOAuthRoute(model);
|
|
18649
19025
|
const params = translateOpenAiRequest(body, { openAiOAuth });
|
|
19026
|
+
if (goSessionHeaders) params.headers = { ...params.headers, ...goSessionHeaders };
|
|
18650
19027
|
const clientWantsStream = Boolean(body.stream);
|
|
18651
19028
|
const responseModelId = getResponseModelId(body.model, model, options);
|
|
18652
19029
|
plog(() => `sdk-openai npm=${npm} upstream=${upstreamModelId(model)} responseModel=${responseModelId} stream=${clientWantsStream}`);
|
|
@@ -18901,13 +19278,13 @@ import * as http2 from "http";
|
|
|
18901
19278
|
import * as https from "https";
|
|
18902
19279
|
import * as net from "net";
|
|
18903
19280
|
import { PassThrough } from "stream";
|
|
18904
|
-
import { randomUUID as
|
|
19281
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
18905
19282
|
import { URL as URL2 } from "url";
|
|
18906
19283
|
import { createBrotliDecompress, createGunzip, createInflate } from "zlib";
|
|
18907
19284
|
|
|
18908
19285
|
// src/http-proxy/ca.ts
|
|
18909
19286
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
18910
|
-
import { chmodSync as
|
|
19287
|
+
import { chmodSync as chmodSync5, existsSync as existsSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "fs";
|
|
18911
19288
|
import { dirname as dirname7, join as join9, resolve as resolve3 } from "path";
|
|
18912
19289
|
import forge from "node-forge";
|
|
18913
19290
|
var CERT_DIR = "http-proxy";
|
|
@@ -18934,16 +19311,16 @@ function certPaths() {
|
|
|
18934
19311
|
};
|
|
18935
19312
|
}
|
|
18936
19313
|
function writePrivate(path, value) {
|
|
18937
|
-
|
|
18938
|
-
|
|
19314
|
+
writeFileSync8(path, value, { encoding: "utf8", mode: 384 });
|
|
19315
|
+
chmodSync5(path, 384);
|
|
18939
19316
|
}
|
|
18940
19317
|
function writePublic(path, value) {
|
|
18941
|
-
|
|
18942
|
-
|
|
19318
|
+
writeFileSync8(path, value, { encoding: "utf8", mode: 420 });
|
|
19319
|
+
chmodSync5(path, 420);
|
|
18943
19320
|
}
|
|
18944
19321
|
function generateCertificates(paths) {
|
|
18945
19322
|
mkdirSync7(paths.dir, { recursive: true, mode: 448 });
|
|
18946
|
-
|
|
19323
|
+
chmodSync5(paths.dir, 448);
|
|
18947
19324
|
const caKeys = forge.pki.rsa.generateKeyPair(2048);
|
|
18948
19325
|
const caCert = forge.pki.createCertificate();
|
|
18949
19326
|
caCert.publicKey = caKeys.publicKey;
|
|
@@ -19759,7 +20136,7 @@ async function startHttpProxy(options) {
|
|
|
19759
20136
|
}
|
|
19760
20137
|
const messagesEndpoint = anthropicMessagesEndpoint(req.url);
|
|
19761
20138
|
if (req.method === "POST" && messagesEndpoint) {
|
|
19762
|
-
const requestId =
|
|
20139
|
+
const requestId = randomUUID7();
|
|
19763
20140
|
let parsed = null;
|
|
19764
20141
|
let route;
|
|
19765
20142
|
let adapterBody = rawBody;
|