@buoy-gg/mcp 7.0.20 → 7.0.22
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-S5NQ6EUN.mjs → chunk-5C6BLMHY.mjs} +1386 -96
- package/dist/cli.js +1386 -96
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +147 -10
- package/dist/index.d.ts +147 -10
- package/dist/index.js +1386 -96
- package/dist/index.mjs +1 -1
- package/package.json +5 -3
package/dist/cli.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -57,11 +57,31 @@ declare class SyncClient {
|
|
|
57
57
|
private pendingActions;
|
|
58
58
|
/** Callbacks waiting for the next snapshot of `${deviceId}::${toolId}`. */
|
|
59
59
|
private snapshotWaiters;
|
|
60
|
+
/** When each cached snapshot arrived, keyed by snapKey (staleness reporting). */
|
|
61
|
+
private snapshotAt;
|
|
62
|
+
/** Liveness per device — see {@link noteTimeout}. */
|
|
63
|
+
private health;
|
|
64
|
+
/** Dev-server origin per device — see {@link noteDevServerOrigin}. */
|
|
65
|
+
private devServerOrigins;
|
|
66
|
+
/** Devices whose origin probe already ran (a production bundle has none). */
|
|
67
|
+
private originProbed;
|
|
68
|
+
/** Last time each device appeared in the broker's device list. */
|
|
69
|
+
private lastSeen;
|
|
60
70
|
constructor(opts?: SyncClientOptions);
|
|
61
71
|
private readonly autoSpawn;
|
|
62
72
|
/** Connect to a running broker, or spawn one in-process, then handshake. */
|
|
63
73
|
start(): Promise<BrokerMode>;
|
|
64
74
|
private connectSocket;
|
|
75
|
+
/**
|
|
76
|
+
* Drop everything remembered about devices that have been gone a while.
|
|
77
|
+
*
|
|
78
|
+
* Deliberately NOT on disconnect: a crashed app often drops off the broker,
|
|
79
|
+
* and its cached console snapshot is the crash evidence — throwing that away
|
|
80
|
+
* the instant it disconnects would delete the answer. But device ids change
|
|
81
|
+
* with every simulator erase and fresh dev client, and each one can hold
|
|
82
|
+
* multi-MB snapshots, so a long-lived server has to forget eventually.
|
|
83
|
+
*/
|
|
84
|
+
private pruneStaleDevices;
|
|
65
85
|
/** Disconnect and tear down a spawned broker, if any. */
|
|
66
86
|
stop(): Promise<void>;
|
|
67
87
|
/** All devices the broker knows about, merged with their advertised tools. */
|
|
@@ -91,6 +111,61 @@ declare class SyncClient {
|
|
|
91
111
|
* is blocked.
|
|
92
112
|
*/
|
|
93
113
|
requireProDevice(deviceId?: string): string;
|
|
114
|
+
private healthOf;
|
|
115
|
+
/** The device answered — it's alive. */
|
|
116
|
+
private noteOk;
|
|
117
|
+
/**
|
|
118
|
+
* The device didn't answer. A crashed app never answers again, so after the
|
|
119
|
+
* first miss we stop paying the full timeout on every subsequent call.
|
|
120
|
+
*/
|
|
121
|
+
private noteTimeout;
|
|
122
|
+
/** True once a device has missed a call and hasn't answered since. */
|
|
123
|
+
isUnresponsive(deviceId: string): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Full timeout normally; a short one for a device already not answering.
|
|
126
|
+
*
|
|
127
|
+
* With one escape hatch: every RECOVERY_PROBE_MS a flagged device gets the
|
|
128
|
+
* full budget again. Without it the flag is self-sustaining — a device whose
|
|
129
|
+
* work legitimately takes longer than the short budget (a big snapshot, a
|
|
130
|
+
* slow simulator) can never answer, so it can never clear the flag, and every
|
|
131
|
+
* later reply is a confident "most likely CRASHED" about a healthy app.
|
|
132
|
+
*/
|
|
133
|
+
private timeoutFor;
|
|
134
|
+
/**
|
|
135
|
+
* Plain-language diagnosis for a device that isn't answering, including the
|
|
136
|
+
* app's last words if the console tool got a crash flush out in time.
|
|
137
|
+
*
|
|
138
|
+
* A silent timeout is the worst possible answer here: the app is on a redbox,
|
|
139
|
+
* the reason is already captured, and without this the caller reads "timed
|
|
140
|
+
* out" and keeps retrying the same dead device.
|
|
141
|
+
*/
|
|
142
|
+
unresponsiveNote(deviceId: string): string;
|
|
143
|
+
/**
|
|
144
|
+
* The newest error line the console tool synced for this device, if any.
|
|
145
|
+
* Reads the cached console snapshot rather than the device (which, by the
|
|
146
|
+
* time this matters, is not answering).
|
|
147
|
+
*/
|
|
148
|
+
private lastFatalFor;
|
|
149
|
+
/** Age of the cached snapshot for a tool, in ms (null = never received). */
|
|
150
|
+
snapshotAgeMs(toolId: string, deviceId: string): number | null;
|
|
151
|
+
/**
|
|
152
|
+
* Remember where a device's bundle came from, reported by core's `app`
|
|
153
|
+
* adapter while the app is healthy. It is the only way to reload an app that
|
|
154
|
+
* has crashed: the in-app reload needs the React tree that the crash
|
|
155
|
+
* destroyed, but the dev server's reload is handled natively.
|
|
156
|
+
*/
|
|
157
|
+
noteDevServerOrigin(deviceId: string, origin: unknown): void;
|
|
158
|
+
/**
|
|
159
|
+
* Ask a freshly-announced device where its bundle came from, once.
|
|
160
|
+
*
|
|
161
|
+
* Deliberately eager: this is the piece of information that can ONLY be
|
|
162
|
+
* collected while the app is healthy, and is only ever needed after it has
|
|
163
|
+
* stopped answering. One cheap round-trip per device buys the ability to
|
|
164
|
+
* recover a crashed app instead of telling the caller to go do it by hand.
|
|
165
|
+
*/
|
|
166
|
+
private learnDevServerOrigin;
|
|
167
|
+
/** The dev-server origin last reported by this device, if any. */
|
|
168
|
+
devServerOrigin(deviceId: string): string | null;
|
|
94
169
|
/**
|
|
95
170
|
* Keep the device RECORDING this tool, without asking it to stream.
|
|
96
171
|
*
|
|
@@ -135,10 +210,14 @@ declare class SyncClient {
|
|
|
135
210
|
*/
|
|
136
211
|
getSnapshot(toolId: string, deviceId?: string, opts?: {
|
|
137
212
|
timeoutMs?: number;
|
|
213
|
+
silent?: boolean;
|
|
138
214
|
}): Promise<{
|
|
139
215
|
deviceId: string;
|
|
140
216
|
payload: unknown;
|
|
217
|
+
stale?: string;
|
|
141
218
|
}>;
|
|
219
|
+
/** Header line for data served from cache because the device went quiet. */
|
|
220
|
+
private staleNote;
|
|
142
221
|
private waitForSnapshot;
|
|
143
222
|
/**
|
|
144
223
|
* Invoke a remote action on a device and await its result. Pass deviceId to
|
|
@@ -146,14 +225,10 @@ declare class SyncClient {
|
|
|
146
225
|
*/
|
|
147
226
|
callAction(toolId: string, action: string, params?: unknown, deviceId?: string, opts?: {
|
|
148
227
|
timeoutMs?: number;
|
|
228
|
+
silent?: boolean;
|
|
149
229
|
}): Promise<unknown>;
|
|
150
230
|
}
|
|
151
231
|
|
|
152
|
-
/**
|
|
153
|
-
* Build the Buoy MCP server and register all tools against a connected
|
|
154
|
-
* {@link SyncClient}. Tool packs (perf-monitor, etc.) are layered on top of the
|
|
155
|
-
* generic core here.
|
|
156
|
-
*/
|
|
157
232
|
declare function createMcpServer(sync: SyncClient): McpServer;
|
|
158
233
|
|
|
159
234
|
/**
|
|
@@ -381,10 +456,12 @@ interface IndexEntry {
|
|
|
381
456
|
/** Render-capture mirror (absent when capture was unavailable/disabled). */
|
|
382
457
|
renderCommits?: number;
|
|
383
458
|
renderTotalMs?: number;
|
|
459
|
+
renderWasted?: number;
|
|
384
460
|
topRenderers?: {
|
|
385
461
|
name: string;
|
|
386
462
|
renders: number;
|
|
387
463
|
totalMs: number;
|
|
464
|
+
cause?: string;
|
|
388
465
|
}[];
|
|
389
466
|
}
|
|
390
467
|
/** Per-metric min/max/avg/p95 channel. */
|
|
@@ -406,12 +483,40 @@ interface BenchmarkReportStats {
|
|
|
406
483
|
uiJankFrames: number;
|
|
407
484
|
deviceMaxRefreshRate: number;
|
|
408
485
|
}
|
|
409
|
-
|
|
410
486
|
/**
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
*
|
|
487
|
+
* Why components rendered, counted over a run.
|
|
488
|
+
*
|
|
489
|
+
* `propsUnstable` is the actionable one: props changed by IDENTITY only —
|
|
490
|
+
* a fresh arrow or object literal handed down every render — while every
|
|
491
|
+
* value stayed equal. Reporting that as plain "props" sends you into the
|
|
492
|
+
* child, when the fix is always in the parent.
|
|
414
493
|
*/
|
|
494
|
+
interface RenderCauseCounts {
|
|
495
|
+
mount?: number;
|
|
496
|
+
props?: number;
|
|
497
|
+
propsUnstable?: number;
|
|
498
|
+
hooks?: number;
|
|
499
|
+
parent?: number;
|
|
500
|
+
}
|
|
501
|
+
interface RenderCapture {
|
|
502
|
+
totalCommits: number;
|
|
503
|
+
totalRenders: number;
|
|
504
|
+
capturedDurations: boolean;
|
|
505
|
+
totalRenderMs?: number;
|
|
506
|
+
/** Parent cascades + identity-only prop churn: the removable share. */
|
|
507
|
+
wastedRenders?: number;
|
|
508
|
+
causes?: RenderCauseCounts;
|
|
509
|
+
topComponents: {
|
|
510
|
+
name: string;
|
|
511
|
+
renders: number;
|
|
512
|
+
totalMs: number;
|
|
513
|
+
maxMs: number;
|
|
514
|
+
avgMs: number;
|
|
515
|
+
causes?: RenderCauseCounts;
|
|
516
|
+
changedProps?: string[];
|
|
517
|
+
parentName?: string;
|
|
518
|
+
}[];
|
|
519
|
+
}
|
|
415
520
|
|
|
416
521
|
interface BuildConfigInput {
|
|
417
522
|
targetRoute: string;
|
|
@@ -464,10 +569,12 @@ interface RankRow {
|
|
|
464
569
|
/** React commits during the median run (null when capture was off/unavailable). */
|
|
465
570
|
renderCommits: number | null;
|
|
466
571
|
/** Top components by total render self-time during the median run. */
|
|
572
|
+
renderWasted?: number;
|
|
467
573
|
topRenderers: {
|
|
468
574
|
name: string;
|
|
469
575
|
renders: number;
|
|
470
576
|
totalMs: number;
|
|
577
|
+
cause?: string;
|
|
471
578
|
}[];
|
|
472
579
|
}
|
|
473
580
|
interface BatchRanking {
|
|
@@ -506,14 +613,44 @@ declare function rankBatchFromIndex(index: IndexEntry[], batchId: string, casesO
|
|
|
506
613
|
}[]): BatchRanking;
|
|
507
614
|
/** Render a batch ranking as a trade-off-aware report (no single false winner). */
|
|
508
615
|
declare function formatRankingMarkdown(ranking: BatchRanking): string;
|
|
509
|
-
/**
|
|
616
|
+
/**
|
|
617
|
+
* Side-by-side comparison of two full reports.
|
|
618
|
+
*
|
|
619
|
+
* Renders are part of the comparison, not an afterthought: when someone runs
|
|
620
|
+
* this after a memoization fix, "did the render count actually drop" IS the
|
|
621
|
+
* question, and for a long while this function silently dropped the block
|
|
622
|
+
* that answers it.
|
|
623
|
+
*/
|
|
510
624
|
declare function compareReportStats(a: {
|
|
511
625
|
name: string;
|
|
512
626
|
stats: BenchmarkReportStats;
|
|
627
|
+
renders?: RenderCapture;
|
|
513
628
|
}, b: {
|
|
514
629
|
name: string;
|
|
515
630
|
stats: BenchmarkReportStats;
|
|
631
|
+
renders?: RenderCapture;
|
|
516
632
|
}): {
|
|
633
|
+
renders?: {
|
|
634
|
+
total: {
|
|
635
|
+
a: number;
|
|
636
|
+
b: number;
|
|
637
|
+
delta: number;
|
|
638
|
+
};
|
|
639
|
+
commits: {
|
|
640
|
+
a: number;
|
|
641
|
+
b: number;
|
|
642
|
+
delta: number;
|
|
643
|
+
};
|
|
644
|
+
wasted: {
|
|
645
|
+
a: number;
|
|
646
|
+
b: number;
|
|
647
|
+
delta: number;
|
|
648
|
+
};
|
|
649
|
+
causes: {
|
|
650
|
+
a: RenderCauseCounts;
|
|
651
|
+
b: RenderCauseCounts;
|
|
652
|
+
};
|
|
653
|
+
} | undefined;
|
|
517
654
|
a: string;
|
|
518
655
|
b: string;
|
|
519
656
|
uiFps: {
|
package/dist/index.d.ts
CHANGED
|
@@ -57,11 +57,31 @@ declare class SyncClient {
|
|
|
57
57
|
private pendingActions;
|
|
58
58
|
/** Callbacks waiting for the next snapshot of `${deviceId}::${toolId}`. */
|
|
59
59
|
private snapshotWaiters;
|
|
60
|
+
/** When each cached snapshot arrived, keyed by snapKey (staleness reporting). */
|
|
61
|
+
private snapshotAt;
|
|
62
|
+
/** Liveness per device — see {@link noteTimeout}. */
|
|
63
|
+
private health;
|
|
64
|
+
/** Dev-server origin per device — see {@link noteDevServerOrigin}. */
|
|
65
|
+
private devServerOrigins;
|
|
66
|
+
/** Devices whose origin probe already ran (a production bundle has none). */
|
|
67
|
+
private originProbed;
|
|
68
|
+
/** Last time each device appeared in the broker's device list. */
|
|
69
|
+
private lastSeen;
|
|
60
70
|
constructor(opts?: SyncClientOptions);
|
|
61
71
|
private readonly autoSpawn;
|
|
62
72
|
/** Connect to a running broker, or spawn one in-process, then handshake. */
|
|
63
73
|
start(): Promise<BrokerMode>;
|
|
64
74
|
private connectSocket;
|
|
75
|
+
/**
|
|
76
|
+
* Drop everything remembered about devices that have been gone a while.
|
|
77
|
+
*
|
|
78
|
+
* Deliberately NOT on disconnect: a crashed app often drops off the broker,
|
|
79
|
+
* and its cached console snapshot is the crash evidence — throwing that away
|
|
80
|
+
* the instant it disconnects would delete the answer. But device ids change
|
|
81
|
+
* with every simulator erase and fresh dev client, and each one can hold
|
|
82
|
+
* multi-MB snapshots, so a long-lived server has to forget eventually.
|
|
83
|
+
*/
|
|
84
|
+
private pruneStaleDevices;
|
|
65
85
|
/** Disconnect and tear down a spawned broker, if any. */
|
|
66
86
|
stop(): Promise<void>;
|
|
67
87
|
/** All devices the broker knows about, merged with their advertised tools. */
|
|
@@ -91,6 +111,61 @@ declare class SyncClient {
|
|
|
91
111
|
* is blocked.
|
|
92
112
|
*/
|
|
93
113
|
requireProDevice(deviceId?: string): string;
|
|
114
|
+
private healthOf;
|
|
115
|
+
/** The device answered — it's alive. */
|
|
116
|
+
private noteOk;
|
|
117
|
+
/**
|
|
118
|
+
* The device didn't answer. A crashed app never answers again, so after the
|
|
119
|
+
* first miss we stop paying the full timeout on every subsequent call.
|
|
120
|
+
*/
|
|
121
|
+
private noteTimeout;
|
|
122
|
+
/** True once a device has missed a call and hasn't answered since. */
|
|
123
|
+
isUnresponsive(deviceId: string): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Full timeout normally; a short one for a device already not answering.
|
|
126
|
+
*
|
|
127
|
+
* With one escape hatch: every RECOVERY_PROBE_MS a flagged device gets the
|
|
128
|
+
* full budget again. Without it the flag is self-sustaining — a device whose
|
|
129
|
+
* work legitimately takes longer than the short budget (a big snapshot, a
|
|
130
|
+
* slow simulator) can never answer, so it can never clear the flag, and every
|
|
131
|
+
* later reply is a confident "most likely CRASHED" about a healthy app.
|
|
132
|
+
*/
|
|
133
|
+
private timeoutFor;
|
|
134
|
+
/**
|
|
135
|
+
* Plain-language diagnosis for a device that isn't answering, including the
|
|
136
|
+
* app's last words if the console tool got a crash flush out in time.
|
|
137
|
+
*
|
|
138
|
+
* A silent timeout is the worst possible answer here: the app is on a redbox,
|
|
139
|
+
* the reason is already captured, and without this the caller reads "timed
|
|
140
|
+
* out" and keeps retrying the same dead device.
|
|
141
|
+
*/
|
|
142
|
+
unresponsiveNote(deviceId: string): string;
|
|
143
|
+
/**
|
|
144
|
+
* The newest error line the console tool synced for this device, if any.
|
|
145
|
+
* Reads the cached console snapshot rather than the device (which, by the
|
|
146
|
+
* time this matters, is not answering).
|
|
147
|
+
*/
|
|
148
|
+
private lastFatalFor;
|
|
149
|
+
/** Age of the cached snapshot for a tool, in ms (null = never received). */
|
|
150
|
+
snapshotAgeMs(toolId: string, deviceId: string): number | null;
|
|
151
|
+
/**
|
|
152
|
+
* Remember where a device's bundle came from, reported by core's `app`
|
|
153
|
+
* adapter while the app is healthy. It is the only way to reload an app that
|
|
154
|
+
* has crashed: the in-app reload needs the React tree that the crash
|
|
155
|
+
* destroyed, but the dev server's reload is handled natively.
|
|
156
|
+
*/
|
|
157
|
+
noteDevServerOrigin(deviceId: string, origin: unknown): void;
|
|
158
|
+
/**
|
|
159
|
+
* Ask a freshly-announced device where its bundle came from, once.
|
|
160
|
+
*
|
|
161
|
+
* Deliberately eager: this is the piece of information that can ONLY be
|
|
162
|
+
* collected while the app is healthy, and is only ever needed after it has
|
|
163
|
+
* stopped answering. One cheap round-trip per device buys the ability to
|
|
164
|
+
* recover a crashed app instead of telling the caller to go do it by hand.
|
|
165
|
+
*/
|
|
166
|
+
private learnDevServerOrigin;
|
|
167
|
+
/** The dev-server origin last reported by this device, if any. */
|
|
168
|
+
devServerOrigin(deviceId: string): string | null;
|
|
94
169
|
/**
|
|
95
170
|
* Keep the device RECORDING this tool, without asking it to stream.
|
|
96
171
|
*
|
|
@@ -135,10 +210,14 @@ declare class SyncClient {
|
|
|
135
210
|
*/
|
|
136
211
|
getSnapshot(toolId: string, deviceId?: string, opts?: {
|
|
137
212
|
timeoutMs?: number;
|
|
213
|
+
silent?: boolean;
|
|
138
214
|
}): Promise<{
|
|
139
215
|
deviceId: string;
|
|
140
216
|
payload: unknown;
|
|
217
|
+
stale?: string;
|
|
141
218
|
}>;
|
|
219
|
+
/** Header line for data served from cache because the device went quiet. */
|
|
220
|
+
private staleNote;
|
|
142
221
|
private waitForSnapshot;
|
|
143
222
|
/**
|
|
144
223
|
* Invoke a remote action on a device and await its result. Pass deviceId to
|
|
@@ -146,14 +225,10 @@ declare class SyncClient {
|
|
|
146
225
|
*/
|
|
147
226
|
callAction(toolId: string, action: string, params?: unknown, deviceId?: string, opts?: {
|
|
148
227
|
timeoutMs?: number;
|
|
228
|
+
silent?: boolean;
|
|
149
229
|
}): Promise<unknown>;
|
|
150
230
|
}
|
|
151
231
|
|
|
152
|
-
/**
|
|
153
|
-
* Build the Buoy MCP server and register all tools against a connected
|
|
154
|
-
* {@link SyncClient}. Tool packs (perf-monitor, etc.) are layered on top of the
|
|
155
|
-
* generic core here.
|
|
156
|
-
*/
|
|
157
232
|
declare function createMcpServer(sync: SyncClient): McpServer;
|
|
158
233
|
|
|
159
234
|
/**
|
|
@@ -381,10 +456,12 @@ interface IndexEntry {
|
|
|
381
456
|
/** Render-capture mirror (absent when capture was unavailable/disabled). */
|
|
382
457
|
renderCommits?: number;
|
|
383
458
|
renderTotalMs?: number;
|
|
459
|
+
renderWasted?: number;
|
|
384
460
|
topRenderers?: {
|
|
385
461
|
name: string;
|
|
386
462
|
renders: number;
|
|
387
463
|
totalMs: number;
|
|
464
|
+
cause?: string;
|
|
388
465
|
}[];
|
|
389
466
|
}
|
|
390
467
|
/** Per-metric min/max/avg/p95 channel. */
|
|
@@ -406,12 +483,40 @@ interface BenchmarkReportStats {
|
|
|
406
483
|
uiJankFrames: number;
|
|
407
484
|
deviceMaxRefreshRate: number;
|
|
408
485
|
}
|
|
409
|
-
|
|
410
486
|
/**
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
*
|
|
487
|
+
* Why components rendered, counted over a run.
|
|
488
|
+
*
|
|
489
|
+
* `propsUnstable` is the actionable one: props changed by IDENTITY only —
|
|
490
|
+
* a fresh arrow or object literal handed down every render — while every
|
|
491
|
+
* value stayed equal. Reporting that as plain "props" sends you into the
|
|
492
|
+
* child, when the fix is always in the parent.
|
|
414
493
|
*/
|
|
494
|
+
interface RenderCauseCounts {
|
|
495
|
+
mount?: number;
|
|
496
|
+
props?: number;
|
|
497
|
+
propsUnstable?: number;
|
|
498
|
+
hooks?: number;
|
|
499
|
+
parent?: number;
|
|
500
|
+
}
|
|
501
|
+
interface RenderCapture {
|
|
502
|
+
totalCommits: number;
|
|
503
|
+
totalRenders: number;
|
|
504
|
+
capturedDurations: boolean;
|
|
505
|
+
totalRenderMs?: number;
|
|
506
|
+
/** Parent cascades + identity-only prop churn: the removable share. */
|
|
507
|
+
wastedRenders?: number;
|
|
508
|
+
causes?: RenderCauseCounts;
|
|
509
|
+
topComponents: {
|
|
510
|
+
name: string;
|
|
511
|
+
renders: number;
|
|
512
|
+
totalMs: number;
|
|
513
|
+
maxMs: number;
|
|
514
|
+
avgMs: number;
|
|
515
|
+
causes?: RenderCauseCounts;
|
|
516
|
+
changedProps?: string[];
|
|
517
|
+
parentName?: string;
|
|
518
|
+
}[];
|
|
519
|
+
}
|
|
415
520
|
|
|
416
521
|
interface BuildConfigInput {
|
|
417
522
|
targetRoute: string;
|
|
@@ -464,10 +569,12 @@ interface RankRow {
|
|
|
464
569
|
/** React commits during the median run (null when capture was off/unavailable). */
|
|
465
570
|
renderCommits: number | null;
|
|
466
571
|
/** Top components by total render self-time during the median run. */
|
|
572
|
+
renderWasted?: number;
|
|
467
573
|
topRenderers: {
|
|
468
574
|
name: string;
|
|
469
575
|
renders: number;
|
|
470
576
|
totalMs: number;
|
|
577
|
+
cause?: string;
|
|
471
578
|
}[];
|
|
472
579
|
}
|
|
473
580
|
interface BatchRanking {
|
|
@@ -506,14 +613,44 @@ declare function rankBatchFromIndex(index: IndexEntry[], batchId: string, casesO
|
|
|
506
613
|
}[]): BatchRanking;
|
|
507
614
|
/** Render a batch ranking as a trade-off-aware report (no single false winner). */
|
|
508
615
|
declare function formatRankingMarkdown(ranking: BatchRanking): string;
|
|
509
|
-
/**
|
|
616
|
+
/**
|
|
617
|
+
* Side-by-side comparison of two full reports.
|
|
618
|
+
*
|
|
619
|
+
* Renders are part of the comparison, not an afterthought: when someone runs
|
|
620
|
+
* this after a memoization fix, "did the render count actually drop" IS the
|
|
621
|
+
* question, and for a long while this function silently dropped the block
|
|
622
|
+
* that answers it.
|
|
623
|
+
*/
|
|
510
624
|
declare function compareReportStats(a: {
|
|
511
625
|
name: string;
|
|
512
626
|
stats: BenchmarkReportStats;
|
|
627
|
+
renders?: RenderCapture;
|
|
513
628
|
}, b: {
|
|
514
629
|
name: string;
|
|
515
630
|
stats: BenchmarkReportStats;
|
|
631
|
+
renders?: RenderCapture;
|
|
516
632
|
}): {
|
|
633
|
+
renders?: {
|
|
634
|
+
total: {
|
|
635
|
+
a: number;
|
|
636
|
+
b: number;
|
|
637
|
+
delta: number;
|
|
638
|
+
};
|
|
639
|
+
commits: {
|
|
640
|
+
a: number;
|
|
641
|
+
b: number;
|
|
642
|
+
delta: number;
|
|
643
|
+
};
|
|
644
|
+
wasted: {
|
|
645
|
+
a: number;
|
|
646
|
+
b: number;
|
|
647
|
+
delta: number;
|
|
648
|
+
};
|
|
649
|
+
causes: {
|
|
650
|
+
a: RenderCauseCounts;
|
|
651
|
+
b: RenderCauseCounts;
|
|
652
|
+
};
|
|
653
|
+
} | undefined;
|
|
517
654
|
a: string;
|
|
518
655
|
b: string;
|
|
519
656
|
uiFps: {
|