// {{ display_name }} MCP server — generated by mcpify. Do not hand-edit.
// Summarizes one or more V8 `.heapprofile` files (produced by `node
// --heap-prof` — Vitest forks a worker process per test file, so a real
// test run usually produces several) as plain text: top functions by
// self size, merged across all inputs — so it's LLM/tool-ingestable
// without needing to open Chrome DevTools' Memory tab.
import { readFileSync, writeFileSync } from 'node:fs';

const args = process.argv.slice(2);
const outputPath = args.pop();
const inputPaths = args;
if (!outputPath || inputPaths.length === 0) {
  console.error('usage: node heap-profile-summary.js <profile.heapprofile...> <out.txt>');
  process.exit(1);
}

const selfSizeByFunction = new Map();

function walk(node) {
  const name = node.callFrame?.functionName || '(anonymous)';
  selfSizeByFunction.set(name, (selfSizeByFunction.get(name) || 0) + (node.selfSize || 0));
  for (const child of node.children || []) walk(child);
}

for (const inputPath of inputPaths) {
  const profile = JSON.parse(readFileSync(inputPath, 'utf8'));
  walk(profile.head);
}

const top = [...selfSizeByFunction.entries()]
  .sort((a, b) => b[1] - a[1])
  .slice(0, 30);

const lines = [`# Top functions by heap self-size (bytes), merged across ${inputPaths.length} profile(s)`];
for (const [name, size] of top) {
  lines.push(`${String(size).padStart(10)}  ${name}`);
}

writeFileSync(outputPath, lines.join('\n') + '\n');
console.log(`wrote top ${top.length} functions to ${outputPath}`);
