@agent-scope/cli 1.17.2 → 1.18.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/cli.js CHANGED
@@ -61,9 +61,9 @@ import { Command } from "commander";
61
61
  // src/component-bundler.ts
62
62
  import { dirname } from "path";
63
63
  import * as esbuild from "esbuild";
64
- async function buildComponentHarness(filePath, componentName, props, viewportWidth, projectCss) {
64
+ async function buildComponentHarness(filePath, componentName, props, viewportWidth, projectCss, wrapperScript) {
65
65
  const bundledScript = await bundleComponentToIIFE(filePath, componentName, props);
66
- return wrapInHtml(bundledScript, viewportWidth, projectCss);
66
+ return wrapInHtml(bundledScript, viewportWidth, projectCss, wrapperScript);
67
67
  }
68
68
  async function bundleComponentToIIFE(filePath, componentName, props) {
69
69
  const propsJson = JSON.stringify(props).replace(/<\/script>/gi, "<\\/script>");
@@ -99,7 +99,12 @@ import { createElement } from "react";
99
99
  window.__SCOPE_RENDER_COMPLETE__ = true;
100
100
  return;
101
101
  }
102
- createRoot(rootEl).render(createElement(Component, props));
102
+ // If a scope file wrapper was injected, use it to wrap the component
103
+ var Wrapper = (window).__SCOPE_WRAPPER__;
104
+ var element = Wrapper
105
+ ? createElement(Wrapper, null, createElement(Component, props))
106
+ : createElement(Component, props);
107
+ createRoot(rootEl).render(element);
103
108
  // Use requestAnimationFrame to let React flush the render
104
109
  requestAnimationFrame(function() {
105
110
  window.__SCOPE_RENDER_COMPLETE__ = true;
@@ -149,10 +154,11 @@ ${msg}`);
149
154
  }
150
155
  return outputFile.text;
151
156
  }
152
- function wrapInHtml(bundledScript, viewportWidth, projectCss) {
157
+ function wrapInHtml(bundledScript, viewportWidth, projectCss, wrapperScript) {
153
158
  const projectStyleBlock = projectCss != null && projectCss.length > 0 ? `<style id="scope-project-css">
154
159
  ${projectCss.replace(/<\/style>/gi, "<\\/style>")}
155
160
  </style>` : "";
161
+ const wrapperScriptBlock = wrapperScript != null && wrapperScript.length > 0 ? `<script id="scope-wrapper-script">${wrapperScript}</script>` : "";
156
162
  return `<!DOCTYPE html>
157
163
  <html lang="en">
158
164
  <head>
@@ -167,6 +173,7 @@ ${projectCss.replace(/<\/style>/gi, "<\\/style>")}
167
173
  </head>
168
174
  <body>
169
175
  <div id="scope-root" data-reactscope-root></div>
176
+ ${wrapperScriptBlock}
170
177
  <script>${bundledScript}</script>
171
178
  </body>
172
179
  </html>`;
@@ -535,16 +542,16 @@ async function getTailwindCompiler(cwd) {
535
542
  from: entryPath,
536
543
  loadStylesheet
537
544
  });
538
- const build2 = result.build.bind(result);
539
- compilerCache = { cwd, build: build2 };
540
- return build2;
545
+ const build3 = result.build.bind(result);
546
+ compilerCache = { cwd, build: build3 };
547
+ return build3;
541
548
  }
542
549
  async function getCompiledCssForClasses(cwd, classes) {
543
- const build2 = await getTailwindCompiler(cwd);
544
- if (build2 === null) return null;
550
+ const build3 = await getTailwindCompiler(cwd);
551
+ if (build3 === null) return null;
545
552
  const deduped = [...new Set(classes)].filter(Boolean);
546
553
  if (deduped.length === 0) return null;
547
- return build2(deduped);
554
+ return build3(deduped);
548
555
  }
549
556
 
550
557
  // src/ci/commands.ts
@@ -1174,9 +1181,9 @@ function createRL() {
1174
1181
  });
1175
1182
  }
1176
1183
  async function ask(rl, question) {
1177
- return new Promise((resolve17) => {
1184
+ return new Promise((resolve18) => {
1178
1185
  rl.question(question, (answer) => {
1179
- resolve17(answer.trim());
1186
+ resolve18(answer.trim());
1180
1187
  });
1181
1188
  });
1182
1189
  }
@@ -1326,6 +1333,7 @@ function createInitCommand() {
1326
1333
 
1327
1334
  // src/instrument/renders.ts
1328
1335
  import { resolve as resolve7 } from "path";
1336
+ import { getBrowserEntryScript as getBrowserEntryScript5 } from "@agent-scope/playwright";
1329
1337
  import { BrowserPool as BrowserPool2 } from "@agent-scope/render";
1330
1338
  import { Command as Command5 } from "commander";
1331
1339
 
@@ -1765,8 +1773,15 @@ async function runHooksProfiling(componentName, filePath, props) {
1765
1773
  try {
1766
1774
  const context = await browser.newContext();
1767
1775
  const page = await context.newPage();
1768
- await page.addInitScript({ content: getBrowserEntryScript2() });
1769
- const htmlHarness = await buildComponentHarness(filePath, componentName, props, 1280);
1776
+ const scopeRuntime = getBrowserEntryScript2();
1777
+ const htmlHarness = await buildComponentHarness(
1778
+ filePath,
1779
+ componentName,
1780
+ props,
1781
+ 1280,
1782
+ void 0,
1783
+ scopeRuntime
1784
+ );
1770
1785
  await page.setContent(htmlHarness, { waitUntil: "load" });
1771
1786
  await page.waitForFunction(
1772
1787
  () => {
@@ -1860,6 +1875,7 @@ Available: ${available}`
1860
1875
 
1861
1876
  // src/instrument/profile.ts
1862
1877
  import { resolve as resolve5 } from "path";
1878
+ import { getBrowserEntryScript as getBrowserEntryScript3 } from "@agent-scope/playwright";
1863
1879
  import { Command as Cmd2 } from "commander";
1864
1880
  import { chromium as chromium3 } from "playwright";
1865
1881
  var MANIFEST_PATH3 = ".reactscope/manifest.json";
@@ -2030,7 +2046,15 @@ async function runInteractionProfile(componentName, filePath, props, interaction
2030
2046
  try {
2031
2047
  const context = await browser.newContext();
2032
2048
  const page = await context.newPage();
2033
- const htmlHarness = await buildComponentHarness(filePath, componentName, props, 1280);
2049
+ const scopeRuntime = getBrowserEntryScript3();
2050
+ const htmlHarness = await buildComponentHarness(
2051
+ filePath,
2052
+ componentName,
2053
+ props,
2054
+ 1280,
2055
+ void 0,
2056
+ scopeRuntime
2057
+ );
2034
2058
  await page.setContent(htmlHarness, { waitUntil: "load" });
2035
2059
  await page.waitForFunction(
2036
2060
  () => {
@@ -2154,7 +2178,7 @@ Available: ${available}`
2154
2178
 
2155
2179
  // src/instrument/tree.ts
2156
2180
  import { resolve as resolve6 } from "path";
2157
- import { getBrowserEntryScript as getBrowserEntryScript3 } from "@agent-scope/playwright";
2181
+ import { getBrowserEntryScript as getBrowserEntryScript4 } from "@agent-scope/playwright";
2158
2182
  import { Command as Command4 } from "commander";
2159
2183
  import { chromium as chromium4 } from "playwright";
2160
2184
  var MANIFEST_PATH4 = ".reactscope/manifest.json";
@@ -2377,12 +2401,14 @@ async function runInstrumentTree(options) {
2377
2401
  viewport: { width: DEFAULT_VIEWPORT_WIDTH, height: DEFAULT_VIEWPORT_HEIGHT }
2378
2402
  });
2379
2403
  const page = await context.newPage();
2380
- await page.addInitScript({ content: getBrowserEntryScript3() });
2404
+ const scopeRuntime = getBrowserEntryScript4();
2381
2405
  const htmlHarness = await buildComponentHarness(
2382
2406
  filePath,
2383
2407
  componentName,
2384
2408
  {},
2385
- DEFAULT_VIEWPORT_WIDTH
2409
+ DEFAULT_VIEWPORT_WIDTH,
2410
+ void 0,
2411
+ scopeRuntime
2386
2412
  );
2387
2413
  await page.setContent(htmlHarness, { waitUntil: "load" });
2388
2414
  await page.waitForFunction(
@@ -2830,13 +2856,20 @@ Available: ${available}`
2830
2856
  }
2831
2857
  const rootDir = process.cwd();
2832
2858
  const filePath = resolve7(rootDir, descriptor.filePath);
2833
- const htmlHarness = await buildComponentHarness(filePath, options.componentName, {}, 1280);
2859
+ const preScript = getBrowserEntryScript5() + "\n" + buildInstrumentationScript();
2860
+ const htmlHarness = await buildComponentHarness(
2861
+ filePath,
2862
+ options.componentName,
2863
+ {},
2864
+ 1280,
2865
+ void 0,
2866
+ preScript
2867
+ );
2834
2868
  const pool = await getPool2();
2835
2869
  const slot = await pool.acquire();
2836
2870
  const { page } = slot;
2837
2871
  const startMs = performance.now();
2838
2872
  try {
2839
- await page.addInitScript(buildInstrumentationScript());
2840
2873
  await page.setContent(htmlHarness, { waitUntil: "load" });
2841
2874
  await page.waitForFunction(
2842
2875
  () => window.__SCOPE_RENDER_COMPLETE__ === true,
@@ -2968,8 +3001,8 @@ function createInstrumentCommand() {
2968
3001
  }
2969
3002
 
2970
3003
  // src/render-commands.ts
2971
- import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "fs";
2972
- import { resolve as resolve8 } from "path";
3004
+ import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
3005
+ import { resolve as resolve9 } from "path";
2973
3006
  import {
2974
3007
  ALL_CONTEXT_IDS,
2975
3008
  ALL_STRESS_IDS,
@@ -2981,6 +3014,129 @@ import {
2981
3014
  stressAxis
2982
3015
  } from "@agent-scope/render";
2983
3016
  import { Command as Command6 } from "commander";
3017
+
3018
+ // src/scope-file.ts
3019
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, rmSync } from "fs";
3020
+ import { createRequire as createRequire2 } from "module";
3021
+ import { tmpdir } from "os";
3022
+ import { dirname as dirname2, join as join3, resolve as resolve8 } from "path";
3023
+ import * as esbuild2 from "esbuild";
3024
+ var SCOPE_EXTENSIONS = [".scope.tsx", ".scope.ts", ".scope.jsx", ".scope.js"];
3025
+ function findScopeFile(componentFilePath) {
3026
+ const dir = dirname2(componentFilePath);
3027
+ const stem = componentFilePath.replace(/\.(tsx?|jsx?)$/, "");
3028
+ const baseName = stem.slice(dir.length + 1);
3029
+ for (const ext of SCOPE_EXTENSIONS) {
3030
+ const candidate = join3(dir, `${baseName}${ext}`);
3031
+ if (existsSync6(candidate)) return candidate;
3032
+ }
3033
+ return null;
3034
+ }
3035
+ async function loadScopeFile(scopeFilePath) {
3036
+ const tmpDir = join3(tmpdir(), `scope-file-${Date.now()}-${Math.random().toString(36).slice(2)}`);
3037
+ mkdirSync3(tmpDir, { recursive: true });
3038
+ const outFile = join3(tmpDir, "scope-file.cjs");
3039
+ try {
3040
+ const result = await esbuild2.build({
3041
+ entryPoints: [scopeFilePath],
3042
+ bundle: true,
3043
+ format: "cjs",
3044
+ platform: "node",
3045
+ target: "node18",
3046
+ outfile: outFile,
3047
+ write: true,
3048
+ jsx: "automatic",
3049
+ jsxImportSource: "react",
3050
+ // Externalize React — we don't need to execute JSX, just extract plain data
3051
+ external: ["react", "react-dom", "react/jsx-runtime"],
3052
+ define: {
3053
+ "process.env.NODE_ENV": '"development"'
3054
+ },
3055
+ logLevel: "silent"
3056
+ });
3057
+ if (result.errors.length > 0) {
3058
+ const msg = result.errors.map((e) => `${e.text}${e.location ? ` (${e.location.file}:${e.location.line})` : ""}`).join("\n");
3059
+ throw new Error(`Failed to bundle scope file ${scopeFilePath}:
3060
+ ${msg}`);
3061
+ }
3062
+ const req = createRequire2(import.meta.url);
3063
+ delete req.cache[resolve8(outFile)];
3064
+ const mod = req(outFile);
3065
+ const scenarios = extractScenarios(mod, scopeFilePath);
3066
+ const hasWrapper = typeof mod.wrapper === "function" || typeof mod.default?.wrapper === "function";
3067
+ return { filePath: scopeFilePath, scenarios, hasWrapper };
3068
+ } finally {
3069
+ try {
3070
+ rmSync(tmpDir, { recursive: true, force: true });
3071
+ } catch {
3072
+ }
3073
+ }
3074
+ }
3075
+ async function loadScopeFileForComponent(componentFilePath) {
3076
+ const scopeFilePath = findScopeFile(componentFilePath);
3077
+ if (scopeFilePath === null) return null;
3078
+ return loadScopeFile(scopeFilePath);
3079
+ }
3080
+ function extractScenarios(mod, filePath) {
3081
+ const raw = mod.scenarios ?? mod.default?.scenarios;
3082
+ if (raw === void 0) return {};
3083
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
3084
+ console.warn(`[scope] ${filePath}: "scenarios" export is not a plain object \u2014 ignoring.`);
3085
+ return {};
3086
+ }
3087
+ const result = {};
3088
+ for (const [name, props] of Object.entries(raw)) {
3089
+ if (typeof props !== "object" || props === null || Array.isArray(props)) {
3090
+ console.warn(`[scope] ${filePath}: scenario "${name}" is not a plain object \u2014 skipping.`);
3091
+ continue;
3092
+ }
3093
+ result[name] = props;
3094
+ }
3095
+ return result;
3096
+ }
3097
+ async function buildWrapperScript(scopeFilePath) {
3098
+ const wrapperEntry = (
3099
+ /* ts */
3100
+ `
3101
+ import * as __scopeMod from ${JSON.stringify(scopeFilePath)};
3102
+ // Expose the wrapper on window so the harness can access it
3103
+ var wrapper =
3104
+ __scopeMod.wrapper ??
3105
+ (__scopeMod.default && __scopeMod.default.wrapper) ??
3106
+ null;
3107
+ window.__SCOPE_WRAPPER__ = wrapper;
3108
+ `
3109
+ );
3110
+ const result = await esbuild2.build({
3111
+ stdin: {
3112
+ contents: wrapperEntry,
3113
+ resolveDir: dirname2(scopeFilePath),
3114
+ loader: "tsx",
3115
+ sourcefile: "__scope_wrapper_entry__.tsx"
3116
+ },
3117
+ bundle: true,
3118
+ format: "iife",
3119
+ platform: "browser",
3120
+ target: "es2020",
3121
+ write: false,
3122
+ jsx: "automatic",
3123
+ jsxImportSource: "react",
3124
+ external: [],
3125
+ define: {
3126
+ "process.env.NODE_ENV": '"development"',
3127
+ global: "globalThis"
3128
+ },
3129
+ logLevel: "silent"
3130
+ });
3131
+ if (result.errors.length > 0) {
3132
+ const msg = result.errors.map((e) => `${e.text}${e.location ? ` (${e.location.file}:${e.location.line})` : ""}`).join("\n");
3133
+ throw new Error(`Failed to build wrapper script from ${scopeFilePath}:
3134
+ ${msg}`);
3135
+ }
3136
+ return result.outputFiles?.[0]?.text ?? "";
3137
+ }
3138
+
3139
+ // src/render-commands.ts
2984
3140
  var MANIFEST_PATH6 = ".reactscope/manifest.json";
2985
3141
  var DEFAULT_OUTPUT_DIR = ".reactscope/renders";
2986
3142
  var _pool3 = null;
@@ -3001,7 +3157,7 @@ async function shutdownPool3() {
3001
3157
  _pool3 = null;
3002
3158
  }
3003
3159
  }
3004
- function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
3160
+ function buildRenderer(filePath, componentName, viewportWidth, viewportHeight, wrapperScript) {
3005
3161
  const satori = new SatoriRenderer({
3006
3162
  defaultViewport: { width: viewportWidth, height: viewportHeight }
3007
3163
  });
@@ -3014,7 +3170,10 @@ function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
3014
3170
  filePath,
3015
3171
  componentName,
3016
3172
  props,
3017
- viewportWidth
3173
+ viewportWidth,
3174
+ void 0,
3175
+ // projectCss (handled separately)
3176
+ wrapperScript
3018
3177
  );
3019
3178
  const slot = await pool.acquire();
3020
3179
  const { page } = slot;
@@ -3105,8 +3264,37 @@ function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
3105
3264
  }
3106
3265
  };
3107
3266
  }
3267
+ function buildScenarioMap(opts, scopeData) {
3268
+ if (opts.scenario !== void 0) {
3269
+ if (scopeData === null) {
3270
+ throw new Error(`--scenario "${opts.scenario}" requires a .scope file next to the component`);
3271
+ }
3272
+ const props = scopeData.scenarios[opts.scenario];
3273
+ if (props === void 0) {
3274
+ const available = Object.keys(scopeData.scenarios).join(", ") || "(none)";
3275
+ throw new Error(
3276
+ `Scenario "${opts.scenario}" not found in scope file.
3277
+ Available: ${available}`
3278
+ );
3279
+ }
3280
+ return { [opts.scenario]: props };
3281
+ }
3282
+ if (opts.props !== void 0) {
3283
+ let parsed;
3284
+ try {
3285
+ parsed = JSON.parse(opts.props);
3286
+ } catch {
3287
+ throw new Error(`Invalid props JSON: ${opts.props}`);
3288
+ }
3289
+ return { __default__: parsed };
3290
+ }
3291
+ if (scopeData !== null && Object.keys(scopeData.scenarios).length > 0) {
3292
+ return scopeData.scenarios;
3293
+ }
3294
+ return { __default__: {} };
3295
+ }
3108
3296
  function registerRenderSingle(renderCmd) {
3109
- 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(
3297
+ 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("--scenario <name>", "Run a named scenario from the component's .scope file").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(
3110
3298
  async (componentName, opts) => {
3111
3299
  try {
3112
3300
  const manifest = loadManifest(opts.manifest);
@@ -3118,80 +3306,71 @@ function registerRenderSingle(renderCmd) {
3118
3306
  Available: ${available}`
3119
3307
  );
3120
3308
  }
3121
- let props = {};
3122
- if (opts.props !== void 0) {
3123
- try {
3124
- props = JSON.parse(opts.props);
3125
- } catch {
3126
- throw new Error(`Invalid props JSON: ${opts.props}`);
3127
- }
3128
- }
3129
3309
  const { width, height } = parseViewport(opts.viewport);
3130
3310
  const rootDir = process.cwd();
3131
- const filePath = resolve8(rootDir, descriptor.filePath);
3132
- const renderer = buildRenderer(filePath, componentName, width, height);
3311
+ const filePath = resolve9(rootDir, descriptor.filePath);
3312
+ const scopeData = await loadScopeFileForComponent(filePath);
3313
+ const wrapperScript = scopeData?.hasWrapper === true ? await buildWrapperScript(scopeData.filePath) : void 0;
3314
+ const scenarios = buildScenarioMap(opts, scopeData);
3315
+ const renderer = buildRenderer(filePath, componentName, width, height, wrapperScript);
3133
3316
  process.stderr.write(
3134
3317
  `Rendering ${componentName} [${descriptor.complexityClass}] at ${width}\xD7${height}\u2026
3135
3318
  `
3136
3319
  );
3137
- const outcome = await safeRender2(
3138
- () => renderer.renderCell(props, descriptor.complexityClass),
3139
- {
3140
- props,
3141
- sourceLocation: {
3142
- file: descriptor.filePath,
3143
- line: descriptor.loc.start,
3144
- column: 0
3320
+ const fmt2 = resolveSingleFormat(opts.format);
3321
+ let anyFailed = false;
3322
+ for (const [scenarioName, props] of Object.entries(scenarios)) {
3323
+ const isNamed = scenarioName !== "__default__";
3324
+ const label = isNamed ? `${componentName}:${scenarioName}` : componentName;
3325
+ const outcome = await safeRender2(
3326
+ () => renderer.renderCell(props, descriptor.complexityClass),
3327
+ {
3328
+ props,
3329
+ sourceLocation: {
3330
+ file: descriptor.filePath,
3331
+ line: descriptor.loc.start,
3332
+ column: 0
3333
+ }
3145
3334
  }
3146
- }
3147
- );
3148
- await shutdownPool3();
3149
- if (outcome.crashed) {
3150
- process.stderr.write(`\u2717 Render failed: ${outcome.error.message}
3335
+ );
3336
+ if (outcome.crashed) {
3337
+ process.stderr.write(`\u2717 ${label} render failed: ${outcome.error.message}
3151
3338
  `);
3152
- const hintList = outcome.error.heuristicFlags.join(", ");
3153
- if (hintList.length > 0) {
3154
- process.stderr.write(` Hints: ${hintList}
3339
+ const hintList = outcome.error.heuristicFlags.join(", ");
3340
+ if (hintList.length > 0) {
3341
+ process.stderr.write(` Hints: ${hintList}
3155
3342
  `);
3343
+ }
3344
+ anyFailed = true;
3345
+ continue;
3156
3346
  }
3157
- process.exit(1);
3158
- }
3159
- const result = outcome.result;
3160
- if (opts.output !== void 0) {
3161
- const outPath = resolve8(process.cwd(), opts.output);
3162
- writeFileSync5(outPath, result.screenshot);
3163
- process.stdout.write(
3164
- `\u2713 ${componentName} \u2192 ${opts.output} (${result.width}\xD7${result.height}, ${result.renderTimeMs.toFixed(0)}ms)
3347
+ const result = outcome.result;
3348
+ const outFileName = isNamed ? `${componentName}-${scenarioName}.png` : `${componentName}.png`;
3349
+ if (opts.output !== void 0 && !isNamed) {
3350
+ const outPath = resolve9(process.cwd(), opts.output);
3351
+ writeFileSync5(outPath, result.screenshot);
3352
+ process.stdout.write(
3353
+ `\u2713 ${label} \u2192 ${opts.output} (${result.width}\xD7${result.height}, ${result.renderTimeMs.toFixed(0)}ms)
3165
3354
  `
3166
- );
3167
- return;
3168
- }
3169
- const fmt2 = resolveSingleFormat(opts.format);
3170
- if (fmt2 === "json") {
3171
- const json = formatRenderJson(componentName, props, result);
3172
- process.stdout.write(`${JSON.stringify(json, null, 2)}
3355
+ );
3356
+ } else if (fmt2 === "json") {
3357
+ const json = formatRenderJson(label, props, result);
3358
+ process.stdout.write(`${JSON.stringify(json, null, 2)}
3173
3359
  `);
3174
- } else if (fmt2 === "file") {
3175
- const dir = resolve8(process.cwd(), DEFAULT_OUTPUT_DIR);
3176
- mkdirSync3(dir, { recursive: true });
3177
- const outPath = resolve8(dir, `${componentName}.png`);
3178
- writeFileSync5(outPath, result.screenshot);
3179
- const relPath = `${DEFAULT_OUTPUT_DIR}/${componentName}.png`;
3180
- process.stdout.write(
3181
- `\u2713 ${componentName} \u2192 ${relPath} (${result.width}\xD7${result.height}, ${result.renderTimeMs.toFixed(0)}ms)
3182
- `
3183
- );
3184
- } else {
3185
- const dir = resolve8(process.cwd(), DEFAULT_OUTPUT_DIR);
3186
- mkdirSync3(dir, { recursive: true });
3187
- const outPath = resolve8(dir, `${componentName}.png`);
3188
- writeFileSync5(outPath, result.screenshot);
3189
- const relPath = `${DEFAULT_OUTPUT_DIR}/${componentName}.png`;
3190
- process.stdout.write(
3191
- `\u2713 ${componentName} \u2192 ${relPath} (${result.width}\xD7${result.height}, ${result.renderTimeMs.toFixed(0)}ms)
3360
+ } else {
3361
+ const dir = resolve9(process.cwd(), DEFAULT_OUTPUT_DIR);
3362
+ mkdirSync4(dir, { recursive: true });
3363
+ const outPath = resolve9(dir, outFileName);
3364
+ writeFileSync5(outPath, result.screenshot);
3365
+ const relPath = `${DEFAULT_OUTPUT_DIR}/${outFileName}`;
3366
+ process.stdout.write(
3367
+ `\u2713 ${label} \u2192 ${relPath} (${result.width}\xD7${result.height}, ${result.renderTimeMs.toFixed(0)}ms)
3192
3368
  `
3193
- );
3369
+ );
3370
+ }
3194
3371
  }
3372
+ await shutdownPool3();
3373
+ if (anyFailed) process.exit(1);
3195
3374
  } catch (err) {
3196
3375
  await shutdownPool3();
3197
3376
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
@@ -3220,7 +3399,7 @@ Available: ${available}`
3220
3399
  const concurrency = Math.max(1, parseInt(opts.concurrency, 10) || 8);
3221
3400
  const { width, height } = { width: 375, height: 812 };
3222
3401
  const rootDir = process.cwd();
3223
- const filePath = resolve8(rootDir, descriptor.filePath);
3402
+ const filePath = resolve9(rootDir, descriptor.filePath);
3224
3403
  const renderer = buildRenderer(filePath, componentName, width, height);
3225
3404
  const axes = [];
3226
3405
  if (opts.axes !== void 0) {
@@ -3287,7 +3466,7 @@ Available: ${available}`
3287
3466
  const { SpriteSheetGenerator: SpriteSheetGenerator2 } = await import("@agent-scope/render");
3288
3467
  const gen = new SpriteSheetGenerator2();
3289
3468
  const sheet = await gen.generate(result);
3290
- const spritePath = resolve8(process.cwd(), opts.sprite);
3469
+ const spritePath = resolve9(process.cwd(), opts.sprite);
3291
3470
  writeFileSync5(spritePath, sheet.png);
3292
3471
  process.stderr.write(`Sprite sheet saved to ${spritePath}
3293
3472
  `);
@@ -3297,9 +3476,9 @@ Available: ${available}`
3297
3476
  const { SpriteSheetGenerator: SpriteSheetGenerator2 } = await import("@agent-scope/render");
3298
3477
  const gen = new SpriteSheetGenerator2();
3299
3478
  const sheet = await gen.generate(result);
3300
- const dir = resolve8(process.cwd(), DEFAULT_OUTPUT_DIR);
3301
- mkdirSync3(dir, { recursive: true });
3302
- const outPath = resolve8(dir, `${componentName}-matrix.png`);
3479
+ const dir = resolve9(process.cwd(), DEFAULT_OUTPUT_DIR);
3480
+ mkdirSync4(dir, { recursive: true });
3481
+ const outPath = resolve9(dir, `${componentName}-matrix.png`);
3303
3482
  writeFileSync5(outPath, sheet.png);
3304
3483
  const relPath = `${DEFAULT_OUTPUT_DIR}/${componentName}-matrix.png`;
3305
3484
  process.stdout.write(
@@ -3343,8 +3522,8 @@ function registerRenderAll(renderCmd) {
3343
3522
  return;
3344
3523
  }
3345
3524
  const concurrency = Math.max(1, parseInt(opts.concurrency, 10) || 4);
3346
- const outputDir = resolve8(process.cwd(), opts.outputDir);
3347
- mkdirSync3(outputDir, { recursive: true });
3525
+ const outputDir = resolve9(process.cwd(), opts.outputDir);
3526
+ mkdirSync4(outputDir, { recursive: true });
3348
3527
  const rootDir = process.cwd();
3349
3528
  process.stderr.write(`Rendering ${total} components (concurrency: ${concurrency})\u2026
3350
3529
  `);
@@ -3353,7 +3532,7 @@ function registerRenderAll(renderCmd) {
3353
3532
  const renderOne = async (name) => {
3354
3533
  const descriptor = manifest.components[name];
3355
3534
  if (descriptor === void 0) return;
3356
- const filePath = resolve8(rootDir, descriptor.filePath);
3535
+ const filePath = resolve9(rootDir, descriptor.filePath);
3357
3536
  const renderer = buildRenderer(filePath, name, 375, 812);
3358
3537
  const outcome = await safeRender2(
3359
3538
  () => renderer.renderCell({}, descriptor.complexityClass),
@@ -3376,7 +3555,7 @@ function registerRenderAll(renderCmd) {
3376
3555
  success: false,
3377
3556
  errorMessage: outcome.error.message
3378
3557
  });
3379
- const errPath = resolve8(outputDir, `${name}.error.json`);
3558
+ const errPath = resolve9(outputDir, `${name}.error.json`);
3380
3559
  writeFileSync5(
3381
3560
  errPath,
3382
3561
  JSON.stringify(
@@ -3394,9 +3573,9 @@ function registerRenderAll(renderCmd) {
3394
3573
  }
3395
3574
  const result = outcome.result;
3396
3575
  results.push({ name, renderTimeMs: result.renderTimeMs, success: true });
3397
- const pngPath = resolve8(outputDir, `${name}.png`);
3576
+ const pngPath = resolve9(outputDir, `${name}.png`);
3398
3577
  writeFileSync5(pngPath, result.screenshot);
3399
- const jsonPath = resolve8(outputDir, `${name}.json`);
3578
+ const jsonPath = resolve9(outputDir, `${name}.json`);
3400
3579
  writeFileSync5(jsonPath, JSON.stringify(formatRenderJson(name, {}, result), null, 2));
3401
3580
  if (isTTY()) {
3402
3581
  process.stdout.write(
@@ -3469,8 +3648,8 @@ function createRenderCommand() {
3469
3648
  }
3470
3649
 
3471
3650
  // src/report/baseline.ts
3472
- import { existsSync as existsSync6, mkdirSync as mkdirSync4, rmSync, writeFileSync as writeFileSync6 } from "fs";
3473
- import { resolve as resolve9 } from "path";
3651
+ import { existsSync as existsSync7, mkdirSync as mkdirSync5, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "fs";
3652
+ import { resolve as resolve10 } from "path";
3474
3653
  import { generateManifest as generateManifest3 } from "@agent-scope/manifest";
3475
3654
  import { BrowserPool as BrowserPool4, safeRender as safeRender3 } from "@agent-scope/render";
3476
3655
  import { ComplianceEngine as ComplianceEngine2, TokenResolver as TokenResolver2 } from "@agent-scope/tokens";
@@ -3619,17 +3798,17 @@ async function runBaseline(options = {}) {
3619
3798
  } = options;
3620
3799
  const startTime = performance.now();
3621
3800
  const rootDir = process.cwd();
3622
- const baselineDir = resolve9(rootDir, outputDir);
3623
- const rendersDir = resolve9(baselineDir, "renders");
3624
- if (existsSync6(baselineDir)) {
3625
- rmSync(baselineDir, { recursive: true, force: true });
3801
+ const baselineDir = resolve10(rootDir, outputDir);
3802
+ const rendersDir = resolve10(baselineDir, "renders");
3803
+ if (existsSync7(baselineDir)) {
3804
+ rmSync2(baselineDir, { recursive: true, force: true });
3626
3805
  }
3627
- mkdirSync4(rendersDir, { recursive: true });
3806
+ mkdirSync5(rendersDir, { recursive: true });
3628
3807
  let manifest;
3629
3808
  if (manifestPath !== void 0) {
3630
3809
  const { readFileSync: readFileSync12 } = await import("fs");
3631
- const absPath = resolve9(rootDir, manifestPath);
3632
- if (!existsSync6(absPath)) {
3810
+ const absPath = resolve10(rootDir, manifestPath);
3811
+ if (!existsSync7(absPath)) {
3633
3812
  throw new Error(`Manifest not found at ${absPath}.`);
3634
3813
  }
3635
3814
  manifest = JSON.parse(readFileSync12(absPath, "utf-8"));
@@ -3642,7 +3821,7 @@ async function runBaseline(options = {}) {
3642
3821
  process.stderr.write(`Found ${count} components.
3643
3822
  `);
3644
3823
  }
3645
- writeFileSync6(resolve9(baselineDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
3824
+ writeFileSync6(resolve10(baselineDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
3646
3825
  let componentNames = Object.keys(manifest.components);
3647
3826
  if (componentsGlob !== void 0) {
3648
3827
  componentNames = componentNames.filter((name) => matchGlob(componentsGlob, name));
@@ -3663,7 +3842,7 @@ async function runBaseline(options = {}) {
3663
3842
  auditedAt: (/* @__PURE__ */ new Date()).toISOString()
3664
3843
  };
3665
3844
  writeFileSync6(
3666
- resolve9(baselineDir, "compliance.json"),
3845
+ resolve10(baselineDir, "compliance.json"),
3667
3846
  JSON.stringify(emptyReport, null, 2),
3668
3847
  "utf-8"
3669
3848
  );
@@ -3684,7 +3863,7 @@ async function runBaseline(options = {}) {
3684
3863
  const renderOne = async (name) => {
3685
3864
  const descriptor = manifest.components[name];
3686
3865
  if (descriptor === void 0) return;
3687
- const filePath = resolve9(rootDir, descriptor.filePath);
3866
+ const filePath = resolve10(rootDir, descriptor.filePath);
3688
3867
  const outcome = await safeRender3(
3689
3868
  () => renderComponent2(filePath, name, {}, viewportWidth, viewportHeight),
3690
3869
  {
@@ -3703,7 +3882,7 @@ async function runBaseline(options = {}) {
3703
3882
  }
3704
3883
  if (outcome.crashed) {
3705
3884
  failureCount++;
3706
- const errPath = resolve9(rendersDir, `${name}.error.json`);
3885
+ const errPath = resolve10(rendersDir, `${name}.error.json`);
3707
3886
  writeFileSync6(
3708
3887
  errPath,
3709
3888
  JSON.stringify(
@@ -3721,10 +3900,10 @@ async function runBaseline(options = {}) {
3721
3900
  return;
3722
3901
  }
3723
3902
  const result = outcome.result;
3724
- writeFileSync6(resolve9(rendersDir, `${name}.png`), result.screenshot);
3903
+ writeFileSync6(resolve10(rendersDir, `${name}.png`), result.screenshot);
3725
3904
  const jsonOutput = formatRenderJson(name, {}, result);
3726
3905
  writeFileSync6(
3727
- resolve9(rendersDir, `${name}.json`),
3906
+ resolve10(rendersDir, `${name}.json`),
3728
3907
  JSON.stringify(jsonOutput, null, 2),
3729
3908
  "utf-8"
3730
3909
  );
@@ -3752,7 +3931,7 @@ async function runBaseline(options = {}) {
3752
3931
  const engine = new ComplianceEngine2(resolver);
3753
3932
  const batchReport = engine.auditBatch(computedStylesMap);
3754
3933
  writeFileSync6(
3755
- resolve9(baselineDir, "compliance.json"),
3934
+ resolve10(baselineDir, "compliance.json"),
3756
3935
  JSON.stringify(batchReport, null, 2),
3757
3936
  "utf-8"
3758
3937
  );
@@ -3795,21 +3974,21 @@ function registerBaselineSubCommand(reportCmd) {
3795
3974
  }
3796
3975
 
3797
3976
  // src/report/diff.ts
3798
- import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync7 } from "fs";
3799
- import { resolve as resolve10 } from "path";
3977
+ import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync7 } from "fs";
3978
+ import { resolve as resolve11 } from "path";
3800
3979
  import { generateManifest as generateManifest4 } from "@agent-scope/manifest";
3801
3980
  import { BrowserPool as BrowserPool5, safeRender as safeRender4 } from "@agent-scope/render";
3802
3981
  import { ComplianceEngine as ComplianceEngine3, TokenResolver as TokenResolver3 } from "@agent-scope/tokens";
3803
3982
  var DEFAULT_BASELINE_DIR2 = ".reactscope/baseline";
3804
3983
  function loadBaselineCompliance(baselineDir) {
3805
- const compliancePath = resolve10(baselineDir, "compliance.json");
3806
- if (!existsSync7(compliancePath)) return null;
3984
+ const compliancePath = resolve11(baselineDir, "compliance.json");
3985
+ if (!existsSync8(compliancePath)) return null;
3807
3986
  const raw = JSON.parse(readFileSync6(compliancePath, "utf-8"));
3808
3987
  return raw;
3809
3988
  }
3810
3989
  function loadBaselineRenderJson2(baselineDir, componentName) {
3811
- const jsonPath = resolve10(baselineDir, "renders", `${componentName}.json`);
3812
- if (!existsSync7(jsonPath)) return null;
3990
+ const jsonPath = resolve11(baselineDir, "renders", `${componentName}.json`);
3991
+ if (!existsSync8(jsonPath)) return null;
3813
3992
  return JSON.parse(readFileSync6(jsonPath, "utf-8"));
3814
3993
  }
3815
3994
  var _pool5 = null;
@@ -3977,14 +4156,14 @@ async function runDiff(options = {}) {
3977
4156
  } = options;
3978
4157
  const startTime = performance.now();
3979
4158
  const rootDir = process.cwd();
3980
- const baselineDir = resolve10(rootDir, baselineDirRaw);
3981
- if (!existsSync7(baselineDir)) {
4159
+ const baselineDir = resolve11(rootDir, baselineDirRaw);
4160
+ if (!existsSync8(baselineDir)) {
3982
4161
  throw new Error(
3983
4162
  `Baseline directory not found at "${baselineDir}". Run \`scope report baseline\` first to create a baseline snapshot.`
3984
4163
  );
3985
4164
  }
3986
- const baselineManifestPath = resolve10(baselineDir, "manifest.json");
3987
- if (!existsSync7(baselineManifestPath)) {
4165
+ const baselineManifestPath = resolve11(baselineDir, "manifest.json");
4166
+ if (!existsSync8(baselineManifestPath)) {
3988
4167
  throw new Error(
3989
4168
  `Baseline manifest.json not found at "${baselineManifestPath}". The baseline directory may be incomplete \u2014 re-run \`scope report baseline\`.`
3990
4169
  );
@@ -3998,8 +4177,8 @@ async function runDiff(options = {}) {
3998
4177
  );
3999
4178
  let currentManifest;
4000
4179
  if (manifestPath !== void 0) {
4001
- const absPath = resolve10(rootDir, manifestPath);
4002
- if (!existsSync7(absPath)) {
4180
+ const absPath = resolve11(rootDir, manifestPath);
4181
+ if (!existsSync8(absPath)) {
4003
4182
  throw new Error(`Manifest not found at "${absPath}".`);
4004
4183
  }
4005
4184
  currentManifest = JSON.parse(readFileSync6(absPath, "utf-8"));
@@ -4035,7 +4214,7 @@ async function runDiff(options = {}) {
4035
4214
  const renderOne = async (name) => {
4036
4215
  const descriptor = currentManifest.components[name];
4037
4216
  if (descriptor === void 0) return;
4038
- const filePath = resolve10(rootDir, descriptor.filePath);
4217
+ const filePath = resolve11(rootDir, descriptor.filePath);
4039
4218
  const outcome = await safeRender4(
4040
4219
  () => renderComponent3(filePath, name, {}, viewportWidth, viewportHeight),
4041
4220
  {
@@ -4275,8 +4454,8 @@ function registerDiffSubCommand(reportCmd) {
4275
4454
  }
4276
4455
 
4277
4456
  // src/report/pr-comment.ts
4278
- import { existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync8 } from "fs";
4279
- import { resolve as resolve11 } from "path";
4457
+ import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync8 } from "fs";
4458
+ import { resolve as resolve12 } from "path";
4280
4459
  var STATUS_BADGE = {
4281
4460
  added: "\u2705 added",
4282
4461
  removed: "\u{1F5D1}\uFE0F removed",
@@ -4359,8 +4538,8 @@ function formatPrComment(diff) {
4359
4538
  return lines.join("\n");
4360
4539
  }
4361
4540
  function loadDiffResult(filePath) {
4362
- const abs = resolve11(filePath);
4363
- if (!existsSync8(abs)) {
4541
+ const abs = resolve12(filePath);
4542
+ if (!existsSync9(abs)) {
4364
4543
  throw new Error(`DiffResult file not found: ${abs}`);
4365
4544
  }
4366
4545
  let raw;
@@ -4392,7 +4571,7 @@ function registerPrCommentSubCommand(reportCmd) {
4392
4571
  const diff = loadDiffResult(opts.input);
4393
4572
  const comment = formatPrComment(diff);
4394
4573
  if (opts.output !== void 0) {
4395
- writeFileSync8(resolve11(opts.output), comment, "utf-8");
4574
+ writeFileSync8(resolve12(opts.output), comment, "utf-8");
4396
4575
  process.stderr.write(`PR comment written to ${opts.output}
4397
4576
  `);
4398
4577
  } else {
@@ -4687,9 +4866,9 @@ function buildStructuredReport(report) {
4687
4866
  }
4688
4867
 
4689
4868
  // src/site-commands.ts
4690
- import { createReadStream, existsSync as existsSync9, statSync } from "fs";
4869
+ import { createReadStream, existsSync as existsSync10, statSync } from "fs";
4691
4870
  import { createServer } from "http";
4692
- import { extname, join as join3, resolve as resolve12 } from "path";
4871
+ import { extname, join as join4, resolve as resolve13 } from "path";
4693
4872
  import { buildSite } from "@agent-scope/site";
4694
4873
  import { Command as Command7 } from "commander";
4695
4874
  var MIME_TYPES = {
@@ -4707,16 +4886,16 @@ function registerBuild(siteCmd) {
4707
4886
  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
4887
  async (opts) => {
4709
4888
  try {
4710
- const inputDir = resolve12(process.cwd(), opts.input);
4711
- const outputDir = resolve12(process.cwd(), opts.output);
4712
- if (!existsSync9(inputDir)) {
4889
+ const inputDir = resolve13(process.cwd(), opts.input);
4890
+ const outputDir = resolve13(process.cwd(), opts.output);
4891
+ if (!existsSync10(inputDir)) {
4713
4892
  throw new Error(
4714
4893
  `Input directory not found: ${inputDir}
4715
4894
  Run \`scope manifest generate\` and \`scope render\` first.`
4716
4895
  );
4717
4896
  }
4718
- const manifestPath = join3(inputDir, "manifest.json");
4719
- if (!existsSync9(manifestPath)) {
4897
+ const manifestPath = join4(inputDir, "manifest.json");
4898
+ if (!existsSync10(manifestPath)) {
4720
4899
  throw new Error(
4721
4900
  `Manifest not found at ${manifestPath}
4722
4901
  Run \`scope manifest generate\` first.`
@@ -4729,7 +4908,7 @@ Run \`scope manifest generate\` first.`
4729
4908
  outputDir,
4730
4909
  basePath: opts.basePath,
4731
4910
  ...opts.compliance !== void 0 && {
4732
- compliancePath: resolve12(process.cwd(), opts.compliance)
4911
+ compliancePath: resolve13(process.cwd(), opts.compliance)
4733
4912
  },
4734
4913
  title: opts.title
4735
4914
  });
@@ -4752,8 +4931,8 @@ function registerServe(siteCmd) {
4752
4931
  if (Number.isNaN(port) || port < 1 || port > 65535) {
4753
4932
  throw new Error(`Invalid port: ${opts.port}`);
4754
4933
  }
4755
- const serveDir = resolve12(process.cwd(), opts.dir);
4756
- if (!existsSync9(serveDir)) {
4934
+ const serveDir = resolve13(process.cwd(), opts.dir);
4935
+ if (!existsSync10(serveDir)) {
4757
4936
  throw new Error(
4758
4937
  `Serve directory not found: ${serveDir}
4759
4938
  Run \`scope site build\` first.`
@@ -4762,13 +4941,13 @@ Run \`scope site build\` first.`
4762
4941
  const server = createServer((req, res) => {
4763
4942
  const rawUrl = req.url ?? "/";
4764
4943
  const urlPath = decodeURIComponent(rawUrl.split("?")[0] ?? "/");
4765
- const filePath = join3(serveDir, urlPath.endsWith("/") ? `${urlPath}index.html` : urlPath);
4944
+ const filePath = join4(serveDir, urlPath.endsWith("/") ? `${urlPath}index.html` : urlPath);
4766
4945
  if (!filePath.startsWith(serveDir)) {
4767
4946
  res.writeHead(403, { "Content-Type": "text/plain" });
4768
4947
  res.end("Forbidden");
4769
4948
  return;
4770
4949
  }
4771
- if (existsSync9(filePath) && statSync(filePath).isFile()) {
4950
+ if (existsSync10(filePath) && statSync(filePath).isFile()) {
4772
4951
  const ext = extname(filePath).toLowerCase();
4773
4952
  const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
4774
4953
  res.writeHead(200, { "Content-Type": contentType });
@@ -4776,7 +4955,7 @@ Run \`scope site build\` first.`
4776
4955
  return;
4777
4956
  }
4778
4957
  const htmlPath = `${filePath}.html`;
4779
- if (existsSync9(htmlPath) && statSync(htmlPath).isFile()) {
4958
+ if (existsSync10(htmlPath) && statSync(htmlPath).isFile()) {
4780
4959
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
4781
4960
  createReadStream(htmlPath).pipe(res);
4782
4961
  return;
@@ -4818,8 +4997,8 @@ function createSiteCommand() {
4818
4997
  }
4819
4998
 
4820
4999
  // src/tokens/commands.ts
4821
- import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
4822
- import { resolve as resolve16 } from "path";
5000
+ import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
5001
+ import { resolve as resolve17 } from "path";
4823
5002
  import {
4824
5003
  parseTokenFileSync as parseTokenFileSync2,
4825
5004
  TokenParseError,
@@ -4830,16 +5009,16 @@ import {
4830
5009
  import { Command as Command9 } from "commander";
4831
5010
 
4832
5011
  // src/tokens/compliance.ts
4833
- import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
4834
- import { resolve as resolve13 } from "path";
5012
+ import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
5013
+ import { resolve as resolve14 } from "path";
4835
5014
  import {
4836
5015
  ComplianceEngine as ComplianceEngine4,
4837
5016
  TokenResolver as TokenResolver4
4838
5017
  } from "@agent-scope/tokens";
4839
5018
  var DEFAULT_STYLES_PATH = ".reactscope/compliance-styles.json";
4840
5019
  function loadStylesFile(stylesPath) {
4841
- const absPath = resolve13(process.cwd(), stylesPath);
4842
- if (!existsSync10(absPath)) {
5020
+ const absPath = resolve14(process.cwd(), stylesPath);
5021
+ if (!existsSync11(absPath)) {
4843
5022
  throw new Error(
4844
5023
  `Compliance styles file not found at ${absPath}.
4845
5024
  Run \`scope render all\` first to generate component styles, or use --styles to specify a path.
@@ -5006,8 +5185,8 @@ function registerCompliance(tokensCmd) {
5006
5185
  }
5007
5186
 
5008
5187
  // src/tokens/export.ts
5009
- import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "fs";
5010
- import { resolve as resolve14 } from "path";
5188
+ import { existsSync as existsSync12, readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "fs";
5189
+ import { resolve as resolve15 } from "path";
5011
5190
  import {
5012
5191
  exportTokens,
5013
5192
  parseTokenFileSync,
@@ -5020,21 +5199,21 @@ var CONFIG_FILE = "reactscope.config.json";
5020
5199
  var SUPPORTED_FORMATS = ["css", "ts", "scss", "tailwind", "flat-json", "figma"];
5021
5200
  function resolveTokenFilePath2(fileFlag) {
5022
5201
  if (fileFlag !== void 0) {
5023
- return resolve14(process.cwd(), fileFlag);
5202
+ return resolve15(process.cwd(), fileFlag);
5024
5203
  }
5025
- const configPath = resolve14(process.cwd(), CONFIG_FILE);
5026
- if (existsSync11(configPath)) {
5204
+ const configPath = resolve15(process.cwd(), CONFIG_FILE);
5205
+ if (existsSync12(configPath)) {
5027
5206
  try {
5028
5207
  const raw = readFileSync9(configPath, "utf-8");
5029
5208
  const config = JSON.parse(raw);
5030
5209
  if (typeof config === "object" && config !== null && "tokens" in config && typeof config.tokens === "object" && config.tokens !== null && typeof config.tokens?.file === "string") {
5031
5210
  const file = config.tokens.file;
5032
- return resolve14(process.cwd(), file);
5211
+ return resolve15(process.cwd(), file);
5033
5212
  }
5034
5213
  } catch {
5035
5214
  }
5036
5215
  }
5037
- return resolve14(process.cwd(), DEFAULT_TOKEN_FILE);
5216
+ return resolve15(process.cwd(), DEFAULT_TOKEN_FILE);
5038
5217
  }
5039
5218
  function createTokensExportCommand() {
5040
5219
  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(
@@ -5053,7 +5232,7 @@ Supported formats: ${SUPPORTED_FORMATS.join(", ")}
5053
5232
  const format = opts.format;
5054
5233
  try {
5055
5234
  const filePath = resolveTokenFilePath2(opts.file);
5056
- if (!existsSync11(filePath)) {
5235
+ if (!existsSync12(filePath)) {
5057
5236
  throw new Error(
5058
5237
  `Token file not found at ${filePath}.
5059
5238
  Create a reactscope.tokens.json file or use --file to specify a path.`
@@ -5098,7 +5277,7 @@ Available themes: ${themeNames.join(", ")}`
5098
5277
  themes: themesMap
5099
5278
  });
5100
5279
  if (opts.out !== void 0) {
5101
- const outPath = resolve14(process.cwd(), opts.out);
5280
+ const outPath = resolve15(process.cwd(), opts.out);
5102
5281
  writeFileSync9(outPath, output, "utf-8");
5103
5282
  process.stderr.write(`Exported ${tokens.length} tokens to ${outPath}
5104
5283
  `);
@@ -5213,8 +5392,8 @@ ${formatImpactSummary(report)}
5213
5392
  }
5214
5393
 
5215
5394
  // src/tokens/preview.ts
5216
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync10 } from "fs";
5217
- import { resolve as resolve15 } from "path";
5395
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync10 } from "fs";
5396
+ import { resolve as resolve16 } from "path";
5218
5397
  import { BrowserPool as BrowserPool6, SpriteSheetGenerator } from "@agent-scope/render";
5219
5398
  import { ComplianceEngine as ComplianceEngine6, ImpactAnalyzer as ImpactAnalyzer2, TokenResolver as TokenResolver7 } from "@agent-scope/tokens";
5220
5399
  var DEFAULT_STYLES_PATH3 = ".reactscope/compliance-styles.json";
@@ -5395,9 +5574,9 @@ function registerPreview(tokensCmd) {
5395
5574
  });
5396
5575
  const spriteResult = await generator.generate(matrixResult);
5397
5576
  const tokenLabel = tokenPath.replace(/\./g, "-");
5398
- const outputPath = opts.output ?? resolve15(process.cwd(), DEFAULT_OUTPUT_DIR2, `preview-${tokenLabel}.png`);
5399
- const outputDir = resolve15(outputPath, "..");
5400
- mkdirSync5(outputDir, { recursive: true });
5577
+ const outputPath = opts.output ?? resolve16(process.cwd(), DEFAULT_OUTPUT_DIR2, `preview-${tokenLabel}.png`);
5578
+ const outputDir = resolve16(outputPath, "..");
5579
+ mkdirSync6(outputDir, { recursive: true });
5401
5580
  writeFileSync10(outputPath, spriteResult.png);
5402
5581
  const useJson = opts.format === "json" || opts.format !== "text" && !isTTY();
5403
5582
  if (useJson) {
@@ -5457,24 +5636,24 @@ function buildTable2(headers, rows) {
5457
5636
  }
5458
5637
  function resolveTokenFilePath(fileFlag) {
5459
5638
  if (fileFlag !== void 0) {
5460
- return resolve16(process.cwd(), fileFlag);
5639
+ return resolve17(process.cwd(), fileFlag);
5461
5640
  }
5462
- const configPath = resolve16(process.cwd(), CONFIG_FILE2);
5463
- if (existsSync12(configPath)) {
5641
+ const configPath = resolve17(process.cwd(), CONFIG_FILE2);
5642
+ if (existsSync13(configPath)) {
5464
5643
  try {
5465
5644
  const raw = readFileSync10(configPath, "utf-8");
5466
5645
  const config = JSON.parse(raw);
5467
5646
  if (typeof config === "object" && config !== null && "tokens" in config && typeof config.tokens === "object" && config.tokens !== null && typeof config.tokens?.file === "string") {
5468
5647
  const file = config.tokens.file;
5469
- return resolve16(process.cwd(), file);
5648
+ return resolve17(process.cwd(), file);
5470
5649
  }
5471
5650
  } catch {
5472
5651
  }
5473
5652
  }
5474
- return resolve16(process.cwd(), DEFAULT_TOKEN_FILE2);
5653
+ return resolve17(process.cwd(), DEFAULT_TOKEN_FILE2);
5475
5654
  }
5476
5655
  function loadTokens(absPath) {
5477
- if (!existsSync12(absPath)) {
5656
+ if (!existsSync13(absPath)) {
5478
5657
  throw new Error(
5479
5658
  `Token file not found at ${absPath}.
5480
5659
  Create a reactscope.tokens.json file or use --file to specify a path.`
@@ -5694,7 +5873,7 @@ function registerValidate(tokensCmd) {
5694
5873
  ).option("--file <path>", "Path to token file (overrides config)").option("--format <fmt>", "Output format: json or text (default: auto-detect)").action((opts) => {
5695
5874
  try {
5696
5875
  const filePath = resolveTokenFilePath(opts.file);
5697
- if (!existsSync12(filePath)) {
5876
+ if (!existsSync13(filePath)) {
5698
5877
  throw new Error(
5699
5878
  `Token file not found at ${filePath}.
5700
5879
  Create a reactscope.tokens.json file or use --file to specify a path.`