@norskvideo/ctl-dev-kit 0.2.58 → 0.2.60
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.
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
// tsconfig.base.json, the .gitignore core block, scripts/demo (only a
|
|
6
6
|
// product with tests/demo.spec.ts is asked for it), publish-docs-site.yml
|
|
7
7
|
// (only a repo with a docs site may carry it, and never a turnkey)
|
|
8
|
-
// - masked per-repo line: checks.yml
|
|
8
|
+
// - masked per-repo line: checks.yml, upgrade-latest.yml, publish-docs.yml
|
|
9
|
+
// and the other dispatching workflows (`product:` key)
|
|
9
10
|
// - base + sanctioned extension block: dprint.json (repo-specific excludes)
|
|
10
11
|
// - must import the shared module: flake.nix (otherwise the product's own)
|
|
11
12
|
// - structural: root tsconfig.json (shape-dependent includes stay free),
|
|
@@ -789,18 +790,21 @@ export function checkDrift(repoRoot: string, canonical: CanonicalBytes, opts: Ch
|
|
|
789
790
|
}
|
|
790
791
|
|
|
791
792
|
// publish-docs.yml is OPTIONAL — a product carries it once it has an
|
|
792
|
-
// illustrated manual to publish nightly.
|
|
793
|
-
//
|
|
794
|
-
//
|
|
795
|
-
// verbatim
|
|
793
|
+
// illustrated manual to publish nightly. Everything per-repo about the manual
|
|
794
|
+
// lives in scripts/doc-guide/regen-manual.sh (+ an optional prepull-extra.sh);
|
|
795
|
+
// the one per-repo line is the `product:` key its `docs` result is dispatched
|
|
796
|
+
// under, masked like checks.yml's. It was held verbatim when that dispatch was
|
|
797
|
+
// added, so the only passing copy was one that sent the placeholder.
|
|
796
798
|
const publishDocsPath = join(repoRoot, ".github", "workflows", "publish-docs.yml");
|
|
797
799
|
if (existsSync(publishDocsPath)) {
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
800
|
+
push(
|
|
801
|
+
workflowProblem(
|
|
802
|
+
".github/workflows/publish-docs.yml",
|
|
803
|
+
"conventions/publish-docs.yml",
|
|
804
|
+
readFileSync(publishDocsPath, "utf8"),
|
|
805
|
+
canonical.publishDocs,
|
|
806
|
+
),
|
|
807
|
+
);
|
|
804
808
|
}
|
|
805
809
|
|
|
806
810
|
// build-docs.yml is the embedded twin of publish-docs.yml: optional, verbatim.
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
# whenever it builds its docs.
|
|
14
14
|
#
|
|
15
15
|
# This workflow is SINGLE-SOURCED in @norskvideo/ctl-dev-kit
|
|
16
|
-
# (conventions/publish-docs.yml) and copied verbatim, same as checks.yml
|
|
17
|
-
#
|
|
18
|
-
# it calls —
|
|
16
|
+
# (conventions/publish-docs.yml) and copied verbatim, same as checks.yml: only
|
|
17
|
+
# the `product:` value below is per-repo (set it to this repo's dashboard key).
|
|
18
|
+
# Everything else per-repo lives in repo-local scripts it calls —
|
|
19
19
|
# - scripts/doc-guide/regen-manual.sh : the guide tiers + slug list + assemble
|
|
20
20
|
# - scripts/doc-guide/prepull-extra.sh : OPTIONAL, any images beyond media+studio
|
|
21
|
-
# so the drift gate can keep every product's copy byte-identical.
|
|
21
|
+
# so the drift gate can keep every product's copy otherwise byte-identical.
|
|
22
22
|
#
|
|
23
23
|
# Nightly-only by design: a guide's engine tier stands up real instances (slow,
|
|
24
24
|
# and subject to teardown flakes), so it does not ride every push. The
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
// It only touches copies whose convergent form is mechanical — there is no
|
|
8
8
|
// judgement anywhere:
|
|
9
9
|
// - verbatim (biome.json, tsconfig.base.json) -> overwrite with canonical
|
|
10
|
-
// - masked workflows (checks / upgrade / sync
|
|
10
|
+
// - masked workflows (checks / upgrade / sync / -> canonical, repo's product: key kept
|
|
11
|
+
// publish-docs)
|
|
11
12
|
// - nix/ctl-shell.nix -> overwrite with canonical (created if absent)
|
|
12
13
|
// - flake.nix (legacy verbatim copy only) -> the starter, repo's floating ctl pin kept
|
|
13
14
|
// - marker-block (CLAUDE core, dprint, .gitignore) -> replace the shared block, keep the rest
|
|
@@ -86,6 +87,28 @@ function syncWorkflow(repoRoot: string, rel: string, canonical: string, r: SyncR
|
|
|
86
87
|
writeIfChanged(path, canonical.replace(PRODUCT_LINE, `$1${key}`), rel, r.written);
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
// publish-docs.yml: optional, and masked like checks.yml (only re-synced where
|
|
91
|
+
// the repo already carries it). Every copy predating the mask was written
|
|
92
|
+
// verbatim with the sentinel, so a copy with no key of its own takes the one
|
|
93
|
+
// checks.yml (required, and always filled) dispatches under — otherwise no
|
|
94
|
+
// nightly could ever converge those copies.
|
|
95
|
+
function syncPublishDocs(repoRoot: string, canonical: string, r: SyncReport): void {
|
|
96
|
+
const rel = ".github/workflows/publish-docs.yml";
|
|
97
|
+
const path = join(repoRoot, rel);
|
|
98
|
+
if (!existsSync(path)) return;
|
|
99
|
+
const own = readFileSync(path, "utf8").match(/^\s*product:\s*(\S+)/m)?.[1];
|
|
100
|
+
const checksPath = join(repoRoot, ".github/workflows/checks.yml");
|
|
101
|
+
const fromChecks = existsSync(checksPath)
|
|
102
|
+
? readFileSync(checksPath, "utf8").match(/^\s*product:\s*(\S+)/m)?.[1]
|
|
103
|
+
: undefined;
|
|
104
|
+
const key = own && own !== PRODUCT_SENTINEL ? own : fromChecks;
|
|
105
|
+
if (!key || key === PRODUCT_SENTINEL) {
|
|
106
|
+
r.skipped.push(`${rel} (no product: key to preserve)`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
writeIfChanged(path, canonical.replace(PRODUCT_LINE, `$1${key}`), rel, r.written);
|
|
110
|
+
}
|
|
111
|
+
|
|
89
112
|
// build-image.yml: canonical byte-for-byte except two per-repo lines — the
|
|
90
113
|
// notify job's `product:` dispatch key and the PUBLISH_IMAGE env (the Docker Hub
|
|
91
114
|
// repo, or empty for a build-only product). Re-emit the canonical with both of
|
|
@@ -376,12 +399,7 @@ export function syncDrift(
|
|
|
376
399
|
syncSmoke(repoRoot, canonical.smoke, r);
|
|
377
400
|
syncIntegration(repoRoot, canonical.integration, r);
|
|
378
401
|
|
|
379
|
-
|
|
380
|
-
// repo that already carries it, unlike biome/tsconfig which every repo must have.
|
|
381
|
-
const publishDocsRel = ".github/workflows/publish-docs.yml";
|
|
382
|
-
if (existsSync(join(repoRoot, publishDocsRel))) {
|
|
383
|
-
writeIfChanged(join(repoRoot, publishDocsRel), canonical.publishDocs, publishDocsRel, r.written);
|
|
384
|
-
}
|
|
402
|
+
syncPublishDocs(repoRoot, canonical.publishDocs, r);
|
|
385
403
|
// build-docs.yml, the embedded variant, the same way: carrying it is the
|
|
386
404
|
// repo's declaration (ADR-0012); sync only keeps the copy verbatim.
|
|
387
405
|
const buildDocsRel = ".github/workflows/build-docs.yml";
|
package/doc-guide/doc-guide.d.ts
CHANGED
|
@@ -28,11 +28,13 @@ export declare function docsRoot(): string;
|
|
|
28
28
|
* at about 2.5 words/s: 35 words is 14 s on one still, 50 is 20 s, and the
|
|
29
29
|
* renderer's own lint warns at 35. This is the hard stop. */
|
|
30
30
|
export declare const DEFAULT_CAPTION_WORDS = 50;
|
|
31
|
+
/** The part of a step's text that is narrated: everything but its fenced blocks. */
|
|
32
|
+
export declare function spokenText(text: string): string;
|
|
31
33
|
/** Why a step's text cannot be narrated as written, or null when it can. Pure,
|
|
32
34
|
* so the wording is pinned without a browser. Checks the budget first: an
|
|
33
35
|
* over-long caption gets rewritten anyway, and the rewrite is where the
|
|
34
|
-
* phrasing gets fixed. */
|
|
35
|
-
export declare function captionFault(
|
|
36
|
+
* phrasing gets fixed. Only the spoken part is held to either. */
|
|
37
|
+
export declare function captionFault(caption: string, budget: number): string | null;
|
|
36
38
|
/** Device scale factor for a capture: 2 in a DOCS_GENERATE run, 1 otherwise.
|
|
37
39
|
* The video spike found the manual's component crops 383 to 778 px wide; in
|
|
38
40
|
* a 1080p frame they are soft, and no renderer recovers detail that was never
|
package/doc-guide/doc-guide.js
CHANGED
|
@@ -17,11 +17,19 @@ export const DEFAULT_CAPTION_WORDS = 50;
|
|
|
17
17
|
const SPOKEN_WORD = /[\p{L}\p{N}]/u;
|
|
18
18
|
const RAW_URL = /https?:\/\/\S+/;
|
|
19
19
|
const SLASH_BETWEEN_WORDS = /\S+\/\S+/;
|
|
20
|
+
/** A fenced block (``` or ~~~, closed or running to the end as markdown has
|
|
21
|
+
* it) is a transcript or a file to copy: the page shows it, nobody speaks it. */
|
|
22
|
+
const FENCED_BLOCK = /^(`{3,}|~{3,})[^\n]*$[\s\S]*?(?:^\1[ \t]*$|(?![\s\S]))/gm;
|
|
23
|
+
/** The part of a step's text that is narrated: everything but its fenced blocks. */
|
|
24
|
+
export function spokenText(text) {
|
|
25
|
+
return text.replace(FENCED_BLOCK, "");
|
|
26
|
+
}
|
|
20
27
|
/** Why a step's text cannot be narrated as written, or null when it can. Pure,
|
|
21
28
|
* so the wording is pinned without a browser. Checks the budget first: an
|
|
22
29
|
* over-long caption gets rewritten anyway, and the rewrite is where the
|
|
23
|
-
* phrasing gets fixed. */
|
|
24
|
-
export function captionFault(
|
|
30
|
+
* phrasing gets fixed. Only the spoken part is held to either. */
|
|
31
|
+
export function captionFault(caption, budget) {
|
|
32
|
+
const text = spokenText(caption);
|
|
25
33
|
const count = text.split(/\s+/).filter((token) => SPOKEN_WORD.test(token)).length;
|
|
26
34
|
if (count > budget)
|
|
27
35
|
return `${count} words; the spoken budget is ${budget}`;
|