@bman654/clodex 2.5.1 → 2.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -374,7 +374,7 @@ import { join } from "path";
374
374
  // package.json
375
375
  var package_default = {
376
376
  name: "@bman654/clodex",
377
- version: "2.5.1",
377
+ version: "2.5.2",
378
378
  publishConfig: {
379
379
  access: "public"
380
380
  },
@@ -15600,11 +15600,11 @@ import {
15600
15600
  readFileSync as readFileSync10,
15601
15601
  renameSync as renameSync3,
15602
15602
  rmSync,
15603
- statSync as statSync5,
15603
+ statSync as statSync6,
15604
15604
  unlinkSync as unlinkSync4,
15605
15605
  writeFileSync as writeFileSync7,
15606
- openSync as openSync4,
15607
- closeSync as closeSync4,
15606
+ openSync as openSync5,
15607
+ closeSync as closeSync5,
15608
15608
  realpathSync
15609
15609
  } from "fs";
15610
15610
  import { homedir as homedir3 } from "os";
@@ -15987,9 +15987,152 @@ function builtInPatchProofsChanged(source, proofs) {
15987
15987
  );
15988
15988
  }
15989
15989
 
15990
+ // src/bun-entry-module.ts
15991
+ import { closeSync as closeSync4, openSync as openSync4, readSync, statSync as statSync4, writeSync as writeSync3 } from "fs";
15992
+ import { execFileSync } from "child_process";
15993
+ var BUN_TRAILER = Buffer.from("\n---- Bun! ----\n");
15994
+ var BUN_OFFSETS_BYTES = 32;
15995
+ var TAIL_SCAN_BYTES = 16 * 1024 * 1024;
15996
+ var MODULE_STRUCT_BYTES_CURRENT = 52;
15997
+ var MODULE_STRUCT_BYTES_LEGACY = 36;
15998
+ var MAX_MODULE_NAME_BYTES = 4096;
15999
+ var MIN_SHIMMABLE_NAME_BYTES = 7;
16000
+ function tweakccRecognizesModuleName(name) {
16001
+ return name.endsWith("/claude") || name === "claude" || name.endsWith("/claude.exe") || name === "claude.exe" || name.endsWith("/src/entrypoints/cli.js") || name === "src/entrypoints/cli.js";
16002
+ }
16003
+ function entryModuleShimName(byteLength) {
16004
+ if (byteLength < MIN_SHIMMABLE_NAME_BYTES) return null;
16005
+ const padding = byteLength - MIN_SHIMMABLE_NAME_BYTES;
16006
+ return "/clodex".padEnd(padding, "-").slice(0, padding) + "/claude";
16007
+ }
16008
+ function readAt(fd, length, position) {
16009
+ if (length <= 0 || position < 0) return null;
16010
+ const buffer = Buffer.alloc(length);
16011
+ const read = readSync(fd, buffer, 0, length, position);
16012
+ return read === length ? buffer : null;
16013
+ }
16014
+ function readBunModuleNames(fd, fileSize) {
16015
+ const tailLength = Math.min(fileSize, TAIL_SCAN_BYTES);
16016
+ const tail = readAt(fd, tailLength, fileSize - tailLength);
16017
+ if (!tail) return null;
16018
+ const tailAt = fileSize - tailLength;
16019
+ for (let searchFrom = tail.length - 1; searchFrom >= 0; ) {
16020
+ const trailerInTail = tail.lastIndexOf(BUN_TRAILER, searchFrom);
16021
+ if (trailerInTail < 0) return null;
16022
+ const parsed = parseBunModuleNamesAt(fd, tailAt + trailerInTail - BUN_OFFSETS_BYTES);
16023
+ if (parsed) return parsed;
16024
+ searchFrom = trailerInTail - 1;
16025
+ }
16026
+ return null;
16027
+ }
16028
+ function parseBunModuleNamesAt(fd, offsetsAt) {
16029
+ try {
16030
+ return parseBunModuleNamesAtUnchecked(fd, offsetsAt);
16031
+ } catch {
16032
+ return null;
16033
+ }
16034
+ }
16035
+ function parseBunModuleNamesAtUnchecked(fd, offsetsAt) {
16036
+ const offsets = readAt(fd, BUN_OFFSETS_BYTES, offsetsAt);
16037
+ if (!offsets) return null;
16038
+ const byteCount = offsets.readBigUInt64LE(0);
16039
+ const modulesOffset = offsets.readUInt32LE(8);
16040
+ const modulesLength = offsets.readUInt32LE(12);
16041
+ const entryPointId = offsets.readUInt32LE(16);
16042
+ if (byteCount <= 0n || byteCount > BigInt(offsetsAt)) return null;
16043
+ const blobAt = offsetsAt - Number(byteCount);
16044
+ if (modulesLength <= 0 || BigInt(modulesOffset) + BigInt(modulesLength) > byteCount) return null;
16045
+ const structBytes = modulesLength % MODULE_STRUCT_BYTES_LEGACY === 0 && modulesLength % MODULE_STRUCT_BYTES_CURRENT !== 0 ? MODULE_STRUCT_BYTES_LEGACY : MODULE_STRUCT_BYTES_CURRENT;
16046
+ const moduleCount = Math.floor(modulesLength / structBytes);
16047
+ if (moduleCount <= 0 || entryPointId >= moduleCount) return null;
16048
+ const modules = readAt(fd, moduleCount * structBytes, blobAt + modulesOffset);
16049
+ if (!modules) return null;
16050
+ const names = [];
16051
+ const nameOffsets = [];
16052
+ for (let index = 0; index < moduleCount; index++) {
16053
+ const nameOffset = modules.readUInt32LE(index * structBytes);
16054
+ const nameLength = modules.readUInt32LE(index * structBytes + 4);
16055
+ if (nameLength <= 0 || nameLength > MAX_MODULE_NAME_BYTES) return null;
16056
+ if (BigInt(nameOffset) + BigInt(nameLength) > byteCount) return null;
16057
+ const bytes = readAt(fd, nameLength + 1, blobAt + nameOffset);
16058
+ if (!bytes || bytes[nameLength] !== 0) return null;
16059
+ const name = bytes.subarray(0, nameLength).toString("utf8");
16060
+ if (!/^[\x20-\x7e]+$/.test(name)) return null;
16061
+ names.push(name);
16062
+ nameOffsets.push(blobAt + nameOffset);
16063
+ }
16064
+ return { names, entryPointId, offsets: nameOffsets };
16065
+ }
16066
+ function assertShimGone(fd, fileSize, marker) {
16067
+ const needle = Buffer.from(marker);
16068
+ const chunkBytes = 8 * 1024 * 1024;
16069
+ let carry = Buffer.alloc(0);
16070
+ for (let position = 0; position < fileSize; ) {
16071
+ const length = Math.min(chunkBytes, fileSize - position);
16072
+ const chunk = readAt(fd, length, position);
16073
+ if (!chunk) throw new Error("could not re-read the candidate to verify the entry-module name");
16074
+ const window = carry.length > 0 ? Buffer.concat([carry, chunk]) : chunk;
16075
+ if (window.includes(needle)) {
16076
+ throw new Error(`the entry-module stand-in ${marker} survived restoration`);
16077
+ }
16078
+ carry = Buffer.from(window.subarray(Math.max(0, window.length - (needle.length - 1))));
16079
+ position += length;
16080
+ }
16081
+ }
16082
+ function writeNameBytes(fd, name, offset) {
16083
+ const bytes = Buffer.from(name);
16084
+ const written = writeSync3(fd, bytes, 0, bytes.length, offset);
16085
+ if (written !== bytes.length) {
16086
+ throw new Error(`wrote ${written} of ${bytes.length} entry-module name bytes at ${offset}`);
16087
+ }
16088
+ }
16089
+ function isMachO(fd) {
16090
+ const magic = readAt(fd, 4, 0);
16091
+ if (!magic) return false;
16092
+ const value = magic.readUInt32BE(0);
16093
+ return value === 4277009102 || value === 4277009103 || value === 3472551422 || value === 3489328638 || value === 3405691582 || value === 3405691583;
16094
+ }
16095
+ function shimEntryModuleName(path) {
16096
+ const fd = openSync4(path, "r+");
16097
+ try {
16098
+ const parsed = readBunModuleNames(fd, statSync4(path).size);
16099
+ if (!parsed) return null;
16100
+ if (parsed.names.some(tweakccRecognizesModuleName)) return null;
16101
+ const original = parsed.names[parsed.entryPointId];
16102
+ const offset = parsed.offsets[parsed.entryPointId];
16103
+ const marker = entryModuleShimName(Buffer.byteLength(original));
16104
+ if (marker === null) return null;
16105
+ writeNameBytes(fd, marker, offset);
16106
+ return { offset, original, marker };
16107
+ } finally {
16108
+ closeSync4(fd);
16109
+ }
16110
+ }
16111
+ function restoreEntryModuleName(path, shim, { resign }) {
16112
+ const fd = openSync4(path, "r+");
16113
+ let machO;
16114
+ try {
16115
+ const parsed = readBunModuleNames(fd, statSync4(path).size);
16116
+ const offset = parsed?.offsets[parsed.entryPointId];
16117
+ if (!parsed || offset === void 0 || parsed.names[parsed.entryPointId] !== shim.marker) {
16118
+ throw new Error(
16119
+ `expected the entry module of ${path} to be named ${shim.marker}, found ${parsed ? JSON.stringify(parsed.names[parsed.entryPointId]) : "no readable Bun module list"}`
16120
+ );
16121
+ }
16122
+ writeNameBytes(fd, shim.original, offset);
16123
+ assertShimGone(fd, statSync4(path).size, shim.marker);
16124
+ machO = resign && isMachO(fd);
16125
+ } finally {
16126
+ closeSync4(fd);
16127
+ }
16128
+ if (machO && process.platform === "darwin") {
16129
+ execFileSync("codesign", ["-s", "-", "-f", path], { stdio: "ignore" });
16130
+ }
16131
+ }
16132
+
15990
16133
  // src/patch-backup.ts
15991
16134
  import { createHash as createHash8 } from "crypto";
15992
- import { existsSync as existsSync6, readFileSync as readFileSync9, readdirSync, statSync as statSync4 } from "fs";
16135
+ import { existsSync as existsSync6, readFileSync as readFileSync9, readdirSync, statSync as statSync5 } from "fs";
15993
16136
  import { homedir as homedir2 } from "os";
15994
16137
  import { join as join7 } from "path";
15995
16138
  var BACKUP_SHA_PREFIX_LENGTH = 16;
@@ -16027,7 +16170,7 @@ function scanPristineBackups(version, dir = backupDir()) {
16027
16170
  const path = join7(dir, entry);
16028
16171
  let sha256;
16029
16172
  try {
16030
- if (!statSync4(path).isFile()) continue;
16173
+ if (!statSync5(path).isFile()) continue;
16031
16174
  sha256 = sha256File(path);
16032
16175
  } catch {
16033
16176
  corrupt.push(path);
@@ -16619,10 +16762,10 @@ function tryAcquirePatchLock(lockPath = getPatchLockPath(), opts = {}) {
16619
16762
  mkdirSync7(join8(lockPath, ".."), { recursive: true, mode: 448 });
16620
16763
  for (let attempt = 0; attempt < 2; attempt++) {
16621
16764
  try {
16622
- const fd = openSync4(lockPath, "wx");
16765
+ const fd = openSync5(lockPath, "wx");
16623
16766
  const content = { pid: process.pid, startedAt: now };
16624
16767
  writeFileSync7(fd, JSON.stringify(content));
16625
- closeSync4(fd);
16768
+ closeSync5(fd);
16626
16769
  return () => {
16627
16770
  try {
16628
16771
  unlinkSync4(lockPath);
@@ -16658,7 +16801,7 @@ function resolveClaudeBinaryForPatch() {
16658
16801
  return { ok: false, reason: "binary-not-found" };
16659
16802
  }
16660
16803
  try {
16661
- if (!statSync5(resolved).isFile()) return { ok: false, reason: "binary-not-found" };
16804
+ if (!statSync6(resolved).isFile()) return { ok: false, reason: "binary-not-found" };
16662
16805
  } catch {
16663
16806
  return { ok: false, reason: "binary-not-found" };
16664
16807
  }
@@ -16767,8 +16910,11 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
16767
16910
  const candidatePath = join8(candidateDir, basename(binaryPath));
16768
16911
  const seedCandidate = async (from) => {
16769
16912
  copyFileSync(from, candidatePath);
16913
+ const shim = shimEntryModuleName(candidatePath);
16770
16914
  const installation = await tryDetectInstallation({ path: candidatePath });
16771
- return { installation, source: await readContent(installation) };
16915
+ const source = await readContent(installation);
16916
+ if (shim) restoreEntryModuleName(candidatePath, shim, { resign: false });
16917
+ return { installation, source };
16772
16918
  };
16773
16919
  const facts = collectPristineFacts({
16774
16920
  version,
@@ -16805,6 +16951,11 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
16805
16951
  return { ok: false, message: describePoisonedPristineSource(backup, version) };
16806
16952
  }
16807
16953
  } else if (plan.action === "snapshot") {
16954
+ if (sha256File(candidatePath) !== plan.pristineSha256) {
16955
+ throw new Error(
16956
+ `the patch candidate no longer matches the pristine bytes it was seeded from; refusing to publish it as ${plan.backupPath}`
16957
+ );
16958
+ }
16808
16959
  publishBackupFile(candidatePath, plan.backupPath);
16809
16960
  }
16810
16961
  const canonical = contentAddressedBackupPath(version, pristineSha256);
@@ -16855,8 +17006,10 @@ async function applyPatch(binaryPath, version, desired, configHash, opts) {
16855
17006
  local = discardLocalPatchOutcome(builtIn.content, local.results);
16856
17007
  }
16857
17008
  results = [...results, ...local.results];
17009
+ const writeShim = shimEntryModuleName(candidatePath);
16858
17010
  await writeContent(loaded.installation, local.content);
16859
- patchedSize = statSync5(candidatePath).size;
17011
+ if (writeShim) restoreEntryModuleName(candidatePath, writeShim, { resign: true });
17012
+ patchedSize = statSync6(candidatePath).size;
16860
17013
  patchedSha256 = sha256File(candidatePath);
16861
17014
  renameSync3(candidatePath, binaryPath);
16862
17015
  } catch (err) {
@@ -16981,7 +17134,7 @@ async function runPatchCommand(opts = {}) {
16981
17134
  binaryPath,
16982
17135
  claudeVersion: version,
16983
17136
  configHash,
16984
- binarySize: statSync5(binaryPath).size
17137
+ binarySize: statSync6(binaryPath).size
16985
17138
  });
16986
17139
  if (state === "current") {
16987
17140
  p11.log.success(`claude ${version} is already patched with the current model config \u2014 nothing to do.`);
@@ -17037,7 +17190,7 @@ async function runLaunchPatchCheck(opts = {}) {
17037
17190
  binaryPath: resolved.binaryPath,
17038
17191
  claudeVersion: resolved.version,
17039
17192
  configHash,
17040
- binarySize: statSync5(resolved.binaryPath).size
17193
+ binarySize: statSync6(resolved.binaryPath).size
17041
17194
  });
17042
17195
  if (state === "current") return;
17043
17196
  const interactive = !opts.dryRun && !opts.agentStdout && process.stdin.isTTY === true && process.stdout.isTTY === true;