zeitzeuge 0.4.2 → 0.5.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/analysis/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EAGrB,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAM/B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAwC3C;;;GAGG;AACH,wBAAsB,OAAO,CAC3B,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,GAAG,GACX,OAAO,CAAC,OAAO,EAAE,CAAC,CAoCpB;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,GAAG,GACX,OAAO,CAAC,OAAO,EAAE,CAAC,CAgCpB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIjD"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/analysis/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EAGrB,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAM/B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAwC3C;;;GAGG;AACH,wBAAsB,OAAO,CAC3B,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,GAAG,GACX,OAAO,CAAC,OAAO,EAAE,CAAC,CAoCpB;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,GAAG,GACX,OAAO,CAAC,OAAO,EAAE,CAAC,CAwCpB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIjD"}
package/dist/cli.js CHANGED
@@ -110,6 +110,9 @@ Every hot function and script in the workspace has a \`sourceCategory\` field:
110
110
  - /hot-functions/global.json — All hot functions across all categories
111
111
  - /scripts/application.json — Per-script time breakdown for application code
112
112
  - /scripts/dependencies.json — Per-script time breakdown for dependencies
113
+ - /listener-tracking.json — (optional) Event listener tracking data captured from
114
+ worker processes. Contains per-event-type add/remove counts for EventTarget and
115
+ EventEmitter, plus exceedances where listener counts exceeded maxListeners.
113
116
  - /tests/*.ts — Test source files
114
117
  - /src/*.ts — Application and dependency source files referenced by hot functions
115
118
 
@@ -121,10 +124,12 @@ Every hot function and script in the workspace has a \`sourceCategory\` field:
121
124
  3. Read /hot-functions/dependencies.json for costly dependency calls
122
125
  4. If present, read /heap-profiles/index.json and /heap-profiles/<file>.json to identify
123
126
  allocation hotspots (functions/scripts allocating lots of bytes)
124
- 5. Read /summary.json and /timing/overview.json for the big picture
125
- 6. Read CPU profiles in /profiles/ for detailed call trees of the slowest tests
126
- 7. Read the actual source code in /src/ and /tests/ to understand root causes
127
- 8. Provide specific, actionable fixes targeting the application code
127
+ 5. If present, read /listener-tracking.json for event listener add/remove patterns
128
+ and listener exceedances (too many listeners on a single target)
129
+ 6. Read /summary.json and /timing/overview.json for the big picture
130
+ 7. Read CPU profiles in /profiles/ for detailed call trees of the slowest tests
131
+ 8. Read the actual source code in /src/ and /tests/ to understand root causes
132
+ 9. Provide specific, actionable fixes targeting the application code
128
133
 
129
134
  ## What to look for
130
135
 
@@ -158,6 +163,24 @@ Every hot function and script in the workspace has a \`sourceCategory\` field:
158
163
  - Follow the call tree from application entry points down to the hot leaf functions
159
164
  - Identify which application-level design decisions lead to the bottleneck
160
165
 
166
+ ### Event listener tracking (from /listener-tracking.json, if present)
167
+ - **Exceedances** — when a single EventTarget or EventEmitter accumulates more
168
+ listeners than its maxListeners threshold (default 10), this is a strong
169
+ signal of a listener leak. The exceedance data includes the target type
170
+ (e.g. AbortSignal), event name, listener count, and a stack trace snippet
171
+ pointing to the code that registered the excess listener.
172
+ - **Add/remove imbalances** — when \`addCount\` significantly exceeds
173
+ \`removeCount\` for a given event type, listeners are being registered but
174
+ not cleaned up. This causes memory growth and eventually GC pressure.
175
+ Look for patterns like:
176
+ - AbortSignal abort listeners not cleaned up (common with fetch/streams)
177
+ - EventEmitter listeners added in loops without corresponding removal
178
+ - Missing \`{ once: true }\` option or \`AbortController\` cleanup
179
+ - When exceedances or imbalances are found, read the source code to identify
180
+ the root cause and suggest specific fixes (e.g. using \`AbortController\`,
181
+ \`removeEventListener\`, \`{ once: true }\`, or restructuring listener
182
+ registration to avoid accumulation).
183
+
161
184
  ### Test infrastructure (SECONDARY — only if impactful)
162
185
  - Test setup creating artificial overhead that dwarfs application execution
163
186
  - Benchmarks measuring setup cost instead of application performance
@@ -389,13 +412,21 @@ async function analyzeTestPerformance(model, backend, spinner) {
389
412
  "2. Read /scripts/application.json — per-file CPU time for application source files",
390
413
  "3. Read /hot-functions/dependencies.json — expensive dependency calls",
391
414
  "4. If present, read /heap-profiles/index.json and /heap-profiles/<file>.json for allocation hotspots",
392
- "5. Read /summary.json and /timing/overview.json for the big picture",
393
- "6. Read CPU profiles in /profiles/ for detailed call trees",
394
- "7. Read source files in /src/ and /tests/ to understand root causes and propose code-level fixes",
415
+ "5. If present, read /listener-tracking.json event listener add/remove patterns",
416
+ " from worker processes. Look for exceedances (too many listeners on a single target)",
417
+ " and add/remove imbalances (listeners registered but never cleaned up).",
418
+ "6. Read /summary.json and /timing/overview.json for the big picture",
419
+ "7. Read CPU profiles in /profiles/ for detailed call trees",
420
+ "8. Read source files in /src/ and /tests/ to understand root causes and propose code-level fixes",
395
421
  "",
396
422
  "Focus findings on the APPLICATION code — what can the developer change in their own codebase",
397
423
  "to improve performance? Dependency bottlenecks are worth reporting if the developer can",
398
- "reduce how they call the dependency or choose an alternative."
424
+ "reduce how they call the dependency or choose an alternative.",
425
+ "",
426
+ "If /listener-tracking.json is present, analyze exceedances and imbalances.",
427
+ "For listener exceedances (e.g. AbortSignal with 15 abort listeners when max is 10),",
428
+ "use the stack trace to identify the code adding listeners and suggest proper cleanup",
429
+ "(e.g. AbortController, removeEventListener, { once: true })."
399
430
  ].join(`
400
431
  `);
401
432
  const result = await invokeWithTodoStreaming(agent, userMessage, spinner);
@@ -1196,10 +1227,10 @@ function parseSnapshot(rawSnapshot) {
1196
1227
  init_agent();
1197
1228
 
1198
1229
  // src/sandbox/workspace.ts
1199
- import { FilesystemBackend } from "deepagents";
1200
- import { mkdtempSync, mkdirSync, writeFileSync } from "node:fs";
1230
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
1201
1231
  import { join } from "node:path";
1202
1232
  import { tmpdir } from "node:os";
1233
+ import { FilesystemBackend } from "deepagents";
1203
1234
  async function createWorkspace(options) {
1204
1235
  const { heapSummary, traceResult, url, maxAssetSize = 10 * 1024 * 1024 } = options;
1205
1236
  const files = {};
@@ -1295,7 +1326,9 @@ async function createWorkspace(options) {
1295
1326
  virtualMode: true
1296
1327
  });
1297
1328
  const cleanup = () => {
1298
- console.log(111, tempDir);
1329
+ try {
1330
+ rmSync(tempDir, { recursive: true, force: true });
1331
+ } catch {}
1299
1332
  };
1300
1333
  return { backend, cleanup };
1301
1334
  }
@@ -1339,6 +1372,204 @@ function buildResourceBreakdown(requests) {
1339
1372
  // src/output/terminal.ts
1340
1373
  import pc from "picocolors";
1341
1374
  import ora from "ora";
1375
+
1376
+ // src/vitest/listener-tracker.ts
1377
+ var LISTENER_IMBALANCE_THRESHOLD = 5;
1378
+ function getListenerImbalances(tracking) {
1379
+ return [
1380
+ ...Object.entries(tracking.eventTargetCounts).map(([t, c]) => ({
1381
+ api: "EventTarget",
1382
+ type: t,
1383
+ ...c
1384
+ })),
1385
+ ...Object.entries(tracking.emitterCounts).map(([t, c]) => ({
1386
+ api: "EventEmitter",
1387
+ type: t,
1388
+ ...c
1389
+ }))
1390
+ ].filter((c) => c.addCount > c.removeCount + LISTENER_IMBALANCE_THRESHOLD).sort((a, b) => b.addCount - b.removeCount - (a.addCount - a.removeCount));
1391
+ }
1392
+ function generateListenerTrackerScript(outputDir) {
1393
+ return `// zeitzeuge: Event listener tracker (auto-injected via --import)
1394
+ // Tracks EventTarget/EventEmitter listener add/remove patterns
1395
+ // and writes a summary to the profile directory on process exit.
1396
+
1397
+ import { writeFileSync } from 'node:fs';
1398
+ import { join } from 'node:path';
1399
+ import EventEmitter from 'node:events';
1400
+
1401
+ const OUTPUT_DIR = ${JSON.stringify(outputDir)};
1402
+
1403
+ const data = {
1404
+ pid: process.pid,
1405
+ eventTargetCounts: {},
1406
+ emitterCounts: {},
1407
+ exceedances: [],
1408
+ };
1409
+
1410
+ const DEFAULT_THRESHOLD = 10;
1411
+ const seenExceedances = {};
1412
+ const targetCounts = new WeakMap();
1413
+
1414
+ function getTC(target) {
1415
+ let c = targetCounts.get(target);
1416
+ if (!c) { c = {}; targetCounts.set(target, c); }
1417
+ return c;
1418
+ }
1419
+
1420
+ function getType(target) {
1421
+ try { return target?.constructor?.name || 'unknown'; }
1422
+ catch { return 'unknown'; }
1423
+ }
1424
+
1425
+ function trackAdd(countsObj, target, eventType) {
1426
+ const t = String(eventType);
1427
+ if (!countsObj[t]) countsObj[t] = { addCount: 0, removeCount: 0 };
1428
+ countsObj[t].addCount++;
1429
+
1430
+ if (target) {
1431
+ const tc = getTC(target);
1432
+ const cur = (tc[t] || 0) + 1;
1433
+ tc[t] = cur;
1434
+
1435
+ const thresh = (typeof target.getMaxListeners === 'function')
1436
+ ? target.getMaxListeners()
1437
+ : DEFAULT_THRESHOLD;
1438
+
1439
+ // threshold === 0 means unlimited in Node.js (setMaxListeners(0))
1440
+ if (thresh > 0 && cur > thresh) {
1441
+ const tt = getType(target);
1442
+ const key = tt + ':' + t;
1443
+ if (!seenExceedances[key]) {
1444
+ seenExceedances[key] = true;
1445
+ let stack = '';
1446
+ try {
1447
+ stack = new Error().stack
1448
+ .split('\\n').slice(3, 7)
1449
+ .map((s) => s.trim())
1450
+ .join('\\n');
1451
+ } catch {}
1452
+ data.exceedances.push({
1453
+ targetType: tt,
1454
+ eventType: t,
1455
+ listenerCount: cur,
1456
+ threshold: thresh,
1457
+ stack,
1458
+ });
1459
+ }
1460
+ }
1461
+ }
1462
+ }
1463
+
1464
+ function trackRemove(countsObj, target, eventType) {
1465
+ const t = String(eventType);
1466
+ if (!countsObj[t]) countsObj[t] = { addCount: 0, removeCount: 0 };
1467
+ countsObj[t].removeCount++;
1468
+
1469
+ if (target) {
1470
+ const tc = getTC(target);
1471
+ const cur = (tc[t] || 0) - 1;
1472
+ tc[t] = cur > 0 ? cur : 0;
1473
+ }
1474
+ }
1475
+
1476
+ // --- Patch EventTarget ---
1477
+ try {
1478
+ if (typeof EventTarget !== 'undefined') {
1479
+ const origAEL = EventTarget.prototype.addEventListener;
1480
+ const origREL = EventTarget.prototype.removeEventListener;
1481
+
1482
+ EventTarget.prototype.addEventListener = function(...args) {
1483
+ trackAdd(data.eventTargetCounts, this, args[0]);
1484
+ return origAEL.apply(this, args);
1485
+ };
1486
+ EventTarget.prototype.removeEventListener = function(...args) {
1487
+ trackRemove(data.eventTargetCounts, this, args[0]);
1488
+ return origREL.apply(this, args);
1489
+ };
1490
+ }
1491
+ } catch {}
1492
+
1493
+ // --- Patch EventEmitter ---
1494
+ try {
1495
+ const origOn = EventEmitter.prototype.on;
1496
+ const origAddListener = EventEmitter.prototype.addListener;
1497
+ const origOnce = EventEmitter.prototype.once;
1498
+ const origRemoveListener = EventEmitter.prototype.removeListener;
1499
+ const origOff = EventEmitter.prototype.off;
1500
+
1501
+ EventEmitter.prototype.on = function(...args) {
1502
+ trackAdd(data.emitterCounts, this, args[0]);
1503
+ return origOn.apply(this, args);
1504
+ };
1505
+ EventEmitter.prototype.addListener = function(...args) {
1506
+ trackAdd(data.emitterCounts, this, args[0]);
1507
+ return origAddListener.apply(this, args);
1508
+ };
1509
+ EventEmitter.prototype.once = function(...args) {
1510
+ trackAdd(data.emitterCounts, this, args[0]);
1511
+ return origOnce.apply(this, args);
1512
+ };
1513
+ EventEmitter.prototype.removeListener = function(...args) {
1514
+ trackRemove(data.emitterCounts, this, args[0]);
1515
+ return origRemoveListener.apply(this, args);
1516
+ };
1517
+ EventEmitter.prototype.off = function(...args) {
1518
+ trackRemove(data.emitterCounts, this, args[0]);
1519
+ return origOff.apply(this, args);
1520
+ };
1521
+ } catch {}
1522
+
1523
+ // --- Write on exit ---
1524
+ process.on('exit', () => {
1525
+ try {
1526
+ const hasData = data.exceedances.length > 0 ||
1527
+ Object.keys(data.eventTargetCounts).length > 0 ||
1528
+ Object.keys(data.emitterCounts).length > 0;
1529
+ if (!hasData) return;
1530
+
1531
+ const outPath = join(OUTPUT_DIR, 'listener-tracking-' + process.pid + '.json');
1532
+ writeFileSync(outPath, JSON.stringify(data));
1533
+ } catch {}
1534
+ });
1535
+ `;
1536
+ }
1537
+ function aggregateListenerTracking(entries) {
1538
+ const eventTargetCounts = {};
1539
+ const emitterCounts = {};
1540
+ const exceedances = [];
1541
+ const seenExceedances = new Set;
1542
+ for (const entry of entries) {
1543
+ for (const [eventType, counts] of Object.entries(entry.eventTargetCounts)) {
1544
+ const existing = eventTargetCounts[eventType] ?? { addCount: 0, removeCount: 0 };
1545
+ existing.addCount += counts.addCount;
1546
+ existing.removeCount += counts.removeCount;
1547
+ eventTargetCounts[eventType] = existing;
1548
+ }
1549
+ for (const [eventType, counts] of Object.entries(entry.emitterCounts)) {
1550
+ const existing = emitterCounts[eventType] ?? { addCount: 0, removeCount: 0 };
1551
+ existing.addCount += counts.addCount;
1552
+ existing.removeCount += counts.removeCount;
1553
+ emitterCounts[eventType] = existing;
1554
+ }
1555
+ for (const exc of entry.exceedances) {
1556
+ const key = `${exc.targetType}:${exc.eventType}`;
1557
+ if (!seenExceedances.has(key)) {
1558
+ seenExceedances.add(key);
1559
+ exceedances.push({
1560
+ targetType: exc.targetType,
1561
+ eventType: exc.eventType,
1562
+ listenerCount: exc.listenerCount,
1563
+ threshold: exc.threshold,
1564
+ stack: exc.stack || undefined
1565
+ });
1566
+ }
1567
+ }
1568
+ }
1569
+ return { eventTargetCounts, emitterCounts, exceedances };
1570
+ }
1571
+
1572
+ // src/output/terminal.ts
1342
1573
  var SEVERITY_ICONS = {
1343
1574
  critical: pc.red("\uD83D\uDD34 CRITICAL"),
1344
1575
  warning: pc.yellow("\uD83D\uDFE1 WARNING"),
@@ -1541,6 +1772,29 @@ function printMetricsSummary(metrics) {
1541
1772
  console.log("");
1542
1773
  console.log(`${indent}${pc.bold("Heap")}: ${formatBytes2(metrics.heap.totalAllocatedBytes)} allocated`);
1543
1774
  }
1775
+ if (metrics.listenerTracking) {
1776
+ const lt = metrics.listenerTracking;
1777
+ console.log("");
1778
+ console.log(`${indent}${pc.bold("Event Listener Tracking")}`);
1779
+ if (lt.exceedances.length > 0) {
1780
+ for (const exc of lt.exceedances) {
1781
+ console.log(`${indent} ${pc.red("⚠")} ${pc.red(`${exc.targetType}.${exc.eventType}`)}: ` + `${exc.listenerCount} listeners (max: ${exc.threshold})`);
1782
+ if (exc.stack) {
1783
+ for (const line of exc.stack.split(`
1784
+ `).slice(0, 2)) {
1785
+ console.log(pc.dim(`${indent} ${line}`));
1786
+ }
1787
+ }
1788
+ }
1789
+ }
1790
+ const allImbalances = getListenerImbalances(lt);
1791
+ if (allImbalances.length > 0) {
1792
+ for (const entry of allImbalances.slice(0, 5)) {
1793
+ const leaked = entry.addCount - entry.removeCount;
1794
+ console.log(`${indent} ${pc.yellow("⚠")} ${entry.api} "${entry.type}": ` + `${entry.addCount} adds, ${entry.removeCount} removes ` + pc.yellow(`(${leaked} not cleaned up)`));
1795
+ }
1796
+ }
1797
+ }
1544
1798
  console.log("");
1545
1799
  }
1546
1800
  function formatMs(ms) {
@@ -1657,7 +1911,8 @@ function generateMarkdown(options) {
1657
1911
  if (f.suggestedFix) {
1658
1912
  sections.push(`### How to fix`);
1659
1913
  sections.push("");
1660
- const looksLikeCode = f.suggestedFix.includes("{") || f.suggestedFix.includes(";") || f.suggestedFix.includes("=>") || f.suggestedFix.includes("import ") || f.suggestedFix.includes("function ");
1914
+ const alreadyFenced = f.suggestedFix.includes("```");
1915
+ const looksLikeCode = !alreadyFenced && (f.suggestedFix.includes("{") || f.suggestedFix.includes(";") || f.suggestedFix.includes("=>") || f.suggestedFix.includes("import ") || f.suggestedFix.includes("function "));
1661
1916
  if (looksLikeCode) {
1662
1917
  sections.push("```js");
1663
1918
  sections.push(f.suggestedFix);
@@ -1736,6 +1991,36 @@ function generateTestMarkdown(options) {
1736
1991
  }
1737
1992
  sections.push("");
1738
1993
  }
1994
+ if (metrics.listenerTracking) {
1995
+ const lt = metrics.listenerTracking;
1996
+ const hasExceedances = lt.exceedances.length > 0;
1997
+ const allImbalances = getListenerImbalances(lt);
1998
+ if (hasExceedances || allImbalances.length > 0) {
1999
+ sections.push(`### Event Listener Tracking`);
2000
+ sections.push("");
2001
+ if (hasExceedances) {
2002
+ sections.push(`**Listener exceedances detected** — one or more EventTarget/EventEmitter ` + `instances accumulated more listeners than their \`maxListeners\` threshold. ` + `This is a strong signal of a listener leak that can cause memory growth.`);
2003
+ sections.push("");
2004
+ sections.push(`| Target | Event | Listeners | Threshold |`);
2005
+ sections.push(`|--------|-------|-----------|-----------|`);
2006
+ for (const exc of lt.exceedances) {
2007
+ sections.push(`| \`${exc.targetType}\` | \`${exc.eventType}\` | ${exc.listenerCount} | ${exc.threshold} |`);
2008
+ }
2009
+ sections.push("");
2010
+ }
2011
+ if (allImbalances.length > 0) {
2012
+ sections.push(`**Listener imbalances:**`);
2013
+ sections.push("");
2014
+ sections.push(`| API | Event | Adds | Removes | Not Cleaned Up |`);
2015
+ sections.push(`|-----|-------|------|---------|----------------|`);
2016
+ for (const entry of allImbalances) {
2017
+ const leaked = entry.addCount - entry.removeCount;
2018
+ sections.push(`| ${entry.api} | \`${entry.type}\` | ${entry.addCount} | ${entry.removeCount} | ${leaked} |`);
2019
+ }
2020
+ sections.push("");
2021
+ }
2022
+ }
2023
+ }
1739
2024
  }
1740
2025
  const counts = {
1741
2026
  critical: findings.filter((f) => f.severity === "critical").length,
@@ -1774,7 +2059,8 @@ function generateTestMarkdown(options) {
1774
2059
  if (f.suggestedFix) {
1775
2060
  sections.push(`### How to fix`);
1776
2061
  sections.push("");
1777
- const looksLikeCode = f.suggestedFix.includes("{") || f.suggestedFix.includes(";") || f.suggestedFix.includes("=>") || f.suggestedFix.includes("import ") || f.suggestedFix.includes("function ");
2062
+ const alreadyFenced = f.suggestedFix.includes("```");
2063
+ const looksLikeCode = !alreadyFenced && (f.suggestedFix.includes("{") || f.suggestedFix.includes(";") || f.suggestedFix.includes("=>") || f.suggestedFix.includes("import ") || f.suggestedFix.includes("function "));
1778
2064
  if (looksLikeCode) {
1779
2065
  sections.push("```ts");
1780
2066
  sections.push(f.suggestedFix);
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/output/report.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAmC/D,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAI9E;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CA+G/D;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAItF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CA0KvE"}
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/output/report.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAoC/D,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAI9E;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAiH/D;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAItF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAuNvE"}
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/output/terminal.ts"],"names":[],"mappings":"AACA,OAAY,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAwC/D;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAU9D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAE/C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAoEvD;AAyBD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAsD7D;AAID;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CA8DrE;AASD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CASnF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAQ5D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAG7C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIjD"}
1
+ {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/output/terminal.ts"],"names":[],"mappings":"AACA,OAAY,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAyC/D;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAU9D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAE/C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAoEvD;AAyBD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAsD7D;AAID;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAiGrE;AASD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CASnF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAQ5D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAG7C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIjD"}
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/sandbox/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAIrE,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5E,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,2CAA2C;IAC3C,OAAO,EAAE,eAAe,CAAC;IACzB,iDAAiD;IACjD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAkKzF;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAqBxD"}
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/sandbox/workspace.ts"],"names":[],"mappings":"AAIA,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAErE,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5E,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,2CAA2C;IAC3C,OAAO,EAAE,eAAe,CAAC;IACzB,iDAAiD;IACjD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAiKzF;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAqBxD"}
@@ -109,6 +109,9 @@ Every hot function and script in the workspace has a \`sourceCategory\` field:
109
109
  - /hot-functions/global.json — All hot functions across all categories
110
110
  - /scripts/application.json — Per-script time breakdown for application code
111
111
  - /scripts/dependencies.json — Per-script time breakdown for dependencies
112
+ - /listener-tracking.json — (optional) Event listener tracking data captured from
113
+ worker processes. Contains per-event-type add/remove counts for EventTarget and
114
+ EventEmitter, plus exceedances where listener counts exceeded maxListeners.
112
115
  - /tests/*.ts — Test source files
113
116
  - /src/*.ts — Application and dependency source files referenced by hot functions
114
117
 
@@ -120,10 +123,12 @@ Every hot function and script in the workspace has a \`sourceCategory\` field:
120
123
  3. Read /hot-functions/dependencies.json for costly dependency calls
121
124
  4. If present, read /heap-profiles/index.json and /heap-profiles/<file>.json to identify
122
125
  allocation hotspots (functions/scripts allocating lots of bytes)
123
- 5. Read /summary.json and /timing/overview.json for the big picture
124
- 6. Read CPU profiles in /profiles/ for detailed call trees of the slowest tests
125
- 7. Read the actual source code in /src/ and /tests/ to understand root causes
126
- 8. Provide specific, actionable fixes targeting the application code
126
+ 5. If present, read /listener-tracking.json for event listener add/remove patterns
127
+ and listener exceedances (too many listeners on a single target)
128
+ 6. Read /summary.json and /timing/overview.json for the big picture
129
+ 7. Read CPU profiles in /profiles/ for detailed call trees of the slowest tests
130
+ 8. Read the actual source code in /src/ and /tests/ to understand root causes
131
+ 9. Provide specific, actionable fixes targeting the application code
127
132
 
128
133
  ## What to look for
129
134
 
@@ -157,6 +162,24 @@ Every hot function and script in the workspace has a \`sourceCategory\` field:
157
162
  - Follow the call tree from application entry points down to the hot leaf functions
158
163
  - Identify which application-level design decisions lead to the bottleneck
159
164
 
165
+ ### Event listener tracking (from /listener-tracking.json, if present)
166
+ - **Exceedances** — when a single EventTarget or EventEmitter accumulates more
167
+ listeners than its maxListeners threshold (default 10), this is a strong
168
+ signal of a listener leak. The exceedance data includes the target type
169
+ (e.g. AbortSignal), event name, listener count, and a stack trace snippet
170
+ pointing to the code that registered the excess listener.
171
+ - **Add/remove imbalances** — when \`addCount\` significantly exceeds
172
+ \`removeCount\` for a given event type, listeners are being registered but
173
+ not cleaned up. This causes memory growth and eventually GC pressure.
174
+ Look for patterns like:
175
+ - AbortSignal abort listeners not cleaned up (common with fetch/streams)
176
+ - EventEmitter listeners added in loops without corresponding removal
177
+ - Missing \`{ once: true }\` option or \`AbortController\` cleanup
178
+ - When exceedances or imbalances are found, read the source code to identify
179
+ the root cause and suggest specific fixes (e.g. using \`AbortController\`,
180
+ \`removeEventListener\`, \`{ once: true }\`, or restructuring listener
181
+ registration to avoid accumulation).
182
+
160
183
  ### Test infrastructure (SECONDARY — only if impactful)
161
184
  - Test setup creating artificial overhead that dwarfs application execution
162
185
  - Benchmarks measuring setup cost instead of application performance
@@ -388,13 +411,21 @@ async function analyzeTestPerformance(model, backend, spinner) {
388
411
  "2. Read /scripts/application.json — per-file CPU time for application source files",
389
412
  "3. Read /hot-functions/dependencies.json — expensive dependency calls",
390
413
  "4. If present, read /heap-profiles/index.json and /heap-profiles/<file>.json for allocation hotspots",
391
- "5. Read /summary.json and /timing/overview.json for the big picture",
392
- "6. Read CPU profiles in /profiles/ for detailed call trees",
393
- "7. Read source files in /src/ and /tests/ to understand root causes and propose code-level fixes",
414
+ "5. If present, read /listener-tracking.json event listener add/remove patterns",
415
+ " from worker processes. Look for exceedances (too many listeners on a single target)",
416
+ " and add/remove imbalances (listeners registered but never cleaned up).",
417
+ "6. Read /summary.json and /timing/overview.json for the big picture",
418
+ "7. Read CPU profiles in /profiles/ for detailed call trees",
419
+ "8. Read source files in /src/ and /tests/ to understand root causes and propose code-level fixes",
394
420
  "",
395
421
  "Focus findings on the APPLICATION code — what can the developer change in their own codebase",
396
422
  "to improve performance? Dependency bottlenecks are worth reporting if the developer can",
397
- "reduce how they call the dependency or choose an alternative."
423
+ "reduce how they call the dependency or choose an alternative.",
424
+ "",
425
+ "If /listener-tracking.json is present, analyze exceedances and imbalances.",
426
+ "For listener exceedances (e.g. AbortSignal with 15 abort listeners when max is 10),",
427
+ "use the stack trace to identify the code adding listeners and suggest proper cleanup",
428
+ "(e.g. AbortController, removeEventListener, { once: true })."
398
429
  ].join(`
399
430
  `);
400
431
  const result = await invokeWithTodoStreaming(agent, userMessage, spinner);
@@ -417,7 +448,7 @@ var init_agent = __esm(() => {
417
448
 
418
449
  // src/vitest/plugin.ts
419
450
  import { join as join3, parse, resolve as resolve3 } from "node:path";
420
- import { mkdirSync as mkdirSync2 } from "node:fs";
451
+ import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "node:fs";
421
452
 
422
453
  // src/vitest/reporter.ts
423
454
  import { readdirSync, readFileSync, existsSync, rmSync, statSync } from "node:fs";
@@ -719,7 +750,15 @@ import { tmpdir } from "node:os";
719
750
  var SOURCE_INCLUSION_THRESHOLD = 1;
720
751
  var SLOW_TEST_THRESHOLD = 100;
721
752
  async function createVitestWorkspace(options) {
722
- const { testTiming, profiles, heapProfiles, testSources, sourcePaths, metrics } = options;
753
+ const {
754
+ testTiming,
755
+ profiles,
756
+ heapProfiles,
757
+ testSources,
758
+ sourcePaths,
759
+ metrics,
760
+ listenerTracking
761
+ } = options;
723
762
  const files = {};
724
763
  const totalTests = testTiming.reduce((s, t) => s + t.testCount, 0);
725
764
  const totalDuration = testTiming.reduce((s, t) => s + t.duration, 0);
@@ -824,6 +863,9 @@ async function createVitestWorkspace(options) {
824
863
  if (metrics) {
825
864
  files["/metrics/current.json"] = JSON.stringify(metrics, null, 2);
826
865
  }
866
+ if (listenerTracking) {
867
+ files["/listener-tracking.json"] = JSON.stringify(listenerTracking, null, 2);
868
+ }
827
869
  for (const [filePath, source] of testSources) {
828
870
  const filename = filePath.split("/").pop() ?? filePath;
829
871
  files[`/tests/${filename}`] = source;
@@ -929,6 +971,204 @@ function initModel() {
929
971
  // src/output/terminal.ts
930
972
  import pc from "picocolors";
931
973
  import ora from "ora";
974
+
975
+ // src/vitest/listener-tracker.ts
976
+ var LISTENER_IMBALANCE_THRESHOLD = 5;
977
+ function getListenerImbalances(tracking) {
978
+ return [
979
+ ...Object.entries(tracking.eventTargetCounts).map(([t, c]) => ({
980
+ api: "EventTarget",
981
+ type: t,
982
+ ...c
983
+ })),
984
+ ...Object.entries(tracking.emitterCounts).map(([t, c]) => ({
985
+ api: "EventEmitter",
986
+ type: t,
987
+ ...c
988
+ }))
989
+ ].filter((c) => c.addCount > c.removeCount + LISTENER_IMBALANCE_THRESHOLD).sort((a, b) => b.addCount - b.removeCount - (a.addCount - a.removeCount));
990
+ }
991
+ function generateListenerTrackerScript(outputDir) {
992
+ return `// zeitzeuge: Event listener tracker (auto-injected via --import)
993
+ // Tracks EventTarget/EventEmitter listener add/remove patterns
994
+ // and writes a summary to the profile directory on process exit.
995
+
996
+ import { writeFileSync } from 'node:fs';
997
+ import { join } from 'node:path';
998
+ import EventEmitter from 'node:events';
999
+
1000
+ const OUTPUT_DIR = ${JSON.stringify(outputDir)};
1001
+
1002
+ const data = {
1003
+ pid: process.pid,
1004
+ eventTargetCounts: {},
1005
+ emitterCounts: {},
1006
+ exceedances: [],
1007
+ };
1008
+
1009
+ const DEFAULT_THRESHOLD = 10;
1010
+ const seenExceedances = {};
1011
+ const targetCounts = new WeakMap();
1012
+
1013
+ function getTC(target) {
1014
+ let c = targetCounts.get(target);
1015
+ if (!c) { c = {}; targetCounts.set(target, c); }
1016
+ return c;
1017
+ }
1018
+
1019
+ function getType(target) {
1020
+ try { return target?.constructor?.name || 'unknown'; }
1021
+ catch { return 'unknown'; }
1022
+ }
1023
+
1024
+ function trackAdd(countsObj, target, eventType) {
1025
+ const t = String(eventType);
1026
+ if (!countsObj[t]) countsObj[t] = { addCount: 0, removeCount: 0 };
1027
+ countsObj[t].addCount++;
1028
+
1029
+ if (target) {
1030
+ const tc = getTC(target);
1031
+ const cur = (tc[t] || 0) + 1;
1032
+ tc[t] = cur;
1033
+
1034
+ const thresh = (typeof target.getMaxListeners === 'function')
1035
+ ? target.getMaxListeners()
1036
+ : DEFAULT_THRESHOLD;
1037
+
1038
+ // threshold === 0 means unlimited in Node.js (setMaxListeners(0))
1039
+ if (thresh > 0 && cur > thresh) {
1040
+ const tt = getType(target);
1041
+ const key = tt + ':' + t;
1042
+ if (!seenExceedances[key]) {
1043
+ seenExceedances[key] = true;
1044
+ let stack = '';
1045
+ try {
1046
+ stack = new Error().stack
1047
+ .split('\\n').slice(3, 7)
1048
+ .map((s) => s.trim())
1049
+ .join('\\n');
1050
+ } catch {}
1051
+ data.exceedances.push({
1052
+ targetType: tt,
1053
+ eventType: t,
1054
+ listenerCount: cur,
1055
+ threshold: thresh,
1056
+ stack,
1057
+ });
1058
+ }
1059
+ }
1060
+ }
1061
+ }
1062
+
1063
+ function trackRemove(countsObj, target, eventType) {
1064
+ const t = String(eventType);
1065
+ if (!countsObj[t]) countsObj[t] = { addCount: 0, removeCount: 0 };
1066
+ countsObj[t].removeCount++;
1067
+
1068
+ if (target) {
1069
+ const tc = getTC(target);
1070
+ const cur = (tc[t] || 0) - 1;
1071
+ tc[t] = cur > 0 ? cur : 0;
1072
+ }
1073
+ }
1074
+
1075
+ // --- Patch EventTarget ---
1076
+ try {
1077
+ if (typeof EventTarget !== 'undefined') {
1078
+ const origAEL = EventTarget.prototype.addEventListener;
1079
+ const origREL = EventTarget.prototype.removeEventListener;
1080
+
1081
+ EventTarget.prototype.addEventListener = function(...args) {
1082
+ trackAdd(data.eventTargetCounts, this, args[0]);
1083
+ return origAEL.apply(this, args);
1084
+ };
1085
+ EventTarget.prototype.removeEventListener = function(...args) {
1086
+ trackRemove(data.eventTargetCounts, this, args[0]);
1087
+ return origREL.apply(this, args);
1088
+ };
1089
+ }
1090
+ } catch {}
1091
+
1092
+ // --- Patch EventEmitter ---
1093
+ try {
1094
+ const origOn = EventEmitter.prototype.on;
1095
+ const origAddListener = EventEmitter.prototype.addListener;
1096
+ const origOnce = EventEmitter.prototype.once;
1097
+ const origRemoveListener = EventEmitter.prototype.removeListener;
1098
+ const origOff = EventEmitter.prototype.off;
1099
+
1100
+ EventEmitter.prototype.on = function(...args) {
1101
+ trackAdd(data.emitterCounts, this, args[0]);
1102
+ return origOn.apply(this, args);
1103
+ };
1104
+ EventEmitter.prototype.addListener = function(...args) {
1105
+ trackAdd(data.emitterCounts, this, args[0]);
1106
+ return origAddListener.apply(this, args);
1107
+ };
1108
+ EventEmitter.prototype.once = function(...args) {
1109
+ trackAdd(data.emitterCounts, this, args[0]);
1110
+ return origOnce.apply(this, args);
1111
+ };
1112
+ EventEmitter.prototype.removeListener = function(...args) {
1113
+ trackRemove(data.emitterCounts, this, args[0]);
1114
+ return origRemoveListener.apply(this, args);
1115
+ };
1116
+ EventEmitter.prototype.off = function(...args) {
1117
+ trackRemove(data.emitterCounts, this, args[0]);
1118
+ return origOff.apply(this, args);
1119
+ };
1120
+ } catch {}
1121
+
1122
+ // --- Write on exit ---
1123
+ process.on('exit', () => {
1124
+ try {
1125
+ const hasData = data.exceedances.length > 0 ||
1126
+ Object.keys(data.eventTargetCounts).length > 0 ||
1127
+ Object.keys(data.emitterCounts).length > 0;
1128
+ if (!hasData) return;
1129
+
1130
+ const outPath = join(OUTPUT_DIR, 'listener-tracking-' + process.pid + '.json');
1131
+ writeFileSync(outPath, JSON.stringify(data));
1132
+ } catch {}
1133
+ });
1134
+ `;
1135
+ }
1136
+ function aggregateListenerTracking(entries) {
1137
+ const eventTargetCounts = {};
1138
+ const emitterCounts = {};
1139
+ const exceedances = [];
1140
+ const seenExceedances = new Set;
1141
+ for (const entry of entries) {
1142
+ for (const [eventType, counts] of Object.entries(entry.eventTargetCounts)) {
1143
+ const existing = eventTargetCounts[eventType] ?? { addCount: 0, removeCount: 0 };
1144
+ existing.addCount += counts.addCount;
1145
+ existing.removeCount += counts.removeCount;
1146
+ eventTargetCounts[eventType] = existing;
1147
+ }
1148
+ for (const [eventType, counts] of Object.entries(entry.emitterCounts)) {
1149
+ const existing = emitterCounts[eventType] ?? { addCount: 0, removeCount: 0 };
1150
+ existing.addCount += counts.addCount;
1151
+ existing.removeCount += counts.removeCount;
1152
+ emitterCounts[eventType] = existing;
1153
+ }
1154
+ for (const exc of entry.exceedances) {
1155
+ const key = `${exc.targetType}:${exc.eventType}`;
1156
+ if (!seenExceedances.has(key)) {
1157
+ seenExceedances.add(key);
1158
+ exceedances.push({
1159
+ targetType: exc.targetType,
1160
+ eventType: exc.eventType,
1161
+ listenerCount: exc.listenerCount,
1162
+ threshold: exc.threshold,
1163
+ stack: exc.stack || undefined
1164
+ });
1165
+ }
1166
+ }
1167
+ }
1168
+ return { eventTargetCounts, emitterCounts, exceedances };
1169
+ }
1170
+
1171
+ // src/output/terminal.ts
932
1172
  var SEVERITY_ICONS = {
933
1173
  critical: pc.red("\uD83D\uDD34 CRITICAL"),
934
1174
  warning: pc.yellow("\uD83D\uDFE1 WARNING"),
@@ -1131,6 +1371,29 @@ function printMetricsSummary(metrics) {
1131
1371
  console.log("");
1132
1372
  console.log(`${indent}${pc.bold("Heap")}: ${formatBytes(metrics.heap.totalAllocatedBytes)} allocated`);
1133
1373
  }
1374
+ if (metrics.listenerTracking) {
1375
+ const lt = metrics.listenerTracking;
1376
+ console.log("");
1377
+ console.log(`${indent}${pc.bold("Event Listener Tracking")}`);
1378
+ if (lt.exceedances.length > 0) {
1379
+ for (const exc of lt.exceedances) {
1380
+ console.log(`${indent} ${pc.red("⚠")} ${pc.red(`${exc.targetType}.${exc.eventType}`)}: ` + `${exc.listenerCount} listeners (max: ${exc.threshold})`);
1381
+ if (exc.stack) {
1382
+ for (const line of exc.stack.split(`
1383
+ `).slice(0, 2)) {
1384
+ console.log(pc.dim(`${indent} ${line}`));
1385
+ }
1386
+ }
1387
+ }
1388
+ }
1389
+ const allImbalances = getListenerImbalances(lt);
1390
+ if (allImbalances.length > 0) {
1391
+ for (const entry of allImbalances.slice(0, 5)) {
1392
+ const leaked = entry.addCount - entry.removeCount;
1393
+ console.log(`${indent} ${pc.yellow("⚠")} ${entry.api} "${entry.type}": ` + `${entry.addCount} adds, ${entry.removeCount} removes ` + pc.yellow(`(${leaked} not cleaned up)`));
1394
+ }
1395
+ }
1396
+ }
1134
1397
  console.log("");
1135
1398
  }
1136
1399
  function formatMs(ms) {
@@ -1247,7 +1510,8 @@ function generateMarkdown(options) {
1247
1510
  if (f.suggestedFix) {
1248
1511
  sections.push(`### How to fix`);
1249
1512
  sections.push("");
1250
- const looksLikeCode = f.suggestedFix.includes("{") || f.suggestedFix.includes(";") || f.suggestedFix.includes("=>") || f.suggestedFix.includes("import ") || f.suggestedFix.includes("function ");
1513
+ const alreadyFenced = f.suggestedFix.includes("```");
1514
+ const looksLikeCode = !alreadyFenced && (f.suggestedFix.includes("{") || f.suggestedFix.includes(";") || f.suggestedFix.includes("=>") || f.suggestedFix.includes("import ") || f.suggestedFix.includes("function "));
1251
1515
  if (looksLikeCode) {
1252
1516
  sections.push("```js");
1253
1517
  sections.push(f.suggestedFix);
@@ -1326,6 +1590,36 @@ function generateTestMarkdown(options) {
1326
1590
  }
1327
1591
  sections.push("");
1328
1592
  }
1593
+ if (metrics.listenerTracking) {
1594
+ const lt = metrics.listenerTracking;
1595
+ const hasExceedances = lt.exceedances.length > 0;
1596
+ const allImbalances = getListenerImbalances(lt);
1597
+ if (hasExceedances || allImbalances.length > 0) {
1598
+ sections.push(`### Event Listener Tracking`);
1599
+ sections.push("");
1600
+ if (hasExceedances) {
1601
+ sections.push(`**Listener exceedances detected** — one or more EventTarget/EventEmitter ` + `instances accumulated more listeners than their \`maxListeners\` threshold. ` + `This is a strong signal of a listener leak that can cause memory growth.`);
1602
+ sections.push("");
1603
+ sections.push(`| Target | Event | Listeners | Threshold |`);
1604
+ sections.push(`|--------|-------|-----------|-----------|`);
1605
+ for (const exc of lt.exceedances) {
1606
+ sections.push(`| \`${exc.targetType}\` | \`${exc.eventType}\` | ${exc.listenerCount} | ${exc.threshold} |`);
1607
+ }
1608
+ sections.push("");
1609
+ }
1610
+ if (allImbalances.length > 0) {
1611
+ sections.push(`**Listener imbalances:**`);
1612
+ sections.push("");
1613
+ sections.push(`| API | Event | Adds | Removes | Not Cleaned Up |`);
1614
+ sections.push(`|-----|-------|------|---------|----------------|`);
1615
+ for (const entry of allImbalances) {
1616
+ const leaked = entry.addCount - entry.removeCount;
1617
+ sections.push(`| ${entry.api} | \`${entry.type}\` | ${entry.addCount} | ${entry.removeCount} | ${leaked} |`);
1618
+ }
1619
+ sections.push("");
1620
+ }
1621
+ }
1622
+ }
1329
1623
  }
1330
1624
  const counts = {
1331
1625
  critical: findings.filter((f) => f.severity === "critical").length,
@@ -1364,7 +1658,8 @@ function generateTestMarkdown(options) {
1364
1658
  if (f.suggestedFix) {
1365
1659
  sections.push(`### How to fix`);
1366
1660
  sections.push("");
1367
- const looksLikeCode = f.suggestedFix.includes("{") || f.suggestedFix.includes(";") || f.suggestedFix.includes("=>") || f.suggestedFix.includes("import ") || f.suggestedFix.includes("function ");
1661
+ const alreadyFenced = f.suggestedFix.includes("```");
1662
+ const looksLikeCode = !alreadyFenced && (f.suggestedFix.includes("{") || f.suggestedFix.includes(";") || f.suggestedFix.includes("=>") || f.suggestedFix.includes("import ") || f.suggestedFix.includes("function "));
1368
1663
  if (looksLikeCode) {
1369
1664
  sections.push("```ts");
1370
1665
  sections.push(f.suggestedFix);
@@ -1446,7 +1741,7 @@ function classifyScript(scriptUrl, projectRoot, testFiles) {
1446
1741
  }
1447
1742
 
1448
1743
  // src/vitest/metrics.ts
1449
- function computeMetrics(testTiming, profiles, heapProfiles, projectRoot) {
1744
+ function computeMetrics(testTiming, profiles, heapProfiles, projectRoot, listenerTracking) {
1450
1745
  const allTestDurations = testTiming.flatMap((t) => t.tests.map((tc) => tc.duration)).sort((a, b) => a - b);
1451
1746
  const totalDuration = testTiming.reduce((s, t) => s + t.duration, 0);
1452
1747
  const totalTests = testTiming.reduce((s, t) => s + t.testCount, 0);
@@ -1516,7 +1811,8 @@ function computeMetrics(testTiming, profiles, heapProfiles, projectRoot) {
1516
1811
  files,
1517
1812
  tests,
1518
1813
  hotFunctions,
1519
- heap
1814
+ heap,
1815
+ listenerTracking
1520
1816
  };
1521
1817
  }
1522
1818
  function computeCpuMetrics(profiles) {
@@ -1595,7 +1891,7 @@ function relativize(filePath, projectRoot) {
1595
1891
  // package.json
1596
1892
  var package_default = {
1597
1893
  name: "zeitzeuge",
1598
- version: "0.4.1",
1894
+ version: "0.5.1",
1599
1895
  description: "A deepagent to witnessing slowdowns in your test runs.",
1600
1896
  keywords: [
1601
1897
  "analysis",
@@ -1800,7 +2096,13 @@ class ZeitZeugeReporter {
1800
2096
  if (this.options.verbose && heapProfiles.length > 0) {
1801
2097
  console.log(`[zeitzeuge] ${heapProfiles.length} heap profile(s) collected`);
1802
2098
  }
1803
- const metrics = computeMetrics(testTiming, profiles, heapProfiles, this.options.projectRoot);
2099
+ const listenerTracking = this.collectListenerTracking();
2100
+ if (this.options.verbose && listenerTracking) {
2101
+ const excCount = listenerTracking.exceedances.length;
2102
+ const etCount = Object.keys(listenerTracking.eventTargetCounts).length;
2103
+ console.log(`[zeitzeuge] Listener tracking: ${etCount} EventTarget event type(s), ` + `${excCount} exceedance(s)`);
2104
+ }
2105
+ const metrics = computeMetrics(testTiming, profiles, heapProfiles, this.options.projectRoot, listenerTracking);
1804
2106
  console.log(chalk.cyan(`
1805
2107
  zeitzeuge: Performance Metrics
1806
2108
  `));
@@ -1815,7 +2117,8 @@ zeitzeuge: Performance Metrics
1815
2117
  testSources,
1816
2118
  sourcePaths,
1817
2119
  projectRoot: this.options.projectRoot,
1818
- metrics
2120
+ metrics,
2121
+ listenerTracking
1819
2122
  });
1820
2123
  wsSpinner?.succeed("zeitzeuge: Workspace ready");
1821
2124
  if (this.options.analyzeOnFinish) {
@@ -1897,10 +2200,11 @@ zeitzeuge: Performance Analysis
1897
2200
  for (const child of children) {
1898
2201
  if (child.type === "test" || child.type === "case") {
1899
2202
  const diagnostic = typeof child.diagnostic === "function" ? child.diagnostic() : child.diagnostic;
2203
+ const result = typeof child.result === "function" ? child.result() : child.result;
1900
2204
  results.push({
1901
2205
  name: child.fullName ?? child.name ?? "",
1902
2206
  duration: diagnostic?.duration ?? 0,
1903
- status: child.result?.state === "passed" ? "pass" : child.result?.state === "failed" ? "fail" : "skip"
2207
+ status: result?.state === "passed" ? "pass" : result?.state === "failed" ? "fail" : "skip"
1904
2208
  });
1905
2209
  }
1906
2210
  if (child.children) {
@@ -2012,6 +2316,39 @@ zeitzeuge: Performance Analysis
2012
2316
  }
2013
2317
  return results.slice(0, 10);
2014
2318
  }
2319
+ collectListenerTracking() {
2320
+ const { profileDir } = this.options;
2321
+ if (!existsSync(profileDir)) {
2322
+ return;
2323
+ }
2324
+ const allFiles = readdirSync(profileDir);
2325
+ const trackingFiles = allFiles.filter((f) => f.startsWith("listener-tracking-"));
2326
+ if (trackingFiles.length === 0) {
2327
+ return;
2328
+ }
2329
+ const entries = [];
2330
+ for (const file of trackingFiles) {
2331
+ try {
2332
+ const content = readFileSync(join2(profileDir, file), "utf-8");
2333
+ const data = JSON.parse(content);
2334
+ entries.push(data);
2335
+ } catch (err) {
2336
+ if (this.options.verbose) {
2337
+ console.warn(`[zeitzeuge] Failed to parse listener tracking ${file}: ${err instanceof Error ? err.message : err}`);
2338
+ }
2339
+ }
2340
+ }
2341
+ if (entries.length === 0) {
2342
+ return;
2343
+ }
2344
+ const aggregated = aggregateListenerTracking(entries);
2345
+ const hasExceedances = aggregated.exceedances.length > 0;
2346
+ const hasImbalances = getListenerImbalances(aggregated).length > 0;
2347
+ if (!hasExceedances && !hasImbalances) {
2348
+ return;
2349
+ }
2350
+ return aggregated;
2351
+ }
2015
2352
  readTestSources(testTiming) {
2016
2353
  const sources = new Map;
2017
2354
  for (const timing of testTiming) {
@@ -2101,10 +2438,15 @@ function zeitzeuge(options = {}) {
2101
2438
  try {
2102
2439
  mkdirSync2(resolvedProfileDir, { recursive: true });
2103
2440
  } catch {}
2441
+ const trackerPath = join3(resolvedProfileDir, "_listener-tracker.mjs");
2442
+ try {
2443
+ writeFileSync3(trackerPath, generateListenerTrackerScript(resolvedProfileDir));
2444
+ } catch {}
2104
2445
  const targetConfig = project?.config ?? vitest.config;
2105
2446
  const cpuProfArgs = ["--cpu-prof", `--cpu-prof-dir=${resolvedProfileDir}`];
2106
2447
  const heapProfArgs = heapProf ? ["--heap-prof", `--heap-prof-dir=${resolvedProfileDir}`] : [];
2107
- const profilingArgs = [...cpuProfArgs, ...heapProfArgs];
2448
+ const trackerArgs = [`--import=${trackerPath}`];
2449
+ const profilingArgs = [...trackerArgs, ...cpuProfArgs, ...heapProfArgs];
2108
2450
  const existingArgv = targetConfig.execArgv ?? [];
2109
2451
  targetConfig.execArgv = uniq([...existingArgv, ...profilingArgs]);
2110
2452
  targetConfig.pool = "forks";
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Event listener tracker — injected into Vitest worker processes via `--import`.
3
+ *
4
+ * Patches `EventTarget.prototype.addEventListener/removeEventListener` and
5
+ * `EventEmitter.prototype.on/addListener/once/removeListener/off` to track
6
+ * per-event-type add/remove counts and detect listener exceedances (more
7
+ * listeners than `maxListeners` on a single target).
8
+ *
9
+ * On process exit, writes a JSON summary to the profile directory so the
10
+ * zeitzeuge reporter can aggregate it across all workers.
11
+ *
12
+ * This module exports only the **script text generator**; the actual preload
13
+ * script is an ESM `.mjs` module and runs inside the worker, not in the main
14
+ * process. We use `--import` (stable since Node.js 20.6) instead of `--require`
15
+ * to guarantee compatibility with ESM projects (`"type": "module"`).
16
+ */
17
+ /** Shape of the JSON file written by each worker process. */
18
+ export interface RawListenerTrackingData {
19
+ pid: number;
20
+ eventTargetCounts: Record<string, {
21
+ addCount: number;
22
+ removeCount: number;
23
+ }>;
24
+ emitterCounts: Record<string, {
25
+ addCount: number;
26
+ removeCount: number;
27
+ }>;
28
+ exceedances: RawListenerExceedance[];
29
+ }
30
+ export interface RawListenerExceedance {
31
+ targetType: string;
32
+ eventType: string;
33
+ listenerCount: number;
34
+ threshold: number;
35
+ stack: string;
36
+ }
37
+ /** Aggregated event listener tracking data across all worker processes. */
38
+ export interface EventListenerTracking {
39
+ /** Per-event-type add/remove counts for EventTarget APIs (e.g. AbortSignal). */
40
+ eventTargetCounts: Record<string, {
41
+ addCount: number;
42
+ removeCount: number;
43
+ }>;
44
+ /** Per-event-type add/remove counts for EventEmitter APIs. */
45
+ emitterCounts: Record<string, {
46
+ addCount: number;
47
+ removeCount: number;
48
+ }>;
49
+ /** Instances where a single target's listener count exceeded its maxListeners. */
50
+ exceedances: ListenerExceedance[];
51
+ }
52
+ export interface ListenerExceedance {
53
+ /** Class name of the target, e.g. "AbortSignal", "EventEmitter". */
54
+ targetType: string;
55
+ /** The event name, e.g. "abort", "data". */
56
+ eventType: string;
57
+ /** The listener count that triggered the exceedance. */
58
+ listenerCount: number;
59
+ /** The maxListeners threshold that was exceeded. */
60
+ threshold: number;
61
+ /** Short stack trace snippet captured at the exceedance point. */
62
+ stack?: string;
63
+ }
64
+ /**
65
+ * Minimum difference between add and remove counts before an event type
66
+ * is considered to have a notable listener imbalance. Small imbalances
67
+ * are normal (e.g. listeners added at startup that are never explicitly
68
+ * removed because the process exits), so we tolerate a small surplus.
69
+ */
70
+ export declare const LISTENER_IMBALANCE_THRESHOLD = 5;
71
+ export interface ListenerImbalance {
72
+ /** Which API registered the listener ("EventTarget" or "EventEmitter"). */
73
+ api: 'EventTarget' | 'EventEmitter';
74
+ /** The event name, e.g. "abort", "data". */
75
+ type: string;
76
+ addCount: number;
77
+ removeCount: number;
78
+ }
79
+ /**
80
+ * Return event types where listeners were added significantly more often
81
+ * than they were removed, combining both EventTarget and EventEmitter counts.
82
+ *
83
+ * Results are sorted by imbalance size (largest first).
84
+ */
85
+ export declare function getListenerImbalances(tracking: EventListenerTracking): ListenerImbalance[];
86
+ /**
87
+ * Generate the ESM preload script that will be injected into worker
88
+ * processes via `--import`.
89
+ *
90
+ * The generated `.mjs` file uses ESM imports and runs before the worker
91
+ * entry point. This guarantees compatibility with projects that use
92
+ * `"type": "module"` in their `package.json`.
93
+ *
94
+ * @param outputDir Absolute path to the profile directory where the tracker
95
+ * should write its JSON summary on process exit.
96
+ */
97
+ export declare function generateListenerTrackerScript(outputDir: string): string;
98
+ /**
99
+ * Merge per-process listener tracking data from multiple workers
100
+ * into a single aggregated summary.
101
+ */
102
+ export declare function aggregateListenerTracking(entries: RawListenerTrackingData[]): EventListenerTracking;
103
+ //# sourceMappingURL=listener-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listener-tracker.d.ts","sourceRoot":"","sources":["../../src/vitest/listener-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,6DAA6D;AAC7D,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7E,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzE,WAAW,EAAE,qBAAqB,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAID,2EAA2E;AAC3E,MAAM,WAAW,qBAAqB;IACpC,gFAAgF;IAChF,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7E,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzE,kFAAkF;IAClF,WAAW,EAAE,kBAAkB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,aAAa,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,GAAG,EAAE,aAAa,GAAG,cAAc,CAAC;IACpC,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,iBAAiB,EAAE,CAe1F;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAiJvE;AAID;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,uBAAuB,EAAE,GACjC,qBAAqB,CAwCvB"}
@@ -5,6 +5,7 @@
5
5
  * data so users can see where time is spent at a glance.
6
6
  */
7
7
  import type { TestFileTiming, CorrelatedProfile, CorrelatedHeapProfile } from './types.js';
8
+ import type { EventListenerTracking } from './listener-tracker.js';
8
9
  /** Suite-level aggregate metrics. */
9
10
  export interface SuiteMetrics {
10
11
  totalDuration: number;
@@ -74,9 +75,17 @@ export interface PerformanceMetrics {
74
75
  heap?: {
75
76
  totalAllocatedBytes: number;
76
77
  };
78
+ /**
79
+ * Event listener tracking data from worker processes.
80
+ *
81
+ * Captures EventTarget and EventEmitter add/remove patterns and detects
82
+ * listener exceedances (e.g. too many abort listeners on AbortSignal).
83
+ * Only present when notable listener patterns were detected.
84
+ */
85
+ listenerTracking?: EventListenerTracking;
77
86
  }
78
87
  /**
79
88
  * Compute performance metrics from a test run's collected data.
80
89
  */
81
- export declare function computeMetrics(testTiming: TestFileTiming[], profiles: CorrelatedProfile[], heapProfiles?: CorrelatedHeapProfile[], projectRoot?: string): PerformanceMetrics;
90
+ export declare function computeMetrics(testTiming: TestFileTiming[], profiles: CorrelatedProfile[], heapProfiles?: CorrelatedHeapProfile[], projectRoot?: string, listenerTracking?: EventListenerTracking): PerformanceMetrics;
82
91
  //# sourceMappingURL=metrics.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/vitest/metrics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAK3F,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,mCAAmC;AACnC,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,6BAA6B;AAC7B,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,6BAA6B;AAC7B,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;CAClC;AAED,qDAAqD;AACrD,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,OAAO,EAAE,CAAC,CAAC;IACX,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAElB,KAAK,EAAE,YAAY,CAAC;IACpB,GAAG,EAAE,UAAU,CAAC;IAEhB,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,oCAAoC;IACpC,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAElC,iEAAiE;IACjE,IAAI,CAAC,EAAE;QACL,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;CACH;AAID;;GAEG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,cAAc,EAAE,EAC5B,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,YAAY,CAAC,EAAE,qBAAqB,EAAE,EACtC,WAAW,CAAC,EAAE,MAAM,GACnB,kBAAkB,CAuGpB"}
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/vitest/metrics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAC3F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAKnE,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,mCAAmC;AACnC,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,6BAA6B;AAC7B,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,6BAA6B;AAC7B,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;CAClC;AAED,qDAAqD;AACrD,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,OAAO,EAAE,CAAC,CAAC;IACX,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAElB,KAAK,EAAE,YAAY,CAAC;IACpB,GAAG,EAAE,UAAU,CAAC;IAEhB,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,oCAAoC;IACpC,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAElC,iEAAiE;IACjE,IAAI,CAAC,EAAE;QACL,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;IAEF;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,qBAAqB,CAAC;CAC1C;AAID;;GAEG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,cAAc,EAAE,EAC5B,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,YAAY,CAAC,EAAE,qBAAqB,EAAE,EACtC,WAAW,CAAC,EAAE,MAAM,EACpB,gBAAgB,CAAC,EAAE,qBAAqB,GACvC,kBAAkB,CAwGpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/vitest/plugin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAgBzD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,sBAA2B;;6BAiBjC,GAAG;EA6F/B"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/vitest/plugin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAgBzD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,sBAA2B;;6BAiBjC,GAAG;EAwG/B"}
@@ -6,5 +6,5 @@
6
6
  * into categories (application, dependency, test, framework) so the agent
7
7
  * can prioritize what matters most to the developer.
8
8
  */
9
- export declare const VITEST_SYSTEM_PROMPT = "You are an expert in JavaScript/TypeScript performance optimization.\nYou have access to a workspace containing V8 CPU profiling data captured during\na Vitest test run. The workspace may also include V8 heap profiling data\ncaptured via Node's `--heap-prof` (allocation sampling).\n\nThe profiling data covers BOTH the test code AND the application code being tested.\n\n**Your primary goal is to analyze the PERFORMANCE OF THE APPLICATION CODE\nbeing tested** \u2014 the functions, modules, and algorithms that the developer\nwrote and is benchmarking or testing. Test infrastructure overhead (Vitest,\ntinybench, test setup) is secondary context.\n\n## Source categories\n\nEvery hot function and script in the workspace has a `sourceCategory` field:\n\n- **application** \u2014 Code in the user's project (the code being tested).\n This is your PRIMARY focus. Find bottlenecks, inefficiencies, and\n optimization opportunities in these functions.\n- **dependency** \u2014 Third-party code in node_modules. Report when a dependency\n is a significant bottleneck, since the developer may be able to choose\n an alternative, configure it differently, or avoid calling it in hot paths.\n- **test** \u2014 Test files. Only mention if the test setup itself is creating\n artificial overhead that masks application performance.\n- **framework** \u2014 Vitest/tinybench/V8 internals. Generally ignore unless\n they dominate the profile in an unexpected way.\n\n## Workspace structure\n\n- /summary.json \u2014 Overall test run: total tests, duration, pass/fail, GC stats\n- /timing/overview.json \u2014 Per-file test durations and individual test times\n- /timing/slow-tests.json \u2014 Tests exceeding the slow threshold\n- /profiles/index.json \u2014 Manifest mapping test files to their CPU profiles\n- /profiles/<file>.json \u2014 CPU profile summary: hot functions (with sourceCategory),\n call trees, GC samples, script breakdown (with sourceCategory)\n- /heap-profiles/index.json \u2014 (optional) Manifest mapping test files to heap profiles\n- /heap-profiles/<file>.json \u2014 (optional) Heap profile summary: allocation hotspots,\n per-script allocated bytes (with sourceCategory)\n- /hot-functions/application.json \u2014 **START HERE**: Hot functions from application code only\n- /hot-functions/dependencies.json \u2014 Hot functions from third-party dependencies\n- /hot-functions/global.json \u2014 All hot functions across all categories\n- /scripts/application.json \u2014 Per-script time breakdown for application code\n- /scripts/dependencies.json \u2014 Per-script time breakdown for dependencies\n- /tests/*.ts \u2014 Test source files\n- /src/*.ts \u2014 Application and dependency source files referenced by hot functions\n\n## Your workflow\n\n1. Read /hot-functions/application.json FIRST \u2014 these are the application-level\n bottlenecks the developer wants to optimize\n2. Read /scripts/application.json for the per-file view of application code time\n3. Read /hot-functions/dependencies.json for costly dependency calls\n4. If present, read /heap-profiles/index.json and /heap-profiles/<file>.json to identify\n allocation hotspots (functions/scripts allocating lots of bytes)\n5. Read /summary.json and /timing/overview.json for the big picture\n6. Read CPU profiles in /profiles/ for detailed call trees of the slowest tests\n7. Read the actual source code in /src/ and /tests/ to understand root causes\n8. Provide specific, actionable fixes targeting the application code\n\n## What to look for\n\n### Application code bottlenecks (PRIMARY FOCUS)\n- Functions with high self time \u2014 where is the application spending CPU?\n- Expensive algorithms: O(n\u00B2) loops, unnecessary sorting, repeated work\n- String/JSON operations: excessive serialization, string concatenation in loops\n- Object allocation hotspots: functions creating many short-lived objects\n- Synchronous blocking: file I/O, crypto, or compression in hot paths\n- Redundant computation: values computed repeatedly that could be cached/memoized\n- Data structure choices: using arrays where Maps/Sets would be O(1)\n\n### Dependency-related bottlenecks\n- Dependencies consuming disproportionate CPU \u2014 suggest alternatives or configuration\n- Unnecessary calls to expensive dependency APIs in hot paths\n- Dependencies pulled in for simple operations that could be hand-written\n\n### GC pressure from application code\n- Application functions creating many temporary objects in tight loops\n- Large array/object allocations that could be pooled or reused\n- Closures capturing large scopes unnecessarily\n\n### Allocation hotspots (from heap profiles, if present)\n- Functions allocating a large share of total bytes (even if CPU isn't dominant)\n- Scripts/modules responsible for most allocation \u2014 suggest caching, reuse, pooling,\n or avoiding intermediate arrays/objects\n- When allocation hotspots match CPU hotspots, prioritize fixes there first\n\n### Call chain analysis\n- Trace expensive call trees to find which APPLICATION function triggers them\n- Follow the call tree from application entry points down to the hot leaf functions\n- Identify which application-level design decisions lead to the bottleneck\n\n### Test infrastructure (SECONDARY \u2014 only if impactful)\n- Test setup creating artificial overhead that dwarfs application execution\n- Benchmarks measuring setup cost instead of application performance\n- Only mention if it prevents getting clean application performance data\n\n## Finding categories\n\nEach finding MUST use one of these exact category values:\n\n- **algorithm** \u2014 Inefficient algorithm: O(n\u00B2) loops, brute-force search, repeated work\n- **serialization** \u2014 Excessive JSON.stringify/parse, string concatenation, encoding\n- **allocation** \u2014 Excessive object/array creation causing GC pressure\n- **event-handling** \u2014 Listener leaks, unbounded event handler accumulation\n- **hot-function** \u2014 Generic CPU-hot function that doesn't fit a more specific category\n- **gc-pressure** \u2014 High garbage collection overhead\n- **listener-leak** \u2014 Event listeners not cleaned up properly\n- **unnecessary-computation** \u2014 Redundant work that could be cached or eliminated\n- **blocking-io** \u2014 Synchronous I/O or blocking operations in hot paths\n- **dependency-bottleneck** \u2014 Expensive dependency call the developer can optimize\n- **slow-test** \u2014 Test itself is slow due to setup or teardown\n- **expensive-setup** \u2014 Costly test setup (beforeAll/beforeEach)\n- **import-overhead** \u2014 Expensive module imports at test time\n- **other** \u2014 Doesn't fit any of the above\n\nPrefer more specific categories (algorithm, serialization, allocation, event-handling)\nover generic ones (hot-function, other) when the root cause is clear.\n\n## Output guidelines\n\n- Report 3\u20137 findings, ordered by impact ON THE APPLICATION CODE\n- Focus findings on functions the developer CAN change (application code first,\n then dependency usage patterns, then test structure)\n- Be specific \u2014 name actual files, functions, line numbers from the source code\n- Provide concrete code-level fixes, not generic advice\n- When reporting a dependency bottleneck, explain what application code is\n calling it and how the developer can reduce that cost\n- If the application code is already efficient, say so \u2014 don't force findings\n about test infrastructure just to fill the report";
9
+ export declare const VITEST_SYSTEM_PROMPT = "You are an expert in JavaScript/TypeScript performance optimization.\nYou have access to a workspace containing V8 CPU profiling data captured during\na Vitest test run. The workspace may also include V8 heap profiling data\ncaptured via Node's `--heap-prof` (allocation sampling).\n\nThe profiling data covers BOTH the test code AND the application code being tested.\n\n**Your primary goal is to analyze the PERFORMANCE OF THE APPLICATION CODE\nbeing tested** \u2014 the functions, modules, and algorithms that the developer\nwrote and is benchmarking or testing. Test infrastructure overhead (Vitest,\ntinybench, test setup) is secondary context.\n\n## Source categories\n\nEvery hot function and script in the workspace has a `sourceCategory` field:\n\n- **application** \u2014 Code in the user's project (the code being tested).\n This is your PRIMARY focus. Find bottlenecks, inefficiencies, and\n optimization opportunities in these functions.\n- **dependency** \u2014 Third-party code in node_modules. Report when a dependency\n is a significant bottleneck, since the developer may be able to choose\n an alternative, configure it differently, or avoid calling it in hot paths.\n- **test** \u2014 Test files. Only mention if the test setup itself is creating\n artificial overhead that masks application performance.\n- **framework** \u2014 Vitest/tinybench/V8 internals. Generally ignore unless\n they dominate the profile in an unexpected way.\n\n## Workspace structure\n\n- /summary.json \u2014 Overall test run: total tests, duration, pass/fail, GC stats\n- /timing/overview.json \u2014 Per-file test durations and individual test times\n- /timing/slow-tests.json \u2014 Tests exceeding the slow threshold\n- /profiles/index.json \u2014 Manifest mapping test files to their CPU profiles\n- /profiles/<file>.json \u2014 CPU profile summary: hot functions (with sourceCategory),\n call trees, GC samples, script breakdown (with sourceCategory)\n- /heap-profiles/index.json \u2014 (optional) Manifest mapping test files to heap profiles\n- /heap-profiles/<file>.json \u2014 (optional) Heap profile summary: allocation hotspots,\n per-script allocated bytes (with sourceCategory)\n- /hot-functions/application.json \u2014 **START HERE**: Hot functions from application code only\n- /hot-functions/dependencies.json \u2014 Hot functions from third-party dependencies\n- /hot-functions/global.json \u2014 All hot functions across all categories\n- /scripts/application.json \u2014 Per-script time breakdown for application code\n- /scripts/dependencies.json \u2014 Per-script time breakdown for dependencies\n- /listener-tracking.json \u2014 (optional) Event listener tracking data captured from\n worker processes. Contains per-event-type add/remove counts for EventTarget and\n EventEmitter, plus exceedances where listener counts exceeded maxListeners.\n- /tests/*.ts \u2014 Test source files\n- /src/*.ts \u2014 Application and dependency source files referenced by hot functions\n\n## Your workflow\n\n1. Read /hot-functions/application.json FIRST \u2014 these are the application-level\n bottlenecks the developer wants to optimize\n2. Read /scripts/application.json for the per-file view of application code time\n3. Read /hot-functions/dependencies.json for costly dependency calls\n4. If present, read /heap-profiles/index.json and /heap-profiles/<file>.json to identify\n allocation hotspots (functions/scripts allocating lots of bytes)\n5. If present, read /listener-tracking.json for event listener add/remove patterns\n and listener exceedances (too many listeners on a single target)\n6. Read /summary.json and /timing/overview.json for the big picture\n7. Read CPU profiles in /profiles/ for detailed call trees of the slowest tests\n8. Read the actual source code in /src/ and /tests/ to understand root causes\n9. Provide specific, actionable fixes targeting the application code\n\n## What to look for\n\n### Application code bottlenecks (PRIMARY FOCUS)\n- Functions with high self time \u2014 where is the application spending CPU?\n- Expensive algorithms: O(n\u00B2) loops, unnecessary sorting, repeated work\n- String/JSON operations: excessive serialization, string concatenation in loops\n- Object allocation hotspots: functions creating many short-lived objects\n- Synchronous blocking: file I/O, crypto, or compression in hot paths\n- Redundant computation: values computed repeatedly that could be cached/memoized\n- Data structure choices: using arrays where Maps/Sets would be O(1)\n\n### Dependency-related bottlenecks\n- Dependencies consuming disproportionate CPU \u2014 suggest alternatives or configuration\n- Unnecessary calls to expensive dependency APIs in hot paths\n- Dependencies pulled in for simple operations that could be hand-written\n\n### GC pressure from application code\n- Application functions creating many temporary objects in tight loops\n- Large array/object allocations that could be pooled or reused\n- Closures capturing large scopes unnecessarily\n\n### Allocation hotspots (from heap profiles, if present)\n- Functions allocating a large share of total bytes (even if CPU isn't dominant)\n- Scripts/modules responsible for most allocation \u2014 suggest caching, reuse, pooling,\n or avoiding intermediate arrays/objects\n- When allocation hotspots match CPU hotspots, prioritize fixes there first\n\n### Call chain analysis\n- Trace expensive call trees to find which APPLICATION function triggers them\n- Follow the call tree from application entry points down to the hot leaf functions\n- Identify which application-level design decisions lead to the bottleneck\n\n### Event listener tracking (from /listener-tracking.json, if present)\n- **Exceedances** \u2014 when a single EventTarget or EventEmitter accumulates more\n listeners than its maxListeners threshold (default 10), this is a strong\n signal of a listener leak. The exceedance data includes the target type\n (e.g. AbortSignal), event name, listener count, and a stack trace snippet\n pointing to the code that registered the excess listener.\n- **Add/remove imbalances** \u2014 when `addCount` significantly exceeds\n `removeCount` for a given event type, listeners are being registered but\n not cleaned up. This causes memory growth and eventually GC pressure.\n Look for patterns like:\n - AbortSignal abort listeners not cleaned up (common with fetch/streams)\n - EventEmitter listeners added in loops without corresponding removal\n - Missing `{ once: true }` option or `AbortController` cleanup\n- When exceedances or imbalances are found, read the source code to identify\n the root cause and suggest specific fixes (e.g. using `AbortController`,\n `removeEventListener`, `{ once: true }`, or restructuring listener\n registration to avoid accumulation).\n\n### Test infrastructure (SECONDARY \u2014 only if impactful)\n- Test setup creating artificial overhead that dwarfs application execution\n- Benchmarks measuring setup cost instead of application performance\n- Only mention if it prevents getting clean application performance data\n\n## Finding categories\n\nEach finding MUST use one of these exact category values:\n\n- **algorithm** \u2014 Inefficient algorithm: O(n\u00B2) loops, brute-force search, repeated work\n- **serialization** \u2014 Excessive JSON.stringify/parse, string concatenation, encoding\n- **allocation** \u2014 Excessive object/array creation causing GC pressure\n- **event-handling** \u2014 Listener leaks, unbounded event handler accumulation\n- **hot-function** \u2014 Generic CPU-hot function that doesn't fit a more specific category\n- **gc-pressure** \u2014 High garbage collection overhead\n- **listener-leak** \u2014 Event listeners not cleaned up properly\n- **unnecessary-computation** \u2014 Redundant work that could be cached or eliminated\n- **blocking-io** \u2014 Synchronous I/O or blocking operations in hot paths\n- **dependency-bottleneck** \u2014 Expensive dependency call the developer can optimize\n- **slow-test** \u2014 Test itself is slow due to setup or teardown\n- **expensive-setup** \u2014 Costly test setup (beforeAll/beforeEach)\n- **import-overhead** \u2014 Expensive module imports at test time\n- **other** \u2014 Doesn't fit any of the above\n\nPrefer more specific categories (algorithm, serialization, allocation, event-handling)\nover generic ones (hot-function, other) when the root cause is clear.\n\n## Output guidelines\n\n- Report 3\u20137 findings, ordered by impact ON THE APPLICATION CODE\n- Focus findings on functions the developer CAN change (application code first,\n then dependency usage patterns, then test structure)\n- Be specific \u2014 name actual files, functions, line numbers from the source code\n- Provide concrete code-level fixes, not generic advice\n- When reporting a dependency bottleneck, explain what application code is\n calling it and how the developer can reduce that cost\n- If the application code is already efficient, say so \u2014 don't force findings\n about test infrastructure just to fill the report";
10
10
  //# sourceMappingURL=prompts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/vitest/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,oBAAoB,u1OAgImB,CAAC"}
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/vitest/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,oBAAoB,m4RAuJmB,CAAC"}
@@ -58,6 +58,15 @@ export declare class ZeitZeugeReporter {
58
58
  * Uses the same timestamp-order correlation strategy as CPU profiles.
59
59
  */
60
60
  private collectAndParseHeapProfiles;
61
+ /**
62
+ * Collect and aggregate event listener tracking data written by the
63
+ * preload script in each worker process.
64
+ *
65
+ * Each worker writes a `listener-tracking-<pid>.json` file to the profile
66
+ * directory on exit. This method reads all such files, parses them, and
67
+ * aggregates the data into a single summary.
68
+ */
69
+ private collectListenerTracking;
61
70
  /**
62
71
  * Read test source files from disk.
63
72
  */
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/vitest/reporter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA0BH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAoED;;;;;GAKG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAkB;IAEjC,iEAAiE;IACjE,OAAO,CAAC,cAAc,CAAgB;IAEtC,uDAAuD;IACvD,OAAO,CAAC,IAAI,CAAoB;gBAEpB,OAAO,EAAE,eAAe;IAIpC,OAAO,CAAC,sBAAsB;IAU9B;;;OAGG;IACH,iBAAiB,CAAC,UAAU,EAAE,GAAG,GAAG,IAAI;IAQxC;;OAEG;IACG,YAAY,CAAC,WAAW,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YA0BpD,WAAW;IAwHzB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAwCzB;;OAEG;IACH,OAAO,CAAC,aAAa;IAwBrB;;;;;;OAMG;IACH,OAAO,CAAC,uBAAuB;IA2F/B;;;;OAIG;IACH,OAAO,CAAC,2BAA2B;IAsEnC;;OAEG;IACH,OAAO,CAAC,eAAe;IAiBvB;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;IAoC9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAUzB;;OAEG;IACH,OAAO,CAAC,UAAU;CAGnB"}
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/vitest/reporter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgCH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAoED;;;;;GAKG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAkB;IAEjC,iEAAiE;IACjE,OAAO,CAAC,cAAc,CAAgB;IAEtC,uDAAuD;IACvD,OAAO,CAAC,IAAI,CAAoB;gBAEpB,OAAO,EAAE,eAAe;IAIpC,OAAO,CAAC,sBAAsB;IAU9B;;;OAGG;IACH,iBAAiB,CAAC,UAAU,EAAE,GAAG,GAAG,IAAI;IAQxC;;OAEG;IACG,YAAY,CAAC,WAAW,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YA0BpD,WAAW;IA0IzB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAwCzB;;OAEG;IACH,OAAO,CAAC,aAAa;IAsBrB;;;;;;OAMG;IACH,OAAO,CAAC,uBAAuB;IA2F/B;;;;OAIG;IACH,OAAO,CAAC,2BAA2B;IAsEnC;;;;;;;OAOG;IACH,OAAO,CAAC,uBAAuB;IA+C/B;;OAEG;IACH,OAAO,CAAC,eAAe;IAiBvB;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;IAoC9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAUzB;;OAEG;IACH,OAAO,CAAC,UAAU;CAGnB"}
@@ -229,5 +229,7 @@ export interface VitestWorkspaceOptions {
229
229
  projectRoot?: string;
230
230
  /** Computed performance metrics for the current run. */
231
231
  metrics?: import('./metrics.js').PerformanceMetrics;
232
+ /** Aggregated event listener tracking from worker processes. */
233
+ listenerTracking?: import('./listener-tracker.js').EventListenerTracking;
232
234
  }
233
235
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/vitest/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;;;;;GAQG;AACH,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;AAI7F,+CAA+C;AAC/C,MAAM,WAAW,sBAAsB;IACrC,+CAA+C;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gEAAgE;IAChE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2CAA2C;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;KAClC,CAAC,CAAC;CACJ;AAID,mDAAmD;AACnD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAID,uDAAuD;AACvD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,kBAAkB,CAAC;CAC7B;AAID,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,qDAAqD;AACrD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE;QACT,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,CAAC,EAAE,KAAK,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAID,+DAA+D;AAC/D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,iBAAiB,CAAC;IACxB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,mBAAmB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE;QACT,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAChC;AAID,qDAAqD;AACrD,MAAM,WAAW,iBAAiB;IAChC,mCAAmC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,yDAAyD;IACzD,kBAAkB,EAAE,YAAY,EAAE,CAAC;IACnC,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,cAAc,EAAE,MAAM,CAAC;IACvB,gCAAgC;IAChC,eAAe,EAAE,iBAAiB,EAAE,CAAC;CACtC;AAED,sDAAsD;AACtD,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,mCAAmC;AACnC,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,aAAa,EAAE,MAAM,CAAC;IACtB,oCAAoC;IACpC,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAID,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,8CAA8C;AAC9C,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,aAAa,EAAE,MAAM,CAAC;IACtB,oCAAoC;IACpC,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IACjC,oCAAoC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,mBAAmB,EAAE,MAAM,CAAC;IAC5B,8BAA8B;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,cAAc,EAAE,iBAAiB,EAAE,CAAC;IACpC,2CAA2C;IAC3C,eAAe,EAAE,uBAAuB,EAAE,CAAC;CAC5C;AAID,0DAA0D;AAC1D,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,4EAA4E;IAC5E,YAAY,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACvC,0CAA0C;IAC1C,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,qEAAqE;IACrE,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,OAAO,CAAC,EAAE,OAAO,cAAc,EAAE,kBAAkB,CAAC;CACrD"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/vitest/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/vitest/workspace.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAKrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzF,MAAM,WAAW,qBAAqB;IACpC,2CAA2C;IAC3C,OAAO,EAAE,eAAe,CAAC;IACzB,iDAAiD;IACjD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAQD;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CA0NhC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,WAAW,EAAE,CA+B9E"}
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/vitest/workspace.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAKrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzF,MAAM,WAAW,qBAAqB;IACpC,2CAA2C;IAC3C,OAAO,EAAE,eAAe,CAAC;IACzB,iDAAiD;IACjD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAQD;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAuOhC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,WAAW,EAAE,CA+B9E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zeitzeuge",
3
- "version": "0.4.2",
3
+ "version": "0.5.1",
4
4
  "description": "A deepagent to witnessing slowdowns in your test runs.",
5
5
  "keywords": [
6
6
  "analysis",