makecoder 5.0.21 → 5.0.23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makecoder",
3
- "version": "5.0.21",
3
+ "version": "5.0.23",
4
4
  "description": "MakeCoder Coder: AI Agent Runtime OS that runs and orchestrates Claude Code, Codex, Gemini and more across CLI, API, Web and chat",
5
5
  "main": "./dist/coder.js",
6
6
  "bin": {
@@ -37,6 +37,8 @@
37
37
  "dependencies": {
38
38
  "@larksuiteoapi/node-sdk": "^1.59.0",
39
39
  "@wecom/aibot-node-sdk": "1.0.7",
40
+ "bidi-js": "^1.1.0",
41
+ "bun": "1.3.14",
40
42
  "commander": "^15.0.0",
41
43
  "node-fetch": "^3.3.2",
42
44
  "node-pty": "^1.1.0",
@@ -46,33 +48,26 @@
46
48
  "yazl": "^3.3.1",
47
49
  "zod": "^3.25.76"
48
50
  },
49
- "optionalDependencies": {
50
- "@anthropic-ai/claude-code-darwin-arm64": "2.1.283",
51
- "@anthropic-ai/claude-code-darwin-x64": "2.1.283",
52
- "@anthropic-ai/claude-code-linux-arm64": "2.1.283",
53
- "@anthropic-ai/claude-code-linux-x64": "2.1.283",
54
- "@anthropic-ai/claude-code-win32-x64": "2.1.283",
55
- "makecoder-bin-darwin-arm64": "5.0.21",
56
- "makecoder-bin-linux-arm64": "5.0.21",
57
- "makecoder-bin-linux-x64": "5.0.21",
58
- "makecoder-bin-win-x64": "5.0.21",
59
- "makecoder-c-bin-darwin-arm64": "5.0.21",
60
- "makecoder-c-bin-darwin-x64": "5.0.21",
61
- "makecoder-c-bin-linux-arm64": "5.0.21",
62
- "makecoder-c-bin-linux-x64": "5.0.21",
63
- "makecoder-c-bin-win-x64": "5.0.21"
64
- },
65
51
  "engines": {
66
52
  "node": ">=20.0.0"
67
53
  },
68
54
  "devDependencies": {
69
- "bun": ">=1.3.12",
70
55
  "chokidar": "^4.0.3"
71
56
  },
72
57
  "files": [
73
58
  "dist",
74
59
  "scripts/postinstall.js",
75
- "scripts/assemble-claude-native.mjs",
76
- "scripts/claude-native-runtime.mjs"
77
- ]
60
+ "scripts/claude-cell-segmenter-shim.js"
61
+ ],
62
+ "optionalDependencies": {
63
+ "makecoder-bin-darwin-arm64": "5.0.23",
64
+ "makecoder-bin-linux-arm64": "5.0.23",
65
+ "makecoder-bin-linux-x64": "5.0.23",
66
+ "makecoder-bin-win-x64": "5.0.23",
67
+ "makecoder-c-bin-darwin-arm64": "5.0.23",
68
+ "makecoder-c-bin-darwin-x64": "5.0.23",
69
+ "makecoder-c-bin-linux-arm64": "5.0.23",
70
+ "makecoder-c-bin-linux-x64": "5.0.23",
71
+ "makecoder-c-bin-win-x64": "5.0.23"
72
+ }
78
73
  }
@@ -0,0 +1,172 @@
1
+ // Public Bun adapter for Claude Code 2.1.284.
2
+ const SEG = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
3
+ const BIDI = require('bidi-js')();
4
+ class CellSegmenter {
5
+ constructor(opts) {
6
+ this.opts=opts;
7
+ this.graphemes=[' ',''];
8
+ for(let i=33;i<=126;i++) this.graphemes.push(String.fromCharCode(i));
9
+ this.graphemes.push('\t','\ufffd');
10
+ this.charIds=new Map(this.graphemes.map((v,i)=>[v,i]));
11
+ this.sgrKeys=[''];this.sgrCloseKeys=[''];this.uris=[''];
12
+ this.styleIds=new Map([['',0]]);this.uriIds=new Map([['',0]]);
13
+ this.styles=[];
14
+ }
15
+ internChar(ch){let id=this.charIds.get(ch);if(id===undefined){id=this.graphemes.length;this.graphemes.push(ch);this.charIds.set(ch,id)}return id}
16
+ internStyle(codes){const key=codes.map(x=>x.open).join('\0');let id=this.styleIds.get(key);if(id===undefined){id=this.sgrKeys.length;this.sgrKeys.push(key);this.sgrCloseKeys.push(codes.map(x=>x.close).join('\0'));this.styleIds.set(key,id)}return id}
17
+ applySgr(codes,params){
18
+ const close={1:22,2:22,3:23,4:24,5:25,7:27,8:28,9:29,21:24};
19
+ const group={1:'intensity',2:'intensity',3:'italic',4:'underline',21:'underline',5:'blink',7:'inverse',8:'conceal',9:'strike'};
20
+ const resets={22:['intensity'],23:['italic'],24:['underline'],25:['blink'],27:['inverse'],28:['conceal'],29:['strike'],39:['foreground'],49:['background']};
21
+ const result=[...codes];
22
+ const clear=name=>{const i=result.findIndex(x=>x.group===name);if(i>=0)result.splice(i,1)};
23
+ const add=(name,open,end)=>{const i=result.findIndex(x=>x.group===name);if(i>=0&&result[i].open===open)return;if(i>=0)result.splice(i,1);result.push({group:name,open,close:end})};
24
+ const nums=params===''?[0]:params.split(';').map(x=>x===''?0:Number(x));
25
+ for(let i=0;i<nums.length;i++){
26
+ const n=nums[i];
27
+ if(n===0){result.length=0;continue}
28
+ if(resets[n]){for(const name of resets[n])clear(name);continue}
29
+ if(n===38||n===48){
30
+ const mode=nums[i+1],length=mode===5?1:mode===2?3:0;
31
+ if(length&&i+1+length<nums.length){
32
+ const values=nums.slice(i,i+2+length);i+=1+length;
33
+ if(values.every(Number.isInteger)&&values.slice(2).every(x=>x>=0&&x<=255))add(n===38?'foreground':'background',`\x1b[${values.join(';')}m`,n===38?'\x1b[39m':'\x1b[49m');
34
+ }
35
+ continue;
36
+ }
37
+ if(close[n]){add(group[n],`\x1b[${n}m`,`\x1b[${close[n]}m`);continue}
38
+ if(n>=30&&n<=37||n>=90&&n<=97)add('foreground',`\x1b[${n}m`,'\x1b[39m');
39
+ else if(n>=40&&n<=47||n>=100&&n<=107)add('background',`\x1b[${n}m`,'\x1b[49m');
40
+ }
41
+ return result;
42
+ }
43
+ internUri(uri){let id=this.uriIds.get(uri);if(id===undefined){id=this.uris.length;this.uris.push(uri);this.uriIds.set(uri,id)}return id}
44
+ segment(text,cells,runs,reorder){
45
+ let visible='', codes=[],uri='',state=[];
46
+ for(let i=0;i<text.length;){
47
+ if(text[i]==='\x1b'){
48
+ const rest=text.slice(i);let m=/^\x1b\[[0-9;]*m/.exec(rest);
49
+ if(m){codes=this.applySgr(codes,m[0].slice(2,-1));i+=m[0].length;continue}
50
+ m=/^\x1b\]8;[^;]*;([^\x07\x1b]*)(?:\x07|\x1b\\)/.exec(rest);
51
+ if(m){uri=m[1];this.internUri(uri);i+=m[0].length;continue}
52
+ m=/^\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1b\\))/.exec(rest);
53
+ if(m){i+=m[0].length;continue}
54
+ i++;continue;
55
+ }
56
+ const codePoint=text.codePointAt(i),raw=String.fromCodePoint(codePoint);
57
+ const replaced=(this.opts.substitute||[]).some(([lo,hi])=>codePoint>=lo&&codePoint<=hi)?'\ufffd':raw;
58
+ state.push({codes,uri});
59
+ if(replaced.length===2)state.push({codes,uri});
60
+ visible+=replaced;i+=raw.length;
61
+ }
62
+ let tokens=[];let run=-1,lastStyle=-1,lastUri=-1;
63
+ for(const part of SEG.segment(visible)){
64
+ const ch=part.segment;
65
+ if(ch==='\n'||ch==='\r'||ch==='\r\n')continue;
66
+ // A joiner chain after a zero-width space is folded into that cluster;
67
+ // style changes on the joiners are not interned as separate entries.
68
+ if(/^\u200d+$/u.test(ch)){
69
+ let prior=part.index-1;
70
+ while(prior>=0&&visible[prior]==='\u200d')prior--;
71
+ if(prior>=0&&visible[prior]==='\u200b')continue;
72
+ }
73
+ const width=ch==='\t'?256:Math.min(2,Math.max(0,Bun.stringWidth(ch,{ambiguousIsNarrow:true})));
74
+ const {codes:style,uri:link}=state[part.index]||{codes:[],uri:''};
75
+ const sid=this.internStyle(style),uid=this.internUri(link);
76
+ if(width===0)continue;
77
+ if(sid!==lastStyle||uid!==lastUri){run++;lastStyle=sid;lastUri=uid}
78
+ runs[2*run]=sid;runs[2*run+1]=uid;
79
+ tokens.push({ch:this.internChar(ch),width,sid,uid,run,start:part.index,end:part.index+ch.length});
80
+ }
81
+ if(reorder&&tokens.length&&/[\u0590-\u08ff\ufb1d-\ufdff\ufe70-\ufeff]/u.test(visible)){
82
+ // The native object resolves one visual run across line breaks. bidi-js
83
+ // treats LF/CR as paragraph separators, so retain their positions as
84
+ // neutral spaces while calculating the order of the visible cells.
85
+ const bidiText=visible.replace(/[\n\r]/g,' ');
86
+ const strong=bidiText.match(/[\p{L}]/u)?.[0];
87
+ const direction=strong&&/[\u0590-\u08ff\ufb1d-\ufdff\ufe70-\ufeff]/u.test(strong)?'rtl':'ltr';
88
+ const levels=BIDI.getEmbeddingLevels(bidiText,direction);
89
+ const rtl=/[\u0590-\u08ff\ufb1d-\ufdff\ufe70-\ufeff]/u;
90
+ const nearestStrong=(at,step)=>{
91
+ for(let i=at;i>=0&&i<bidiText.length;i+=step){
92
+ if(/\p{L}/u.test(bidiText[i]))return rtl.test(bidiText[i])?'rtl':'ltr';
93
+ }
94
+ return null;
95
+ };
96
+ for(let i=0;i<bidiText.length;i++){
97
+ const cp=bidiText.codePointAt(i);
98
+ if(cp<=0xffff)continue;
99
+ const emoji=String.fromCodePoint(cp);
100
+ const left=nearestStrong(i-1,-1),right=nearestStrong(i+2,1);
101
+ const rtlContext=left&&left===right?left==='rtl':direction==='rtl';
102
+ if(rtlContext){
103
+ levels.levels[i]=1;levels.levels[i+1]=1;
104
+ if(direction==='rtl'&&/\p{Extended_Pictographic}/u.test(emoji)){
105
+ let before=i-1,after=i+2;
106
+ while(before>=0&&bidiText[before]==='\u200d')levels.levels[before--]=1;
107
+ while(after<bidiText.length&&bidiText[after]==='\u200d')levels.levels[after++]=1;
108
+ for(let j=before;j>=0&&bidiText[j]===' ';j--)levels.levels[j]=1;
109
+ for(let j=after;j<bidiText.length&&bidiText[j]===' ';j++)levels.levels[j]=1;
110
+ }
111
+ }
112
+ i++;
113
+ }
114
+ // Reordering is by rendered grapheme. A joiner attached to the prior
115
+ // grapheme inherits its level instead of forming a separate bidi cell.
116
+ for(let i=1;i<bidiText.length;i++){
117
+ if(bidiText[i]==='\u200d')levels.levels[i]=levels.levels[i-1];
118
+ }
119
+ // bidi-js resets trailing formatting characters during reordering.
120
+ // ZWJ belongs to the preceding grapheme here, so preserve its level.
121
+ const indices=BIDI.getReorderedIndices(bidiText.replace(/\u200d/g,'\ufffc'),levels);
122
+ const chars=new Int32Array(visible.length).fill(-1);
123
+ for(let i=0;i<tokens.length;i++)for(let k=tokens[i].start;k<tokens[i].end;k++)chars[k]=i;
124
+ const seen=new Set(),ordered=[];
125
+ for(const pos of indices){const i=chars[pos];if(i>=0&&!seen.has(i)){ordered.push(tokens[i]);seen.add(i)}}
126
+ tokens=ordered;
127
+ }
128
+ if(tokens.length*2>cells.length||tokens.length*2>runs.length)return -tokens.length;
129
+ for(let k=0;k<tokens.length;k++){let {ch,width,run}=tokens[k];cells[2*k]=ch;cells[2*k+1]=width|(run<<10)}
130
+ return tokens.length;
131
+ }
132
+
133
+ setCell(dst,screenWidth,x,y,ch,word){
134
+ const maxRows=Math.floor(dst.length/(2*screenWidth));
135
+ if(x<0||y<0||x>=screenWidth||y>=maxRows)return 65535*1048576+x+1;
136
+ const ix=2*(y*screenWidth+x),prev=dst[ix+1]&this.opts.screen.widthMask,next=word&this.opts.screen.widthMask;
137
+ let start=x,end=x+1;
138
+ if(prev===1&&next!==1&&x+1<screenWidth){const tail=ix+2;if((dst[tail+1]&3)===2){dst[tail]=this.opts.screen.emptyCharIndex;dst[tail+1]=this.opts.screen.emptyWord;end=x+2}}
139
+ if(prev===2&&next!==2&&x>0){const head=ix-2;if((dst[head+1]&3)===1){dst[head]=this.opts.screen.emptyCharIndex;dst[head+1]=this.opts.screen.emptyWord;start=x-1}}
140
+ dst[ix]=ch;dst[ix+1]=word;
141
+ if(next===1&&x+1<screenWidth){
142
+ if((dst[ix+3]&3)===1&&x+2<screenWidth&&(dst[ix+5]&3)===2){dst[ix+4]=this.opts.screen.emptyCharIndex;dst[ix+5]=this.opts.screen.emptyWord;end=x+3}
143
+ dst[ix+2]=this.opts.screen.spacerCharIndex;dst[ix+3]=this.opts.screen.spacerTail;end=Math.max(end,x+2)
144
+ }
145
+ return end*68719476736+start*1048576+(x+1);
146
+ }
147
+ paint(dst,screenWidth,x,y,cells,count,_unused,charIndices,runWords){
148
+ let start=screenWidth,end=-1,col=x;
149
+ for(let k=0;k<count;k++){
150
+ let charId=cells[2*k],packed=cells[2*k+1],width=packed&255;
151
+ if(packed&256){
152
+ if(col>=screenWidth)continue;
153
+ const next=Math.min(screenWidth,(Math.floor(col/this.opts.screen.tabWidth)+1)*this.opts.screen.tabWidth);
154
+ if(col<screenWidth){start=Math.min(start,col);end=Math.max(end,next);for(let at=col;at<next;at++){const ix=2*(y*screenWidth+at);if(ix>=0&&ix+1<dst.length){dst[ix]=this.opts.screen.emptyCharIndex;dst[ix+1]=this.opts.screen.emptyWord}}}
155
+ col=next;continue;
156
+ }
157
+ if(width<1)continue;
158
+ if(col>=screenWidth){col+=width===2?1:width;continue}
159
+ let actual=width===2&&col===screenWidth-1?3:width;
160
+ const idx=2*(y*screenWidth+col),run=packed>>>10;
161
+ if(idx<0||idx+1>=dst.length)break;
162
+ dst[idx]=actual===3?this.opts.screen.emptyCharIndex:charIndices[charId];
163
+ dst[idx+1]=actual===3?3:(runWords[run]||0)|(actual===2?1:0);
164
+ start=Math.min(start,col);end=Math.max(end,col+1);
165
+ if(actual===2&&col+1<screenWidth){dst[idx+2]=this.opts.screen.spacerCharIndex;dst[idx+3]=this.opts.screen.spacerTail;end=Math.max(end,col+2)}
166
+ col+=actual===3?1:width;
167
+ }
168
+ if(end<0)return 65535*1048576+col;
169
+ return end*68719476736+start*1048576+col;
170
+ }
171
+ }
172
+ if (typeof Bun.ant?.CellSegmenter !== "function") Bun.ant={...Bun.ant,CellSegmenter};
@@ -3,6 +3,7 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const { execFileSync } = require('child_process');
6
+ const { createHash } = require('crypto');
6
7
 
7
8
  const PLATFORM_PACKAGES = {
8
9
  'darwin-arm64': '@oven/bun-darwin-aarch64',
@@ -12,27 +13,41 @@ const PLATFORM_PACKAGES = {
12
13
  'win32-x64': '@oven/bun-windows-x64',
13
14
  };
14
15
 
15
- function isBunAvailable() {
16
+ function isBunAvailable(requiredVersion = null) {
16
17
  const isWindows = process.platform === 'win32';
17
18
  const binName = isWindows ? 'bun.exe' : 'bun';
19
+ const usable = candidate => {
20
+ try {
21
+ const version = execFileSync(candidate, ['--version'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
22
+ return !requiredVersion || version === requiredVersion;
23
+ } catch { return false; }
24
+ };
18
25
 
19
26
  // 1. PATH
20
- try {
21
- execFileSync(binName, ['--version'], { stdio: 'ignore' });
22
- return true;
23
- } catch {}
27
+ if (!requiredVersion && usable(binName)) return true;
24
28
 
25
29
  // 2. npm's bun package names the launcher bun.exe even on Unix.
26
30
  for (const spec of ['bun/bin/bun.exe', 'bun/bin/bun']) {
27
31
  try {
28
32
  const resolved = require.resolve(spec, { paths: [path.join(__dirname, '..')] });
29
- if (fs.existsSync(resolved)) return true;
33
+ if (fs.existsSync(resolved) && usable(resolved)) return true;
34
+ } catch {}
35
+ }
36
+
37
+ // bun's wrapper can be a non-executable placeholder if its install script
38
+ // was skipped; the platform package may still contain a usable binary.
39
+ const platformPkg = PLATFORM_PACKAGES[`${process.platform}-${process.arch}`];
40
+ if (platformPkg) {
41
+ try {
42
+ const dir = path.dirname(require.resolve(`${platformPkg}/package.json`, { paths: [path.join(__dirname, '..')] }));
43
+ const candidate = path.join(dir, 'bin', binName);
44
+ if (usable(candidate)) return true;
30
45
  } catch {}
31
46
  }
32
47
 
33
48
  // 3. ~/.bun/bin/bun (curl bun.sh/install fallback location)
34
49
  const home = process.env.HOME || process.env.USERPROFILE || '';
35
- if (home && fs.existsSync(path.join(home, '.bun', 'bin', binName))) {
50
+ if (!requiredVersion && home && fs.existsSync(path.join(home, '.bun', 'bin', binName))) {
36
51
  return true;
37
52
  }
38
53
 
@@ -43,25 +58,6 @@ function npmCmd() {
43
58
  return process.platform === 'win32' ? 'npm.cmd' : 'npm';
44
59
  }
45
60
 
46
- // Native Claude packages execute the bundled Anthropic runtime. Public Bun is
47
- // needed only for building cc.js or launching older public-runtime artifacts.
48
- function hasNativeClaudeRuntime(packageRoot = path.join(__dirname, '..'), platform = process.platform, arch = process.arch) {
49
- const platformKey = `${platform}-${arch}`;
50
- const dir = path.join(packageRoot, 'dist', platformKey);
51
- const manifestPath = path.join(dir, 'cc-runtime.json');
52
- try {
53
- const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
54
- const executable = platform === 'win32' ? 'cc-native.exe' : 'cc-native';
55
- return manifest.schemaVersion === 1 && manifest.mode === 'anthropic-native' &&
56
- manifest.platform === platformKey && manifest.executable === executable &&
57
- fs.existsSync(path.join(dir, 'cc.js')) &&
58
- fs.existsSync(path.join(dir, executable)) &&
59
- fs.existsSync(path.join(dir, `${executable}.mjs`));
60
- } catch {
61
- return false;
62
- }
63
- }
64
-
65
61
  function installClaudeSidecars(packageRoot = path.join(__dirname, '..'), platform = process.platform, arch = process.arch) {
66
62
  const markerPath = path.join(packageRoot, 'dist', 'claude-sidecar-release.json');
67
63
  if (!fs.existsSync(markerPath)) return false; // Source checkout / old-style local build.
@@ -70,6 +66,7 @@ function installClaudeSidecars(packageRoot = path.join(__dirname, '..'), platfor
70
66
  if (marker.schemaVersion !== 1 || !marker.platforms?.includes(platformKey)) {
71
67
  throw new Error(`Claude sidecar release does not support ${platformKey}`);
72
68
  }
69
+ if (marker.mode !== 'public-shim') throw new Error(`Unsupported Claude sidecar mode: ${marker.mode}`);
73
70
  let sidecars = path.join(packageRoot, 'dist', platformKey);
74
71
  if (marker.packageVersion) {
75
72
  const sidecarName = `makecoder-c-bin-${platformKey === 'win32-x64' ? 'win-x64' : platformKey}`;
@@ -85,22 +82,28 @@ function installClaudeSidecars(packageRoot = path.join(__dirname, '..'), platfor
85
82
  }
86
83
  sidecars = path.join(sidecarPackage, 'dist', platformKey);
87
84
  }
88
- const packageName = `@anthropic-ai/claude-code-${platformKey}`;
89
- let officialPackage;
90
- try {
91
- officialPackage = path.dirname(require.resolve(`${packageName}/package.json`, { paths: [packageRoot] }));
92
- } catch {
93
- throw new Error(`Official Claude runtime ${packageName}@${marker.version} is missing. Reinstall with optional dependencies enabled.`);
85
+ const manifest = JSON.parse(fs.readFileSync(path.join(sidecars, 'cc-runtime.json'), 'utf8'));
86
+ if (manifest.schemaVersion !== 1 || manifest.mode !== 'public-shim' ||
87
+ manifest.platform !== platformKey || manifest.version !== marker.version ||
88
+ manifest.shimFile !== 'cc-cell-segmenter-shim.js') {
89
+ throw new Error(`Invalid Claude public Bun sidecar for ${platformKey}`);
90
+ }
91
+ for (const [file, digest] of [['cc.js', manifest.bundleSha256],
92
+ [manifest.shimFile, manifest.shimSha256]]) {
93
+ if (!/^[a-f0-9]{64}$/.test(digest) ||
94
+ createHash('sha256').update(fs.readFileSync(path.join(sidecars, file))).digest('hex') !== digest) {
95
+ throw new Error(`Claude public Bun sidecar hash mismatch: ${file}`);
96
+ }
94
97
  }
95
- const officialManifest = JSON.parse(fs.readFileSync(path.join(officialPackage, 'package.json'), 'utf8'));
96
- if (officialManifest.name !== packageName || officialManifest.version !== marker.version) {
97
- throw new Error(`Official Claude runtime version mismatch: expected ${packageName}@${marker.version}`);
98
+ if (['cc-native', 'cc-native.exe', 'cc-native.mjs', 'cc-native.exe.mjs'].some(file =>
99
+ fs.existsSync(path.join(sidecars, file)))) {
100
+ throw new Error('Claude public Bun sidecar contains an obsolete native runtime');
98
101
  }
99
102
  const output = path.join(packageRoot, 'dist', platformKey);
100
- execFileSync(process.execPath, [path.join(packageRoot, 'scripts', 'assemble-claude-native.mjs'),
101
- officialPackage, sidecars, output], { cwd: packageRoot, stdio: 'inherit', timeout: 120000 });
102
- if (!hasNativeClaudeRuntime(packageRoot, platform, arch)) {
103
- throw new Error(`Claude runtime assembly did not produce a usable ${platformKey} artifact`);
103
+ fs.mkdirSync(output, { recursive: true });
104
+ fs.cpSync(sidecars, output, { recursive: true, force: true });
105
+ for (const file of ['cc-native', 'cc-native.exe', 'cc-native.mjs', 'cc-native.exe.mjs']) {
106
+ fs.rmSync(path.join(output, file), { force: true });
104
107
  }
105
108
  return true;
106
109
  }
@@ -274,8 +277,10 @@ function installBun() {
274
277
  return;
275
278
  }
276
279
 
277
- console.log(`bun not found, installing ${platformPkg} via npm...`);
278
280
  const installDir = path.join(__dirname, '..');
281
+ const pinnedBun = JSON.parse(fs.readFileSync(path.join(installDir, 'package.json'), 'utf8')).dependencies?.bun;
282
+ const bunSpec = pinnedBun && /^\d+\.\d+\.\d+$/.test(pinnedBun) ? `bun@${pinnedBun}` : 'bun@latest';
283
+ console.log(`bun not found, installing ${bunSpec} and ${platformPkg} via npm...`);
279
284
 
280
285
  // Install into makecoder's own node_modules so _resolveBunPath()'s
281
286
  // require.resolve('bun/bin/bun.exe') and the @oven fallback can find it.
@@ -284,7 +289,7 @@ function installBun() {
284
289
  try {
285
290
  execFileSync(
286
291
  npmCmd(),
287
- ['install', '--no-save', '--no-audit', '--no-fund', `bun@latest`, platformPkg],
292
+ ['install', '--no-save', '--no-audit', '--no-fund', bunSpec, platformPkg],
288
293
  { cwd: installDir, stdio: 'inherit' },
289
294
  );
290
295
  console.log('bun installed successfully.');
@@ -297,10 +302,13 @@ function installBun() {
297
302
 
298
303
  function main() {
299
304
  try {
300
- const assembled = installClaudeSidecars();
301
- if (!assembled && !hasNativeClaudeRuntime() && !isBunAvailable()) {
305
+ installClaudeSidecars();
306
+ if (!isBunAvailable('1.3.14')) {
302
307
  installBun();
303
308
  }
309
+ if (!isBunAvailable('1.3.14')) {
310
+ throw new Error('bun@1.3.14 is required for this Claude sidecar release');
311
+ }
304
312
  } catch (error) {
305
313
  console.error('Error during postinstall setup:', error.message);
306
314
  process.exit(1);
@@ -333,4 +341,4 @@ if (require.main === module) {
333
341
  main();
334
342
  }
335
343
 
336
- module.exports = { main, checkCodexCodeModeHost, ensureNodePtyHelperExecutable, hasNativeClaudeRuntime, installClaudeSidecars };
344
+ module.exports = { main, checkCodexCodeModeHost, ensureNodePtyHelperExecutable, installClaudeSidecars };
@@ -1,139 +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
- if (fs.existsSync(output)) renameWithWindowsRetry(output, backup);
107
- try { renameWithWindowsRetry(staging, output); }
108
- catch (error) {
109
- if (fs.existsSync(backup)) {
110
- try { renameWithWindowsRetry(backup, output); }
111
- catch (restoreError) {
112
- throw new AggregateError([error, restoreError], "Failed to install Claude runtime and restore the previous artifact");
113
- }
114
- }
115
- throw error;
116
- }
117
- fs.rmSync(backup, { recursive: true, force: true, maxRetries: 10, retryDelay: 500 });
118
- console.log(`Assembled ${pkg.name}@${pkg.version} -> ${output}`);
119
- } catch (error) {
120
- assemblyError = error;
121
- throw error;
122
- } finally {
123
- try {
124
- // Windows can briefly lock an executable after execFileSync returns.
125
- fs.rmSync(staging, { recursive: true, force: true, maxRetries: 10, retryDelay: 500 });
126
- } catch (cleanupError) {
127
- if (!assemblyError) throw cleanupError;
128
- console.warn(`Could not clean staging directory ${staging}: ${cleanupError.message}`);
129
- }
130
- }
131
- }
132
-
133
- if (process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) {
134
- const [official, sidecars, output, ...rest] = process.argv.slice(2);
135
- if (!official || !sidecars || !output || rest.length) {
136
- throw new Error("Usage: assemble-claude-native.mjs <official-platform-package> <patch-sidecars> <output>");
137
- }
138
- assembleNative(official, sidecars, output);
139
- }