makecoder 5.0.22 → 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/dist/claude-sidecar-release.json +3 -2
- package/dist/coder.js +375 -376
- package/dist/cowork.js +375 -376
- package/package.json +16 -21
- package/scripts/claude-cell-segmenter-shim.js +172 -0
- package/scripts/postinstall.js +52 -44
- package/scripts/assemble-claude-native.mjs +0 -142
- package/scripts/claude-native-runtime.mjs +0 -230
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "makecoder",
|
|
3
|
-
"version": "5.0.
|
|
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.22",
|
|
56
|
-
"makecoder-bin-linux-arm64": "5.0.22",
|
|
57
|
-
"makecoder-bin-linux-x64": "5.0.22",
|
|
58
|
-
"makecoder-bin-win-x64": "5.0.22",
|
|
59
|
-
"makecoder-c-bin-darwin-arm64": "5.0.22",
|
|
60
|
-
"makecoder-c-bin-darwin-x64": "5.0.22",
|
|
61
|
-
"makecoder-c-bin-linux-arm64": "5.0.22",
|
|
62
|
-
"makecoder-c-bin-linux-x64": "5.0.22",
|
|
63
|
-
"makecoder-c-bin-win-x64": "5.0.22"
|
|
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/
|
|
76
|
-
|
|
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};
|
package/scripts/postinstall.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
throw new Error(
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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',
|
|
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
|
-
|
|
301
|
-
if (!
|
|
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,
|
|
344
|
+
module.exports = { main, checkCodexCodeModeHost, ensureNodePtyHelperExecutable, installClaudeSidecars };
|
|
@@ -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
|
-
}
|