@agent-scope/cli 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import { loadTrace, generateTest, getBrowserEntryScript } from '@agent-scope/pla
6
6
  import { chromium } from 'playwright';
7
7
  import { safeRender, ALL_CONTEXT_IDS, contextAxis, stressAxis, ALL_STRESS_IDS, RenderMatrix, SatoriRenderer, BrowserPool } from '@agent-scope/render';
8
8
  import * as esbuild from 'esbuild';
9
+ import { createRequire } from 'module';
9
10
 
10
11
  // src/manifest-commands.ts
11
12
 
@@ -315,7 +316,7 @@ function writeReportToFile(report, outputPath, pretty) {
315
316
  const json = pretty ? JSON.stringify(report, null, 2) : JSON.stringify(report);
316
317
  writeFileSync(outputPath, json, "utf-8");
317
318
  }
318
- async function buildComponentHarness(filePath, componentName, props, viewportWidth) {
319
+ async function buildComponentHarness(filePath, componentName, props, viewportWidth, projectCss) {
319
320
  const bundledScript = await bundleComponentToIIFE(filePath, componentName, props);
320
321
  return wrapInHtml(bundledScript, viewportWidth);
321
322
  }
@@ -403,7 +404,8 @@ ${msg}`);
403
404
  }
404
405
  return outputFile.text;
405
406
  }
406
- function wrapInHtml(bundledScript, viewportWidth) {
407
+ function wrapInHtml(bundledScript, viewportWidth, projectCss) {
408
+ const projectStyleBlock = "";
407
409
  return `<!DOCTYPE html>
408
410
  <html lang="en">
409
411
  <head>
@@ -414,6 +416,7 @@ function wrapInHtml(bundledScript, viewportWidth) {
414
416
  html, body { margin: 0; padding: 0; background: #fff; font-family: system-ui, sans-serif; }
415
417
  #scope-root { display: inline-block; min-width: 1px; min-height: 1px; }
416
418
  </style>
419
+ ${projectStyleBlock}
417
420
  </head>
418
421
  <body>
419
422
  <div id="scope-root" data-reactscope-root></div>
@@ -581,6 +584,121 @@ function csvEscape(value) {
581
584
  }
582
585
  return value;
583
586
  }
587
+ var CONFIG_FILENAMES = [
588
+ ".reactscope/config.json",
589
+ ".reactscope/config.js",
590
+ ".reactscope/config.mjs"
591
+ ];
592
+ var STYLE_ENTRY_CANDIDATES = [
593
+ "src/index.css",
594
+ "src/globals.css",
595
+ "app/globals.css",
596
+ "app/index.css",
597
+ "styles/index.css",
598
+ "index.css"
599
+ ];
600
+ var TAILWIND_IMPORT = /@import\s+["']tailwindcss["']\s*;?/;
601
+ var compilerCache = null;
602
+ function getCachedBuild(cwd) {
603
+ if (compilerCache !== null && resolve(compilerCache.cwd) === resolve(cwd)) {
604
+ return compilerCache.build;
605
+ }
606
+ return null;
607
+ }
608
+ function findStylesEntry(cwd) {
609
+ for (const name of CONFIG_FILENAMES) {
610
+ const p = resolve(cwd, name);
611
+ if (!existsSync(p)) continue;
612
+ try {
613
+ if (name.endsWith(".json")) {
614
+ const raw = readFileSync(p, "utf-8");
615
+ const data = JSON.parse(raw);
616
+ const scope = data.scope;
617
+ const entry = scope?.stylesEntry ?? data.stylesEntry;
618
+ if (typeof entry === "string") {
619
+ const full = resolve(cwd, entry);
620
+ if (existsSync(full)) return full;
621
+ }
622
+ }
623
+ } catch {
624
+ }
625
+ }
626
+ const pkgPath = resolve(cwd, "package.json");
627
+ if (existsSync(pkgPath)) {
628
+ try {
629
+ const raw = readFileSync(pkgPath, "utf-8");
630
+ const pkg = JSON.parse(raw);
631
+ const entry = pkg.scope?.stylesEntry;
632
+ if (typeof entry === "string") {
633
+ const full = resolve(cwd, entry);
634
+ if (existsSync(full)) return full;
635
+ }
636
+ } catch {
637
+ }
638
+ }
639
+ for (const candidate of STYLE_ENTRY_CANDIDATES) {
640
+ const full = resolve(cwd, candidate);
641
+ if (existsSync(full)) {
642
+ try {
643
+ const content = readFileSync(full, "utf-8");
644
+ if (TAILWIND_IMPORT.test(content)) return full;
645
+ } catch {
646
+ }
647
+ }
648
+ }
649
+ return null;
650
+ }
651
+ async function getTailwindCompiler(cwd) {
652
+ const cached = getCachedBuild(cwd);
653
+ if (cached !== null) return cached;
654
+ const entryPath = findStylesEntry(cwd);
655
+ if (entryPath === null) return null;
656
+ let compile;
657
+ try {
658
+ const require2 = createRequire(resolve(cwd, "package.json"));
659
+ const tailwind = require2("tailwindcss");
660
+ const fn = tailwind.compile;
661
+ if (typeof fn !== "function") return null;
662
+ compile = fn;
663
+ } catch {
664
+ return null;
665
+ }
666
+ const entryContent = readFileSync(entryPath, "utf-8");
667
+ const loadStylesheet = async (id, base) => {
668
+ if (id === "tailwindcss") {
669
+ const nodeModules = resolve(cwd, "node_modules");
670
+ const tailwindCssPath = resolve(nodeModules, "tailwindcss", "index.css");
671
+ if (!existsSync(tailwindCssPath)) {
672
+ throw new Error(
673
+ `Tailwind v4: tailwindcss package not found at ${tailwindCssPath}. Install with: npm install tailwindcss`
674
+ );
675
+ }
676
+ const content = readFileSync(tailwindCssPath, "utf-8");
677
+ return { path: "virtual:tailwindcss/index.css", base, content };
678
+ }
679
+ const full = resolve(base, id);
680
+ if (existsSync(full)) {
681
+ const content = readFileSync(full, "utf-8");
682
+ return { path: full, base: resolve(full, ".."), content };
683
+ }
684
+ throw new Error(`Tailwind v4: could not load stylesheet: ${id} (base: ${base})`);
685
+ };
686
+ const result = await compile(entryContent, {
687
+ base: cwd,
688
+ from: entryPath,
689
+ loadStylesheet
690
+ });
691
+ const build2 = result.build.bind(result);
692
+ compilerCache = { cwd, build: build2 };
693
+ return build2;
694
+ }
695
+ async function getCompiledCssForClasses(cwd, classes) {
696
+ const build2 = await getTailwindCompiler(cwd);
697
+ if (build2 === null) return null;
698
+ const deduped = [...new Set(classes)].filter(Boolean);
699
+ if (deduped.length === 0) return null;
700
+ return build2(deduped);
701
+ }
584
702
 
585
703
  // src/render-commands.ts
586
704
  var MANIFEST_PATH2 = ".reactscope/manifest.json";
@@ -635,6 +753,20 @@ function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
635
753
  if (renderError !== null) {
636
754
  throw new Error(`Component render error: ${renderError}`);
637
755
  }
756
+ const rootDir = process.cwd();
757
+ const classes = await page.evaluate(() => {
758
+ const set = /* @__PURE__ */ new Set();
759
+ document.querySelectorAll("[class]").forEach((el) => {
760
+ for (const c of el.className.split(/\s+/)) {
761
+ if (c) set.add(c);
762
+ }
763
+ });
764
+ return [...set];
765
+ });
766
+ const projectCss = await getCompiledCssForClasses(rootDir, classes);
767
+ if (projectCss != null && projectCss.length > 0) {
768
+ await page.addStyleTag({ content: projectCss });
769
+ }
638
770
  const renderTimeMs = performance.now() - startMs;
639
771
  const rootLocator = page.locator("[data-reactscope-root]");
640
772
  const boundingBox = await rootLocator.boundingBox();