@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.cjs CHANGED
@@ -228,9 +228,9 @@ function createRL() {
228
228
  });
229
229
  }
230
230
  async function ask(rl, question) {
231
- return new Promise((resolve10) => {
231
+ return new Promise((resolve11) => {
232
232
  rl.question(question, (answer) => {
233
- resolve10(answer.trim());
233
+ resolve11(answer.trim());
234
234
  });
235
235
  });
236
236
  }
@@ -1547,9 +1547,364 @@ Available: ${available}`
1547
1547
  );
1548
1548
  return cmd;
1549
1549
  }
1550
+ var MANIFEST_PATH4 = ".reactscope/manifest.json";
1551
+ var DEFAULT_VIEWPORT_WIDTH = 375;
1552
+ var DEFAULT_VIEWPORT_HEIGHT = 812;
1553
+ var _pool = null;
1554
+ async function getPool() {
1555
+ if (_pool === null) {
1556
+ _pool = new render.BrowserPool({
1557
+ size: { browsers: 1, pagesPerBrowser: 1 },
1558
+ viewportWidth: DEFAULT_VIEWPORT_WIDTH,
1559
+ viewportHeight: DEFAULT_VIEWPORT_HEIGHT
1560
+ });
1561
+ await _pool.init();
1562
+ }
1563
+ return _pool;
1564
+ }
1565
+ async function shutdownPool() {
1566
+ if (_pool !== null) {
1567
+ await _pool.close();
1568
+ _pool = null;
1569
+ }
1570
+ }
1571
+ function mapNodeType(node) {
1572
+ if (node.type === "forward_ref") return "forwardRef";
1573
+ if (node.type === "host") return "host";
1574
+ const name = node.name;
1575
+ if (name.endsWith(".Provider") || name === "Provider") return "context.provider";
1576
+ if (name.endsWith(".Consumer") || name === "Consumer") return "context.consumer";
1577
+ return node.type;
1578
+ }
1579
+ function flattenSerializedValue(sv) {
1580
+ if (sv === null || sv === void 0) return null;
1581
+ const v = sv;
1582
+ switch (v.type) {
1583
+ case "null":
1584
+ case "undefined":
1585
+ return null;
1586
+ case "string":
1587
+ case "number":
1588
+ case "boolean":
1589
+ return v.value;
1590
+ case "object": {
1591
+ if (!Array.isArray(v.entries)) return {};
1592
+ const result = {};
1593
+ for (const entry of v.entries) {
1594
+ result[entry.key] = flattenSerializedValue(entry.value);
1595
+ }
1596
+ return result;
1597
+ }
1598
+ case "array": {
1599
+ if (!Array.isArray(v.items)) return [];
1600
+ return v.items.map(flattenSerializedValue);
1601
+ }
1602
+ case "function":
1603
+ return "[Function]";
1604
+ case "symbol":
1605
+ return `[Symbol: ${v.description ?? ""}]`;
1606
+ case "circular":
1607
+ return "[Circular]";
1608
+ case "truncated":
1609
+ return `[Truncated: ${v.preview ?? ""}]`;
1610
+ default:
1611
+ return v.preview ?? null;
1612
+ }
1613
+ }
1614
+ function flattenHookState(hooks) {
1615
+ const result = {};
1616
+ for (let i = 0; i < hooks.length; i++) {
1617
+ const hook = hooks[i];
1618
+ if (hook === void 0) continue;
1619
+ const key = hook.name !== null && hook.name !== void 0 ? hook.name : `${hook.type}[${i}]`;
1620
+ result[key] = flattenSerializedValue(hook.value);
1621
+ }
1622
+ return result;
1623
+ }
1624
+ function extractContextNames(contexts) {
1625
+ const names = contexts.map((c) => c.contextName ?? "Unknown").filter((name, idx, arr) => arr.indexOf(name) === idx);
1626
+ return names;
1627
+ }
1628
+ function anyContextChanged(contexts) {
1629
+ return contexts.some((c) => c.didTriggerRender);
1630
+ }
1631
+ function convertToInstrumentNode(node, depth = 0) {
1632
+ const contexts = extractContextNames(node.context);
1633
+ const contextChanged = anyContextChanged(node.context);
1634
+ const state = flattenHookState(node.state);
1635
+ const propsFlat = flattenSerializedValue(node.props);
1636
+ const props = propsFlat !== null && typeof propsFlat === "object" && !Array.isArray(propsFlat) ? propsFlat : {};
1637
+ return {
1638
+ component: node.name,
1639
+ type: mapNodeType(node),
1640
+ renderCount: node.renderCount,
1641
+ lastRenderDuration: node.renderDuration,
1642
+ memoized: node.type === "memo",
1643
+ // memoSkipped requires tracking bail-outs across commits — not available from
1644
+ // a single-shot capture. Defaulted to 0.
1645
+ memoSkipped: 0,
1646
+ props,
1647
+ // propsChanged is not tracked in a single-shot capture — would need a diff
1648
+ // between two renders. Defaulted to false.
1649
+ propsChanged: false,
1650
+ state,
1651
+ stateChanged: false,
1652
+ contextChanged,
1653
+ contexts,
1654
+ depth,
1655
+ children: node.children.map((child) => convertToInstrumentNode(child, depth + 1))
1656
+ };
1657
+ }
1658
+ function filterByContext(node, contextName) {
1659
+ const filteredChildren = node.children.map((child) => filterByContext(child, contextName)).filter((c) => c !== null);
1660
+ const selfMatches = node.contexts.some((c) => c.toLowerCase() === contextName.toLowerCase());
1661
+ if (!selfMatches && filteredChildren.length === 0) return null;
1662
+ return { ...node, children: filteredChildren };
1663
+ }
1664
+ function filterWastedRenders(node) {
1665
+ const filteredChildren = node.children.map((child) => filterWastedRenders(child)).filter((c) => c !== null);
1666
+ const isWasted = !node.propsChanged && !node.stateChanged && !node.contextChanged && !node.memoized && node.renderCount > 1;
1667
+ if (!isWasted && filteredChildren.length === 0) return null;
1668
+ return { ...node, children: filteredChildren };
1669
+ }
1670
+ function sortTree(node, sortBy) {
1671
+ const sortedChildren = node.children.map((child) => sortTree(child, sortBy)).sort((a, b) => {
1672
+ if (sortBy === "renderCount") return b.renderCount - a.renderCount;
1673
+ return a.depth - b.depth;
1674
+ });
1675
+ return { ...node, children: sortedChildren };
1676
+ }
1677
+ function annotateProviderDepth(node, providerDepth = 0) {
1678
+ const isProvider = node.type === "context.provider";
1679
+ const childProviderDepth = isProvider ? providerDepth + 1 : providerDepth;
1680
+ return {
1681
+ ...node,
1682
+ _providerDepth: providerDepth,
1683
+ children: node.children.map((child) => annotateProviderDepth(child, childProviderDepth))
1684
+ };
1685
+ }
1686
+ function limitNodes(root, limit) {
1687
+ let remaining = limit;
1688
+ const clip = (node) => {
1689
+ if (remaining <= 0) return null;
1690
+ remaining--;
1691
+ const clippedChildren = [];
1692
+ for (const child of node.children) {
1693
+ const clipped = clip(child);
1694
+ if (clipped !== null) clippedChildren.push(clipped);
1695
+ }
1696
+ return { ...node, children: clippedChildren };
1697
+ };
1698
+ return clip(root) ?? root;
1699
+ }
1700
+ var BRANCH = "\u251C\u2500\u2500 ";
1701
+ var LAST_BRANCH = "\u2514\u2500\u2500 ";
1702
+ var VERTICAL = "\u2502 ";
1703
+ var EMPTY = " ";
1704
+ function buildTTYLabel(node, showProviderDepth) {
1705
+ const parts = [node.component];
1706
+ switch (node.type) {
1707
+ case "memo":
1708
+ parts.push("[memo]");
1709
+ break;
1710
+ case "forwardRef":
1711
+ parts.push("[forwardRef]");
1712
+ break;
1713
+ case "class":
1714
+ parts.push("[class]");
1715
+ break;
1716
+ case "context.provider":
1717
+ parts.push("[provider]");
1718
+ break;
1719
+ case "context.consumer":
1720
+ parts.push("[consumer]");
1721
+ break;
1722
+ }
1723
+ if (node.renderCount > 0) {
1724
+ const durationStr = node.lastRenderDuration > 0 ? ` ${node.lastRenderDuration.toFixed(2)}ms` : "";
1725
+ parts.push(`(renders:${node.renderCount}${durationStr})`);
1726
+ }
1727
+ if (node.contexts.length > 0) {
1728
+ parts.push(`[ctx:${node.contexts.join(",")}]`);
1729
+ }
1730
+ if (showProviderDepth) {
1731
+ const pd = node._providerDepth;
1732
+ if (pd !== void 0 && pd > 0) {
1733
+ parts.push(`[pd:${pd}]`);
1734
+ }
1735
+ }
1736
+ return parts.join(" ");
1737
+ }
1738
+ function renderTTYNode(node, prefix, isLast, showProviderDepth, lines) {
1739
+ if (node.type === "host") {
1740
+ for (let i = 0; i < node.children.length; i++) {
1741
+ const child = node.children[i];
1742
+ if (child !== void 0) {
1743
+ renderTTYNode(child, prefix, i === node.children.length - 1, showProviderDepth, lines);
1744
+ }
1745
+ }
1746
+ return;
1747
+ }
1748
+ const connector = isLast ? LAST_BRANCH : BRANCH;
1749
+ lines.push(`${prefix}${connector}${buildTTYLabel(node, showProviderDepth)}`);
1750
+ const nextPrefix = prefix + (isLast ? EMPTY : VERTICAL);
1751
+ for (let i = 0; i < node.children.length; i++) {
1752
+ const child = node.children[i];
1753
+ if (child !== void 0) {
1754
+ renderTTYNode(child, nextPrefix, i === node.children.length - 1, showProviderDepth, lines);
1755
+ }
1756
+ }
1757
+ }
1758
+ function formatInstrumentTree(root, showProviderDepth = false) {
1759
+ const lines = [];
1760
+ if (root.type !== "host") {
1761
+ lines.push(buildTTYLabel(root, showProviderDepth));
1762
+ for (let i = 0; i < root.children.length; i++) {
1763
+ const child = root.children[i];
1764
+ if (child !== void 0) {
1765
+ renderTTYNode(child, "", i === root.children.length - 1, showProviderDepth, lines);
1766
+ }
1767
+ }
1768
+ } else {
1769
+ for (let i = 0; i < root.children.length; i++) {
1770
+ const child = root.children[i];
1771
+ if (child !== void 0) {
1772
+ renderTTYNode(child, "", i === root.children.length - 1, showProviderDepth, lines);
1773
+ }
1774
+ }
1775
+ }
1776
+ return lines.join("\n");
1777
+ }
1778
+ async function runInstrumentTree(options) {
1779
+ const { componentName, filePath } = options;
1780
+ const pool = await getPool();
1781
+ const slot = await pool.acquire();
1782
+ const { page } = slot;
1783
+ try {
1784
+ await page.addInitScript({ content: playwright.getBrowserEntryScript() });
1785
+ const htmlHarness = await buildComponentHarness(
1786
+ filePath,
1787
+ componentName,
1788
+ {},
1789
+ DEFAULT_VIEWPORT_WIDTH
1790
+ );
1791
+ await page.setContent(htmlHarness, { waitUntil: "load" });
1792
+ await page.waitForFunction(
1793
+ () => {
1794
+ const w = window;
1795
+ return w.__SCOPE_RENDER_COMPLETE__ === true;
1796
+ },
1797
+ { timeout: 15e3 }
1798
+ );
1799
+ const renderError = await page.evaluate(
1800
+ () => window.__SCOPE_RENDER_ERROR__ ?? null
1801
+ );
1802
+ if (renderError !== null) {
1803
+ throw new Error(`Component render error: ${renderError}`);
1804
+ }
1805
+ const captureJson = await page.evaluate(async () => {
1806
+ const w = window;
1807
+ if (typeof w.__SCOPE_CAPTURE_JSON__ !== "function") {
1808
+ throw new Error("__SCOPE_CAPTURE_JSON__ not available \u2014 Scope runtime not injected");
1809
+ }
1810
+ return w.__SCOPE_CAPTURE_JSON__({ lightweight: false });
1811
+ });
1812
+ const captureResult = JSON.parse(captureJson);
1813
+ const componentTree = captureResult.tree;
1814
+ if (componentTree === void 0 || componentTree === null) {
1815
+ throw new Error(`No component tree found for "${componentName}"`);
1816
+ }
1817
+ let instrumentRoot = convertToInstrumentNode(componentTree, 0);
1818
+ if (options.usesContext !== void 0) {
1819
+ const filtered = filterByContext(instrumentRoot, options.usesContext);
1820
+ instrumentRoot = filtered !== null ? filtered : { ...instrumentRoot, children: [] };
1821
+ }
1822
+ if (options.wastedRenders === true) {
1823
+ const filtered = filterWastedRenders(instrumentRoot);
1824
+ instrumentRoot = filtered !== null ? filtered : { ...instrumentRoot, children: [] };
1825
+ }
1826
+ if (options.sortBy !== void 0) {
1827
+ instrumentRoot = sortTree(instrumentRoot, options.sortBy);
1828
+ }
1829
+ if (options.providerDepth === true) {
1830
+ instrumentRoot = annotateProviderDepth(instrumentRoot, 0);
1831
+ }
1832
+ if (options.limit !== void 0 && options.limit > 0) {
1833
+ instrumentRoot = limitNodes(instrumentRoot, options.limit);
1834
+ }
1835
+ return instrumentRoot;
1836
+ } finally {
1837
+ pool.release(slot);
1838
+ }
1839
+ }
1840
+ function createInstrumentTreeCommand() {
1841
+ return new commander.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(
1842
+ "--wasted-renders",
1843
+ "Filter to components with wasted renders (no prop/state/context changes, not memoized)",
1844
+ false
1845
+ ).option("--format <fmt>", "Output format: json | tree (default: auto)").option("--manifest <path>", "Path to manifest.json", MANIFEST_PATH4).action(async (componentName, opts) => {
1846
+ try {
1847
+ const manifest = loadManifest(opts.manifest);
1848
+ const descriptor = manifest.components[componentName];
1849
+ if (descriptor === void 0) {
1850
+ const available = Object.keys(manifest.components).slice(0, 5).join(", ");
1851
+ throw new Error(
1852
+ `Component "${componentName}" not found in manifest.
1853
+ Available: ${available}`
1854
+ );
1855
+ }
1856
+ if (opts.sortBy !== void 0) {
1857
+ const allowed = ["renderCount", "depth"];
1858
+ if (!allowed.includes(opts.sortBy)) {
1859
+ throw new Error(
1860
+ `Unknown --sort-by value "${opts.sortBy}". Allowed: ${allowed.join(", ")}`
1861
+ );
1862
+ }
1863
+ }
1864
+ const rootDir = process.cwd();
1865
+ const filePath = path.resolve(rootDir, descriptor.filePath);
1866
+ process.stderr.write(`Instrumenting ${componentName}\u2026
1867
+ `);
1868
+ const instrumentRoot = await runInstrumentTree({
1869
+ componentName,
1870
+ filePath,
1871
+ sortBy: opts.sortBy,
1872
+ limit: opts.limit !== void 0 ? Math.max(1, parseInt(opts.limit, 10)) : void 0,
1873
+ usesContext: opts.usesContext,
1874
+ providerDepth: opts.providerDepth,
1875
+ wastedRenders: opts.wastedRenders
1876
+ });
1877
+ await shutdownPool();
1878
+ const fmt = resolveFormat2(opts.format);
1879
+ if (fmt === "json") {
1880
+ process.stdout.write(`${JSON.stringify(instrumentRoot, null, 2)}
1881
+ `);
1882
+ } else {
1883
+ const tree = formatInstrumentTree(instrumentRoot, opts.providerDepth ?? false);
1884
+ process.stdout.write(`${tree}
1885
+ `);
1886
+ }
1887
+ } catch (err) {
1888
+ await shutdownPool();
1889
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
1890
+ `);
1891
+ process.exit(1);
1892
+ }
1893
+ });
1894
+ }
1895
+ function resolveFormat2(formatFlag) {
1896
+ if (formatFlag !== void 0) {
1897
+ const lower = formatFlag.toLowerCase();
1898
+ if (lower !== "json" && lower !== "tree") {
1899
+ throw new Error(`Unknown format "${formatFlag}". Allowed: json, tree`);
1900
+ }
1901
+ return lower;
1902
+ }
1903
+ return isTTY() ? "tree" : "json";
1904
+ }
1550
1905
 
1551
1906
  // src/instrument/renders.ts
1552
- var MANIFEST_PATH4 = ".reactscope/manifest.json";
1907
+ var MANIFEST_PATH5 = ".reactscope/manifest.json";
1553
1908
  function determineTrigger(event) {
1554
1909
  if (event.forceUpdate) return "force_update";
1555
1910
  if (event.stateChanged) return "state_change";
@@ -1848,26 +2203,26 @@ async function replayInteraction2(page, steps) {
1848
2203
  }
1849
2204
  }
1850
2205
  }
1851
- var _pool = null;
1852
- async function getPool() {
1853
- if (_pool === null) {
1854
- _pool = new render.BrowserPool({
2206
+ var _pool2 = null;
2207
+ async function getPool2() {
2208
+ if (_pool2 === null) {
2209
+ _pool2 = new render.BrowserPool({
1855
2210
  size: { browsers: 1, pagesPerBrowser: 2 },
1856
2211
  viewportWidth: 1280,
1857
2212
  viewportHeight: 800
1858
2213
  });
1859
- await _pool.init();
2214
+ await _pool2.init();
1860
2215
  }
1861
- return _pool;
2216
+ return _pool2;
1862
2217
  }
1863
- async function shutdownPool() {
1864
- if (_pool !== null) {
1865
- await _pool.close();
1866
- _pool = null;
2218
+ async function shutdownPool2() {
2219
+ if (_pool2 !== null) {
2220
+ await _pool2.close();
2221
+ _pool2 = null;
1867
2222
  }
1868
2223
  }
1869
2224
  async function analyzeRenders(options) {
1870
- const manifestPath = options.manifestPath ?? MANIFEST_PATH4;
2225
+ const manifestPath = options.manifestPath ?? MANIFEST_PATH5;
1871
2226
  const manifest = loadManifest(manifestPath);
1872
2227
  const descriptor = manifest.components[options.componentName];
1873
2228
  if (descriptor === void 0) {
@@ -1880,7 +2235,7 @@ Available: ${available}`
1880
2235
  const rootDir = process.cwd();
1881
2236
  const filePath = path.resolve(rootDir, descriptor.filePath);
1882
2237
  const htmlHarness = await buildComponentHarness(filePath, options.componentName, {}, 1280);
1883
- const pool = await getPool();
2238
+ const pool = await getPool2();
1884
2239
  const slot = await pool.acquire();
1885
2240
  const { page } = slot;
1886
2241
  const startMs = performance.now();
@@ -1965,7 +2320,7 @@ function createInstrumentRendersCommand() {
1965
2320
  "--interaction <json>",
1966
2321
  `Interaction sequence JSON, e.g. '[{"action":"click","target":"button"}]'`,
1967
2322
  "[]"
1968
- ).option("--json", "Output as JSON regardless of TTY", false).option("--manifest <path>", "Path to manifest.json", MANIFEST_PATH4).action(
2323
+ ).option("--json", "Output as JSON regardless of TTY", false).option("--manifest <path>", "Path to manifest.json", MANIFEST_PATH5).action(
1969
2324
  async (componentName, opts) => {
1970
2325
  let interaction = [];
1971
2326
  try {
@@ -1988,7 +2343,7 @@ function createInstrumentRendersCommand() {
1988
2343
  interaction,
1989
2344
  manifestPath: opts.manifest
1990
2345
  });
1991
- await shutdownPool();
2346
+ await shutdownPool2();
1992
2347
  if (opts.json || !isTTY()) {
1993
2348
  process.stdout.write(`${JSON.stringify(result, null, 2)}
1994
2349
  `);
@@ -1997,7 +2352,7 @@ function createInstrumentRendersCommand() {
1997
2352
  `);
1998
2353
  }
1999
2354
  } catch (err) {
2000
- await shutdownPool();
2355
+ await shutdownPool2();
2001
2356
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2002
2357
  `);
2003
2358
  process.exit(1);
@@ -2012,6 +2367,7 @@ function createInstrumentCommand() {
2012
2367
  instrumentCmd.addCommand(createInstrumentRendersCommand());
2013
2368
  instrumentCmd.addCommand(createInstrumentHooksCommand());
2014
2369
  instrumentCmd.addCommand(createInstrumentProfileCommand());
2370
+ instrumentCmd.addCommand(createInstrumentTreeCommand());
2015
2371
  return instrumentCmd;
2016
2372
  }
2017
2373
  async function browserCapture(options) {
@@ -2171,24 +2527,24 @@ async function getCompiledCssForClasses(cwd, classes) {
2171
2527
  }
2172
2528
 
2173
2529
  // src/render-commands.ts
2174
- var MANIFEST_PATH5 = ".reactscope/manifest.json";
2530
+ var MANIFEST_PATH6 = ".reactscope/manifest.json";
2175
2531
  var DEFAULT_OUTPUT_DIR = ".reactscope/renders";
2176
- var _pool2 = null;
2177
- async function getPool2(viewportWidth, viewportHeight) {
2178
- if (_pool2 === null) {
2179
- _pool2 = new render.BrowserPool({
2532
+ var _pool3 = null;
2533
+ async function getPool3(viewportWidth, viewportHeight) {
2534
+ if (_pool3 === null) {
2535
+ _pool3 = new render.BrowserPool({
2180
2536
  size: { browsers: 1, pagesPerBrowser: 4 },
2181
2537
  viewportWidth,
2182
2538
  viewportHeight
2183
2539
  });
2184
- await _pool2.init();
2540
+ await _pool3.init();
2185
2541
  }
2186
- return _pool2;
2542
+ return _pool3;
2187
2543
  }
2188
- async function shutdownPool2() {
2189
- if (_pool2 !== null) {
2190
- await _pool2.close();
2191
- _pool2 = null;
2544
+ async function shutdownPool3() {
2545
+ if (_pool3 !== null) {
2546
+ await _pool3.close();
2547
+ _pool3 = null;
2192
2548
  }
2193
2549
  }
2194
2550
  function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
@@ -2199,7 +2555,7 @@ function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
2199
2555
  _satori: satori,
2200
2556
  async renderCell(props, _complexityClass) {
2201
2557
  const startMs = performance.now();
2202
- const pool = await getPool2(viewportWidth, viewportHeight);
2558
+ const pool = await getPool3(viewportWidth, viewportHeight);
2203
2559
  const htmlHarness = await buildComponentHarness(
2204
2560
  filePath,
2205
2561
  componentName,
@@ -2296,7 +2652,7 @@ function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
2296
2652
  };
2297
2653
  }
2298
2654
  function registerRenderSingle(renderCmd) {
2299
- 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(
2655
+ 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(
2300
2656
  async (componentName, opts) => {
2301
2657
  try {
2302
2658
  const manifest = loadManifest(opts.manifest);
@@ -2335,7 +2691,7 @@ Available: ${available}`
2335
2691
  }
2336
2692
  }
2337
2693
  );
2338
- await shutdownPool2();
2694
+ await shutdownPool3();
2339
2695
  if (outcome.crashed) {
2340
2696
  process.stderr.write(`\u2717 Render failed: ${outcome.error.message}
2341
2697
  `);
@@ -2383,7 +2739,7 @@ Available: ${available}`
2383
2739
  );
2384
2740
  }
2385
2741
  } catch (err) {
2386
- await shutdownPool2();
2742
+ await shutdownPool3();
2387
2743
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2388
2744
  `);
2389
2745
  process.exit(1);
@@ -2395,7 +2751,7 @@ function registerRenderMatrix(renderCmd) {
2395
2751
  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(
2396
2752
  "--contexts <ids>",
2397
2753
  "Composition context IDs, comma-separated (e.g. centered,rtl,sidebar)"
2398
- ).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(
2754
+ ).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(
2399
2755
  async (componentName, opts) => {
2400
2756
  try {
2401
2757
  const manifest = loadManifest(opts.manifest);
@@ -2468,7 +2824,7 @@ Available: ${available}`
2468
2824
  concurrency
2469
2825
  });
2470
2826
  const result = await matrix.render();
2471
- await shutdownPool2();
2827
+ await shutdownPool3();
2472
2828
  process.stderr.write(
2473
2829
  `Done. ${result.stats.totalCells} cells, avg ${result.stats.avgRenderTimeMs.toFixed(1)}ms
2474
2830
  `
@@ -2513,7 +2869,7 @@ Available: ${available}`
2513
2869
  process.stdout.write(formatMatrixCsv(componentName, result));
2514
2870
  }
2515
2871
  } catch (err) {
2516
- await shutdownPool2();
2872
+ await shutdownPool3();
2517
2873
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2518
2874
  `);
2519
2875
  process.exit(1);
@@ -2522,7 +2878,7 @@ Available: ${available}`
2522
2878
  );
2523
2879
  }
2524
2880
  function registerRenderAll(renderCmd) {
2525
- 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(
2881
+ 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(
2526
2882
  async (opts) => {
2527
2883
  try {
2528
2884
  const manifest = loadManifest(opts.manifest);
@@ -2610,13 +2966,13 @@ function registerRenderAll(renderCmd) {
2610
2966
  workers.push(worker());
2611
2967
  }
2612
2968
  await Promise.all(workers);
2613
- await shutdownPool2();
2969
+ await shutdownPool3();
2614
2970
  process.stderr.write("\n");
2615
2971
  const summary = formatSummaryText(results, outputDir);
2616
2972
  process.stderr.write(`${summary}
2617
2973
  `);
2618
2974
  } catch (err) {
2619
- await shutdownPool2();
2975
+ await shutdownPool3();
2620
2976
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2621
2977
  `);
2622
2978
  process.exit(1);
@@ -2658,26 +3014,26 @@ function createRenderCommand() {
2658
3014
  return renderCmd;
2659
3015
  }
2660
3016
  var DEFAULT_BASELINE_DIR = ".reactscope/baseline";
2661
- var _pool3 = null;
2662
- async function getPool3(viewportWidth, viewportHeight) {
2663
- if (_pool3 === null) {
2664
- _pool3 = new render.BrowserPool({
3017
+ var _pool4 = null;
3018
+ async function getPool4(viewportWidth, viewportHeight) {
3019
+ if (_pool4 === null) {
3020
+ _pool4 = new render.BrowserPool({
2665
3021
  size: { browsers: 1, pagesPerBrowser: 4 },
2666
3022
  viewportWidth,
2667
3023
  viewportHeight
2668
3024
  });
2669
- await _pool3.init();
3025
+ await _pool4.init();
2670
3026
  }
2671
- return _pool3;
3027
+ return _pool4;
2672
3028
  }
2673
- async function shutdownPool3() {
2674
- if (_pool3 !== null) {
2675
- await _pool3.close();
2676
- _pool3 = null;
3029
+ async function shutdownPool4() {
3030
+ if (_pool4 !== null) {
3031
+ await _pool4.close();
3032
+ _pool4 = null;
2677
3033
  }
2678
3034
  }
2679
3035
  async function renderComponent(filePath, componentName, props, viewportWidth, viewportHeight) {
2680
- const pool = await getPool3(viewportWidth, viewportHeight);
3036
+ const pool = await getPool4(viewportWidth, viewportHeight);
2681
3037
  const htmlHarness = await buildComponentHarness(filePath, componentName, props, viewportWidth);
2682
3038
  const slot = await pool.acquire();
2683
3039
  const { page } = slot;
@@ -2927,7 +3283,7 @@ async function runBaseline(options = {}) {
2927
3283
  workers.push(worker());
2928
3284
  }
2929
3285
  await Promise.all(workers);
2930
- await shutdownPool3();
3286
+ await shutdownPool4();
2931
3287
  if (isTTY()) {
2932
3288
  process.stderr.write("\n");
2933
3289
  }
@@ -2978,10 +3334,10 @@ function registerBaselineSubCommand(reportCmd) {
2978
3334
  }
2979
3335
 
2980
3336
  // src/tree-formatter.ts
2981
- var BRANCH = "\u251C\u2500\u2500 ";
2982
- var LAST_BRANCH = "\u2514\u2500\u2500 ";
2983
- var VERTICAL = "\u2502 ";
2984
- var EMPTY = " ";
3337
+ var BRANCH2 = "\u251C\u2500\u2500 ";
3338
+ var LAST_BRANCH2 = "\u2514\u2500\u2500 ";
3339
+ var VERTICAL2 = "\u2502 ";
3340
+ var EMPTY2 = " ";
2985
3341
  function buildLabel(node, options) {
2986
3342
  const parts = [node.name];
2987
3343
  if (node.type === "memo") {
@@ -3028,19 +3384,19 @@ function renderNode(node, prefix, isLast, depth, options, lines) {
3028
3384
  }
3029
3385
  return;
3030
3386
  }
3031
- const connector = isLast ? LAST_BRANCH : BRANCH;
3387
+ const connector = isLast ? LAST_BRANCH2 : BRANCH2;
3032
3388
  const label = buildLabel(node, options);
3033
3389
  lines.push(`${prefix}${connector}${label}`);
3034
3390
  if (options.maxDepth !== void 0 && depth >= options.maxDepth) {
3035
3391
  const childCount = countVisibleDescendants(node, options);
3036
3392
  if (childCount > 0) {
3037
- const nextPrefix2 = prefix + (isLast ? EMPTY : VERTICAL);
3038
- lines.push(`${nextPrefix2}${LAST_BRANCH}\u2026 (${childCount} more)`);
3393
+ const nextPrefix2 = prefix + (isLast ? EMPTY2 : VERTICAL2);
3394
+ lines.push(`${nextPrefix2}${LAST_BRANCH2}\u2026 (${childCount} more)`);
3039
3395
  }
3040
3396
  return;
3041
3397
  }
3042
3398
  const visibleChildren = getVisibleChildren(node, options);
3043
- const nextPrefix = prefix + (isLast ? EMPTY : VERTICAL);
3399
+ const nextPrefix = prefix + (isLast ? EMPTY2 : VERTICAL2);
3044
3400
  for (let i = 0; i < visibleChildren.length; i++) {
3045
3401
  const child = visibleChildren[i];
3046
3402
  if (child !== void 0) {
@@ -3082,7 +3438,7 @@ function formatTree(root, options = {}) {
3082
3438
  if (options.maxDepth === 0) {
3083
3439
  const childCount = countVisibleDescendants(root, options);
3084
3440
  if (childCount > 0) {
3085
- lines.push(`${LAST_BRANCH}\u2026 (${childCount} more)`);
3441
+ lines.push(`${LAST_BRANCH2}\u2026 (${childCount} more)`);
3086
3442
  }
3087
3443
  } else {
3088
3444
  const visibleChildren = getVisibleChildren(root, options);