makecoder 5.0.22 → 5.0.24

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.
@@ -1,142 +0,0 @@
1
- #!/usr/bin/env node
2
- /** Assemble a MakeCoder UI runtime from the official platform binary and patch sidecars. */
3
- import fs from "node:fs";
4
- import path from "node:path";
5
- import { fileURLToPath } from "node:url";
6
- import { execFileSync } from "node:child_process";
7
- import { bootstrapSource, inspectModuleGraph, loaderSource, replaceEntry, sha256 } from "./claude-native-runtime.mjs";
8
-
9
- const excluded = new Set(["cc-runtime.json", "cc-native", "cc-native.exe",
10
- "cc-native.mjs", "cc-native.exe.mjs"]);
11
- const windowsLockErrors = new Set(["EPERM", "EACCES", "EBUSY"]);
12
- const retrySignal = new Int32Array(new SharedArrayBuffer(4));
13
-
14
- export function renameWithWindowsRetry(source, target, {
15
- platform = process.platform,
16
- rename = fs.renameSync,
17
- pause = ms => Atomics.wait(retrySignal, 0, 0, ms),
18
- } = {}) {
19
- for (let attempt = 0; ; attempt++) {
20
- try {
21
- return rename(source, target);
22
- } catch (error) {
23
- if (platform !== "win32" || !windowsLockErrors.has(error.code) || attempt >= 20) throw error;
24
- // A just-exited executable can still have an open handle on Windows.
25
- pause(500);
26
- }
27
- }
28
- }
29
-
30
- export function assembleNative(officialDir, sidecarDir, outputDir) {
31
- const official = fs.realpathSync(officialDir);
32
- const sidecars = fs.realpathSync(sidecarDir);
33
- const output = path.resolve(outputDir);
34
- if (output === official || output.startsWith(official + path.sep) ||
35
- (output !== sidecars && output.startsWith(sidecars + path.sep))) {
36
- throw new Error("Output cannot be inside the official package or patch sidecars");
37
- }
38
- const pkg = JSON.parse(fs.readFileSync(path.join(official, "package.json"), "utf8"));
39
- const platform = pkg.name?.replace(/^@anthropic-ai\/claude-code-/, "");
40
- if (!/^@anthropic-ai\/claude-code-(darwin-(arm64|x64)|linux-(arm64|x64)|win32-x64)$/.test(pkg.name) ||
41
- !/^\d+\.\d+\.\d+$/.test(pkg.version)) {
42
- throw new Error("Expected a versioned official Claude platform package");
43
- }
44
- const patch = JSON.parse(fs.readFileSync(path.join(sidecars, "cc-runtime.json"), "utf8"));
45
- if (patch.schemaVersion !== 1 || patch.mode !== "anthropic-native" ||
46
- patch.platform !== platform || patch.version !== pkg.version || patch.package !== pkg.name) {
47
- throw new Error("Patch sidecars and official package must have the same platform and version");
48
- }
49
- const sourceBinary = path.join(official, platform === "win32-x64" ? "claude.exe" : "claude");
50
- const upstream = fs.readFileSync(sourceBinary);
51
- if (sha256(upstream) !== patch.upstreamSha256 || inspectModuleGraph(upstream).platform !== platform) {
52
- throw new Error("Official binary does not match the binary used to build the patch sidecars");
53
- }
54
- if (sha256(fs.readFileSync(path.join(sidecars, "cc.js"))) !== patch.bundleSha256) {
55
- throw new Error("Patch sidecar bundle hash mismatch");
56
- }
57
- if (platform.startsWith("darwin")) {
58
- if (process.platform !== "darwin") throw new Error("macOS assembly requires macOS codesign");
59
- execFileSync("codesign", ["--verify", "--strict", sourceBinary], { stdio: "inherit" });
60
- }
61
- if (fs.existsSync(output)) {
62
- const previous = JSON.parse(fs.readFileSync(path.join(output, "cc-runtime.json"), "utf8"));
63
- if (previous.schemaVersion !== 1 || previous.mode !== "anthropic-native") {
64
- throw new Error(`Output is not a generated native artifact: ${output}`);
65
- }
66
- }
67
- fs.mkdirSync(path.dirname(output), { recursive: true });
68
- const staging = fs.mkdtempSync(path.join(path.dirname(output), ".claude-assembled-"));
69
- const backup = staging + "-previous";
70
- let assemblyError;
71
- try {
72
- for (const name of fs.readdirSync(sidecars)) {
73
- if (!excluded.has(name)) fs.cpSync(path.join(sidecars, name), path.join(staging, name), { recursive: true });
74
- }
75
- const executable = platform === "win32-x64" ? "cc-native.exe" : "cc-native";
76
- const nativePath = path.join(staging, executable);
77
- fs.writeFileSync(nativePath + ".mjs", loaderSource(patch.bundleSha256));
78
- fs.writeFileSync(nativePath,
79
- replaceEntry(upstream, bootstrapSource(patch.bundleSha256, pkg.version), platform), { mode: 0o755 });
80
- if (platform.startsWith("darwin")) {
81
- execFileSync("codesign", ["--force", "--sign", process.env.CODER_CODESIGN_IDENTITY || "-", nativePath], { stdio: "inherit" });
82
- execFileSync("codesign", ["--verify", "--strict", nativePath], { stdio: "inherit" });
83
- }
84
- const manifest = {
85
- schemaVersion: 1, mode: "anthropic-native", platform, version: pkg.version,
86
- package: pkg.name, source: patch.source, upstreamSha256: patch.upstreamSha256,
87
- bundleSha256: patch.bundleSha256, executable,
88
- runtimeSha256: sha256(fs.readFileSync(nativePath)),
89
- loaderSha256: sha256(fs.readFileSync(nativePath + ".mjs")),
90
- signing: platform.startsWith("darwin") ? (process.env.CODER_CODESIGN_IDENTITY ? "identity" : "ad-hoc") :
91
- platform === "win32-x64" ? "unsigned" : "not-applicable",
92
- };
93
- if (platform === `${process.platform}-${process.arch}`) {
94
- const probe = JSON.parse(execFileSync(nativePath, ["--coder-runtime-info"], { encoding: "utf8", timeout: 30000 }));
95
- if (probe.cellSegmenter !== "function" || probe.bundleSha256 !== patch.bundleSha256 ||
96
- `${probe.platform}-${probe.arch}` !== platform || probe.version !== pkg.version) {
97
- throw new Error("Assembled native runtime capability probe failed");
98
- }
99
- manifest.bunVersion = probe.bun;
100
- const version = execFileSync(nativePath, ["--version"], { encoding: "utf8", timeout: 30000 });
101
- if (!version.includes(`${pkg.version} (Claude Code)`)) {
102
- throw new Error("Assembled native runtime failed to load the MakeCoder CLI");
103
- }
104
- }
105
- fs.writeFileSync(path.join(staging, "cc-runtime.json"), JSON.stringify(manifest, null, 2) + "\n");
106
- // mkdtemp creates a 0700 directory. Docker image builds assemble as root,
107
- // but the CLI runs as an unprivileged user after the image is published.
108
- if (process.platform !== "win32") fs.chmodSync(staging, 0o755);
109
- if (fs.existsSync(output)) renameWithWindowsRetry(output, backup);
110
- try { renameWithWindowsRetry(staging, output); }
111
- catch (error) {
112
- if (fs.existsSync(backup)) {
113
- try { renameWithWindowsRetry(backup, output); }
114
- catch (restoreError) {
115
- throw new AggregateError([error, restoreError], "Failed to install Claude runtime and restore the previous artifact");
116
- }
117
- }
118
- throw error;
119
- }
120
- fs.rmSync(backup, { recursive: true, force: true, maxRetries: 10, retryDelay: 500 });
121
- console.log(`Assembled ${pkg.name}@${pkg.version} -> ${output}`);
122
- } catch (error) {
123
- assemblyError = error;
124
- throw error;
125
- } finally {
126
- try {
127
- // Windows can briefly lock an executable after execFileSync returns.
128
- fs.rmSync(staging, { recursive: true, force: true, maxRetries: 10, retryDelay: 500 });
129
- } catch (cleanupError) {
130
- if (!assemblyError) throw cleanupError;
131
- console.warn(`Could not clean staging directory ${staging}: ${cleanupError.message}`);
132
- }
133
- }
134
- }
135
-
136
- if (process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) {
137
- const [official, sidecars, output, ...rest] = process.argv.slice(2);
138
- if (!official || !sidecars || !output || rest.length) {
139
- throw new Error("Usage: assemble-claude-native.mjs <official-platform-package> <patch-sidecars> <output>");
140
- }
141
- assembleNative(official, sidecars, output);
142
- }
@@ -1,230 +0,0 @@
1
- /**
2
- * Keep Anthropic's runtime and replace only its standalone entry module.
3
- * No sections move, no public Bun compiler rewrites private runtime metadata,
4
- * and all original embedded assets remain available. Unknown layouts fail
5
- * closed. The on-disk cc.js and its sidecars retain their existing semantics.
6
- */
7
- import { createHash } from "node:crypto";
8
-
9
- const TRAILER = Buffer.from("\n---- Bun! ----\n");
10
- const MODULE_SIZE = 52;
11
- const OFFSETS_SIZE = 32;
12
-
13
- function check(condition, message) {
14
- if (!condition) throw new Error(`Unsupported Claude native runtime: ${message}`);
15
- }
16
-
17
- function range(buffer, offset, size, label) {
18
- check(Number.isSafeInteger(offset) && Number.isSafeInteger(size) &&
19
- offset >= 0 && size >= 0 && offset <= buffer.length - size,
20
- `${label} is outside the binary`);
21
- }
22
-
23
- function u64(buffer, offset) {
24
- range(buffer, offset, 8, "uint64");
25
- const value = Number(buffer.readBigUInt64LE(offset));
26
- check(Number.isSafeInteger(value), "uint64 exceeds safe integer range");
27
- return value;
28
- }
29
-
30
- function name(buffer, offset, size) {
31
- range(buffer, offset, size, "section name");
32
- const bytes = buffer.subarray(offset, offset + size);
33
- return bytes.subarray(0, bytes.indexOf(0) < 0 ? size : bytes.indexOf(0)).toString();
34
- }
35
-
36
- /** Locate the file-backed Bun section using platform headers, not byte scans. */
37
- export function inspectExecutable(buffer) {
38
- range(buffer, 0, 64, "executable header");
39
- let platform;
40
- let signatureDirectory;
41
- let checksumOffset;
42
- const sections = [];
43
- if (buffer.readUInt32LE(0) === 0xfeedfacf) {
44
- const cpu = buffer.readUInt32LE(4);
45
- check(cpu === 0x100000c || cpu === 0x1000007, "unknown Mach-O CPU");
46
- platform = cpu === 0x100000c ? "darwin-arm64" : "darwin-x64";
47
- check(buffer.readUInt32LE(12) === 2, "Mach-O is not executable");
48
- const end = 32 + buffer.readUInt32LE(20);
49
- range(buffer, 32, end - 32, "Mach-O commands");
50
- let cursor = 32;
51
- for (let i = 0; i < buffer.readUInt32LE(16); i++) {
52
- check(cursor + 8 <= end, "truncated Mach-O command");
53
- const cmd = buffer.readUInt32LE(cursor);
54
- const size = buffer.readUInt32LE(cursor + 4);
55
- check(size >= 8 && size % 8 === 0 && cursor + size <= end, "invalid Mach-O command size");
56
- if (cmd === 0x19) {
57
- check(size >= 72, "truncated segment command");
58
- const count = buffer.readUInt32LE(cursor + 64);
59
- check(size === 72 + count * 80, "unexpected segment command layout");
60
- if (name(buffer, cursor + 8, 16) === "__BUN") {
61
- check(count === 1, "expected one __BUN section");
62
- const offset = u64(buffer, cursor + 40);
63
- const length = u64(buffer, cursor + 48);
64
- check(buffer.readUInt32LE(cursor + 72 + 48) === offset &&
65
- u64(buffer, cursor + 72 + 40) <= length, "__BUN section/segment mismatch");
66
- sections.push({ offset, length });
67
- }
68
- }
69
- cursor += size;
70
- }
71
- check(cursor === end, "Mach-O command count mismatch");
72
- } else if (buffer.subarray(0, 4).equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46]))) {
73
- check(buffer[4] === 2 && buffer[5] === 1 && buffer[6] === 1,
74
- "expected little-endian ELF64");
75
- const cpu = buffer.readUInt16LE(18);
76
- check(cpu === 62 || cpu === 183, "unknown ELF CPU");
77
- check([2, 3].includes(buffer.readUInt16LE(16)), "ELF is not executable");
78
- platform = cpu === 183 ? "linux-arm64" : "linux-x64";
79
- const table = u64(buffer, 40);
80
- const count = buffer.readUInt16LE(60);
81
- const stringsIndex = buffer.readUInt16LE(62);
82
- check(buffer.readUInt16LE(58) === 64 && count > 0 && stringsIndex < count,
83
- "unsupported ELF section table");
84
- range(buffer, table, count * 64, "ELF sections");
85
- const stringsHeader = table + stringsIndex * 64;
86
- const strings = u64(buffer, stringsHeader + 24);
87
- const stringsSize = u64(buffer, stringsHeader + 32);
88
- range(buffer, strings, stringsSize, "ELF section names");
89
- for (let i = 0; i < count; i++) {
90
- const header = table + i * 64;
91
- const nameOffset = buffer.readUInt32LE(header);
92
- check(nameOffset < stringsSize, "ELF section name outside string table");
93
- if (name(buffer, strings + nameOffset, Math.min(5, stringsSize - nameOffset)) === ".bun" &&
94
- buffer[strings + nameOffset + 4] === 0) {
95
- check(buffer.readUInt32LE(header + 4) === 1, ".bun is not PROGBITS");
96
- sections.push({ offset: u64(buffer, header + 24), length: u64(buffer, header + 32) });
97
- }
98
- }
99
- } else if (buffer.readUInt16LE(0) === 0x5a4d) {
100
- const pe = buffer.readUInt32LE(0x3c);
101
- range(buffer, pe, 24, "PE header");
102
- check(buffer.readUInt32LE(pe) === 0x4550 && buffer.readUInt16LE(pe + 4) === 0x8664,
103
- "expected x64 PE");
104
- platform = "win32-x64";
105
- const optional = pe + 24;
106
- const optionalSize = buffer.readUInt16LE(pe + 20);
107
- range(buffer, optional, optionalSize, "PE optional header");
108
- check(optionalSize >= 152 && buffer.readUInt16LE(optional) === 0x20b &&
109
- buffer.readUInt32LE(optional + 108) >= 5, "unsupported PE optional header");
110
- signatureDirectory = optional + 112 + 4 * 8;
111
- checksumOffset = optional + 64;
112
- const table = optional + optionalSize;
113
- const count = buffer.readUInt16LE(pe + 6);
114
- range(buffer, table, count * 40, "PE sections");
115
- for (let i = 0; i < count; i++) {
116
- const header = table + i * 40;
117
- if (name(buffer, header, 8) === ".bun") {
118
- sections.push({ offset: buffer.readUInt32LE(header + 20), length: buffer.readUInt32LE(header + 16) });
119
- }
120
- }
121
- } else {
122
- throw new Error("Unsupported Claude native runtime: expected Mach-O, ELF64 or PE64");
123
- }
124
- check(sections.length === 1, "expected exactly one Bun section");
125
- const section = sections[0];
126
- range(buffer, section.offset, section.length, "Bun section");
127
- check(section.length >= 8 + OFFSETS_SIZE + TRAILER.length, "Bun section is too short");
128
- return { platform, ...section, signatureDirectory, checksumOffset };
129
- }
130
-
131
- export function inspectModuleGraph(buffer) {
132
- const executable = inspectExecutable(buffer);
133
- const { offset, length } = executable;
134
- const graphSize = u64(buffer, offset);
135
- check(graphSize >= OFFSETS_SIZE + TRAILER.length && graphSize <= length - 8,
136
- "invalid Bun graph size");
137
- const start = offset + 8;
138
- const trailer = start + graphSize - TRAILER.length;
139
- check(buffer.subarray(trailer, trailer + TRAILER.length).equals(TRAILER), "Bun trailer mismatch");
140
- const offsets = trailer - OFFSETS_SIZE;
141
- check(u64(buffer, offsets) === offsets - start, "Bun byte count mismatch");
142
- const table = start + buffer.readUInt32LE(offsets + 8);
143
- const tableSize = buffer.readUInt32LE(offsets + 12);
144
- const entryIndex = buffer.readUInt32LE(offsets + 16);
145
- check(tableSize > 0 && tableSize % MODULE_SIZE === 0 && table >= start &&
146
- table + tableSize <= offsets, "unsupported Bun module table");
147
- check(entryIndex < tableSize / MODULE_SIZE, "entry index outside module table");
148
- const entry = table + entryIndex * MODULE_SIZE;
149
- const regions = [];
150
- for (let row = table; row < table + tableSize; row += MODULE_SIZE) {
151
- // path, source, sourcemap, bytecode, bytecode module map, module path.
152
- for (const field of [0, 8, 16, 24, 32, 40]) {
153
- const pos = buffer.readUInt32LE(row + field);
154
- const size = buffer.readUInt32LE(row + field + 4);
155
- check(pos <= table - start && size <= table - start - pos,
156
- "module data overlaps metadata or exceeds graph");
157
- if (size > 0) regions.push({ row, field, start: start + pos, end: start + pos + size });
158
- }
159
- }
160
- const sourceOffset = start + buffer.readUInt32LE(entry + 8);
161
- const sourceSize = buffer.readUInt32LE(entry + 12);
162
- check(sourceSize > 0 && buffer[sourceOffset + sourceSize] === 0, "entry source is not null terminated");
163
- for (const region of regions) {
164
- if (region.row === entry && region.field === 8) continue;
165
- check(region.end <= sourceOffset || region.start > sourceOffset + sourceSize,
166
- "entry source overlaps another module field");
167
- }
168
- check(buffer.subarray(entry + 48, entry + 52).equals(Buffer.from([1, 1, 1, 0])),
169
- "expected UTF-8 JavaScript ESM entry (module ABI changed)");
170
- const pathOffset = start + buffer.readUInt32LE(entry);
171
- const entryPath = buffer.subarray(pathOffset, pathOffset + buffer.readUInt32LE(entry + 4)).toString();
172
- check(/^(\/\$bunfs\/root\/|B:\/~BUN\/root\/|file:\/\/\/B:\/%7EBUN\/root\/)/.test(entryPath),
173
- "unexpected standalone entry path");
174
- return { ...executable, start, offsets, table, tableSize, entry, entryPath, sourceOffset, sourceSize };
175
- }
176
-
177
- export function sha256(buffer) {
178
- return createHash("sha256").update(buffer).digest("hex");
179
- }
180
-
181
- /** The hash binds the native entry to exactly the patched bundle we packaged. */
182
- export function bootstrapSource(bundleSha256, version) {
183
- check(/^[a-f0-9]{64}$/.test(bundleSha256), "invalid bundle SHA-256");
184
- // Native graph entries carry an upstream builtin-import map. A dynamic
185
- // filesystem import enters Bun's normal loader without reusing that map.
186
- return `if (typeof Bun.ant?.CellSegmenter !== "function") throw new Error("Claude requires Anthropic's private Bun.ant.CellSegmenter runtime");
187
- if (process.argv[2] === "--coder-runtime-info") {
188
- console.log(JSON.stringify({version:${JSON.stringify(version)},bun:Bun.version,platform:process.platform,arch:process.arch,cellSegmenter:typeof Bun.ant.CellSegmenter,bundleSha256:${JSON.stringify(bundleSha256)}}));
189
- } else {
190
- globalThis[Symbol.for("coder.claude.bundleSha256")] = ${JSON.stringify(bundleSha256)};
191
- await import(process.execPath + ".mjs");
192
- }
193
- `;
194
- }
195
-
196
- export function loaderSource(bundleSha256) {
197
- check(/^[a-f0-9]{64}$/.test(bundleSha256), "invalid bundle SHA-256");
198
- return `import { dirname, join } from "node:path";
199
- import { pathToFileURL } from "node:url";
200
- import { readFileSync } from "node:fs";
201
- import { createHash } from "node:crypto";
202
- const bundle = join(dirname(process.execPath), "cc.js");
203
- if (globalThis[Symbol.for("coder.claude.bundleSha256")] !== ${JSON.stringify(bundleSha256)}) throw new Error("Claude native runtime / loader hash mismatch; reinstall the complete platform artifact");
204
- if (createHash("sha256").update(readFileSync(bundle)).digest("hex") !== ${JSON.stringify(bundleSha256)}) throw new Error("Claude native runtime / cc.js hash mismatch; rebuild and copy the complete platform artifact");
205
- await import(pathToFileURL(bundle).href);
206
- `;
207
- }
208
-
209
- export function replaceEntry(buffer, source, expectedPlatform) {
210
- const graph = inspectModuleGraph(buffer);
211
- check(graph.platform === expectedPlatform, `expected ${expectedPlatform}, found ${graph.platform}`);
212
- const code = Buffer.from(source);
213
- check(code.length > 0 && code.length <= graph.sourceSize, "replacement exceeds entry source allocation");
214
- const result = Buffer.from(buffer);
215
- result.fill(0, graph.sourceOffset, graph.sourceOffset + graph.sourceSize);
216
- code.copy(result, graph.sourceOffset);
217
- result.writeUInt32LE(code.length, graph.entry + 12);
218
- // Invalidate the entry's source map, compiled bytecode and bytecode module
219
- // map; otherwise JSC can execute the old Claude entry despite the new source.
220
- result.fill(0, graph.entry + 16, graph.entry + 40);
221
- if (graph.signatureDirectory !== undefined) {
222
- // The upstream Authenticode signature is no longer valid. Leave overlay
223
- // bytes in place, detach its certificate table, and let release signing
224
- // apply the project's identity. A zero PE checksum is valid for user apps.
225
- result.fill(0, graph.signatureDirectory, graph.signatureDirectory + 8);
226
- result.writeUInt32LE(0, graph.checksumOffset);
227
- }
228
- inspectModuleGraph(result);
229
- return result;
230
- }