@glissade/cli 0.59.0 → 0.60.0-pre.1

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 };
@@ -156,10 +156,20 @@ const EXEMPT_INTERNALS = new Set([
156
156
  "vec2Equals",
157
157
  "vec2Signal",
158
158
  "velocityAt",
159
- "validateScene",
160
- "resolveAt",
161
- "instanceProps",
162
- "DIAGNOSTIC_SCHEMA_VERSION"
159
+ "DIAGNOSTIC_SCHEMA_VERSION",
160
+ "emitWithIds",
161
+ "diffDisplayLists",
162
+ "formatDisplayDiff",
163
+ "serializeDisplayList",
164
+ "parseDisplaySnapshot",
165
+ "DL_SNAPSHOT_VERSION",
166
+ "auditCacheCold",
167
+ "collectTextUsages",
168
+ "collectLocalizedTextUsages",
169
+ "validateSceneFonts",
170
+ "nearestId",
171
+ "levenshtein",
172
+ "sortDiagnostics"
163
173
  ]);
164
174
  /**
165
175
  * PATTERN-exempt runtime exports (no per-name entry needed): error classes
@@ -208,7 +218,7 @@ function describeLint(manifest, surface, opts = {}) {
208
218
  const callables = /* @__PURE__ */ new Set();
209
219
  for (const name of Object.keys(manifest.nodes)) callables.add(name);
210
220
  for (const h of manifest.helpers) callables.add(h.name);
211
- for (const e of manifest.surface ?? []) if (e.kind === "value" && (e.form === "constructor" || e.form === "function")) callables.add(e.name);
221
+ for (const e of manifest.surface ?? []) if ((e.kind === "value" || e.kind === "diagnostic") && (e.form === "constructor" || e.form === "function")) callables.add(e.name);
212
222
  for (const name of [...callables].sort()) {
213
223
  if (exempt.has(name) || isFn(name)) continue;
214
224
  out.push(present(name) ? {
@@ -269,6 +279,7 @@ async function collectRuntimeSurface(manifest) {
269
279
  "@glissade/core/clips",
270
280
  "@glissade/scene",
271
281
  "@glissade/scene/describe",
282
+ "@glissade/scene/diagnostics",
272
283
  "@glissade/scene/layout-ctors",
273
284
  "@glissade/scene/path"
274
285
  ]);
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.1",
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.1",
32
+ "@glissade/core": "0.60.0-pre.1",
33
+ "@glissade/interact": "0.60.0-pre.1",
34
+ "@glissade/lottie": "0.60.0-pre.1",
35
+ "@glissade/narrate": "0.60.0-pre.1",
36
+ "@glissade/player": "0.60.0-pre.1",
37
+ "@glissade/scene": "0.60.0-pre.1",
38
+ "@glissade/sfx": "0.60.0-pre.1",
39
+ "@glissade/svg": "0.60.0-pre.1"
40
40
  },
41
41
  "repository": {
42
42
  "type": "git",