thebird 1.2.79 → 1.2.81

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 (79) hide show
  1. package/.github/workflows/publish.yml +9 -1
  2. package/CHANGELOG.md +217 -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-fs-mirror.js +15 -0
  9. package/docs/kilo-http-stream.js +47 -0
  10. package/docs/node-builtins.js +24 -0
  11. package/docs/preview/index.html +32 -0
  12. package/docs/preview-sw-client.js +37 -6
  13. package/docs/preview-sw.js +55 -51
  14. package/docs/shell-awk.js +113 -0
  15. package/docs/shell-builtins-extra.js +121 -0
  16. package/docs/shell-builtins-text.js +109 -0
  17. package/docs/shell-builtins-util.js +112 -0
  18. package/docs/shell-builtins.js +183 -0
  19. package/docs/shell-bun.js +45 -0
  20. package/docs/shell-control.js +132 -0
  21. package/docs/shell-deno.js +54 -0
  22. package/docs/shell-exec.js +85 -0
  23. package/docs/shell-expand.js +164 -0
  24. package/docs/shell-fd.js +86 -0
  25. package/docs/shell-jobs.js +86 -0
  26. package/docs/shell-node-advanced.js +86 -0
  27. package/docs/shell-node-brotli.js +22 -0
  28. package/docs/shell-node-busnet.js +90 -0
  29. package/docs/shell-node-cipher.js +61 -0
  30. package/docs/shell-node-cluster.js +33 -0
  31. package/docs/shell-node-coreutils.js +36 -0
  32. package/docs/shell-node-crypto.js +137 -0
  33. package/docs/shell-node-dns.js +41 -0
  34. package/docs/shell-node-extras.js +148 -0
  35. package/docs/shell-node-firefox.js +95 -0
  36. package/docs/shell-node-git.js +60 -0
  37. package/docs/shell-node-inspector.js +39 -0
  38. package/docs/shell-node-io.js +131 -0
  39. package/docs/shell-node-ipc.js +15 -0
  40. package/docs/shell-node-keyobject.js +60 -0
  41. package/docs/shell-node-modules.js +157 -0
  42. package/docs/shell-node-native.js +31 -0
  43. package/docs/shell-node-net.js +71 -0
  44. package/docs/shell-node-observe.js +80 -0
  45. package/docs/shell-node-opfs.js +54 -0
  46. package/docs/shell-node-procfs.js +42 -0
  47. package/docs/shell-node-profiler.js +50 -0
  48. package/docs/shell-node-registry.js +24 -0
  49. package/docs/shell-node-resolve.js +147 -0
  50. package/docs/shell-node-runtime.js +83 -0
  51. package/docs/shell-node-srcmap.js +52 -0
  52. package/docs/shell-node-stdlib.js +103 -0
  53. package/docs/shell-node-streams.js +66 -0
  54. package/docs/shell-node-tar.js +47 -0
  55. package/docs/shell-node-testrunner.js +35 -0
  56. package/docs/shell-node-util-extras.js +66 -0
  57. package/docs/shell-node.js +175 -169
  58. package/docs/shell-npm.js +173 -0
  59. package/docs/shell-parser.js +122 -0
  60. package/docs/shell-pm-layout.js +62 -0
  61. package/docs/shell-pm.js +39 -0
  62. package/docs/shell-posix.js +70 -0
  63. package/docs/shell-procsub.js +65 -0
  64. package/docs/shell-readline.js +59 -4
  65. package/docs/shell-runtime.js +37 -0
  66. package/docs/shell-sed.js +83 -0
  67. package/docs/shell-signals.js +54 -0
  68. package/docs/shell-sw-jobs.js +76 -0
  69. package/docs/shell-ts.js +30 -0
  70. package/docs/shell.js +161 -152
  71. package/docs/terminal.js +9 -11
  72. package/docs/todo.html +211 -0
  73. package/package.json +1 -1
  74. package/server.js +43 -4
  75. package/start-kilo.js +45 -0
  76. package/test.js +199 -0
  77. package/.codeinsight +0 -73
  78. package/docs/acp-stream.js +0 -102
  79. package/docs/coi-serviceworker.js +0 -2
@@ -0,0 +1,103 @@
1
+ const COLORS = { string: '\x1b[32m', number: '\x1b[33m', boolean: '\x1b[33m', bigint: '\x1b[33m', null: '\x1b[1m', undefined: '\x1b[90m', symbol: '\x1b[35m', regexp: '\x1b[31m', date: '\x1b[35m', special: '\x1b[36m' };
2
+ const RESET = '\x1b[0m';
3
+ const paint = (s, c, on) => on ? c + s + RESET : s;
4
+
5
+ function inspectPrimitive(v, colors) {
6
+ if (v === null) return paint('null', COLORS.null, colors);
7
+ if (v === undefined) return paint('undefined', COLORS.undefined, colors);
8
+ const t = typeof v;
9
+ if (t === 'string') return paint("'" + v.replace(/\\/g, '\\\\').replace(/'/g, "\\'") + "'", COLORS.string, colors);
10
+ if (t === 'bigint') return paint(String(v) + 'n', COLORS.bigint, colors);
11
+ if (t === 'number' || t === 'boolean') return paint(String(v), COLORS[t], colors);
12
+ if (t === 'symbol') return paint(v.toString(), COLORS.symbol, colors);
13
+ if (t === 'function') return paint('[Function' + (v.name ? ': ' + v.name : ' (anonymous)') + ']', COLORS.special, colors);
14
+ return null;
15
+ }
16
+
17
+ export function inspect(v, opts = {}, depth = 0, seen = new Map(), refCount = { n: 0 }) {
18
+ const colors = !!opts.colors;
19
+ const prim = inspectPrimitive(v, colors);
20
+ if (prim !== null) return prim;
21
+ if (v instanceof Date) return paint(v.toISOString(), COLORS.date, colors);
22
+ if (v instanceof RegExp) return paint(v.toString(), COLORS.regexp, colors);
23
+ if (v instanceof Error) return v.stack || (v.name + ': ' + v.message);
24
+ if (seen.has(v)) { const id = seen.get(v); if (id.ref == null) id.ref = ++refCount.n; return '[Circular *' + id.ref + ']'; }
25
+ const entry = { ref: null }; seen.set(v, entry);
26
+ const maxDepth = opts.depth ?? 2;
27
+ if (depth > maxDepth) return Array.isArray(v) ? '[Array]' : '[Object]';
28
+ if (Array.isArray(v)) {
29
+ if (!v.length) return '[]';
30
+ return '[ ' + v.map(x => inspect(x, opts, depth + 1, seen, refCount)).join(', ') + ' ]';
31
+ }
32
+ if (v instanceof Map) {
33
+ const entries = [...v.entries()].map(([k, val]) => inspect(k, opts, depth + 1, seen, refCount) + ' => ' + inspect(val, opts, depth + 1, seen, refCount));
34
+ return 'Map(' + v.size + ')' + (v.size ? ' { ' + entries.join(', ') + ' }' : ' {}');
35
+ }
36
+ if (v instanceof Set) {
37
+ const items = [...v].map(x => inspect(x, opts, depth + 1, seen, refCount));
38
+ return 'Set(' + v.size + ')' + (v.size ? ' { ' + items.join(', ') + ' }' : ' {}');
39
+ }
40
+ if (v instanceof Uint8Array) {
41
+ const hex = [...v.slice(0, 16)].map(b => b.toString(16).padStart(2, '0')).join(' ');
42
+ return '<Buffer ' + hex + (v.length > 16 ? ' ... ' + (v.length - 16) + ' more bytes' : '') + '>';
43
+ }
44
+ const keys = opts.showHidden ? Object.getOwnPropertyNames(v) : Object.keys(v);
45
+ const syms = Object.getOwnPropertySymbols(v);
46
+ if (!keys.length && !syms.length) return '{}';
47
+ const parts = keys.map(k => {
48
+ const ks = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(k) ? k : "'" + k + "'";
49
+ return ks + ': ' + inspect(v[k], opts, depth + 1, seen, refCount);
50
+ }).concat(syms.map(s => '[' + s.toString() + ']: ' + inspect(v[s], opts, depth + 1, seen, refCount)));
51
+ const ctor = v.constructor && v.constructor !== Object ? v.constructor.name + ' ' : '';
52
+ const body = ctor + '{ ' + parts.join(', ') + ' }';
53
+ return entry.ref != null ? '<ref *' + entry.ref + '> ' + body : body;
54
+ }
55
+
56
+ export function format(...args) {
57
+ if (!args.length) return '';
58
+ const fmt = args[0];
59
+ if (typeof fmt !== 'string') return args.map(a => typeof a === 'object' ? inspect(a) : String(a)).join(' ');
60
+ let i = 1;
61
+ const out = fmt.replace(/%[sdifjoO%]/g, m => {
62
+ if (m === '%%') return '%';
63
+ if (i >= args.length) return m;
64
+ const a = args[i++];
65
+ if (m === '%s') return String(a);
66
+ if (m === '%d' || m === '%i') return String(parseInt(a, 10));
67
+ if (m === '%f') return String(parseFloat(a));
68
+ if (m === '%j') return JSON.stringify(a);
69
+ if (m === '%o' || m === '%O') return inspect(a);
70
+ return m;
71
+ });
72
+ const extra = args.slice(i).map(a => typeof a === 'object' ? inspect(a) : String(a));
73
+ return extra.length ? out + ' ' + extra.join(' ') : out;
74
+ }
75
+
76
+ export { createHash } from './shell-node-crypto.js';
77
+
78
+ let fflatePromise = null;
79
+ async function getFflate() {
80
+ if (!fflatePromise) fflatePromise = import('https://esm.sh/fflate@0.8.2/es2022/fflate.mjs').then(m => m.gzipSync ? m : (m.default && m.default.gzipSync ? m.default : m));
81
+ return fflatePromise;
82
+ }
83
+ let fflateSync = null;
84
+ export async function preloadFflate() { fflateSync = await getFflate(); return fflateSync; }
85
+
86
+ export function createZlib(Buf) {
87
+ const need = () => { if (!fflateSync) throw new Error('zlib sync: preloadFflate() must run before sync zlib calls (auto-preloaded on node entry)'); return fflateSync; };
88
+ return {
89
+ gzipSync: b => Buf.from(need().gzipSync(b instanceof Uint8Array ? b : new TextEncoder().encode(String(b)))),
90
+ gunzipSync: b => Buf.from(need().gunzipSync(b)),
91
+ deflateSync: b => Buf.from(need().deflateSync(b instanceof Uint8Array ? b : new TextEncoder().encode(String(b)))),
92
+ inflateSync: b => Buf.from(need().inflateSync(b)),
93
+ deflateRawSync: b => Buf.from(need().deflateSync(b, { raw: true }) || need().deflateSync(b)),
94
+ inflateRawSync: b => Buf.from(need().inflateSync(b, { raw: true }) || need().inflateSync(b)),
95
+ gzip: async (buf, cb) => { try { const p = await getFflate(); const out = Buf.from(p.gzipSync(buf instanceof Uint8Array ? buf : new TextEncoder().encode(String(buf)))); if (cb) cb(null, out); return out; } catch (e) { if (cb) cb(e); else throw e; } },
96
+ gunzip: async (buf, cb) => { try { const p = await getFflate(); const out = Buf.from(p.gunzipSync(buf)); if (cb) cb(null, out); return out; } catch (e) { if (cb) cb(e); else throw e; } },
97
+ deflate: async (buf, cb) => { const p = await getFflate(); const out = Buf.from(p.deflateSync(buf instanceof Uint8Array ? buf : new TextEncoder().encode(String(buf)))); if (cb) cb(null, out); return out; },
98
+ inflate: async (buf, cb) => { const p = await getFflate(); const out = Buf.from(p.inflateSync(buf)); if (cb) cb(null, out); return out; },
99
+ createGzip: () => ({ pipe: () => {}, on: () => {}, write: () => {}, end: () => {} }),
100
+ createGunzip: () => ({ pipe: () => {}, on: () => {}, write: () => {}, end: () => {} }),
101
+ constants: { Z_NO_FLUSH: 0, Z_PARTIAL_FLUSH: 1, Z_SYNC_FLUSH: 2, Z_FULL_FLUSH: 3, Z_FINISH: 4, Z_BLOCK: 5, Z_TREES: 6, Z_OK: 0, Z_STREAM_END: 1 },
102
+ };
103
+ }
@@ -0,0 +1,66 @@
1
+ function makeEmitter(){
2
+ const h={};
3
+ return {
4
+ on(e,f){(h[e]=h[e]||[]).push(f);return this;},
5
+ once(e,f){const w=(...a)=>{this.off(e,w);f(...a);};return this.on(e,w);},
6
+ off(e,f){h[e]=(h[e]||[]).filter(x=>x!==f);return this;},
7
+ removeListener(e,f){return this.off(e,f);},
8
+ removeAllListeners(e){if(e)delete h[e];else for(const k of Object.keys(h))delete h[k];return this;},
9
+ emit(e,...a){for(const f of(h[e]||[]).slice())f(...a);return(h[e]||[]).length>0;},
10
+ listenerCount(e){return(h[e]||[]).length;},
11
+ _h:h,
12
+ };
13
+ }
14
+
15
+ class Readable{
16
+ constructor(opts={}){
17
+ Object.assign(this,makeEmitter());
18
+ this._q=[];this._ended=false;this._flowing=null;this._paused=false;this._destroyed=false;
19
+ this.readable=true;this.readableHighWaterMark=opts.highWaterMark??16384;this.readableEnded=false;this.readableObjectMode=!!opts.objectMode;
20
+ this._read=opts.read||(()=>{});this._encoding=null;
21
+ }
22
+ push(chunk){if(chunk===null){this._ended=true;queueMicrotask(()=>this._drain());return false;}this._q.push(chunk);queueMicrotask(()=>this._drain());return this._q.length<this.readableHighWaterMark;}
23
+ read(n){if(!this._q.length)return null;return n?this._q.shift():this._q.shift();}
24
+ _drain(){if(this._paused||this._destroyed)return;while(this._q.length){const c=this._q.shift();const data=this._encoding&&c instanceof Uint8Array?new TextDecoder(this._encoding).decode(c):c;this.emit('data',data);}if(this._ended&&!this.readableEnded){this.readableEnded=true;this.emit('end');}}
25
+ pause(){this._paused=true;return this;}
26
+ resume(){this._paused=false;queueMicrotask(()=>this._drain());return this;}
27
+ pipe(dest){this.on('data',c=>{if(dest.write(c)===false)this.pause();});this.on('end',()=>dest.end?.());dest.on?.('drain',()=>this.resume());return dest;}
28
+ unpipe(){return this;}
29
+ setEncoding(enc){this._encoding=enc;return this;}
30
+ destroy(e){this._destroyed=true;if(e)this.emit('error',e);this.emit('close');return this;}
31
+ [Symbol.asyncIterator](){const self=this;return{async next(){if(self._q.length)return{value:self._q.shift(),done:false};if(self._ended)return{value:undefined,done:true};return new Promise(r=>{const onData=c=>{self.off('data',onData);self.off('end',onEnd);r({value:c,done:false});};const onEnd=()=>{self.off('data',onData);r({value:undefined,done:true});};self.on('data',onData);self.once('end',onEnd);});}};}
32
+ }
33
+
34
+ class Writable{
35
+ constructor(opts={}){
36
+ Object.assign(this,makeEmitter());
37
+ this._write=opts.write||((c,e,cb)=>cb());this.writable=true;this.writableEnded=false;this.writableFinished=false;this.writableHighWaterMark=opts.highWaterMark??16384;this._pending=0;
38
+ }
39
+ write(chunk,enc,cb){if(typeof enc==='function'){cb=enc;enc=null;}if(this.writableEnded){const e=Object.assign(new Error('write after end'),{code:'ERR_STREAM_WRITE_AFTER_END'});queueMicrotask(()=>cb?.(e));return false;}this._pending++;this._write(chunk,enc,err=>{this._pending--;cb?.(err);if(this._pending===0)this.emit('drain');});return this._pending<this.writableHighWaterMark;}
40
+ end(chunk,enc,cb){if(chunk!=null)this.write(chunk,enc);this.writableEnded=true;queueMicrotask(()=>{this.writableFinished=true;this.emit('finish');this.emit('close');cb?.();});return this;}
41
+ destroy(e){if(e)this.emit('error',e);this.emit('close');return this;}
42
+ }
43
+
44
+ class Duplex extends Readable{constructor(opts={}){super(opts);Object.assign(this,new Writable(opts));this._write=opts.write||((c,e,cb)=>cb());}write(...a){return Writable.prototype.write.call(this,...a);}end(...a){return Writable.prototype.end.call(this,...a);}}
45
+
46
+ class Transform extends Duplex{
47
+ constructor(opts={}){super(opts);this._transform=opts.transform||((c,e,cb)=>cb(null,c));this._flush=opts.flush||(cb=>cb());this._write=(c,e,cb)=>{this._transform(c,e,(err,out)=>{if(err)return cb(err);if(out!=null)this.push(out);cb();});};const origEnd=this.end.bind(this);this.end=(...a)=>{this._flush((err,out)=>{if(out!=null)this.push(out);this.push(null);});return origEnd(...a);};}
48
+ }
49
+
50
+ class PassThrough extends Transform{constructor(opts){super({...opts,transform:(c,e,cb)=>cb(null,c)});}}
51
+
52
+ function pipeline(...args){const cb=typeof args[args.length-1]==='function'?args.pop():null;const streams=args;let done=false;const fin=e=>{if(done)return;done=true;cb?.(e);};for(let i=0;i<streams.length-1;i++){const src=streams[i],dst=streams[i+1];src.on('error',fin);src.pipe(dst);}streams[streams.length-1].on('finish',()=>fin(null));streams[streams.length-1].on('error',fin);return streams[streams.length-1];}
53
+
54
+ function finished(stream,cb){const onFin=()=>cb();const onErr=e=>cb(e);stream.on?.('finish',onFin);stream.on?.('end',onFin);stream.on?.('error',onErr);return()=>{stream.off?.('finish',onFin);stream.off?.('end',onFin);stream.off?.('error',onErr);};}
55
+
56
+ export function makeStream(){
57
+ const mod={Readable,Writable,Duplex,Transform,PassThrough,pipeline,finished,promises:{pipeline:(...a)=>new Promise((res,rej)=>pipeline(...a,e=>e?rej(e):res())),finished:s=>new Promise((res,rej)=>finished(s,e=>e?rej(e):res()))}};
58
+ Readable.from=iter=>{const r=new Readable();(async()=>{try{for await(const c of iter)r.push(c);r.push(null);}catch(e){r.destroy(e);}})();return r;};
59
+ return mod;
60
+ }
61
+
62
+ export function extendFsStreams(fs,Buf){
63
+ fs.createReadStream=(path,opts={})=>{const r=new Readable();queueMicrotask(()=>{try{const data=fs.readFileSync(path);const buf=typeof data==='string'?Buf.from(data):data;const start=opts.start||0;const end=opts.end??buf.length;r.push(buf.slice(start,end));r.push(null);}catch(e){r.destroy(e);}});return r;};
64
+ fs.createWriteStream=(path,opts={})=>{const chunks=[];const w=new Writable({write:(c,e,cb)=>{chunks.push(typeof c==='string'?Buf.from(c):c);cb();}});w.on('finish',()=>{try{fs.writeFileSync(path,Buf.concat(chunks));}catch(e){w.emit('error',e);}});return w;};
65
+ return fs;
66
+ }
@@ -0,0 +1,47 @@
1
+ const BLOCK=512;
2
+ const readStr=(buf,o,len)=>{let e=o;while(e<o+len&&buf[e]!==0)e++;return new TextDecoder().decode(buf.slice(o,e));};
3
+ const readOctal=(buf,o,len)=>{const s=readStr(buf,o,len).trim();return s?parseInt(s,8):0;};
4
+
5
+ export function untar(data){
6
+ const buf=data instanceof Uint8Array?data:new Uint8Array(data);
7
+ const entries=[];let off=0;
8
+ while(off+BLOCK<=buf.length){
9
+ if(buf[off]===0&&buf[off+BLOCK-1]===0){off+=BLOCK;continue;}
10
+ const name=readStr(buf,off,100);
11
+ if(!name)break;
12
+ const mode=readOctal(buf,off+100,8);
13
+ const size=readOctal(buf,off+124,12);
14
+ const mtime=readOctal(buf,off+136,12);
15
+ const type=String.fromCharCode(buf[off+156]||0x30);
16
+ const prefix=readStr(buf,off+345,155);
17
+ const fullName=prefix?prefix+'/'+name:name;
18
+ const dataStart=off+BLOCK;
19
+ const dataEnd=dataStart+size;
20
+ const body=type==='0'||type==='\0'?buf.slice(dataStart,dataEnd):null;
21
+ entries.push({name:fullName,mode,size,mtime,type,data:body});
22
+ const padded=Math.ceil(size/BLOCK)*BLOCK;
23
+ off=dataStart+padded;
24
+ }
25
+ return entries;
26
+ }
27
+
28
+ export function makeTar(fs,fflate,Buf){
29
+ return{
30
+ async extract(data,dest='/'){
31
+ let bytes=data instanceof Uint8Array?data:new Uint8Array(data);
32
+ if(bytes[0]===0x1f&&bytes[1]===0x8b){bytes=fflate?.gunzipSync?fflate.gunzipSync(bytes):bytes;}
33
+ const entries=untar(bytes);
34
+ const out=[];
35
+ for(const e of entries){
36
+ if(!e.data&&e.type!=='5')continue;
37
+ const target=(dest.replace(/\/$/,'')+'/'+e.name).replace(/^\/+/,'/');
38
+ if(e.type==='5'){try{fs.mkdirSync(target,{recursive:true});}catch{}}
39
+ else{const parts=target.split('/');for(let i=1;i<parts.length;i++){const d=parts.slice(0,i).join('/');if(d&&!fs.existsSync(d)){try{fs.mkdirSync(d,{recursive:true});}catch{}}}fs.writeFileSync(target,Buf.from(e.data));}
40
+ out.push(target);
41
+ }
42
+ return out;
43
+ },
44
+ async list(data){let bytes=data instanceof Uint8Array?data:new Uint8Array(data);if(bytes[0]===0x1f&&bytes[1]===0x8b)bytes=fflate?.gunzipSync?fflate.gunzipSync(bytes):bytes;return untar(bytes).map(e=>e.name);},
45
+ untar,
46
+ };
47
+ }
@@ -0,0 +1,35 @@
1
+ export function makeTestRunner(term){
2
+ const suites=[];let current=null;const results={pass:0,fail:0,skip:0,failures:[]};
3
+ const write=term?(s=>term.write(s)):(s=>console.log(s.replace(/\r\n/g,'')));
4
+ const color=(c,s)=>`\x1b[${c}m${s}\x1b[0m`;
5
+ async function runOne(name,fn,parentPath=''){
6
+ const path=(parentPath?parentPath+' > ':'')+name;
7
+ if(!fn){results.skip++;write(color(33,' - '+path+' (skip)')+'\r\n');return;}
8
+ const t0=performance.now();
9
+ try{await fn(tctx(name,path));results.pass++;write(color(32,' ✓ '+path)+` ${(performance.now()-t0).toFixed(1)}ms\r\n`);}
10
+ catch(e){results.fail++;results.failures.push({path,error:e});write(color(31,' ✗ '+path+' — '+e.message)+'\r\n');}
11
+ }
12
+ function tctx(name,path){return{name,fullName:path,diagnostic(m){write(color(90,' # '+m)+'\r\n');},skip(){throw Object.assign(new Error('skip'),{__skip:true});},todo(){throw Object.assign(new Error('todo'),{__todo:true});},signal:new AbortController().signal,plan(n){}};}
13
+ function test(name,optsOrFn,maybeFn){const fn=typeof optsOrFn==='function'?optsOrFn:maybeFn;const opts=typeof optsOrFn==='object'?optsOrFn:{};if(opts.skip)return runOne(name,null);if(opts.only){}if(current){current.tests.push({name,fn});return Promise.resolve();}return runOne(name,fn);}
14
+ function describe(name,fn){const prev=current;current={name,tests:[],parentPath:prev?prev.fullPath:'',fullPath:(prev?prev.fullPath+' > ':'')+name};try{fn(current);}finally{const c=current;current=prev;return(async()=>{for(const t of c.tests)await runOne(t.name,t.fn,c.fullPath);})();}}
15
+ const mock={
16
+ fn(impl){const calls=[];const mk=function(...a){calls.push({arguments:a,result:undefined,error:undefined,target:this});try{const r=impl?impl.apply(this,a):undefined;calls[calls.length-1].result=r;return r;}catch(e){calls[calls.length-1].error=e;throw e;}};mk.mock={calls,callCount(){return calls.length;},resetCalls(){calls.length=0;},restore(){}};return mk;},
17
+ method(obj,key,impl){const orig=obj[key];const m=mock.fn(impl||orig);obj[key]=m;m.mock.restore=()=>{obj[key]=orig;};return m;},
18
+ timers:{enable(){},reset(){},runAll(){},tick(){},restore(){}},
19
+ };
20
+ const api={test,describe,it:test,before:fn=>fn?.(),after:fn=>fn?.(),beforeEach:()=>{},afterEach:()=>{},mock,run(){},results,
21
+ async summarize(){write('\r\n'+color(1,`# tests ${results.pass+results.fail+results.skip}`)+'\r\n');write(color(32,`# pass ${results.pass}`)+'\r\n');write(color(31,`# fail ${results.fail}`)+'\r\n');write(color(33,`# skip ${results.skip}`)+'\r\n');return results.fail===0;},
22
+ };
23
+ return api;
24
+ }
25
+
26
+ export function makeTapReporter(term){
27
+ const w=term?(s=>term.write(s)):(s=>console.log(s));
28
+ let n=0;
29
+ return{
30
+ ok(name){w(`ok ${++n} - ${name}\r\n`);},
31
+ notOk(name,msg){w(`not ok ${++n} - ${name}\r\n ---\r\n error: ${msg}\r\n ...\r\n`);},
32
+ plan(total){w(`1..${total}\r\n`);},
33
+ comment(m){w(`# ${m}\r\n`);},
34
+ };
35
+ }
@@ -0,0 +1,66 @@
1
+ const ANSI_RE=/\x1b\[[0-9;]*[a-zA-Z]/g;
2
+ const STYLE_CODES={reset:0,bold:1,dim:2,italic:3,underline:4,inverse:7,hidden:8,strikethrough:9,black:30,red:31,green:32,yellow:33,blue:34,magenta:35,cyan:36,white:37,gray:90,bgBlack:40,bgRed:41,bgGreen:42,bgYellow:43,bgBlue:44,bgMagenta:45,bgCyan:46,bgWhite:47};
3
+
4
+ export function styleText(styles,text){
5
+ const arr=Array.isArray(styles)?styles:[styles];
6
+ const codes=arr.map(s=>STYLE_CODES[s]).filter(c=>c!=null);
7
+ if(!codes.length)return text;
8
+ return `\x1b[${codes.join(';')}m${text}\x1b[0m`;
9
+ }
10
+
11
+ export function stripVTControlCharacters(s){return String(s).replace(ANSI_RE,'');}
12
+
13
+ export function getCallSites(frames=10){
14
+ const e=new Error();const lines=(e.stack||'').split('\n').slice(2,2+frames);
15
+ return lines.map(l=>{const m=l.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?/);return{functionName:m?.[1]||'<anonymous>',scriptName:m?.[2]||'',lineNumber:m?+m[3]:0,column:m?+m[4]:0,scriptId:'0'};});
16
+ }
17
+
18
+ export class MIMEType{
19
+ constructor(input){
20
+ const [essence,...paramParts]=String(input).split(';');
21
+ const [type,subtype]=essence.trim().split('/');
22
+ if(!type||!subtype)throw new TypeError('Invalid MIME: '+input);
23
+ this._type=type.toLowerCase();this._sub=subtype.toLowerCase();
24
+ this._params=new MIMEParams();
25
+ for(const p of paramParts){const [k,v]=p.split('=');if(k&&v)this._params.set(k.trim().toLowerCase(),v.trim().replace(/^["']|["']$/g,''));}
26
+ }
27
+ get type(){return this._type;}set type(v){this._type=String(v).toLowerCase();}
28
+ get subtype(){return this._sub;}set subtype(v){this._sub=String(v).toLowerCase();}
29
+ get essence(){return `${this._type}/${this._sub}`;}
30
+ get params(){return this._params;}
31
+ toString(){const p=[...this._params].map(([k,v])=>`${k}=${v}`).join(';');return this.essence+(p?';'+p:'');}
32
+ }
33
+
34
+ export class MIMEParams{
35
+ constructor(){this._m=new Map();}
36
+ get(k){return this._m.get(k);}
37
+ set(k,v){this._m.set(String(k).toLowerCase(),String(v));return this;}
38
+ delete(k){return this._m.delete(k);}
39
+ has(k){return this._m.has(k);}
40
+ *entries(){yield*this._m.entries();}
41
+ *keys(){yield*this._m.keys();}
42
+ *values(){yield*this._m.values();}
43
+ [Symbol.iterator](){return this._m[Symbol.iterator]();}
44
+ }
45
+
46
+ export function makeConsoleExtras(origConsole,term){
47
+ const write=term?(s=>term.write(s)):(s=>origConsole.log(s));
48
+ const timers=new Map();const counters=new Map();let groupDepth=0;const ind=()=>' '.repeat(groupDepth);
49
+ return{
50
+ table(data,columns){if(!data||typeof data!=='object')return origConsole.log(data);const rows=Array.isArray(data)?data:Object.entries(data).map(([k,v])=>({'(index)':k,...(typeof v==='object'?v:{Values:v})}));if(!rows.length)return;const cols=columns||[...new Set(rows.flatMap(r=>Object.keys(r)))];const w=cols.map(c=>Math.max(c.length,...rows.map(r=>String(r[c]??'').length)));const line=(cells,pad)=>'│ '+cells.map((c,i)=>String(c??'').padEnd(w[i]))+' │\r\n';const sep=s=>s+cols.map((_,i)=>'─'.repeat(w[i]+2)).join(s==='├'?'┼':'─')+(s==='├'?'┤':'╯')+'\r\n';write('╭'+cols.map((_,i)=>'─'.repeat(w[i]+2)).join('─')+'╮\r\n');write('│ '+cols.map((c,i)=>c.padEnd(w[i])).join(' │ ')+' │\r\n');write('├'+cols.map((_,i)=>'─'.repeat(w[i]+2)).join('┼')+'┤\r\n');for(const r of rows)write('│ '+cols.map((c,i)=>String(r[c]??'').padEnd(w[i])).join(' │ ')+' │\r\n');write('╰'+cols.map((_,i)=>'─'.repeat(w[i]+2)).join('─')+'╯\r\n');},
51
+ group(label){if(label)write(ind()+label+'\r\n');groupDepth++;},
52
+ groupCollapsed(label){this.group(label);},
53
+ groupEnd(){groupDepth=Math.max(0,groupDepth-1);},
54
+ time(label='default'){timers.set(label,performance.now());},
55
+ timeEnd(label='default'){const t=timers.get(label);if(t==null)return;timers.delete(label);write(`${label}: ${(performance.now()-t).toFixed(3)}ms\r\n`);},
56
+ timeLog(label='default',...rest){const t=timers.get(label);if(t==null)return;write(`${label}: ${(performance.now()-t).toFixed(3)}ms ${rest.join(' ')}\r\n`);},
57
+ count(label='default'){const n=(counters.get(label)||0)+1;counters.set(label,n);write(`${label}: ${n}\r\n`);},
58
+ countReset(label='default'){counters.set(label,0);},
59
+ dir(v){write(JSON.stringify(v,null,2)+'\r\n');},
60
+ dirxml(v){this.dir(v);},
61
+ trace(...a){write('Trace: '+a.join(' ')+'\r\n'+new Error().stack+'\r\n');},
62
+ assert(cond,...msg){if(!cond)write('Assertion failed: '+msg.join(' ')+'\r\n');},
63
+ clear(){write('\x1b[2J\x1b[H');},
64
+ profile(){},profileEnd(){},timeStamp(){},
65
+ };
66
+ }