@agent-scope/cli 1.11.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -205,9 +205,9 @@ function createRL() {
205
205
  });
206
206
  }
207
207
  async function ask(rl, question) {
208
- return new Promise((resolve10) => {
208
+ return new Promise((resolve11) => {
209
209
  rl.question(question, (answer) => {
210
- resolve10(answer.trim());
210
+ resolve11(answer.trim());
211
211
  });
212
212
  });
213
213
  }
@@ -1524,9 +1524,364 @@ Available: ${available}`
1524
1524
  );
1525
1525
  return cmd;
1526
1526
  }
1527
+ var MANIFEST_PATH4 = ".reactscope/manifest.json";
1528
+ var DEFAULT_VIEWPORT_WIDTH = 375;
1529
+ var DEFAULT_VIEWPORT_HEIGHT = 812;
1530
+ var _pool = null;
1531
+ async function getPool() {
1532
+ if (_pool === null) {
1533
+ _pool = new BrowserPool({
1534
+ size: { browsers: 1, pagesPerBrowser: 1 },
1535
+ viewportWidth: DEFAULT_VIEWPORT_WIDTH,
1536
+ viewportHeight: DEFAULT_VIEWPORT_HEIGHT
1537
+ });
1538
+ await _pool.init();
1539
+ }
1540
+ return _pool;
1541
+ }
1542
+ async function shutdownPool() {
1543
+ if (_pool !== null) {
1544
+ await _pool.close();
1545
+ _pool = null;
1546
+ }
1547
+ }
1548
+ function mapNodeType(node) {
1549
+ if (node.type === "forward_ref") return "forwardRef";
1550
+ if (node.type === "host") return "host";
1551
+ const name = node.name;
1552
+ if (name.endsWith(".Provider") || name === "Provider") return "context.provider";
1553
+ if (name.endsWith(".Consumer") || name === "Consumer") return "context.consumer";
1554
+ return node.type;
1555
+ }
1556
+ function flattenSerializedValue(sv) {
1557
+ if (sv === null || sv === void 0) return null;
1558
+ const v = sv;
1559
+ switch (v.type) {
1560
+ case "null":
1561
+ case "undefined":
1562
+ return null;
1563
+ case "string":
1564
+ case "number":
1565
+ case "boolean":
1566
+ return v.value;
1567
+ case "object": {
1568
+ if (!Array.isArray(v.entries)) return {};
1569
+ const result = {};
1570
+ for (const entry of v.entries) {
1571
+ result[entry.key] = flattenSerializedValue(entry.value);
1572
+ }
1573
+ return result;
1574
+ }
1575
+ case "array": {
1576
+ if (!Array.isArray(v.items)) return [];
1577
+ return v.items.map(flattenSerializedValue);
1578
+ }
1579
+ case "function":
1580
+ return "[Function]";
1581
+ case "symbol":
1582
+ return `[Symbol: ${v.description ?? ""}]`;
1583
+ case "circular":
1584
+ return "[Circular]";
1585
+ case "truncated":
1586
+ return `[Truncated: ${v.preview ?? ""}]`;
1587
+ default:
1588
+ return v.preview ?? null;
1589
+ }
1590
+ }
1591
+ function flattenHookState(hooks) {
1592
+ const result = {};
1593
+ for (let i = 0; i < hooks.length; i++) {
1594
+ const hook = hooks[i];
1595
+ if (hook === void 0) continue;
1596
+ const key = hook.name !== null && hook.name !== void 0 ? hook.name : `${hook.type}[${i}]`;
1597
+ result[key] = flattenSerializedValue(hook.value);
1598
+ }
1599
+ return result;
1600
+ }
1601
+ function extractContextNames(contexts) {
1602
+ const names = contexts.map((c) => c.contextName ?? "Unknown").filter((name, idx, arr) => arr.indexOf(name) === idx);
1603
+ return names;
1604
+ }
1605
+ function anyContextChanged(contexts) {
1606
+ return contexts.some((c) => c.didTriggerRender);
1607
+ }
1608
+ function convertToInstrumentNode(node, depth = 0) {
1609
+ const contexts = extractContextNames(node.context);
1610
+ const contextChanged = anyContextChanged(node.context);
1611
+ const state = flattenHookState(node.state);
1612
+ const propsFlat = flattenSerializedValue(node.props);
1613
+ const props = propsFlat !== null && typeof propsFlat === "object" && !Array.isArray(propsFlat) ? propsFlat : {};
1614
+ return {
1615
+ component: node.name,
1616
+ type: mapNodeType(node),
1617
+ renderCount: node.renderCount,
1618
+ lastRenderDuration: node.renderDuration,
1619
+ memoized: node.type === "memo",
1620
+ // memoSkipped requires tracking bail-outs across commits — not available from
1621
+ // a single-shot capture. Defaulted to 0.
1622
+ memoSkipped: 0,
1623
+ props,
1624
+ // propsChanged is not tracked in a single-shot capture — would need a diff
1625
+ // between two renders. Defaulted to false.
1626
+ propsChanged: false,
1627
+ state,
1628
+ stateChanged: false,
1629
+ contextChanged,
1630
+ contexts,
1631
+ depth,
1632
+ children: node.children.map((child) => convertToInstrumentNode(child, depth + 1))
1633
+ };
1634
+ }
1635
+ function filterByContext(node, contextName) {
1636
+ const filteredChildren = node.children.map((child) => filterByContext(child, contextName)).filter((c) => c !== null);
1637
+ const selfMatches = node.contexts.some((c) => c.toLowerCase() === contextName.toLowerCase());
1638
+ if (!selfMatches && filteredChildren.length === 0) return null;
1639
+ return { ...node, children: filteredChildren };
1640
+ }
1641
+ function filterWastedRenders(node) {
1642
+ const filteredChildren = node.children.map((child) => filterWastedRenders(child)).filter((c) => c !== null);
1643
+ const isWasted = !node.propsChanged && !node.stateChanged && !node.contextChanged && !node.memoized && node.renderCount > 1;
1644
+ if (!isWasted && filteredChildren.length === 0) return null;
1645
+ return { ...node, children: filteredChildren };
1646
+ }
1647
+ function sortTree(node, sortBy) {
1648
+ const sortedChildren = node.children.map((child) => sortTree(child, sortBy)).sort((a, b) => {
1649
+ if (sortBy === "renderCount") return b.renderCount - a.renderCount;
1650
+ return a.depth - b.depth;
1651
+ });
1652
+ return { ...node, children: sortedChildren };
1653
+ }
1654
+ function annotateProviderDepth(node, providerDepth = 0) {
1655
+ const isProvider = node.type === "context.provider";
1656
+ const childProviderDepth = isProvider ? providerDepth + 1 : providerDepth;
1657
+ return {
1658
+ ...node,
1659
+ _providerDepth: providerDepth,
1660
+ children: node.children.map((child) => annotateProviderDepth(child, childProviderDepth))
1661
+ };
1662
+ }
1663
+ function limitNodes(root, limit) {
1664
+ let remaining = limit;
1665
+ const clip = (node) => {
1666
+ if (remaining <= 0) return null;
1667
+ remaining--;
1668
+ const clippedChildren = [];
1669
+ for (const child of node.children) {
1670
+ const clipped = clip(child);
1671
+ if (clipped !== null) clippedChildren.push(clipped);
1672
+ }
1673
+ return { ...node, children: clippedChildren };
1674
+ };
1675
+ return clip(root) ?? root;
1676
+ }
1677
+ var BRANCH = "\u251C\u2500\u2500 ";
1678
+ var LAST_BRANCH = "\u2514\u2500\u2500 ";
1679
+ var VERTICAL = "\u2502 ";
1680
+ var EMPTY = " ";
1681
+ function buildTTYLabel(node, showProviderDepth) {
1682
+ const parts = [node.component];
1683
+ switch (node.type) {
1684
+ case "memo":
1685
+ parts.push("[memo]");
1686
+ break;
1687
+ case "forwardRef":
1688
+ parts.push("[forwardRef]");
1689
+ break;
1690
+ case "class":
1691
+ parts.push("[class]");
1692
+ break;
1693
+ case "context.provider":
1694
+ parts.push("[provider]");
1695
+ break;
1696
+ case "context.consumer":
1697
+ parts.push("[consumer]");
1698
+ break;
1699
+ }
1700
+ if (node.renderCount > 0) {
1701
+ const durationStr = node.lastRenderDuration > 0 ? ` ${node.lastRenderDuration.toFixed(2)}ms` : "";
1702
+ parts.push(`(renders:${node.renderCount}${durationStr})`);
1703
+ }
1704
+ if (node.contexts.length > 0) {
1705
+ parts.push(`[ctx:${node.contexts.join(",")}]`);
1706
+ }
1707
+ if (showProviderDepth) {
1708
+ const pd = node._providerDepth;
1709
+ if (pd !== void 0 && pd > 0) {
1710
+ parts.push(`[pd:${pd}]`);
1711
+ }
1712
+ }
1713
+ return parts.join(" ");
1714
+ }
1715
+ function renderTTYNode(node, prefix, isLast, showProviderDepth, lines) {
1716
+ if (node.type === "host") {
1717
+ for (let i = 0; i < node.children.length; i++) {
1718
+ const child = node.children[i];
1719
+ if (child !== void 0) {
1720
+ renderTTYNode(child, prefix, i === node.children.length - 1, showProviderDepth, lines);
1721
+ }
1722
+ }
1723
+ return;
1724
+ }
1725
+ const connector = isLast ? LAST_BRANCH : BRANCH;
1726
+ lines.push(`${prefix}${connector}${buildTTYLabel(node, showProviderDepth)}`);
1727
+ const nextPrefix = prefix + (isLast ? EMPTY : VERTICAL);
1728
+ for (let i = 0; i < node.children.length; i++) {
1729
+ const child = node.children[i];
1730
+ if (child !== void 0) {
1731
+ renderTTYNode(child, nextPrefix, i === node.children.length - 1, showProviderDepth, lines);
1732
+ }
1733
+ }
1734
+ }
1735
+ function formatInstrumentTree(root, showProviderDepth = false) {
1736
+ const lines = [];
1737
+ if (root.type !== "host") {
1738
+ lines.push(buildTTYLabel(root, showProviderDepth));
1739
+ for (let i = 0; i < root.children.length; i++) {
1740
+ const child = root.children[i];
1741
+ if (child !== void 0) {
1742
+ renderTTYNode(child, "", i === root.children.length - 1, showProviderDepth, lines);
1743
+ }
1744
+ }
1745
+ } else {
1746
+ for (let i = 0; i < root.children.length; i++) {
1747
+ const child = root.children[i];
1748
+ if (child !== void 0) {
1749
+ renderTTYNode(child, "", i === root.children.length - 1, showProviderDepth, lines);
1750
+ }
1751
+ }
1752
+ }
1753
+ return lines.join("\n");
1754
+ }
1755
+ async function runInstrumentTree(options) {
1756
+ const { componentName, filePath } = options;
1757
+ const pool = await getPool();
1758
+ const slot = await pool.acquire();
1759
+ const { page } = slot;
1760
+ try {
1761
+ await page.addInitScript({ content: getBrowserEntryScript() });
1762
+ const htmlHarness = await buildComponentHarness(
1763
+ filePath,
1764
+ componentName,
1765
+ {},
1766
+ DEFAULT_VIEWPORT_WIDTH
1767
+ );
1768
+ await page.setContent(htmlHarness, { waitUntil: "load" });
1769
+ await page.waitForFunction(
1770
+ () => {
1771
+ const w = window;
1772
+ return w.__SCOPE_RENDER_COMPLETE__ === true;
1773
+ },
1774
+ { timeout: 15e3 }
1775
+ );
1776
+ const renderError = await page.evaluate(
1777
+ () => window.__SCOPE_RENDER_ERROR__ ?? null
1778
+ );
1779
+ if (renderError !== null) {
1780
+ throw new Error(`Component render error: ${renderError}`);
1781
+ }
1782
+ const captureJson = await page.evaluate(async () => {
1783
+ const w = window;
1784
+ if (typeof w.__SCOPE_CAPTURE_JSON__ !== "function") {
1785
+ throw new Error("__SCOPE_CAPTURE_JSON__ not available \u2014 Scope runtime not injected");
1786
+ }
1787
+ return w.__SCOPE_CAPTURE_JSON__({ lightweight: false });
1788
+ });
1789
+ const captureResult = JSON.parse(captureJson);
1790
+ const componentTree = captureResult.tree;
1791
+ if (componentTree === void 0 || componentTree === null) {
1792
+ throw new Error(`No component tree found for "${componentName}"`);
1793
+ }
1794
+ let instrumentRoot = convertToInstrumentNode(componentTree, 0);
1795
+ if (options.usesContext !== void 0) {
1796
+ const filtered = filterByContext(instrumentRoot, options.usesContext);
1797
+ instrumentRoot = filtered !== null ? filtered : { ...instrumentRoot, children: [] };
1798
+ }
1799
+ if (options.wastedRenders === true) {
1800
+ const filtered = filterWastedRenders(instrumentRoot);
1801
+ instrumentRoot = filtered !== null ? filtered : { ...instrumentRoot, children: [] };
1802
+ }
1803
+ if (options.sortBy !== void 0) {
1804
+ instrumentRoot = sortTree(instrumentRoot, options.sortBy);
1805
+ }
1806
+ if (options.providerDepth === true) {
1807
+ instrumentRoot = annotateProviderDepth(instrumentRoot, 0);
1808
+ }
1809
+ if (options.limit !== void 0 && options.limit > 0) {
1810
+ instrumentRoot = limitNodes(instrumentRoot, options.limit);
1811
+ }
1812
+ return instrumentRoot;
1813
+ } finally {
1814
+ pool.release(slot);
1815
+ }
1816
+ }
1817
+ function createInstrumentTreeCommand() {
1818
+ return new Command("tree").description("Render a component via BrowserPool and output a structured instrumentation tree").argument("<component>", "Component name to instrument (must exist in the manifest)").option("--sort-by <field>", "Sort nodes by field: renderCount | depth").option("--limit <n>", "Limit output to the first N nodes (depth-first)").option("--uses-context <name>", "Filter to components that use a specific context").option("--provider-depth", "Annotate each node with its context-provider nesting depth", false).option(
1819
+ "--wasted-renders",
1820
+ "Filter to components with wasted renders (no prop/state/context changes, not memoized)",
1821
+ false
1822
+ ).option("--format <fmt>", "Output format: json | tree (default: auto)").option("--manifest <path>", "Path to manifest.json", MANIFEST_PATH4).action(async (componentName, opts) => {
1823
+ try {
1824
+ const manifest = loadManifest(opts.manifest);
1825
+ const descriptor = manifest.components[componentName];
1826
+ if (descriptor === void 0) {
1827
+ const available = Object.keys(manifest.components).slice(0, 5).join(", ");
1828
+ throw new Error(
1829
+ `Component "${componentName}" not found in manifest.
1830
+ Available: ${available}`
1831
+ );
1832
+ }
1833
+ if (opts.sortBy !== void 0) {
1834
+ const allowed = ["renderCount", "depth"];
1835
+ if (!allowed.includes(opts.sortBy)) {
1836
+ throw new Error(
1837
+ `Unknown --sort-by value "${opts.sortBy}". Allowed: ${allowed.join(", ")}`
1838
+ );
1839
+ }
1840
+ }
1841
+ const rootDir = process.cwd();
1842
+ const filePath = resolve(rootDir, descriptor.filePath);
1843
+ process.stderr.write(`Instrumenting ${componentName}\u2026
1844
+ `);
1845
+ const instrumentRoot = await runInstrumentTree({
1846
+ componentName,
1847
+ filePath,
1848
+ sortBy: opts.sortBy,
1849
+ limit: opts.limit !== void 0 ? Math.max(1, parseInt(opts.limit, 10)) : void 0,
1850
+ usesContext: opts.usesContext,
1851
+ providerDepth: opts.providerDepth,
1852
+ wastedRenders: opts.wastedRenders
1853
+ });
1854
+ await shutdownPool();
1855
+ const fmt = resolveFormat2(opts.format);
1856
+ if (fmt === "json") {
1857
+ process.stdout.write(`${JSON.stringify(instrumentRoot, null, 2)}
1858
+ `);
1859
+ } else {
1860
+ const tree = formatInstrumentTree(instrumentRoot, opts.providerDepth ?? false);
1861
+ process.stdout.write(`${tree}
1862
+ `);
1863
+ }
1864
+ } catch (err) {
1865
+ await shutdownPool();
1866
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
1867
+ `);
1868
+ process.exit(1);
1869
+ }
1870
+ });
1871
+ }
1872
+ function resolveFormat2(formatFlag) {
1873
+ if (formatFlag !== void 0) {
1874
+ const lower = formatFlag.toLowerCase();
1875
+ if (lower !== "json" && lower !== "tree") {
1876
+ throw new Error(`Unknown format "${formatFlag}". Allowed: json, tree`);
1877
+ }
1878
+ return lower;
1879
+ }
1880
+ return isTTY() ? "tree" : "json";
1881
+ }
1527
1882
 
1528
1883
  // src/instrument/renders.ts
1529
- var MANIFEST_PATH4 = ".reactscope/manifest.json";
1884
+ var MANIFEST_PATH5 = ".reactscope/manifest.json";
1530
1885
  function determineTrigger(event) {
1531
1886
  if (event.forceUpdate) return "force_update";
1532
1887
  if (event.stateChanged) return "state_change";
@@ -1825,26 +2180,26 @@ async function replayInteraction2(page, steps) {
1825
2180
  }
1826
2181
  }
1827
2182
  }
1828
- var _pool = null;
1829
- async function getPool() {
1830
- if (_pool === null) {
1831
- _pool = new BrowserPool({
2183
+ var _pool2 = null;
2184
+ async function getPool2() {
2185
+ if (_pool2 === null) {
2186
+ _pool2 = new BrowserPool({
1832
2187
  size: { browsers: 1, pagesPerBrowser: 2 },
1833
2188
  viewportWidth: 1280,
1834
2189
  viewportHeight: 800
1835
2190
  });
1836
- await _pool.init();
2191
+ await _pool2.init();
1837
2192
  }
1838
- return _pool;
2193
+ return _pool2;
1839
2194
  }
1840
- async function shutdownPool() {
1841
- if (_pool !== null) {
1842
- await _pool.close();
1843
- _pool = null;
2195
+ async function shutdownPool2() {
2196
+ if (_pool2 !== null) {
2197
+ await _pool2.close();
2198
+ _pool2 = null;
1844
2199
  }
1845
2200
  }
1846
2201
  async function analyzeRenders(options) {
1847
- const manifestPath = options.manifestPath ?? MANIFEST_PATH4;
2202
+ const manifestPath = options.manifestPath ?? MANIFEST_PATH5;
1848
2203
  const manifest = loadManifest(manifestPath);
1849
2204
  const descriptor = manifest.components[options.componentName];
1850
2205
  if (descriptor === void 0) {
@@ -1857,7 +2212,7 @@ Available: ${available}`
1857
2212
  const rootDir = process.cwd();
1858
2213
  const filePath = resolve(rootDir, descriptor.filePath);
1859
2214
  const htmlHarness = await buildComponentHarness(filePath, options.componentName, {}, 1280);
1860
- const pool = await getPool();
2215
+ const pool = await getPool2();
1861
2216
  const slot = await pool.acquire();
1862
2217
  const { page } = slot;
1863
2218
  const startMs = performance.now();
@@ -1942,7 +2297,7 @@ function createInstrumentRendersCommand() {
1942
2297
  "--interaction <json>",
1943
2298
  `Interaction sequence JSON, e.g. '[{"action":"click","target":"button"}]'`,
1944
2299
  "[]"
1945
- ).option("--json", "Output as JSON regardless of TTY", false).option("--manifest <path>", "Path to manifest.json", MANIFEST_PATH4).action(
2300
+ ).option("--json", "Output as JSON regardless of TTY", false).option("--manifest <path>", "Path to manifest.json", MANIFEST_PATH5).action(
1946
2301
  async (componentName, opts) => {
1947
2302
  let interaction = [];
1948
2303
  try {
@@ -1965,7 +2320,7 @@ function createInstrumentRendersCommand() {
1965
2320
  interaction,
1966
2321
  manifestPath: opts.manifest
1967
2322
  });
1968
- await shutdownPool();
2323
+ await shutdownPool2();
1969
2324
  if (opts.json || !isTTY()) {
1970
2325
  process.stdout.write(`${JSON.stringify(result, null, 2)}
1971
2326
  `);
@@ -1974,7 +2329,7 @@ function createInstrumentRendersCommand() {
1974
2329
  `);
1975
2330
  }
1976
2331
  } catch (err) {
1977
- await shutdownPool();
2332
+ await shutdownPool2();
1978
2333
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
1979
2334
  `);
1980
2335
  process.exit(1);
@@ -1989,6 +2344,7 @@ function createInstrumentCommand() {
1989
2344
  instrumentCmd.addCommand(createInstrumentRendersCommand());
1990
2345
  instrumentCmd.addCommand(createInstrumentHooksCommand());
1991
2346
  instrumentCmd.addCommand(createInstrumentProfileCommand());
2347
+ instrumentCmd.addCommand(createInstrumentTreeCommand());
1992
2348
  return instrumentCmd;
1993
2349
  }
1994
2350
  async function browserCapture(options) {
@@ -2148,24 +2504,24 @@ async function getCompiledCssForClasses(cwd, classes) {
2148
2504
  }
2149
2505
 
2150
2506
  // src/render-commands.ts
2151
- var MANIFEST_PATH5 = ".reactscope/manifest.json";
2507
+ var MANIFEST_PATH6 = ".reactscope/manifest.json";
2152
2508
  var DEFAULT_OUTPUT_DIR = ".reactscope/renders";
2153
- var _pool2 = null;
2154
- async function getPool2(viewportWidth, viewportHeight) {
2155
- if (_pool2 === null) {
2156
- _pool2 = new BrowserPool({
2509
+ var _pool3 = null;
2510
+ async function getPool3(viewportWidth, viewportHeight) {
2511
+ if (_pool3 === null) {
2512
+ _pool3 = new BrowserPool({
2157
2513
  size: { browsers: 1, pagesPerBrowser: 4 },
2158
2514
  viewportWidth,
2159
2515
  viewportHeight
2160
2516
  });
2161
- await _pool2.init();
2517
+ await _pool3.init();
2162
2518
  }
2163
- return _pool2;
2519
+ return _pool3;
2164
2520
  }
2165
- async function shutdownPool2() {
2166
- if (_pool2 !== null) {
2167
- await _pool2.close();
2168
- _pool2 = null;
2521
+ async function shutdownPool3() {
2522
+ if (_pool3 !== null) {
2523
+ await _pool3.close();
2524
+ _pool3 = null;
2169
2525
  }
2170
2526
  }
2171
2527
  function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
@@ -2176,7 +2532,7 @@ function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
2176
2532
  _satori: satori,
2177
2533
  async renderCell(props, _complexityClass) {
2178
2534
  const startMs = performance.now();
2179
- const pool = await getPool2(viewportWidth, viewportHeight);
2535
+ const pool = await getPool3(viewportWidth, viewportHeight);
2180
2536
  const htmlHarness = await buildComponentHarness(
2181
2537
  filePath,
2182
2538
  componentName,
@@ -2273,7 +2629,7 @@ function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
2273
2629
  };
2274
2630
  }
2275
2631
  function registerRenderSingle(renderCmd) {
2276
- renderCmd.command("component <component>", { isDefault: true }).description("Render a single component to PNG or JSON").option("--props <json>", `Inline props JSON, e.g. '{"variant":"primary"}'`).option("--viewport <WxH>", "Viewport size e.g. 1280x720", "375x812").option("--theme <name>", "Theme name from the token system").option("-o, --output <path>", "Write PNG to file instead of stdout").option("--format <fmt>", "Output format: png or json (default: auto)").option("--manifest <path>", "Path to manifest.json", MANIFEST_PATH5).action(
2632
+ renderCmd.command("component <component>", { isDefault: true }).description("Render a single component to PNG or JSON").option("--props <json>", `Inline props JSON, e.g. '{"variant":"primary"}'`).option("--viewport <WxH>", "Viewport size e.g. 1280x720", "375x812").option("--theme <name>", "Theme name from the token system").option("-o, --output <path>", "Write PNG to file instead of stdout").option("--format <fmt>", "Output format: png or json (default: auto)").option("--manifest <path>", "Path to manifest.json", MANIFEST_PATH6).action(
2277
2633
  async (componentName, opts) => {
2278
2634
  try {
2279
2635
  const manifest = loadManifest(opts.manifest);
@@ -2312,7 +2668,7 @@ Available: ${available}`
2312
2668
  }
2313
2669
  }
2314
2670
  );
2315
- await shutdownPool2();
2671
+ await shutdownPool3();
2316
2672
  if (outcome.crashed) {
2317
2673
  process.stderr.write(`\u2717 Render failed: ${outcome.error.message}
2318
2674
  `);
@@ -2360,7 +2716,7 @@ Available: ${available}`
2360
2716
  );
2361
2717
  }
2362
2718
  } catch (err) {
2363
- await shutdownPool2();
2719
+ await shutdownPool3();
2364
2720
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2365
2721
  `);
2366
2722
  process.exit(1);
@@ -2372,7 +2728,7 @@ function registerRenderMatrix(renderCmd) {
2372
2728
  renderCmd.command("matrix <component>").description("Render a component across a matrix of prop axes").option("--axes <spec>", "Axis definitions e.g. 'variant:primary,secondary size:sm,md,lg'").option(
2373
2729
  "--contexts <ids>",
2374
2730
  "Composition context IDs, comma-separated (e.g. centered,rtl,sidebar)"
2375
- ).option("--stress <ids>", "Stress preset IDs, comma-separated (e.g. text.long,text.unicode)").option("--sprite <path>", "Write sprite sheet PNG to file").option("--format <fmt>", "Output format: json|png|html|csv (default: auto)").option("--concurrency <n>", "Max parallel renders", "8").option("--manifest <path>", "Path to manifest.json", MANIFEST_PATH5).action(
2731
+ ).option("--stress <ids>", "Stress preset IDs, comma-separated (e.g. text.long,text.unicode)").option("--sprite <path>", "Write sprite sheet PNG to file").option("--format <fmt>", "Output format: json|png|html|csv (default: auto)").option("--concurrency <n>", "Max parallel renders", "8").option("--manifest <path>", "Path to manifest.json", MANIFEST_PATH6).action(
2376
2732
  async (componentName, opts) => {
2377
2733
  try {
2378
2734
  const manifest = loadManifest(opts.manifest);
@@ -2445,7 +2801,7 @@ Available: ${available}`
2445
2801
  concurrency
2446
2802
  });
2447
2803
  const result = await matrix.render();
2448
- await shutdownPool2();
2804
+ await shutdownPool3();
2449
2805
  process.stderr.write(
2450
2806
  `Done. ${result.stats.totalCells} cells, avg ${result.stats.avgRenderTimeMs.toFixed(1)}ms
2451
2807
  `
@@ -2490,7 +2846,7 @@ Available: ${available}`
2490
2846
  process.stdout.write(formatMatrixCsv(componentName, result));
2491
2847
  }
2492
2848
  } catch (err) {
2493
- await shutdownPool2();
2849
+ await shutdownPool3();
2494
2850
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2495
2851
  `);
2496
2852
  process.exit(1);
@@ -2499,7 +2855,7 @@ Available: ${available}`
2499
2855
  );
2500
2856
  }
2501
2857
  function registerRenderAll(renderCmd) {
2502
- renderCmd.command("all").description("Render all components from the manifest").option("--concurrency <n>", "Max parallel renders", "4").option("--output-dir <dir>", "Output directory for renders", DEFAULT_OUTPUT_DIR).option("--manifest <path>", "Path to manifest.json", MANIFEST_PATH5).option("--format <fmt>", "Output format: json|png (default: png)", "png").action(
2858
+ renderCmd.command("all").description("Render all components from the manifest").option("--concurrency <n>", "Max parallel renders", "4").option("--output-dir <dir>", "Output directory for renders", DEFAULT_OUTPUT_DIR).option("--manifest <path>", "Path to manifest.json", MANIFEST_PATH6).option("--format <fmt>", "Output format: json|png (default: png)", "png").action(
2503
2859
  async (opts) => {
2504
2860
  try {
2505
2861
  const manifest = loadManifest(opts.manifest);
@@ -2587,13 +2943,13 @@ function registerRenderAll(renderCmd) {
2587
2943
  workers.push(worker());
2588
2944
  }
2589
2945
  await Promise.all(workers);
2590
- await shutdownPool2();
2946
+ await shutdownPool3();
2591
2947
  process.stderr.write("\n");
2592
2948
  const summary = formatSummaryText(results, outputDir);
2593
2949
  process.stderr.write(`${summary}
2594
2950
  `);
2595
2951
  } catch (err) {
2596
- await shutdownPool2();
2952
+ await shutdownPool3();
2597
2953
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2598
2954
  `);
2599
2955
  process.exit(1);
@@ -2635,26 +2991,26 @@ function createRenderCommand() {
2635
2991
  return renderCmd;
2636
2992
  }
2637
2993
  var DEFAULT_BASELINE_DIR = ".reactscope/baseline";
2638
- var _pool3 = null;
2639
- async function getPool3(viewportWidth, viewportHeight) {
2640
- if (_pool3 === null) {
2641
- _pool3 = new BrowserPool({
2994
+ var _pool4 = null;
2995
+ async function getPool4(viewportWidth, viewportHeight) {
2996
+ if (_pool4 === null) {
2997
+ _pool4 = new BrowserPool({
2642
2998
  size: { browsers: 1, pagesPerBrowser: 4 },
2643
2999
  viewportWidth,
2644
3000
  viewportHeight
2645
3001
  });
2646
- await _pool3.init();
3002
+ await _pool4.init();
2647
3003
  }
2648
- return _pool3;
3004
+ return _pool4;
2649
3005
  }
2650
- async function shutdownPool3() {
2651
- if (_pool3 !== null) {
2652
- await _pool3.close();
2653
- _pool3 = null;
3006
+ async function shutdownPool4() {
3007
+ if (_pool4 !== null) {
3008
+ await _pool4.close();
3009
+ _pool4 = null;
2654
3010
  }
2655
3011
  }
2656
3012
  async function renderComponent(filePath, componentName, props, viewportWidth, viewportHeight) {
2657
- const pool = await getPool3(viewportWidth, viewportHeight);
3013
+ const pool = await getPool4(viewportWidth, viewportHeight);
2658
3014
  const htmlHarness = await buildComponentHarness(filePath, componentName, props, viewportWidth);
2659
3015
  const slot = await pool.acquire();
2660
3016
  const { page } = slot;
@@ -2904,7 +3260,7 @@ async function runBaseline(options = {}) {
2904
3260
  workers.push(worker());
2905
3261
  }
2906
3262
  await Promise.all(workers);
2907
- await shutdownPool3();
3263
+ await shutdownPool4();
2908
3264
  if (isTTY()) {
2909
3265
  process.stderr.write("\n");
2910
3266
  }
@@ -2955,10 +3311,10 @@ function registerBaselineSubCommand(reportCmd) {
2955
3311
  }
2956
3312
 
2957
3313
  // src/tree-formatter.ts
2958
- var BRANCH = "\u251C\u2500\u2500 ";
2959
- var LAST_BRANCH = "\u2514\u2500\u2500 ";
2960
- var VERTICAL = "\u2502 ";
2961
- var EMPTY = " ";
3314
+ var BRANCH2 = "\u251C\u2500\u2500 ";
3315
+ var LAST_BRANCH2 = "\u2514\u2500\u2500 ";
3316
+ var VERTICAL2 = "\u2502 ";
3317
+ var EMPTY2 = " ";
2962
3318
  function buildLabel(node, options) {
2963
3319
  const parts = [node.name];
2964
3320
  if (node.type === "memo") {
@@ -3005,19 +3361,19 @@ function renderNode(node, prefix, isLast, depth, options, lines) {
3005
3361
  }
3006
3362
  return;
3007
3363
  }
3008
- const connector = isLast ? LAST_BRANCH : BRANCH;
3364
+ const connector = isLast ? LAST_BRANCH2 : BRANCH2;
3009
3365
  const label = buildLabel(node, options);
3010
3366
  lines.push(`${prefix}${connector}${label}`);
3011
3367
  if (options.maxDepth !== void 0 && depth >= options.maxDepth) {
3012
3368
  const childCount = countVisibleDescendants(node, options);
3013
3369
  if (childCount > 0) {
3014
- const nextPrefix2 = prefix + (isLast ? EMPTY : VERTICAL);
3015
- lines.push(`${nextPrefix2}${LAST_BRANCH}\u2026 (${childCount} more)`);
3370
+ const nextPrefix2 = prefix + (isLast ? EMPTY2 : VERTICAL2);
3371
+ lines.push(`${nextPrefix2}${LAST_BRANCH2}\u2026 (${childCount} more)`);
3016
3372
  }
3017
3373
  return;
3018
3374
  }
3019
3375
  const visibleChildren = getVisibleChildren(node, options);
3020
- const nextPrefix = prefix + (isLast ? EMPTY : VERTICAL);
3376
+ const nextPrefix = prefix + (isLast ? EMPTY2 : VERTICAL2);
3021
3377
  for (let i = 0; i < visibleChildren.length; i++) {
3022
3378
  const child = visibleChildren[i];
3023
3379
  if (child !== void 0) {
@@ -3059,7 +3415,7 @@ function formatTree(root, options = {}) {
3059
3415
  if (options.maxDepth === 0) {
3060
3416
  const childCount = countVisibleDescendants(root, options);
3061
3417
  if (childCount > 0) {
3062
- lines.push(`${LAST_BRANCH}\u2026 (${childCount} more)`);
3418
+ lines.push(`${LAST_BRANCH2}\u2026 (${childCount} more)`);
3063
3419
  }
3064
3420
  } else {
3065
3421
  const visibleChildren = getVisibleChildren(root, options);