@bman654/clodex 2.17.0 → 2.18.0
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 +26 -7
- package/dist/{chunk-5TG736TX.js → chunk-YGEPQOPA.js} +3 -3
- package/dist/chunk-YGEPQOPA.js.map +1 -0
- package/dist/claude-wrapper.js +1 -1
- package/dist/cli.js +372 -124
- package/dist/cli.js.map +1 -1
- package/docs/background-agents.md +3 -1
- package/docs/windows-setup.md +27 -4
- package/package.json +1 -1
- package/dist/chunk-5TG736TX.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -74,7 +74,7 @@ import {
|
|
|
74
74
|
withRegistryWriteLockSync,
|
|
75
75
|
writeParentNoticeLines,
|
|
76
76
|
writeParentNoticeLinesSync
|
|
77
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-YGEPQOPA.js";
|
|
78
78
|
|
|
79
79
|
// src/cli.ts
|
|
80
80
|
import pc13 from "picocolors";
|
|
@@ -249,7 +249,7 @@ function printFavoritesOnlyPanel() {
|
|
|
249
249
|
|
|
250
250
|
// src/cli.ts
|
|
251
251
|
import * as p13 from "@clack/prompts";
|
|
252
|
-
import { realpathSync as
|
|
252
|
+
import { realpathSync as realpathSync4 } from "fs";
|
|
253
253
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
254
254
|
|
|
255
255
|
// src/launch.ts
|
|
@@ -346,7 +346,7 @@ import { join } from "path";
|
|
|
346
346
|
// package.json
|
|
347
347
|
var package_default = {
|
|
348
348
|
name: "@bman654/clodex",
|
|
349
|
-
version: "2.
|
|
349
|
+
version: "2.18.0",
|
|
350
350
|
publishConfig: {
|
|
351
351
|
access: "public"
|
|
352
352
|
},
|
|
@@ -3186,7 +3186,7 @@ function pricingBoundaryWarning(modelLabel, limits, resolved) {
|
|
|
3186
3186
|
const boundary = positiveInteger(limits.pricingBoundary);
|
|
3187
3187
|
if (boundary === void 0 || !resolved.crossesPricingBoundary) return null;
|
|
3188
3188
|
const note = limits.pricingBoundaryNote?.trim();
|
|
3189
|
-
return `${modelLabel}: a ${withThousands(resolved.effective)}-token window can grow past the ${withThousands(boundary)}-token pricing boundary.` + (note ? ` ${note}` : "") + "
|
|
3189
|
+
return `${modelLabel}: a ${withThousands(resolved.effective)}-token window can grow past the ${withThousands(boundary)}-token pricing boundary.` + (note ? ` ${note}` : "") + " Choose a smaller context stop to reduce the chance of higher-rate requests.";
|
|
3190
3190
|
}
|
|
3191
3191
|
function contextClampNotice(modelLabel, resolved) {
|
|
3192
3192
|
if (resolved.clampedFrom === void 0) return null;
|
|
@@ -3867,7 +3867,7 @@ import {
|
|
|
3867
3867
|
existsSync as existsSync4,
|
|
3868
3868
|
mkdtempSync,
|
|
3869
3869
|
mkdirSync as mkdirSync5,
|
|
3870
|
-
readFileSync as
|
|
3870
|
+
readFileSync as readFileSync10,
|
|
3871
3871
|
renameSync as renameSync2,
|
|
3872
3872
|
rmSync,
|
|
3873
3873
|
statSync as statSync7,
|
|
@@ -3875,10 +3875,10 @@ import {
|
|
|
3875
3875
|
writeFileSync as writeFileSync5,
|
|
3876
3876
|
openSync as openSync8,
|
|
3877
3877
|
closeSync as closeSync8,
|
|
3878
|
-
realpathSync as
|
|
3878
|
+
realpathSync as realpathSync3
|
|
3879
3879
|
} from "fs";
|
|
3880
|
-
import { homedir as
|
|
3881
|
-
import { basename, dirname as dirname5, join as
|
|
3880
|
+
import { homedir as homedir3 } from "os";
|
|
3881
|
+
import { basename, dirname as dirname5, join as join8 } from "path";
|
|
3882
3882
|
import pc3 from "picocolors";
|
|
3883
3883
|
import * as p2 from "@clack/prompts";
|
|
3884
3884
|
|
|
@@ -5979,6 +5979,69 @@ function deriveBrand(family) {
|
|
|
5979
5979
|
return "Other";
|
|
5980
5980
|
}
|
|
5981
5981
|
|
|
5982
|
+
// src/registry/server-text.ts
|
|
5983
|
+
function isControlCode(code) {
|
|
5984
|
+
return code <= 31 || code >= 127 && code <= 159;
|
|
5985
|
+
}
|
|
5986
|
+
function hasControlChars(value) {
|
|
5987
|
+
for (let i = 0; i < value.length; i++) {
|
|
5988
|
+
if (isControlCode(value.charCodeAt(i))) return true;
|
|
5989
|
+
}
|
|
5990
|
+
return false;
|
|
5991
|
+
}
|
|
5992
|
+
function printableServerText(value) {
|
|
5993
|
+
let out = "";
|
|
5994
|
+
for (const ch of value) out += isControlCode(ch.charCodeAt(0)) ? " " : ch;
|
|
5995
|
+
return out.trim();
|
|
5996
|
+
}
|
|
5997
|
+
|
|
5998
|
+
// src/codex-client-version.ts
|
|
5999
|
+
var VERSION2 = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$(?![\s\S])/;
|
|
6000
|
+
function readCodexClientVersion(value) {
|
|
6001
|
+
return typeof value === "string" && VERSION2.test(value) ? value : void 0;
|
|
6002
|
+
}
|
|
6003
|
+
function compareCodexClientVersions(a, b) {
|
|
6004
|
+
const left = VERSION2.exec(a);
|
|
6005
|
+
const right = VERSION2.exec(b);
|
|
6006
|
+
if (!left || !right) return void 0;
|
|
6007
|
+
for (let i = 1; i <= 3; i++) {
|
|
6008
|
+
const x = BigInt(left[i]);
|
|
6009
|
+
const y = BigInt(right[i]);
|
|
6010
|
+
if (x !== y) return x < y ? -1 : 1;
|
|
6011
|
+
}
|
|
6012
|
+
const preA = left[4];
|
|
6013
|
+
const preB = right[4];
|
|
6014
|
+
if (preA === preB) return 0;
|
|
6015
|
+
if (preA === void 0) return 1;
|
|
6016
|
+
if (preB === void 0) return -1;
|
|
6017
|
+
const partsA = preA.split(".");
|
|
6018
|
+
const partsB = preB.split(".");
|
|
6019
|
+
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
|
|
6020
|
+
const x = partsA[i];
|
|
6021
|
+
const y = partsB[i];
|
|
6022
|
+
if (x === void 0) return -1;
|
|
6023
|
+
if (y === void 0) return 1;
|
|
6024
|
+
if (x === y) continue;
|
|
6025
|
+
const numericX = /^\d+$/.test(x);
|
|
6026
|
+
const numericY = /^\d+$/.test(y);
|
|
6027
|
+
if (numericX && numericY) return BigInt(x) < BigInt(y) ? -1 : 1;
|
|
6028
|
+
if (numericX !== numericY) return numericX ? -1 : 1;
|
|
6029
|
+
return x < y ? -1 : 1;
|
|
6030
|
+
}
|
|
6031
|
+
return 0;
|
|
6032
|
+
}
|
|
6033
|
+
function requiresNewerCodexClient(model) {
|
|
6034
|
+
if (!model.useResponsesLite) return false;
|
|
6035
|
+
const minimum = readCodexClientVersion(model.minimalClientVersion);
|
|
6036
|
+
return minimum !== void 0 && compareCodexClientVersions(minimum, CODEX_RESPONSES_LITE_VERSION) === 1;
|
|
6037
|
+
}
|
|
6038
|
+
function codexClientVersionWarning(models) {
|
|
6039
|
+
const unavailable = models.filter(requiresNewerCodexClient);
|
|
6040
|
+
if (unavailable.length === 0) return void 0;
|
|
6041
|
+
const details = unavailable.map((model) => `${printableServerText(model.id)} (requires ${model.minimalClientVersion})`).join(", ");
|
|
6042
|
+
return `Hidden ChatGPT-plan models: ${details}. clodex sends Codex client version ${CODEX_RESPONSES_LITE_VERSION} for Responses-Lite; their catalog minimum exceeds this version. Update clodex to a release supporting their required version to use them.`;
|
|
6043
|
+
}
|
|
6044
|
+
|
|
5982
6045
|
// src/data/openai-oauth-models.ts
|
|
5983
6046
|
var GPT_HIGH_CONTEXT_PRICING_BOUNDARY = 272e3;
|
|
5984
6047
|
var GPT_HIGH_CONTEXT_PRICING_NOTE = "Above it, OpenAI prices the full request at 2x input and 1.5x output.";
|
|
@@ -5993,17 +6056,17 @@ var OPENAI_OAUTH_MODEL_SEEDS = [
|
|
|
5993
6056
|
// context window, but the Codex client is served a smaller one, and this path is
|
|
5994
6057
|
// Codex-only. All three cards publish a 128,000 output limit and the same 272K
|
|
5995
6058
|
// pricing boundary as the GPT-5.6 family.
|
|
5996
|
-
{ id: "gpt-6-astra", name: "GPT-6 Astra", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true },
|
|
5997
|
-
{ id: "gpt-6-sol", name: "GPT-6 Sol", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true },
|
|
5998
|
-
{ id: "gpt-6-luna", name: "GPT-6 Luna", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true },
|
|
6059
|
+
{ id: "gpt-6-astra", name: "GPT-6 Astra", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true, minimalClientVersion: "0.153.0" },
|
|
6060
|
+
{ id: "gpt-6-sol", name: "GPT-6 Sol", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true, minimalClientVersion: "0.155.0" },
|
|
6061
|
+
{ id: "gpt-6-luna", name: "GPT-6 Luna", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true, minimalClientVersion: "0.155.0" },
|
|
5999
6062
|
// "An alias for our flagship general-purpose models, with safeguards calibrated
|
|
6000
6063
|
// for defensive cybersecurity work" — access is gated on a separate opt-in
|
|
6001
6064
|
// program, so most installs will never see this id in their catalog.
|
|
6002
|
-
{ id: "gpt-daybreak-blue-latest", name: "GPT Daybreak Blue", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true },
|
|
6065
|
+
{ id: "gpt-daybreak-blue-latest", name: "GPT Daybreak Blue", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true, minimalClientVersion: "0.144.0" },
|
|
6003
6066
|
// GPT-5.6 family (Sol / Terra / Luna)
|
|
6004
|
-
{ id: "gpt-5.6-sol", name: "GPT-5.6 Sol", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true },
|
|
6005
|
-
{ id: "gpt-5.6-terra", name: "GPT-5.6 Terra", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true },
|
|
6006
|
-
{ id: "gpt-5.6-luna", name: "GPT-5.6 Luna", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true },
|
|
6067
|
+
{ id: "gpt-5.6-sol", name: "GPT-5.6 Sol", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, minimalClientVersion: "0.144.0" },
|
|
6068
|
+
{ id: "gpt-5.6-terra", name: "GPT-5.6 Terra", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, minimalClientVersion: "0.144.0" },
|
|
6069
|
+
{ id: "gpt-5.6-luna", name: "GPT-5.6 Luna", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true, minimalClientVersion: "0.144.0" },
|
|
6007
6070
|
// GPT-5.5 family (Pro)
|
|
6008
6071
|
{ id: "gpt-5.5", name: "GPT-5.5", contextWindow: 272e3, maxOutputTokens: 128e3, reasoning: true },
|
|
6009
6072
|
// GPT-5.4 family
|
|
@@ -6045,12 +6108,16 @@ function applyOAuthSeedContextMetadata(models) {
|
|
|
6045
6108
|
const pricing = openAiPricingMetadata(model.id);
|
|
6046
6109
|
return {
|
|
6047
6110
|
...model,
|
|
6111
|
+
contextWindow: model.contextWindow ?? seed?.contextWindow,
|
|
6048
6112
|
maxContextWindow: model.maxContextWindow ?? seed?.maxContextWindow,
|
|
6049
6113
|
effectiveContextPercent: migratedEffectiveContextPercent(model.effectiveContextPercent),
|
|
6050
6114
|
pricingBoundary: model.pricingBoundary ?? seed?.pricingBoundary ?? pricing.pricingBoundary,
|
|
6051
6115
|
pricingBoundaryNote: model.pricingBoundaryNote ?? seed?.pricingBoundaryNote ?? pricing.pricingBoundaryNote,
|
|
6052
6116
|
maxOutputTokens: model.maxOutputTokens ?? seed?.maxOutputTokens,
|
|
6053
|
-
reasoning: seed?.reasoning ?? model.reasoning
|
|
6117
|
+
reasoning: seed?.reasoning ?? model.reasoning,
|
|
6118
|
+
useResponsesLite: model.useResponsesLite ?? seed?.useResponsesLite,
|
|
6119
|
+
preferWebSockets: model.preferWebSockets ?? seed?.preferWebSockets,
|
|
6120
|
+
minimalClientVersion: model.minimalClientVersion ?? seed?.minimalClientVersion
|
|
6054
6121
|
};
|
|
6055
6122
|
});
|
|
6056
6123
|
}
|
|
@@ -6074,7 +6141,8 @@ function buildOpenAiOAuthModels() {
|
|
|
6074
6141
|
npm: "@ai-sdk/openai",
|
|
6075
6142
|
reasoning: seed.reasoning,
|
|
6076
6143
|
useResponsesLite: seed.useResponsesLite,
|
|
6077
|
-
preferWebSockets: seed.preferWebSockets
|
|
6144
|
+
preferWebSockets: seed.preferWebSockets,
|
|
6145
|
+
minimalClientVersion: seed.minimalClientVersion
|
|
6078
6146
|
};
|
|
6079
6147
|
});
|
|
6080
6148
|
}
|
|
@@ -6104,22 +6172,6 @@ function normalizeGoogleDisplayName(rawName, bareId) {
|
|
|
6104
6172
|
return stripGoogleModelPrefix(trimmed);
|
|
6105
6173
|
}
|
|
6106
6174
|
|
|
6107
|
-
// src/registry/server-text.ts
|
|
6108
|
-
function isControlCode(code) {
|
|
6109
|
-
return code <= 31 || code >= 127 && code <= 159;
|
|
6110
|
-
}
|
|
6111
|
-
function hasControlChars(value) {
|
|
6112
|
-
for (let i = 0; i < value.length; i++) {
|
|
6113
|
-
if (isControlCode(value.charCodeAt(i))) return true;
|
|
6114
|
-
}
|
|
6115
|
-
return false;
|
|
6116
|
-
}
|
|
6117
|
-
function printableServerText(value) {
|
|
6118
|
-
let out = "";
|
|
6119
|
-
for (const ch of value) out += isControlCode(ch.charCodeAt(0)) ? " " : ch;
|
|
6120
|
-
return out.trim();
|
|
6121
|
-
}
|
|
6122
|
-
|
|
6123
6175
|
// src/trace-log.ts
|
|
6124
6176
|
import {
|
|
6125
6177
|
chmodSync as chmodSync3,
|
|
@@ -6590,6 +6642,7 @@ function parseModelList(body, npm, allowBareArray) {
|
|
|
6590
6642
|
family,
|
|
6591
6643
|
brand: deriveBrand(family),
|
|
6592
6644
|
contextWindow,
|
|
6645
|
+
...npm === "@ai-sdk/openai" ? openAiPricingMetadata(id) : {},
|
|
6593
6646
|
cost,
|
|
6594
6647
|
isFree: isFreeStatus(freeStatus),
|
|
6595
6648
|
freeStatus,
|
|
@@ -6607,6 +6660,7 @@ function materializeTemplateModel(template, model, baseUrl) {
|
|
|
6607
6660
|
const { id, upstreamModelId: normalizedUpstream } = normalizeGoogleModelId(model.id, npm);
|
|
6608
6661
|
const family = model.family ?? (id.split(/[-/:]/)[0] ?? id);
|
|
6609
6662
|
const freeStatus = model.freeStatus ?? classifyFreeStatus({ model });
|
|
6663
|
+
const pricing = npm === "@ai-sdk/openai" ? openAiPricingMetadata(model.upstreamModelId ?? id) : {};
|
|
6610
6664
|
return {
|
|
6611
6665
|
...model,
|
|
6612
6666
|
id,
|
|
@@ -6615,6 +6669,8 @@ function materializeTemplateModel(template, model, baseUrl) {
|
|
|
6615
6669
|
family,
|
|
6616
6670
|
brand: model.brand ?? deriveBrand(family),
|
|
6617
6671
|
contextWindow: model.contextWindow ?? lookupKnownContextWindow(id),
|
|
6672
|
+
pricingBoundary: model.pricingBoundary ?? pricing.pricingBoundary,
|
|
6673
|
+
pricingBoundaryNote: model.pricingBoundaryNote ?? pricing.pricingBoundaryNote,
|
|
6618
6674
|
isFree: model.isFree ?? isFreeStatus(freeStatus),
|
|
6619
6675
|
freeStatus,
|
|
6620
6676
|
modelFormat: model.modelFormat ?? modelFormatForNpm(npm),
|
|
@@ -6807,8 +6863,21 @@ function resolveEndpoint(npm, apiUrl) {
|
|
|
6807
6863
|
}
|
|
6808
6864
|
function projectProviderCachedModels(provider) {
|
|
6809
6865
|
const cached = provider.modelsCache?.models ?? [];
|
|
6810
|
-
if (isChatGptOAuthProvider(provider))
|
|
6811
|
-
|
|
6866
|
+
if (isChatGptOAuthProvider(provider)) {
|
|
6867
|
+
return applyOAuthSeedContextMetadata(cached).filter((model) => !requiresNewerCodexClient(model));
|
|
6868
|
+
}
|
|
6869
|
+
if (!isRetainedOpenCodeGoProvider(provider)) {
|
|
6870
|
+
if (!cached.some((model) => (model.npm ?? provider.api.npm) === "@ai-sdk/openai")) return cached;
|
|
6871
|
+
return cached.map((model) => {
|
|
6872
|
+
if ((model.npm ?? provider.api.npm) !== "@ai-sdk/openai") return model;
|
|
6873
|
+
const pricing = openAiPricingMetadata(model.upstreamModelId ?? model.id);
|
|
6874
|
+
return {
|
|
6875
|
+
...model,
|
|
6876
|
+
pricingBoundary: model.pricingBoundary ?? pricing.pricingBoundary,
|
|
6877
|
+
pricingBoundaryNote: model.pricingBoundaryNote ?? pricing.pricingBoundaryNote
|
|
6878
|
+
};
|
|
6879
|
+
});
|
|
6880
|
+
}
|
|
6812
6881
|
const template = retainedOpenCodeGoTemplate();
|
|
6813
6882
|
return template ? applyTemplateModelMetadata(template, cached) : [];
|
|
6814
6883
|
}
|
|
@@ -6962,8 +7031,162 @@ function materializeRegistry(registry, resolveCredential, opts) {
|
|
|
6962
7031
|
return result;
|
|
6963
7032
|
}
|
|
6964
7033
|
|
|
7034
|
+
// src/editor-extension-version.ts
|
|
7035
|
+
import { execFileSync, execSync } from "child_process";
|
|
7036
|
+
import { readdirSync, readFileSync as readFileSync7, realpathSync } from "fs";
|
|
7037
|
+
import { homedir as homedir2 } from "os";
|
|
7038
|
+
import { join as join6 } from "path";
|
|
7039
|
+
var CLAUDE_EXTENSION_ID = "anthropic.claude-code";
|
|
7040
|
+
var EDITOR_EXTENSION_ROOTS = [
|
|
7041
|
+
{ editor: "VS Code", dir: ".vscode" },
|
|
7042
|
+
{ editor: "VS Code Insiders", dir: ".vscode-insiders" },
|
|
7043
|
+
{ editor: "VS Code (remote server)", dir: ".vscode-server" },
|
|
7044
|
+
{ editor: "VSCodium", dir: ".vscode-oss" },
|
|
7045
|
+
{ editor: "Cursor", dir: ".cursor" },
|
|
7046
|
+
{ editor: "Windsurf", dir: ".windsurf" }
|
|
7047
|
+
];
|
|
7048
|
+
var CHECKED_EDITORS_DESCRIPTION = EDITOR_EXTENSION_ROOTS.map((root) => root.editor).join(", ");
|
|
7049
|
+
function releaseKey(version) {
|
|
7050
|
+
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version.trim());
|
|
7051
|
+
return match ? match.slice(1).map(Number) : null;
|
|
7052
|
+
}
|
|
7053
|
+
function compareVersionKeys(a, b) {
|
|
7054
|
+
for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
|
|
7055
|
+
const diff = (a[i] ?? 0) - (b[i] ?? 0);
|
|
7056
|
+
if (diff !== 0) return diff;
|
|
7057
|
+
}
|
|
7058
|
+
return 0;
|
|
7059
|
+
}
|
|
7060
|
+
function newestVersion(versions) {
|
|
7061
|
+
let best = null;
|
|
7062
|
+
for (const version of versions) {
|
|
7063
|
+
const key = releaseKey(version);
|
|
7064
|
+
if (key && (!best || compareVersionKeys(key, best.key) > 0)) best = { version, key };
|
|
7065
|
+
}
|
|
7066
|
+
return best?.version ?? null;
|
|
7067
|
+
}
|
|
7068
|
+
var EXTENSION_DIR_PATTERN = /^anthropic\.claude-code-(\d+\.\d+\.\d+)(?:-[a-z0-9]+)*$/i;
|
|
7069
|
+
function readJson(path) {
|
|
7070
|
+
try {
|
|
7071
|
+
return JSON.parse(readFileSync7(path, "utf8"));
|
|
7072
|
+
} catch {
|
|
7073
|
+
return void 0;
|
|
7074
|
+
}
|
|
7075
|
+
}
|
|
7076
|
+
function entryDirectoryName(entry) {
|
|
7077
|
+
if (typeof entry.relativeLocation === "string") return entry.relativeLocation;
|
|
7078
|
+
const location = entry.location;
|
|
7079
|
+
const raw = typeof location === "string" ? location : location && typeof location === "object" ? location.fsPath ?? location.path : void 0;
|
|
7080
|
+
if (typeof raw !== "string") return null;
|
|
7081
|
+
const parts = raw.split(/[\\/]/).filter(Boolean);
|
|
7082
|
+
return parts.at(-1) ?? null;
|
|
7083
|
+
}
|
|
7084
|
+
function readClaudeExtensionVersion(extensionsDir) {
|
|
7085
|
+
let names;
|
|
7086
|
+
try {
|
|
7087
|
+
names = readdirSync(extensionsDir);
|
|
7088
|
+
} catch {
|
|
7089
|
+
return null;
|
|
7090
|
+
}
|
|
7091
|
+
const present = new Set(names);
|
|
7092
|
+
const listed = readJson(join6(extensionsDir, "extensions.json"));
|
|
7093
|
+
if (Array.isArray(listed)) {
|
|
7094
|
+
const versions2 = [];
|
|
7095
|
+
for (const item of listed) {
|
|
7096
|
+
if (!item || typeof item !== "object") continue;
|
|
7097
|
+
const entry = item;
|
|
7098
|
+
const identifier = entry.identifier;
|
|
7099
|
+
if (typeof identifier?.id !== "string" || identifier.id.toLowerCase() !== CLAUDE_EXTENSION_ID) continue;
|
|
7100
|
+
if (typeof entry.version !== "string") continue;
|
|
7101
|
+
const dirName = entryDirectoryName(entry);
|
|
7102
|
+
if (dirName !== null && !present.has(dirName)) continue;
|
|
7103
|
+
versions2.push(entry.version);
|
|
7104
|
+
}
|
|
7105
|
+
return newestVersion(versions2);
|
|
7106
|
+
}
|
|
7107
|
+
const obsoleteRaw = readJson(join6(extensionsDir, ".obsolete"));
|
|
7108
|
+
const obsolete = obsoleteRaw && typeof obsoleteRaw === "object" && !Array.isArray(obsoleteRaw) ? new Set(Object.entries(obsoleteRaw).filter(([, flagged]) => flagged).map(([name]) => name)) : /* @__PURE__ */ new Set();
|
|
7109
|
+
const versions = [];
|
|
7110
|
+
for (const name of names) {
|
|
7111
|
+
if (obsolete.has(name)) continue;
|
|
7112
|
+
const match = EXTENSION_DIR_PATTERN.exec(name);
|
|
7113
|
+
if (match) versions.push(match[1]);
|
|
7114
|
+
}
|
|
7115
|
+
return newestVersion(versions);
|
|
7116
|
+
}
|
|
7117
|
+
function findInstalledClaudeExtensions(home = homedir2()) {
|
|
7118
|
+
const found = [];
|
|
7119
|
+
for (const root of EDITOR_EXTENSION_ROOTS) {
|
|
7120
|
+
const extensionsDir = join6(home, root.dir, "extensions");
|
|
7121
|
+
const version = readClaudeExtensionVersion(extensionsDir);
|
|
7122
|
+
if (version) found.push({ editor: root.editor, extensionsDir, version });
|
|
7123
|
+
}
|
|
7124
|
+
return found;
|
|
7125
|
+
}
|
|
7126
|
+
var NPM_ROOT_TIMEOUT_MS = 1e4;
|
|
7127
|
+
function readNpmGlobalRoot(env = process.env) {
|
|
7128
|
+
try {
|
|
7129
|
+
const options = {
|
|
7130
|
+
env,
|
|
7131
|
+
encoding: "utf8",
|
|
7132
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
7133
|
+
timeout: NPM_ROOT_TIMEOUT_MS
|
|
7134
|
+
};
|
|
7135
|
+
const output = process.platform === "win32" ? execSync("npm root -g", options) : execFileSync("npm", ["root", "-g"], options);
|
|
7136
|
+
const root = output.trim().split(/\r?\n/).at(-1)?.trim();
|
|
7137
|
+
return root || null;
|
|
7138
|
+
} catch {
|
|
7139
|
+
return null;
|
|
7140
|
+
}
|
|
7141
|
+
}
|
|
7142
|
+
function comparablePath(path) {
|
|
7143
|
+
let real = path;
|
|
7144
|
+
try {
|
|
7145
|
+
real = realpathSync(path);
|
|
7146
|
+
} catch {
|
|
7147
|
+
}
|
|
7148
|
+
const normalized = real.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
7149
|
+
return /^[a-z]:\//i.test(normalized) ? normalized.toLowerCase() : normalized;
|
|
7150
|
+
}
|
|
7151
|
+
function claudeInstallCommand(binaryPath, version, npmGlobalRoot) {
|
|
7152
|
+
const path = comparablePath(binaryPath);
|
|
7153
|
+
if (/\/\.local\/share\/claude\/versions\/[^/]+$/.test(path)) return `claude install ${version}`;
|
|
7154
|
+
if (/\/node_modules\/@anthropic-ai\/claude-code/.test(path)) {
|
|
7155
|
+
const root = npmGlobalRoot();
|
|
7156
|
+
const packagePrefix = root === null ? null : `${comparablePath(root)}/@anthropic-ai/claude-code`;
|
|
7157
|
+
const underGlobalPackage = packagePrefix !== null && path.startsWith(packagePrefix) && ["/", "-"].includes(path.charAt(packagePrefix.length));
|
|
7158
|
+
if (underGlobalPackage) return `npm install -g @anthropic-ai/claude-code@${version}`;
|
|
7159
|
+
}
|
|
7160
|
+
return null;
|
|
7161
|
+
}
|
|
7162
|
+
function describeExtensionDrift(extension, patched, npmGlobalRoot) {
|
|
7163
|
+
const extensionKey = releaseKey(extension.version);
|
|
7164
|
+
const patchedKey = releaseKey(patched.version);
|
|
7165
|
+
if (!extensionKey || !patchedKey) return null;
|
|
7166
|
+
const order = compareVersionKeys(extensionKey, patchedKey);
|
|
7167
|
+
if (order === 0) return null;
|
|
7168
|
+
const { editor, version } = extension;
|
|
7169
|
+
const install = claudeInstallCommand(patched.binaryPath, version, npmGlobalRoot);
|
|
7170
|
+
const lines = [
|
|
7171
|
+
`${editor}'s Claude Code extension is ${version}, but the Claude Code clodex patched is ${patched.version} (${patched.binaryPath}).`,
|
|
7172
|
+
`When ${editor} launches Claude Code through clodex-claude (claudeCode.claudeProcessWrapper), its chats run the extension's own bundled ${version} binary and clodex models will not appear in its model picker.`,
|
|
7173
|
+
...install ? ["To fix it, run:", ` ${install}`, " clodex patch"] : [`To fix it, update the Claude Code at ${patched.binaryPath} to ${version} with the tool that installed it, then run:`, " clodex patch"]
|
|
7174
|
+
];
|
|
7175
|
+
if (order < 0) lines.push(`Or update the extension in ${editor} to ${patched.version}.`);
|
|
7176
|
+
return lines.join("\n");
|
|
7177
|
+
}
|
|
7178
|
+
function claudeExtensionDriftWarnings(patched, home = homedir2(), npmGlobalRoot = () => readNpmGlobalRoot()) {
|
|
7179
|
+
let root = null;
|
|
7180
|
+
const cachedRoot = () => (root ??= { value: npmGlobalRoot() }).value;
|
|
7181
|
+
try {
|
|
7182
|
+
return findInstalledClaudeExtensions(home).map((extension) => describeExtensionDrift(extension, patched, cachedRoot)).filter((warning) => warning !== null);
|
|
7183
|
+
} catch {
|
|
7184
|
+
return [];
|
|
7185
|
+
}
|
|
7186
|
+
}
|
|
7187
|
+
|
|
6965
7188
|
// src/npm-shim.ts
|
|
6966
|
-
import { readFileSync as
|
|
7189
|
+
import { readFileSync as readFileSync8, realpathSync as realpathSync2, statSync as statSync4 } from "fs";
|
|
6967
7190
|
import { dirname as dirname3, resolve as resolve2 } from "path";
|
|
6968
7191
|
var MAX_LAUNCHER_BYTES = 64 * 1024;
|
|
6969
7192
|
var MAX_LAUNCHER_HOPS = 4;
|
|
@@ -6986,7 +7209,7 @@ function launcherKind(shimPath) {
|
|
|
6986
7209
|
function readLauncherText(path) {
|
|
6987
7210
|
try {
|
|
6988
7211
|
if (statSync4(path).size > MAX_LAUNCHER_BYTES) return null;
|
|
6989
|
-
return
|
|
7212
|
+
return readFileSync8(path, "utf8");
|
|
6990
7213
|
} catch {
|
|
6991
7214
|
return null;
|
|
6992
7215
|
}
|
|
@@ -7043,7 +7266,7 @@ function resolveThroughNpmShims(startPath) {
|
|
|
7043
7266
|
}
|
|
7044
7267
|
let hopped;
|
|
7045
7268
|
try {
|
|
7046
|
-
hopped =
|
|
7269
|
+
hopped = realpathSync2(reading.target);
|
|
7047
7270
|
} catch {
|
|
7048
7271
|
return {
|
|
7049
7272
|
ok: false,
|
|
@@ -7068,13 +7291,13 @@ import {
|
|
|
7068
7291
|
closeSync as closeSync2,
|
|
7069
7292
|
fstatSync,
|
|
7070
7293
|
openSync as openSync2,
|
|
7071
|
-
readFileSync as
|
|
7294
|
+
readFileSync as readFileSync9,
|
|
7072
7295
|
readSync,
|
|
7073
7296
|
statSync as statSync5
|
|
7074
7297
|
} from "fs";
|
|
7075
7298
|
import { createRequire } from "module";
|
|
7076
7299
|
import { arch } from "os";
|
|
7077
|
-
import { dirname as dirname4, join as
|
|
7300
|
+
import { dirname as dirname4, join as join7 } from "path";
|
|
7078
7301
|
var MAX_PLACEHOLDER_BYTES = 64 * 1024;
|
|
7079
7302
|
var CLAUDE_PACKAGE = "@anthropic-ai/claude-code";
|
|
7080
7303
|
var MISSING_BINARY_MARKER = "claude native binary not installed";
|
|
@@ -7101,11 +7324,11 @@ function getPlatformKey() {
|
|
|
7101
7324
|
}
|
|
7102
7325
|
function inspectNativePackage(binaryPath) {
|
|
7103
7326
|
const packageRoot2 = dirname4(dirname4(binaryPath));
|
|
7104
|
-
const packageJsonPath =
|
|
7105
|
-
const installScriptPath =
|
|
7327
|
+
const packageJsonPath = join7(packageRoot2, "package.json");
|
|
7328
|
+
const installScriptPath = join7(packageRoot2, "install.cjs");
|
|
7106
7329
|
let manifest;
|
|
7107
7330
|
try {
|
|
7108
|
-
manifest = JSON.parse(
|
|
7331
|
+
manifest = JSON.parse(readFileSync9(packageJsonPath, "utf8"));
|
|
7109
7332
|
if (manifest.name !== CLAUDE_PACKAGE || !statSync5(installScriptPath).isFile()) {
|
|
7110
7333
|
return { nativePackageState: "unknown", installScriptPath: null };
|
|
7111
7334
|
}
|
|
@@ -7159,7 +7382,7 @@ function inspectClaudeNativeBinaryPlaceholder(path) {
|
|
|
7159
7382
|
|
|
7160
7383
|
// src/bun-entry-module.ts
|
|
7161
7384
|
import { closeSync as closeSync3, openSync as openSync3, readSync as readSync2, statSync as statSync6, writeSync } from "fs";
|
|
7162
|
-
import { execFileSync } from "child_process";
|
|
7385
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
7163
7386
|
var BUN_TRAILER = Buffer.from("\n---- Bun! ----\n");
|
|
7164
7387
|
var BUN_OFFSETS_BYTES = 32;
|
|
7165
7388
|
var TAIL_SCAN_BYTES = 16 * 1024 * 1024;
|
|
@@ -7415,7 +7638,7 @@ function resignMachOBinary(path) {
|
|
|
7415
7638
|
closeSync3(fd);
|
|
7416
7639
|
}
|
|
7417
7640
|
if (machO && process.platform === "darwin") {
|
|
7418
|
-
|
|
7641
|
+
execFileSync2("codesign", ["-s", "-", "-f", path], { stdio: "ignore" });
|
|
7419
7642
|
}
|
|
7420
7643
|
}
|
|
7421
7644
|
|
|
@@ -11705,7 +11928,7 @@ function withThousands2(value) {
|
|
|
11705
11928
|
return value.toLocaleString("en-US");
|
|
11706
11929
|
}
|
|
11707
11930
|
function formatPricingBoundaryWarning(modelLabel, boundary, inputTokens) {
|
|
11708
|
-
return `clodex: ${modelLabel} request counted ${withThousands2(inputTokens)} input tokens, above the ${withThousands2(boundary)}-token pricing boundary. The provider prices the full request at a higher rate above this point.
|
|
11931
|
+
return `clodex: ${modelLabel} request counted ${withThousands2(inputTokens)} input tokens, above the ${withThousands2(boundary)}-token pricing boundary. The provider prices the full request at a higher rate above this point. Choose a smaller context stop to reduce the chance of higher-rate requests.`;
|
|
11709
11932
|
}
|
|
11710
11933
|
function reportPricingBoundaryCrossing(observation, emit = emitParentNotice) {
|
|
11711
11934
|
const { modelKey, modelLabel, pricingBoundary, inputTokens } = observation;
|
|
@@ -12515,15 +12738,10 @@ function annotateToolNames(messages) {
|
|
|
12515
12738
|
}
|
|
12516
12739
|
}
|
|
12517
12740
|
function thinkingToSdkPart(block, npm) {
|
|
12518
|
-
|
|
12519
|
-
|
|
12520
|
-
|
|
12521
|
-
|
|
12522
|
-
if (npm === "@ai-sdk/google") {
|
|
12523
|
-
part.providerOptions = { google: { thoughtSignature: block.signature } };
|
|
12524
|
-
} else if (npm === "@ai-sdk/openai" || npm === "@ai-sdk/openai-compatible") {
|
|
12525
|
-
part.providerOptions = { openai: { reasoningEncryptedContent: block.signature } };
|
|
12526
|
-
}
|
|
12741
|
+
if (npm === "@ai-sdk/openai") return null;
|
|
12742
|
+
const part = { type: "reasoning", text: block.thinking ?? "" };
|
|
12743
|
+
if (block.signature && npm === "@ai-sdk/google") {
|
|
12744
|
+
part.providerOptions = { google: { thoughtSignature: block.signature } };
|
|
12527
12745
|
}
|
|
12528
12746
|
return part;
|
|
12529
12747
|
}
|
|
@@ -14062,7 +14280,7 @@ function buildHttpProxyRoutes(providers, favorites, modelAliases = void 0, max =
|
|
|
14062
14280
|
|
|
14063
14281
|
// src/patcher.ts
|
|
14064
14282
|
function getPatchLockPath() {
|
|
14065
|
-
return
|
|
14283
|
+
return join8(getAppHome(), "patch.lock");
|
|
14066
14284
|
}
|
|
14067
14285
|
function writePatchManifest(manifest, path = getPatchManifestPath()) {
|
|
14068
14286
|
mkdirSync5(getAppHome(), { recursive: true, mode: 448 });
|
|
@@ -14219,7 +14437,7 @@ function pidIsAlive(pid) {
|
|
|
14219
14437
|
function tryAcquirePatchLock(lockPath = getPatchLockPath(), opts = {}) {
|
|
14220
14438
|
const now = opts.now ?? Date.now();
|
|
14221
14439
|
const isAlive = opts.isAlive ?? pidIsAlive;
|
|
14222
|
-
mkdirSync5(
|
|
14440
|
+
mkdirSync5(join8(lockPath, ".."), { recursive: true, mode: 448 });
|
|
14223
14441
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
14224
14442
|
try {
|
|
14225
14443
|
const fd = openSync8(lockPath, "wx");
|
|
@@ -14235,7 +14453,7 @@ function tryAcquirePatchLock(lockPath = getPatchLockPath(), opts = {}) {
|
|
|
14235
14453
|
} catch {
|
|
14236
14454
|
let stale = false;
|
|
14237
14455
|
try {
|
|
14238
|
-
const existing = JSON.parse(
|
|
14456
|
+
const existing = JSON.parse(readFileSync10(lockPath, "utf8"));
|
|
14239
14457
|
stale = !existing.pid || !isAlive(existing.pid) || typeof existing.startedAt === "number" && now - existing.startedAt > PATCH_LOCK_STALE_MS;
|
|
14240
14458
|
} catch {
|
|
14241
14459
|
stale = true;
|
|
@@ -14257,7 +14475,7 @@ function takeIgnoredLaunchOverride() {
|
|
|
14257
14475
|
}
|
|
14258
14476
|
function resolveClaudeBinaryForPatch() {
|
|
14259
14477
|
const envOverride = process.env["TWEAKCC_CC_INSTALLATION_PATH"]?.trim() || null;
|
|
14260
|
-
const nativeSymlink =
|
|
14478
|
+
const nativeSymlink = join8(homedir3(), ".local", "bin", "claude");
|
|
14261
14479
|
if (envOverride && !existsSync4(envOverride)) {
|
|
14262
14480
|
return { ok: false, reason: "patch-target-missing", declaredPath: envOverride };
|
|
14263
14481
|
}
|
|
@@ -14265,7 +14483,7 @@ function resolveClaudeBinaryForPatch() {
|
|
|
14265
14483
|
if (!source) return { ok: false, reason: "binary-not-found" };
|
|
14266
14484
|
let resolved;
|
|
14267
14485
|
try {
|
|
14268
|
-
resolved =
|
|
14486
|
+
resolved = realpathSync3(source);
|
|
14269
14487
|
} catch {
|
|
14270
14488
|
return { ok: false, reason: "binary-not-found" };
|
|
14271
14489
|
}
|
|
@@ -14285,8 +14503,8 @@ function resolveClaudeBinaryForPatch() {
|
|
|
14285
14503
|
let launchOverrideResolved = null;
|
|
14286
14504
|
if (launchOverride) {
|
|
14287
14505
|
try {
|
|
14288
|
-
const followedOverride = resolveThroughNpmShims(
|
|
14289
|
-
launchOverrideResolved = followedOverride.ok ? followedOverride.path :
|
|
14506
|
+
const followedOverride = resolveThroughNpmShims(realpathSync3(launchOverride));
|
|
14507
|
+
launchOverrideResolved = followedOverride.ok ? followedOverride.path : realpathSync3(launchOverride);
|
|
14290
14508
|
} catch {
|
|
14291
14509
|
launchOverrideResolved = launchOverride;
|
|
14292
14510
|
}
|
|
@@ -14425,8 +14643,8 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14425
14643
|
try {
|
|
14426
14644
|
mkdirSync5(backupDir(), { recursive: true });
|
|
14427
14645
|
const { tryDetectInstallation, readContent, writeContent } = await import("tweakcc");
|
|
14428
|
-
candidateDir = mkdtempSync(
|
|
14429
|
-
const candidatePath =
|
|
14646
|
+
candidateDir = mkdtempSync(join8(dirname5(binaryPath), ".clodex-patch-"));
|
|
14647
|
+
const candidatePath = join8(candidateDir, basename(binaryPath));
|
|
14430
14648
|
const seedCandidate = async (from) => {
|
|
14431
14649
|
copyFileSync(from, candidatePath);
|
|
14432
14650
|
const shim = shimEntryModuleName(candidatePath);
|
|
@@ -14713,6 +14931,9 @@ function runRestoreCommand(target) {
|
|
|
14713
14931
|
p2.log.success(`Restored pristine claude ${version} from ${plan.backupPath}.`);
|
|
14714
14932
|
return 0;
|
|
14715
14933
|
}
|
|
14934
|
+
function warnOnEditorExtensionDrift(binaryPath, version) {
|
|
14935
|
+
for (const warning of claudeExtensionDriftWarnings({ binaryPath, version })) p2.log.warn(warning);
|
|
14936
|
+
}
|
|
14716
14937
|
async function runPatchCommand(opts = {}) {
|
|
14717
14938
|
const target = resolveClaudeBinaryForPatch();
|
|
14718
14939
|
const ignoredOverride = takeIgnoredLaunchOverride();
|
|
@@ -14758,6 +14979,7 @@ async function runPatchCommand(opts = {}) {
|
|
|
14758
14979
|
});
|
|
14759
14980
|
if (state === "current") {
|
|
14760
14981
|
p2.log.success(`claude ${version} is already patched with the current model config \u2014 nothing to do.`);
|
|
14982
|
+
warnOnEditorExtensionDrift(binaryPath, version);
|
|
14761
14983
|
return 0;
|
|
14762
14984
|
}
|
|
14763
14985
|
const release = tryAcquirePatchLock();
|
|
@@ -14793,6 +15015,7 @@ async function runPatchCommand(opts = {}) {
|
|
|
14793
15015
|
if (!opts.trace) {
|
|
14794
15016
|
for (const line of outcome.detailLines ?? []) p2.log.info(pc3.dim(line));
|
|
14795
15017
|
}
|
|
15018
|
+
warnOnEditorExtensionDrift(binaryPath, version);
|
|
14796
15019
|
return 0;
|
|
14797
15020
|
} finally {
|
|
14798
15021
|
release();
|
|
@@ -15166,7 +15389,7 @@ import {
|
|
|
15166
15389
|
lstatSync,
|
|
15167
15390
|
mkdirSync as mkdirSync6,
|
|
15168
15391
|
openSync as openSync9,
|
|
15169
|
-
readFileSync as
|
|
15392
|
+
readFileSync as readFileSync11,
|
|
15170
15393
|
renameSync as renameSync3,
|
|
15171
15394
|
unlinkSync as unlinkSync4,
|
|
15172
15395
|
writeFileSync as writeFileSync6
|
|
@@ -15273,7 +15496,7 @@ function readJournalUnlocked(path) {
|
|
|
15273
15496
|
if (opened.size > MAX_JOURNAL_BYTES) {
|
|
15274
15497
|
throw new Error("Credential cleanup journal is too large.");
|
|
15275
15498
|
}
|
|
15276
|
-
return parseJournal(JSON.parse(
|
|
15499
|
+
return parseJournal(JSON.parse(readFileSync11(fd, "utf8")));
|
|
15277
15500
|
} catch (error) {
|
|
15278
15501
|
const message = error instanceof Error ? error.message : String(error);
|
|
15279
15502
|
throw new Error(`Could not read credential cleanup journal: ${message}`);
|
|
@@ -16340,7 +16563,8 @@ function readCapabilityFlags(m) {
|
|
|
16340
16563
|
const bool = (v) => typeof v === "boolean" ? v : void 0;
|
|
16341
16564
|
return {
|
|
16342
16565
|
useResponsesLite: bool(m["use_responses_lite"]),
|
|
16343
|
-
preferWebSockets: bool(m["prefer_websockets"])
|
|
16566
|
+
preferWebSockets: bool(m["prefer_websockets"]),
|
|
16567
|
+
minimalClientVersion: readCodexClientVersion(m["minimal_client_version"])
|
|
16344
16568
|
};
|
|
16345
16569
|
}
|
|
16346
16570
|
function parseOpenAiModelEntries(body) {
|
|
@@ -16377,7 +16601,8 @@ function buildDynamicOAuthModel(entry, seedById, codexCatalog) {
|
|
|
16377
16601
|
effectiveContextPercent: entry.effective_context_window_percent ?? seed.effectiveContextPercent,
|
|
16378
16602
|
maxOutputTokens: entry.max_output_tokens ?? seed.maxOutputTokens,
|
|
16379
16603
|
useResponsesLite: entry.useResponsesLite ?? seed.useResponsesLite,
|
|
16380
|
-
preferWebSockets: entry.preferWebSockets ?? seed.preferWebSockets
|
|
16604
|
+
preferWebSockets: entry.preferWebSockets ?? seed.preferWebSockets,
|
|
16605
|
+
minimalClientVersion: entry.minimalClientVersion ?? seed.minimalClientVersion
|
|
16381
16606
|
};
|
|
16382
16607
|
}
|
|
16383
16608
|
const { id } = entry;
|
|
@@ -16412,7 +16637,8 @@ function buildDynamicOAuthModel(entry, seedById, codexCatalog) {
|
|
|
16412
16637
|
// so a wrong `true` here costs an unusable menu entry, not a 400.
|
|
16413
16638
|
reasoning: codexCatalog ? true : modelPrefersResponsesApi(id),
|
|
16414
16639
|
useResponsesLite: entry.useResponsesLite,
|
|
16415
|
-
preferWebSockets: entry.preferWebSockets
|
|
16640
|
+
preferWebSockets: entry.preferWebSockets,
|
|
16641
|
+
minimalClientVersion: entry.minimalClientVersion
|
|
16416
16642
|
};
|
|
16417
16643
|
}
|
|
16418
16644
|
async function fetchJsonWithAuth(url, accessToken, timeoutMs) {
|
|
@@ -16473,6 +16699,10 @@ async function refreshOpenAiOAuthModels(accessToken) {
|
|
|
16473
16699
|
credentialRejected: credentialFailure !== void 0
|
|
16474
16700
|
};
|
|
16475
16701
|
}
|
|
16702
|
+
function warningSuffix(models) {
|
|
16703
|
+
const warning = codexClientVersionWarning(applyOAuthSeedContextMetadata(models));
|
|
16704
|
+
return warning ? ` ${warning}` : "";
|
|
16705
|
+
}
|
|
16476
16706
|
async function refreshApiListProvider(provider, apiKey) {
|
|
16477
16707
|
const npm = provider.api.npm ?? "@ai-sdk/openai-compatible";
|
|
16478
16708
|
const retained = isRetainedOpenCodeGoProvider(provider);
|
|
@@ -16682,7 +16912,7 @@ async function refreshProviderModels(providerId, apiKey, registry, credentialSna
|
|
|
16682
16912
|
if (oauthResult.source === "seed" && cachedModelCount(cacheProvider) > 0) {
|
|
16683
16913
|
return skipWithCachedModels(
|
|
16684
16914
|
cacheProvider,
|
|
16685
|
-
`Live model discovery failed${failureDetail} \u2014 kept your existing cached model list instead of overwriting it with clodex's built-in fallback list. Try refreshing again later.`
|
|
16915
|
+
`Live model discovery failed${failureDetail} \u2014 kept your existing cached model list instead of overwriting it with clodex's built-in fallback list. Try refreshing again later.` + warningSuffix(cacheProvider.modelsCache.models)
|
|
16686
16916
|
);
|
|
16687
16917
|
}
|
|
16688
16918
|
if (oauthResult.source === "seed") {
|
|
@@ -16776,7 +17006,7 @@ async function refreshProviderModels(providerId, apiKey, registry, credentialSna
|
|
|
16776
17006
|
ok: true,
|
|
16777
17007
|
modelCount: enriched.length,
|
|
16778
17008
|
previousModelCount: hadPreviousRefresh ? previousModelCount : void 0,
|
|
16779
|
-
reason: oauthFallbackReason
|
|
17009
|
+
reason: isChatGptOAuthProvider(provider) ? [oauthFallbackReason, codexClientVersionWarning(models)].filter(Boolean).join(" ") || void 0 : void 0
|
|
16780
17010
|
};
|
|
16781
17011
|
} catch (err) {
|
|
16782
17012
|
return {
|
|
@@ -17133,6 +17363,7 @@ async function authenticateProvider(providerId, options = {}) {
|
|
|
17133
17363
|
refreshSpinner.stop(`Models not refreshed${refreshResult.reason ? ` \u2014 ${refreshResult.reason}` : ""}`);
|
|
17134
17364
|
} else if (refreshResult.ok) {
|
|
17135
17365
|
refreshSpinner.stop("Models refreshed");
|
|
17366
|
+
if (refreshResult.reason) p4.log.warn(refreshResult.reason);
|
|
17136
17367
|
} else {
|
|
17137
17368
|
refreshSpinner.stop(`Could not refresh models${refreshResult.reason ? ` \u2014 ${refreshResult.reason}` : ""}`);
|
|
17138
17369
|
}
|
|
@@ -18812,7 +19043,7 @@ async function routeRequest(req, res, options, modelCache, plog) {
|
|
|
18812
19043
|
}
|
|
18813
19044
|
async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
18814
19045
|
const clientAbort = watchClientDisconnect(res);
|
|
18815
|
-
const body = await
|
|
19046
|
+
const body = await readJson2(req);
|
|
18816
19047
|
if (!body) {
|
|
18817
19048
|
sendJson(res, 400, { error: { message: "Invalid JSON body" } });
|
|
18818
19049
|
return;
|
|
@@ -19082,7 +19313,7 @@ data: ${JSON.stringify({
|
|
|
19082
19313
|
}
|
|
19083
19314
|
async function handleAnthropicCountTokens(req, res, options, plog) {
|
|
19084
19315
|
const clientAbort = watchClientDisconnect(res);
|
|
19085
|
-
const body = await
|
|
19316
|
+
const body = await readJson2(req);
|
|
19086
19317
|
if (!body) {
|
|
19087
19318
|
sendJson(res, 400, { error: { message: "Invalid JSON body" } });
|
|
19088
19319
|
return;
|
|
@@ -19151,7 +19382,7 @@ async function handleAnthropicCountTokens(req, res, options, plog) {
|
|
|
19151
19382
|
}
|
|
19152
19383
|
async function handleOpenAIChatCompletions(req, res, options, modelCache, plog) {
|
|
19153
19384
|
const clientAbort = watchClientDisconnect(res);
|
|
19154
|
-
const body = await
|
|
19385
|
+
const body = await readJson2(req);
|
|
19155
19386
|
if (!body) {
|
|
19156
19387
|
sendJson(res, 400, { error: { message: "Invalid JSON body" } });
|
|
19157
19388
|
return;
|
|
@@ -19358,7 +19589,7 @@ function getResponseModelId(bodyModel, model, options) {
|
|
|
19358
19589
|
if (typeof bodyModel === "string" && options.aliasNames?.has(bodyModel)) return bodyModel;
|
|
19359
19590
|
return options.gateway?.maskGatewayIds ? gatewayDisplayName(model, options.gateway) : typeof bodyModel === "string" ? bodyModel : model.id;
|
|
19360
19591
|
}
|
|
19361
|
-
async function
|
|
19592
|
+
async function readJson2(req) {
|
|
19362
19593
|
try {
|
|
19363
19594
|
const raw = await readBody(req);
|
|
19364
19595
|
return raw ? JSON.parse(raw) : {};
|
|
@@ -19502,8 +19733,8 @@ import { createBrotliDecompress, createGunzip, createInflate } from "zlib";
|
|
|
19502
19733
|
|
|
19503
19734
|
// src/http-proxy/ca.ts
|
|
19504
19735
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
19505
|
-
import { chmodSync as chmodSync5, existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as
|
|
19506
|
-
import { dirname as dirname7, join as
|
|
19736
|
+
import { chmodSync as chmodSync5, existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
|
|
19737
|
+
import { dirname as dirname7, join as join9, resolve as resolve3 } from "path";
|
|
19507
19738
|
import forge from "node-forge";
|
|
19508
19739
|
var CERT_DIR = "http-proxy";
|
|
19509
19740
|
var CA_CERT_FILE = "clodex-ca.pem";
|
|
@@ -19518,14 +19749,14 @@ function serialNumber() {
|
|
|
19518
19749
|
return bytes.toString("hex");
|
|
19519
19750
|
}
|
|
19520
19751
|
function certPaths() {
|
|
19521
|
-
const dir =
|
|
19752
|
+
const dir = join9(getAppHome(), CERT_DIR);
|
|
19522
19753
|
return {
|
|
19523
19754
|
dir,
|
|
19524
|
-
caCert:
|
|
19525
|
-
caKey:
|
|
19526
|
-
serverCert:
|
|
19527
|
-
serverKey:
|
|
19528
|
-
version:
|
|
19755
|
+
caCert: join9(dir, CA_CERT_FILE),
|
|
19756
|
+
caKey: join9(dir, CA_KEY_FILE),
|
|
19757
|
+
serverCert: join9(dir, SERVER_CERT_FILE),
|
|
19758
|
+
serverKey: join9(dir, SERVER_KEY_FILE),
|
|
19759
|
+
version: join9(dir, CERT_VERSION_FILE)
|
|
19529
19760
|
};
|
|
19530
19761
|
}
|
|
19531
19762
|
function writePrivate(path, value) {
|
|
@@ -19578,8 +19809,8 @@ function generateCertificates(paths) {
|
|
|
19578
19809
|
}
|
|
19579
19810
|
function storedCertificatesAreCurrent(paths) {
|
|
19580
19811
|
try {
|
|
19581
|
-
const ca = forge.pki.certificateFromPem(
|
|
19582
|
-
const server = forge.pki.certificateFromPem(
|
|
19812
|
+
const ca = forge.pki.certificateFromPem(readFileSync12(paths.caCert, "utf8"));
|
|
19813
|
+
const server = forge.pki.certificateFromPem(readFileSync12(paths.serverCert, "utf8"));
|
|
19583
19814
|
const now = Date.now();
|
|
19584
19815
|
const renewalBuffer = 7 * 24 * 60 * 60 * 1e3;
|
|
19585
19816
|
return ca.validity.notBefore.getTime() <= now && ca.validity.notAfter.getTime() > now + renewalBuffer && server.validity.notBefore.getTime() <= now && server.validity.notAfter.getTime() > now + renewalBuffer && ca.verify(ca) && ca.verify(server);
|
|
@@ -19590,13 +19821,13 @@ function storedCertificatesAreCurrent(paths) {
|
|
|
19590
19821
|
function ensureHttpProxyCertificates() {
|
|
19591
19822
|
const paths = certPaths();
|
|
19592
19823
|
const required = [paths.caCert, paths.caKey, paths.serverCert, paths.serverKey, paths.version];
|
|
19593
|
-
const current = required.every(existsSync6) &&
|
|
19824
|
+
const current = required.every(existsSync6) && readFileSync12(paths.version, "utf8") === CERT_VERSION && storedCertificatesAreCurrent(paths);
|
|
19594
19825
|
if (!current) generateCertificates(paths);
|
|
19595
19826
|
return {
|
|
19596
19827
|
caCertPath: paths.caCert,
|
|
19597
|
-
caCert:
|
|
19598
|
-
serverCert:
|
|
19599
|
-
serverKey:
|
|
19828
|
+
caCert: readFileSync12(paths.caCert, "utf8"),
|
|
19829
|
+
serverCert: readFileSync12(paths.serverCert, "utf8"),
|
|
19830
|
+
serverKey: readFileSync12(paths.serverKey, "utf8")
|
|
19600
19831
|
};
|
|
19601
19832
|
}
|
|
19602
19833
|
function ensureHttpProxyCaBundle(relayCaCertPath, additionalCaCertPath, onWarning) {
|
|
@@ -19610,7 +19841,7 @@ function ensureHttpProxyCaBundle(relayCaCertPath, additionalCaCertPath, onWarnin
|
|
|
19610
19841
|
let additionalCa;
|
|
19611
19842
|
try {
|
|
19612
19843
|
if (resolve3(additionalCaCertPath) === resolve3(relayCaCertPath)) return relayCaCertPath;
|
|
19613
|
-
additionalCa =
|
|
19844
|
+
additionalCa = readFileSync12(additionalCaCertPath, "utf8").trim();
|
|
19614
19845
|
} catch (err) {
|
|
19615
19846
|
return warn(
|
|
19616
19847
|
`NODE_EXTRA_CA_CERTS=${additionalCaCertPath} cannot be read (${err instanceof Error ? err.message : String(err)}), so it is not part of the proxy CA bundle. Where node reports this itself it says only "Ignoring extra certs ... load failed", without naming the variable. Clear or correct it.`
|
|
@@ -19620,8 +19851,8 @@ function ensureHttpProxyCaBundle(relayCaCertPath, additionalCaCertPath, onWarnin
|
|
|
19620
19851
|
return warn(`NODE_EXTRA_CA_CERTS=${additionalCaCertPath} is empty, so it adds nothing.`);
|
|
19621
19852
|
}
|
|
19622
19853
|
try {
|
|
19623
|
-
const relayCa =
|
|
19624
|
-
const combinedPath =
|
|
19854
|
+
const relayCa = readFileSync12(relayCaCertPath, "utf8").trimEnd();
|
|
19855
|
+
const combinedPath = join9(dirname7(relayCaCertPath), "combined-ca.pem");
|
|
19625
19856
|
writePublic(combinedPath, `${relayCa}
|
|
19626
19857
|
${additionalCa}
|
|
19627
19858
|
`);
|
|
@@ -21502,9 +21733,9 @@ function planLaunchWizard(opts) {
|
|
|
21502
21733
|
|
|
21503
21734
|
// src/vscode-launcher.ts
|
|
21504
21735
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
21505
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync2, readdirSync, readFileSync as
|
|
21506
|
-
import { tmpdir } from "os";
|
|
21507
|
-
import { dirname as dirname8, join as
|
|
21736
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync2, readdirSync as readdirSync2, readFileSync as readFileSync13, rmSync as rmSync2, statSync as statSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
21737
|
+
import { homedir as homedir4, tmpdir } from "os";
|
|
21738
|
+
import { dirname as dirname8, join as join10 } from "path";
|
|
21508
21739
|
import { fileURLToPath } from "url";
|
|
21509
21740
|
var LAUNCHER_EXE_NAME = "clodex-claude.exe";
|
|
21510
21741
|
var VSCODE_WRAPPER_SETTING = "claudeCode.claudeProcessWrapper";
|
|
@@ -21513,15 +21744,15 @@ var WRAPPER_PATH_PLACEHOLDER = '"__CLODEX_WRAPPER_SCRIPT_PATH__"';
|
|
|
21513
21744
|
var LAUNCHER_SOURCE_FILE = "clodex-claude-launcher.cs";
|
|
21514
21745
|
var UTF8_BOM = "\uFEFF";
|
|
21515
21746
|
var CSC_ARGS = ["/nologo", "/target:exe", "/platform:anycpu", "/optimize+", `/out:${LAUNCHER_EXE_NAME}`, LAUNCHER_SOURCE_FILE];
|
|
21516
|
-
var packageRoot =
|
|
21747
|
+
var packageRoot = join10(dirname8(fileURLToPath(import.meta.url)), "..");
|
|
21517
21748
|
function defaultLauncherInputs() {
|
|
21518
21749
|
return {
|
|
21519
|
-
launcherSourcePath:
|
|
21520
|
-
wrapperScriptPath:
|
|
21750
|
+
launcherSourcePath: join10(packageRoot, "launcher", LAUNCHER_SOURCE_FILE),
|
|
21751
|
+
wrapperScriptPath: join10(packageRoot, "dist", "claude-wrapper.js")
|
|
21521
21752
|
};
|
|
21522
21753
|
}
|
|
21523
21754
|
function launcherInstallPath(env = process.env) {
|
|
21524
|
-
return
|
|
21755
|
+
return join10(getAppHome(env), "bin", LAUNCHER_EXE_NAME);
|
|
21525
21756
|
}
|
|
21526
21757
|
function csharpStringLiteral(value) {
|
|
21527
21758
|
let literal = '"';
|
|
@@ -21547,30 +21778,23 @@ function renderLauncherSource(template, paths) {
|
|
|
21547
21778
|
}
|
|
21548
21779
|
function cscSearchRoots(env = process.env) {
|
|
21549
21780
|
const windir = env.WINDIR?.trim() || env.SystemRoot?.trim() || "C:\\Windows";
|
|
21550
|
-
const dotnet =
|
|
21551
|
-
return [
|
|
21781
|
+
const dotnet = join10(windir, "Microsoft.NET");
|
|
21782
|
+
return [join10(dotnet, "Framework64"), join10(dotnet, "Framework")];
|
|
21552
21783
|
}
|
|
21553
21784
|
function frameworkVersionKey(name) {
|
|
21554
21785
|
return name.slice(1).split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
21555
21786
|
}
|
|
21556
|
-
function compareVersionKeys(a, b) {
|
|
21557
|
-
for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
|
|
21558
|
-
const diff = (a[i] ?? 0) - (b[i] ?? 0);
|
|
21559
|
-
if (diff !== 0) return diff;
|
|
21560
|
-
}
|
|
21561
|
-
return 0;
|
|
21562
|
-
}
|
|
21563
21787
|
function findCsc(env = process.env) {
|
|
21564
21788
|
for (const root of cscSearchRoots(env)) {
|
|
21565
21789
|
let entries;
|
|
21566
21790
|
try {
|
|
21567
|
-
entries =
|
|
21791
|
+
entries = readdirSync2(root);
|
|
21568
21792
|
} catch {
|
|
21569
21793
|
continue;
|
|
21570
21794
|
}
|
|
21571
21795
|
const candidates = entries.filter((name) => /^v4\.\d+(\.\d+)*$/i.test(name)).sort((a, b) => compareVersionKeys(frameworkVersionKey(b), frameworkVersionKey(a)));
|
|
21572
21796
|
for (const version of candidates) {
|
|
21573
|
-
const csc =
|
|
21797
|
+
const csc = join10(root, version, "csc.exe");
|
|
21574
21798
|
try {
|
|
21575
21799
|
if (statSync8(csc).isFile()) return csc;
|
|
21576
21800
|
} catch {
|
|
@@ -21629,7 +21853,7 @@ function installVscodeLauncher(opts = {}) {
|
|
|
21629
21853
|
}
|
|
21630
21854
|
let source;
|
|
21631
21855
|
try {
|
|
21632
|
-
source = renderLauncherSource(
|
|
21856
|
+
source = renderLauncherSource(readFileSync13(launcherSourcePath, "utf8"), { nodePath, wrapperScriptPath });
|
|
21633
21857
|
} catch (err) {
|
|
21634
21858
|
return { ok: false, reason: "missing-input", message: `could not prepare the launcher source: ${describeError(err)}` };
|
|
21635
21859
|
}
|
|
@@ -21637,7 +21861,7 @@ function installVscodeLauncher(opts = {}) {
|
|
|
21637
21861
|
const tempRoot = opts.tempRoot ?? tmpdir();
|
|
21638
21862
|
let scratch;
|
|
21639
21863
|
try {
|
|
21640
|
-
scratch = mkdtempSync2(
|
|
21864
|
+
scratch = mkdtempSync2(join10(tempRoot, "clodex-vscode-launcher-"));
|
|
21641
21865
|
} catch (err) {
|
|
21642
21866
|
return { ok: false, reason: "install-failed", message: `could not create a scratch directory under ${tempRoot}: ${describeError(err)}` };
|
|
21643
21867
|
}
|
|
@@ -21652,9 +21876,9 @@ function installVscodeLauncher(opts = {}) {
|
|
|
21652
21876
|
}
|
|
21653
21877
|
function buildAndPublish(step) {
|
|
21654
21878
|
const { scratch, cscPath, exePath } = step;
|
|
21655
|
-
writeFileSync8(
|
|
21879
|
+
writeFileSync8(join10(scratch, LAUNCHER_SOURCE_FILE), UTF8_BOM + step.source, "utf8");
|
|
21656
21880
|
const compiled = step.compile(cscPath, CSC_ARGS, scratch);
|
|
21657
|
-
const builtExe =
|
|
21881
|
+
const builtExe = join10(scratch, LAUNCHER_EXE_NAME);
|
|
21658
21882
|
if (compiled.error || compiled.status !== 0 || !existsSync7(builtExe)) {
|
|
21659
21883
|
const output = [compiled.stdout, compiled.stderr].map((text6) => text6.trim()).filter(Boolean).join("\n");
|
|
21660
21884
|
return {
|
|
@@ -21709,16 +21933,27 @@ function successReport(result) {
|
|
|
21709
21933
|
"install: the paths above are compiled into the executable."
|
|
21710
21934
|
];
|
|
21711
21935
|
}
|
|
21936
|
+
function launcherExtensionDriftWarnings(opts = {}) {
|
|
21937
|
+
const env = opts.env ?? process.env;
|
|
21938
|
+
const manifest = readPatchManifest(getPatchManifestPath(env));
|
|
21939
|
+
if (!manifest || typeof manifest.claudeVersion !== "string") return [];
|
|
21940
|
+
return claudeExtensionDriftWarnings(
|
|
21941
|
+
{ binaryPath: manifest.binaryPath, version: manifest.claudeVersion },
|
|
21942
|
+
opts.homeDir ?? homedir4(),
|
|
21943
|
+
() => readNpmGlobalRoot(env)
|
|
21944
|
+
);
|
|
21945
|
+
}
|
|
21712
21946
|
function runInstallVscodeLauncherCommand(opts = {}) {
|
|
21713
21947
|
const result = installVscodeLauncher(opts);
|
|
21714
21948
|
if (result.warning) console.error(`clodex: warning: ${result.warning}`);
|
|
21715
21949
|
if (!result.ok) {
|
|
21716
21950
|
console.error(`clodex: ${result.message}`);
|
|
21717
21951
|
if (result.detail) console.error(result.detail);
|
|
21718
|
-
|
|
21952
|
+
} else {
|
|
21953
|
+
console.log(successReport(result).join("\n"));
|
|
21719
21954
|
}
|
|
21720
|
-
|
|
21721
|
-
return 0;
|
|
21955
|
+
for (const drift of launcherExtensionDriftWarnings(opts)) console.error(`clodex: warning: ${drift}`);
|
|
21956
|
+
return result.ok ? 0 : 1;
|
|
21722
21957
|
}
|
|
21723
21958
|
|
|
21724
21959
|
// src/cli.ts
|
|
@@ -22052,8 +22287,10 @@ ${pc13.bold("Options:")}
|
|
|
22052
22287
|
--trace Write debug logs to ~/.clodex/logs/ and show errors on exit
|
|
22053
22288
|
--fast Request Codex fast mode (service_tier=priority) on ChatGPT-OAuth models
|
|
22054
22289
|
(equivalent to CLODEX_SERVICE_TIER=fast; warns if the SDK omits it)
|
|
22055
|
-
--provider
|
|
22056
|
-
|
|
22290
|
+
--provider Endpoint mode only: boot provider id (skip wizard when paired with
|
|
22291
|
+
--model or in print mode)
|
|
22292
|
+
--model Endpoint mode only: boot model id (skip wizard when paired with
|
|
22293
|
+
--provider or in print mode)
|
|
22057
22294
|
--context <model=stop> use a different share of a model's window for this
|
|
22058
22295
|
launch only (standard, max, default, or a token count). Nothing is
|
|
22059
22296
|
saved. It reaches Claude Code through the exported catalog, so a
|
|
@@ -22094,7 +22331,7 @@ ${pc13.bold("Examples:")}
|
|
|
22094
22331
|
clodex claude --trace --resume abc-123
|
|
22095
22332
|
clodex claude --endpoint
|
|
22096
22333
|
clodex claude --endpoint --save-mode
|
|
22097
|
-
clodex claude --provider openai-oauth --model gpt-6-sol
|
|
22334
|
+
clodex claude --endpoint --provider openai-oauth --model gpt-6-sol
|
|
22098
22335
|
clodex claude -- --print "hello"
|
|
22099
22336
|
clodex claude -- --dangerously-skip-permissions`;
|
|
22100
22337
|
}
|
|
@@ -22216,8 +22453,11 @@ ${pc13.bold("How it works:")}
|
|
|
22216
22453
|
|
|
22217
22454
|
${pc13.bold("Context stops and cost:")}
|
|
22218
22455
|
Some providers price large prompts in bands: GPT-5.6 and GPT-6 bill the full request at
|
|
22219
|
-
a higher rate above 272,000 input tokens.
|
|
22220
|
-
|
|
22456
|
+
a higher rate above 272,000 input tokens. For ChatGPT/Codex-plan models whose
|
|
22457
|
+
catalog reports a 272,000-token window, standard stays at that line and a
|
|
22458
|
+
larger window is opt-in. OpenAI API-key models retain their full window, so
|
|
22459
|
+
standard may already cross the boundary. Choose a smaller numeric stop such
|
|
22460
|
+
as 250k to limit exposure to the higher rate.
|
|
22221
22461
|
|
|
22222
22462
|
${pc13.bold("Examples:")}
|
|
22223
22463
|
clodex favorites
|
|
@@ -22254,7 +22494,13 @@ ${pc13.bold("Behavior:")}
|
|
|
22254
22494
|
Local patches execute after the built-ins as an all-or-none set. Enabling
|
|
22255
22495
|
them executes trusted JavaScript from local-patches.mjs with your full user
|
|
22256
22496
|
permissions. Local failures are reported but never block the built-ins.
|
|
22257
|
-
Run clodex patch again after every claude update
|
|
22497
|
+
Run clodex patch again after every claude update.
|
|
22498
|
+
|
|
22499
|
+
An editor launching Claude Code through clodex-claude runs this patched
|
|
22500
|
+
install only when its Claude Code extension is the same build. When an
|
|
22501
|
+
installed extension is a different version, clodex patch warns and prints the
|
|
22502
|
+
commands that align them. Editors checked:
|
|
22503
|
+
${CHECKED_EDITORS_DESCRIPTION}`;
|
|
22258
22504
|
}
|
|
22259
22505
|
function installVscodeLauncherHelpText() {
|
|
22260
22506
|
return `${pc13.bold("clodex install-vscode-launcher")} v${VERSION}
|
|
@@ -22284,6 +22530,8 @@ ${pc13.bold("Behavior:")}
|
|
|
22284
22530
|
As on macOS and Linux, clodex-claude then runs your clodex-patched install in
|
|
22285
22531
|
place of the bundled claude.exe when the two builds match, so clodex models
|
|
22286
22532
|
appear in the extension's model picker; re-run clodex patch after updates.
|
|
22533
|
+
Like clodex patch, it warns when an installed Claude Code extension is a
|
|
22534
|
+
different version from the Claude Code clodex last patched.
|
|
22287
22535
|
|
|
22288
22536
|
The paths to node.exe and to the clodex install are compiled in: re-run this
|
|
22289
22537
|
command after switching Node versions or moving the clodex install.
|
|
@@ -23234,7 +23482,7 @@ Error: ${resolved.error}
|
|
|
23234
23482
|
function isCliEntryPoint() {
|
|
23235
23483
|
if (!process.argv[1]) return false;
|
|
23236
23484
|
try {
|
|
23237
|
-
return
|
|
23485
|
+
return realpathSync4(fileURLToPath2(import.meta.url)) === realpathSync4(process.argv[1]);
|
|
23238
23486
|
} catch {
|
|
23239
23487
|
return false;
|
|
23240
23488
|
}
|