@agent-scope/cli 1.16.0 → 1.17.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.
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // src/program.ts
4
4
  import { readFileSync as readFileSync11 } from "fs";
5
5
  import { generateTest, loadTrace } from "@agent-scope/playwright";
6
- import { Command as Command9 } from "commander";
6
+ import { Command as Command10 } from "commander";
7
7
 
8
8
  // src/browser.ts
9
9
  import { writeFileSync } from "fs";
@@ -1174,9 +1174,9 @@ function createRL() {
1174
1174
  });
1175
1175
  }
1176
1176
  async function ask(rl, question) {
1177
- return new Promise((resolve16) => {
1177
+ return new Promise((resolve17) => {
1178
1178
  rl.question(question, (answer) => {
1179
- resolve16(answer.trim());
1179
+ resolve17(answer.trim());
1180
1180
  });
1181
1181
  });
1182
1182
  }
@@ -1326,7 +1326,7 @@ function createInitCommand() {
1326
1326
 
1327
1327
  // src/instrument/renders.ts
1328
1328
  import { resolve as resolve7 } from "path";
1329
- import { BrowserPool as BrowserPool3 } from "@agent-scope/render";
1329
+ import { BrowserPool as BrowserPool2 } from "@agent-scope/render";
1330
1330
  import { Command as Command5 } from "commander";
1331
1331
 
1332
1332
  // src/manifest-commands.ts
@@ -1507,6 +1507,7 @@ function createManifestCommand() {
1507
1507
 
1508
1508
  // src/instrument/hooks.ts
1509
1509
  import { resolve as resolve4 } from "path";
1510
+ import { getBrowserEntryScript as getBrowserEntryScript2 } from "@agent-scope/playwright";
1510
1511
  import { Command as Cmd } from "commander";
1511
1512
  import { chromium as chromium2 } from "playwright";
1512
1513
  var MANIFEST_PATH2 = ".reactscope/manifest.json";
@@ -1764,6 +1765,7 @@ async function runHooksProfiling(componentName, filePath, props) {
1764
1765
  try {
1765
1766
  const context = await browser.newContext();
1766
1767
  const page = await context.newPage();
1768
+ await page.addInitScript({ content: getBrowserEntryScript2() });
1767
1769
  const htmlHarness = await buildComponentHarness(filePath, componentName, props, 1280);
1768
1770
  await page.setContent(htmlHarness, { waitUntil: "load" });
1769
1771
  await page.waitForFunction(
@@ -2152,30 +2154,12 @@ Available: ${available}`
2152
2154
 
2153
2155
  // src/instrument/tree.ts
2154
2156
  import { resolve as resolve6 } from "path";
2155
- import { getBrowserEntryScript as getBrowserEntryScript2 } from "@agent-scope/playwright";
2156
- import { BrowserPool as BrowserPool2 } from "@agent-scope/render";
2157
+ import { getBrowserEntryScript as getBrowserEntryScript3 } from "@agent-scope/playwright";
2157
2158
  import { Command as Command4 } from "commander";
2159
+ import { chromium as chromium4 } from "playwright";
2158
2160
  var MANIFEST_PATH4 = ".reactscope/manifest.json";
2159
2161
  var DEFAULT_VIEWPORT_WIDTH = 375;
2160
2162
  var DEFAULT_VIEWPORT_HEIGHT = 812;
2161
- var _pool2 = null;
2162
- async function getPool2() {
2163
- if (_pool2 === null) {
2164
- _pool2 = new BrowserPool2({
2165
- size: { browsers: 1, pagesPerBrowser: 1 },
2166
- viewportWidth: DEFAULT_VIEWPORT_WIDTH,
2167
- viewportHeight: DEFAULT_VIEWPORT_HEIGHT
2168
- });
2169
- await _pool2.init();
2170
- }
2171
- return _pool2;
2172
- }
2173
- async function shutdownPool2() {
2174
- if (_pool2 !== null) {
2175
- await _pool2.close();
2176
- _pool2 = null;
2177
- }
2178
- }
2179
2163
  function mapNodeType(node) {
2180
2164
  if (node.type === "forward_ref") return "forwardRef";
2181
2165
  if (node.type === "host") return "host";
@@ -2387,11 +2371,13 @@ function formatInstrumentTree(root, showProviderDepth = false) {
2387
2371
  }
2388
2372
  async function runInstrumentTree(options) {
2389
2373
  const { componentName, filePath } = options;
2390
- const pool = await getPool2();
2391
- const slot = await pool.acquire();
2392
- const { page } = slot;
2374
+ const browser = await chromium4.launch({ headless: true });
2393
2375
  try {
2394
- await page.addInitScript({ content: getBrowserEntryScript2() });
2376
+ const context = await browser.newContext({
2377
+ viewport: { width: DEFAULT_VIEWPORT_WIDTH, height: DEFAULT_VIEWPORT_HEIGHT }
2378
+ });
2379
+ const page = await context.newPage();
2380
+ await page.addInitScript({ content: getBrowserEntryScript3() });
2395
2381
  const htmlHarness = await buildComponentHarness(
2396
2382
  filePath,
2397
2383
  componentName,
@@ -2444,7 +2430,7 @@ async function runInstrumentTree(options) {
2444
2430
  }
2445
2431
  return instrumentRoot;
2446
2432
  } finally {
2447
- pool.release(slot);
2433
+ await browser.close();
2448
2434
  }
2449
2435
  }
2450
2436
  function createInstrumentTreeCommand() {
@@ -2484,7 +2470,6 @@ Available: ${available}`
2484
2470
  providerDepth: opts.providerDepth,
2485
2471
  wastedRenders: opts.wastedRenders
2486
2472
  });
2487
- await shutdownPool2();
2488
2473
  const fmt2 = resolveFormat2(opts.format);
2489
2474
  if (fmt2 === "json") {
2490
2475
  process.stdout.write(`${JSON.stringify(instrumentRoot, null, 2)}
@@ -2495,7 +2480,6 @@ Available: ${available}`
2495
2480
  `);
2496
2481
  }
2497
2482
  } catch (err) {
2498
- await shutdownPool2();
2499
2483
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2500
2484
  `);
2501
2485
  process.exit(1);
@@ -2815,22 +2799,22 @@ async function replayInteraction2(page, steps) {
2815
2799
  }
2816
2800
  }
2817
2801
  }
2818
- var _pool3 = null;
2819
- async function getPool3() {
2820
- if (_pool3 === null) {
2821
- _pool3 = new BrowserPool3({
2802
+ var _pool2 = null;
2803
+ async function getPool2() {
2804
+ if (_pool2 === null) {
2805
+ _pool2 = new BrowserPool2({
2822
2806
  size: { browsers: 1, pagesPerBrowser: 2 },
2823
2807
  viewportWidth: 1280,
2824
2808
  viewportHeight: 800
2825
2809
  });
2826
- await _pool3.init();
2810
+ await _pool2.init();
2827
2811
  }
2828
- return _pool3;
2812
+ return _pool2;
2829
2813
  }
2830
- async function shutdownPool3() {
2831
- if (_pool3 !== null) {
2832
- await _pool3.close();
2833
- _pool3 = null;
2814
+ async function shutdownPool2() {
2815
+ if (_pool2 !== null) {
2816
+ await _pool2.close();
2817
+ _pool2 = null;
2834
2818
  }
2835
2819
  }
2836
2820
  async function analyzeRenders(options) {
@@ -2847,7 +2831,7 @@ Available: ${available}`
2847
2831
  const rootDir = process.cwd();
2848
2832
  const filePath = resolve7(rootDir, descriptor.filePath);
2849
2833
  const htmlHarness = await buildComponentHarness(filePath, options.componentName, {}, 1280);
2850
- const pool = await getPool3();
2834
+ const pool = await getPool2();
2851
2835
  const slot = await pool.acquire();
2852
2836
  const { page } = slot;
2853
2837
  const startMs = performance.now();
@@ -2955,7 +2939,7 @@ function createInstrumentRendersCommand() {
2955
2939
  interaction,
2956
2940
  manifestPath: opts.manifest
2957
2941
  });
2958
- await shutdownPool3();
2942
+ await shutdownPool2();
2959
2943
  if (opts.json || !isTTY()) {
2960
2944
  process.stdout.write(`${JSON.stringify(result, null, 2)}
2961
2945
  `);
@@ -2964,7 +2948,7 @@ function createInstrumentRendersCommand() {
2964
2948
  `);
2965
2949
  }
2966
2950
  } catch (err) {
2967
- await shutdownPool3();
2951
+ await shutdownPool2();
2968
2952
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2969
2953
  `);
2970
2954
  process.exit(1);
@@ -2989,7 +2973,7 @@ import { resolve as resolve8 } from "path";
2989
2973
  import {
2990
2974
  ALL_CONTEXT_IDS,
2991
2975
  ALL_STRESS_IDS,
2992
- BrowserPool as BrowserPool4,
2976
+ BrowserPool as BrowserPool3,
2993
2977
  contextAxis,
2994
2978
  RenderMatrix,
2995
2979
  SatoriRenderer,
@@ -2999,22 +2983,22 @@ import {
2999
2983
  import { Command as Command6 } from "commander";
3000
2984
  var MANIFEST_PATH6 = ".reactscope/manifest.json";
3001
2985
  var DEFAULT_OUTPUT_DIR = ".reactscope/renders";
3002
- var _pool4 = null;
3003
- async function getPool4(viewportWidth, viewportHeight) {
3004
- if (_pool4 === null) {
3005
- _pool4 = new BrowserPool4({
2986
+ var _pool3 = null;
2987
+ async function getPool3(viewportWidth, viewportHeight) {
2988
+ if (_pool3 === null) {
2989
+ _pool3 = new BrowserPool3({
3006
2990
  size: { browsers: 1, pagesPerBrowser: 4 },
3007
2991
  viewportWidth,
3008
2992
  viewportHeight
3009
2993
  });
3010
- await _pool4.init();
2994
+ await _pool3.init();
3011
2995
  }
3012
- return _pool4;
2996
+ return _pool3;
3013
2997
  }
3014
- async function shutdownPool4() {
3015
- if (_pool4 !== null) {
3016
- await _pool4.close();
3017
- _pool4 = null;
2998
+ async function shutdownPool3() {
2999
+ if (_pool3 !== null) {
3000
+ await _pool3.close();
3001
+ _pool3 = null;
3018
3002
  }
3019
3003
  }
3020
3004
  function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
@@ -3025,7 +3009,7 @@ function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
3025
3009
  _satori: satori,
3026
3010
  async renderCell(props, _complexityClass) {
3027
3011
  const startMs = performance.now();
3028
- const pool = await getPool4(viewportWidth, viewportHeight);
3012
+ const pool = await getPool3(viewportWidth, viewportHeight);
3029
3013
  const htmlHarness = await buildComponentHarness(
3030
3014
  filePath,
3031
3015
  componentName,
@@ -3161,7 +3145,7 @@ Available: ${available}`
3161
3145
  }
3162
3146
  }
3163
3147
  );
3164
- await shutdownPool4();
3148
+ await shutdownPool3();
3165
3149
  if (outcome.crashed) {
3166
3150
  process.stderr.write(`\u2717 Render failed: ${outcome.error.message}
3167
3151
  `);
@@ -3209,7 +3193,7 @@ Available: ${available}`
3209
3193
  );
3210
3194
  }
3211
3195
  } catch (err) {
3212
- await shutdownPool4();
3196
+ await shutdownPool3();
3213
3197
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
3214
3198
  `);
3215
3199
  process.exit(1);
@@ -3294,7 +3278,7 @@ Available: ${available}`
3294
3278
  concurrency
3295
3279
  });
3296
3280
  const result = await matrix.render();
3297
- await shutdownPool4();
3281
+ await shutdownPool3();
3298
3282
  process.stderr.write(
3299
3283
  `Done. ${result.stats.totalCells} cells, avg ${result.stats.avgRenderTimeMs.toFixed(1)}ms
3300
3284
  `
@@ -3339,7 +3323,7 @@ Available: ${available}`
3339
3323
  process.stdout.write(formatMatrixCsv(componentName, result));
3340
3324
  }
3341
3325
  } catch (err) {
3342
- await shutdownPool4();
3326
+ await shutdownPool3();
3343
3327
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
3344
3328
  `);
3345
3329
  process.exit(1);
@@ -3436,13 +3420,13 @@ function registerRenderAll(renderCmd) {
3436
3420
  workers.push(worker());
3437
3421
  }
3438
3422
  await Promise.all(workers);
3439
- await shutdownPool4();
3423
+ await shutdownPool3();
3440
3424
  process.stderr.write("\n");
3441
3425
  const summary = formatSummaryText(results, outputDir);
3442
3426
  process.stderr.write(`${summary}
3443
3427
  `);
3444
3428
  } catch (err) {
3445
- await shutdownPool4();
3429
+ await shutdownPool3();
3446
3430
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
3447
3431
  `);
3448
3432
  process.exit(1);
@@ -3488,29 +3472,29 @@ function createRenderCommand() {
3488
3472
  import { existsSync as existsSync6, mkdirSync as mkdirSync4, rmSync, writeFileSync as writeFileSync6 } from "fs";
3489
3473
  import { resolve as resolve9 } from "path";
3490
3474
  import { generateManifest as generateManifest3 } from "@agent-scope/manifest";
3491
- import { BrowserPool as BrowserPool5, safeRender as safeRender3 } from "@agent-scope/render";
3475
+ import { BrowserPool as BrowserPool4, safeRender as safeRender3 } from "@agent-scope/render";
3492
3476
  import { ComplianceEngine as ComplianceEngine2, TokenResolver as TokenResolver2 } from "@agent-scope/tokens";
3493
3477
  var DEFAULT_BASELINE_DIR = ".reactscope/baseline";
3494
- var _pool5 = null;
3495
- async function getPool5(viewportWidth, viewportHeight) {
3496
- if (_pool5 === null) {
3497
- _pool5 = new BrowserPool5({
3478
+ var _pool4 = null;
3479
+ async function getPool4(viewportWidth, viewportHeight) {
3480
+ if (_pool4 === null) {
3481
+ _pool4 = new BrowserPool4({
3498
3482
  size: { browsers: 1, pagesPerBrowser: 4 },
3499
3483
  viewportWidth,
3500
3484
  viewportHeight
3501
3485
  });
3502
- await _pool5.init();
3486
+ await _pool4.init();
3503
3487
  }
3504
- return _pool5;
3488
+ return _pool4;
3505
3489
  }
3506
- async function shutdownPool5() {
3507
- if (_pool5 !== null) {
3508
- await _pool5.close();
3509
- _pool5 = null;
3490
+ async function shutdownPool4() {
3491
+ if (_pool4 !== null) {
3492
+ await _pool4.close();
3493
+ _pool4 = null;
3510
3494
  }
3511
3495
  }
3512
3496
  async function renderComponent2(filePath, componentName, props, viewportWidth, viewportHeight) {
3513
- const pool = await getPool5(viewportWidth, viewportHeight);
3497
+ const pool = await getPool4(viewportWidth, viewportHeight);
3514
3498
  const htmlHarness = await buildComponentHarness(filePath, componentName, props, viewportWidth);
3515
3499
  const slot = await pool.acquire();
3516
3500
  const { page } = slot;
@@ -3760,7 +3744,7 @@ async function runBaseline(options = {}) {
3760
3744
  workers.push(worker());
3761
3745
  }
3762
3746
  await Promise.all(workers);
3763
- await shutdownPool5();
3747
+ await shutdownPool4();
3764
3748
  if (isTTY()) {
3765
3749
  process.stderr.write("\n");
3766
3750
  }
@@ -3814,7 +3798,7 @@ function registerBaselineSubCommand(reportCmd) {
3814
3798
  import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync7 } from "fs";
3815
3799
  import { resolve as resolve10 } from "path";
3816
3800
  import { generateManifest as generateManifest4 } from "@agent-scope/manifest";
3817
- import { BrowserPool as BrowserPool6, safeRender as safeRender4 } from "@agent-scope/render";
3801
+ import { BrowserPool as BrowserPool5, safeRender as safeRender4 } from "@agent-scope/render";
3818
3802
  import { ComplianceEngine as ComplianceEngine3, TokenResolver as TokenResolver3 } from "@agent-scope/tokens";
3819
3803
  var DEFAULT_BASELINE_DIR2 = ".reactscope/baseline";
3820
3804
  function loadBaselineCompliance(baselineDir) {
@@ -3828,26 +3812,26 @@ function loadBaselineRenderJson2(baselineDir, componentName) {
3828
3812
  if (!existsSync7(jsonPath)) return null;
3829
3813
  return JSON.parse(readFileSync6(jsonPath, "utf-8"));
3830
3814
  }
3831
- var _pool6 = null;
3832
- async function getPool6(viewportWidth, viewportHeight) {
3833
- if (_pool6 === null) {
3834
- _pool6 = new BrowserPool6({
3815
+ var _pool5 = null;
3816
+ async function getPool5(viewportWidth, viewportHeight) {
3817
+ if (_pool5 === null) {
3818
+ _pool5 = new BrowserPool5({
3835
3819
  size: { browsers: 1, pagesPerBrowser: 4 },
3836
3820
  viewportWidth,
3837
3821
  viewportHeight
3838
3822
  });
3839
- await _pool6.init();
3823
+ await _pool5.init();
3840
3824
  }
3841
- return _pool6;
3825
+ return _pool5;
3842
3826
  }
3843
- async function shutdownPool6() {
3844
- if (_pool6 !== null) {
3845
- await _pool6.close();
3846
- _pool6 = null;
3827
+ async function shutdownPool5() {
3828
+ if (_pool5 !== null) {
3829
+ await _pool5.close();
3830
+ _pool5 = null;
3847
3831
  }
3848
3832
  }
3849
3833
  async function renderComponent3(filePath, componentName, props, viewportWidth, viewportHeight) {
3850
- const pool = await getPool6(viewportWidth, viewportHeight);
3834
+ const pool = await getPool5(viewportWidth, viewportHeight);
3851
3835
  const htmlHarness = await buildComponentHarness(filePath, componentName, props, viewportWidth);
3852
3836
  const slot = await pool.acquire();
3853
3837
  const { page } = slot;
@@ -4096,7 +4080,7 @@ async function runDiff(options = {}) {
4096
4080
  }
4097
4081
  await Promise.all(workers);
4098
4082
  }
4099
- await shutdownPool6();
4083
+ await shutdownPool5();
4100
4084
  if (isTTY() && total > 0) {
4101
4085
  process.stderr.write("\n");
4102
4086
  }
@@ -4702,9 +4686,140 @@ function buildStructuredReport(report) {
4702
4686
  };
4703
4687
  }
4704
4688
 
4689
+ // src/site-commands.ts
4690
+ import { createReadStream, existsSync as existsSync9, statSync } from "fs";
4691
+ import { createServer } from "http";
4692
+ import { extname, join as join3, resolve as resolve12 } from "path";
4693
+ import { buildSite } from "@agent-scope/site";
4694
+ import { Command as Command7 } from "commander";
4695
+ var MIME_TYPES = {
4696
+ ".html": "text/html; charset=utf-8",
4697
+ ".css": "text/css; charset=utf-8",
4698
+ ".js": "application/javascript; charset=utf-8",
4699
+ ".json": "application/json; charset=utf-8",
4700
+ ".png": "image/png",
4701
+ ".jpg": "image/jpeg",
4702
+ ".jpeg": "image/jpeg",
4703
+ ".svg": "image/svg+xml",
4704
+ ".ico": "image/x-icon"
4705
+ };
4706
+ function registerBuild(siteCmd) {
4707
+ siteCmd.command("build").description("Build a static HTML gallery from .reactscope/ output").option("-i, --input <path>", "Path to .reactscope input directory", ".reactscope").option("-o, --output <path>", "Output directory for generated site", ".reactscope/site").option("--base-path <path>", "Base URL path prefix for subdirectory deployment", "/").option("--compliance <path>", "Path to compliance batch report JSON").option("--title <text>", "Site title", "Scope \u2014 Component Gallery").action(
4708
+ async (opts) => {
4709
+ try {
4710
+ const inputDir = resolve12(process.cwd(), opts.input);
4711
+ const outputDir = resolve12(process.cwd(), opts.output);
4712
+ if (!existsSync9(inputDir)) {
4713
+ throw new Error(
4714
+ `Input directory not found: ${inputDir}
4715
+ Run \`scope manifest generate\` and \`scope render\` first.`
4716
+ );
4717
+ }
4718
+ const manifestPath = join3(inputDir, "manifest.json");
4719
+ if (!existsSync9(manifestPath)) {
4720
+ throw new Error(
4721
+ `Manifest not found at ${manifestPath}
4722
+ Run \`scope manifest generate\` first.`
4723
+ );
4724
+ }
4725
+ process.stderr.write(`Building site from ${inputDir}\u2026
4726
+ `);
4727
+ await buildSite({
4728
+ inputDir,
4729
+ outputDir,
4730
+ basePath: opts.basePath,
4731
+ ...opts.compliance !== void 0 && {
4732
+ compliancePath: resolve12(process.cwd(), opts.compliance)
4733
+ },
4734
+ title: opts.title
4735
+ });
4736
+ process.stderr.write(`Site written to ${outputDir}
4737
+ `);
4738
+ process.stdout.write(`${outputDir}
4739
+ `);
4740
+ } catch (err) {
4741
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4742
+ `);
4743
+ process.exit(1);
4744
+ }
4745
+ }
4746
+ );
4747
+ }
4748
+ function registerServe(siteCmd) {
4749
+ siteCmd.command("serve").description("Serve the built static site locally").option("-p, --port <number>", "Port to listen on", "3000").option("-d, --dir <path>", "Directory to serve", ".reactscope/site").action((opts) => {
4750
+ try {
4751
+ const port = Number.parseInt(opts.port, 10);
4752
+ if (Number.isNaN(port) || port < 1 || port > 65535) {
4753
+ throw new Error(`Invalid port: ${opts.port}`);
4754
+ }
4755
+ const serveDir = resolve12(process.cwd(), opts.dir);
4756
+ if (!existsSync9(serveDir)) {
4757
+ throw new Error(
4758
+ `Serve directory not found: ${serveDir}
4759
+ Run \`scope site build\` first.`
4760
+ );
4761
+ }
4762
+ const server = createServer((req, res) => {
4763
+ const rawUrl = req.url ?? "/";
4764
+ const urlPath = decodeURIComponent(rawUrl.split("?")[0] ?? "/");
4765
+ const filePath = join3(serveDir, urlPath.endsWith("/") ? `${urlPath}index.html` : urlPath);
4766
+ if (!filePath.startsWith(serveDir)) {
4767
+ res.writeHead(403, { "Content-Type": "text/plain" });
4768
+ res.end("Forbidden");
4769
+ return;
4770
+ }
4771
+ if (existsSync9(filePath) && statSync(filePath).isFile()) {
4772
+ const ext = extname(filePath).toLowerCase();
4773
+ const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
4774
+ res.writeHead(200, { "Content-Type": contentType });
4775
+ createReadStream(filePath).pipe(res);
4776
+ return;
4777
+ }
4778
+ const htmlPath = `${filePath}.html`;
4779
+ if (existsSync9(htmlPath) && statSync(htmlPath).isFile()) {
4780
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
4781
+ createReadStream(htmlPath).pipe(res);
4782
+ return;
4783
+ }
4784
+ res.writeHead(404, { "Content-Type": "text/plain" });
4785
+ res.end(`Not found: ${urlPath}`);
4786
+ });
4787
+ server.listen(port, () => {
4788
+ process.stderr.write(`Scope site running at http://localhost:${port}
4789
+ `);
4790
+ process.stderr.write(`Serving ${serveDir}
4791
+ `);
4792
+ process.stderr.write("Press Ctrl+C to stop.\n");
4793
+ });
4794
+ server.on("error", (err) => {
4795
+ if (err.code === "EADDRINUSE") {
4796
+ process.stderr.write(`Error: Port ${port} is already in use.
4797
+ `);
4798
+ } else {
4799
+ process.stderr.write(`Server error: ${err.message}
4800
+ `);
4801
+ }
4802
+ process.exit(1);
4803
+ });
4804
+ } catch (err) {
4805
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4806
+ `);
4807
+ process.exit(1);
4808
+ }
4809
+ });
4810
+ }
4811
+ function createSiteCommand() {
4812
+ const siteCmd = new Command7("site").description(
4813
+ "Build and serve the static component gallery site"
4814
+ );
4815
+ registerBuild(siteCmd);
4816
+ registerServe(siteCmd);
4817
+ return siteCmd;
4818
+ }
4819
+
4705
4820
  // src/tokens/commands.ts
4706
- import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
4707
- import { resolve as resolve15 } from "path";
4821
+ import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
4822
+ import { resolve as resolve16 } from "path";
4708
4823
  import {
4709
4824
  parseTokenFileSync as parseTokenFileSync2,
4710
4825
  TokenParseError,
@@ -4712,19 +4827,19 @@ import {
4712
4827
  TokenValidationError,
4713
4828
  validateTokenFile
4714
4829
  } from "@agent-scope/tokens";
4715
- import { Command as Command8 } from "commander";
4830
+ import { Command as Command9 } from "commander";
4716
4831
 
4717
4832
  // src/tokens/compliance.ts
4718
- import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
4719
- import { resolve as resolve12 } from "path";
4833
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
4834
+ import { resolve as resolve13 } from "path";
4720
4835
  import {
4721
4836
  ComplianceEngine as ComplianceEngine4,
4722
4837
  TokenResolver as TokenResolver4
4723
4838
  } from "@agent-scope/tokens";
4724
4839
  var DEFAULT_STYLES_PATH = ".reactscope/compliance-styles.json";
4725
4840
  function loadStylesFile(stylesPath) {
4726
- const absPath = resolve12(process.cwd(), stylesPath);
4727
- if (!existsSync9(absPath)) {
4841
+ const absPath = resolve13(process.cwd(), stylesPath);
4842
+ if (!existsSync10(absPath)) {
4728
4843
  throw new Error(
4729
4844
  `Compliance styles file not found at ${absPath}.
4730
4845
  Run \`scope render all\` first to generate component styles, or use --styles to specify a path.
@@ -4891,38 +5006,38 @@ function registerCompliance(tokensCmd) {
4891
5006
  }
4892
5007
 
4893
5008
  // src/tokens/export.ts
4894
- import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "fs";
4895
- import { resolve as resolve13 } from "path";
5009
+ import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "fs";
5010
+ import { resolve as resolve14 } from "path";
4896
5011
  import {
4897
5012
  exportTokens,
4898
5013
  parseTokenFileSync,
4899
5014
  ThemeResolver,
4900
5015
  TokenResolver as TokenResolver5
4901
5016
  } from "@agent-scope/tokens";
4902
- import { Command as Command7 } from "commander";
5017
+ import { Command as Command8 } from "commander";
4903
5018
  var DEFAULT_TOKEN_FILE = "reactscope.tokens.json";
4904
5019
  var CONFIG_FILE = "reactscope.config.json";
4905
5020
  var SUPPORTED_FORMATS = ["css", "ts", "scss", "tailwind", "flat-json", "figma"];
4906
5021
  function resolveTokenFilePath2(fileFlag) {
4907
5022
  if (fileFlag !== void 0) {
4908
- return resolve13(process.cwd(), fileFlag);
5023
+ return resolve14(process.cwd(), fileFlag);
4909
5024
  }
4910
- const configPath = resolve13(process.cwd(), CONFIG_FILE);
4911
- if (existsSync10(configPath)) {
5025
+ const configPath = resolve14(process.cwd(), CONFIG_FILE);
5026
+ if (existsSync11(configPath)) {
4912
5027
  try {
4913
5028
  const raw = readFileSync9(configPath, "utf-8");
4914
5029
  const config = JSON.parse(raw);
4915
5030
  if (typeof config === "object" && config !== null && "tokens" in config && typeof config.tokens === "object" && config.tokens !== null && typeof config.tokens?.file === "string") {
4916
5031
  const file = config.tokens.file;
4917
- return resolve13(process.cwd(), file);
5032
+ return resolve14(process.cwd(), file);
4918
5033
  }
4919
5034
  } catch {
4920
5035
  }
4921
5036
  }
4922
- return resolve13(process.cwd(), DEFAULT_TOKEN_FILE);
5037
+ return resolve14(process.cwd(), DEFAULT_TOKEN_FILE);
4923
5038
  }
4924
5039
  function createTokensExportCommand() {
4925
- return new Command7("export").description("Export design tokens to a downstream format").requiredOption("--format <fmt>", `Output format: ${SUPPORTED_FORMATS.join(", ")}`).option("--file <path>", "Path to token file (overrides config)").option("--out <path>", "Write output to file instead of stdout").option("--prefix <prefix>", "CSS/SCSS: prefix for variable names (e.g. 'scope')").option("--selector <selector>", "CSS: custom root selector (default: ':root')").option(
5040
+ return new Command8("export").description("Export design tokens to a downstream format").requiredOption("--format <fmt>", `Output format: ${SUPPORTED_FORMATS.join(", ")}`).option("--file <path>", "Path to token file (overrides config)").option("--out <path>", "Write output to file instead of stdout").option("--prefix <prefix>", "CSS/SCSS: prefix for variable names (e.g. 'scope')").option("--selector <selector>", "CSS: custom root selector (default: ':root')").option(
4926
5041
  "--theme <name>",
4927
5042
  "Include theme overrides for the named theme (applies to css, ts, scss, tailwind, figma)"
4928
5043
  ).action(
@@ -4938,7 +5053,7 @@ Supported formats: ${SUPPORTED_FORMATS.join(", ")}
4938
5053
  const format = opts.format;
4939
5054
  try {
4940
5055
  const filePath = resolveTokenFilePath2(opts.file);
4941
- if (!existsSync10(filePath)) {
5056
+ if (!existsSync11(filePath)) {
4942
5057
  throw new Error(
4943
5058
  `Token file not found at ${filePath}.
4944
5059
  Create a reactscope.tokens.json file or use --file to specify a path.`
@@ -4983,7 +5098,7 @@ Available themes: ${themeNames.join(", ")}`
4983
5098
  themes: themesMap
4984
5099
  });
4985
5100
  if (opts.out !== void 0) {
4986
- const outPath = resolve13(process.cwd(), opts.out);
5101
+ const outPath = resolve14(process.cwd(), opts.out);
4987
5102
  writeFileSync9(outPath, output, "utf-8");
4988
5103
  process.stderr.write(`Exported ${tokens.length} tokens to ${outPath}
4989
5104
  `);
@@ -5099,8 +5214,8 @@ ${formatImpactSummary(report)}
5099
5214
 
5100
5215
  // src/tokens/preview.ts
5101
5216
  import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync10 } from "fs";
5102
- import { resolve as resolve14 } from "path";
5103
- import { BrowserPool as BrowserPool7, SpriteSheetGenerator } from "@agent-scope/render";
5217
+ import { resolve as resolve15 } from "path";
5218
+ import { BrowserPool as BrowserPool6, SpriteSheetGenerator } from "@agent-scope/render";
5104
5219
  import { ComplianceEngine as ComplianceEngine6, ImpactAnalyzer as ImpactAnalyzer2, TokenResolver as TokenResolver7 } from "@agent-scope/tokens";
5105
5220
  var DEFAULT_STYLES_PATH3 = ".reactscope/compliance-styles.json";
5106
5221
  var DEFAULT_MANIFEST_PATH = ".reactscope/manifest.json";
@@ -5115,7 +5230,7 @@ async function renderComponentWithCssOverride(filePath, componentName, cssOverri
5115
5230
  cssOverride
5116
5231
  // injected as <style>
5117
5232
  );
5118
- const pool = new BrowserPool7({
5233
+ const pool = new BrowserPool6({
5119
5234
  size: { browsers: 1, pagesPerBrowser: 1 },
5120
5235
  viewportWidth: vpWidth,
5121
5236
  viewportHeight: vpHeight
@@ -5280,8 +5395,8 @@ function registerPreview(tokensCmd) {
5280
5395
  });
5281
5396
  const spriteResult = await generator.generate(matrixResult);
5282
5397
  const tokenLabel = tokenPath.replace(/\./g, "-");
5283
- const outputPath = opts.output ?? resolve14(process.cwd(), DEFAULT_OUTPUT_DIR2, `preview-${tokenLabel}.png`);
5284
- const outputDir = resolve14(outputPath, "..");
5398
+ const outputPath = opts.output ?? resolve15(process.cwd(), DEFAULT_OUTPUT_DIR2, `preview-${tokenLabel}.png`);
5399
+ const outputDir = resolve15(outputPath, "..");
5285
5400
  mkdirSync5(outputDir, { recursive: true });
5286
5401
  writeFileSync10(outputPath, spriteResult.png);
5287
5402
  const useJson = opts.format === "json" || opts.format !== "text" && !isTTY();
@@ -5342,24 +5457,24 @@ function buildTable2(headers, rows) {
5342
5457
  }
5343
5458
  function resolveTokenFilePath(fileFlag) {
5344
5459
  if (fileFlag !== void 0) {
5345
- return resolve15(process.cwd(), fileFlag);
5460
+ return resolve16(process.cwd(), fileFlag);
5346
5461
  }
5347
- const configPath = resolve15(process.cwd(), CONFIG_FILE2);
5348
- if (existsSync11(configPath)) {
5462
+ const configPath = resolve16(process.cwd(), CONFIG_FILE2);
5463
+ if (existsSync12(configPath)) {
5349
5464
  try {
5350
5465
  const raw = readFileSync10(configPath, "utf-8");
5351
5466
  const config = JSON.parse(raw);
5352
5467
  if (typeof config === "object" && config !== null && "tokens" in config && typeof config.tokens === "object" && config.tokens !== null && typeof config.tokens?.file === "string") {
5353
5468
  const file = config.tokens.file;
5354
- return resolve15(process.cwd(), file);
5469
+ return resolve16(process.cwd(), file);
5355
5470
  }
5356
5471
  } catch {
5357
5472
  }
5358
5473
  }
5359
- return resolve15(process.cwd(), DEFAULT_TOKEN_FILE2);
5474
+ return resolve16(process.cwd(), DEFAULT_TOKEN_FILE2);
5360
5475
  }
5361
5476
  function loadTokens(absPath) {
5362
- if (!existsSync11(absPath)) {
5477
+ if (!existsSync12(absPath)) {
5363
5478
  throw new Error(
5364
5479
  `Token file not found at ${absPath}.
5365
5480
  Create a reactscope.tokens.json file or use --file to specify a path.`
@@ -5579,7 +5694,7 @@ function registerValidate(tokensCmd) {
5579
5694
  ).option("--file <path>", "Path to token file (overrides config)").option("--format <fmt>", "Output format: json or text (default: auto-detect)").action((opts) => {
5580
5695
  try {
5581
5696
  const filePath = resolveTokenFilePath(opts.file);
5582
- if (!existsSync11(filePath)) {
5697
+ if (!existsSync12(filePath)) {
5583
5698
  throw new Error(
5584
5699
  `Token file not found at ${filePath}.
5585
5700
  Create a reactscope.tokens.json file or use --file to specify a path.`
@@ -5653,7 +5768,7 @@ function outputValidationResult(filePath, errors, useJson) {
5653
5768
  }
5654
5769
  }
5655
5770
  function createTokensCommand() {
5656
- const tokensCmd = new Command8("tokens").description(
5771
+ const tokensCmd = new Command9("tokens").description(
5657
5772
  "Query and validate design tokens from a reactscope.tokens.json file"
5658
5773
  );
5659
5774
  registerGet2(tokensCmd);
@@ -5670,7 +5785,7 @@ function createTokensCommand() {
5670
5785
 
5671
5786
  // src/program.ts
5672
5787
  function createProgram(options = {}) {
5673
- const program2 = new Command9("scope").version(options.version ?? "0.1.0").description("Scope \u2014 React instrumentation toolkit");
5788
+ const program2 = new Command10("scope").version(options.version ?? "0.1.0").description("Scope \u2014 React instrumentation toolkit");
5674
5789
  program2.command("capture <url>").description("Capture a React component tree from a live URL and output as JSON").option("-o, --output <path>", "Write JSON to file instead of stdout").option("--pretty", "Pretty-print JSON output (default: minified)", false).option("--timeout <ms>", "Max wait time for React to mount (ms)", "10000").option("--wait <ms>", "Additional wait after page load before capture (ms)", "0").action(
5675
5790
  async (url, opts) => {
5676
5791
  try {
@@ -5764,6 +5879,7 @@ function createProgram(options = {}) {
5764
5879
  registerDiffSubCommand(existingReportCmd);
5765
5880
  registerPrCommentSubCommand(existingReportCmd);
5766
5881
  }
5882
+ program2.addCommand(createSiteCommand());
5767
5883
  return program2;
5768
5884
  }
5769
5885