@agent-scope/cli 1.17.3 → 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 +316 -165
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +226 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +224 -79
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
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
|
-
|
|
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,12 +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>` : "";
|
|
156
|
-
const
|
|
157
|
-
` : "";
|
|
161
|
+
const wrapperScriptBlock = wrapperScript != null && wrapperScript.length > 0 ? `<script id="scope-wrapper-script">${wrapperScript}</script>` : "";
|
|
158
162
|
return `<!DOCTYPE html>
|
|
159
163
|
<html lang="en">
|
|
160
164
|
<head>
|
|
@@ -169,7 +173,8 @@ ${projectCss.replace(/<\/style>/gi, "<\\/style>")}
|
|
|
169
173
|
</head>
|
|
170
174
|
<body>
|
|
171
175
|
<div id="scope-root" data-reactscope-root></div>
|
|
172
|
-
${
|
|
176
|
+
${wrapperScriptBlock}
|
|
177
|
+
<script>${bundledScript}</script>
|
|
173
178
|
</body>
|
|
174
179
|
</html>`;
|
|
175
180
|
}
|
|
@@ -537,16 +542,16 @@ async function getTailwindCompiler(cwd) {
|
|
|
537
542
|
from: entryPath,
|
|
538
543
|
loadStylesheet
|
|
539
544
|
});
|
|
540
|
-
const
|
|
541
|
-
compilerCache = { cwd, build:
|
|
542
|
-
return
|
|
545
|
+
const build3 = result.build.bind(result);
|
|
546
|
+
compilerCache = { cwd, build: build3 };
|
|
547
|
+
return build3;
|
|
543
548
|
}
|
|
544
549
|
async function getCompiledCssForClasses(cwd, classes) {
|
|
545
|
-
const
|
|
546
|
-
if (
|
|
550
|
+
const build3 = await getTailwindCompiler(cwd);
|
|
551
|
+
if (build3 === null) return null;
|
|
547
552
|
const deduped = [...new Set(classes)].filter(Boolean);
|
|
548
553
|
if (deduped.length === 0) return null;
|
|
549
|
-
return
|
|
554
|
+
return build3(deduped);
|
|
550
555
|
}
|
|
551
556
|
|
|
552
557
|
// src/ci/commands.ts
|
|
@@ -1176,9 +1181,9 @@ function createRL() {
|
|
|
1176
1181
|
});
|
|
1177
1182
|
}
|
|
1178
1183
|
async function ask(rl, question) {
|
|
1179
|
-
return new Promise((
|
|
1184
|
+
return new Promise((resolve18) => {
|
|
1180
1185
|
rl.question(question, (answer) => {
|
|
1181
|
-
|
|
1186
|
+
resolve18(answer.trim());
|
|
1182
1187
|
});
|
|
1183
1188
|
});
|
|
1184
1189
|
}
|
|
@@ -2996,8 +3001,8 @@ function createInstrumentCommand() {
|
|
|
2996
3001
|
}
|
|
2997
3002
|
|
|
2998
3003
|
// src/render-commands.ts
|
|
2999
|
-
import { mkdirSync as
|
|
3000
|
-
import { resolve as
|
|
3004
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
3005
|
+
import { resolve as resolve9 } from "path";
|
|
3001
3006
|
import {
|
|
3002
3007
|
ALL_CONTEXT_IDS,
|
|
3003
3008
|
ALL_STRESS_IDS,
|
|
@@ -3009,6 +3014,129 @@ import {
|
|
|
3009
3014
|
stressAxis
|
|
3010
3015
|
} from "@agent-scope/render";
|
|
3011
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
|
|
3012
3140
|
var MANIFEST_PATH6 = ".reactscope/manifest.json";
|
|
3013
3141
|
var DEFAULT_OUTPUT_DIR = ".reactscope/renders";
|
|
3014
3142
|
var _pool3 = null;
|
|
@@ -3029,7 +3157,7 @@ async function shutdownPool3() {
|
|
|
3029
3157
|
_pool3 = null;
|
|
3030
3158
|
}
|
|
3031
3159
|
}
|
|
3032
|
-
function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
|
|
3160
|
+
function buildRenderer(filePath, componentName, viewportWidth, viewportHeight, wrapperScript) {
|
|
3033
3161
|
const satori = new SatoriRenderer({
|
|
3034
3162
|
defaultViewport: { width: viewportWidth, height: viewportHeight }
|
|
3035
3163
|
});
|
|
@@ -3042,7 +3170,10 @@ function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
|
|
|
3042
3170
|
filePath,
|
|
3043
3171
|
componentName,
|
|
3044
3172
|
props,
|
|
3045
|
-
viewportWidth
|
|
3173
|
+
viewportWidth,
|
|
3174
|
+
void 0,
|
|
3175
|
+
// projectCss (handled separately)
|
|
3176
|
+
wrapperScript
|
|
3046
3177
|
);
|
|
3047
3178
|
const slot = await pool.acquire();
|
|
3048
3179
|
const { page } = slot;
|
|
@@ -3133,8 +3264,37 @@ function buildRenderer(filePath, componentName, viewportWidth, viewportHeight) {
|
|
|
3133
3264
|
}
|
|
3134
3265
|
};
|
|
3135
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
|
+
}
|
|
3136
3296
|
function registerRenderSingle(renderCmd) {
|
|
3137
|
-
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(
|
|
3138
3298
|
async (componentName, opts) => {
|
|
3139
3299
|
try {
|
|
3140
3300
|
const manifest = loadManifest(opts.manifest);
|
|
@@ -3146,80 +3306,71 @@ function registerRenderSingle(renderCmd) {
|
|
|
3146
3306
|
Available: ${available}`
|
|
3147
3307
|
);
|
|
3148
3308
|
}
|
|
3149
|
-
let props = {};
|
|
3150
|
-
if (opts.props !== void 0) {
|
|
3151
|
-
try {
|
|
3152
|
-
props = JSON.parse(opts.props);
|
|
3153
|
-
} catch {
|
|
3154
|
-
throw new Error(`Invalid props JSON: ${opts.props}`);
|
|
3155
|
-
}
|
|
3156
|
-
}
|
|
3157
3309
|
const { width, height } = parseViewport(opts.viewport);
|
|
3158
3310
|
const rootDir = process.cwd();
|
|
3159
|
-
const filePath =
|
|
3160
|
-
const
|
|
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);
|
|
3161
3316
|
process.stderr.write(
|
|
3162
3317
|
`Rendering ${componentName} [${descriptor.complexityClass}] at ${width}\xD7${height}\u2026
|
|
3163
3318
|
`
|
|
3164
3319
|
);
|
|
3165
|
-
const
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
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
|
+
}
|
|
3173
3334
|
}
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
if (outcome.crashed) {
|
|
3178
|
-
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}
|
|
3179
3338
|
`);
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3339
|
+
const hintList = outcome.error.heuristicFlags.join(", ");
|
|
3340
|
+
if (hintList.length > 0) {
|
|
3341
|
+
process.stderr.write(` Hints: ${hintList}
|
|
3183
3342
|
`);
|
|
3343
|
+
}
|
|
3344
|
+
anyFailed = true;
|
|
3345
|
+
continue;
|
|
3184
3346
|
}
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
`\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)
|
|
3193
3354
|
`
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
if (fmt2 === "json") {
|
|
3199
|
-
const json = formatRenderJson(componentName, props, result);
|
|
3200
|
-
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)}
|
|
3201
3359
|
`);
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
`
|
|
3211
|
-
);
|
|
3212
|
-
} else {
|
|
3213
|
-
const dir = resolve8(process.cwd(), DEFAULT_OUTPUT_DIR);
|
|
3214
|
-
mkdirSync3(dir, { recursive: true });
|
|
3215
|
-
const outPath = resolve8(dir, `${componentName}.png`);
|
|
3216
|
-
writeFileSync5(outPath, result.screenshot);
|
|
3217
|
-
const relPath = `${DEFAULT_OUTPUT_DIR}/${componentName}.png`;
|
|
3218
|
-
process.stdout.write(
|
|
3219
|
-
`\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)
|
|
3220
3368
|
`
|
|
3221
|
-
|
|
3369
|
+
);
|
|
3370
|
+
}
|
|
3222
3371
|
}
|
|
3372
|
+
await shutdownPool3();
|
|
3373
|
+
if (anyFailed) process.exit(1);
|
|
3223
3374
|
} catch (err) {
|
|
3224
3375
|
await shutdownPool3();
|
|
3225
3376
|
process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -3248,7 +3399,7 @@ Available: ${available}`
|
|
|
3248
3399
|
const concurrency = Math.max(1, parseInt(opts.concurrency, 10) || 8);
|
|
3249
3400
|
const { width, height } = { width: 375, height: 812 };
|
|
3250
3401
|
const rootDir = process.cwd();
|
|
3251
|
-
const filePath =
|
|
3402
|
+
const filePath = resolve9(rootDir, descriptor.filePath);
|
|
3252
3403
|
const renderer = buildRenderer(filePath, componentName, width, height);
|
|
3253
3404
|
const axes = [];
|
|
3254
3405
|
if (opts.axes !== void 0) {
|
|
@@ -3315,7 +3466,7 @@ Available: ${available}`
|
|
|
3315
3466
|
const { SpriteSheetGenerator: SpriteSheetGenerator2 } = await import("@agent-scope/render");
|
|
3316
3467
|
const gen = new SpriteSheetGenerator2();
|
|
3317
3468
|
const sheet = await gen.generate(result);
|
|
3318
|
-
const spritePath =
|
|
3469
|
+
const spritePath = resolve9(process.cwd(), opts.sprite);
|
|
3319
3470
|
writeFileSync5(spritePath, sheet.png);
|
|
3320
3471
|
process.stderr.write(`Sprite sheet saved to ${spritePath}
|
|
3321
3472
|
`);
|
|
@@ -3325,9 +3476,9 @@ Available: ${available}`
|
|
|
3325
3476
|
const { SpriteSheetGenerator: SpriteSheetGenerator2 } = await import("@agent-scope/render");
|
|
3326
3477
|
const gen = new SpriteSheetGenerator2();
|
|
3327
3478
|
const sheet = await gen.generate(result);
|
|
3328
|
-
const dir =
|
|
3329
|
-
|
|
3330
|
-
const outPath =
|
|
3479
|
+
const dir = resolve9(process.cwd(), DEFAULT_OUTPUT_DIR);
|
|
3480
|
+
mkdirSync4(dir, { recursive: true });
|
|
3481
|
+
const outPath = resolve9(dir, `${componentName}-matrix.png`);
|
|
3331
3482
|
writeFileSync5(outPath, sheet.png);
|
|
3332
3483
|
const relPath = `${DEFAULT_OUTPUT_DIR}/${componentName}-matrix.png`;
|
|
3333
3484
|
process.stdout.write(
|
|
@@ -3371,8 +3522,8 @@ function registerRenderAll(renderCmd) {
|
|
|
3371
3522
|
return;
|
|
3372
3523
|
}
|
|
3373
3524
|
const concurrency = Math.max(1, parseInt(opts.concurrency, 10) || 4);
|
|
3374
|
-
const outputDir =
|
|
3375
|
-
|
|
3525
|
+
const outputDir = resolve9(process.cwd(), opts.outputDir);
|
|
3526
|
+
mkdirSync4(outputDir, { recursive: true });
|
|
3376
3527
|
const rootDir = process.cwd();
|
|
3377
3528
|
process.stderr.write(`Rendering ${total} components (concurrency: ${concurrency})\u2026
|
|
3378
3529
|
`);
|
|
@@ -3381,7 +3532,7 @@ function registerRenderAll(renderCmd) {
|
|
|
3381
3532
|
const renderOne = async (name) => {
|
|
3382
3533
|
const descriptor = manifest.components[name];
|
|
3383
3534
|
if (descriptor === void 0) return;
|
|
3384
|
-
const filePath =
|
|
3535
|
+
const filePath = resolve9(rootDir, descriptor.filePath);
|
|
3385
3536
|
const renderer = buildRenderer(filePath, name, 375, 812);
|
|
3386
3537
|
const outcome = await safeRender2(
|
|
3387
3538
|
() => renderer.renderCell({}, descriptor.complexityClass),
|
|
@@ -3404,7 +3555,7 @@ function registerRenderAll(renderCmd) {
|
|
|
3404
3555
|
success: false,
|
|
3405
3556
|
errorMessage: outcome.error.message
|
|
3406
3557
|
});
|
|
3407
|
-
const errPath =
|
|
3558
|
+
const errPath = resolve9(outputDir, `${name}.error.json`);
|
|
3408
3559
|
writeFileSync5(
|
|
3409
3560
|
errPath,
|
|
3410
3561
|
JSON.stringify(
|
|
@@ -3422,9 +3573,9 @@ function registerRenderAll(renderCmd) {
|
|
|
3422
3573
|
}
|
|
3423
3574
|
const result = outcome.result;
|
|
3424
3575
|
results.push({ name, renderTimeMs: result.renderTimeMs, success: true });
|
|
3425
|
-
const pngPath =
|
|
3576
|
+
const pngPath = resolve9(outputDir, `${name}.png`);
|
|
3426
3577
|
writeFileSync5(pngPath, result.screenshot);
|
|
3427
|
-
const jsonPath =
|
|
3578
|
+
const jsonPath = resolve9(outputDir, `${name}.json`);
|
|
3428
3579
|
writeFileSync5(jsonPath, JSON.stringify(formatRenderJson(name, {}, result), null, 2));
|
|
3429
3580
|
if (isTTY()) {
|
|
3430
3581
|
process.stdout.write(
|
|
@@ -3497,8 +3648,8 @@ function createRenderCommand() {
|
|
|
3497
3648
|
}
|
|
3498
3649
|
|
|
3499
3650
|
// src/report/baseline.ts
|
|
3500
|
-
import { existsSync as
|
|
3501
|
-
import { resolve as
|
|
3651
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
3652
|
+
import { resolve as resolve10 } from "path";
|
|
3502
3653
|
import { generateManifest as generateManifest3 } from "@agent-scope/manifest";
|
|
3503
3654
|
import { BrowserPool as BrowserPool4, safeRender as safeRender3 } from "@agent-scope/render";
|
|
3504
3655
|
import { ComplianceEngine as ComplianceEngine2, TokenResolver as TokenResolver2 } from "@agent-scope/tokens";
|
|
@@ -3647,17 +3798,17 @@ async function runBaseline(options = {}) {
|
|
|
3647
3798
|
} = options;
|
|
3648
3799
|
const startTime = performance.now();
|
|
3649
3800
|
const rootDir = process.cwd();
|
|
3650
|
-
const baselineDir =
|
|
3651
|
-
const rendersDir =
|
|
3652
|
-
if (
|
|
3653
|
-
|
|
3801
|
+
const baselineDir = resolve10(rootDir, outputDir);
|
|
3802
|
+
const rendersDir = resolve10(baselineDir, "renders");
|
|
3803
|
+
if (existsSync7(baselineDir)) {
|
|
3804
|
+
rmSync2(baselineDir, { recursive: true, force: true });
|
|
3654
3805
|
}
|
|
3655
|
-
|
|
3806
|
+
mkdirSync5(rendersDir, { recursive: true });
|
|
3656
3807
|
let manifest;
|
|
3657
3808
|
if (manifestPath !== void 0) {
|
|
3658
3809
|
const { readFileSync: readFileSync12 } = await import("fs");
|
|
3659
|
-
const absPath =
|
|
3660
|
-
if (!
|
|
3810
|
+
const absPath = resolve10(rootDir, manifestPath);
|
|
3811
|
+
if (!existsSync7(absPath)) {
|
|
3661
3812
|
throw new Error(`Manifest not found at ${absPath}.`);
|
|
3662
3813
|
}
|
|
3663
3814
|
manifest = JSON.parse(readFileSync12(absPath, "utf-8"));
|
|
@@ -3670,7 +3821,7 @@ async function runBaseline(options = {}) {
|
|
|
3670
3821
|
process.stderr.write(`Found ${count} components.
|
|
3671
3822
|
`);
|
|
3672
3823
|
}
|
|
3673
|
-
writeFileSync6(
|
|
3824
|
+
writeFileSync6(resolve10(baselineDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
3674
3825
|
let componentNames = Object.keys(manifest.components);
|
|
3675
3826
|
if (componentsGlob !== void 0) {
|
|
3676
3827
|
componentNames = componentNames.filter((name) => matchGlob(componentsGlob, name));
|
|
@@ -3691,7 +3842,7 @@ async function runBaseline(options = {}) {
|
|
|
3691
3842
|
auditedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3692
3843
|
};
|
|
3693
3844
|
writeFileSync6(
|
|
3694
|
-
|
|
3845
|
+
resolve10(baselineDir, "compliance.json"),
|
|
3695
3846
|
JSON.stringify(emptyReport, null, 2),
|
|
3696
3847
|
"utf-8"
|
|
3697
3848
|
);
|
|
@@ -3712,7 +3863,7 @@ async function runBaseline(options = {}) {
|
|
|
3712
3863
|
const renderOne = async (name) => {
|
|
3713
3864
|
const descriptor = manifest.components[name];
|
|
3714
3865
|
if (descriptor === void 0) return;
|
|
3715
|
-
const filePath =
|
|
3866
|
+
const filePath = resolve10(rootDir, descriptor.filePath);
|
|
3716
3867
|
const outcome = await safeRender3(
|
|
3717
3868
|
() => renderComponent2(filePath, name, {}, viewportWidth, viewportHeight),
|
|
3718
3869
|
{
|
|
@@ -3731,7 +3882,7 @@ async function runBaseline(options = {}) {
|
|
|
3731
3882
|
}
|
|
3732
3883
|
if (outcome.crashed) {
|
|
3733
3884
|
failureCount++;
|
|
3734
|
-
const errPath =
|
|
3885
|
+
const errPath = resolve10(rendersDir, `${name}.error.json`);
|
|
3735
3886
|
writeFileSync6(
|
|
3736
3887
|
errPath,
|
|
3737
3888
|
JSON.stringify(
|
|
@@ -3749,10 +3900,10 @@ async function runBaseline(options = {}) {
|
|
|
3749
3900
|
return;
|
|
3750
3901
|
}
|
|
3751
3902
|
const result = outcome.result;
|
|
3752
|
-
writeFileSync6(
|
|
3903
|
+
writeFileSync6(resolve10(rendersDir, `${name}.png`), result.screenshot);
|
|
3753
3904
|
const jsonOutput = formatRenderJson(name, {}, result);
|
|
3754
3905
|
writeFileSync6(
|
|
3755
|
-
|
|
3906
|
+
resolve10(rendersDir, `${name}.json`),
|
|
3756
3907
|
JSON.stringify(jsonOutput, null, 2),
|
|
3757
3908
|
"utf-8"
|
|
3758
3909
|
);
|
|
@@ -3780,7 +3931,7 @@ async function runBaseline(options = {}) {
|
|
|
3780
3931
|
const engine = new ComplianceEngine2(resolver);
|
|
3781
3932
|
const batchReport = engine.auditBatch(computedStylesMap);
|
|
3782
3933
|
writeFileSync6(
|
|
3783
|
-
|
|
3934
|
+
resolve10(baselineDir, "compliance.json"),
|
|
3784
3935
|
JSON.stringify(batchReport, null, 2),
|
|
3785
3936
|
"utf-8"
|
|
3786
3937
|
);
|
|
@@ -3823,21 +3974,21 @@ function registerBaselineSubCommand(reportCmd) {
|
|
|
3823
3974
|
}
|
|
3824
3975
|
|
|
3825
3976
|
// src/report/diff.ts
|
|
3826
|
-
import { existsSync as
|
|
3827
|
-
import { resolve as
|
|
3977
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
3978
|
+
import { resolve as resolve11 } from "path";
|
|
3828
3979
|
import { generateManifest as generateManifest4 } from "@agent-scope/manifest";
|
|
3829
3980
|
import { BrowserPool as BrowserPool5, safeRender as safeRender4 } from "@agent-scope/render";
|
|
3830
3981
|
import { ComplianceEngine as ComplianceEngine3, TokenResolver as TokenResolver3 } from "@agent-scope/tokens";
|
|
3831
3982
|
var DEFAULT_BASELINE_DIR2 = ".reactscope/baseline";
|
|
3832
3983
|
function loadBaselineCompliance(baselineDir) {
|
|
3833
|
-
const compliancePath =
|
|
3834
|
-
if (!
|
|
3984
|
+
const compliancePath = resolve11(baselineDir, "compliance.json");
|
|
3985
|
+
if (!existsSync8(compliancePath)) return null;
|
|
3835
3986
|
const raw = JSON.parse(readFileSync6(compliancePath, "utf-8"));
|
|
3836
3987
|
return raw;
|
|
3837
3988
|
}
|
|
3838
3989
|
function loadBaselineRenderJson2(baselineDir, componentName) {
|
|
3839
|
-
const jsonPath =
|
|
3840
|
-
if (!
|
|
3990
|
+
const jsonPath = resolve11(baselineDir, "renders", `${componentName}.json`);
|
|
3991
|
+
if (!existsSync8(jsonPath)) return null;
|
|
3841
3992
|
return JSON.parse(readFileSync6(jsonPath, "utf-8"));
|
|
3842
3993
|
}
|
|
3843
3994
|
var _pool5 = null;
|
|
@@ -4005,14 +4156,14 @@ async function runDiff(options = {}) {
|
|
|
4005
4156
|
} = options;
|
|
4006
4157
|
const startTime = performance.now();
|
|
4007
4158
|
const rootDir = process.cwd();
|
|
4008
|
-
const baselineDir =
|
|
4009
|
-
if (!
|
|
4159
|
+
const baselineDir = resolve11(rootDir, baselineDirRaw);
|
|
4160
|
+
if (!existsSync8(baselineDir)) {
|
|
4010
4161
|
throw new Error(
|
|
4011
4162
|
`Baseline directory not found at "${baselineDir}". Run \`scope report baseline\` first to create a baseline snapshot.`
|
|
4012
4163
|
);
|
|
4013
4164
|
}
|
|
4014
|
-
const baselineManifestPath =
|
|
4015
|
-
if (!
|
|
4165
|
+
const baselineManifestPath = resolve11(baselineDir, "manifest.json");
|
|
4166
|
+
if (!existsSync8(baselineManifestPath)) {
|
|
4016
4167
|
throw new Error(
|
|
4017
4168
|
`Baseline manifest.json not found at "${baselineManifestPath}". The baseline directory may be incomplete \u2014 re-run \`scope report baseline\`.`
|
|
4018
4169
|
);
|
|
@@ -4026,8 +4177,8 @@ async function runDiff(options = {}) {
|
|
|
4026
4177
|
);
|
|
4027
4178
|
let currentManifest;
|
|
4028
4179
|
if (manifestPath !== void 0) {
|
|
4029
|
-
const absPath =
|
|
4030
|
-
if (!
|
|
4180
|
+
const absPath = resolve11(rootDir, manifestPath);
|
|
4181
|
+
if (!existsSync8(absPath)) {
|
|
4031
4182
|
throw new Error(`Manifest not found at "${absPath}".`);
|
|
4032
4183
|
}
|
|
4033
4184
|
currentManifest = JSON.parse(readFileSync6(absPath, "utf-8"));
|
|
@@ -4063,7 +4214,7 @@ async function runDiff(options = {}) {
|
|
|
4063
4214
|
const renderOne = async (name) => {
|
|
4064
4215
|
const descriptor = currentManifest.components[name];
|
|
4065
4216
|
if (descriptor === void 0) return;
|
|
4066
|
-
const filePath =
|
|
4217
|
+
const filePath = resolve11(rootDir, descriptor.filePath);
|
|
4067
4218
|
const outcome = await safeRender4(
|
|
4068
4219
|
() => renderComponent3(filePath, name, {}, viewportWidth, viewportHeight),
|
|
4069
4220
|
{
|
|
@@ -4303,8 +4454,8 @@ function registerDiffSubCommand(reportCmd) {
|
|
|
4303
4454
|
}
|
|
4304
4455
|
|
|
4305
4456
|
// src/report/pr-comment.ts
|
|
4306
|
-
import { existsSync as
|
|
4307
|
-
import { resolve as
|
|
4457
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync8 } from "fs";
|
|
4458
|
+
import { resolve as resolve12 } from "path";
|
|
4308
4459
|
var STATUS_BADGE = {
|
|
4309
4460
|
added: "\u2705 added",
|
|
4310
4461
|
removed: "\u{1F5D1}\uFE0F removed",
|
|
@@ -4387,8 +4538,8 @@ function formatPrComment(diff) {
|
|
|
4387
4538
|
return lines.join("\n");
|
|
4388
4539
|
}
|
|
4389
4540
|
function loadDiffResult(filePath) {
|
|
4390
|
-
const abs =
|
|
4391
|
-
if (!
|
|
4541
|
+
const abs = resolve12(filePath);
|
|
4542
|
+
if (!existsSync9(abs)) {
|
|
4392
4543
|
throw new Error(`DiffResult file not found: ${abs}`);
|
|
4393
4544
|
}
|
|
4394
4545
|
let raw;
|
|
@@ -4420,7 +4571,7 @@ function registerPrCommentSubCommand(reportCmd) {
|
|
|
4420
4571
|
const diff = loadDiffResult(opts.input);
|
|
4421
4572
|
const comment = formatPrComment(diff);
|
|
4422
4573
|
if (opts.output !== void 0) {
|
|
4423
|
-
writeFileSync8(
|
|
4574
|
+
writeFileSync8(resolve12(opts.output), comment, "utf-8");
|
|
4424
4575
|
process.stderr.write(`PR comment written to ${opts.output}
|
|
4425
4576
|
`);
|
|
4426
4577
|
} else {
|
|
@@ -4715,9 +4866,9 @@ function buildStructuredReport(report) {
|
|
|
4715
4866
|
}
|
|
4716
4867
|
|
|
4717
4868
|
// src/site-commands.ts
|
|
4718
|
-
import { createReadStream, existsSync as
|
|
4869
|
+
import { createReadStream, existsSync as existsSync10, statSync } from "fs";
|
|
4719
4870
|
import { createServer } from "http";
|
|
4720
|
-
import { extname, join as
|
|
4871
|
+
import { extname, join as join4, resolve as resolve13 } from "path";
|
|
4721
4872
|
import { buildSite } from "@agent-scope/site";
|
|
4722
4873
|
import { Command as Command7 } from "commander";
|
|
4723
4874
|
var MIME_TYPES = {
|
|
@@ -4735,16 +4886,16 @@ function registerBuild(siteCmd) {
|
|
|
4735
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(
|
|
4736
4887
|
async (opts) => {
|
|
4737
4888
|
try {
|
|
4738
|
-
const inputDir =
|
|
4739
|
-
const outputDir =
|
|
4740
|
-
if (!
|
|
4889
|
+
const inputDir = resolve13(process.cwd(), opts.input);
|
|
4890
|
+
const outputDir = resolve13(process.cwd(), opts.output);
|
|
4891
|
+
if (!existsSync10(inputDir)) {
|
|
4741
4892
|
throw new Error(
|
|
4742
4893
|
`Input directory not found: ${inputDir}
|
|
4743
4894
|
Run \`scope manifest generate\` and \`scope render\` first.`
|
|
4744
4895
|
);
|
|
4745
4896
|
}
|
|
4746
|
-
const manifestPath =
|
|
4747
|
-
if (!
|
|
4897
|
+
const manifestPath = join4(inputDir, "manifest.json");
|
|
4898
|
+
if (!existsSync10(manifestPath)) {
|
|
4748
4899
|
throw new Error(
|
|
4749
4900
|
`Manifest not found at ${manifestPath}
|
|
4750
4901
|
Run \`scope manifest generate\` first.`
|
|
@@ -4757,7 +4908,7 @@ Run \`scope manifest generate\` first.`
|
|
|
4757
4908
|
outputDir,
|
|
4758
4909
|
basePath: opts.basePath,
|
|
4759
4910
|
...opts.compliance !== void 0 && {
|
|
4760
|
-
compliancePath:
|
|
4911
|
+
compliancePath: resolve13(process.cwd(), opts.compliance)
|
|
4761
4912
|
},
|
|
4762
4913
|
title: opts.title
|
|
4763
4914
|
});
|
|
@@ -4780,8 +4931,8 @@ function registerServe(siteCmd) {
|
|
|
4780
4931
|
if (Number.isNaN(port) || port < 1 || port > 65535) {
|
|
4781
4932
|
throw new Error(`Invalid port: ${opts.port}`);
|
|
4782
4933
|
}
|
|
4783
|
-
const serveDir =
|
|
4784
|
-
if (!
|
|
4934
|
+
const serveDir = resolve13(process.cwd(), opts.dir);
|
|
4935
|
+
if (!existsSync10(serveDir)) {
|
|
4785
4936
|
throw new Error(
|
|
4786
4937
|
`Serve directory not found: ${serveDir}
|
|
4787
4938
|
Run \`scope site build\` first.`
|
|
@@ -4790,13 +4941,13 @@ Run \`scope site build\` first.`
|
|
|
4790
4941
|
const server = createServer((req, res) => {
|
|
4791
4942
|
const rawUrl = req.url ?? "/";
|
|
4792
4943
|
const urlPath = decodeURIComponent(rawUrl.split("?")[0] ?? "/");
|
|
4793
|
-
const filePath =
|
|
4944
|
+
const filePath = join4(serveDir, urlPath.endsWith("/") ? `${urlPath}index.html` : urlPath);
|
|
4794
4945
|
if (!filePath.startsWith(serveDir)) {
|
|
4795
4946
|
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
4796
4947
|
res.end("Forbidden");
|
|
4797
4948
|
return;
|
|
4798
4949
|
}
|
|
4799
|
-
if (
|
|
4950
|
+
if (existsSync10(filePath) && statSync(filePath).isFile()) {
|
|
4800
4951
|
const ext = extname(filePath).toLowerCase();
|
|
4801
4952
|
const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
4802
4953
|
res.writeHead(200, { "Content-Type": contentType });
|
|
@@ -4804,7 +4955,7 @@ Run \`scope site build\` first.`
|
|
|
4804
4955
|
return;
|
|
4805
4956
|
}
|
|
4806
4957
|
const htmlPath = `${filePath}.html`;
|
|
4807
|
-
if (
|
|
4958
|
+
if (existsSync10(htmlPath) && statSync(htmlPath).isFile()) {
|
|
4808
4959
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
4809
4960
|
createReadStream(htmlPath).pipe(res);
|
|
4810
4961
|
return;
|
|
@@ -4846,8 +4997,8 @@ function createSiteCommand() {
|
|
|
4846
4997
|
}
|
|
4847
4998
|
|
|
4848
4999
|
// src/tokens/commands.ts
|
|
4849
|
-
import { existsSync as
|
|
4850
|
-
import { resolve as
|
|
5000
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
|
|
5001
|
+
import { resolve as resolve17 } from "path";
|
|
4851
5002
|
import {
|
|
4852
5003
|
parseTokenFileSync as parseTokenFileSync2,
|
|
4853
5004
|
TokenParseError,
|
|
@@ -4858,16 +5009,16 @@ import {
|
|
|
4858
5009
|
import { Command as Command9 } from "commander";
|
|
4859
5010
|
|
|
4860
5011
|
// src/tokens/compliance.ts
|
|
4861
|
-
import { existsSync as
|
|
4862
|
-
import { resolve as
|
|
5012
|
+
import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
|
|
5013
|
+
import { resolve as resolve14 } from "path";
|
|
4863
5014
|
import {
|
|
4864
5015
|
ComplianceEngine as ComplianceEngine4,
|
|
4865
5016
|
TokenResolver as TokenResolver4
|
|
4866
5017
|
} from "@agent-scope/tokens";
|
|
4867
5018
|
var DEFAULT_STYLES_PATH = ".reactscope/compliance-styles.json";
|
|
4868
5019
|
function loadStylesFile(stylesPath) {
|
|
4869
|
-
const absPath =
|
|
4870
|
-
if (!
|
|
5020
|
+
const absPath = resolve14(process.cwd(), stylesPath);
|
|
5021
|
+
if (!existsSync11(absPath)) {
|
|
4871
5022
|
throw new Error(
|
|
4872
5023
|
`Compliance styles file not found at ${absPath}.
|
|
4873
5024
|
Run \`scope render all\` first to generate component styles, or use --styles to specify a path.
|
|
@@ -5034,8 +5185,8 @@ function registerCompliance(tokensCmd) {
|
|
|
5034
5185
|
}
|
|
5035
5186
|
|
|
5036
5187
|
// src/tokens/export.ts
|
|
5037
|
-
import { existsSync as
|
|
5038
|
-
import { resolve as
|
|
5188
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
5189
|
+
import { resolve as resolve15 } from "path";
|
|
5039
5190
|
import {
|
|
5040
5191
|
exportTokens,
|
|
5041
5192
|
parseTokenFileSync,
|
|
@@ -5048,21 +5199,21 @@ var CONFIG_FILE = "reactscope.config.json";
|
|
|
5048
5199
|
var SUPPORTED_FORMATS = ["css", "ts", "scss", "tailwind", "flat-json", "figma"];
|
|
5049
5200
|
function resolveTokenFilePath2(fileFlag) {
|
|
5050
5201
|
if (fileFlag !== void 0) {
|
|
5051
|
-
return
|
|
5202
|
+
return resolve15(process.cwd(), fileFlag);
|
|
5052
5203
|
}
|
|
5053
|
-
const configPath =
|
|
5054
|
-
if (
|
|
5204
|
+
const configPath = resolve15(process.cwd(), CONFIG_FILE);
|
|
5205
|
+
if (existsSync12(configPath)) {
|
|
5055
5206
|
try {
|
|
5056
5207
|
const raw = readFileSync9(configPath, "utf-8");
|
|
5057
5208
|
const config = JSON.parse(raw);
|
|
5058
5209
|
if (typeof config === "object" && config !== null && "tokens" in config && typeof config.tokens === "object" && config.tokens !== null && typeof config.tokens?.file === "string") {
|
|
5059
5210
|
const file = config.tokens.file;
|
|
5060
|
-
return
|
|
5211
|
+
return resolve15(process.cwd(), file);
|
|
5061
5212
|
}
|
|
5062
5213
|
} catch {
|
|
5063
5214
|
}
|
|
5064
5215
|
}
|
|
5065
|
-
return
|
|
5216
|
+
return resolve15(process.cwd(), DEFAULT_TOKEN_FILE);
|
|
5066
5217
|
}
|
|
5067
5218
|
function createTokensExportCommand() {
|
|
5068
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(
|
|
@@ -5081,7 +5232,7 @@ Supported formats: ${SUPPORTED_FORMATS.join(", ")}
|
|
|
5081
5232
|
const format = opts.format;
|
|
5082
5233
|
try {
|
|
5083
5234
|
const filePath = resolveTokenFilePath2(opts.file);
|
|
5084
|
-
if (!
|
|
5235
|
+
if (!existsSync12(filePath)) {
|
|
5085
5236
|
throw new Error(
|
|
5086
5237
|
`Token file not found at ${filePath}.
|
|
5087
5238
|
Create a reactscope.tokens.json file or use --file to specify a path.`
|
|
@@ -5126,7 +5277,7 @@ Available themes: ${themeNames.join(", ")}`
|
|
|
5126
5277
|
themes: themesMap
|
|
5127
5278
|
});
|
|
5128
5279
|
if (opts.out !== void 0) {
|
|
5129
|
-
const outPath =
|
|
5280
|
+
const outPath = resolve15(process.cwd(), opts.out);
|
|
5130
5281
|
writeFileSync9(outPath, output, "utf-8");
|
|
5131
5282
|
process.stderr.write(`Exported ${tokens.length} tokens to ${outPath}
|
|
5132
5283
|
`);
|
|
@@ -5241,8 +5392,8 @@ ${formatImpactSummary(report)}
|
|
|
5241
5392
|
}
|
|
5242
5393
|
|
|
5243
5394
|
// src/tokens/preview.ts
|
|
5244
|
-
import { mkdirSync as
|
|
5245
|
-
import { resolve as
|
|
5395
|
+
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync10 } from "fs";
|
|
5396
|
+
import { resolve as resolve16 } from "path";
|
|
5246
5397
|
import { BrowserPool as BrowserPool6, SpriteSheetGenerator } from "@agent-scope/render";
|
|
5247
5398
|
import { ComplianceEngine as ComplianceEngine6, ImpactAnalyzer as ImpactAnalyzer2, TokenResolver as TokenResolver7 } from "@agent-scope/tokens";
|
|
5248
5399
|
var DEFAULT_STYLES_PATH3 = ".reactscope/compliance-styles.json";
|
|
@@ -5423,9 +5574,9 @@ function registerPreview(tokensCmd) {
|
|
|
5423
5574
|
});
|
|
5424
5575
|
const spriteResult = await generator.generate(matrixResult);
|
|
5425
5576
|
const tokenLabel = tokenPath.replace(/\./g, "-");
|
|
5426
|
-
const outputPath = opts.output ??
|
|
5427
|
-
const outputDir =
|
|
5428
|
-
|
|
5577
|
+
const outputPath = opts.output ?? resolve16(process.cwd(), DEFAULT_OUTPUT_DIR2, `preview-${tokenLabel}.png`);
|
|
5578
|
+
const outputDir = resolve16(outputPath, "..");
|
|
5579
|
+
mkdirSync6(outputDir, { recursive: true });
|
|
5429
5580
|
writeFileSync10(outputPath, spriteResult.png);
|
|
5430
5581
|
const useJson = opts.format === "json" || opts.format !== "text" && !isTTY();
|
|
5431
5582
|
if (useJson) {
|
|
@@ -5485,24 +5636,24 @@ function buildTable2(headers, rows) {
|
|
|
5485
5636
|
}
|
|
5486
5637
|
function resolveTokenFilePath(fileFlag) {
|
|
5487
5638
|
if (fileFlag !== void 0) {
|
|
5488
|
-
return
|
|
5639
|
+
return resolve17(process.cwd(), fileFlag);
|
|
5489
5640
|
}
|
|
5490
|
-
const configPath =
|
|
5491
|
-
if (
|
|
5641
|
+
const configPath = resolve17(process.cwd(), CONFIG_FILE2);
|
|
5642
|
+
if (existsSync13(configPath)) {
|
|
5492
5643
|
try {
|
|
5493
5644
|
const raw = readFileSync10(configPath, "utf-8");
|
|
5494
5645
|
const config = JSON.parse(raw);
|
|
5495
5646
|
if (typeof config === "object" && config !== null && "tokens" in config && typeof config.tokens === "object" && config.tokens !== null && typeof config.tokens?.file === "string") {
|
|
5496
5647
|
const file = config.tokens.file;
|
|
5497
|
-
return
|
|
5648
|
+
return resolve17(process.cwd(), file);
|
|
5498
5649
|
}
|
|
5499
5650
|
} catch {
|
|
5500
5651
|
}
|
|
5501
5652
|
}
|
|
5502
|
-
return
|
|
5653
|
+
return resolve17(process.cwd(), DEFAULT_TOKEN_FILE2);
|
|
5503
5654
|
}
|
|
5504
5655
|
function loadTokens(absPath) {
|
|
5505
|
-
if (!
|
|
5656
|
+
if (!existsSync13(absPath)) {
|
|
5506
5657
|
throw new Error(
|
|
5507
5658
|
`Token file not found at ${absPath}.
|
|
5508
5659
|
Create a reactscope.tokens.json file or use --file to specify a path.`
|
|
@@ -5722,7 +5873,7 @@ function registerValidate(tokensCmd) {
|
|
|
5722
5873
|
).option("--file <path>", "Path to token file (overrides config)").option("--format <fmt>", "Output format: json or text (default: auto-detect)").action((opts) => {
|
|
5723
5874
|
try {
|
|
5724
5875
|
const filePath = resolveTokenFilePath(opts.file);
|
|
5725
|
-
if (!
|
|
5876
|
+
if (!existsSync13(filePath)) {
|
|
5726
5877
|
throw new Error(
|
|
5727
5878
|
`Token file not found at ${filePath}.
|
|
5728
5879
|
Create a reactscope.tokens.json file or use --file to specify a path.`
|