@loworbitstudio/visor 1.21.0 → 1.22.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/CHANGELOG.json +1 -1
- package/dist/index.js +86 -40
- package/dist/registry.json +21 -21
- package/dist/visor-manifest.json +185 -4
- package/package.json +2 -2
package/dist/CHANGELOG.json
CHANGED
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { readFileSync as readFileSync33 } from "fs";
|
|
5
|
-
import { dirname as
|
|
5
|
+
import { dirname as dirname15, join as join33 } from "path";
|
|
6
6
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
7
7
|
import { Command as Command2 } from "commander";
|
|
8
8
|
|
|
@@ -1693,27 +1693,10 @@ function initCommand(cwd, options) {
|
|
|
1693
1693
|
);
|
|
1694
1694
|
process.exit(1);
|
|
1695
1695
|
}
|
|
1696
|
-
if (configExists(cwd)) {
|
|
1697
|
-
filesSkipped.push("visor.json");
|
|
1698
|
-
if (!json) {
|
|
1699
|
-
logger.warn("visor.json already exists. Skipping config creation.");
|
|
1700
|
-
}
|
|
1701
|
-
} else {
|
|
1702
|
-
writeConfig(cwd, DEFAULT_CONFIG);
|
|
1703
|
-
filesCreated.push("visor.json");
|
|
1704
|
-
if (!json) {
|
|
1705
|
-
logger.success("Created visor.json");
|
|
1706
|
-
logger.blank();
|
|
1707
|
-
logger.info("Default paths:");
|
|
1708
|
-
logger.item(`components \u2192 ${DEFAULT_CONFIG.paths.components}`);
|
|
1709
|
-
logger.item(`deck components \u2192 ${DEFAULT_CONFIG.paths.deckComponents}`);
|
|
1710
|
-
logger.item(`blocks \u2192 ${DEFAULT_CONFIG.paths.blocks}`);
|
|
1711
|
-
logger.item(`hooks \u2192 ${DEFAULT_CONFIG.paths.hooks}`);
|
|
1712
|
-
logger.item(`lib \u2192 ${DEFAULT_CONFIG.paths.lib}`);
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
1696
|
if (options?.template === "nextjs") {
|
|
1716
1697
|
scaffoldNextjs(cwd, json, filesCreated, filesSkipped, warnings);
|
|
1698
|
+
} else {
|
|
1699
|
+
writeVisorConfig(cwd, json, filesCreated, filesSkipped);
|
|
1717
1700
|
}
|
|
1718
1701
|
if (options?.template !== "nextjs") {
|
|
1719
1702
|
const missingTokens = !hasVisorTokens(cwd);
|
|
@@ -1845,12 +1828,34 @@ function emitError(json, message) {
|
|
|
1845
1828
|
logger.error(message);
|
|
1846
1829
|
}
|
|
1847
1830
|
}
|
|
1831
|
+
function writeVisorConfig(cwd, json, filesCreated, filesSkipped) {
|
|
1832
|
+
if (configExists(cwd)) {
|
|
1833
|
+
filesSkipped.push("visor.json");
|
|
1834
|
+
if (!json) {
|
|
1835
|
+
logger.warn("visor.json already exists. Skipping config creation.");
|
|
1836
|
+
}
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
writeConfig(cwd, DEFAULT_CONFIG);
|
|
1840
|
+
filesCreated.push("visor.json");
|
|
1841
|
+
if (!json) {
|
|
1842
|
+
logger.success("Created visor.json");
|
|
1843
|
+
logger.blank();
|
|
1844
|
+
logger.info("Default paths:");
|
|
1845
|
+
logger.item(`components \u2192 ${DEFAULT_CONFIG.paths.components}`);
|
|
1846
|
+
logger.item(`deck components \u2192 ${DEFAULT_CONFIG.paths.deckComponents}`);
|
|
1847
|
+
logger.item(`blocks \u2192 ${DEFAULT_CONFIG.paths.blocks}`);
|
|
1848
|
+
logger.item(`hooks \u2192 ${DEFAULT_CONFIG.paths.hooks}`);
|
|
1849
|
+
logger.item(`lib \u2192 ${DEFAULT_CONFIG.paths.lib}`);
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1848
1852
|
function scaffoldNextjs(cwd, json, filesCreated, filesSkipped, warnings) {
|
|
1849
1853
|
if (!json) {
|
|
1850
1854
|
logger.blank();
|
|
1851
1855
|
logger.info("Scaffolding a Borealis-native Next.js app...");
|
|
1852
1856
|
}
|
|
1853
1857
|
runCreateNextApp(cwd, json);
|
|
1858
|
+
writeVisorConfig(cwd, json, filesCreated, filesSkipped);
|
|
1854
1859
|
runInstallVisorDeps(cwd, json);
|
|
1855
1860
|
const yamlPath = join8(cwd, ".visor.yaml");
|
|
1856
1861
|
if (existsSync6(yamlPath)) {
|
|
@@ -7992,10 +7997,10 @@ import {
|
|
|
7992
7997
|
existsSync as existsSync29,
|
|
7993
7998
|
readFileSync as readFileSync31,
|
|
7994
7999
|
readdirSync as readdirSync16,
|
|
7995
|
-
rmSync as rmSync4
|
|
8000
|
+
rmSync as rmSync4,
|
|
8001
|
+
statSync as statSync11
|
|
7996
8002
|
} from "fs";
|
|
7997
|
-
import { basename as basename8, isAbsolute as isAbsolute5, join as join31, resolve as resolve19 } from "path";
|
|
7998
|
-
import { homedir as homedir3 } from "os";
|
|
8003
|
+
import { basename as basename8, dirname as dirname13, isAbsolute as isAbsolute5, join as join31, resolve as resolve19 } from "path";
|
|
7999
8004
|
import * as childProcess6 from "child_process";
|
|
8000
8005
|
import { parse as parseYaml5 } from "yaml";
|
|
8001
8006
|
import { generateThemeData as generateThemeData7 } from "@loworbitstudio/visor-theme-engine";
|
|
@@ -8003,7 +8008,7 @@ import { nextjsAdapter as nextjsAdapter3 } from "@loworbitstudio/visor-theme-eng
|
|
|
8003
8008
|
import { validate as validate3 } from "@loworbitstudio/visor-theme-engine";
|
|
8004
8009
|
|
|
8005
8010
|
// src/lib/blessed-discovery.ts
|
|
8006
|
-
import { existsSync as existsSync28, readdirSync as readdirSync15 } from "fs";
|
|
8011
|
+
import { existsSync as existsSync28, readdirSync as readdirSync15, statSync as statSync10 } from "fs";
|
|
8007
8012
|
import { join as join30 } from "path";
|
|
8008
8013
|
var WALK_EXCLUDE_DIRS = /* @__PURE__ */ new Set([
|
|
8009
8014
|
"node_modules",
|
|
@@ -8014,11 +8019,15 @@ var WALK_EXCLUDE_DIRS = /* @__PURE__ */ new Set([
|
|
|
8014
8019
|
"coverage",
|
|
8015
8020
|
".cache"
|
|
8016
8021
|
]);
|
|
8022
|
+
var REFERENCE_BUILD_DIRNAME = "reference-build";
|
|
8023
|
+
var APPROVED_CAPTURES_SUBPATH = join30("captures", "approved");
|
|
8024
|
+
var MISSING_MANIFEST_REASON = `missing ${BLESSED_MANIFEST_FILENAME}`;
|
|
8017
8025
|
function discoverBlessedBuilds(blessedDir, maxDepth = 8) {
|
|
8018
8026
|
const builds = [];
|
|
8027
|
+
const incomplete = [];
|
|
8019
8028
|
const errors = [];
|
|
8020
8029
|
if (!existsSync28(blessedDir)) {
|
|
8021
|
-
return { builds, errors };
|
|
8030
|
+
return { builds, incomplete, errors };
|
|
8022
8031
|
}
|
|
8023
8032
|
walk2(blessedDir, 0);
|
|
8024
8033
|
builds.sort((a, b) => {
|
|
@@ -8027,7 +8036,8 @@ function discoverBlessedBuilds(blessedDir, maxDepth = 8) {
|
|
|
8027
8036
|
}
|
|
8028
8037
|
return a.manifest.pattern.localeCompare(b.manifest.pattern);
|
|
8029
8038
|
});
|
|
8030
|
-
|
|
8039
|
+
incomplete.sort((a, b) => a.dir.localeCompare(b.dir));
|
|
8040
|
+
return { builds, incomplete, errors };
|
|
8031
8041
|
function walk2(dir, depth) {
|
|
8032
8042
|
if (depth > maxDepth) return;
|
|
8033
8043
|
let entries;
|
|
@@ -8048,6 +8058,10 @@ function discoverBlessedBuilds(blessedDir, maxDepth = 8) {
|
|
|
8048
8058
|
}
|
|
8049
8059
|
return;
|
|
8050
8060
|
}
|
|
8061
|
+
if (isNearMissRoot(dir, entries)) {
|
|
8062
|
+
incomplete.push({ dir, reason: MISSING_MANIFEST_REASON });
|
|
8063
|
+
return;
|
|
8064
|
+
}
|
|
8051
8065
|
for (const entry of entries) {
|
|
8052
8066
|
if (!entry.isDirectory()) continue;
|
|
8053
8067
|
if (WALK_EXCLUDE_DIRS.has(entry.name)) continue;
|
|
@@ -8055,6 +8069,19 @@ function discoverBlessedBuilds(blessedDir, maxDepth = 8) {
|
|
|
8055
8069
|
}
|
|
8056
8070
|
}
|
|
8057
8071
|
}
|
|
8072
|
+
function isNearMissRoot(dir, entries) {
|
|
8073
|
+
const hasReferenceBuild = entries.some(
|
|
8074
|
+
(entry) => entry.isDirectory() && entry.name === REFERENCE_BUILD_DIRNAME
|
|
8075
|
+
);
|
|
8076
|
+
if (!hasReferenceBuild) return false;
|
|
8077
|
+
const approved = join30(dir, APPROVED_CAPTURES_SUBPATH);
|
|
8078
|
+
try {
|
|
8079
|
+
if (!statSync10(approved).isDirectory()) return false;
|
|
8080
|
+
} catch {
|
|
8081
|
+
return false;
|
|
8082
|
+
}
|
|
8083
|
+
return !existsSync28(join30(dir, REFERENCE_BUILD_DIRNAME, BLESSED_MANIFEST_FILENAME));
|
|
8084
|
+
}
|
|
8058
8085
|
function resolveBlessedBuild(blessedDir, shape, pattern2) {
|
|
8059
8086
|
const { builds } = discoverBlessedBuilds(blessedDir);
|
|
8060
8087
|
const build = builds.find(
|
|
@@ -8064,13 +8091,18 @@ function resolveBlessedBuild(blessedDir, shape, pattern2) {
|
|
|
8064
8091
|
}
|
|
8065
8092
|
|
|
8066
8093
|
// src/commands/spawn.ts
|
|
8067
|
-
var
|
|
8068
|
-
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
|
|
8073
|
-
);
|
|
8094
|
+
var BLESSED_ROOT_DIRNAME = "design-prototypes";
|
|
8095
|
+
var NO_BLESSED_ROOT_ERROR = `No blessed-build root configured. Pass --blessed-dir <path>, set VISOR_BLESSED_DIR, or run from a checkout that contains a '${BLESSED_ROOT_DIRNAME}/' directory. See docs/blessed-builds.md.`;
|
|
8096
|
+
function discoverBlessedRoot(cwd) {
|
|
8097
|
+
let dir = resolve19(cwd);
|
|
8098
|
+
for (; ; ) {
|
|
8099
|
+
const candidate = join31(dir, BLESSED_ROOT_DIRNAME);
|
|
8100
|
+
if (existsSync29(candidate) && statSync11(candidate).isDirectory()) return candidate;
|
|
8101
|
+
const parent = dirname13(dir);
|
|
8102
|
+
if (parent === dir) return void 0;
|
|
8103
|
+
dir = parent;
|
|
8104
|
+
}
|
|
8105
|
+
}
|
|
8074
8106
|
var FORK_EXCLUDE = /* @__PURE__ */ new Set([
|
|
8075
8107
|
"node_modules",
|
|
8076
8108
|
".next",
|
|
@@ -8099,8 +8131,11 @@ function parseBlessedIdentifier(from) {
|
|
|
8099
8131
|
return { shape: parts[0], pattern: parts[1] };
|
|
8100
8132
|
}
|
|
8101
8133
|
function resolveBlessedDir(cwd, options) {
|
|
8102
|
-
const
|
|
8103
|
-
|
|
8134
|
+
const explicit = options.blessedDir ?? (process.env.VISOR_BLESSED_DIR && process.env.VISOR_BLESSED_DIR.length > 0 ? process.env.VISOR_BLESSED_DIR : void 0);
|
|
8135
|
+
if (explicit !== void 0) {
|
|
8136
|
+
return isAbsolute5(explicit) ? explicit : resolve19(cwd, explicit);
|
|
8137
|
+
}
|
|
8138
|
+
return discoverBlessedRoot(cwd);
|
|
8104
8139
|
}
|
|
8105
8140
|
function resolveThemeFile(theme2, cwd, themeFile) {
|
|
8106
8141
|
const candidates = [];
|
|
@@ -8162,6 +8197,7 @@ function runSpawn(cwd, options) {
|
|
|
8162
8197
|
if (!options.output) throw new Error("Missing required --output <path>.");
|
|
8163
8198
|
const { shape, pattern: pattern2 } = parseBlessedIdentifier(options.from);
|
|
8164
8199
|
const blessedDir = resolveBlessedDir(cwd, options);
|
|
8200
|
+
if (blessedDir === void 0) throw new Error(NO_BLESSED_ROOT_ERROR);
|
|
8165
8201
|
const { build, available } = resolveBlessedBuild(blessedDir, shape, pattern2);
|
|
8166
8202
|
if (!build) {
|
|
8167
8203
|
const list = available.length > 0 ? available.map((b) => ` - blessed:${b.manifest.shape}:${b.manifest.pattern}`).join("\n") : " (none found)";
|
|
@@ -8218,7 +8254,8 @@ ${list}`
|
|
|
8218
8254
|
}
|
|
8219
8255
|
function listBlessed(cwd, options) {
|
|
8220
8256
|
const blessedDir = resolveBlessedDir(cwd, options);
|
|
8221
|
-
|
|
8257
|
+
if (blessedDir === void 0) throw new Error(NO_BLESSED_ROOT_ERROR);
|
|
8258
|
+
const { builds, incomplete, errors } = discoverBlessedBuilds(blessedDir);
|
|
8222
8259
|
if (options.json) {
|
|
8223
8260
|
console.log(
|
|
8224
8261
|
JSON.stringify({
|
|
@@ -8233,6 +8270,7 @@ function listBlessed(cwd, options) {
|
|
|
8233
8270
|
three_gates_status: b.manifest.three_gates_status,
|
|
8234
8271
|
dir: b.dir
|
|
8235
8272
|
})),
|
|
8273
|
+
incomplete,
|
|
8236
8274
|
errors
|
|
8237
8275
|
})
|
|
8238
8276
|
);
|
|
@@ -8246,6 +8284,14 @@ function listBlessed(cwd, options) {
|
|
|
8246
8284
|
logger.success(`blessed:${b.manifest.shape}:${b.manifest.pattern}`);
|
|
8247
8285
|
logger.item(`base theme: ${b.manifest.base_theme} \xB7 requires visor ${b.manifest.requires_visor} \xB7 gates: ${b.manifest.three_gates_status}`);
|
|
8248
8286
|
}
|
|
8287
|
+
if (incomplete.length > 0) {
|
|
8288
|
+
logger.blank();
|
|
8289
|
+
logger.heading(`Near-miss builds (not spawnable) \u2014 ${incomplete.length}`);
|
|
8290
|
+
for (const i of incomplete) {
|
|
8291
|
+
logger.warn(i.dir);
|
|
8292
|
+
logger.item(i.reason);
|
|
8293
|
+
}
|
|
8294
|
+
}
|
|
8249
8295
|
for (const e of errors) {
|
|
8250
8296
|
logger.warn(`Skipped ${e.dir}: ${e.error}`);
|
|
8251
8297
|
}
|
|
@@ -8288,7 +8334,7 @@ function spawnCommand(cwd, options) {
|
|
|
8288
8334
|
|
|
8289
8335
|
// src/commands/render.ts
|
|
8290
8336
|
import { existsSync as existsSync30, mkdirSync as mkdirSync14, readFileSync as readFileSync32 } from "fs";
|
|
8291
|
-
import { dirname as
|
|
8337
|
+
import { dirname as dirname14, isAbsolute as isAbsolute6, resolve as resolve20 } from "path";
|
|
8292
8338
|
var FIXTURES = {
|
|
8293
8339
|
"stat-card": {
|
|
8294
8340
|
default: {
|
|
@@ -8650,7 +8696,7 @@ async function renderCommand(component, cwd, options) {
|
|
|
8650
8696
|
const width = Number(options.width ?? 720);
|
|
8651
8697
|
const height = Number(options.height ?? 640);
|
|
8652
8698
|
const outPath = resolveOutPath(cwd, options.out, component, options.theme, mode, state);
|
|
8653
|
-
mkdirSync14(
|
|
8699
|
+
mkdirSync14(dirname14(outPath), { recursive: true });
|
|
8654
8700
|
const browser = await playwright.chromium.launch();
|
|
8655
8701
|
let probe;
|
|
8656
8702
|
try {
|
|
@@ -8762,7 +8808,7 @@ function formatBytes2(bytes) {
|
|
|
8762
8808
|
}
|
|
8763
8809
|
|
|
8764
8810
|
// src/index.ts
|
|
8765
|
-
var __dirname2 =
|
|
8811
|
+
var __dirname2 = dirname15(fileURLToPath4(import.meta.url));
|
|
8766
8812
|
var pkg = JSON.parse(
|
|
8767
8813
|
readFileSync33(join33(__dirname2, "..", "package.json"), "utf-8")
|
|
8768
8814
|
);
|
|
@@ -8959,7 +9005,7 @@ sandbox.command("approve").description(
|
|
|
8959
9005
|
);
|
|
8960
9006
|
program.command("spawn").description(
|
|
8961
9007
|
"Fork a Playbook blessed reference build with atomic theme re-skinning \u2014 one command replaces cp -R + npm install + theme apply"
|
|
8962
|
-
).option("--from <identifier>", "blessed build to spawn: blessed:{shape}:{pattern}").option("--theme <id>", "theme id (or path to a .visor.yaml) to re-skin the fork with").option("--theme-file <path>", "explicit path to a theme.visor.yaml \u2014 bypasses --theme name resolution").option("--output <path>", "destination directory for the forked project").option("--blessed-dir <path>", "override the blessed-build root (default: VISOR_BLESSED_DIR
|
|
9008
|
+
).option("--from <identifier>", "blessed build to spawn: blessed:{shape}:{pattern}").option("--theme <id>", "theme id (or path to a .visor.yaml) to re-skin the fork with").option("--theme-file <path>", "explicit path to a theme.visor.yaml \u2014 bypasses --theme name resolution").option("--output <path>", "destination directory for the forked project").option("--blessed-dir <path>", "override the blessed-build root (default: VISOR_BLESSED_DIR, else the nearest design-prototypes/ directory found by walking up from the cwd)").option("--install", "run npm install in the forked project (default: skip)").option("--validate", "validate the applied theme after forking (default: skip)").option("--list-blessed", "list all discoverable blessed builds and exit").option("--json", "output structured JSON (for AI agents)").action((options) => {
|
|
8963
9009
|
spawnCommand(process.cwd(), options);
|
|
8964
9010
|
});
|
|
8965
9011
|
program.command("render").description(
|