@buoy-gg/mcp 7.0.47 → 7.0.49
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/chunk-2PTJT2QF.mjs +64 -0
- package/dist/chunk-MLEZPZP3.mjs +369 -0
- package/dist/cli.js +181 -111
- package/dist/cli.mjs +8 -6
- package/dist/index.d.mts +63 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +175 -107
- package/dist/index.mjs +1 -1
- package/dist/webBench-LKAOZXHK.mjs +1 -0
- package/package.json +3 -3
- package/skill/buoy-optimize/SKILL.md +12 -2
- package/dist/chunk-QF624MC2.mjs +0 -364
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import{createRequire as Y}from"module";import{join as E}from"path";import{mkdirSync as K,writeFileSync as Q}from"fs";import{pathToFileURL as X}from"url";var Z=`(() => {
|
|
2
|
+
const supported = (t) => {
|
|
3
|
+
try { return (PerformanceObserver.supportedEntryTypes || []).includes(t); } catch { return false; }
|
|
4
|
+
};
|
|
5
|
+
const frames = [], longTasks = [], loaf = [], shifts = [], observers = [];
|
|
6
|
+
const watch = (type, cb) => {
|
|
7
|
+
if (!supported(type)) return false;
|
|
8
|
+
const o = new PerformanceObserver((l) => l.getEntries().forEach(cb));
|
|
9
|
+
o.observe({ type, buffered: false });
|
|
10
|
+
observers.push([o, cb]);
|
|
11
|
+
return true;
|
|
12
|
+
};
|
|
13
|
+
const hasLong = watch("longtask", (e) => longTasks.push({ start: e.startTime, end: e.startTime + e.duration }));
|
|
14
|
+
const hasLoaf = watch("long-animation-frame", (e) => loaf.push({
|
|
15
|
+
startTime: e.startTime,
|
|
16
|
+
duration: e.duration,
|
|
17
|
+
blockingDuration: e.blockingDuration || 0,
|
|
18
|
+
styleAndLayoutStart: e.styleAndLayoutStart || 0,
|
|
19
|
+
scripts: (e.scripts || []).map((s) => {
|
|
20
|
+
const file = s.sourceURL ? s.sourceURL.split("?")[0].split("/").pop() : "";
|
|
21
|
+
const where = s.sourceFunctionName ? s.sourceFunctionName + (file ? " @ " + file : "") : file;
|
|
22
|
+
// Invokers like "FrameRequestCallback" say how a script ran, not which
|
|
23
|
+
// one; add the function and file when the browser gives them.
|
|
24
|
+
const name = s.invoker ? (where ? s.invoker + " \u2192 " + where : s.invoker) : where || "(anonymous)";
|
|
25
|
+
return { duration: s.duration, name, forced: s.forcedStyleAndLayoutDuration || 0 };
|
|
26
|
+
}),
|
|
27
|
+
}));
|
|
28
|
+
const hasShift = watch("layout-shift", (e) => shifts.push({ startTime: e.startTime, value: e.value, hadRecentInput: e.hadRecentInput }));
|
|
29
|
+
let hidden = document.visibilityState === "hidden";
|
|
30
|
+
const onVis = () => { if (document.visibilityState === "hidden") hidden = true; };
|
|
31
|
+
document.addEventListener("visibilitychange", onVis);
|
|
32
|
+
let raf = 0;
|
|
33
|
+
const tick = (t) => { frames.push(t); raf = requestAnimationFrame(tick); };
|
|
34
|
+
raf = requestAnimationFrame(tick);
|
|
35
|
+
const start = performance.now();
|
|
36
|
+
const domStart = document.getElementsByTagName("*").length;
|
|
37
|
+
window.__buoyBench = {
|
|
38
|
+
stop: () => {
|
|
39
|
+
const end = performance.now();
|
|
40
|
+
cancelAnimationFrame(raf);
|
|
41
|
+
document.removeEventListener("visibilitychange", onVis);
|
|
42
|
+
for (const [o, cb] of observers) { o.takeRecords().forEach(cb); o.disconnect(); }
|
|
43
|
+
return {
|
|
44
|
+
start, end, frames,
|
|
45
|
+
longTasks: hasLong ? longTasks : null,
|
|
46
|
+
loaf: hasLoaf ? loaf : null,
|
|
47
|
+
shifts: hasShift ? shifts : null,
|
|
48
|
+
domStart,
|
|
49
|
+
domEnd: document.getElementsByTagName("*").length,
|
|
50
|
+
hidden,
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
return true;
|
|
55
|
+
})()`;var ee=`(() => (window.__buoyBench ? window.__buoyBench.stop() : null))()`;var te=`new Promise((resolve) => {
|
|
56
|
+
let n = 0, t0 = 0;
|
|
57
|
+
const tick = (t) => {
|
|
58
|
+
if (!t0) t0 = t;
|
|
59
|
+
n++;
|
|
60
|
+
if (t - t0 >= 1000) resolve(((n - 1) / (t - t0)) * 1000);
|
|
61
|
+
else requestAnimationFrame(tick);
|
|
62
|
+
};
|
|
63
|
+
requestAnimationFrame(tick);
|
|
64
|
+
})`;var w=e=>Math.round(e*10)/10;function C(e,s){if(e.length===0)return null;const t=[...e].sort((r,n)=>r-n);const o=Math.ceil(s/100*t.length)-1;return t[Math.min(t.length-1,Math.max(0,o))]}var ne=[30,60,75,90,120,144,165,240];function R(e){for(const s of ne)if(Math.abs(e-s)/s<=.08)return s;return Math.max(1,Math.round(e))}function D(e,s){let t=s>>>0;const o=()=>{t=t+1831565813>>>0;let n=t;n=Math.imul(n^n>>>15,n|1);n^=n+Math.imul(n^n>>>7,n|61);return((n^n>>>14)>>>0)/4294967296};const r=[...e];for(let n=r.length-1;n>0;n--){const l=Math.floor(o()*(n+1));[r[n],r[l]]=[r[l],r[n]]}return r}function N(e,s,t){const o=new URL(e);const r=s.path??t;if(r)o.pathname=r.startsWith("/")?r:`${o.pathname.replace(/\/$/,"")}/${r}`;for(const[n,l]of Object.entries(s.params??{}))o.searchParams.set(n,l);return o.toString()}function A(e,s){const{start:t,end:o}=e;const r=Math.max(1,o-t);const n=[];for(let u=1;u<e.frames.length;u++)n.push(e.frames[u]-e.frames[u-1]);const l=1e3/s;const a=C(n,95);let i=null;if(e.longTasks){let u=0;for(const d of e.longTasks){const c=Math.min(d.end,o)-Math.max(d.start,t);if(c>0)u+=c}i=w(Math.min(100,u/r*100))}let v=null;let S=null;let M=null;let y=[];if(e.loaf){let u=0;let d=0;let c=0;const f=new Map;for(const h of e.loaf){if(h.startTime<t||h.startTime>o)continue;u+=h.blockingDuration;if(h.styleAndLayoutStart>h.startTime)d+=Math.max(0,h.startTime+h.duration-h.styleAndLayoutStart);for(const m of h.scripts){c+=m.forced;const g=f.get(m.name)??{ms:0,count:0};g.ms+=m.duration;g.count++;f.set(m.name,g)}}v=w(u);S=w(d);M=w(c);y=[...f.entries()].map(([h,m])=>({name:h,ms:w(m.ms),count:m.count})).sort((h,m)=>m.ms-h.ms).slice(0,5)}let $=null;if(e.shifts){let u=0;for(const d of e.shifts)if(!d.hadRecentInput&&d.startTime>=t&&d.startTime<=o)u+=d.value;$=Math.round(u*1e3)/1e3}return{fps:e.frames.length>1?w((e.frames.length-1)/r*1e3):null,frameGapP95Ms:a==null?null:w(a),frameGapMaxMs:n.length?w(Math.max(...n)):null,longFrames:n.filter(u=>u>l*1.5).length,longTaskPct:i,loafBlockingMs:v,styleLayoutMs:S,forcedLayoutMs:M,topScripts:y,layoutShift:$,domNodesStart:e.domStart,domNodesEnd:e.domEnd}}function B(e,s,t){const o=l=>l in e&&l in s?s[l]-e[l]:null;const r=l=>{const a=o(l);return a==null?null:w(a*1e3)};const n=r("TaskDuration");return{mainThreadPct:n==null?null:w(Math.min(100,n/Math.max(1,t)*100)),scriptMs:r("ScriptDuration"),styleMs:r("RecalcStyleDuration"),layoutMs:r("LayoutDuration"),layoutCount:o("LayoutCount"),styleCount:o("RecalcStyleCount"),heapMb:"JSHeapUsedSize"in s?w(s.JSHeapUsedSize/(1024*1024)):null}}function _(e,s,t){const o=[];if(e.fps!=null&&e.fps<s*.95)o.push("Main thread drops frames");if(e.frameGapMaxMs!=null&&e.frameGapMaxMs>=100)o.push(`Freeze of ${Math.round(e.frameGapMaxMs)} ms`);if(e.mainThreadPct!=null&&e.mainThreadPct>=80)o.push("Main thread near full");if(e.longTaskPct!=null&&e.longTaskPct>=20)o.push("Long tasks block the main thread");if(e.forcedLayoutMs!=null&&e.forcedLayoutMs>=50)o.push(`Forced layout in scripts (${Math.round(e.forcedLayoutMs)} ms)`);if(e.layoutShift!=null&&e.layoutShift>=.1)o.push(`Layout shifts (${e.layoutShift})`);if(t)o.push(`DOM grows each run (+${t} nodes)`);return o}function U(e,s){const t=e.filter(a=>!a.failed&&a.fps!=null);const o=[...t].sort((a,i)=>(a.fps??0)-(i.fps??0));const r=o.length?o[Math.floor((o.length-1)/2)]:null;const n=[...t].sort((a,i)=>a.round-i.round).map(a=>a.domNodesEnd).filter(a=>a!=null);let l=null;if(n.length>=3&&n.every((a,i)=>i===0||a>n[i-1])){const a=n[n.length-1]-n[0];if(a>=Math.max(50,n[0]*.05))l=a}return{caseName:e[0]?.caseName??"",cpu:e[0]?.cpu??1,validRuns:t.length,runs:e,median:r,fpsMin:o.length?o[0].fps:null,fpsMax:o.length?o[o.length-1].fps:null,domGrowth:l,flags:r?_(r,s,l):[]}}var G="Playwright isn't installed in this project. Install it, then run again:\n npm i -D playwright && npx playwright install chromium";async function ae(){const e=Y(E(process.cwd(),"noop.js"));for(const s of["playwright","playwright-core"]){try{const t=await import(X(e.resolve(s)).href);const o=t.chromium??t.default?.chromium;if(o)return o}catch{}}throw new Error(G)}function O(e){return e.replace(/\u001b\[[0-9;]*m/g,"").split("\n")[0].trim().slice(0,160)}var j=e=>new Promise(s=>setTimeout(s,e));async function I(e){const{metrics:s}=await e.send("Performance.getMetrics");return Object.fromEntries(s.map(t=>[t.name,t.value]))}async function se(e,s=()=>{}){if(e.cases.length===0)throw new Error("Give at least one case.");const t=Math.max(1,Math.min(10,e.runsPerCase??3));const o=Math.max(500,e.durationMs??5e3);const r=Math.max(0,e.settleMs??1e3);const n=(e.cpuSlowdown?.length?e.cpuSlowdown:[1]).map(u=>Math.max(1,u));let l=e.refreshHz??60;const a={width:e.viewport?.width??1280,height:e.viewport?.height??800,deviceScaleFactor:e.viewport?.deviceScaleFactor??1};const i=[];const v=[];if(t<2)i.push("runsPerCase=1 gives no spread; use 3 or more before choosing.");const S=await ae();const M=await S.launch({headless:!e.headed});const y=[];try{const u=await M.newContext({viewport:{width:a.width,height:a.height},deviceScaleFactor:a.deviceScaleFactor});const d=async(c,f,h,m)=>{const g=await u.newPage();const x=[];g.on("pageerror",p=>x.push(String(p?.message??p)));const T={caseName:c.name,cpu:f,round:h,fps:null,frameGapP95Ms:null,frameGapMaxMs:null,longFrames:0,longTaskPct:null,loafBlockingMs:null,styleLayoutMs:null,forcedLayoutMs:null,topScripts:[],layoutShift:null,domNodesStart:null,domNodesEnd:null,mainThreadPct:null,scriptMs:null,styleMs:null,layoutMs:null,layoutCount:null,styleCount:null,heapMb:null,pageErrors:x};try{const p=await u.newCDPSession(g);await p.send("Performance.enable",{timeDomain:"timeTicks"});if(f>1)await p.send("Emulation.setCPUThrottlingRate",{rate:f});const k=await g.goto(N(e.url,c,e.path),{waitUntil:"load",timeout:3e4});if(k&&k.status()>=400)return{...T,failed:`HTTP ${k.status()}`};if(e.readySelector)await g.waitForSelector(e.readySelector,{state:"attached",timeout:15e3});await j(r);if(m){await p.send("Tracing.start",{transferMode:"ReturnAsStream",categories:["devtools.timeline","disabled-by-default-devtools.timeline","disabled-by-default-devtools.timeline.frame","blink.user_timing","loading","latencyInfo","v8.execute"].join(",")})}const H=await I(p);const z=Date.now();await g.evaluate(Z);await j(o);const P=await g.evaluate(ee);const q=await I(p);const W=Date.now()-z;if(m){const J=new Promise(b=>p.on("Tracing.tracingComplete",V=>b(V.stream)));await p.send("Tracing.end");const F=await J;let L="";for(;;){const b=await p.send("IO.read",{handle:F});L+=b.base64Encoded?Buffer.from(b.data,"base64").toString("utf8"):b.data;if(b.eof)break}await p.send("IO.close",{handle:F});Q(m,L);v.push(m)}if(!P)return{...T,failed:"probe returned nothing (page navigated away?)"};if(P.hidden)return{...T,failed:"page was hidden during the run"};return{...T,...A(P,l),...B(H,q,W)}}catch(p){return{...T,failed:O(p?.message??String(p))}}finally{await g.close().catch(()=>{})}};if(e.refreshHz==null){const c=await u.newPage();try{await c.goto("about:blank");const f=await c.evaluate(te);l=R(f);s(`idle frame rate ${f.toFixed(1)} \u2192 ${l} Hz`)}catch{i.push("Couldn't measure the idle frame rate; frame budgets assume 60 Hz.")}finally{await c.close().catch(()=>{})}}s("warmup load");await d(e.cases[0],1,-1);for(const c of n){for(let f=0;f<t;f++){const h=D(e.cases,2654435769^f*7919+c);for(const m of h){s(`cpu ${c}x \xB7 round ${f+1}/${t} \xB7 ${m.name}`);y.push(await d(m,c,f))}}}if(e.traceDir){K(e.traceDir,{recursive:true});for(const c of e.cases){const f=E(e.traceDir,`${c.name.replace(/[^\w.-]+/g,"_")}.json`);s(`trace \xB7 ${c.name}`);await d(c,n[0],-1,f)}}await u.close()}finally{await M.close().catch(()=>{})}const $=[];for(const u of n){for(const d of e.cases){$.push(U(y.filter(c=>c.cpu===u&&c.caseName===d.name),l))}}if(y.some(u=>u.pageErrors.length))i.push("Some runs threw page errors; check them before trusting those cases.");return{url:e.url,browser:`Chromium ${M.version()}${e.headed?"":" (headless)"}`,viewport:a,refreshHz:l,durationMs:o,runsPerCase:t,results:$,traces:v,warnings:i}}function oe(e){const s=(r,n=1)=>r==null?"\u2014":r.toFixed(n);const t=[];t.push(`### Web benchmark \xB7 ${e.url}`);t.push(`${e.browser} \xB7 ${e.viewport.width}\xD7${e.viewport.height} @${e.viewport.deviceScaleFactor}x \xB7 ${e.runsPerCase} runs \xD7 ${e.durationMs/1e3}s per case, fresh page each run, case order shuffled each round.`);t.push("");t.push(`**No single winner \u2014 weigh the trade-offs.** FPS and frame gaps come from the page's main thread. Main thread % is Chrome's own task time for the run. Desktop numbers, even with CPU slowdown, don't stand in for a real phone's GPU, memory or heat.`);const o=Array.from(new Set(e.results.map(r=>r.cpu)));for(const r of o){t.push("");t.push(r===1?`#### No CPU slowdown`:`#### CPU slowed ${r}x`);t.push("");t.push(`| Case | FPS (range) | p95 gap ms | Worst gap ms | Long frames | Main thread % | Script ms | Style ms | Layout ms | Layouts | DOM nodes | Heap MB | Flags |`);t.push(`|------|------------:|-----------:|-------------:|------------:|--------------:|----------:|---------:|----------:|--------:|----------:|--------:|-------|`);for(const a of e.results.filter(i=>i.cpu===r)){const i=a.median;if(!i){const M=a.runs.find(y=>y.failed)?.failed??"no valid runs";t.push(`| ${a.caseName} | \u2014 | \u2014 | \u2014 | \u2014 | \u2014 | \u2014 | \u2014 | \u2014 | \u2014 | \u2014 | \u2014 | \u274C FAILED (${M}) |`);continue}const v=a.fpsMin!=null&&a.fpsMax!=null&&a.validRuns>1?` (${s(a.fpsMin)}\u2013${s(a.fpsMax)})`:"";const S=a.flags.length?`\u26A0\uFE0F ${a.flags.join("; ")}`:"\u2713 clean";t.push(`| ${a.caseName} | ${s(i.fps)}${v} | ${s(i.frameGapP95Ms)} | ${s(i.frameGapMaxMs)} | ${i.longFrames} | ${s(i.mainThreadPct)} | ${s(i.scriptMs,0)} | ${s(i.styleMs,0)} | ${s(i.layoutMs,0)} | ${s(i.layoutCount,0)} | ${s(i.domNodesEnd,0)} | ${s(i.heapMb)} | ${S} |`)}const n=e.results.filter(a=>a.cpu===r&&a.median?.fps!=null).sort((a,i)=>i.median.fps-a.median.fps);if(n.length>=2&&n[0].validRuns>1&&n[1].validRuns>1&&(n[1].fpsMax??0)>=(n[0].fpsMin??0)){t.push("");t.push(`**Too close to call:** ${n[0].caseName} and ${n[1].caseName} overlap across runs. Use more runs before picking.`)}const l=e.results.filter(a=>a.cpu===r&&a.median&&a.median.topScripts.length).map(a=>`- **${a.caseName}**: ${a.median.topScripts.slice(0,3).map(i=>`${i.name} ${i.ms} ms`).join(", ")}`);if(l.length){t.push("");t.push(`Scripts in slow frames (Long Animation Frames):`);t.push(...l)}}if(e.traces.length){t.push("");t.push(`Chrome traces (open in DevTools \u2192 Performance \u2192 Load profile): ${e.traces.join(", ")}`)}if(e.warnings.length){t.push("");t.push(...e.warnings.map(r=>`\u26A0\uFE0F ${r}`))}return t.join("\n")}export{C as percentile,R as snapRefreshRate,D as shuffled,N as caseUrl,A as summarizeProbe,B as cdpDeltas,_ as webBenchFlags,U as aggregateCase,G as PLAYWRIGHT_MISSING,O as oneLine,se as runWebBench,oe as formatWebBenchMarkdown};
|