@bman654/clodex 2.1.9 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -2
- package/dist/{chunk-VQOX3AXE.js → chunk-W4SVDQCZ.js} +7 -1
- package/dist/chunk-W4SVDQCZ.js.map +1 -0
- package/dist/claude-wrapper.js +1 -1
- package/dist/cli.js +524 -32
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-VQOX3AXE.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
getCredentialMutationLockPath,
|
|
10
10
|
getCredentialStateRoot,
|
|
11
11
|
getInstalledClaudeVersion,
|
|
12
|
+
getLocalPatchesPath,
|
|
12
13
|
getLogsPath,
|
|
13
14
|
getSavedServerPassword,
|
|
14
15
|
getServerExposedProviders,
|
|
@@ -39,7 +40,7 @@ import {
|
|
|
39
40
|
withProviderMutationLock,
|
|
40
41
|
withRegistryWriteLock,
|
|
41
42
|
withRegistryWriteLockSync
|
|
42
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-W4SVDQCZ.js";
|
|
43
44
|
|
|
44
45
|
// src/cli.ts
|
|
45
46
|
import pc13 from "picocolors";
|
|
@@ -217,7 +218,7 @@ import { join } from "path";
|
|
|
217
218
|
// package.json
|
|
218
219
|
var package_default = {
|
|
219
220
|
name: "@bman654/clodex",
|
|
220
|
-
version: "2.1
|
|
221
|
+
version: "2.2.1",
|
|
221
222
|
publishConfig: {
|
|
222
223
|
access: "public"
|
|
223
224
|
},
|
|
@@ -273,7 +274,7 @@ var package_default = {
|
|
|
273
274
|
open: "11.0.0",
|
|
274
275
|
picocolors: "1.1.1",
|
|
275
276
|
tweakcc: "4.3.0",
|
|
276
|
-
undici: "7.
|
|
277
|
+
undici: "7.29.0",
|
|
277
278
|
ws: "8.21.0"
|
|
278
279
|
},
|
|
279
280
|
devDependencies: {
|
|
@@ -13917,16 +13918,16 @@ function planLaunchWizard(opts) {
|
|
|
13917
13918
|
}
|
|
13918
13919
|
|
|
13919
13920
|
// src/patcher.ts
|
|
13920
|
-
import { createHash as
|
|
13921
|
+
import { createHash as createHash9 } from "crypto";
|
|
13921
13922
|
import {
|
|
13922
13923
|
copyFileSync,
|
|
13923
13924
|
existsSync as existsSync7,
|
|
13924
13925
|
mkdtempSync,
|
|
13925
13926
|
mkdirSync as mkdirSync7,
|
|
13926
|
-
readFileSync as
|
|
13927
|
+
readFileSync as readFileSync10,
|
|
13927
13928
|
renameSync as renameSync3,
|
|
13928
13929
|
rmSync,
|
|
13929
|
-
statSync as
|
|
13930
|
+
statSync as statSync5,
|
|
13930
13931
|
unlinkSync as unlinkSync4,
|
|
13931
13932
|
writeFileSync as writeFileSync7,
|
|
13932
13933
|
openSync as openSync4,
|
|
@@ -13938,9 +13939,380 @@ import { basename, dirname as dirname5, join as join8 } from "path";
|
|
|
13938
13939
|
import pc12 from "picocolors";
|
|
13939
13940
|
import * as p11 from "@clack/prompts";
|
|
13940
13941
|
|
|
13941
|
-
// src/
|
|
13942
|
+
// src/local-patches.ts
|
|
13942
13943
|
import { createHash as createHash7 } from "crypto";
|
|
13943
|
-
import {
|
|
13944
|
+
import { readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
13945
|
+
var LOCAL_PATCH_API_VERSION = 1;
|
|
13946
|
+
var LOCAL_PATCH_ID_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/;
|
|
13947
|
+
var MAX_LOCAL_PATCH_BYTES = 1024 * 1024;
|
|
13948
|
+
var RESERVED_MARKER_PREFIX = "/*ccpatch:";
|
|
13949
|
+
var LOCAL_MARKER_PREFIX = "/*clodex-local:";
|
|
13950
|
+
var MAX_ERROR_LENGTH = 300;
|
|
13951
|
+
var localModuleEvaluationSequence = 0;
|
|
13952
|
+
function describeLocalError(error) {
|
|
13953
|
+
const raw = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
13954
|
+
const redacted = raw.replace(
|
|
13955
|
+
/data:text\/javascript;base64,[^\s"'`]+/g,
|
|
13956
|
+
"<local-patches.mjs>"
|
|
13957
|
+
);
|
|
13958
|
+
const singleLine = redacted.replace(/[\r\n\t]+/g, " ").replace(/\s{2,}/g, " ").trim();
|
|
13959
|
+
if (singleLine.length <= MAX_ERROR_LENGTH) return singleLine || "unknown error";
|
|
13960
|
+
return `${singleLine.slice(0, MAX_ERROR_LENGTH - 1)}\u2026`;
|
|
13961
|
+
}
|
|
13962
|
+
function describeLocalId(id) {
|
|
13963
|
+
const encoded = JSON.stringify(id);
|
|
13964
|
+
return encoded.length <= 96 ? encoded : `${encoded.slice(0, 95)}\u2026`;
|
|
13965
|
+
}
|
|
13966
|
+
function countOccurrences(source, needle) {
|
|
13967
|
+
let count = 0;
|
|
13968
|
+
let offset = 0;
|
|
13969
|
+
while ((offset = source.indexOf(needle, offset)) !== -1) {
|
|
13970
|
+
count += 1;
|
|
13971
|
+
offset += needle.length;
|
|
13972
|
+
}
|
|
13973
|
+
return count;
|
|
13974
|
+
}
|
|
13975
|
+
function reservedMarkerInventory(source) {
|
|
13976
|
+
const count = countOccurrences(source, RESERVED_MARKER_PREFIX);
|
|
13977
|
+
const markers = source.match(/\/\*ccpatch:[\s\S]*?\*\//g)?.sort() ?? [];
|
|
13978
|
+
return JSON.stringify([count, markers]);
|
|
13979
|
+
}
|
|
13980
|
+
function localMarkerInventory(source) {
|
|
13981
|
+
const count = countOccurrences(source, LOCAL_MARKER_PREFIX);
|
|
13982
|
+
const markers = source.match(/\/\*clodex-local:[\s\S]*?\*\//g)?.sort() ?? [];
|
|
13983
|
+
return JSON.stringify([count, markers]);
|
|
13984
|
+
}
|
|
13985
|
+
function inspectLocalPatchSource(enabled) {
|
|
13986
|
+
const path = getLocalPatchesPath();
|
|
13987
|
+
if (!enabled) return { enabled: false, path };
|
|
13988
|
+
try {
|
|
13989
|
+
const stats = statSync3(path);
|
|
13990
|
+
if (!stats.isFile()) throw Object.assign(new Error("not a regular file"), { code: "EINVAL" });
|
|
13991
|
+
if (stats.size > MAX_LOCAL_PATCH_BYTES) {
|
|
13992
|
+
throw Object.assign(new Error("module exceeds 1 MiB"), { code: "EFBIG" });
|
|
13993
|
+
}
|
|
13994
|
+
const bytes = readFileSync8(path);
|
|
13995
|
+
if (bytes.length > MAX_LOCAL_PATCH_BYTES) {
|
|
13996
|
+
throw Object.assign(new Error("module exceeds 1 MiB"), { code: "EFBIG" });
|
|
13997
|
+
}
|
|
13998
|
+
const digest = createHash7("sha256").update(bytes).digest("hex");
|
|
13999
|
+
const source = bytes.toString("utf8");
|
|
14000
|
+
if (!Buffer.from(source, "utf8").equals(bytes)) {
|
|
14001
|
+
return {
|
|
14002
|
+
enabled: true,
|
|
14003
|
+
path,
|
|
14004
|
+
configIdentity: `v${LOCAL_PATCH_API_VERSION}:invalid-utf8:${digest}`,
|
|
14005
|
+
error: `could not read ${path}: module must be UTF-8`
|
|
14006
|
+
};
|
|
14007
|
+
}
|
|
14008
|
+
return {
|
|
14009
|
+
enabled: true,
|
|
14010
|
+
path,
|
|
14011
|
+
configIdentity: `v${LOCAL_PATCH_API_VERSION}:${digest}`,
|
|
14012
|
+
source
|
|
14013
|
+
};
|
|
14014
|
+
} catch (error) {
|
|
14015
|
+
const code = error instanceof Error && "code" in error ? String(error.code) : "UNKNOWN";
|
|
14016
|
+
const reason = code === "EFBIG" ? "module exceeds 1 MiB" : code === "EINVAL" ? "not a regular file" : code;
|
|
14017
|
+
return {
|
|
14018
|
+
enabled: true,
|
|
14019
|
+
path,
|
|
14020
|
+
configIdentity: `v${LOCAL_PATCH_API_VERSION}:unavailable:${code}`,
|
|
14021
|
+
error: `could not read ${path}: ${reason}`
|
|
14022
|
+
};
|
|
14023
|
+
}
|
|
14024
|
+
}
|
|
14025
|
+
function failedLocalTransaction(source, patches, results, failedIndex, extra) {
|
|
14026
|
+
const failedName = `LOCAL ${patches[failedIndex].id}`;
|
|
14027
|
+
const rolledBack = results.map((result) => result.status === "OK" ? {
|
|
14028
|
+
status: "SKIP",
|
|
14029
|
+
name: result.name,
|
|
14030
|
+
extra: `rolled back after ${failedName} failed`
|
|
14031
|
+
} : result);
|
|
14032
|
+
rolledBack.push({ status: "FAIL", name: failedName, extra });
|
|
14033
|
+
for (const remaining of patches.slice(failedIndex + 1)) {
|
|
14034
|
+
rolledBack.push({
|
|
14035
|
+
status: "SKIP",
|
|
14036
|
+
name: `LOCAL ${remaining.id}`,
|
|
14037
|
+
extra: `not run after ${failedName} failed`
|
|
14038
|
+
});
|
|
14039
|
+
}
|
|
14040
|
+
return { content: source, results: rolledBack };
|
|
14041
|
+
}
|
|
14042
|
+
function snapshotLocalPatchDefinitions(value) {
|
|
14043
|
+
if (!Array.isArray(value)) return "default export must be an array";
|
|
14044
|
+
const rawDefinitions = [...value];
|
|
14045
|
+
const snapshot = [];
|
|
14046
|
+
const ids = /* @__PURE__ */ new Set();
|
|
14047
|
+
for (const [index, definition] of rawDefinitions.entries()) {
|
|
14048
|
+
if (definition === null || typeof definition !== "object") {
|
|
14049
|
+
return `entry at index ${index} must be an object`;
|
|
14050
|
+
}
|
|
14051
|
+
const candidate = definition;
|
|
14052
|
+
const id = candidate.id;
|
|
14053
|
+
const apply = candidate.apply;
|
|
14054
|
+
if (typeof id !== "string") return `entry at index ${index} must have a string id`;
|
|
14055
|
+
if (typeof apply !== "function") {
|
|
14056
|
+
return `entry ${describeLocalId(id)} must have an apply function`;
|
|
14057
|
+
}
|
|
14058
|
+
if (!LOCAL_PATCH_ID_PATTERN.test(id)) {
|
|
14059
|
+
return `invalid id at index ${index}: ${describeLocalId(id)}`;
|
|
14060
|
+
}
|
|
14061
|
+
if (ids.has(id)) return `duplicate id at index ${index}: ${describeLocalId(id)}`;
|
|
14062
|
+
ids.add(id);
|
|
14063
|
+
snapshot.push(Object.freeze({ id, apply }));
|
|
14064
|
+
}
|
|
14065
|
+
return Object.freeze(snapshot);
|
|
14066
|
+
}
|
|
14067
|
+
function applyLocalPatchSnapshot(source, patches) {
|
|
14068
|
+
let content = source;
|
|
14069
|
+
const results = [];
|
|
14070
|
+
for (const [index, patch] of patches.entries()) {
|
|
14071
|
+
const marker = `/*clodex-local:${patch.id}*/`;
|
|
14072
|
+
const existingMarkerCount = countOccurrences(content, marker);
|
|
14073
|
+
if (existingMarkerCount > 1) {
|
|
14074
|
+
return failedLocalTransaction(
|
|
14075
|
+
source,
|
|
14076
|
+
patches,
|
|
14077
|
+
results,
|
|
14078
|
+
index,
|
|
14079
|
+
"existing marker appears more than once"
|
|
14080
|
+
);
|
|
14081
|
+
}
|
|
14082
|
+
if (existingMarkerCount === 1) {
|
|
14083
|
+
results.push({
|
|
14084
|
+
status: "SKIP",
|
|
14085
|
+
name: `LOCAL ${patch.id}`,
|
|
14086
|
+
extra: "already patched"
|
|
14087
|
+
});
|
|
14088
|
+
continue;
|
|
14089
|
+
}
|
|
14090
|
+
let next;
|
|
14091
|
+
const reservedMarkers = reservedMarkerInventory(content);
|
|
14092
|
+
const localMarkers = localMarkerInventory(content);
|
|
14093
|
+
try {
|
|
14094
|
+
next = patch.apply(content, { marker });
|
|
14095
|
+
} catch (error) {
|
|
14096
|
+
return failedLocalTransaction(
|
|
14097
|
+
source,
|
|
14098
|
+
patches,
|
|
14099
|
+
results,
|
|
14100
|
+
index,
|
|
14101
|
+
describeLocalError(error)
|
|
14102
|
+
);
|
|
14103
|
+
}
|
|
14104
|
+
if (typeof next !== "string") {
|
|
14105
|
+
return failedLocalTransaction(
|
|
14106
|
+
source,
|
|
14107
|
+
patches,
|
|
14108
|
+
results,
|
|
14109
|
+
index,
|
|
14110
|
+
`transform returned ${typeof next} instead of a string`
|
|
14111
|
+
);
|
|
14112
|
+
}
|
|
14113
|
+
if (reservedMarkerInventory(next) !== reservedMarkers) {
|
|
14114
|
+
return failedLocalTransaction(
|
|
14115
|
+
source,
|
|
14116
|
+
patches,
|
|
14117
|
+
results,
|
|
14118
|
+
index,
|
|
14119
|
+
"transform changed reserved /*ccpatch: markers"
|
|
14120
|
+
);
|
|
14121
|
+
}
|
|
14122
|
+
const markerCount = countOccurrences(next, marker);
|
|
14123
|
+
if (markerCount !== 1) {
|
|
14124
|
+
return failedLocalTransaction(
|
|
14125
|
+
source,
|
|
14126
|
+
patches,
|
|
14127
|
+
results,
|
|
14128
|
+
index,
|
|
14129
|
+
markerCount === 0 ? `transform did not emit ${marker}` : `transform must emit exactly one ${marker} marker`
|
|
14130
|
+
);
|
|
14131
|
+
}
|
|
14132
|
+
if (localMarkerInventory(next.replace(marker, "")) !== localMarkers) {
|
|
14133
|
+
return failedLocalTransaction(
|
|
14134
|
+
source,
|
|
14135
|
+
patches,
|
|
14136
|
+
results,
|
|
14137
|
+
index,
|
|
14138
|
+
"transform changed another local patch marker"
|
|
14139
|
+
);
|
|
14140
|
+
}
|
|
14141
|
+
content = next;
|
|
14142
|
+
results.push({ status: "OK", name: `LOCAL ${patch.id}` });
|
|
14143
|
+
}
|
|
14144
|
+
return { content, results };
|
|
14145
|
+
}
|
|
14146
|
+
function localPatchSetFailure(source, extra) {
|
|
14147
|
+
return {
|
|
14148
|
+
content: source,
|
|
14149
|
+
results: [{ status: "FAIL", name: "LOCAL PATCH SET", extra }]
|
|
14150
|
+
};
|
|
14151
|
+
}
|
|
14152
|
+
async function applyLocalPatches(source, localSource) {
|
|
14153
|
+
if (!localSource.enabled) return { content: source, results: [] };
|
|
14154
|
+
if (typeof localSource.error === "string") {
|
|
14155
|
+
return localPatchSetFailure(source, localSource.error);
|
|
14156
|
+
}
|
|
14157
|
+
try {
|
|
14158
|
+
const moduleUrl = `data:text/javascript;base64,${Buffer.from(localSource.source).toString("base64")}#clodex-local-eval-${++localModuleEvaluationSequence}`;
|
|
14159
|
+
const loaded = await import(
|
|
14160
|
+
/* @vite-ignore */
|
|
14161
|
+
moduleUrl
|
|
14162
|
+
);
|
|
14163
|
+
const definitions = snapshotLocalPatchDefinitions(loaded.default);
|
|
14164
|
+
if (typeof definitions === "string") {
|
|
14165
|
+
return localPatchSetFailure(source, definitions);
|
|
14166
|
+
}
|
|
14167
|
+
if (definitions.length === 0) {
|
|
14168
|
+
return {
|
|
14169
|
+
content: source,
|
|
14170
|
+
results: [{
|
|
14171
|
+
status: "SKIP",
|
|
14172
|
+
name: "LOCAL PATCH SET",
|
|
14173
|
+
extra: "no patches exported"
|
|
14174
|
+
}]
|
|
14175
|
+
};
|
|
14176
|
+
}
|
|
14177
|
+
return applyLocalPatchSnapshot(source, definitions);
|
|
14178
|
+
} catch (error) {
|
|
14179
|
+
return localPatchSetFailure(
|
|
14180
|
+
source,
|
|
14181
|
+
describeLocalError(error)
|
|
14182
|
+
);
|
|
14183
|
+
}
|
|
14184
|
+
}
|
|
14185
|
+
|
|
14186
|
+
// src/built-in-patch-proofs.ts
|
|
14187
|
+
function escapeRegex(value) {
|
|
14188
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14189
|
+
}
|
|
14190
|
+
function countExactOccurrences(source, needle) {
|
|
14191
|
+
let count = 0;
|
|
14192
|
+
let offset = 0;
|
|
14193
|
+
while ((offset = source.indexOf(needle, offset)) !== -1) {
|
|
14194
|
+
count += 1;
|
|
14195
|
+
offset += needle.length;
|
|
14196
|
+
}
|
|
14197
|
+
return count;
|
|
14198
|
+
}
|
|
14199
|
+
function uniqueMatch(source, name, pattern) {
|
|
14200
|
+
const flags = pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`;
|
|
14201
|
+
const matcher = new RegExp(pattern.source, flags);
|
|
14202
|
+
const match = matcher.exec(source);
|
|
14203
|
+
if (!match || matcher.exec(source)) {
|
|
14204
|
+
throw new Error(`clodex patch: could not capture built-in postcondition: ${name}`);
|
|
14205
|
+
}
|
|
14206
|
+
return match[0];
|
|
14207
|
+
}
|
|
14208
|
+
function captureNeedle(source, name, needle) {
|
|
14209
|
+
if (countExactOccurrences(source, needle) !== 1) {
|
|
14210
|
+
throw new Error(`clodex patch: could not capture built-in postcondition: ${name}`);
|
|
14211
|
+
}
|
|
14212
|
+
return {
|
|
14213
|
+
name,
|
|
14214
|
+
protectedText: needle,
|
|
14215
|
+
occurrences: 1
|
|
14216
|
+
};
|
|
14217
|
+
}
|
|
14218
|
+
function capturePattern(source, name, pattern) {
|
|
14219
|
+
return captureNeedle(source, name, uniqueMatch(source, name, pattern));
|
|
14220
|
+
}
|
|
14221
|
+
function normalizedPatchName(name) {
|
|
14222
|
+
return name.replace(/ \(refresh\)$/, "");
|
|
14223
|
+
}
|
|
14224
|
+
function protectsResult(results, name) {
|
|
14225
|
+
const result = results.find((entry) => normalizedPatchName(entry.name) === name);
|
|
14226
|
+
return result !== void 0 && result.status !== "FAIL" && result.extra !== "no aliases configured";
|
|
14227
|
+
}
|
|
14228
|
+
function configuredAliases(config) {
|
|
14229
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
14230
|
+
for (const [id, entry] of Object.entries(config)) {
|
|
14231
|
+
if (entry.alias === void 0) continue;
|
|
14232
|
+
const alias = String(entry.alias).trim().toLowerCase();
|
|
14233
|
+
aliases.set(alias, {
|
|
14234
|
+
id,
|
|
14235
|
+
...entry.display === void 0 ? {} : { display: String(entry.display) }
|
|
14236
|
+
});
|
|
14237
|
+
}
|
|
14238
|
+
return [...aliases].map(([alias, entry]) => ({ alias, ...entry }));
|
|
14239
|
+
}
|
|
14240
|
+
function effortProofPattern(marker) {
|
|
14241
|
+
return new RegExp(
|
|
14242
|
+
escapeRegex(marker) + 'var _ccv=Object\\.assign\\(Object\\.create\\(null\\),\\{[^{}]*\\}\\)\\[String\\([\\w$]+\\|\\|""\\)\\.trim\\(\\)\\.toLowerCase\\(\\)\\];if\\(_ccv!==void 0\\)return _ccv;'
|
|
14243
|
+
);
|
|
14244
|
+
}
|
|
14245
|
+
function captureBuiltInPatchProofs(source, config, results) {
|
|
14246
|
+
const proofs = [];
|
|
14247
|
+
const addPattern = (name, pattern) => {
|
|
14248
|
+
if (protectsResult(results, name)) {
|
|
14249
|
+
proofs.push(capturePattern(source, name, pattern));
|
|
14250
|
+
}
|
|
14251
|
+
};
|
|
14252
|
+
addPattern(
|
|
14253
|
+
"PATCH 1: Agent tool model enum",
|
|
14254
|
+
/(?:\.enum|model:[A-Za-z_$][\w$]*)\(\["sonnet","opus","haiku"(?:,"[^"]+")*\]\)\.optional\(\)\.describe\(/
|
|
14255
|
+
);
|
|
14256
|
+
addPattern(
|
|
14257
|
+
"PATCH 3: known-alias validator list",
|
|
14258
|
+
/\["sonnet","opus","haiku","fable"(?:,"[^"]+")*,"opusplan"(?:,"[^"]+")*\]/
|
|
14259
|
+
);
|
|
14260
|
+
addPattern(
|
|
14261
|
+
"PATCH 4: Agent tool model description",
|
|
14262
|
+
/describe\(`Optional model override for this agent[^`]*?`\)/
|
|
14263
|
+
);
|
|
14264
|
+
const aliases = configuredAliases(config);
|
|
14265
|
+
if (protectsResult(results, "PATCH 6: alias resolver switch")) {
|
|
14266
|
+
for (const { alias } of aliases) {
|
|
14267
|
+
const value = JSON.stringify(alias);
|
|
14268
|
+
proofs.push(captureNeedle(
|
|
14269
|
+
source,
|
|
14270
|
+
`PATCH 6: alias resolver switch (${alias})`,
|
|
14271
|
+
`case${value}:return ${value};`
|
|
14272
|
+
));
|
|
14273
|
+
}
|
|
14274
|
+
}
|
|
14275
|
+
if (protectsResult(results, "PATCH 5: model picker options")) {
|
|
14276
|
+
for (const { alias, id, display } of aliases) {
|
|
14277
|
+
const entry = "{value:" + JSON.stringify(alias) + ",label:" + JSON.stringify(alias.charAt(0).toUpperCase() + alias.slice(1)) + ",description:" + JSON.stringify(display ?? `Custom model (${id})`) + "}";
|
|
14278
|
+
proofs.push(captureNeedle(
|
|
14279
|
+
source,
|
|
14280
|
+
`PATCH 5: model picker options (${alias})`,
|
|
14281
|
+
entry
|
|
14282
|
+
));
|
|
14283
|
+
}
|
|
14284
|
+
}
|
|
14285
|
+
addPattern(
|
|
14286
|
+
"PATCH 7: per-model context window",
|
|
14287
|
+
/\/\*ccpatch:ctx\*\/var _ccw=\(\{[^{}]*\}\)\[[^\]]*\];if\(_ccw!==void 0\)return _ccw;/
|
|
14288
|
+
);
|
|
14289
|
+
addPattern(
|
|
14290
|
+
"PATCH 8a: effort capability",
|
|
14291
|
+
effortProofPattern("/*ccpatch:effort*/")
|
|
14292
|
+
);
|
|
14293
|
+
addPattern(
|
|
14294
|
+
"PATCH 8b: xhigh effort capability",
|
|
14295
|
+
effortProofPattern("/*ccpatch:xhigh-effort*/")
|
|
14296
|
+
);
|
|
14297
|
+
addPattern(
|
|
14298
|
+
"PATCH 8c: max effort capability",
|
|
14299
|
+
effortProofPattern("/*ccpatch:max-effort*/")
|
|
14300
|
+
);
|
|
14301
|
+
addPattern(
|
|
14302
|
+
"PATCH 9: default effort",
|
|
14303
|
+
/\/\*ccpatch:default-effort\*\/var _cce=Object\.assign\(Object\.create\(null\),\{[^{}]*\}\)\[String\([\w$]+\|\|""\)\.trim\(\)\.toLowerCase\(\)\];if\(_cce!==void 0\)return _cce;/
|
|
14304
|
+
);
|
|
14305
|
+
return proofs;
|
|
14306
|
+
}
|
|
14307
|
+
function builtInPatchProofsChanged(source, proofs) {
|
|
14308
|
+
return proofs.some(
|
|
14309
|
+
(proof) => countExactOccurrences(source, proof.protectedText) !== proof.occurrences
|
|
14310
|
+
);
|
|
14311
|
+
}
|
|
14312
|
+
|
|
14313
|
+
// src/patch-backup.ts
|
|
14314
|
+
import { createHash as createHash8 } from "crypto";
|
|
14315
|
+
import { existsSync as existsSync6, readFileSync as readFileSync9, readdirSync, statSync as statSync4 } from "fs";
|
|
13944
14316
|
import { homedir as homedir2 } from "os";
|
|
13945
14317
|
import { join as join7 } from "path";
|
|
13946
14318
|
var BACKUP_SHA_PREFIX_LENGTH = 16;
|
|
@@ -13948,7 +14320,7 @@ function backupDir() {
|
|
|
13948
14320
|
return process.env["TWEAKCC_CONFIG_DIR"]?.trim() || join7(homedir2(), ".tweakcc");
|
|
13949
14321
|
}
|
|
13950
14322
|
function sha256File(path) {
|
|
13951
|
-
return
|
|
14323
|
+
return createHash8("sha256").update(readFileSync9(path)).digest("hex");
|
|
13952
14324
|
}
|
|
13953
14325
|
function backupVersionTag(version) {
|
|
13954
14326
|
const tag = version.trim().replace(/[^\w.-]+/g, "_");
|
|
@@ -13978,7 +14350,7 @@ function scanPristineBackups(version, dir = backupDir()) {
|
|
|
13978
14350
|
const path = join7(dir, entry);
|
|
13979
14351
|
let sha256;
|
|
13980
14352
|
try {
|
|
13981
|
-
if (!
|
|
14353
|
+
if (!statSync4(path).isFile()) continue;
|
|
13982
14354
|
sha256 = sha256File(path);
|
|
13983
14355
|
} catch {
|
|
13984
14356
|
corrupt.push(path);
|
|
@@ -14092,7 +14464,7 @@ function collectPristineFacts(args) {
|
|
|
14092
14464
|
}
|
|
14093
14465
|
|
|
14094
14466
|
// src/patch-transforms.ts
|
|
14095
|
-
var PATCH_TRANSFORMS_VERSION =
|
|
14467
|
+
var PATCH_TRANSFORMS_VERSION = 3;
|
|
14096
14468
|
var NATIVE_EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
|
|
14097
14469
|
var BASE_EFFORT_LEVELS = ["low", "medium", "high"];
|
|
14098
14470
|
function projectNativeEffort(effort) {
|
|
@@ -14238,8 +14610,8 @@ function applyClodexPatches(source, config) {
|
|
|
14238
14610
|
}
|
|
14239
14611
|
applyOnce(
|
|
14240
14612
|
"PATCH 1: Agent tool model enum",
|
|
14241
|
-
|
|
14242
|
-
(_m, arr) =>
|
|
14613
|
+
/((?:\.enum|model:[A-Za-z_$][\w$]*)\()(\["sonnet","opus","haiku"(?:,"[^"]+")*\])\)(\.optional\(\)\.describe\()/,
|
|
14614
|
+
(_m, open2, arr, tail) => open2 + extendAliasArray(arr) + ")" + tail,
|
|
14243
14615
|
{ required: true, noopIsSkip: true }
|
|
14244
14616
|
);
|
|
14245
14617
|
applyOnce(
|
|
@@ -14399,7 +14771,7 @@ function getPatchLockPath() {
|
|
|
14399
14771
|
}
|
|
14400
14772
|
function readPatchManifest(path = getPatchManifestPath()) {
|
|
14401
14773
|
try {
|
|
14402
|
-
const parsed = JSON.parse(
|
|
14774
|
+
const parsed = JSON.parse(readFileSync10(path, "utf8"));
|
|
14403
14775
|
if (parsed && typeof parsed.binaryPath === "string" && typeof parsed.configHash === "string") {
|
|
14404
14776
|
return parsed;
|
|
14405
14777
|
}
|
|
@@ -14465,7 +14837,7 @@ function reportRejectedModelAliases(rejections) {
|
|
|
14465
14837
|
);
|
|
14466
14838
|
}
|
|
14467
14839
|
}
|
|
14468
|
-
function computePatchConfigHash(config, transformsVersion = PATCH_TRANSFORMS_VERSION) {
|
|
14840
|
+
function computePatchConfigHash(config, transformsVersion = PATCH_TRANSFORMS_VERSION, localPatchIdentity) {
|
|
14469
14841
|
const canonical = Object.keys(config).sort().map((key) => {
|
|
14470
14842
|
const entry = config[key];
|
|
14471
14843
|
return [
|
|
@@ -14477,7 +14849,11 @@ function computePatchConfigHash(config, transformsVersion = PATCH_TRANSFORMS_VER
|
|
|
14477
14849
|
entry.effort?.defaultLevel ?? null
|
|
14478
14850
|
];
|
|
14479
14851
|
});
|
|
14480
|
-
|
|
14852
|
+
const payload = [transformsVersion, canonical];
|
|
14853
|
+
if (localPatchIdentity !== void 0) {
|
|
14854
|
+
payload.push(["local-patches", localPatchIdentity]);
|
|
14855
|
+
}
|
|
14856
|
+
return createHash9("sha256").update(JSON.stringify(payload)).digest("hex");
|
|
14481
14857
|
}
|
|
14482
14858
|
function buildDesiredPatchConfig() {
|
|
14483
14859
|
const prefs = loadPreferences();
|
|
@@ -14548,7 +14924,7 @@ function tryAcquirePatchLock(lockPath = getPatchLockPath(), opts = {}) {
|
|
|
14548
14924
|
} catch {
|
|
14549
14925
|
let stale = false;
|
|
14550
14926
|
try {
|
|
14551
|
-
const existing = JSON.parse(
|
|
14927
|
+
const existing = JSON.parse(readFileSync10(lockPath, "utf8"));
|
|
14552
14928
|
stale = !existing.pid || !isAlive(existing.pid) || typeof existing.startedAt === "number" && now - existing.startedAt > PATCH_LOCK_STALE_MS;
|
|
14553
14929
|
} catch {
|
|
14554
14930
|
stale = true;
|
|
@@ -14574,7 +14950,7 @@ function resolveClaudeBinaryForPatch() {
|
|
|
14574
14950
|
return { ok: false, reason: "binary-not-found" };
|
|
14575
14951
|
}
|
|
14576
14952
|
try {
|
|
14577
|
-
if (!
|
|
14953
|
+
if (!statSync5(resolved).isFile()) return { ok: false, reason: "binary-not-found" };
|
|
14578
14954
|
} catch {
|
|
14579
14955
|
return { ok: false, reason: "binary-not-found" };
|
|
14580
14956
|
}
|
|
@@ -14626,6 +15002,49 @@ function requiredEffortPatchFailures(results) {
|
|
|
14626
15002
|
(result) => result.status === "FAIL" && (result.name.startsWith("PATCH 8a:") || result.name.startsWith("PATCH 8b:") || result.name.startsWith("PATCH 8c:") || result.name.startsWith("PATCH 9:"))
|
|
14627
15003
|
);
|
|
14628
15004
|
}
|
|
15005
|
+
function builtInPatchVerificationFailed(source, config, expected, proofs) {
|
|
15006
|
+
if (builtInPatchProofsChanged(source, proofs)) return true;
|
|
15007
|
+
let verification;
|
|
15008
|
+
try {
|
|
15009
|
+
verification = applyClodexPatches(source, config);
|
|
15010
|
+
} catch {
|
|
15011
|
+
return true;
|
|
15012
|
+
}
|
|
15013
|
+
if (verification.content !== source || verification.results.length !== expected.length) {
|
|
15014
|
+
return true;
|
|
15015
|
+
}
|
|
15016
|
+
const expectedByName = new Map(expected.map((result) => [
|
|
15017
|
+
result.name.replace(/ \(refresh\)$/, ""),
|
|
15018
|
+
result
|
|
15019
|
+
]));
|
|
15020
|
+
for (const result of verification.results) {
|
|
15021
|
+
const original = expectedByName.get(result.name.replace(/ \(refresh\)$/, ""));
|
|
15022
|
+
if (!original) return true;
|
|
15023
|
+
if (original.status === "FAIL") {
|
|
15024
|
+
if (result.status !== "FAIL" || result.extra !== original.extra) return true;
|
|
15025
|
+
} else if (result.status !== "SKIP") {
|
|
15026
|
+
return true;
|
|
15027
|
+
}
|
|
15028
|
+
}
|
|
15029
|
+
return false;
|
|
15030
|
+
}
|
|
15031
|
+
function discardLocalPatchOutcome(builtInContent, results) {
|
|
15032
|
+
return {
|
|
15033
|
+
content: builtInContent,
|
|
15034
|
+
results: [
|
|
15035
|
+
...results.map((result) => result.status === "OK" ? {
|
|
15036
|
+
status: "SKIP",
|
|
15037
|
+
name: result.name,
|
|
15038
|
+
extra: "rolled back after built-in verification failed"
|
|
15039
|
+
} : result),
|
|
15040
|
+
{
|
|
15041
|
+
status: "FAIL",
|
|
15042
|
+
name: "LOCAL PATCH SET",
|
|
15043
|
+
extra: "local output changed built-in patch sites"
|
|
15044
|
+
}
|
|
15045
|
+
]
|
|
15046
|
+
};
|
|
15047
|
+
}
|
|
14629
15048
|
async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
14630
15049
|
let candidateDir;
|
|
14631
15050
|
let results;
|
|
@@ -14689,8 +15108,8 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14689
15108
|
backup = canonical;
|
|
14690
15109
|
}
|
|
14691
15110
|
publishBackupFile(backup, tweakccMirrorBackupPath());
|
|
14692
|
-
const
|
|
14693
|
-
results =
|
|
15111
|
+
const builtIn = applyClodexPatches(loaded.source, desired.config);
|
|
15112
|
+
results = builtIn.results;
|
|
14694
15113
|
const failedEffortPatches = requiredEffortPatchFailures(results);
|
|
14695
15114
|
if (failedEffortPatches.length > 0) {
|
|
14696
15115
|
throw new PatchApplyError(
|
|
@@ -14698,8 +15117,38 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
|
|
|
14698
15117
|
results
|
|
14699
15118
|
);
|
|
14700
15119
|
}
|
|
14701
|
-
|
|
14702
|
-
|
|
15120
|
+
let builtInProofs = [];
|
|
15121
|
+
let local;
|
|
15122
|
+
if (opts.localPatches?.enabled && typeof opts.localPatches.source === "string") {
|
|
15123
|
+
try {
|
|
15124
|
+
builtInProofs = captureBuiltInPatchProofs(
|
|
15125
|
+
builtIn.content,
|
|
15126
|
+
desired.config,
|
|
15127
|
+
builtIn.results
|
|
15128
|
+
);
|
|
15129
|
+
} catch {
|
|
15130
|
+
local = {
|
|
15131
|
+
content: builtIn.content,
|
|
15132
|
+
results: [{
|
|
15133
|
+
status: "FAIL",
|
|
15134
|
+
name: "LOCAL PATCH SET",
|
|
15135
|
+
extra: "could not capture built-in postconditions"
|
|
15136
|
+
}]
|
|
15137
|
+
};
|
|
15138
|
+
}
|
|
15139
|
+
}
|
|
15140
|
+
local ??= opts.localPatches ? await applyLocalPatches(builtIn.content, opts.localPatches) : { content: builtIn.content, results: [] };
|
|
15141
|
+
if (local.results.some((result) => result.status === "OK") && builtInPatchVerificationFailed(
|
|
15142
|
+
local.content,
|
|
15143
|
+
desired.config,
|
|
15144
|
+
builtIn.results,
|
|
15145
|
+
builtInProofs
|
|
15146
|
+
)) {
|
|
15147
|
+
local = discardLocalPatchOutcome(builtIn.content, local.results);
|
|
15148
|
+
}
|
|
15149
|
+
results = [...results, ...local.results];
|
|
15150
|
+
await writeContent(loaded.installation, local.content);
|
|
15151
|
+
patchedSize = statSync5(candidatePath).size;
|
|
14703
15152
|
patchedSha256 = sha256File(candidatePath);
|
|
14704
15153
|
renameSync3(candidatePath, binaryPath);
|
|
14705
15154
|
} catch (err) {
|
|
@@ -14799,6 +15248,9 @@ async function runPatchCommand(opts = {}) {
|
|
|
14799
15248
|
return 1;
|
|
14800
15249
|
}
|
|
14801
15250
|
const { binaryPath, version } = target;
|
|
15251
|
+
if (opts.localPatches !== void 0) {
|
|
15252
|
+
savePreferences({ localPatchesEnabled: opts.localPatches });
|
|
15253
|
+
}
|
|
14802
15254
|
const desired = buildDesiredPatchConfig();
|
|
14803
15255
|
if (Object.keys(desired.config).length === 0) {
|
|
14804
15256
|
p11.log.error("No favorite models to patch. Save favorites with `clodex models` first.");
|
|
@@ -14808,13 +15260,20 @@ async function runPatchCommand(opts = {}) {
|
|
|
14808
15260
|
p11.log.warn(`No context window metadata for ${id} \u2014 Claude Code will assume the 200k default.`);
|
|
14809
15261
|
}
|
|
14810
15262
|
reportRejectedModelAliases(desired.rejectedAliasRejections);
|
|
14811
|
-
const
|
|
15263
|
+
const localPatches = inspectLocalPatchSource(
|
|
15264
|
+
loadPreferences().localPatchesEnabled === true
|
|
15265
|
+
);
|
|
15266
|
+
const configHash = computePatchConfigHash(
|
|
15267
|
+
desired.config,
|
|
15268
|
+
PATCH_TRANSFORMS_VERSION,
|
|
15269
|
+
localPatches.enabled ? localPatches.configIdentity : void 0
|
|
15270
|
+
);
|
|
14812
15271
|
const manifest = readPatchManifest();
|
|
14813
15272
|
const state = evaluatePatchState(manifest, {
|
|
14814
15273
|
binaryPath,
|
|
14815
15274
|
claudeVersion: version,
|
|
14816
15275
|
configHash,
|
|
14817
|
-
binarySize:
|
|
15276
|
+
binarySize: statSync5(binaryPath).size
|
|
14818
15277
|
});
|
|
14819
15278
|
if (state === "current") {
|
|
14820
15279
|
p11.log.success(`claude ${version} is already patched with the current model config \u2014 nothing to do.`);
|
|
@@ -14828,7 +15287,8 @@ async function runPatchCommand(opts = {}) {
|
|
|
14828
15287
|
try {
|
|
14829
15288
|
const outcome = await applyPatch(binaryPath, version, desired, configHash, {
|
|
14830
15289
|
trace: opts.trace ?? false,
|
|
14831
|
-
manifest
|
|
15290
|
+
manifest,
|
|
15291
|
+
localPatches
|
|
14832
15292
|
});
|
|
14833
15293
|
if (!outcome.ok) {
|
|
14834
15294
|
p11.log.error(outcome.message);
|
|
@@ -14856,13 +15316,20 @@ async function runLaunchPatchCheck(opts = {}) {
|
|
|
14856
15316
|
return;
|
|
14857
15317
|
}
|
|
14858
15318
|
const resolved = target;
|
|
14859
|
-
const
|
|
15319
|
+
const localPatches = inspectLocalPatchSource(
|
|
15320
|
+
loadPreferences().localPatchesEnabled === true
|
|
15321
|
+
);
|
|
15322
|
+
const configHash = computePatchConfigHash(
|
|
15323
|
+
desired.config,
|
|
15324
|
+
PATCH_TRANSFORMS_VERSION,
|
|
15325
|
+
localPatches.enabled ? localPatches.configIdentity : void 0
|
|
15326
|
+
);
|
|
14860
15327
|
const manifest = readPatchManifest();
|
|
14861
15328
|
const state = evaluatePatchState(manifest, {
|
|
14862
15329
|
binaryPath: resolved.binaryPath,
|
|
14863
15330
|
claudeVersion: resolved.version,
|
|
14864
15331
|
configHash,
|
|
14865
|
-
binarySize:
|
|
15332
|
+
binarySize: statSync5(resolved.binaryPath).size
|
|
14866
15333
|
});
|
|
14867
15334
|
if (state === "current") return;
|
|
14868
15335
|
const interactive = !opts.dryRun && !opts.agentStdout && process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
@@ -15068,9 +15535,22 @@ function parseArgs(args) {
|
|
|
15068
15535
|
if (arg === "--help" || arg === "-h") parsed2.showHelp = true;
|
|
15069
15536
|
else if (arg === "--version" || arg === "-v") parsed2.showVersion = true;
|
|
15070
15537
|
else if (arg === "--restore") parsed2.patchRestore = true;
|
|
15071
|
-
else if (arg === "--
|
|
15538
|
+
else if (arg === "--enable-local-patches") {
|
|
15539
|
+
if (parsed2.patchLocalPatches === false && !parsed2.error) {
|
|
15540
|
+
parsed2.error = "--enable-local-patches and --disable-local-patches cannot be combined";
|
|
15541
|
+
}
|
|
15542
|
+
parsed2.patchLocalPatches = true;
|
|
15543
|
+
} else if (arg === "--disable-local-patches") {
|
|
15544
|
+
if (parsed2.patchLocalPatches === true && !parsed2.error) {
|
|
15545
|
+
parsed2.error = "--enable-local-patches and --disable-local-patches cannot be combined";
|
|
15546
|
+
}
|
|
15547
|
+
parsed2.patchLocalPatches = false;
|
|
15548
|
+
} else if (arg === "--trace") parsed2.trace = true;
|
|
15072
15549
|
else if (!parsed2.error) parsed2.error = `Unknown patch option: ${arg}`;
|
|
15073
15550
|
}
|
|
15551
|
+
if (parsed2.patchRestore && parsed2.patchLocalPatches !== void 0 && !parsed2.error) {
|
|
15552
|
+
parsed2.error = "--restore cannot be combined with local-patch settings";
|
|
15553
|
+
}
|
|
15074
15554
|
return parsed2;
|
|
15075
15555
|
}
|
|
15076
15556
|
if (first !== "claude") {
|
|
@@ -15113,7 +15593,7 @@ Bridge Claude Code to OpenAI models \u2014 OpenAI API key or ChatGPT/Codex-plan
|
|
|
15113
15593
|
${pc13.bold("Usage:")}
|
|
15114
15594
|
clodex claude [options] [claude-flags]
|
|
15115
15595
|
clodex server [options]
|
|
15116
|
-
clodex patch [
|
|
15596
|
+
clodex patch [options]
|
|
15117
15597
|
clodex models
|
|
15118
15598
|
clodex favorites
|
|
15119
15599
|
clodex providers
|
|
@@ -15325,11 +15805,15 @@ real ids, and reporting the correct context window.
|
|
|
15325
15805
|
${pc13.bold("Usage:")}
|
|
15326
15806
|
clodex patch
|
|
15327
15807
|
clodex patch --restore
|
|
15808
|
+
clodex patch --enable-local-patches
|
|
15809
|
+
clodex patch --disable-local-patches
|
|
15328
15810
|
clodex patch --help
|
|
15329
15811
|
|
|
15330
15812
|
${pc13.bold("Options:")}
|
|
15331
|
-
--restore
|
|
15332
|
-
--trace
|
|
15813
|
+
--restore Restore the pristine Claude Code binary
|
|
15814
|
+
--trace Show per-patch-site results (OK/SKIP/FAIL)
|
|
15815
|
+
--enable-local-patches Persistently enable ~/.clodex/local-patches.mjs
|
|
15816
|
+
--disable-local-patches Disable local patches and rebuild without them
|
|
15333
15817
|
|
|
15334
15818
|
${pc13.bold("Behavior:")}
|
|
15335
15819
|
The patch map is built automatically from your clodex favorites and aliases
|
|
@@ -15337,6 +15821,10 @@ ${pc13.bold("Behavior:")}
|
|
|
15337
15821
|
per-version backup is kept, and a manifest (~/.clodex/patch-state.json)
|
|
15338
15822
|
makes re-runs no-ops until your config or Claude Code version changes \u2014
|
|
15339
15823
|
then the binary is restored first and re-patched fresh.
|
|
15824
|
+
|
|
15825
|
+
Local patches execute after the built-ins as an all-or-none set. Enabling
|
|
15826
|
+
them executes trusted JavaScript from local-patches.mjs with your full user
|
|
15827
|
+
permissions. Local failures are reported but never block the built-ins.
|
|
15340
15828
|
Run clodex patch again after every claude update.`;
|
|
15341
15829
|
}
|
|
15342
15830
|
function printHelp(text4) {
|
|
@@ -16143,7 +16631,11 @@ Error: ${parsed.error}
|
|
|
16143
16631
|
printHelp(patchHelpText());
|
|
16144
16632
|
return 0;
|
|
16145
16633
|
}
|
|
16146
|
-
return runPatchCommand({
|
|
16634
|
+
return runPatchCommand({
|
|
16635
|
+
restore: parsed.patchRestore,
|
|
16636
|
+
trace: parsed.trace,
|
|
16637
|
+
localPatches: parsed.patchLocalPatches
|
|
16638
|
+
});
|
|
16147
16639
|
}
|
|
16148
16640
|
if (parsed.showVersion) {
|
|
16149
16641
|
console.log(VERSION);
|