thebird 1.2.78 → 1.2.80

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.
Files changed (78) hide show
  1. package/.github/workflows/publish.yml +9 -1
  2. package/CHANGELOG.md +226 -0
  3. package/CLAUDE.md +16 -0
  4. package/docs/agent-chat.js +7 -4
  5. package/docs/app.js +14 -11
  6. package/docs/defaults.json +1 -1
  7. package/docs/index.html +23 -6
  8. package/docs/kilo-http-stream.js +24 -0
  9. package/docs/node-builtins.js +194 -0
  10. package/docs/preview/index.html +32 -0
  11. package/docs/preview-sw-client.js +37 -6
  12. package/docs/preview-sw.js +55 -51
  13. package/docs/shell-awk.js +113 -0
  14. package/docs/shell-builtins-extra.js +121 -0
  15. package/docs/shell-builtins-text.js +109 -0
  16. package/docs/shell-builtins-util.js +112 -0
  17. package/docs/shell-builtins.js +183 -0
  18. package/docs/shell-bun.js +45 -0
  19. package/docs/shell-control.js +132 -0
  20. package/docs/shell-deno.js +54 -0
  21. package/docs/shell-exec.js +85 -0
  22. package/docs/shell-expand.js +164 -0
  23. package/docs/shell-fd.js +86 -0
  24. package/docs/shell-jobs.js +86 -0
  25. package/docs/shell-node-advanced.js +86 -0
  26. package/docs/shell-node-brotli.js +22 -0
  27. package/docs/shell-node-busnet.js +90 -0
  28. package/docs/shell-node-cipher.js +61 -0
  29. package/docs/shell-node-cluster.js +33 -0
  30. package/docs/shell-node-coreutils.js +36 -0
  31. package/docs/shell-node-crypto.js +137 -0
  32. package/docs/shell-node-dns.js +41 -0
  33. package/docs/shell-node-extras.js +148 -0
  34. package/docs/shell-node-firefox.js +95 -0
  35. package/docs/shell-node-git.js +60 -0
  36. package/docs/shell-node-inspector.js +39 -0
  37. package/docs/shell-node-io.js +131 -0
  38. package/docs/shell-node-ipc.js +15 -0
  39. package/docs/shell-node-keyobject.js +60 -0
  40. package/docs/shell-node-modules.js +157 -0
  41. package/docs/shell-node-native.js +31 -0
  42. package/docs/shell-node-net.js +71 -0
  43. package/docs/shell-node-observe.js +80 -0
  44. package/docs/shell-node-opfs.js +54 -0
  45. package/docs/shell-node-procfs.js +42 -0
  46. package/docs/shell-node-profiler.js +50 -0
  47. package/docs/shell-node-registry.js +24 -0
  48. package/docs/shell-node-resolve.js +147 -0
  49. package/docs/shell-node-runtime.js +83 -0
  50. package/docs/shell-node-srcmap.js +52 -0
  51. package/docs/shell-node-stdlib.js +103 -0
  52. package/docs/shell-node-streams.js +66 -0
  53. package/docs/shell-node-tar.js +47 -0
  54. package/docs/shell-node-testrunner.js +35 -0
  55. package/docs/shell-node-util-extras.js +66 -0
  56. package/docs/shell-node.js +188 -97
  57. package/docs/shell-npm.js +173 -0
  58. package/docs/shell-parser.js +122 -0
  59. package/docs/shell-pm-layout.js +62 -0
  60. package/docs/shell-pm.js +39 -0
  61. package/docs/shell-posix.js +70 -0
  62. package/docs/shell-procsub.js +65 -0
  63. package/docs/shell-readline.js +59 -4
  64. package/docs/shell-runtime.js +37 -0
  65. package/docs/shell-sed.js +83 -0
  66. package/docs/shell-signals.js +54 -0
  67. package/docs/shell-sw-jobs.js +76 -0
  68. package/docs/shell-ts.js +30 -0
  69. package/docs/shell.js +159 -167
  70. package/docs/terminal.js +9 -11
  71. package/docs/todo.html +211 -0
  72. package/package.json +1 -1
  73. package/server.js +43 -4
  74. package/start-kilo.js +17 -0
  75. package/test.js +199 -0
  76. package/.codeinsight +0 -73
  77. package/docs/acp-stream.js +0 -102
  78. package/docs/coi-serviceworker.js +0 -2
@@ -0,0 +1,148 @@
1
+ export function extendBuffer(Buf) {
2
+ const proto = Buf.prototype;
3
+ proto.readBigUInt64BE = function(o=0){return (BigInt(this.readUInt32BE(o))<<32n)|BigInt(this.readUInt32BE(o+4));};
4
+ proto.readBigUInt64LE = function(o=0){return (BigInt(this.readUInt32LE(o)))|(BigInt(this.readUInt32LE(o+4))<<32n);};
5
+ proto.readUInt32LE = function(o=0){return (this[o]|(this[o+1]<<8)|(this[o+2]<<16)|(this[o+3]*0x1000000))>>>0;};
6
+ proto.readDoubleBE = function(o=0){return new DataView(this.buffer,this.byteOffset+o,8).getFloat64(0,false);};
7
+ proto.readDoubleLE = function(o=0){return new DataView(this.buffer,this.byteOffset+o,8).getFloat64(0,true);};
8
+ proto.readFloatBE = function(o=0){return new DataView(this.buffer,this.byteOffset+o,4).getFloat32(0,false);};
9
+ proto.readFloatLE = function(o=0){return new DataView(this.buffer,this.byteOffset+o,4).getFloat32(0,true);};
10
+ proto.writeUInt16BE = function(v,o=0){this[o]=(v>>8)&0xff;this[o+1]=v&0xff;return o+2;};
11
+ proto.writeUInt16LE = function(v,o=0){this[o]=v&0xff;this[o+1]=(v>>8)&0xff;return o+2;};
12
+ proto.writeUInt32BE = function(v,o=0){this[o]=(v>>>24)&0xff;this[o+1]=(v>>>16)&0xff;this[o+2]=(v>>>8)&0xff;this[o+3]=v&0xff;return o+4;};
13
+ proto.swap16 = function(){for(let i=0;i<this.length;i+=2){const t=this[i];this[i]=this[i+1];this[i+1]=t;}return this;};
14
+ proto.swap32 = function(){for(let i=0;i<this.length;i+=4){[this[i],this[i+3]]=[this[i+3],this[i]];[this[i+1],this[i+2]]=[this[i+2],this[i+1]];}return this;};
15
+ proto.swap64 = function(){for(let i=0;i<this.length;i+=8){for(let j=0;j<4;j++){const t=this[i+j];this[i+j]=this[i+7-j];this[i+7-j]=t;}}return this;};
16
+ Buf.copyBytesFrom = (view,off=0,len)=>Buf.from(view.buffer,view.byteOffset+off,len??view.byteLength-off);
17
+ return Buf;
18
+ }
19
+
20
+ const WIN = /^[A-Za-z]:[\\/]/;
21
+ function win32Mod(){
22
+ const sep='\\';
23
+ const norm=p=>{const abs=WIN.test(p);const parts=[];for(const s of p.replace(/\//g,'\\').split('\\')){if(s==='..')parts.pop();else if(s&&s!=='.')parts.push(s);}return (abs?p.slice(0,3):'')+parts.slice(abs?1:0).join('\\');};
24
+ return {sep,delimiter:';',normalize:norm,join:(...a)=>norm(a.join('\\')),resolve:(...a)=>{let r='';for(const p of a)r=WIN.test(p)?p:r+'\\'+p;return norm(r);},dirname:p=>{const i=p.replace(/\//g,'\\').lastIndexOf('\\');return i<=0?'.':p.slice(0,i);},basename:(p,ext)=>{const b=p.replace(/\//g,'\\').split('\\').pop()||'';return ext&&b.endsWith(ext)?b.slice(0,-ext.length):b;},extname:p=>{const b=p.split(/[\\/]/).pop()||'';const i=b.lastIndexOf('.');return i>0?b.slice(i):'';},isAbsolute:p=>WIN.test(p)||p.startsWith('\\'),relative:(f,t)=>t.replace(f+'\\',''),parse:p=>({root:WIN.test(p)?p.slice(0,3):'',dir:p.slice(0,p.lastIndexOf('\\'))||'',base:p.split('\\').pop()||'',ext:'',name:''})};
25
+ }
26
+ export function extendPath(posix){
27
+ posix.delimiter=':';
28
+ posix.posix=posix;
29
+ posix.win32=win32Mod();
30
+ return posix;
31
+ }
32
+
33
+ export function createUrlExt(){
34
+ const pathToFileURL=p=>{const u=new URL('file://');u.pathname=p.startsWith('/')?p:'/'+p;return u;};
35
+ const fileURLToPath=u=>{const url=typeof u==='string'?new URL(u):u;if(url.protocol!=='file:')throw new TypeError('only file: supported');return decodeURIComponent(url.pathname);};
36
+ return {URL,URLSearchParams,parse:s=>{const u=new URL(s);return{protocol:u.protocol,host:u.host,hostname:u.hostname,port:u.port,pathname:u.pathname,search:u.search,query:u.search.slice(1),hash:u.hash,href:u.href};},format:o=>{if(o instanceof URL)return o.href;const u=new URL('http://x');for(const[k,v]of Object.entries(o)){try{u[k]=v;}catch{}}return u.href;},resolve:(f,t)=>new URL(t,f).href,pathToFileURL,fileURLToPath,domainToASCII:s=>s,domainToUnicode:s=>s};
37
+ }
38
+
39
+ export function makeStringDecoder(){
40
+ class StringDecoder{
41
+ constructor(enc='utf8'){this.encoding=enc;this._td=new TextDecoder(enc==='utf8'?'utf-8':enc,{fatal:false});this._buf=null;}
42
+ write(b){return this._td.decode(b,{stream:true});}
43
+ end(b){return this._td.decode(b||new Uint8Array(0),{stream:false});}
44
+ }
45
+ return {StringDecoder};
46
+ }
47
+
48
+ export function makeReadline(term,proc){
49
+ return {
50
+ createInterface:({input,output,prompt='> ',terminal:useTerm}={})=>{
51
+ const handlers={line:[],close:[],history:[]};
52
+ const useXterm=useTerm!==false&&term&&(!input||input===proc?.stdin);
53
+ let buf='';
54
+ const rl={
55
+ on:(ev,fn)=>{(handlers[ev]=handlers[ev]||[]).push(fn);return rl;},
56
+ once:(ev,fn)=>rl.on(ev,(...a)=>{rl.off(ev,fn);fn(...a);}),
57
+ off:(ev,fn)=>{handlers[ev]=(handlers[ev]||[]).filter(f=>f!==fn);return rl;},
58
+ write:s=>(output||term)?.write?.(s),
59
+ prompt:()=>(output||term)?.write?.(prompt),
60
+ question:(q,cb)=>{(output||term)?.write?.(q);return new Promise(resolve=>{const handler=l=>{rl.off('line',handler);resolve(l);cb?.(l);};handlers.line.push(handler);});},
61
+ close:()=>{for(const h of handlers.close)h();},
62
+ setPrompt:p=>{prompt=p;},
63
+ pause:()=>rl,resume:()=>rl,
64
+ [Symbol.asyncIterator](){return{next(){return new Promise(r=>{handlers.line.push(function on(l){handlers.line=handlers.line.filter(f=>f!==on);r({value:l,done:false});});});}};}
65
+ };
66
+ if(useXterm){
67
+ const sink=d=>{if(d==='\r'||d==='\n'){const l=buf;buf='';term.write('\r\n');for(const h of handlers.line)h(l);}else if(d==='\x7f'){if(buf.length){buf=buf.slice(0,-1);term.write('\b \b');}}else if(d>=' '){buf+=d;term.write(d);}};
68
+ if(proc?.stdin?.on)proc.stdin.on('data',sink);
69
+ }else if(input?._onLine)input._onLine(l=>{for(const h of handlers.line)h(l);});
70
+ return rl;
71
+ },
72
+ cursorTo:(s,x,y)=>{if(s?.write)s.write(`\x1b[${(y||0)+1};${(x||0)+1}H`);},
73
+ clearLine:s=>s?.write?.('\x1b[2K'),
74
+ clearScreenDown:s=>s?.write?.('\x1b[J'),
75
+ moveCursor:(s,dx,dy)=>{if(s?.write){if(dx>0)s.write(`\x1b[${dx}C`);else if(dx<0)s.write(`\x1b[${-dx}D`);if(dy>0)s.write(`\x1b[${dy}B`);else if(dy<0)s.write(`\x1b[${-dy}A`);}},
76
+ emitKeypressEvents:(stream,rl)=>{if(!stream?.on)return;stream.on('data',d=>{const name=d==='\r'?'return':d==='\x1b[A'?'up':d==='\x1b[B'?'down':d==='\x7f'?'backspace':d.length===1?d:'';stream.emit?.('keypress',d,{name,ctrl:false,meta:false,shift:false,sequence:d});});},
77
+ };
78
+ }
79
+
80
+ export function makeTimersMod(){
81
+ return {setTimeout,setInterval,setImmediate:fn=>setTimeout(fn,0),clearTimeout,clearInterval,clearImmediate:clearTimeout,promises:{setTimeout:ms=>new Promise(r=>setTimeout(r,ms)),setImmediate:()=>Promise.resolve(),setInterval:async function*(ms){while(1){await new Promise(r=>setTimeout(r,ms));yield;}}}};
82
+ }
83
+
84
+ export function makePerfHooks(){
85
+ return {performance:globalThis.performance,PerformanceObserver:class{observe(){}disconnect(){}},monitorEventLoopDelay:()=>({enable(){},disable(){},reset(){},min:0,max:0,mean:0,stddev:0,percentile:()=>0}),constants:{NODE_PERFORMANCE_GC_MAJOR:2}};
86
+ }
87
+
88
+ export function makeV8Mod(){
89
+ return {getHeapStatistics:()=>({total_heap_size:20000000,used_heap_size:10000000,heap_size_limit:2000000000,total_available_size:1990000000}),getHeapSpaceStatistics:()=>[],serialize:o=>new TextEncoder().encode(JSON.stringify(o)),deserialize:b=>JSON.parse(new TextDecoder().decode(b)),cachedDataVersionTag:()=>0,setFlagsFromString:()=>{}};
90
+ }
91
+
92
+ export function makeAsyncHooks(){
93
+ return {createHook:()=>({enable(){return this;},disable(){return this;}}),executionAsyncId:()=>1,triggerAsyncId:()=>0,executionAsyncResource:()=>({}),AsyncLocalStorage:class{constructor(){this._s=null;}run(s,fn,...a){const p=this._s;this._s=s;try{return fn(...a);}finally{this._s=p;}}getStore(){return this._s;}enterWith(s){this._s=s;}disable(){this._s=null;}exit(fn,...a){const p=this._s;this._s=null;try{return fn(...a);}finally{this._s=p;}}},AsyncResource:class{constructor(){}runInAsyncScope(fn,t,...a){return fn.apply(t,a);}}};
94
+ }
95
+
96
+ export function makeStubs(ctx){
97
+ const stub=name=>({__stub:name,toString:()=>`[${name} stub]`});
98
+ return {
99
+ inspector:{open:()=>{},close:()=>{},url:()=>undefined,waitForDebugger:()=>{},Session:class{connect(){}post(){}}},
100
+ cluster:{isPrimary:true,isMaster:true,isWorker:false,workers:{},fork:()=>{throw new Error('cluster.fork: not supported in browser')},on:()=>{},emit:()=>{}},
101
+ sea:{isSea:()=>false,getAsset:()=>{throw new Error('sea.getAsset: no SEA blob')},getRawAsset:()=>{throw new Error('sea.getRawAsset: no SEA blob')}},
102
+ test_runner:{test:(n,fn)=>Promise.resolve(fn?.()),describe:(n,fn)=>fn?.(),it:(n,fn)=>Promise.resolve(fn?.()),before:fn=>fn?.(),after:fn=>fn?.(),beforeEach:()=>{},afterEach:()=>{},run:()=>({})},
103
+ readline_promises:{createInterface:()=>({close(){},question:q=>Promise.resolve('')})},
104
+ punycode:{encode:s=>s,decode:s=>s,toASCII:s=>s,toUnicode:s=>s,ucs2:{encode:a=>String.fromCodePoint(...a),decode:s=>[...s].map(c=>c.codePointAt(0))}},
105
+ tty:{isatty:()=>true,ReadStream:class{isTTY=true;},WriteStream:class{isTTY=true;columns=80;rows=24;}},
106
+ domain:{create:()=>({run:fn=>fn(),add(){},remove(){},dispose(){},on(){},emit(){}})},
107
+ diagnostics_channel:{channel:name=>({hasSubscribers:false,publish(){},subscribe(){},unsubscribe(){}}),hasSubscribers:()=>false},
108
+ string_decoder:makeStringDecoder(),
109
+ tls:{connect:()=>{throw new Error('tls.connect: use fetch() for HTTPS in browser');},createServer:()=>{throw new Error('tls.createServer: not supported in browser');},DEFAULT_CIPHERS:'',DEFAULT_MIN_VERSION:'TLSv1.2',DEFAULT_MAX_VERSION:'TLSv1.3'},
110
+ };
111
+ }
112
+
113
+ export function makeErrorCodes(){
114
+ const codes={ERR_MODULE_NOT_FOUND:'Cannot find module',ERR_INVALID_ARG_TYPE:'Invalid argument type',ERR_INVALID_ARG_VALUE:'Invalid argument value',ERR_OUT_OF_RANGE:'Value out of range',ERR_UNHANDLED_ERROR:'Unhandled error',ERR_ASSERTION:'Assertion failed',ERR_UNSUPPORTED_DIR_IMPORT:'Directory import not supported',ERR_PACKAGE_PATH_NOT_EXPORTED:'Package path not exported',ERR_REQUIRE_ESM:'Cannot require() ESM module',ERR_UNKNOWN_FILE_EXTENSION:'Unknown file extension',ERR_UNKNOWN_BUILTIN_MODULE:'Unknown builtin module',ERR_INVALID_URL:'Invalid URL',ERR_STREAM_DESTROYED:'Stream destroyed',ERR_STREAM_WRITE_AFTER_END:'Write after end',ERR_STREAM_PREMATURE_CLOSE:'Premature close'};
115
+ const make=(code,msg)=>{const e=new Error(msg||codes[code]);e.code=code;return e;};
116
+ return {codes,make};
117
+ }
118
+
119
+ export function extendProcessExtras(proc,ctx){
120
+ proc.stdout.columns=80;proc.stdout.rows=24;proc.stdout.isTTY=true;proc.stdout.getColorDepth=()=>8;proc.stdout.hasColors=()=>true;
121
+ proc.stderr.columns=80;proc.stderr.rows=24;proc.stderr.isTTY=true;
122
+ proc.stdin.isTTY=true;
123
+ proc.resourceUsage=()=>({userCPUTime:0,systemCPUTime:0,maxRSS:50000,sharedMemorySize:0,unsharedDataSize:0,unsharedStackSize:0,minorPageFault:0,majorPageFault:0,swappedOut:0,fsRead:0,fsWrite:0,ipcSent:0,ipcReceived:0,signalsCount:0,voluntaryContextSwitches:0,involuntaryContextSwitches:0});
124
+ proc.binding=name=>{throw new Error(`process.binding('${name}'): internal bindings not available`);};
125
+ proc.allowedNodeEnvironmentFlags=new Set(['--experimental-vm-modules','--no-warnings','--loader','--import','--require','-r','--enable-source-maps','--inspect','--inspect-brk','--trace-warnings','--unhandled-rejections','--preserve-symlinks','--no-deprecation','--throw-deprecation']);
126
+ const nodeOpts=(ctx.env.NODE_OPTIONS||'').split(/\s+/).filter(Boolean);
127
+ proc.execArgv=nodeOpts;
128
+ proc.sourceMapsEnabled=nodeOpts.includes('--enable-source-maps');
129
+ proc.features={inspector:false,debug:false,uv:false,ipv6:true,tls_alpn:false,tls_sni:false,tls_ocsp:false,tls:false,cached_builtins:true};
130
+ proc.report={getReport:()=>({}),writeReport:()=>'report.json'};
131
+ proc.availableMemory=()=>1073741824;
132
+ proc.constrainedMemory=()=>0;
133
+ proc.loadEnvFile=p=>{};
134
+ proc.noDeprecation=false;proc.throwDeprecation=false;proc.traceDeprecation=false;
135
+ proc.sourceMapsEnabled=false;
136
+ proc.channel=undefined;proc.connected=false;
137
+ const sigH={};
138
+ const origOn=proc.on?.bind(proc);
139
+ proc.on=(ev,fn)=>{if(['SIGINT','SIGTERM','SIGHUP','exit','beforeExit','uncaughtException','unhandledRejection','warning','message'].includes(ev)){(sigH[ev]=sigH[ev]||[]).push(fn);}origOn?.(ev,fn);return proc;};
140
+ proc._emitSignal=(ev,...a)=>{for(const h of sigH[ev]||[])h(...a);};
141
+ proc.kill=()=>true;
142
+ return proc;
143
+ }
144
+
145
+ export function makeStreamConsumers(){
146
+ const toArr=async it=>{const a=[];for await(const c of it)a.push(c);return a;};
147
+ return {text:async s=>{const a=await toArr(s);return a.map(c=>typeof c==='string'?c:new TextDecoder().decode(c)).join('');},json:async s=>JSON.parse(await (await import('./shell-node-extras.js')).makeStreamConsumers().text(s)),arrayBuffer:async s=>{const a=await toArr(s);const b=Buffer.concat(a.map(c=>c instanceof Uint8Array?c:new TextEncoder().encode(c)));return b.buffer;},buffer:async s=>{const a=await toArr(s);return Buffer.concat(a.map(c=>c instanceof Uint8Array?c:new TextEncoder().encode(c)));}};
148
+ }
@@ -0,0 +1,95 @@
1
+ export function detectBrowser(){
2
+ const ua=(typeof navigator!=='undefined'?navigator.userAgent:'')||'';
3
+ const vendor=/Firefox\//.test(ua)?'firefox':/Edg\//.test(ua)?'edge':/Chrome\//.test(ua)?'chromium':/Safari\//.test(ua)?'webkit':'unknown';
4
+ const m=ua.match(/(Firefox|Chrome|Edg|Safari|Version)\/([\d.]+)/);
5
+ const version=m?m[2]:'0';
6
+ const g=globalThis;
7
+ const caps={
8
+ opfs:!!(g.navigator?.storage?.getDirectory),
9
+ sharedArrayBuffer:typeof SharedArrayBuffer!=='undefined'&&g.crossOriginIsolated===true,
10
+ performanceMemory:!!(g.performance?.memory),
11
+ compressionStream:typeof g.CompressionStream!=='undefined',
12
+ webTransport:typeof g.WebTransport!=='undefined',
13
+ webRTCDataChannel:typeof g.RTCPeerConnection!=='undefined',
14
+ webCodecs:typeof g.VideoEncoder!=='undefined',
15
+ storageBuckets:!!(g.navigator?.storageBuckets),
16
+ fileSystemObserver:typeof g.FileSystemObserver!=='undefined',
17
+ measureMemory:typeof g.performance?.measureUserAgentSpecificMemory==='function',
18
+ broadcastChannel:typeof g.BroadcastChannel!=='undefined',
19
+ };
20
+ return{vendor,version,ua,capabilities:caps};
21
+ }
22
+
23
+ export function registerPolyfill(reg,name,backing,reason){
24
+ reg.polyfills=reg.polyfills||{};
25
+ reg.polyfills[name]={active:true,backing,reason,activatedAt:Date.now()};
26
+ }
27
+
28
+ export function makeCompressionStreamZlib(streamMod,Buf){
29
+ if(typeof CompressionStream==='undefined')return null;
30
+ const mk=(name,Ctor)=>()=>{const t=new Ctor(name);const reader=t.readable.getReader();const writer=t.writable.getWriter();const out=new streamMod.Transform({transform(c,e,cb){writer.write(c instanceof Uint8Array?c:new TextEncoder().encode(String(c))).then(()=>cb(),cb);},flush(cb){writer.close().then(async()=>{for(;;){const{value,done}=await reader.read();if(done)break;out.push(Buf.from(value));}cb();},cb);}});return out;};
31
+ return{
32
+ createGzip:mk('gzip',CompressionStream),
33
+ createGunzip:mk('gzip',DecompressionStream),
34
+ createDeflate:mk('deflate',CompressionStream),
35
+ createInflate:mk('deflate',DecompressionStream),
36
+ createDeflateRaw:mk('deflate-raw',CompressionStream),
37
+ createInflateRaw:mk('deflate-raw',DecompressionStream),
38
+ };
39
+ }
40
+
41
+ export function makeWebCodecs(){
42
+ const g=globalThis;
43
+ if(typeof g.VideoEncoder==='undefined')return null;
44
+ return{VideoEncoder:g.VideoEncoder,VideoDecoder:g.VideoDecoder,AudioEncoder:g.AudioEncoder,AudioDecoder:g.AudioDecoder,ImageDecoder:g.ImageDecoder,EncodedVideoChunk:g.EncodedVideoChunk,EncodedAudioChunk:g.EncodedAudioChunk,VideoFrame:g.VideoFrame,AudioData:g.AudioData};
45
+ }
46
+
47
+ export function makeWebPush(){
48
+ return{
49
+ async subscribe(applicationServerKey,opts={}){
50
+ if(!navigator.serviceWorker)throw new Error('web-push: serviceWorker not available');
51
+ const reg=await navigator.serviceWorker.ready;
52
+ return reg.pushManager.subscribe({userVisibleOnly:opts.userVisibleOnly!==false,applicationServerKey});
53
+ },
54
+ async getSubscription(){
55
+ const reg=await navigator.serviceWorker?.ready;
56
+ return reg?reg.pushManager.getSubscription():null;
57
+ },
58
+ async unsubscribe(){
59
+ const sub=await this.getSubscription();
60
+ return sub?sub.unsubscribe():false;
61
+ }
62
+ };
63
+ }
64
+
65
+ export function makeStorageHelpers(){
66
+ const g=globalThis;
67
+ return{
68
+ async estimate(){if(!g.navigator?.storage?.estimate)return{usage:0,quota:0,usageDetails:{}};return g.navigator.storage.estimate();},
69
+ async persist(){if(!g.navigator?.storage?.persist)return false;return g.navigator.storage.persist();},
70
+ async persisted(){if(!g.navigator?.storage?.persisted)return false;return g.navigator.storage.persisted();},
71
+ buckets:g.navigator?.storageBuckets||null,
72
+ };
73
+ }
74
+
75
+ export function makeFsObserver(getSnap,fsWatchers){
76
+ const g=globalThis;
77
+ if(typeof g.FileSystemObserver==='undefined')return null;
78
+ return async (opfsRoot)=>{
79
+ const obs=new g.FileSystemObserver(records=>{
80
+ for(const r of records){
81
+ const path=r.relativePathComponents.join('/');
82
+ for(const w of fsWatchers)if(path===w.path||(w.recursive&&path.startsWith(w.path+'/')))for(const h of w.handlers.change)h(r.type,path.split('/').pop());
83
+ }
84
+ });
85
+ if(opfsRoot)await obs.observe(opfsRoot,{recursive:true});
86
+ return obs;
87
+ };
88
+ }
89
+
90
+ export function wrapWorkerForFirefox(opts={}){
91
+ const ua=typeof navigator!=='undefined'?navigator.userAgent:'';
92
+ const isOldFirefox=/Firefox\/(\d+)/.test(ua)&&parseInt(ua.match(/Firefox\/(\d+)/)[1])<128;
93
+ if(!isOldFirefox||opts.type!=='module')return opts;
94
+ return{...opts,type:'classic'};
95
+ }
@@ -0,0 +1,60 @@
1
+ let gitMod=null;let gitPromise=null;
2
+
3
+ async function loadGit(){
4
+ if(!gitPromise)gitPromise=Promise.all([
5
+ import('https://esm.sh/isomorphic-git@1.27.1/es2022/isomorphic-git.mjs').then(m=>m.default||m),
6
+ import('https://esm.sh/isomorphic-git@1.27.1/http/web').then(m=>m.default||m).catch(()=>null),
7
+ ]).then(([git,http])=>({git,http}));
8
+ return gitPromise;
9
+ }
10
+
11
+ export async function preloadGit(){gitMod=await loadGit();return gitMod;}
12
+
13
+ export function makeGit(fs){
14
+ const fsAdapter={
15
+ promises:{
16
+ async readFile(path,opts){try{const enc=typeof opts==='string'?opts:opts?.encoding;const d=fs.readFileSync(path);if(enc==='utf8'||enc==='utf-8')return typeof d==='string'?d:new TextDecoder().decode(d);return typeof d==='string'?new TextEncoder().encode(d):d;}catch(e){e.code='ENOENT';throw e;}},
17
+ async writeFile(path,data){const parts=path.split('/');for(let i=1;i<parts.length;i++){const d=parts.slice(0,i).join('/');if(d&&!fs.existsSync(d))fs.mkdirSync(d,{recursive:true});}fs.writeFileSync(path,data);},
18
+ async unlink(path){fs.unlinkSync(path);},
19
+ async readdir(path){return fs.readdirSync(path);},
20
+ async mkdir(path){fs.mkdirSync(path,{recursive:true});},
21
+ async rmdir(path){fs.rmSync?.(path,{recursive:true})||fs.unlinkSync(path);},
22
+ async stat(path){return fs.statSync(path);},
23
+ async lstat(path){return fs.lstatSync?.(path)||fs.statSync(path);},
24
+ async readlink(path){return fs.readlinkSync?.(path);},
25
+ async symlink(target,path){fs.symlinkSync?.(target,path);},
26
+ async chmod(){},
27
+ },
28
+ };
29
+ const need=()=>{if(!gitMod)throw new Error('git: call await preloadGit() once before git ops');return gitMod;};
30
+ const wrap=method=>async opts=>{const{git,http}=need();return git[method]({fs:fsAdapter,http,...opts});};
31
+ return{
32
+ clone:wrap('clone'),
33
+ init:wrap('init'),
34
+ add:wrap('add'),
35
+ commit:wrap('commit'),
36
+ push:wrap('push'),
37
+ pull:wrap('pull'),
38
+ fetch:wrap('fetch'),
39
+ status:wrap('status'),
40
+ statusMatrix:wrap('statusMatrix'),
41
+ log:wrap('log'),
42
+ listBranches:wrap('listBranches'),
43
+ branch:wrap('branch'),
44
+ checkout:wrap('checkout'),
45
+ resolveRef:wrap('resolveRef'),
46
+ currentBranch:wrap('currentBranch'),
47
+ remove:wrap('remove'),
48
+ listRemotes:wrap('listRemotes'),
49
+ addRemote:wrap('addRemote'),
50
+ deleteRemote:wrap('deleteRemote'),
51
+ merge:wrap('merge'),
52
+ readBlob:wrap('readBlob'),
53
+ readTree:wrap('readTree'),
54
+ readCommit:wrap('readCommit'),
55
+ tag:wrap('tag'),
56
+ listTags:wrap('listTags'),
57
+ diff:async opts=>{const s=await wrap('statusMatrix')(opts);return s.filter(([,,w,s])=>w!==s).map(([path])=>path);},
58
+ preload:preloadGit,
59
+ };
60
+ }
@@ -0,0 +1,39 @@
1
+ export function makeInspector(debugReg){
2
+ let opened=false;let url=null;let port=null;const sessions=new Set();
3
+ const targets=()=>[{description:'thebird browser runtime',devtoolsFrontendUrl:'',id:'thebird-1',title:'thebird',type:'node',url:'file://thebird',webSocketDebuggerUrl:url}];
4
+ const handlers={};
5
+ const post=(sess,msg)=>{try{sess.send(JSON.stringify(msg));}catch{}};
6
+ const installServer=u=>{
7
+ if(typeof globalThis.addEventListener!=='function')return;
8
+ globalThis.addEventListener('message',e=>{if(e.data?.type!=='cdp:connect')return;const chan=e.data.channel;const sess={send:m=>globalThis.postMessage({type:'cdp:msg',channel:chan,msg:m},'*')};sessions.add(sess);});
9
+ };
10
+ const dispatch=(sess,raw)=>{
11
+ let msg;try{msg=JSON.parse(raw);}catch{return;}
12
+ const {id,method,params}=msg;
13
+ const send=result=>post(sess,{id,result});
14
+ const err=code=>post(sess,{id,error:{code,message:'not implemented'}});
15
+ const map={
16
+ 'Runtime.enable':()=>send({}),
17
+ 'Runtime.evaluate':()=>{try{const r=(0,eval)(params.expression);send({result:{type:typeof r,value:r,description:String(r)}});}catch(e){send({exceptionDetails:{exception:{type:'object',className:'Error',description:e.stack}}});}},
18
+ 'Debugger.enable':()=>send({debuggerId:'thebird-dbg-1'}),
19
+ 'Debugger.getScriptSource':()=>send({scriptSource:''}),
20
+ 'Profiler.enable':()=>send({}),
21
+ 'Profiler.start':()=>send({}),
22
+ 'Profiler.stop':()=>send({profile:{nodes:[],startTime:0,endTime:0,samples:[],timeDeltas:[]}}),
23
+ 'HeapProfiler.enable':()=>send({}),
24
+ 'HeapProfiler.takeHeapSnapshot':()=>send({}),
25
+ };
26
+ const h=map[method];h?h():err(-32601);
27
+ };
28
+ return{
29
+ open(p=9229,host='127.0.0.1',wait=false){if(opened)return;opened=true;port=p;url=`ws://${host}:${p}/${crypto.randomUUID()}`;installServer(url);debugReg.polyfills=debugReg.polyfills||{};debugReg.polyfills.inspector={active:true,backing:'postMessage-CDP',reason:'real WS debugger unavailable in sandbox'};debugReg.inspector={url,port,targets:targets(),sessions};if(wait)throw new Error('inspector.waitForDebugger: sync block not supported — use openAsync()');return{url};},
30
+ async openAsync(p=9229,host='127.0.0.1'){return this.open(p,host,false);},
31
+ close(){opened=false;url=null;sessions.clear();},
32
+ url:()=>url,
33
+ waitForDebugger(){throw new Error('inspector.waitForDebugger: synchronous block not supported in browser — attach before starting work');},
34
+ Session:class Session{constructor(){this._h={};}connect(){return this;}post(method,params,cb){queueMicrotask(()=>dispatch({send:m=>{const p=JSON.parse(m);cb&&cb(p.error||null,p.result);}},JSON.stringify({id:1,method,params})));}on(ev,fn){(this._h[ev]=this._h[ev]||[]).push(fn);return this;}disconnect(){return this;}},
35
+ console:{context:{}},
36
+ _dispatch:dispatch,
37
+ _targets:targets,
38
+ };
39
+ }
@@ -0,0 +1,131 @@
1
+ export function createChildProcess(ctx) {
2
+ async function runThroughShell(cmd) {
3
+ const shell = window.__debug?.shell;
4
+ if (!shell?.run) throw new Error('child_process: shell not ready');
5
+ let captured = '';
6
+ const origWrite = ctx.term.write.bind(ctx.term);
7
+ ctx.term.write = s => { captured += s; };
8
+ try { await shell.run(cmd); } finally { ctx.term.write = origWrite; }
9
+ return { stdout: captured.replace(/\r\n/g, '\n').replace(/\x1b\[\d+m/g, ''), code: ctx.lastExitCode | 0 };
10
+ }
11
+ return {
12
+ spawn: (cmd, args = [], opts = {}) => {
13
+ const handlers = { stdout: [], stderr: [], exit: [], close: [], error: [] };
14
+ const emit = (ev, ...a) => { for (const h of handlers[ev] || []) h(...a); };
15
+ const emitter = {
16
+ stdout: { on: (ev, fn) => { if (ev === 'data') handlers.stdout.push(fn); return emitter.stdout; }, pipe: () => emitter.stdout },
17
+ stderr: { on: (ev, fn) => { if (ev === 'data') handlers.stderr.push(fn); return emitter.stderr; } },
18
+ stdin: { write: () => true, end: () => {} },
19
+ on: (ev, fn) => { (handlers[ev] = handlers[ev] || []).push(fn); return emitter; },
20
+ once: (ev, fn) => emitter.on(ev, fn),
21
+ kill: () => {},
22
+ pid: Math.floor(Math.random() * 65535) + 1,
23
+ };
24
+ const line = [cmd, ...args].join(' ');
25
+ queueMicrotask(async () => {
26
+ try { const r = await runThroughShell(line); if (r.stdout) emit('stdout', r.stdout); emit('exit', r.code, null); emit('close', r.code, null); }
27
+ catch (e) { emit('error', e); emit('exit', 1, null); emit('close', 1, null); }
28
+ });
29
+ return emitter;
30
+ },
31
+ exec: (cmd, opts, cb) => {
32
+ if (typeof opts === 'function') { cb = opts; opts = {}; }
33
+ queueMicrotask(async () => { try { const r = await runThroughShell(cmd); cb?.(r.code === 0 ? null : Object.assign(new Error('exit ' + r.code), { code: r.code }), r.stdout, ''); } catch (e) { cb?.(e, '', String(e.message)); } });
34
+ },
35
+ execSync: cmd => { throw new Error('child_process.execSync: use exec() with callback in browser — sync subprocess impossible'); },
36
+ fork: () => { throw new Error('child_process.fork: not supported in browser'); },
37
+ };
38
+ }
39
+
40
+ export function createHttpClient(Buf) {
41
+ function makeReq(urlOrOpts, cb) {
42
+ const u = typeof urlOrOpts === 'string' ? urlOrOpts : ('http://' + (urlOrOpts.hostname || 'localhost') + ':' + (urlOrOpts.port || 80) + (urlOrOpts.path || '/'));
43
+ const opts = typeof urlOrOpts === 'object' ? urlOrOpts : {};
44
+ const handlers = { response: [], error: [], finish: [] };
45
+ const emit = (ev, ...a) => { for (const h of handlers[ev] || []) h(...a); };
46
+ let body = '';
47
+ const req = {
48
+ on: (ev, fn) => { (handlers[ev] = handlers[ev] || []).push(fn); return req; },
49
+ write: chunk => { body += String(chunk); return true; },
50
+ end: async chunk => {
51
+ if (chunk != null) body += String(chunk);
52
+ try {
53
+ const res = await fetch(u, { method: opts.method || 'GET', headers: opts.headers || {}, body: body || undefined });
54
+ const text = await res.text();
55
+ const resObj = {
56
+ statusCode: res.status, statusMessage: res.statusText, headers: Object.fromEntries(res.headers.entries()),
57
+ on: (ev, fn) => { if (ev === 'data') queueMicrotask(() => fn(Buf.from(text))); if (ev === 'end') queueMicrotask(() => fn()); return resObj; },
58
+ setEncoding: () => {}, pipe: () => {},
59
+ };
60
+ cb?.(resObj); emit('response', resObj);
61
+ } catch (e) { emit('error', e); }
62
+ },
63
+ setHeader: () => {}, getHeader: () => undefined, abort: () => {}, destroy: () => {},
64
+ };
65
+ return req;
66
+ }
67
+ return {
68
+ request: (urlOrOpts, cb) => makeReq(urlOrOpts, cb),
69
+ get: (urlOrOpts, cb) => { const r = makeReq(urlOrOpts, cb); r.end(); return r; },
70
+ Agent: class Agent {},
71
+ STATUS_CODES: { 200: 'OK', 201: 'Created', 204: 'No Content', 301: 'Moved Permanently', 302: 'Found', 400: 'Bad Request', 401: 'Unauthorized', 403: 'Forbidden', 404: 'Not Found', 500: 'Internal Server Error' },
72
+ };
73
+ }
74
+
75
+ export function extendProcess(proc, ctx) {
76
+ proc.execPath = '/usr/local/bin/node';
77
+ proc.argv0 = 'node';
78
+ proc.title = 'node';
79
+ if (!ctx.env.PATH) ctx.env.PATH = '/usr/local/bin:/usr/bin:/bin';
80
+ if (!ctx.env.HOME) ctx.env.HOME = '/root';
81
+ if (!ctx.env.USER) ctx.env.USER = 'root';
82
+ if (!ctx.env.SHELL) ctx.env.SHELL = '/bin/jsh';
83
+ if (!ctx.env.TERM) ctx.env.TERM = 'xterm-256color';
84
+ if (!ctx.env.LANG) ctx.env.LANG = 'C.UTF-8';
85
+ proc.memoryUsage = () => ({ rss: 50000000, heapTotal: 20000000, heapUsed: 10000000, external: 0, arrayBuffers: 0 });
86
+ proc.uptime = () => performance.now() / 1000;
87
+ proc.cpuUsage = () => ({ user: 0, system: 0 });
88
+ proc.getuid = () => 0; proc.getgid = () => 0; proc.geteuid = () => 0; proc.getegid = () => 0;
89
+ proc.umask = () => 0o022;
90
+ proc.features = { tls: false };
91
+ proc.release = { name: 'node', lts: false, sourceUrl: '', headersUrl: '' };
92
+ return proc;
93
+ }
94
+
95
+ export function rewriteStack(err, filename) {
96
+ if (!err.stack) return err.message;
97
+ const lines = err.stack.split('\n');
98
+ const first = lines[0];
99
+ const fname = filename || '[eval]';
100
+ const frames = lines.slice(1)
101
+ .filter(l => !l.includes('new Function') && !l.includes('AsyncFunction') && !l.includes('<anonymous>'))
102
+ .map(l => l.replace(/\bat eval \(eval at[^)]*\), /, 'at ').replace(/:(\d+):(\d+)\)?$/, (_, ln, col) => ':' + ln + ':' + col))
103
+ .slice(0, 5);
104
+ return [first, ...frames].join('\n') + '\n\nNode.js v23.10.0';
105
+ }
106
+
107
+ export function isEsmCode(code) {
108
+ const stripped = code.replace(/\/\*[\s\S]*?\*\//g, '').replace(/\/\/.*$/gm, '');
109
+ return /^\s*(import\s+[\w*{]|import\s*['"`]|export\s+(default|const|function|class|let|var|\{))/m.test(stripped);
110
+ }
111
+
112
+ export async function runEsm(code, scope) {
113
+ const injectionKeys = Object.keys(scope);
114
+ const preamble = injectionKeys.map(k => `const ${k} = globalThis.__esmScope__.${k};`).join('\n');
115
+ globalThis.__esmScope__ = scope;
116
+ const blob = new Blob([preamble + '\n' + code], { type: 'text/javascript' });
117
+ const url = URL.createObjectURL(blob);
118
+ try { return await import(url); } finally { URL.revokeObjectURL(url); }
119
+ }
120
+
121
+ export function parseDotEnv(text) {
122
+ const out = {};
123
+ for (const line of text.split(/\r?\n/)) {
124
+ const m = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/);
125
+ if (!m) continue;
126
+ let v = m[2];
127
+ if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) v = v.slice(1, -1);
128
+ out[m[1]] = v;
129
+ }
130
+ return out;
131
+ }
@@ -0,0 +1,15 @@
1
+ const CHAN='plugkit-ipc';
2
+
3
+ export function makeForkIpc(proc){
4
+ if(typeof BroadcastChannel==='undefined')return{enabled:false};
5
+ const bc=new BroadcastChannel(CHAN);
6
+ const childId=globalThis.location?.hash==='#ipc-child'?1:0;
7
+ const isChild=childId>0;
8
+ const handlers={message:[],disconnect:[]};
9
+ bc.addEventListener('message',e=>{const{from,to,msg}=e.data||{};if(isChild&&to==='child'){for(const h of handlers.message)h(msg,{});}else if(!isChild&&to==='parent'){for(const h of handlers.message)h(msg,{});}});
10
+ proc.send=msg=>{bc.postMessage({from:isChild?'child':'parent',to:isChild?'parent':'child',msg});return true;};
11
+ proc.on=(ev,fn)=>{if(ev==='message'||ev==='disconnect')(handlers[ev]=handlers[ev]||[]).push(fn);return proc;};
12
+ proc.disconnect=()=>{bc.postMessage({from:isChild?'child':'parent',to:isChild?'parent':'child',type:'disconnect'});for(const h of handlers.disconnect)h();};
13
+ proc.connected=true;
14
+ return{enabled:true,bc,isChild};
15
+ }
@@ -0,0 +1,60 @@
1
+ const pemLabel=pem=>{const m=pem.match(/-----BEGIN ([^-]+)-----/);return m?m[1]:null;};
2
+ const pemToBytes=pem=>{const m=pem.match(/-----BEGIN [^-]+-----([\s\S]+?)-----END/);if(!m)throw new Error('invalid PEM');return Uint8Array.from(atob(m[1].replace(/\s/g,'')),c=>c.charCodeAt(0));};
3
+ const bytesToPem=(bytes,label)=>`-----BEGIN ${label}-----\n${btoa(String.fromCharCode(...bytes)).match(/.{1,64}/g).join('\n')}\n-----END ${label}-----\n`;
4
+
5
+ export function makeKeyObject(pem,type){
6
+ const label=pemLabel(pem);
7
+ const inferredType=type||(label==='PRIVATE KEY'||label==='RSA PRIVATE KEY'||label==='EC PRIVATE KEY'?'private':label==='PUBLIC KEY'?'public':'secret');
8
+ const bytes=pemToBytes(pem);
9
+ const asymType=(()=>{const s=String.fromCharCode(...bytes.slice(0,Math.min(bytes.length,80)));if(s.includes('\x2A\x86\x48\xCE\x3D\x02\x01'))return'ec';if(s.includes('\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01'))return'rsa';return'unknown';})();
10
+ return{
11
+ type:inferredType,
12
+ asymmetricKeyType:asymType,
13
+ export({format='pem',type:expType}={}){
14
+ if(format==='pem'){const l=inferredType==='private'?'PRIVATE KEY':'PUBLIC KEY';return bytesToPem(bytes,l);}
15
+ if(format==='der')return bytes;
16
+ if(format==='jwk')throw new Error('KeyObject.export jwk: use webcrypto exportKey(\'jwk\') directly');
17
+ throw new Error('unsupported format: '+format);
18
+ },
19
+ toCryptoKey(){throw new Error('KeyObject.toCryptoKey: import via webcrypto.importKey instead');}
20
+ };
21
+ }
22
+
23
+ let x509Mod=null;let x509Promise=null;
24
+ async function getX509(){
25
+ if(!x509Promise)x509Promise=import('https://esm.sh/@peculiar/x509@1.9.7/es2022/x509.mjs').then(m=>m.default||m);
26
+ return x509Promise;
27
+ }
28
+ export async function preloadX509(){x509Mod=await getX509();return x509Mod;}
29
+
30
+ export class X509Certificate{
31
+ constructor(pem){
32
+ this._pem=typeof pem==='string'?pem:'-----BEGIN CERTIFICATE-----\n'+btoa(String.fromCharCode(...pem)).match(/.{1,64}/g).join('\n')+'\n-----END CERTIFICATE-----\n';
33
+ if(x509Mod){this._parsed=new x509Mod.X509Certificate(this._pem);}else{this._parsed=null;}
34
+ }
35
+ async _parse(){
36
+ if(this._parsed)return this._parsed;
37
+ const x509=await getX509();x509Mod=x509;
38
+ this._parsed=new x509.X509Certificate(this._pem);
39
+ return this._parsed;
40
+ }
41
+ async fingerprint256Async(){const p=await this._parse();const hash=await crypto.subtle.digest('SHA-256',p.rawData);return [...new Uint8Array(hash)].map(b=>b.toString(16).padStart(2,'0').toUpperCase()).join(':');}
42
+ _need(){if(!this._parsed)throw new Error('X509Certificate: call await crypto.preloadX509() once before sync access, or await cert._parse()');return this._parsed;}
43
+ get subject(){return this._need().subject;}
44
+ get issuer(){return this._need().issuer;}
45
+ get validFrom(){return this._need().notBefore.toISOString();}
46
+ get validTo(){return this._need().notAfter.toISOString();}
47
+ get serialNumber(){return this._need().serialNumber;}
48
+ get raw(){return new Uint8Array(this._need().rawData);}
49
+ toString(){return this._pem;}
50
+ }
51
+
52
+ export function extendKeys(cryptoMod){
53
+ cryptoMod.createPrivateKey=input=>{const pem=typeof input==='string'?input:input.key;return makeKeyObject(pem,'private');};
54
+ cryptoMod.createPublicKey=input=>{const pem=typeof input==='string'?input:input.key;return makeKeyObject(pem,'public');};
55
+ cryptoMod.createSecretKey=buf=>({type:'secret',symmetricKeySize:buf.length,export:()=>buf});
56
+ cryptoMod.X509Certificate=X509Certificate;
57
+ cryptoMod.KeyObject={from:pem=>makeKeyObject(pem)};
58
+ cryptoMod.preloadX509=preloadX509;
59
+ return cryptoMod;
60
+ }