#!/usr/bin/env node /** * Fully automated idle CPU/memory capture for OpenChamber. * * Unlike `profile:browser`, this command needs no human in the loop: it loads * the app, lets it settle, then records a window during which no input is * delivered. Everything it reports is therefore work the app performs while the * user is doing nothing, which is the regression class users notice as fan * noise, battery drain, and a permanently busy tab. * * Reported dimensions (per second of the idle window): * - main-thread busy time, script time, style recalculation, layout; * - style recalculation and layout counts; * - DOM node, document, frame, and JS event listener growth; * - JS heap trajectory (start/end/max plus linear growth rate); * - CPU sampling profile with self time per function; * - scheduled-work attribution per timer/animation-frame/observer call site. * * Runs are directly comparable: `--baseline ` prints a per-metric * delta table and exits non-zero when a budget in `--budget-*` is exceeded, so * the same command works as an investigation tool and as a regression gate. */ import { mkdir, readFile, writeFile } from "node:fs/promises" import { homedir } from "node:os" import { join, resolve } from "node:path" import process from "node:process" import { CdpClient, createPageTarget, evaluateValue, launchChrome, reservePort, resolveChrome, wait } from "./perf/cdp.mjs" import { buildIdleProbeSource, IDLE_PROBE_GLOBAL } from "./perf/idle-probe.mjs" import { summarizeCpuProfile } from "./perf/cpu-profile.mjs" import { expandProjects, expandSessionLists } from "./perf/scenario.mjs" import { growthPerSecond, metricMap, round } from "./perf/metrics.mjs" const HELP = `Usage: bun run profile:idle -- [options] Records what OpenChamber does while nobody is interacting with it. Options: --url OpenChamber URL (default: http://localhost:3000) --session Open this session before recording (deep link) --tab Open this main tab before recording --then-tab After settling, navigate to this tab without a reload, then record. Use it to measure what a surface keeps doing after the user leaves it. --expand-sessions Click every "Show more sessions" control until the sidebar has no collapsed session lists left, so all session rows are mounted. Clicks happen before the recording window, which stays input-free. --expand-projects Expand every project in the sidebar before recording, which mounts a row per worktree and session directory --panel Open the context panel on this surface before recording (chat, preview, terminal, git, pr, notes, file, diff, plan, context, browser, walkthrough). Repeatable; the first entry becomes the active tab. --duration Idle recording window (default: 30) --settle Wait after load before recording (default: 15) --output Artifact directory (default: artifacts/idle-profile-