@glissade/cli 0.59.0 → 0.60.0-pre.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -82,6 +82,7 @@ function parseCaptionsModeOrFail(raw) {
82
82
  const USAGE = `usage:
83
83
  gs render <scene-module> [options]
84
84
  gs diff <scene-module> --at <t> --against <baseline.dl.json|.png>
85
+ gs critique <scene-module> [--json] machine-readable RENDERED diagnostics (OFF_CANVAS/TEXT_OVERFLOW/OCCLUSION) from the DisplayList — the rendered-geometric half of validateScene; samples an integer-frame grid, prints the flat canonically-sorted diagnostics (--json for the raw result)
85
86
  gs verify-determinism <scene-module> [--shards <n>] [--against <frames.manifest>] [--range a..b] [--bisect] [--emit <p>]
86
87
  gs dev <scene-module> [--record] [--port <n>]
87
88
  gs import <lottie.json|asset.svg> [--out <dir>] [--allow-degraded]
@@ -212,7 +213,7 @@ async function main() {
212
213
  process.stdout.write(`${describe().version}\n`);
213
214
  return;
214
215
  }
215
- if (command !== "render" && command !== "diff" && command !== "verify-determinism" && command !== "dev" && command !== "import" && command !== "export" && command !== "narrate" && command !== "narration-lint" && command !== "sfx" && command !== "prepare" && command !== "measure-loudness" && command !== "fonts" && command !== "cache" && command !== "mcp" && command !== "build" && command !== "describe" && command !== "migrate" && command !== "repin" && command !== "parity" && command !== "master" && command !== "localize" && command !== "types") {
216
+ if (command !== "render" && command !== "diff" && command !== "critique" && command !== "verify-determinism" && command !== "dev" && command !== "import" && command !== "export" && command !== "narrate" && command !== "narration-lint" && command !== "sfx" && command !== "prepare" && command !== "measure-loudness" && command !== "fonts" && command !== "cache" && command !== "mcp" && command !== "build" && command !== "describe" && command !== "migrate" && command !== "repin" && command !== "parity" && command !== "master" && command !== "localize" && command !== "types") {
216
217
  console.error(USAGE);
217
218
  process.exit(command === void 0 || command === "help" || command === "--help" ? 0 : 1);
218
219
  }
@@ -653,6 +654,20 @@ async function main() {
653
654
  }
654
655
  return;
655
656
  }
657
+ if (command === "critique") {
658
+ const { critiqueCommand } = await import("./critique.js");
659
+ try {
660
+ const out = await critiqueCommand({
661
+ modulePath,
662
+ json: flags.has("json")
663
+ });
664
+ process.stdout.write(`${out.report}\n`);
665
+ if (out.hasErrors) process.exit(1);
666
+ } catch (err) {
667
+ fail(err instanceof Error ? err.message : String(err));
668
+ }
669
+ return;
670
+ }
656
671
  if (command === "verify-determinism") {
657
672
  let frameRange;
658
673
  const rangeFlag = flags.get("range");
@@ -0,0 +1,53 @@
1
+ import { o as loadSceneModule } from "./render.js";
2
+ import { critique } from "@glissade/scene/diagnostics";
3
+ //#region src/critique.ts
4
+ /**
5
+ * `gs critique <scene-module>` (0.60): machine-readable RENDERED diagnostics from
6
+ * the DisplayList — the rendered-geometric half of `gs describe --lint` /
7
+ * validateScene. Loads the scene, injects the Skia measurer (so TEXT_OVERFLOW
8
+ * measures with the same metrics `gs render` lays out with), runs `critique`, and
9
+ * prints the flat, canonically-sorted diagnostics. `--json` emits the raw result
10
+ * for a machine consumer; exits non-zero iff any diagnostic is `error` severity
11
+ * (only static errors are — the rendered pass emits warnings/info).
12
+ */
13
+ async function critiqueCommand(opts) {
14
+ try {
15
+ const { loadYogaLayoutEngine } = await import("@glissade/scene/layout");
16
+ await loadYogaLayoutEngine();
17
+ } catch {}
18
+ const mod = await loadSceneModule(opts.modulePath);
19
+ const scene = mod.createScene();
20
+ const { SkiaBackend } = await import("@glissade/backend-skia");
21
+ scene.setTextMeasurer(new SkiaBackend(scene.size.w, scene.size.h));
22
+ const result = critique(scene, mod.timeline);
23
+ if (opts.json) return {
24
+ result,
25
+ report: JSON.stringify(result, null, 2),
26
+ hasErrors: result.hasErrors
27
+ };
28
+ return {
29
+ result,
30
+ report: formatCritique(result),
31
+ hasErrors: result.hasErrors
32
+ };
33
+ }
34
+ function formatCritique(r) {
35
+ const lines = [];
36
+ if (r.renderedSkipped) lines.push(`rendered pass SKIPPED: ${r.renderedSkipReason ?? ""}`);
37
+ else lines.push(`sampled ${r.sampledFrames} integer-frame grid sample(s).`);
38
+ if (r.diagnostics.length === 0) {
39
+ lines.push("ok — no diagnostics (clean scene).");
40
+ return lines.join("\n");
41
+ }
42
+ for (const d of r.diagnostics) {
43
+ const where = d.node ? ` [${d.node}]` : d.track ? ` [${d.track}]` : "";
44
+ lines.push(`${d.severity.toUpperCase()} ${d.code}${where} (${d.source ?? "?"}): ${d.message}`);
45
+ }
46
+ const errs = r.diagnostics.filter((d) => d.severity === "error").length;
47
+ const warns = r.diagnostics.filter((d) => d.severity === "warning").length;
48
+ const infos = r.diagnostics.filter((d) => d.severity === "info").length;
49
+ lines.push(`\n${errs} error(s), ${warns} warning(s), ${infos} info.`);
50
+ return lines.join("\n");
51
+ }
52
+ //#endregion
53
+ export { critiqueCommand };
@@ -159,7 +159,9 @@ const EXEMPT_INTERNALS = new Set([
159
159
  "validateScene",
160
160
  "resolveAt",
161
161
  "instanceProps",
162
- "DIAGNOSTIC_SCHEMA_VERSION"
162
+ "DIAGNOSTIC_SCHEMA_VERSION",
163
+ "critique",
164
+ "emitWithIds"
163
165
  ]);
164
166
  /**
165
167
  * PATTERN-exempt runtime exports (no per-name entry needed): error classes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glissade/cli",
3
- "version": "0.59.0",
3
+ "version": "0.60.0-pre.0",
4
4
  "description": "glissade CLI: headless rendering via backend-skia (+ FFmpeg mux).",
5
5
  "license": "Apache-2.0",
6
6
  "engines": {
@@ -28,15 +28,15 @@
28
28
  "@napi-rs/canvas": "^0.1.65",
29
29
  "esbuild": "0.28.0",
30
30
  "jiti": "^2.4.2",
31
- "@glissade/backend-skia": "0.59.0",
32
- "@glissade/core": "0.59.0",
33
- "@glissade/interact": "0.59.0",
34
- "@glissade/lottie": "0.59.0",
35
- "@glissade/narrate": "0.59.0",
36
- "@glissade/player": "0.59.0",
37
- "@glissade/scene": "0.59.0",
38
- "@glissade/sfx": "0.59.0",
39
- "@glissade/svg": "0.59.0"
31
+ "@glissade/backend-skia": "0.60.0-pre.0",
32
+ "@glissade/core": "0.60.0-pre.0",
33
+ "@glissade/interact": "0.60.0-pre.0",
34
+ "@glissade/lottie": "0.60.0-pre.0",
35
+ "@glissade/narrate": "0.60.0-pre.0",
36
+ "@glissade/player": "0.60.0-pre.0",
37
+ "@glissade/scene": "0.60.0-pre.0",
38
+ "@glissade/sfx": "0.60.0-pre.0",
39
+ "@glissade/svg": "0.60.0-pre.0"
40
40
  },
41
41
  "repository": {
42
42
  "type": "git",