@agent-scope/cli 1.15.0 → 1.17.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 +323 -57
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +272 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +274 -17
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/program.ts
|
|
4
|
-
import { readFileSync as
|
|
4
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
5
5
|
import { generateTest, loadTrace } from "@agent-scope/playwright";
|
|
6
|
-
import { Command as
|
|
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((
|
|
1177
|
+
return new Promise((resolve17) => {
|
|
1178
1178
|
rl.question(question, (answer) => {
|
|
1179
|
-
|
|
1179
|
+
resolve17(answer.trim());
|
|
1180
1180
|
});
|
|
1181
1181
|
});
|
|
1182
1182
|
}
|
|
@@ -2485,8 +2485,8 @@ Available: ${available}`
|
|
|
2485
2485
|
wastedRenders: opts.wastedRenders
|
|
2486
2486
|
});
|
|
2487
2487
|
await shutdownPool2();
|
|
2488
|
-
const
|
|
2489
|
-
if (
|
|
2488
|
+
const fmt2 = resolveFormat2(opts.format);
|
|
2489
|
+
if (fmt2 === "json") {
|
|
2490
2490
|
process.stdout.write(`${JSON.stringify(instrumentRoot, null, 2)}
|
|
2491
2491
|
`);
|
|
2492
2492
|
} else {
|
|
@@ -3182,12 +3182,12 @@ Available: ${available}`
|
|
|
3182
3182
|
);
|
|
3183
3183
|
return;
|
|
3184
3184
|
}
|
|
3185
|
-
const
|
|
3186
|
-
if (
|
|
3185
|
+
const fmt2 = resolveSingleFormat(opts.format);
|
|
3186
|
+
if (fmt2 === "json") {
|
|
3187
3187
|
const json = formatRenderJson(componentName, props, result);
|
|
3188
3188
|
process.stdout.write(`${JSON.stringify(json, null, 2)}
|
|
3189
3189
|
`);
|
|
3190
|
-
} else if (
|
|
3190
|
+
} else if (fmt2 === "file") {
|
|
3191
3191
|
const dir = resolve8(process.cwd(), DEFAULT_OUTPUT_DIR);
|
|
3192
3192
|
mkdirSync3(dir, { recursive: true });
|
|
3193
3193
|
const outPath = resolve8(dir, `${componentName}.png`);
|
|
@@ -3308,8 +3308,8 @@ Available: ${available}`
|
|
|
3308
3308
|
process.stderr.write(`Sprite sheet saved to ${spritePath}
|
|
3309
3309
|
`);
|
|
3310
3310
|
}
|
|
3311
|
-
const
|
|
3312
|
-
if (
|
|
3311
|
+
const fmt2 = resolveMatrixFormat(opts.format, opts.sprite !== void 0);
|
|
3312
|
+
if (fmt2 === "file") {
|
|
3313
3313
|
const { SpriteSheetGenerator: SpriteSheetGenerator2 } = await import("@agent-scope/render");
|
|
3314
3314
|
const gen = new SpriteSheetGenerator2();
|
|
3315
3315
|
const sheet = await gen.generate(result);
|
|
@@ -3322,10 +3322,10 @@ Available: ${available}`
|
|
|
3322
3322
|
`\u2713 ${componentName} matrix (${result.stats.totalCells} cells) \u2192 ${relPath} (${result.stats.wallClockTimeMs.toFixed(0)}ms total)
|
|
3323
3323
|
`
|
|
3324
3324
|
);
|
|
3325
|
-
} else if (
|
|
3325
|
+
} else if (fmt2 === "json") {
|
|
3326
3326
|
process.stdout.write(`${JSON.stringify(formatMatrixJson(result), null, 2)}
|
|
3327
3327
|
`);
|
|
3328
|
-
} else if (
|
|
3328
|
+
} else if (fmt2 === "png") {
|
|
3329
3329
|
if (opts.sprite !== void 0) {
|
|
3330
3330
|
} else {
|
|
3331
3331
|
const { SpriteSheetGenerator: SpriteSheetGenerator2 } = await import("@agent-scope/render");
|
|
@@ -3333,9 +3333,9 @@ Available: ${available}`
|
|
|
3333
3333
|
const sheet = await gen.generate(result);
|
|
3334
3334
|
process.stdout.write(sheet.png);
|
|
3335
3335
|
}
|
|
3336
|
-
} else if (
|
|
3336
|
+
} else if (fmt2 === "html") {
|
|
3337
3337
|
process.stdout.write(formatMatrixHtml(componentName, result));
|
|
3338
|
-
} else if (
|
|
3338
|
+
} else if (fmt2 === "csv") {
|
|
3339
3339
|
process.stdout.write(formatMatrixCsv(componentName, result));
|
|
3340
3340
|
}
|
|
3341
3341
|
} catch (err) {
|
|
@@ -3643,12 +3643,12 @@ async function runBaseline(options = {}) {
|
|
|
3643
3643
|
mkdirSync4(rendersDir, { recursive: true });
|
|
3644
3644
|
let manifest;
|
|
3645
3645
|
if (manifestPath !== void 0) {
|
|
3646
|
-
const { readFileSync:
|
|
3646
|
+
const { readFileSync: readFileSync12 } = await import("fs");
|
|
3647
3647
|
const absPath = resolve9(rootDir, manifestPath);
|
|
3648
3648
|
if (!existsSync6(absPath)) {
|
|
3649
3649
|
throw new Error(`Manifest not found at ${absPath}.`);
|
|
3650
3650
|
}
|
|
3651
|
-
manifest = JSON.parse(
|
|
3651
|
+
manifest = JSON.parse(readFileSync12(absPath, "utf-8"));
|
|
3652
3652
|
process.stderr.write(`Loaded manifest from ${manifestPath}
|
|
3653
3653
|
`);
|
|
3654
3654
|
} else {
|
|
@@ -4290,6 +4290,139 @@ function registerDiffSubCommand(reportCmd) {
|
|
|
4290
4290
|
);
|
|
4291
4291
|
}
|
|
4292
4292
|
|
|
4293
|
+
// src/report/pr-comment.ts
|
|
4294
|
+
import { existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync8 } from "fs";
|
|
4295
|
+
import { resolve as resolve11 } from "path";
|
|
4296
|
+
var STATUS_BADGE = {
|
|
4297
|
+
added: "\u2705 added",
|
|
4298
|
+
removed: "\u{1F5D1}\uFE0F removed",
|
|
4299
|
+
unchanged: "\u2014 unchanged",
|
|
4300
|
+
compliance_regressed: "\u274C regressed",
|
|
4301
|
+
compliance_improved: "\u{1F4C8} improved",
|
|
4302
|
+
size_changed: "\u{1F4D0} resized"
|
|
4303
|
+
};
|
|
4304
|
+
function fmt(n) {
|
|
4305
|
+
return `${(n * 100).toFixed(1)}%`;
|
|
4306
|
+
}
|
|
4307
|
+
function fmtDelta(delta) {
|
|
4308
|
+
if (delta === null) return "\u2014";
|
|
4309
|
+
const sign = delta >= 0 ? "+" : "";
|
|
4310
|
+
return `${sign}${(delta * 100).toFixed(1)}%`;
|
|
4311
|
+
}
|
|
4312
|
+
function fmtDimensions(d) {
|
|
4313
|
+
if (d === null) return "\u2014";
|
|
4314
|
+
return `${d.width} \xD7 ${d.height}`;
|
|
4315
|
+
}
|
|
4316
|
+
function complianceDeltaArrow(diff) {
|
|
4317
|
+
const delta = diff.currentAggregateCompliance - diff.baselineAggregateCompliance;
|
|
4318
|
+
if (Math.abs(delta) < 5e-4) return `\u2192 ${fmt(diff.currentAggregateCompliance)} (no change)`;
|
|
4319
|
+
const arrow = delta > 0 ? "\u2191" : "\u2193";
|
|
4320
|
+
return `${arrow} ${fmtDelta(delta)}`;
|
|
4321
|
+
}
|
|
4322
|
+
function formatPrComment(diff) {
|
|
4323
|
+
const { summary, components } = diff;
|
|
4324
|
+
const lines = [];
|
|
4325
|
+
const hasRegressions = diff.hasRegressions;
|
|
4326
|
+
const headerEmoji = hasRegressions ? "\u26A0\uFE0F" : "\u2705";
|
|
4327
|
+
lines.push(`## ${headerEmoji} Scope Report`);
|
|
4328
|
+
lines.push("");
|
|
4329
|
+
lines.push("| Metric | Value |");
|
|
4330
|
+
lines.push("|---|---|");
|
|
4331
|
+
lines.push(`| Baseline compliance | ${fmt(diff.baselineAggregateCompliance)} |`);
|
|
4332
|
+
lines.push(`| Current compliance | ${fmt(diff.currentAggregateCompliance)} |`);
|
|
4333
|
+
lines.push(`| Delta | ${complianceDeltaArrow(diff)} |`);
|
|
4334
|
+
lines.push(
|
|
4335
|
+
`| Components | ${summary.total} total \xB7 ${summary.added} added \xB7 ${summary.removed} removed \xB7 ${summary.complianceRegressed} regressed |`
|
|
4336
|
+
);
|
|
4337
|
+
if (summary.renderFailed > 0) {
|
|
4338
|
+
lines.push(`| Render failures | ${summary.renderFailed} |`);
|
|
4339
|
+
}
|
|
4340
|
+
lines.push("");
|
|
4341
|
+
const changed = components.filter((c) => c.status !== "unchanged");
|
|
4342
|
+
const unchanged = components.filter((c) => c.status === "unchanged");
|
|
4343
|
+
if (changed.length > 0) {
|
|
4344
|
+
lines.push("### Changes");
|
|
4345
|
+
lines.push("");
|
|
4346
|
+
lines.push("| Component | Status | Compliance \u0394 | Dimensions |");
|
|
4347
|
+
lines.push("|---|---|---|---|");
|
|
4348
|
+
for (const c of changed) {
|
|
4349
|
+
const badge = STATUS_BADGE[c.status];
|
|
4350
|
+
const delta = fmtDelta(c.complianceDelta);
|
|
4351
|
+
const dims = fmtDimensions(c.currentDimensions ?? c.baselineDimensions);
|
|
4352
|
+
lines.push(`| \`${c.name}\` | ${badge} | ${delta} | ${dims} |`);
|
|
4353
|
+
}
|
|
4354
|
+
lines.push("");
|
|
4355
|
+
}
|
|
4356
|
+
if (unchanged.length > 0) {
|
|
4357
|
+
lines.push(
|
|
4358
|
+
`<details><summary>${unchanged.length} unchanged component${unchanged.length === 1 ? "" : "s"}</summary>`
|
|
4359
|
+
);
|
|
4360
|
+
lines.push("");
|
|
4361
|
+
lines.push("| Component | Compliance |");
|
|
4362
|
+
lines.push("|---|---|");
|
|
4363
|
+
for (const c of unchanged) {
|
|
4364
|
+
lines.push(
|
|
4365
|
+
`| \`${c.name}\` | ${c.currentCompliance !== null ? fmt(c.currentCompliance) : "\u2014"} |`
|
|
4366
|
+
);
|
|
4367
|
+
}
|
|
4368
|
+
lines.push("");
|
|
4369
|
+
lines.push("</details>");
|
|
4370
|
+
lines.push("");
|
|
4371
|
+
}
|
|
4372
|
+
lines.push(
|
|
4373
|
+
`> Generated by [Scope](https://github.com/FlatFilers/Scope) \xB7 diffed at ${diff.diffedAt}`
|
|
4374
|
+
);
|
|
4375
|
+
return lines.join("\n");
|
|
4376
|
+
}
|
|
4377
|
+
function loadDiffResult(filePath) {
|
|
4378
|
+
const abs = resolve11(filePath);
|
|
4379
|
+
if (!existsSync8(abs)) {
|
|
4380
|
+
throw new Error(`DiffResult file not found: ${abs}`);
|
|
4381
|
+
}
|
|
4382
|
+
let raw;
|
|
4383
|
+
try {
|
|
4384
|
+
raw = readFileSync7(abs, "utf-8");
|
|
4385
|
+
} catch (err) {
|
|
4386
|
+
throw new Error(
|
|
4387
|
+
`Failed to read DiffResult file: ${err instanceof Error ? err.message : String(err)}`
|
|
4388
|
+
);
|
|
4389
|
+
}
|
|
4390
|
+
let parsed;
|
|
4391
|
+
try {
|
|
4392
|
+
parsed = JSON.parse(raw);
|
|
4393
|
+
} catch {
|
|
4394
|
+
throw new Error(`DiffResult file is not valid JSON: ${abs}`);
|
|
4395
|
+
}
|
|
4396
|
+
if (typeof parsed !== "object" || parsed === null || !("diffedAt" in parsed) || !("components" in parsed) || !("summary" in parsed)) {
|
|
4397
|
+
throw new Error(
|
|
4398
|
+
`DiffResult file does not match expected shape (missing diffedAt/components/summary): ${abs}`
|
|
4399
|
+
);
|
|
4400
|
+
}
|
|
4401
|
+
return parsed;
|
|
4402
|
+
}
|
|
4403
|
+
function registerPrCommentSubCommand(reportCmd) {
|
|
4404
|
+
reportCmd.command("pr-comment").description(
|
|
4405
|
+
"Format a DiffResult JSON file as a GitHub PR comment (Markdown, written to stdout)"
|
|
4406
|
+
).requiredOption("-i, --input <path>", "Path to DiffResult JSON (from scope report diff --json)").option("-o, --output <path>", "Write comment to file instead of stdout").action(async (opts) => {
|
|
4407
|
+
try {
|
|
4408
|
+
const diff = loadDiffResult(opts.input);
|
|
4409
|
+
const comment = formatPrComment(diff);
|
|
4410
|
+
if (opts.output !== void 0) {
|
|
4411
|
+
writeFileSync8(resolve11(opts.output), comment, "utf-8");
|
|
4412
|
+
process.stderr.write(`PR comment written to ${opts.output}
|
|
4413
|
+
`);
|
|
4414
|
+
} else {
|
|
4415
|
+
process.stdout.write(`${comment}
|
|
4416
|
+
`);
|
|
4417
|
+
}
|
|
4418
|
+
} catch (err) {
|
|
4419
|
+
process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
|
|
4420
|
+
`);
|
|
4421
|
+
process.exit(1);
|
|
4422
|
+
}
|
|
4423
|
+
});
|
|
4424
|
+
}
|
|
4425
|
+
|
|
4293
4426
|
// src/tree-formatter.ts
|
|
4294
4427
|
var BRANCH2 = "\u251C\u2500\u2500 ";
|
|
4295
4428
|
var LAST_BRANCH2 = "\u2514\u2500\u2500 ";
|
|
@@ -4569,9 +4702,140 @@ function buildStructuredReport(report) {
|
|
|
4569
4702
|
};
|
|
4570
4703
|
}
|
|
4571
4704
|
|
|
4705
|
+
// src/site-commands.ts
|
|
4706
|
+
import { createReadStream, existsSync as existsSync9, statSync } from "fs";
|
|
4707
|
+
import { createServer } from "http";
|
|
4708
|
+
import { extname, join as join3, resolve as resolve12 } from "path";
|
|
4709
|
+
import { buildSite } from "@agent-scope/site";
|
|
4710
|
+
import { Command as Command7 } from "commander";
|
|
4711
|
+
var MIME_TYPES = {
|
|
4712
|
+
".html": "text/html; charset=utf-8",
|
|
4713
|
+
".css": "text/css; charset=utf-8",
|
|
4714
|
+
".js": "application/javascript; charset=utf-8",
|
|
4715
|
+
".json": "application/json; charset=utf-8",
|
|
4716
|
+
".png": "image/png",
|
|
4717
|
+
".jpg": "image/jpeg",
|
|
4718
|
+
".jpeg": "image/jpeg",
|
|
4719
|
+
".svg": "image/svg+xml",
|
|
4720
|
+
".ico": "image/x-icon"
|
|
4721
|
+
};
|
|
4722
|
+
function registerBuild(siteCmd) {
|
|
4723
|
+
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(
|
|
4724
|
+
async (opts) => {
|
|
4725
|
+
try {
|
|
4726
|
+
const inputDir = resolve12(process.cwd(), opts.input);
|
|
4727
|
+
const outputDir = resolve12(process.cwd(), opts.output);
|
|
4728
|
+
if (!existsSync9(inputDir)) {
|
|
4729
|
+
throw new Error(
|
|
4730
|
+
`Input directory not found: ${inputDir}
|
|
4731
|
+
Run \`scope manifest generate\` and \`scope render\` first.`
|
|
4732
|
+
);
|
|
4733
|
+
}
|
|
4734
|
+
const manifestPath = join3(inputDir, "manifest.json");
|
|
4735
|
+
if (!existsSync9(manifestPath)) {
|
|
4736
|
+
throw new Error(
|
|
4737
|
+
`Manifest not found at ${manifestPath}
|
|
4738
|
+
Run \`scope manifest generate\` first.`
|
|
4739
|
+
);
|
|
4740
|
+
}
|
|
4741
|
+
process.stderr.write(`Building site from ${inputDir}\u2026
|
|
4742
|
+
`);
|
|
4743
|
+
await buildSite({
|
|
4744
|
+
inputDir,
|
|
4745
|
+
outputDir,
|
|
4746
|
+
basePath: opts.basePath,
|
|
4747
|
+
...opts.compliance !== void 0 && {
|
|
4748
|
+
compliancePath: resolve12(process.cwd(), opts.compliance)
|
|
4749
|
+
},
|
|
4750
|
+
title: opts.title
|
|
4751
|
+
});
|
|
4752
|
+
process.stderr.write(`Site written to ${outputDir}
|
|
4753
|
+
`);
|
|
4754
|
+
process.stdout.write(`${outputDir}
|
|
4755
|
+
`);
|
|
4756
|
+
} catch (err) {
|
|
4757
|
+
process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
|
|
4758
|
+
`);
|
|
4759
|
+
process.exit(1);
|
|
4760
|
+
}
|
|
4761
|
+
}
|
|
4762
|
+
);
|
|
4763
|
+
}
|
|
4764
|
+
function registerServe(siteCmd) {
|
|
4765
|
+
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) => {
|
|
4766
|
+
try {
|
|
4767
|
+
const port = Number.parseInt(opts.port, 10);
|
|
4768
|
+
if (Number.isNaN(port) || port < 1 || port > 65535) {
|
|
4769
|
+
throw new Error(`Invalid port: ${opts.port}`);
|
|
4770
|
+
}
|
|
4771
|
+
const serveDir = resolve12(process.cwd(), opts.dir);
|
|
4772
|
+
if (!existsSync9(serveDir)) {
|
|
4773
|
+
throw new Error(
|
|
4774
|
+
`Serve directory not found: ${serveDir}
|
|
4775
|
+
Run \`scope site build\` first.`
|
|
4776
|
+
);
|
|
4777
|
+
}
|
|
4778
|
+
const server = createServer((req, res) => {
|
|
4779
|
+
const rawUrl = req.url ?? "/";
|
|
4780
|
+
const urlPath = decodeURIComponent(rawUrl.split("?")[0] ?? "/");
|
|
4781
|
+
const filePath = join3(serveDir, urlPath.endsWith("/") ? `${urlPath}index.html` : urlPath);
|
|
4782
|
+
if (!filePath.startsWith(serveDir)) {
|
|
4783
|
+
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
4784
|
+
res.end("Forbidden");
|
|
4785
|
+
return;
|
|
4786
|
+
}
|
|
4787
|
+
if (existsSync9(filePath) && statSync(filePath).isFile()) {
|
|
4788
|
+
const ext = extname(filePath).toLowerCase();
|
|
4789
|
+
const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
4790
|
+
res.writeHead(200, { "Content-Type": contentType });
|
|
4791
|
+
createReadStream(filePath).pipe(res);
|
|
4792
|
+
return;
|
|
4793
|
+
}
|
|
4794
|
+
const htmlPath = `${filePath}.html`;
|
|
4795
|
+
if (existsSync9(htmlPath) && statSync(htmlPath).isFile()) {
|
|
4796
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
4797
|
+
createReadStream(htmlPath).pipe(res);
|
|
4798
|
+
return;
|
|
4799
|
+
}
|
|
4800
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
4801
|
+
res.end(`Not found: ${urlPath}`);
|
|
4802
|
+
});
|
|
4803
|
+
server.listen(port, () => {
|
|
4804
|
+
process.stderr.write(`Scope site running at http://localhost:${port}
|
|
4805
|
+
`);
|
|
4806
|
+
process.stderr.write(`Serving ${serveDir}
|
|
4807
|
+
`);
|
|
4808
|
+
process.stderr.write("Press Ctrl+C to stop.\n");
|
|
4809
|
+
});
|
|
4810
|
+
server.on("error", (err) => {
|
|
4811
|
+
if (err.code === "EADDRINUSE") {
|
|
4812
|
+
process.stderr.write(`Error: Port ${port} is already in use.
|
|
4813
|
+
`);
|
|
4814
|
+
} else {
|
|
4815
|
+
process.stderr.write(`Server error: ${err.message}
|
|
4816
|
+
`);
|
|
4817
|
+
}
|
|
4818
|
+
process.exit(1);
|
|
4819
|
+
});
|
|
4820
|
+
} catch (err) {
|
|
4821
|
+
process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
|
|
4822
|
+
`);
|
|
4823
|
+
process.exit(1);
|
|
4824
|
+
}
|
|
4825
|
+
});
|
|
4826
|
+
}
|
|
4827
|
+
function createSiteCommand() {
|
|
4828
|
+
const siteCmd = new Command7("site").description(
|
|
4829
|
+
"Build and serve the static component gallery site"
|
|
4830
|
+
);
|
|
4831
|
+
registerBuild(siteCmd);
|
|
4832
|
+
registerServe(siteCmd);
|
|
4833
|
+
return siteCmd;
|
|
4834
|
+
}
|
|
4835
|
+
|
|
4572
4836
|
// src/tokens/commands.ts
|
|
4573
|
-
import { existsSync as
|
|
4574
|
-
import { resolve as
|
|
4837
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
|
|
4838
|
+
import { resolve as resolve16 } from "path";
|
|
4575
4839
|
import {
|
|
4576
4840
|
parseTokenFileSync as parseTokenFileSync2,
|
|
4577
4841
|
TokenParseError,
|
|
@@ -4579,26 +4843,26 @@ import {
|
|
|
4579
4843
|
TokenValidationError,
|
|
4580
4844
|
validateTokenFile
|
|
4581
4845
|
} from "@agent-scope/tokens";
|
|
4582
|
-
import { Command as
|
|
4846
|
+
import { Command as Command9 } from "commander";
|
|
4583
4847
|
|
|
4584
4848
|
// src/tokens/compliance.ts
|
|
4585
|
-
import { existsSync as
|
|
4586
|
-
import { resolve as
|
|
4849
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
|
|
4850
|
+
import { resolve as resolve13 } from "path";
|
|
4587
4851
|
import {
|
|
4588
4852
|
ComplianceEngine as ComplianceEngine4,
|
|
4589
4853
|
TokenResolver as TokenResolver4
|
|
4590
4854
|
} from "@agent-scope/tokens";
|
|
4591
4855
|
var DEFAULT_STYLES_PATH = ".reactscope/compliance-styles.json";
|
|
4592
4856
|
function loadStylesFile(stylesPath) {
|
|
4593
|
-
const absPath =
|
|
4594
|
-
if (!
|
|
4857
|
+
const absPath = resolve13(process.cwd(), stylesPath);
|
|
4858
|
+
if (!existsSync10(absPath)) {
|
|
4595
4859
|
throw new Error(
|
|
4596
4860
|
`Compliance styles file not found at ${absPath}.
|
|
4597
4861
|
Run \`scope render all\` first to generate component styles, or use --styles to specify a path.
|
|
4598
4862
|
Expected format: { "ComponentName": { colors: {}, spacing: {}, typography: {}, borders: {}, shadows: {} } }`
|
|
4599
4863
|
);
|
|
4600
4864
|
}
|
|
4601
|
-
const raw =
|
|
4865
|
+
const raw = readFileSync8(absPath, "utf-8");
|
|
4602
4866
|
let parsed;
|
|
4603
4867
|
try {
|
|
4604
4868
|
parsed = JSON.parse(raw);
|
|
@@ -4758,38 +5022,38 @@ function registerCompliance(tokensCmd) {
|
|
|
4758
5022
|
}
|
|
4759
5023
|
|
|
4760
5024
|
// src/tokens/export.ts
|
|
4761
|
-
import { existsSync as
|
|
4762
|
-
import { resolve as
|
|
5025
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
5026
|
+
import { resolve as resolve14 } from "path";
|
|
4763
5027
|
import {
|
|
4764
5028
|
exportTokens,
|
|
4765
5029
|
parseTokenFileSync,
|
|
4766
5030
|
ThemeResolver,
|
|
4767
5031
|
TokenResolver as TokenResolver5
|
|
4768
5032
|
} from "@agent-scope/tokens";
|
|
4769
|
-
import { Command as
|
|
5033
|
+
import { Command as Command8 } from "commander";
|
|
4770
5034
|
var DEFAULT_TOKEN_FILE = "reactscope.tokens.json";
|
|
4771
5035
|
var CONFIG_FILE = "reactscope.config.json";
|
|
4772
5036
|
var SUPPORTED_FORMATS = ["css", "ts", "scss", "tailwind", "flat-json", "figma"];
|
|
4773
5037
|
function resolveTokenFilePath2(fileFlag) {
|
|
4774
5038
|
if (fileFlag !== void 0) {
|
|
4775
|
-
return
|
|
5039
|
+
return resolve14(process.cwd(), fileFlag);
|
|
4776
5040
|
}
|
|
4777
|
-
const configPath =
|
|
4778
|
-
if (
|
|
5041
|
+
const configPath = resolve14(process.cwd(), CONFIG_FILE);
|
|
5042
|
+
if (existsSync11(configPath)) {
|
|
4779
5043
|
try {
|
|
4780
|
-
const raw =
|
|
5044
|
+
const raw = readFileSync9(configPath, "utf-8");
|
|
4781
5045
|
const config = JSON.parse(raw);
|
|
4782
5046
|
if (typeof config === "object" && config !== null && "tokens" in config && typeof config.tokens === "object" && config.tokens !== null && typeof config.tokens?.file === "string") {
|
|
4783
5047
|
const file = config.tokens.file;
|
|
4784
|
-
return
|
|
5048
|
+
return resolve14(process.cwd(), file);
|
|
4785
5049
|
}
|
|
4786
5050
|
} catch {
|
|
4787
5051
|
}
|
|
4788
5052
|
}
|
|
4789
|
-
return
|
|
5053
|
+
return resolve14(process.cwd(), DEFAULT_TOKEN_FILE);
|
|
4790
5054
|
}
|
|
4791
5055
|
function createTokensExportCommand() {
|
|
4792
|
-
return new
|
|
5056
|
+
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(
|
|
4793
5057
|
"--theme <name>",
|
|
4794
5058
|
"Include theme overrides for the named theme (applies to css, ts, scss, tailwind, figma)"
|
|
4795
5059
|
).action(
|
|
@@ -4805,13 +5069,13 @@ Supported formats: ${SUPPORTED_FORMATS.join(", ")}
|
|
|
4805
5069
|
const format = opts.format;
|
|
4806
5070
|
try {
|
|
4807
5071
|
const filePath = resolveTokenFilePath2(opts.file);
|
|
4808
|
-
if (!
|
|
5072
|
+
if (!existsSync11(filePath)) {
|
|
4809
5073
|
throw new Error(
|
|
4810
5074
|
`Token file not found at ${filePath}.
|
|
4811
5075
|
Create a reactscope.tokens.json file or use --file to specify a path.`
|
|
4812
5076
|
);
|
|
4813
5077
|
}
|
|
4814
|
-
const raw =
|
|
5078
|
+
const raw = readFileSync9(filePath, "utf-8");
|
|
4815
5079
|
const { tokens, rawFile } = parseTokenFileSync(raw);
|
|
4816
5080
|
let themesMap;
|
|
4817
5081
|
if (opts.theme !== void 0) {
|
|
@@ -4850,8 +5114,8 @@ Available themes: ${themeNames.join(", ")}`
|
|
|
4850
5114
|
themes: themesMap
|
|
4851
5115
|
});
|
|
4852
5116
|
if (opts.out !== void 0) {
|
|
4853
|
-
const outPath =
|
|
4854
|
-
|
|
5117
|
+
const outPath = resolve14(process.cwd(), opts.out);
|
|
5118
|
+
writeFileSync9(outPath, output, "utf-8");
|
|
4855
5119
|
process.stderr.write(`Exported ${tokens.length} tokens to ${outPath}
|
|
4856
5120
|
`);
|
|
4857
5121
|
} else {
|
|
@@ -4965,8 +5229,8 @@ ${formatImpactSummary(report)}
|
|
|
4965
5229
|
}
|
|
4966
5230
|
|
|
4967
5231
|
// src/tokens/preview.ts
|
|
4968
|
-
import { mkdirSync as mkdirSync5, writeFileSync as
|
|
4969
|
-
import { resolve as
|
|
5232
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync10 } from "fs";
|
|
5233
|
+
import { resolve as resolve15 } from "path";
|
|
4970
5234
|
import { BrowserPool as BrowserPool7, SpriteSheetGenerator } from "@agent-scope/render";
|
|
4971
5235
|
import { ComplianceEngine as ComplianceEngine6, ImpactAnalyzer as ImpactAnalyzer2, TokenResolver as TokenResolver7 } from "@agent-scope/tokens";
|
|
4972
5236
|
var DEFAULT_STYLES_PATH3 = ".reactscope/compliance-styles.json";
|
|
@@ -5147,10 +5411,10 @@ function registerPreview(tokensCmd) {
|
|
|
5147
5411
|
});
|
|
5148
5412
|
const spriteResult = await generator.generate(matrixResult);
|
|
5149
5413
|
const tokenLabel = tokenPath.replace(/\./g, "-");
|
|
5150
|
-
const outputPath = opts.output ??
|
|
5151
|
-
const outputDir =
|
|
5414
|
+
const outputPath = opts.output ?? resolve15(process.cwd(), DEFAULT_OUTPUT_DIR2, `preview-${tokenLabel}.png`);
|
|
5415
|
+
const outputDir = resolve15(outputPath, "..");
|
|
5152
5416
|
mkdirSync5(outputDir, { recursive: true });
|
|
5153
|
-
|
|
5417
|
+
writeFileSync10(outputPath, spriteResult.png);
|
|
5154
5418
|
const useJson = opts.format === "json" || opts.format !== "text" && !isTTY();
|
|
5155
5419
|
if (useJson) {
|
|
5156
5420
|
process.stdout.write(
|
|
@@ -5209,30 +5473,30 @@ function buildTable2(headers, rows) {
|
|
|
5209
5473
|
}
|
|
5210
5474
|
function resolveTokenFilePath(fileFlag) {
|
|
5211
5475
|
if (fileFlag !== void 0) {
|
|
5212
|
-
return
|
|
5476
|
+
return resolve16(process.cwd(), fileFlag);
|
|
5213
5477
|
}
|
|
5214
|
-
const configPath =
|
|
5215
|
-
if (
|
|
5478
|
+
const configPath = resolve16(process.cwd(), CONFIG_FILE2);
|
|
5479
|
+
if (existsSync12(configPath)) {
|
|
5216
5480
|
try {
|
|
5217
|
-
const raw =
|
|
5481
|
+
const raw = readFileSync10(configPath, "utf-8");
|
|
5218
5482
|
const config = JSON.parse(raw);
|
|
5219
5483
|
if (typeof config === "object" && config !== null && "tokens" in config && typeof config.tokens === "object" && config.tokens !== null && typeof config.tokens?.file === "string") {
|
|
5220
5484
|
const file = config.tokens.file;
|
|
5221
|
-
return
|
|
5485
|
+
return resolve16(process.cwd(), file);
|
|
5222
5486
|
}
|
|
5223
5487
|
} catch {
|
|
5224
5488
|
}
|
|
5225
5489
|
}
|
|
5226
|
-
return
|
|
5490
|
+
return resolve16(process.cwd(), DEFAULT_TOKEN_FILE2);
|
|
5227
5491
|
}
|
|
5228
5492
|
function loadTokens(absPath) {
|
|
5229
|
-
if (!
|
|
5493
|
+
if (!existsSync12(absPath)) {
|
|
5230
5494
|
throw new Error(
|
|
5231
5495
|
`Token file not found at ${absPath}.
|
|
5232
5496
|
Create a reactscope.tokens.json file or use --file to specify a path.`
|
|
5233
5497
|
);
|
|
5234
5498
|
}
|
|
5235
|
-
const raw =
|
|
5499
|
+
const raw = readFileSync10(absPath, "utf-8");
|
|
5236
5500
|
return parseTokenFileSync2(raw);
|
|
5237
5501
|
}
|
|
5238
5502
|
function getRawValue(node, segments) {
|
|
@@ -5446,13 +5710,13 @@ function registerValidate(tokensCmd) {
|
|
|
5446
5710
|
).option("--file <path>", "Path to token file (overrides config)").option("--format <fmt>", "Output format: json or text (default: auto-detect)").action((opts) => {
|
|
5447
5711
|
try {
|
|
5448
5712
|
const filePath = resolveTokenFilePath(opts.file);
|
|
5449
|
-
if (!
|
|
5713
|
+
if (!existsSync12(filePath)) {
|
|
5450
5714
|
throw new Error(
|
|
5451
5715
|
`Token file not found at ${filePath}.
|
|
5452
5716
|
Create a reactscope.tokens.json file or use --file to specify a path.`
|
|
5453
5717
|
);
|
|
5454
5718
|
}
|
|
5455
|
-
const raw =
|
|
5719
|
+
const raw = readFileSync10(filePath, "utf-8");
|
|
5456
5720
|
const useJson = opts.format === "json" || opts.format !== "text" && !isTTY2();
|
|
5457
5721
|
const errors = [];
|
|
5458
5722
|
let parsed;
|
|
@@ -5520,7 +5784,7 @@ function outputValidationResult(filePath, errors, useJson) {
|
|
|
5520
5784
|
}
|
|
5521
5785
|
}
|
|
5522
5786
|
function createTokensCommand() {
|
|
5523
|
-
const tokensCmd = new
|
|
5787
|
+
const tokensCmd = new Command9("tokens").description(
|
|
5524
5788
|
"Query and validate design tokens from a reactscope.tokens.json file"
|
|
5525
5789
|
);
|
|
5526
5790
|
registerGet2(tokensCmd);
|
|
@@ -5537,7 +5801,7 @@ function createTokensCommand() {
|
|
|
5537
5801
|
|
|
5538
5802
|
// src/program.ts
|
|
5539
5803
|
function createProgram(options = {}) {
|
|
5540
|
-
const program2 = new
|
|
5804
|
+
const program2 = new Command10("scope").version(options.version ?? "0.1.0").description("Scope \u2014 React instrumentation toolkit");
|
|
5541
5805
|
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(
|
|
5542
5806
|
async (url, opts) => {
|
|
5543
5807
|
try {
|
|
@@ -5610,7 +5874,7 @@ function createProgram(options = {}) {
|
|
|
5610
5874
|
}
|
|
5611
5875
|
);
|
|
5612
5876
|
program2.command("generate").description("Generate a Playwright test from a Scope trace file").argument("<trace>", "Path to a serialized Scope trace (.json)").option("-o, --output <path>", "Output file path", "scope.spec.ts").option("-d, --description <text>", "Test description").action((tracePath, opts) => {
|
|
5613
|
-
const raw =
|
|
5877
|
+
const raw = readFileSync11(tracePath, "utf-8");
|
|
5614
5878
|
const trace = loadTrace(raw);
|
|
5615
5879
|
const source = generateTest(trace, {
|
|
5616
5880
|
description: opts.description,
|
|
@@ -5629,7 +5893,9 @@ function createProgram(options = {}) {
|
|
|
5629
5893
|
if (existingReportCmd !== void 0) {
|
|
5630
5894
|
registerBaselineSubCommand(existingReportCmd);
|
|
5631
5895
|
registerDiffSubCommand(existingReportCmd);
|
|
5896
|
+
registerPrCommentSubCommand(existingReportCmd);
|
|
5632
5897
|
}
|
|
5898
|
+
program2.addCommand(createSiteCommand());
|
|
5633
5899
|
return program2;
|
|
5634
5900
|
}
|
|
5635
5901
|
|