@norskvideo/ctl-dev-kit 0.2.40 → 0.2.42

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.
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bun
2
+ export interface EngineVerdict {
3
+ ok: boolean;
4
+ reason: string;
5
+ }
6
+ export declare function engineVerdict(output: string): EngineVerdict;
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Whether a doc-guide engine tier that exited non-zero failed for real, or only
4
+ * a teardown hook ran out of time after every guide's test had passed. Each
5
+ * product's scripts/doc-guide/regen-manual.sh asks this, from the tier's own
6
+ * output, instead of "are the capture files on disk": that rule passed a
7
+ * composition guide that hung after two captures (2026-10-03) and passed any
8
+ * guide whose assertions failed after its captures were written. The engine
9
+ * tier is also half of the publish gate (dev-kit conventions/build-image.yml),
10
+ * so what it forgives, the gate forgives.
11
+ *
12
+ * Forgiven: every result line a test passed, apart from unnamed hook failures
13
+ * in guides that also passed a test. Anything else -- a named test failing, a
14
+ * guide whose only result is a failed hook (its setup never finished), or no
15
+ * results at all -- is a real failure.
16
+ *
17
+ * Reads both runners' list output: bun test (`(pass) guide > test [ms]`,
18
+ * `(fail) guide > (unnamed)` for a hook) and Playwright (`✓ n [project] ›
19
+ * file:line › guide › test (t)`; an afterAll failing after every test passed
20
+ * belongs to no test, so it leaves only ✓ lines).
21
+ *
22
+ * bun engine-verdict.ts <captured engine-tier output>
23
+ * exit 0 = teardown only (continue), 1 = real failure (abort)
24
+ *
25
+ * Imports only node: it runs inside product repos (see publish/product-channel.ts).
26
+ */
27
+ import { readFileSync } from "node:fs";
28
+ /** Colour escapes (ESC [ ... m), built from a string: lint refuses a control
29
+ * character in a regex literal. */
30
+ const ANSI = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
31
+ const BUN = /\((pass|fail)\) (.+?) > (.+?) \[[\d.]+m?s\]\s*$/;
32
+ const PLAYWRIGHT = /([✓✘])\s+\d+ \[[^\]]*\] › [^›]+ › (.+?) › (.+?) \([\d.]+m?s\)\s*$/;
33
+ function results(output) {
34
+ const out = [];
35
+ for (const raw of output.split("\n")) {
36
+ const line = raw.replace(ANSI, "");
37
+ const b = line.match(BUN);
38
+ if (b) {
39
+ out.push({ guide: b[2], test: b[3], passed: b[1] === "pass" });
40
+ continue;
41
+ }
42
+ const p = line.match(PLAYWRIGHT);
43
+ if (p)
44
+ out.push({ guide: p[2], test: p[3], passed: p[1] === "✓" });
45
+ }
46
+ return out;
47
+ }
48
+ export function engineVerdict(output) {
49
+ const all = results(output);
50
+ if (all.length === 0)
51
+ return { ok: false, reason: "no test results in the engine tier's output" };
52
+ const failedTests = all.filter((r) => !r.passed && r.test !== "(unnamed)");
53
+ const passedGuides = new Set(all.filter((r) => r.passed).map((r) => r.guide));
54
+ const hookOnlyGuides = [
55
+ ...new Set(all.filter((r) => !r.passed && r.test === "(unnamed)" && !passedGuides.has(r.guide)).map((r) => r.guide)),
56
+ ];
57
+ const problems = [
58
+ ...failedTests.map((r) => `failed: ${r.guide} > ${r.test}`),
59
+ ...hookOnlyGuides.map((g) => `never ran (only a hook result): ${g}`),
60
+ ];
61
+ return problems.length ? { ok: false, reason: problems.join("; ") } : { ok: true, reason: "teardown only" };
62
+ }
63
+ if (import.meta.main) {
64
+ const path = process.argv[2];
65
+ if (!path) {
66
+ console.error("usage: engine-verdict.ts <captured engine-tier output>");
67
+ process.exit(2);
68
+ }
69
+ const verdict = engineVerdict(readFileSync(path, "utf8"));
70
+ console.log(verdict.ok ? `engine tier: ${verdict.reason}` : `engine tier failed: ${verdict.reason}`);
71
+ process.exit(verdict.ok ? 0 : 1);
72
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@norskvideo/ctl-dev-kit",
3
- "version": "0.2.40",
3
+ "version": "0.2.42",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./create-product": "./create-product/create-product.ts",
@@ -8,6 +8,7 @@
8
8
  "./doc-guide/build-manual": "./doc-guide/build-manual.js",
9
9
  "./doc-guide/bundle": "./doc-guide/bundle.js",
10
10
  "./doc-guide/docs-release": "./doc-guide/docs-release.js",
11
+ "./doc-guide/engine-verdict": "./doc-guide/engine-verdict.js",
11
12
  "./doc-guide/guides-config": "./doc-guide/guides-config.js",
12
13
  "./doc-guide/instance-proxy": "./doc-guide/instance-proxy.js",
13
14
  "./doc-guide/live-browser": "./doc-guide/live-browser.js",
@@ -36,10 +37,10 @@
36
37
  },
37
38
  "devDependencies": {
38
39
  "@norskvideo/ctl-oas-to-ts": "^0.1.0",
39
- "@norskvideo/norsk-sdk": "1.3.1-2026-10-04-dc313351",
40
- "@norskvideo/norsk-studio": "1.30.0-2026-10-04-e672beb6",
41
- "@norskvideo/norsk-studio-builder": "1.30.0-2026-10-04-e672beb6",
42
- "@norskvideo/norsk-studio-built-ins": "1.30.0-2026-10-04-e672beb6",
40
+ "@norskvideo/norsk-sdk": "1.3.1-2026-10-04-f034e83d",
41
+ "@norskvideo/norsk-studio": "1.30.0-2026-10-05-3d2846dc",
42
+ "@norskvideo/norsk-studio-builder": "1.30.0-2026-10-05-3d2846dc",
43
+ "@norskvideo/norsk-studio-built-ins": "1.30.0-2026-10-05-3d2846dc",
43
44
  "@playwright/test": "^1.59.0",
44
45
  "@types/bun": "latest",
45
46
  "@types/cors": "^2.8.17",