@bman654/clodex 2.16.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 +31 -12
- 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 +388 -138
- 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
|
},
|
|
@@ -434,7 +434,7 @@ var package_default = {
|
|
|
434
434
|
|
|
435
435
|
// src/constants.ts
|
|
436
436
|
var CODEX_RESPONSES_LITE_WS_URL = "wss://chatgpt.com/backend-api/codex/responses";
|
|
437
|
-
var CODEX_RESPONSES_LITE_VERSION = "0.
|
|
437
|
+
var CODEX_RESPONSES_LITE_VERSION = "0.156.0";
|
|
438
438
|
var CODEX_RESPONSES_WEBSOCKETS_BETA = "responses_websockets=2026-02-06";
|
|
439
439
|
var TEST_TIMEOUT_MS = 1e4;
|
|
440
440
|
var CONFLICTING_ENV_VARS = [
|
|
@@ -631,6 +631,7 @@ var HEURISTIC_RULES = [
|
|
|
631
631
|
[/claude/i, 2e5],
|
|
632
632
|
[/deepseek-v4|deepseek-r1|deepseek-reasoner/i, 1e6],
|
|
633
633
|
[/deepseek/i, 64e3],
|
|
634
|
+
[/gpt-6-(?:astra|sol|luna)/i, 105e4],
|
|
634
635
|
[/gpt-5|gpt-4\.1|o3-|o4-/i, 1e6],
|
|
635
636
|
[/gpt-4o|gpt-4-turbo|gpt-4/i, 128e3],
|
|
636
637
|
[/gpt-oss/i, 131072],
|
|
@@ -3185,7 +3186,7 @@ function pricingBoundaryWarning(modelLabel, limits, resolved) {
|
|
|
3185
3186
|
const boundary = positiveInteger(limits.pricingBoundary);
|
|
3186
3187
|
if (boundary === void 0 || !resolved.crossesPricingBoundary) return null;
|
|
3187
3188
|
const note = limits.pricingBoundaryNote?.trim();
|
|
3188
|
-
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.";
|
|
3189
3190
|
}
|
|
3190
3191
|
function contextClampNotice(modelLabel, resolved) {
|
|
3191
3192
|
if (resolved.clampedFrom === void 0) return null;
|
|
@@ -3866,7 +3867,7 @@ import {
|
|
|
3866
3867
|
existsSync as existsSync4,
|
|
3867
3868
|
mkdtempSync,
|
|
3868
3869
|
mkdirSync as mkdirSync5,
|
|
3869
|
-
readFileSync as
|
|
3870
|
+
readFileSync as readFileSync10,
|
|
3870
3871
|
renameSync as renameSync2,
|
|
3871
3872
|
rmSync,
|
|
3872
3873
|
statSync as statSync7,
|
|
@@ -3874,10 +3875,10 @@ import {
|
|
|
3874
3875
|
writeFileSync as writeFileSync5,
|
|
3875
3876
|
openSync as openSync8,
|
|
3876
3877
|
closeSync as closeSync8,
|
|
3877
|
-
realpathSync as
|
|
3878
|
+
realpathSync as realpathSync3
|
|
3878
3879
|
} from "fs";
|
|
3879
|
-
import { homedir as
|
|
3880
|
-
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";
|
|
3881
3882
|
import pc3 from "picocolors";
|
|
3882
3883
|
import * as p2 from "@clack/prompts";
|
|
3883
3884
|
|
|
@@ -5978,30 +5979,94 @@ function deriveBrand(family) {
|
|
|
5978
5979
|
return "Other";
|
|
5979
5980
|
}
|
|
5980
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
|
+
|
|
5981
6045
|
// src/data/openai-oauth-models.ts
|
|
5982
|
-
var
|
|
5983
|
-
var
|
|
6046
|
+
var GPT_HIGH_CONTEXT_PRICING_BOUNDARY = 272e3;
|
|
6047
|
+
var GPT_HIGH_CONTEXT_PRICING_NOTE = "Above it, OpenAI prices the full request at 2x input and 1.5x output.";
|
|
5984
6048
|
var CHATGPT_CODEX_UNSUPPORTED_MODELS = /* @__PURE__ */ new Set([
|
|
5985
6049
|
"gpt-5.5-fast"
|
|
5986
6050
|
// confirmed: rejected by chatgpt.com/backend-api/codex
|
|
5987
6051
|
]);
|
|
5988
6052
|
var OPENAI_OAUTH_MODEL_SEEDS = [
|
|
5989
|
-
// GPT-6 family. The window and
|
|
5990
|
-
// 2026-09-04 and
|
|
5991
|
-
//
|
|
5992
|
-
//
|
|
5993
|
-
//
|
|
5994
|
-
//
|
|
5995
|
-
|
|
5996
|
-
{ id: "gpt-6-
|
|
6053
|
+
// GPT-6 family. The window, ceiling and Responses-Lite flags are what the live
|
|
6054
|
+
// Codex catalog returned (Astra on 2026-09-04, Sol and Luna on 2026-09-22) and are
|
|
6055
|
+
// deliberately NOT the published API numbers: the model cards list a 1,050,000
|
|
6056
|
+
// context window, but the Codex client is served a smaller one, and this path is
|
|
6057
|
+
// Codex-only. All three cards publish a 128,000 output limit and the same 272K
|
|
6058
|
+
// pricing boundary as the GPT-5.6 family.
|
|
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" },
|
|
5997
6062
|
// "An alias for our flagship general-purpose models, with safeguards calibrated
|
|
5998
6063
|
// for defensive cybersecurity work" — access is gated on a separate opt-in
|
|
5999
6064
|
// program, so most installs will never see this id in their catalog.
|
|
6000
|
-
{ 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" },
|
|
6001
6066
|
// GPT-5.6 family (Sol / Terra / Luna)
|
|
6002
|
-
{ id: "gpt-5.6-sol", name: "GPT-5.6 Sol", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true },
|
|
6003
|
-
{ id: "gpt-5.6-terra", name: "GPT-5.6 Terra", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true },
|
|
6004
|
-
{ 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" },
|
|
6005
6070
|
// GPT-5.5 family (Pro)
|
|
6006
6071
|
{ id: "gpt-5.5", name: "GPT-5.5", contextWindow: 272e3, maxOutputTokens: 128e3, reasoning: true },
|
|
6007
6072
|
// GPT-5.4 family
|
|
@@ -6028,8 +6093,8 @@ function hasPricingBoundary(id) {
|
|
|
6028
6093
|
function openAiPricingMetadata(id) {
|
|
6029
6094
|
if (!hasPricingBoundary(id)) return {};
|
|
6030
6095
|
return {
|
|
6031
|
-
pricingBoundary:
|
|
6032
|
-
pricingBoundaryNote:
|
|
6096
|
+
pricingBoundary: GPT_HIGH_CONTEXT_PRICING_BOUNDARY,
|
|
6097
|
+
pricingBoundaryNote: GPT_HIGH_CONTEXT_PRICING_NOTE
|
|
6033
6098
|
};
|
|
6034
6099
|
}
|
|
6035
6100
|
var LEGACY_IMPOSED_CONTEXT_PERCENT = 95;
|
|
@@ -6043,12 +6108,16 @@ function applyOAuthSeedContextMetadata(models) {
|
|
|
6043
6108
|
const pricing = openAiPricingMetadata(model.id);
|
|
6044
6109
|
return {
|
|
6045
6110
|
...model,
|
|
6111
|
+
contextWindow: model.contextWindow ?? seed?.contextWindow,
|
|
6046
6112
|
maxContextWindow: model.maxContextWindow ?? seed?.maxContextWindow,
|
|
6047
6113
|
effectiveContextPercent: migratedEffectiveContextPercent(model.effectiveContextPercent),
|
|
6048
6114
|
pricingBoundary: model.pricingBoundary ?? seed?.pricingBoundary ?? pricing.pricingBoundary,
|
|
6049
6115
|
pricingBoundaryNote: model.pricingBoundaryNote ?? seed?.pricingBoundaryNote ?? pricing.pricingBoundaryNote,
|
|
6050
6116
|
maxOutputTokens: model.maxOutputTokens ?? seed?.maxOutputTokens,
|
|
6051
|
-
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
|
|
6052
6121
|
};
|
|
6053
6122
|
});
|
|
6054
6123
|
}
|
|
@@ -6072,7 +6141,8 @@ function buildOpenAiOAuthModels() {
|
|
|
6072
6141
|
npm: "@ai-sdk/openai",
|
|
6073
6142
|
reasoning: seed.reasoning,
|
|
6074
6143
|
useResponsesLite: seed.useResponsesLite,
|
|
6075
|
-
preferWebSockets: seed.preferWebSockets
|
|
6144
|
+
preferWebSockets: seed.preferWebSockets,
|
|
6145
|
+
minimalClientVersion: seed.minimalClientVersion
|
|
6076
6146
|
};
|
|
6077
6147
|
});
|
|
6078
6148
|
}
|
|
@@ -6102,22 +6172,6 @@ function normalizeGoogleDisplayName(rawName, bareId) {
|
|
|
6102
6172
|
return stripGoogleModelPrefix(trimmed);
|
|
6103
6173
|
}
|
|
6104
6174
|
|
|
6105
|
-
// src/registry/server-text.ts
|
|
6106
|
-
function isControlCode(code) {
|
|
6107
|
-
return code <= 31 || code >= 127 && code <= 159;
|
|
6108
|
-
}
|
|
6109
|
-
function hasControlChars(value) {
|
|
6110
|
-
for (let i = 0; i < value.length; i++) {
|
|
6111
|
-
if (isControlCode(value.charCodeAt(i))) return true;
|
|
6112
|
-
}
|
|
6113
|
-
return false;
|
|
6114
|
-
}
|
|
6115
|
-
function printableServerText(value) {
|
|
6116
|
-
let out = "";
|
|
6117
|
-
for (const ch of value) out += isControlCode(ch.charCodeAt(0)) ? " " : ch;
|
|
6118
|
-
return out.trim();
|
|
6119
|
-
}
|
|
6120
|
-
|
|
6121
6175
|
// src/trace-log.ts
|
|
6122
6176
|
import {
|
|
6123
6177
|
chmodSync as chmodSync3,
|
|
@@ -6588,6 +6642,7 @@ function parseModelList(body, npm, allowBareArray) {
|
|
|
6588
6642
|
family,
|
|
6589
6643
|
brand: deriveBrand(family),
|
|
6590
6644
|
contextWindow,
|
|
6645
|
+
...npm === "@ai-sdk/openai" ? openAiPricingMetadata(id) : {},
|
|
6591
6646
|
cost,
|
|
6592
6647
|
isFree: isFreeStatus(freeStatus),
|
|
6593
6648
|
freeStatus,
|
|
@@ -6605,6 +6660,7 @@ function materializeTemplateModel(template, model, baseUrl) {
|
|
|
6605
6660
|
const { id, upstreamModelId: normalizedUpstream } = normalizeGoogleModelId(model.id, npm);
|
|
6606
6661
|
const family = model.family ?? (id.split(/[-/:]/)[0] ?? id);
|
|
6607
6662
|
const freeStatus = model.freeStatus ?? classifyFreeStatus({ model });
|
|
6663
|
+
const pricing = npm === "@ai-sdk/openai" ? openAiPricingMetadata(model.upstreamModelId ?? id) : {};
|
|
6608
6664
|
return {
|
|
6609
6665
|
...model,
|
|
6610
6666
|
id,
|
|
@@ -6613,6 +6669,8 @@ function materializeTemplateModel(template, model, baseUrl) {
|
|
|
6613
6669
|
family,
|
|
6614
6670
|
brand: model.brand ?? deriveBrand(family),
|
|
6615
6671
|
contextWindow: model.contextWindow ?? lookupKnownContextWindow(id),
|
|
6672
|
+
pricingBoundary: model.pricingBoundary ?? pricing.pricingBoundary,
|
|
6673
|
+
pricingBoundaryNote: model.pricingBoundaryNote ?? pricing.pricingBoundaryNote,
|
|
6616
6674
|
isFree: model.isFree ?? isFreeStatus(freeStatus),
|
|
6617
6675
|
freeStatus,
|
|
6618
6676
|
modelFormat: model.modelFormat ?? modelFormatForNpm(npm),
|
|
@@ -6805,8 +6863,21 @@ function resolveEndpoint(npm, apiUrl) {
|
|
|
6805
6863
|
}
|
|
6806
6864
|
function projectProviderCachedModels(provider) {
|
|
6807
6865
|
const cached = provider.modelsCache?.models ?? [];
|
|
6808
|
-
if (isChatGptOAuthProvider(provider))
|
|
6809
|
-
|
|
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
|
+
}
|
|
6810
6881
|
const template = retainedOpenCodeGoTemplate();
|
|
6811
6882
|
return template ? applyTemplateModelMetadata(template, cached) : [];
|
|
6812
6883
|
}
|
|
@@ -6960,8 +7031,162 @@ function materializeRegistry(registry, resolveCredential, opts) {
|
|
|
6960
7031
|
return result;
|
|
6961
7032
|
}
|
|
6962
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
|
+
|
|
6963
7188
|
// src/npm-shim.ts
|
|
6964
|
-
import { readFileSync as
|
|
7189
|
+
import { readFileSync as readFileSync8, realpathSync as realpathSync2, statSync as statSync4 } from "fs";
|
|
6965
7190
|
import { dirname as dirname3, resolve as resolve2 } from "path";
|
|
6966
7191
|
var MAX_LAUNCHER_BYTES = 64 * 1024;
|
|
6967
7192
|
var MAX_LAUNCHER_HOPS = 4;
|
|
@@ -6984,7 +7209,7 @@ function launcherKind(shimPath) {
|
|
|
6984
7209
|
function readLauncherText(path) {
|
|
6985
7210
|
try {
|
|
6986
7211
|
if (statSync4(path).size > MAX_LAUNCHER_BYTES) return null;
|
|
6987
|
-
return
|
|
7212
|
+
return readFileSync8(path, "utf8");
|
|
6988
7213
|
} catch {
|
|
6989
7214
|
return null;
|
|
6990
7215
|
}
|
|
@@ -7041,7 +7266,7 @@ function resolveThroughNpmShims(startPath) {
|
|
|
7041
7266
|
}
|
|
7042
7267
|
let hopped;
|
|
7043
7268
|
try {
|
|
7044
|
-
hopped =
|
|
7269
|
+
hopped = realpathSync2(reading.target);
|
|
7045
7270
|
} catch {
|
|
7046
7271
|
return {
|
|
7047
7272
|
ok: false,
|
|
@@ -7066,13 +7291,13 @@ import {
|
|
|
7066
7291
|
closeSync as closeSync2,
|
|
7067
7292
|
fstatSync,
|
|
7068
7293
|
openSync as openSync2,
|
|
7069
|
-
readFileSync as
|
|
7294
|
+
readFileSync as readFileSync9,
|
|
7070
7295
|
readSync,
|
|
7071
7296
|
statSync as statSync5
|
|
7072
7297
|
} from "fs";
|
|
7073
7298
|
import { createRequire } from "module";
|
|
7074
7299
|
import { arch } from "os";
|
|
7075
|
-
import { dirname as dirname4, join as
|
|
7300
|
+
import { dirname as dirname4, join as join7 } from "path";
|
|
7076
7301
|
var MAX_PLACEHOLDER_BYTES = 64 * 1024;
|
|
7077
7302
|
var CLAUDE_PACKAGE = "@anthropic-ai/claude-code";
|
|
7078
7303
|
var MISSING_BINARY_MARKER = "claude native binary not installed";
|
|
@@ -7099,11 +7324,11 @@ function getPlatformKey() {
|
|
|
7099
7324
|
}
|
|
7100
7325
|
function inspectNativePackage(binaryPath) {
|
|
7101
7326
|
const packageRoot2 = dirname4(dirname4(binaryPath));
|
|
7102
|
-
const packageJsonPath =
|
|
7103
|
-
const installScriptPath =
|
|
7327
|
+
const packageJsonPath = join7(packageRoot2, "package.json");
|
|
7328
|
+
const installScriptPath = join7(packageRoot2, "install.cjs");
|
|
7104
7329
|
let manifest;
|
|
7105
7330
|
try {
|
|
7106
|
-
manifest = JSON.parse(
|
|
7331
|
+
manifest = JSON.parse(readFileSync9(packageJsonPath, "utf8"));
|
|
7107
7332
|
if (manifest.name !== CLAUDE_PACKAGE || !statSync5(installScriptPath).isFile()) {
|
|
7108
7333
|
return { nativePackageState: "unknown", installScriptPath: null };
|
|
7109
7334
|
}
|
|
@@ -7157,7 +7382,7 @@ function inspectClaudeNativeBinaryPlaceholder(path) {
|
|
|
7157
7382
|
|
|
7158
7383
|
// src/bun-entry-module.ts
|
|
7159
7384
|
import { closeSync as closeSync3, openSync as openSync3, readSync as readSync2, statSync as statSync6, writeSync } from "fs";
|
|
7160
|
-
import { execFileSync } from "child_process";
|
|
7385
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
7161
7386
|
var BUN_TRAILER = Buffer.from("\n---- Bun! ----\n");
|
|
7162
7387
|
var BUN_OFFSETS_BYTES = 32;
|
|
7163
7388
|
var TAIL_SCAN_BYTES = 16 * 1024 * 1024;
|
|
@@ -7413,7 +7638,7 @@ function resignMachOBinary(path) {
|
|
|
7413
7638
|
closeSync3(fd);
|
|
7414
7639
|
}
|
|
7415
7640
|
if (machO && process.platform === "darwin") {
|
|
7416
|
-
|
|
7641
|
+
execFileSync2("codesign", ["-s", "-", "-f", path], { stdio: "ignore" });
|
|
7417
7642
|
}
|
|
7418
7643
|
}
|
|
7419
7644
|
|
|
@@ -11080,7 +11305,7 @@ function supportsExtendedCodexEffort(modelId) {
|
|
|
11080
11305
|
return /^gpt-daybreak(?:-|$)/i.test(modelId);
|
|
11081
11306
|
}
|
|
11082
11307
|
function supportsNoneEffort(modelId) {
|
|
11083
|
-
return /^gpt-5\.6(?:-|$)/i.test(modelId) || /^gpt-daybreak-blue(?:-|$)/i.test(modelId);
|
|
11308
|
+
return /^gpt-5\.6(?:-|$)/i.test(modelId) || /^gpt-6-(?:sol|luna)(?:-|$)/i.test(modelId) || /^gpt-daybreak-blue(?:-|$)/i.test(modelId);
|
|
11084
11309
|
}
|
|
11085
11310
|
function isReasoningSummaryUnsupportedModel(modelId) {
|
|
11086
11311
|
return /codex-spark(?:-|$)/i.test(modelId);
|
|
@@ -11703,7 +11928,7 @@ function withThousands2(value) {
|
|
|
11703
11928
|
return value.toLocaleString("en-US");
|
|
11704
11929
|
}
|
|
11705
11930
|
function formatPricingBoundaryWarning(modelLabel, boundary, inputTokens) {
|
|
11706
|
-
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.`;
|
|
11707
11932
|
}
|
|
11708
11933
|
function reportPricingBoundaryCrossing(observation, emit = emitParentNotice) {
|
|
11709
11934
|
const { modelKey, modelLabel, pricingBoundary, inputTokens } = observation;
|
|
@@ -12513,15 +12738,10 @@ function annotateToolNames(messages) {
|
|
|
12513
12738
|
}
|
|
12514
12739
|
}
|
|
12515
12740
|
function thinkingToSdkPart(block, npm) {
|
|
12516
|
-
|
|
12517
|
-
|
|
12518
|
-
|
|
12519
|
-
|
|
12520
|
-
if (npm === "@ai-sdk/google") {
|
|
12521
|
-
part.providerOptions = { google: { thoughtSignature: block.signature } };
|
|
12522
|
-
} else if (npm === "@ai-sdk/openai" || npm === "@ai-sdk/openai-compatible") {
|
|
12523
|
-
part.providerOptions = { openai: { reasoningEncryptedContent: block.signature } };
|
|
12524
|
-
}
|
|
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 } };
|
|
12525
12745
|
}
|
|
12526
12746
|
return part;
|
|
12527
12747
|
}
|
|
@@ -14060,7 +14280,7 @@ function buildHttpProxyRoutes(providers, favorites, modelAliases = void 0, max =
|
|
|
14060
14280
|
|
|
14061
14281
|
// src/patcher.ts
|
|
14062
14282
|
function getPatchLockPath() {
|
|
14063
|
-
return
|
|
14283
|
+
return join8(getAppHome(), "patch.lock");
|
|
14064
14284
|
}
|
|
14065
14285
|
function writePatchManifest(manifest, path = getPatchManifestPath()) {
|
|
14066
14286
|
mkdirSync5(getAppHome(), { recursive: true, mode: 448 });
|
|
@@ -14217,7 +14437,7 @@ function pidIsAlive(pid) {
|
|
|
14217
14437
|
function tryAcquirePatchLock(lockPath = getPatchLockPath(), opts = {}) {
|
|
14218
14438
|
const now = opts.now ?? Date.now();
|
|
14219
14439
|
const isAlive = opts.isAlive ?? pidIsAlive;
|
|
14220
|
-
mkdirSync5(
|
|
14440
|
+
mkdirSync5(join8(lockPath, ".."), { recursive: true, mode: 448 });
|
|
14221
14441
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
14222
14442
|
try {
|
|
14223
14443
|
const fd = openSync8(lockPath, "wx");
|
|
@@ -14233,7 +14453,7 @@ function tryAcquirePatchLock(lockPath = getPatchLockPath(), opts = {}) {
|
|
|
14233
14453
|
} catch {
|
|
14234
14454
|
let stale = false;
|
|
14235
14455
|
try {
|
|
14236
|
-
const existing = JSON.parse(
|
|
14456
|
+
const existing = JSON.parse(readFileSync10(lockPath, "utf8"));
|
|
14237
14457
|
stale = !existing.pid || !isAlive(existing.pid) || typeof existing.startedAt === "number" && now - existing.startedAt > PATCH_LOCK_STALE_MS;
|
|
14238
14458
|
} catch {
|
|
14239
14459
|
stale = true;
|
|
@@ -14255,7 +14475,7 @@ function takeIgnoredLaunchOverride() {
|
|
|
14255
14475
|
}
|
|
14256
14476
|
function resolveClaudeBinaryForPatch() {
|
|
14257
14477
|
const envOverride = process.env["TWEAKCC_CC_INSTALLATION_PATH"]?.trim() || null;
|
|
14258
|
-
const nativeSymlink =
|
|
14478
|
+
const nativeSymlink = join8(homedir3(), ".local", "bin", "claude");
|
|
14259
14479
|
if (envOverride && !existsSync4(envOverride)) {
|
|
14260
14480
|
return { ok: false, reason: "patch-target-missing", declaredPath: envOverride };
|
|
14261
14481
|
}
|
|
@@ -14263,7 +14483,7 @@ function resolveClaudeBinaryForPatch() {
|
|
|
14263
14483
|
if (!source) return { ok: false, reason: "binary-not-found" };
|
|
14264
14484
|
let resolved;
|
|
14265
14485
|
try {
|
|
14266
|
-
resolved =
|
|
14486
|
+
resolved = realpathSync3(source);
|
|
14267
14487
|
} catch {
|
|
14268
14488
|
return { ok: false, reason: "binary-not-found" };
|
|
14269
14489
|
}
|
|
@@ -14283,8 +14503,8 @@ function resolveClaudeBinaryForPatch() {
|
|
|
14283
14503
|
let launchOverrideResolved = null;
|
|
14284
14504
|
if (launchOverride) {
|
|
14285
14505
|
try {
|
|
14286
|
-
const followedOverride = resolveThroughNpmShims(
|
|
14287
|
-
launchOverrideResolved = followedOverride.ok ? followedOverride.path :
|
|
14506
|
+
const followedOverride = resolveThroughNpmShims(realpathSync3(launchOverride));
|
|
14507
|
+
launchOverrideResolved = followedOverride.ok ? followedOverride.path : realpathSync3(launchOverride);
|
|
14288
14508
|
} catch {
|
|
14289
14509
|
launchOverrideResolved = launchOverride;
|
|
14290
14510
|
}
|
|
@@ -14423,8 +14643,8 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14423
14643
|
try {
|
|
14424
14644
|
mkdirSync5(backupDir(), { recursive: true });
|
|
14425
14645
|
const { tryDetectInstallation, readContent, writeContent } = await import("tweakcc");
|
|
14426
|
-
candidateDir = mkdtempSync(
|
|
14427
|
-
const candidatePath =
|
|
14646
|
+
candidateDir = mkdtempSync(join8(dirname5(binaryPath), ".clodex-patch-"));
|
|
14647
|
+
const candidatePath = join8(candidateDir, basename(binaryPath));
|
|
14428
14648
|
const seedCandidate = async (from) => {
|
|
14429
14649
|
copyFileSync(from, candidatePath);
|
|
14430
14650
|
const shim = shimEntryModuleName(candidatePath);
|
|
@@ -14711,6 +14931,9 @@ function runRestoreCommand(target) {
|
|
|
14711
14931
|
p2.log.success(`Restored pristine claude ${version} from ${plan.backupPath}.`);
|
|
14712
14932
|
return 0;
|
|
14713
14933
|
}
|
|
14934
|
+
function warnOnEditorExtensionDrift(binaryPath, version) {
|
|
14935
|
+
for (const warning of claudeExtensionDriftWarnings({ binaryPath, version })) p2.log.warn(warning);
|
|
14936
|
+
}
|
|
14714
14937
|
async function runPatchCommand(opts = {}) {
|
|
14715
14938
|
const target = resolveClaudeBinaryForPatch();
|
|
14716
14939
|
const ignoredOverride = takeIgnoredLaunchOverride();
|
|
@@ -14756,6 +14979,7 @@ async function runPatchCommand(opts = {}) {
|
|
|
14756
14979
|
});
|
|
14757
14980
|
if (state === "current") {
|
|
14758
14981
|
p2.log.success(`claude ${version} is already patched with the current model config \u2014 nothing to do.`);
|
|
14982
|
+
warnOnEditorExtensionDrift(binaryPath, version);
|
|
14759
14983
|
return 0;
|
|
14760
14984
|
}
|
|
14761
14985
|
const release = tryAcquirePatchLock();
|
|
@@ -14791,6 +15015,7 @@ async function runPatchCommand(opts = {}) {
|
|
|
14791
15015
|
if (!opts.trace) {
|
|
14792
15016
|
for (const line of outcome.detailLines ?? []) p2.log.info(pc3.dim(line));
|
|
14793
15017
|
}
|
|
15018
|
+
warnOnEditorExtensionDrift(binaryPath, version);
|
|
14794
15019
|
return 0;
|
|
14795
15020
|
} finally {
|
|
14796
15021
|
release();
|
|
@@ -15164,7 +15389,7 @@ import {
|
|
|
15164
15389
|
lstatSync,
|
|
15165
15390
|
mkdirSync as mkdirSync6,
|
|
15166
15391
|
openSync as openSync9,
|
|
15167
|
-
readFileSync as
|
|
15392
|
+
readFileSync as readFileSync11,
|
|
15168
15393
|
renameSync as renameSync3,
|
|
15169
15394
|
unlinkSync as unlinkSync4,
|
|
15170
15395
|
writeFileSync as writeFileSync6
|
|
@@ -15271,7 +15496,7 @@ function readJournalUnlocked(path) {
|
|
|
15271
15496
|
if (opened.size > MAX_JOURNAL_BYTES) {
|
|
15272
15497
|
throw new Error("Credential cleanup journal is too large.");
|
|
15273
15498
|
}
|
|
15274
|
-
return parseJournal(JSON.parse(
|
|
15499
|
+
return parseJournal(JSON.parse(readFileSync11(fd, "utf8")));
|
|
15275
15500
|
} catch (error) {
|
|
15276
15501
|
const message = error instanceof Error ? error.message : String(error);
|
|
15277
15502
|
throw new Error(`Could not read credential cleanup journal: ${message}`);
|
|
@@ -16338,7 +16563,8 @@ function readCapabilityFlags(m) {
|
|
|
16338
16563
|
const bool = (v) => typeof v === "boolean" ? v : void 0;
|
|
16339
16564
|
return {
|
|
16340
16565
|
useResponsesLite: bool(m["use_responses_lite"]),
|
|
16341
|
-
preferWebSockets: bool(m["prefer_websockets"])
|
|
16566
|
+
preferWebSockets: bool(m["prefer_websockets"]),
|
|
16567
|
+
minimalClientVersion: readCodexClientVersion(m["minimal_client_version"])
|
|
16342
16568
|
};
|
|
16343
16569
|
}
|
|
16344
16570
|
function parseOpenAiModelEntries(body) {
|
|
@@ -16375,7 +16601,8 @@ function buildDynamicOAuthModel(entry, seedById, codexCatalog) {
|
|
|
16375
16601
|
effectiveContextPercent: entry.effective_context_window_percent ?? seed.effectiveContextPercent,
|
|
16376
16602
|
maxOutputTokens: entry.max_output_tokens ?? seed.maxOutputTokens,
|
|
16377
16603
|
useResponsesLite: entry.useResponsesLite ?? seed.useResponsesLite,
|
|
16378
|
-
preferWebSockets: entry.preferWebSockets ?? seed.preferWebSockets
|
|
16604
|
+
preferWebSockets: entry.preferWebSockets ?? seed.preferWebSockets,
|
|
16605
|
+
minimalClientVersion: entry.minimalClientVersion ?? seed.minimalClientVersion
|
|
16379
16606
|
};
|
|
16380
16607
|
}
|
|
16381
16608
|
const { id } = entry;
|
|
@@ -16410,7 +16637,8 @@ function buildDynamicOAuthModel(entry, seedById, codexCatalog) {
|
|
|
16410
16637
|
// so a wrong `true` here costs an unusable menu entry, not a 400.
|
|
16411
16638
|
reasoning: codexCatalog ? true : modelPrefersResponsesApi(id),
|
|
16412
16639
|
useResponsesLite: entry.useResponsesLite,
|
|
16413
|
-
preferWebSockets: entry.preferWebSockets
|
|
16640
|
+
preferWebSockets: entry.preferWebSockets,
|
|
16641
|
+
minimalClientVersion: entry.minimalClientVersion
|
|
16414
16642
|
};
|
|
16415
16643
|
}
|
|
16416
16644
|
async function fetchJsonWithAuth(url, accessToken, timeoutMs) {
|
|
@@ -16471,6 +16699,10 @@ async function refreshOpenAiOAuthModels(accessToken) {
|
|
|
16471
16699
|
credentialRejected: credentialFailure !== void 0
|
|
16472
16700
|
};
|
|
16473
16701
|
}
|
|
16702
|
+
function warningSuffix(models) {
|
|
16703
|
+
const warning = codexClientVersionWarning(applyOAuthSeedContextMetadata(models));
|
|
16704
|
+
return warning ? ` ${warning}` : "";
|
|
16705
|
+
}
|
|
16474
16706
|
async function refreshApiListProvider(provider, apiKey) {
|
|
16475
16707
|
const npm = provider.api.npm ?? "@ai-sdk/openai-compatible";
|
|
16476
16708
|
const retained = isRetainedOpenCodeGoProvider(provider);
|
|
@@ -16680,7 +16912,7 @@ async function refreshProviderModels(providerId, apiKey, registry, credentialSna
|
|
|
16680
16912
|
if (oauthResult.source === "seed" && cachedModelCount(cacheProvider) > 0) {
|
|
16681
16913
|
return skipWithCachedModels(
|
|
16682
16914
|
cacheProvider,
|
|
16683
|
-
`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)
|
|
16684
16916
|
);
|
|
16685
16917
|
}
|
|
16686
16918
|
if (oauthResult.source === "seed") {
|
|
@@ -16774,7 +17006,7 @@ async function refreshProviderModels(providerId, apiKey, registry, credentialSna
|
|
|
16774
17006
|
ok: true,
|
|
16775
17007
|
modelCount: enriched.length,
|
|
16776
17008
|
previousModelCount: hadPreviousRefresh ? previousModelCount : void 0,
|
|
16777
|
-
reason: oauthFallbackReason
|
|
17009
|
+
reason: isChatGptOAuthProvider(provider) ? [oauthFallbackReason, codexClientVersionWarning(models)].filter(Boolean).join(" ") || void 0 : void 0
|
|
16778
17010
|
};
|
|
16779
17011
|
} catch (err) {
|
|
16780
17012
|
return {
|
|
@@ -17131,6 +17363,7 @@ async function authenticateProvider(providerId, options = {}) {
|
|
|
17131
17363
|
refreshSpinner.stop(`Models not refreshed${refreshResult.reason ? ` \u2014 ${refreshResult.reason}` : ""}`);
|
|
17132
17364
|
} else if (refreshResult.ok) {
|
|
17133
17365
|
refreshSpinner.stop("Models refreshed");
|
|
17366
|
+
if (refreshResult.reason) p4.log.warn(refreshResult.reason);
|
|
17134
17367
|
} else {
|
|
17135
17368
|
refreshSpinner.stop(`Could not refresh models${refreshResult.reason ? ` \u2014 ${refreshResult.reason}` : ""}`);
|
|
17136
17369
|
}
|
|
@@ -18810,7 +19043,7 @@ async function routeRequest(req, res, options, modelCache, plog) {
|
|
|
18810
19043
|
}
|
|
18811
19044
|
async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
18812
19045
|
const clientAbort = watchClientDisconnect(res);
|
|
18813
|
-
const body = await
|
|
19046
|
+
const body = await readJson2(req);
|
|
18814
19047
|
if (!body) {
|
|
18815
19048
|
sendJson(res, 400, { error: { message: "Invalid JSON body" } });
|
|
18816
19049
|
return;
|
|
@@ -19080,7 +19313,7 @@ data: ${JSON.stringify({
|
|
|
19080
19313
|
}
|
|
19081
19314
|
async function handleAnthropicCountTokens(req, res, options, plog) {
|
|
19082
19315
|
const clientAbort = watchClientDisconnect(res);
|
|
19083
|
-
const body = await
|
|
19316
|
+
const body = await readJson2(req);
|
|
19084
19317
|
if (!body) {
|
|
19085
19318
|
sendJson(res, 400, { error: { message: "Invalid JSON body" } });
|
|
19086
19319
|
return;
|
|
@@ -19149,7 +19382,7 @@ async function handleAnthropicCountTokens(req, res, options, plog) {
|
|
|
19149
19382
|
}
|
|
19150
19383
|
async function handleOpenAIChatCompletions(req, res, options, modelCache, plog) {
|
|
19151
19384
|
const clientAbort = watchClientDisconnect(res);
|
|
19152
|
-
const body = await
|
|
19385
|
+
const body = await readJson2(req);
|
|
19153
19386
|
if (!body) {
|
|
19154
19387
|
sendJson(res, 400, { error: { message: "Invalid JSON body" } });
|
|
19155
19388
|
return;
|
|
@@ -19356,7 +19589,7 @@ function getResponseModelId(bodyModel, model, options) {
|
|
|
19356
19589
|
if (typeof bodyModel === "string" && options.aliasNames?.has(bodyModel)) return bodyModel;
|
|
19357
19590
|
return options.gateway?.maskGatewayIds ? gatewayDisplayName(model, options.gateway) : typeof bodyModel === "string" ? bodyModel : model.id;
|
|
19358
19591
|
}
|
|
19359
|
-
async function
|
|
19592
|
+
async function readJson2(req) {
|
|
19360
19593
|
try {
|
|
19361
19594
|
const raw = await readBody(req);
|
|
19362
19595
|
return raw ? JSON.parse(raw) : {};
|
|
@@ -19500,8 +19733,8 @@ import { createBrotliDecompress, createGunzip, createInflate } from "zlib";
|
|
|
19500
19733
|
|
|
19501
19734
|
// src/http-proxy/ca.ts
|
|
19502
19735
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
19503
|
-
import { chmodSync as chmodSync5, existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as
|
|
19504
|
-
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";
|
|
19505
19738
|
import forge from "node-forge";
|
|
19506
19739
|
var CERT_DIR = "http-proxy";
|
|
19507
19740
|
var CA_CERT_FILE = "clodex-ca.pem";
|
|
@@ -19516,14 +19749,14 @@ function serialNumber() {
|
|
|
19516
19749
|
return bytes.toString("hex");
|
|
19517
19750
|
}
|
|
19518
19751
|
function certPaths() {
|
|
19519
|
-
const dir =
|
|
19752
|
+
const dir = join9(getAppHome(), CERT_DIR);
|
|
19520
19753
|
return {
|
|
19521
19754
|
dir,
|
|
19522
|
-
caCert:
|
|
19523
|
-
caKey:
|
|
19524
|
-
serverCert:
|
|
19525
|
-
serverKey:
|
|
19526
|
-
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)
|
|
19527
19760
|
};
|
|
19528
19761
|
}
|
|
19529
19762
|
function writePrivate(path, value) {
|
|
@@ -19576,8 +19809,8 @@ function generateCertificates(paths) {
|
|
|
19576
19809
|
}
|
|
19577
19810
|
function storedCertificatesAreCurrent(paths) {
|
|
19578
19811
|
try {
|
|
19579
|
-
const ca = forge.pki.certificateFromPem(
|
|
19580
|
-
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"));
|
|
19581
19814
|
const now = Date.now();
|
|
19582
19815
|
const renewalBuffer = 7 * 24 * 60 * 60 * 1e3;
|
|
19583
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);
|
|
@@ -19588,13 +19821,13 @@ function storedCertificatesAreCurrent(paths) {
|
|
|
19588
19821
|
function ensureHttpProxyCertificates() {
|
|
19589
19822
|
const paths = certPaths();
|
|
19590
19823
|
const required = [paths.caCert, paths.caKey, paths.serverCert, paths.serverKey, paths.version];
|
|
19591
|
-
const current = required.every(existsSync6) &&
|
|
19824
|
+
const current = required.every(existsSync6) && readFileSync12(paths.version, "utf8") === CERT_VERSION && storedCertificatesAreCurrent(paths);
|
|
19592
19825
|
if (!current) generateCertificates(paths);
|
|
19593
19826
|
return {
|
|
19594
19827
|
caCertPath: paths.caCert,
|
|
19595
|
-
caCert:
|
|
19596
|
-
serverCert:
|
|
19597
|
-
serverKey:
|
|
19828
|
+
caCert: readFileSync12(paths.caCert, "utf8"),
|
|
19829
|
+
serverCert: readFileSync12(paths.serverCert, "utf8"),
|
|
19830
|
+
serverKey: readFileSync12(paths.serverKey, "utf8")
|
|
19598
19831
|
};
|
|
19599
19832
|
}
|
|
19600
19833
|
function ensureHttpProxyCaBundle(relayCaCertPath, additionalCaCertPath, onWarning) {
|
|
@@ -19608,7 +19841,7 @@ function ensureHttpProxyCaBundle(relayCaCertPath, additionalCaCertPath, onWarnin
|
|
|
19608
19841
|
let additionalCa;
|
|
19609
19842
|
try {
|
|
19610
19843
|
if (resolve3(additionalCaCertPath) === resolve3(relayCaCertPath)) return relayCaCertPath;
|
|
19611
|
-
additionalCa =
|
|
19844
|
+
additionalCa = readFileSync12(additionalCaCertPath, "utf8").trim();
|
|
19612
19845
|
} catch (err) {
|
|
19613
19846
|
return warn(
|
|
19614
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.`
|
|
@@ -19618,8 +19851,8 @@ function ensureHttpProxyCaBundle(relayCaCertPath, additionalCaCertPath, onWarnin
|
|
|
19618
19851
|
return warn(`NODE_EXTRA_CA_CERTS=${additionalCaCertPath} is empty, so it adds nothing.`);
|
|
19619
19852
|
}
|
|
19620
19853
|
try {
|
|
19621
|
-
const relayCa =
|
|
19622
|
-
const combinedPath =
|
|
19854
|
+
const relayCa = readFileSync12(relayCaCertPath, "utf8").trimEnd();
|
|
19855
|
+
const combinedPath = join9(dirname7(relayCaCertPath), "combined-ca.pem");
|
|
19623
19856
|
writePublic(combinedPath, `${relayCa}
|
|
19624
19857
|
${additionalCa}
|
|
19625
19858
|
`);
|
|
@@ -21500,9 +21733,9 @@ function planLaunchWizard(opts) {
|
|
|
21500
21733
|
|
|
21501
21734
|
// src/vscode-launcher.ts
|
|
21502
21735
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
21503
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync2, readdirSync, readFileSync as
|
|
21504
|
-
import { tmpdir } from "os";
|
|
21505
|
-
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";
|
|
21506
21739
|
import { fileURLToPath } from "url";
|
|
21507
21740
|
var LAUNCHER_EXE_NAME = "clodex-claude.exe";
|
|
21508
21741
|
var VSCODE_WRAPPER_SETTING = "claudeCode.claudeProcessWrapper";
|
|
@@ -21511,15 +21744,15 @@ var WRAPPER_PATH_PLACEHOLDER = '"__CLODEX_WRAPPER_SCRIPT_PATH__"';
|
|
|
21511
21744
|
var LAUNCHER_SOURCE_FILE = "clodex-claude-launcher.cs";
|
|
21512
21745
|
var UTF8_BOM = "\uFEFF";
|
|
21513
21746
|
var CSC_ARGS = ["/nologo", "/target:exe", "/platform:anycpu", "/optimize+", `/out:${LAUNCHER_EXE_NAME}`, LAUNCHER_SOURCE_FILE];
|
|
21514
|
-
var packageRoot =
|
|
21747
|
+
var packageRoot = join10(dirname8(fileURLToPath(import.meta.url)), "..");
|
|
21515
21748
|
function defaultLauncherInputs() {
|
|
21516
21749
|
return {
|
|
21517
|
-
launcherSourcePath:
|
|
21518
|
-
wrapperScriptPath:
|
|
21750
|
+
launcherSourcePath: join10(packageRoot, "launcher", LAUNCHER_SOURCE_FILE),
|
|
21751
|
+
wrapperScriptPath: join10(packageRoot, "dist", "claude-wrapper.js")
|
|
21519
21752
|
};
|
|
21520
21753
|
}
|
|
21521
21754
|
function launcherInstallPath(env = process.env) {
|
|
21522
|
-
return
|
|
21755
|
+
return join10(getAppHome(env), "bin", LAUNCHER_EXE_NAME);
|
|
21523
21756
|
}
|
|
21524
21757
|
function csharpStringLiteral(value) {
|
|
21525
21758
|
let literal = '"';
|
|
@@ -21545,30 +21778,23 @@ function renderLauncherSource(template, paths) {
|
|
|
21545
21778
|
}
|
|
21546
21779
|
function cscSearchRoots(env = process.env) {
|
|
21547
21780
|
const windir = env.WINDIR?.trim() || env.SystemRoot?.trim() || "C:\\Windows";
|
|
21548
|
-
const dotnet =
|
|
21549
|
-
return [
|
|
21781
|
+
const dotnet = join10(windir, "Microsoft.NET");
|
|
21782
|
+
return [join10(dotnet, "Framework64"), join10(dotnet, "Framework")];
|
|
21550
21783
|
}
|
|
21551
21784
|
function frameworkVersionKey(name) {
|
|
21552
21785
|
return name.slice(1).split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
21553
21786
|
}
|
|
21554
|
-
function compareVersionKeys(a, b) {
|
|
21555
|
-
for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
|
|
21556
|
-
const diff = (a[i] ?? 0) - (b[i] ?? 0);
|
|
21557
|
-
if (diff !== 0) return diff;
|
|
21558
|
-
}
|
|
21559
|
-
return 0;
|
|
21560
|
-
}
|
|
21561
21787
|
function findCsc(env = process.env) {
|
|
21562
21788
|
for (const root of cscSearchRoots(env)) {
|
|
21563
21789
|
let entries;
|
|
21564
21790
|
try {
|
|
21565
|
-
entries =
|
|
21791
|
+
entries = readdirSync2(root);
|
|
21566
21792
|
} catch {
|
|
21567
21793
|
continue;
|
|
21568
21794
|
}
|
|
21569
21795
|
const candidates = entries.filter((name) => /^v4\.\d+(\.\d+)*$/i.test(name)).sort((a, b) => compareVersionKeys(frameworkVersionKey(b), frameworkVersionKey(a)));
|
|
21570
21796
|
for (const version of candidates) {
|
|
21571
|
-
const csc =
|
|
21797
|
+
const csc = join10(root, version, "csc.exe");
|
|
21572
21798
|
try {
|
|
21573
21799
|
if (statSync8(csc).isFile()) return csc;
|
|
21574
21800
|
} catch {
|
|
@@ -21627,7 +21853,7 @@ function installVscodeLauncher(opts = {}) {
|
|
|
21627
21853
|
}
|
|
21628
21854
|
let source;
|
|
21629
21855
|
try {
|
|
21630
|
-
source = renderLauncherSource(
|
|
21856
|
+
source = renderLauncherSource(readFileSync13(launcherSourcePath, "utf8"), { nodePath, wrapperScriptPath });
|
|
21631
21857
|
} catch (err) {
|
|
21632
21858
|
return { ok: false, reason: "missing-input", message: `could not prepare the launcher source: ${describeError(err)}` };
|
|
21633
21859
|
}
|
|
@@ -21635,7 +21861,7 @@ function installVscodeLauncher(opts = {}) {
|
|
|
21635
21861
|
const tempRoot = opts.tempRoot ?? tmpdir();
|
|
21636
21862
|
let scratch;
|
|
21637
21863
|
try {
|
|
21638
|
-
scratch = mkdtempSync2(
|
|
21864
|
+
scratch = mkdtempSync2(join10(tempRoot, "clodex-vscode-launcher-"));
|
|
21639
21865
|
} catch (err) {
|
|
21640
21866
|
return { ok: false, reason: "install-failed", message: `could not create a scratch directory under ${tempRoot}: ${describeError(err)}` };
|
|
21641
21867
|
}
|
|
@@ -21650,9 +21876,9 @@ function installVscodeLauncher(opts = {}) {
|
|
|
21650
21876
|
}
|
|
21651
21877
|
function buildAndPublish(step) {
|
|
21652
21878
|
const { scratch, cscPath, exePath } = step;
|
|
21653
|
-
writeFileSync8(
|
|
21879
|
+
writeFileSync8(join10(scratch, LAUNCHER_SOURCE_FILE), UTF8_BOM + step.source, "utf8");
|
|
21654
21880
|
const compiled = step.compile(cscPath, CSC_ARGS, scratch);
|
|
21655
|
-
const builtExe =
|
|
21881
|
+
const builtExe = join10(scratch, LAUNCHER_EXE_NAME);
|
|
21656
21882
|
if (compiled.error || compiled.status !== 0 || !existsSync7(builtExe)) {
|
|
21657
21883
|
const output = [compiled.stdout, compiled.stderr].map((text6) => text6.trim()).filter(Boolean).join("\n");
|
|
21658
21884
|
return {
|
|
@@ -21707,16 +21933,27 @@ function successReport(result) {
|
|
|
21707
21933
|
"install: the paths above are compiled into the executable."
|
|
21708
21934
|
];
|
|
21709
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
|
+
}
|
|
21710
21946
|
function runInstallVscodeLauncherCommand(opts = {}) {
|
|
21711
21947
|
const result = installVscodeLauncher(opts);
|
|
21712
21948
|
if (result.warning) console.error(`clodex: warning: ${result.warning}`);
|
|
21713
21949
|
if (!result.ok) {
|
|
21714
21950
|
console.error(`clodex: ${result.message}`);
|
|
21715
21951
|
if (result.detail) console.error(result.detail);
|
|
21716
|
-
|
|
21952
|
+
} else {
|
|
21953
|
+
console.log(successReport(result).join("\n"));
|
|
21717
21954
|
}
|
|
21718
|
-
|
|
21719
|
-
return 0;
|
|
21955
|
+
for (const drift of launcherExtensionDriftWarnings(opts)) console.error(`clodex: warning: ${drift}`);
|
|
21956
|
+
return result.ok ? 0 : 1;
|
|
21720
21957
|
}
|
|
21721
21958
|
|
|
21722
21959
|
// src/cli.ts
|
|
@@ -22050,8 +22287,10 @@ ${pc13.bold("Options:")}
|
|
|
22050
22287
|
--trace Write debug logs to ~/.clodex/logs/ and show errors on exit
|
|
22051
22288
|
--fast Request Codex fast mode (service_tier=priority) on ChatGPT-OAuth models
|
|
22052
22289
|
(equivalent to CLODEX_SERVICE_TIER=fast; warns if the SDK omits it)
|
|
22053
|
-
--provider
|
|
22054
|
-
|
|
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)
|
|
22055
22294
|
--context <model=stop> use a different share of a model's window for this
|
|
22056
22295
|
launch only (standard, max, default, or a token count). Nothing is
|
|
22057
22296
|
saved. It reaches Claude Code through the exported catalog, so a
|
|
@@ -22092,7 +22331,7 @@ ${pc13.bold("Examples:")}
|
|
|
22092
22331
|
clodex claude --trace --resume abc-123
|
|
22093
22332
|
clodex claude --endpoint
|
|
22094
22333
|
clodex claude --endpoint --save-mode
|
|
22095
|
-
clodex claude --provider openai-oauth --model gpt-
|
|
22334
|
+
clodex claude --endpoint --provider openai-oauth --model gpt-6-sol
|
|
22096
22335
|
clodex claude -- --print "hello"
|
|
22097
22336
|
clodex claude -- --dangerously-skip-permissions`;
|
|
22098
22337
|
}
|
|
@@ -22180,7 +22419,7 @@ Manage favorite models for mid-session switching.
|
|
|
22180
22419
|
${pc13.bold("Usage:")}
|
|
22181
22420
|
clodex favorites
|
|
22182
22421
|
clodex models --list
|
|
22183
|
-
clodex models --alias sol=clodex:openai-oauth:gpt-
|
|
22422
|
+
clodex models --alias sol=clodex:openai-oauth:gpt-6-sol
|
|
22184
22423
|
clodex models --unalias sol
|
|
22185
22424
|
clodex models --context sol=max --save
|
|
22186
22425
|
clodex models --json
|
|
@@ -22213,13 +22452,16 @@ ${pc13.bold("How it works:")}
|
|
|
22213
22452
|
Claude Code binary so they pass model validation and report real context.
|
|
22214
22453
|
|
|
22215
22454
|
${pc13.bold("Context stops and cost:")}
|
|
22216
|
-
Some providers price large prompts in bands: GPT-5.6
|
|
22217
|
-
a higher rate above 272,000 input tokens.
|
|
22218
|
-
|
|
22455
|
+
Some providers price large prompts in bands: GPT-5.6 and GPT-6 bill the full request at
|
|
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.
|
|
22219
22461
|
|
|
22220
22462
|
${pc13.bold("Examples:")}
|
|
22221
22463
|
clodex favorites
|
|
22222
|
-
clodex models --alias sol=clodex:openai-oauth:gpt-
|
|
22464
|
+
clodex models --alias sol=clodex:openai-oauth:gpt-6-sol
|
|
22223
22465
|
clodex models --context sol=max --save
|
|
22224
22466
|
clodex claude # switch menu active when favorites are set`;
|
|
22225
22467
|
}
|
|
@@ -22252,7 +22494,13 @@ ${pc13.bold("Behavior:")}
|
|
|
22252
22494
|
Local patches execute after the built-ins as an all-or-none set. Enabling
|
|
22253
22495
|
them executes trusted JavaScript from local-patches.mjs with your full user
|
|
22254
22496
|
permissions. Local failures are reported but never block the built-ins.
|
|
22255
|
-
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}`;
|
|
22256
22504
|
}
|
|
22257
22505
|
function installVscodeLauncherHelpText() {
|
|
22258
22506
|
return `${pc13.bold("clodex install-vscode-launcher")} v${VERSION}
|
|
@@ -22282,6 +22530,8 @@ ${pc13.bold("Behavior:")}
|
|
|
22282
22530
|
As on macOS and Linux, clodex-claude then runs your clodex-patched install in
|
|
22283
22531
|
place of the bundled claude.exe when the two builds match, so clodex models
|
|
22284
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.
|
|
22285
22535
|
|
|
22286
22536
|
The paths to node.exe and to the clodex install are compiled in: re-run this
|
|
22287
22537
|
command after switching Node versions or moving the clodex install.
|
|
@@ -23232,7 +23482,7 @@ Error: ${resolved.error}
|
|
|
23232
23482
|
function isCliEntryPoint() {
|
|
23233
23483
|
if (!process.argv[1]) return false;
|
|
23234
23484
|
try {
|
|
23235
|
-
return
|
|
23485
|
+
return realpathSync4(fileURLToPath2(import.meta.url)) === realpathSync4(process.argv[1]);
|
|
23236
23486
|
} catch {
|
|
23237
23487
|
return false;
|
|
23238
23488
|
}
|