@lingjingai/scriptctl 0.41.0 → 0.43.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.
Files changed (75) hide show
  1. package/changes/0.42.0.md +14 -0
  2. package/changes/0.43.0.md +21 -0
  3. package/dist/cli.js +0 -1
  4. package/dist/cli.js.map +1 -1
  5. package/dist/domain/ingest/serial-context.d.ts +1 -1
  6. package/dist/domain/ingest/serial-context.js +1 -1
  7. package/dist/domain/ingest/serial-context.js.map +1 -1
  8. package/dist/domain/ingest/video-apply.d.ts +0 -33
  9. package/dist/domain/ingest/video-apply.js +8 -159
  10. package/dist/domain/ingest/video-apply.js.map +1 -1
  11. package/dist/domain/ingest/video-context.d.ts +51 -0
  12. package/dist/domain/ingest/video-context.js +293 -0
  13. package/dist/domain/ingest/video-context.js.map +1 -0
  14. package/dist/domain/ingest/video-serial-md.d.ts +60 -0
  15. package/dist/domain/ingest/video-serial-md.js +277 -0
  16. package/dist/domain/ingest/video-serial-md.js.map +1 -0
  17. package/dist/help-text.js +13 -10
  18. package/dist/help-text.js.map +1 -1
  19. package/dist/infra/ingest/video-transcode.d.ts +7 -0
  20. package/dist/infra/ingest/video-transcode.js +86 -0
  21. package/dist/infra/ingest/video-transcode.js.map +1 -0
  22. package/dist/infra/llm/gemini-video-model.js +14 -2
  23. package/dist/infra/llm/gemini-video-model.js.map +1 -1
  24. package/dist/llm/config.js +1 -2
  25. package/dist/llm/config.js.map +1 -1
  26. package/dist/llm/registry.d.ts +1 -7
  27. package/dist/llm/registry.js +9 -17
  28. package/dist/llm/registry.js.map +1 -1
  29. package/dist/llm/tasks/ingest/episode-assets.js +7 -5
  30. package/dist/llm/tasks/ingest/episode-assets.js.map +1 -1
  31. package/dist/llm/tasks/ingest/video-serial.d.ts +9 -0
  32. package/dist/llm/tasks/ingest/video-serial.js +120 -0
  33. package/dist/llm/tasks/ingest/video-serial.js.map +1 -0
  34. package/dist/llm/types.d.ts +1 -1
  35. package/dist/llm/types.js.map +1 -1
  36. package/dist/usecases/ingest/command.js +0 -3
  37. package/dist/usecases/ingest/command.js.map +1 -1
  38. package/dist/usecases/ingest/pipeline.js +6 -1
  39. package/dist/usecases/ingest/pipeline.js.map +1 -1
  40. package/dist/usecases/ingest/serial-govern.d.ts +1 -0
  41. package/dist/usecases/ingest/serial-govern.js +46 -6
  42. package/dist/usecases/ingest/serial-govern.js.map +1 -1
  43. package/dist/usecases/ingest/status.js +8 -20
  44. package/dist/usecases/ingest/status.js.map +1 -1
  45. package/dist/usecases/ingest/video-pipeline.d.ts +0 -6
  46. package/dist/usecases/ingest/video-pipeline.js +145 -127
  47. package/dist/usecases/ingest/video-pipeline.js.map +1 -1
  48. package/dist/usecases/ingest/view-server.d.ts +11 -0
  49. package/dist/usecases/ingest/view-server.js +89 -12
  50. package/dist/usecases/ingest/view-server.js.map +1 -1
  51. package/package.json +1 -1
  52. package/dist/domain/ingest/video-aggregate.d.ts +0 -23
  53. package/dist/domain/ingest/video-aggregate.js +0 -89
  54. package/dist/domain/ingest/video-aggregate.js.map +0 -1
  55. package/dist/domain/ingest/video-md-parser.d.ts +0 -2
  56. package/dist/domain/ingest/video-md-parser.js +0 -233
  57. package/dist/domain/ingest/video-md-parser.js.map +0 -1
  58. package/dist/llm/tasks/ingest/plot-speaker.d.ts +0 -11
  59. package/dist/llm/tasks/ingest/plot-speaker.js +0 -72
  60. package/dist/llm/tasks/ingest/plot-speaker.js.map +0 -1
  61. package/dist/llm/tasks/ingest/roster-merge.d.ts +0 -46
  62. package/dist/llm/tasks/ingest/roster-merge.js +0 -235
  63. package/dist/llm/tasks/ingest/roster-merge.js.map +0 -1
  64. package/dist/llm/tasks/ingest/state-merge.d.ts +0 -10
  65. package/dist/llm/tasks/ingest/state-merge.js +0 -84
  66. package/dist/llm/tasks/ingest/state-merge.js.map +0 -1
  67. package/dist/llm/tasks/ingest/video-correct.d.ts +0 -30
  68. package/dist/llm/tasks/ingest/video-correct.js +0 -144
  69. package/dist/llm/tasks/ingest/video-correct.js.map +0 -1
  70. package/dist/llm/tasks/ingest/video-transcribe.d.ts +0 -4
  71. package/dist/llm/tasks/ingest/video-transcribe.js +0 -105
  72. package/dist/llm/tasks/ingest/video-transcribe.js.map +0 -1
  73. package/dist/usecases/ingest/video-pass3.d.ts +0 -26
  74. package/dist/usecases/ingest/video-pass3.js +0 -0
  75. package/dist/usecases/ingest/video-pass3.js.map +0 -1
@@ -1,32 +1,51 @@
1
- // Video ingest pipeline (§10.2). pass1 transcribe → pass2 parse → pass3 roster
2
- // merge pass4 video-correct pass5 plot-speaker pass6 apply + converge onto
3
- // the SHARED governance tail (assignProvisionalIds runGovern renumberIds
4
- // validateScriptV3) so the final script.json is the exact same v3 as text
5
- // ingest. Expensive LLM units checkpoint for resume; the media file is uploaded
6
- // once per episode and reused across pass1/pass4, deleted best-effort at the end.
1
+ // Video ingest pipeline (§10.2, serial rewrite). Two stages:
2
+ // Stage S parse episodes one at a time, IN ORDER. Each episode's Gemini call
3
+ // watches the video WITH the running cross-episode context (registry + plot
4
+ // digest + open threads) and returns both the episode content and a registry
5
+ // delta. Identity is resolved by plot as we go, so there is no parallel
6
+ // transcribe + roster-merge + correct + speaker compensation. Checkpoint =
7
+ // per episode: ep/ep_NNN.json (content) + context.json (running context,
8
+ // authoritative for resume). script.json is rebuilt after each episode so an
9
+ // editor can stream it as it grows.
10
+ // Stage F — the deterministic tail, SHARED with text ingest: rename provisional
11
+ // names to their revealed identities → docsToNameScript → assignProvisionalIds
12
+ // → stampImportance → governDeterministic → renumberIds → validateScriptV3.
13
+ // The final script.json is the exact same v3 as text ingest.
7
14
  import * as fs from "node:fs";
8
15
  import * as path from "node:path";
9
16
  import { CliError, EXIT_INPUT, sha256Text } from "../../common.js";
10
17
  import { assignProvisionalIds } from "../../domain/ingest/assembler.js";
18
+ import { governDeterministic } from "../../domain/ingest/govern.js";
11
19
  import { renumberIds } from "../../domain/ingest/renumber.js";
12
20
  import { validateScriptV3 } from "../../domain/ingest/validation.js";
13
- import { parseEpisodeMd } from "../../domain/ingest/video-md-parser.js";
14
- import { applyCorrections, docsToNameScript } from "../../domain/ingest/video-apply.js";
21
+ import { applyRename, docsToNameScript } from "../../domain/ingest/video-apply.js";
22
+ import { applyDelta, buildAliasMap, deltaToDoc, emptyContext, renderContext, stampImportance, } from "../../domain/ingest/video-context.js";
15
23
  import { resolveSource } from "../../infra/ingest/source-resolver.js";
16
24
  import { discoverEpisodes } from "../../infra/ingest/video-discovery.js";
25
+ import { transcodeForUpload } from "../../infra/ingest/video-transcode.js";
17
26
  import { WorkspaceStore } from "../../infra/ingest/workspace-store.js";
18
- import { runVideoTranscribe } from "../../llm/tasks/ingest/video-transcribe.js";
19
- import { runVideoCorrect } from "../../llm/tasks/ingest/video-correct.js";
20
- import { runPlotSpeaker } from "../../llm/tasks/ingest/plot-speaker.js";
21
- import { mapSettled } from "./fanout.js";
22
- import { runGovern } from "./pass5-govern.js";
23
- import { runRosterMerge } from "./video-pass3.js";
24
- const PIPELINE_VERSION = "1";
27
+ import { runVideoSerial } from "../../llm/tasks/ingest/video-serial.js";
28
+ const PIPELINE_VERSION = "2"; // serial layout: ep/*.json + context.json (breaks old workspaces)
25
29
  const pad = (n) => String(n).padStart(3, "0");
26
- const epFile = (e) => `ep_${pad(e.episode)}`;
27
30
  function sourceFingerprint(eps) {
28
31
  return sha256Text(JSON.stringify(eps.map((e) => ({ episode: e.episode, path: path.resolve(e.path) }))));
29
32
  }
33
+ function fileSize(p) {
34
+ try {
35
+ return fs.statSync(p).size;
36
+ }
37
+ catch {
38
+ return 0;
39
+ }
40
+ }
41
+ function appendTiming(store, t) {
42
+ try {
43
+ const mb = t.uploadBytes ? (t.uploadBytes / 1024 / 1024).toFixed(1) : "?";
44
+ const line = JSON.stringify({ ...t, uploadMB: mb, at: new Date().toISOString() }) + "\n";
45
+ fs.appendFileSync(store.path("timing.jsonl"), line);
46
+ }
47
+ catch { /* timing is diagnostic-only, never fail the run */ }
48
+ }
30
49
  function checkLifecycle(store, sha, force) {
31
50
  if (store.has("manifest.json")) {
32
51
  const manifest = store.readJson("manifest.json");
@@ -39,142 +58,142 @@ function checkLifecycle(store, sha, force) {
39
58
  }
40
59
  }
41
60
  if (force) {
42
- for (const dir of ["pass1", "pass2", "pass3", "pass4", "pass5", "pass6"])
43
- fs.rmSync(store.path(dir), { recursive: true, force: true });
44
- for (const f of ["script.initial.json", "script.json", "validation.json", "roster.json", "context.merged.md", "id_map.json"])
61
+ fs.rmSync(store.path("ep"), { recursive: true, force: true });
62
+ fs.rmSync(store.path("cache"), { recursive: true, force: true });
63
+ for (const f of ["context.json", "script.initial.json", "script.json", "validation.json", "id_map.json", "timing.jsonl"])
45
64
  fs.rmSync(store.path(f), { force: true });
46
65
  }
47
66
  }
48
- function blockOnFailures(settled, store, sidecar, code, label) {
49
- const failures = settled.filter((s) => !s.ok);
50
- for (const f of failures)
51
- store.writeJson(sidecar(f.index), { error: f.error instanceof Error ? f.error.message : String(f.error) });
52
- if (failures.length > 0) {
53
- throw new CliError(`INGEST ${label} INCOMPLETE`, `${failures.length} unit(s) failed ${label.toLowerCase()}.`, {
54
- exitCode: EXIT_INPUT, errorCode: code,
55
- received: failures.map((f) => (f.error instanceof Error ? f.error.message : String(f.error))).slice(0, 5),
56
- nextSteps: ["Inspect the error sidecars and rerun `scriptctl ingest` to resume."],
57
- });
67
+ // Rename docs' structured names (actors, scene cast, dialogue speakers) through
68
+ // the provisional→real alias map before convergence. Deep-cloned so the persisted
69
+ // ep docs are never mutated.
70
+ function renameDocs(docs, alias) {
71
+ return docs.map((d) => {
72
+ const c = JSON.parse(JSON.stringify(d));
73
+ for (const a of c.actors)
74
+ a.name = applyRename(a.name, alias) ?? a.name;
75
+ for (const sc of c.scenes) {
76
+ for (const ch of sc.characters)
77
+ ch.name = applyRename(ch.name, alias) ?? ch.name;
78
+ for (const an of sc.anchors)
79
+ an.speaker = applyRename(an.speaker, alias);
80
+ }
81
+ return c;
82
+ });
83
+ }
84
+ // Deterministic tail shared with text ingest. Pure (no LLM); ms-fast, so it runs
85
+ // after every episode (streaming) and once at the end (gated on validation).
86
+ function finalizeScript(docs, ctx, title) {
87
+ const alias = buildAliasMap(ctx.registry);
88
+ const renamed = renameDocs(docs, alias);
89
+ const nameScript = docsToNameScript(renamed, title);
90
+ const { script } = assignProvisionalIds(nameScript);
91
+ stampImportance(script, ctx.registry);
92
+ const governed = governDeterministic(script);
93
+ const { script: final, idMap } = renumberIds(governed);
94
+ const validation = validateScriptV3(final);
95
+ return { initial: script, final, idMap, validation };
96
+ }
97
+ function readDocs(store, episodes) {
98
+ const docs = [];
99
+ for (const e of episodes) {
100
+ const rel = `ep/ep_${pad(e.episode)}.json`;
101
+ if (store.has(rel))
102
+ docs.push(store.readJson(rel));
58
103
  }
104
+ return docs;
59
105
  }
60
106
  export async function runVideoIngest(opts) {
61
107
  const resolved = resolveSource(opts.sourcePath);
62
108
  if (resolved.kind === "text")
63
109
  throw new CliError("INGEST WRONG PIPELINE", "runVideoIngest received a text source.", { exitCode: EXIT_INPUT, errorCode: "INGEST_WRONG_PIPELINE" });
64
- const episodes = discoverEpisodes(resolved);
110
+ const episodes = [...discoverEpisodes(resolved)].sort((a, b) => a.episode - b.episode);
65
111
  const sha = sourceFingerprint(episodes);
66
112
  const fps = opts.fps ?? 3;
67
- const videoConc = opts.videoConcurrency ?? 10;
68
- const conc = opts.concurrency ?? 30;
113
+ const force = opts.force ?? false;
69
114
  const sig = opts.signal;
70
115
  const store = new WorkspaceStore(opts.workspacePath);
71
116
  store.ensure();
72
- checkLifecycle(store, sha, opts.force ?? false);
117
+ checkLifecycle(store, sha, force);
73
118
  store.writeJson("manifest.json", {
74
119
  version: 1, pipeline_version: PIPELINE_VERSION, updated: new Date().toISOString(),
75
120
  source: { kind: resolved.kind, sha256: sha },
76
121
  episodes: episodes.map((e) => ({ episode: e.episode, path: path.resolve(e.path), ext: e.ext, mime: e.mime })),
77
122
  fps,
78
123
  });
79
- const transcribePort = opts.executor.videoPort("ingest.video-transcribe");
80
- const correctPort = opts.executor.videoPort("ingest.video-correct");
81
- const handles = new Map(); // in-run upload reuse (pass1 → pass4)
124
+ const port = opts.executor.videoPort("ingest.video-serial");
125
+ const title = deriveTitle(opts.sourcePath);
126
+ let ctx = !force && store.has("context.json") ? store.readJson("context.json") : emptyContext();
82
127
  let reused = 0;
83
- // ===== pass1: upload + transcribe → ep_NNN.md =====
84
- const p1 = await mapSettled(episodes, videoConc, async (e) => {
85
- const mdRel = `pass1/${epFile(e)}.md`;
86
- if (store.has(mdRel) && !opts.force) {
128
+ // ===== Stage S: serial per-episode parse =====
129
+ for (const e of episodes) {
130
+ const rel = `ep/ep_${pad(e.episode)}.json`;
131
+ // Resume: skip only when the episode's content exists AND the running context
132
+ // already accounts for it (a crash between the two writes → rerun this ep).
133
+ if (!force && store.has(rel) && e.episode <= ctx.lastEpisode) {
87
134
  reused++;
88
- return;
135
+ continue;
89
136
  }
90
- const handle = await transcribePort.upload(e.path, e.mime, sig);
91
- handles.set(e.episode, handle);
92
- const md = await runVideoTranscribe(transcribePort, handle, e.episode, fps, sig);
93
- store.writeText(mdRel, md);
94
- store.clearError(`pass1/${epFile(e)}.error.json`);
95
- });
96
- blockOnFailures(p1, store, (i) => `pass1/${epFile(episodes[i])}.error.json`, "INGEST_TRANSCRIBE_INCOMPLETE", "TRANSCRIBE");
97
- // ===== pass2: parse md → per-episode docs (deterministic) =====
98
- const docs = episodes.map((e) => {
99
- const doc = parseEpisodeMd(store.readText(`pass1/${epFile(e)}.md`), e.episode);
100
- store.writeJson(`pass2/${epFile(e)}.json`, doc);
101
- return doc;
102
- });
103
- // ===== pass3: context + roster merge + state merge (checkpointed) =====
104
- let merge;
105
- if (store.has("roster.json") && store.has("context.merged.md") && !opts.force) {
106
- // Reuse the (expensive) roster merge; downstream needs contextMd + the maps.
107
- const r = store.readJson("roster.json");
108
- const context = store.has("pass3/context.json") ? store.readJson("pass3/context.json") : { episodes: [], actors: [], locations: [], props: [] };
109
- merge = { context, contextMd: store.readText("context.merged.md"), roster: r.roster, aliasToCanon: r.aliasToCanon, rosterStates: r.rosterStates, reviewMd: "" };
110
- reused++;
111
- }
112
- else {
113
- merge = await runRosterMerge(docs, { executor: opts.executor, concurrency: conc, ...(sig ? { signal: sig } : {}) });
114
- store.writeJson("pass3/context.json", merge.context);
115
- store.writeJson("roster.json", { roster: merge.roster, aliasToCanon: merge.aliasToCanon, rosterStates: merge.rosterStates });
116
- store.writeText("context.merged.md", merge.contextMd);
117
- store.writeText("roster.review.md", merge.reviewMd);
118
- }
119
- // ===== pass4: video-correct (reuse uploaded handle or re-upload) =====
120
- const p4 = await mapSettled(episodes, videoConc, async (e) => {
121
- const outRel = `pass4/${epFile(e)}.corrections.json`;
122
- if (store.has(outRel) && !opts.force) {
123
- reused++;
124
- return;
137
+ // Persist the exact context fed to Gemini for this episode (inspectable: what
138
+ // prior-episode knowledge the model saw), before the call so a failed episode
139
+ // still shows its input.
140
+ const ctxMd = renderContext(ctx);
141
+ store.writeText(`ep/ep_${pad(e.episode)}.context.md`, ctxMd);
142
+ let md;
143
+ let out;
144
+ const timing = { episode: e.episode };
145
+ try {
146
+ // Shrink the source before upload — short-drama clips ship at ~90MB but
147
+ // Gemini samples at fps=3, so a 720p/12fps re-encode (~14MB) uploads far
148
+ // faster with no recognition loss. Best-effort: falls back to the original.
149
+ const tStart = Date.now();
150
+ const enc = await transcodeForUpload(e.path, store.path(`cache/ep_${pad(e.episode)}.mp4`), e.mime, sig);
151
+ timing.transcodeMs = Date.now() - tStart;
152
+ timing.uploadBytes = fileSize(enc.path);
153
+ timing.transcoded = enc.transcoded;
154
+ if (enc.note)
155
+ timing.note = enc.note;
156
+ const uStart = Date.now();
157
+ const handle = await port.upload(enc.path, enc.mime, sig);
158
+ timing.uploadMs = Date.now() - uStart;
159
+ try {
160
+ const gStart = Date.now();
161
+ ({ md, output: out } = await runVideoSerial(port, handle, e.episode, ctxMd, fps, sig));
162
+ timing.generateMs = Date.now() - gStart;
163
+ }
164
+ finally {
165
+ await port.delete(handle, sig).catch(() => { }); // best-effort cleanup; serial never reuses a handle
166
+ // Drop the local transcode once uploaded+parsed it is a disposable cache.
167
+ if (enc.transcoded)
168
+ fs.rmSync(enc.path, { force: true });
169
+ }
125
170
  }
126
- const handle = handles.get(e.episode) ?? await correctPort.upload(e.path, e.mime, sig);
127
- const pass1Md = store.readText(`pass1/${epFile(e)}.md`);
128
- const corr = await runVideoCorrect(correctPort, handle, e.episode, merge.contextMd, pass1Md, fps, sig);
129
- store.writeJson(outRel, corr);
130
- store.clearError(`pass4/${epFile(e)}.error.json`);
131
- });
132
- blockOnFailures(p4, store, (i) => `pass4/${epFile(episodes[i])}.error.json`, "INGEST_CORRECT_INCOMPLETE", "CORRECT");
133
- // Media files no longer needed after pass4; best-effort cleanup.
134
- for (const h of handles.values())
135
- await transcribePort.delete(h, sig);
136
- // ===== pass5: pure-plot speaker audit (whole-series briefs) =====
137
- const allSynopsis = docs.filter((d) => d.synopsis.trim()).map((d) => `第${d.episode}集:${d.synopsis.trim()}`).join("\n\n");
138
- const p5 = await mapSettled(episodes, conc, async (e) => {
139
- const outRel = `pass5/${epFile(e)}.speaker.json`;
140
- if (store.has(outRel) && !opts.force) {
141
- reused++;
142
- return;
171
+ catch (err) {
172
+ store.writeJson(`ep/ep_${pad(e.episode)}.error.json`, { error: err instanceof Error ? err.message : String(err) });
173
+ throw new CliError("INGEST SERIAL INCOMPLETE", `Episode ${e.episode} failed serial parse; later episodes depend on its context.`, {
174
+ exitCode: EXIT_INPUT, errorCode: "INGEST_SERIAL_INCOMPLETE",
175
+ received: [err instanceof Error ? err.message : String(err)],
176
+ nextSteps: ["Inspect the episode error sidecar and rerun `scriptctl ingest` to resume from this episode."],
177
+ });
143
178
  }
144
- const pass1Md = store.readText(`pass1/${epFile(e)}.md`);
145
- const fixes = await runPlotSpeaker(opts.executor, e.episode, allSynopsis, merge.contextMd, pass1Md, sig);
146
- store.writeJson(outRel, { speaker_fixes: fixes });
147
- store.clearError(`pass5/${epFile(e)}.error.json`);
148
- });
149
- blockOnFailures(p5, store, (i) => `pass5/${epFile(episodes[i])}.error.json`, "INGEST_SPEAKER_INCOMPLETE", "SPEAKER");
150
- // ===== pass6: apply corrections → NameScript → SHARED governance tail =====
151
- const correctionsByEp = new Map();
152
- const plotFixesByEp = new Map();
153
- for (const e of episodes) {
154
- const corr = store.readJson(`pass4/${epFile(e)}.corrections.json`);
155
- correctionsByEp.set(e.episode, corr);
156
- const spk = store.readJson(`pass5/${epFile(e)}.speaker.json`);
157
- plotFixesByEp.set(e.episode, spk.speaker_fixes ?? []);
179
+ const doc = deltaToDoc(out, e.episode);
180
+ applyDelta(ctx, out, e.episode);
181
+ store.writeText(`ep/ep_${pad(e.episode)}.md`, md); // raw transcript for human review
182
+ store.writeJson(rel, doc);
183
+ store.writeJson("context.json", ctx);
184
+ store.clearError(`ep/ep_${pad(e.episode)}.error.json`);
185
+ appendTiming(store, timing); // per-episode transcode/upload/generate durations
186
+ // Streaming: rebuild script.json incrementally so the editor sees it grow.
187
+ // Best-effort the gated finalize below is authoritative.
188
+ try {
189
+ store.writeJson("script.json", finalizeScript(readDocs(store, episodes), ctx, title).final);
190
+ }
191
+ catch { /* streaming write is best-effort */ }
158
192
  }
159
- const fixedDocs = applyCorrections(docs, { correctionsByEp, plotFixesByEp, aliasToCanon: merge.aliasToCanon, rosterStates: merge.rosterStates });
160
- for (const d of fixedDocs)
161
- store.writeJson(`pass6/${pad(d.episode)}.fixed.json`, d);
162
- const title = deriveTitle(opts.sourcePath);
163
- const nameScript = docsToNameScript(fixedDocs, title);
164
- const { script: initial, assets } = assignProvisionalIds(nameScript);
193
+ // ===== Stage F: deterministic finalize (gated) =====
194
+ const { initial, final, idMap, validation } = finalizeScript(readDocs(store, episodes), ctx, title);
165
195
  store.writeJson("script.initial.json", initial);
166
- // Per-unit govern checkpoint under pass6/govern/ so a rerun only redoes the
167
- // sub-units that failed (curate/recall/refine/state), not the whole stage.
168
- const govKey = (key) => `pass6/govern/${sha256Text(key).slice(0, 16)}.json`;
169
- const governCheckpoint = {
170
- read: (key) => { const rel = govKey(key); return store.has(rel) ? store.readJson(rel) : undefined; },
171
- write: (key, value) => store.writeJson(govKey(key), value),
172
- };
173
- const governed = await runGovern(initial, assets, { executor: opts.executor, concurrency: conc, checkpoint: governCheckpoint, ...(sig ? { signal: sig } : {}) });
174
- const { script: renumbered, idMap } = renumberIds(governed);
175
196
  store.writeJson("id_map.json", idMap);
176
- const validation = validateScriptV3(renumbered);
177
- store.writeJson("pass6/script.json", renumbered);
178
197
  store.writeJson("validation.json", validation);
179
198
  if (!validation.ok) {
180
199
  throw new CliError("INGEST VALIDATION FAILED", "Final script.json failed v3 validation.", {
@@ -183,13 +202,12 @@ export async function runVideoIngest(opts) {
183
202
  nextSteps: ["Inspect validation.json."],
184
203
  });
185
204
  }
186
- store.writeJson("script.json", renumbered);
187
- const g = renumbered;
205
+ store.writeJson("script.json", final);
206
+ const g = final;
188
207
  return {
189
208
  workspacePath: store.root,
190
209
  episodes: episodes.length,
191
210
  reused,
192
- roster: { input: merge.context.actors.length, merged: merge.roster.length },
193
211
  assets: { actors: g.actors?.length ?? 0, locations: g.locations?.length ?? 0, props: g.props?.length ?? 0 },
194
212
  scriptPath: store.path("script.json"),
195
213
  validation: { ok: validation.ok, errors: validation.errors.length, warnings: validation.warnings.length },
@@ -1 +1 @@
1
- {"version":3,"file":"video-pipeline.js","sourceRoot":"","sources":["../../../src/usecases/ingest/video-pipeline.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,iFAAiF;AACjF,+EAA+E;AAC/E,0EAA0E;AAC1E,gFAAgF;AAChF,kFAAkF;AAElF,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAExE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAqB,MAAM,oCAAoC,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAqB,MAAM,uCAAuC,CAAC;AAC5F,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAC;AAChF,OAAO,EAAE,eAAe,EAAwB,MAAM,yCAAyC,CAAC;AAChG,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAExE,OAAO,EAAE,UAAU,EAAgB,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,GAAG,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC9D,MAAM,MAAM,GAAG,CAAC,CAAe,EAAU,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;AAuBnE,SAAS,iBAAiB,CAAC,GAAmB;IAC5C,OAAO,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1G,CAAC;AAED,SAAS,cAAc,CAAC,KAAqB,EAAE,GAAW,EAAE,KAAc;IACxE,IAAI,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAmC,eAAe,CAAC,CAAC;QACnF,IAAI,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC9D,MAAM,IAAI,QAAQ,CAAC,wBAAwB,EAAE,kFAAkF,EAAE;gBAC/H,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,wBAAwB;gBACzD,QAAQ,EAAE,CAAC,6CAA6C,CAAC;gBACzD,SAAS,EAAE,CAAC,qDAAqD,CAAC;aACnE,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,IAAI,KAAK,EAAE,CAAC;QACV,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;YAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACvI,KAAK,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,aAAa,EAAE,iBAAiB,EAAE,aAAa,EAAE,mBAAmB,EAAE,aAAa,CAAC;YAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1K,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAI,OAAqB,EAAE,KAAqB,EAAE,OAA8B,EAAE,IAAY,EAAE,KAAa;IACnI,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAA2C,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACvF,KAAK,MAAM,CAAC,IAAI,QAAQ;QAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACrI,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,QAAQ,CAAC,UAAU,KAAK,aAAa,EAAE,GAAG,QAAQ,CAAC,MAAM,mBAAmB,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE;YAC5G,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI;YACrC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;YACzG,SAAS,EAAE,CAAC,oEAAoE,CAAC;SAClF,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAwB;IAC3D,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAChD,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM;QAAE,MAAM,IAAI,QAAQ,CAAC,uBAAuB,EAAE,wCAAwC,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAClL,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,IAAI,EAAE,CAAC;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;IAExB,MAAM,KAAK,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACrD,KAAK,CAAC,MAAM,EAAE,CAAC;IACf,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC;IAChD,KAAK,CAAC,SAAS,CAAC,eAAe,EAAE;QAC/B,OAAO,EAAE,CAAC,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACjF,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;QAC5C,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7G,GAAG;KACJ,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;IAC1E,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC;IACpE,MAAM,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAC,CAAC,sCAAsC;IAC1F,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,qDAAqD;IACrD,MAAM,EAAE,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC3D,MAAM,KAAK,GAAG,SAAS,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;QACtC,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAAC,MAAM,EAAE,CAAC;YAAC,OAAO;QAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC/B,MAAM,EAAE,GAAG,MAAM,kBAAkB,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACjF,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC3B,KAAK,CAAC,UAAU,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IACH,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,aAAa,EAAE,8BAA8B,EAAE,YAAY,CAAC,CAAC;IAE5H,iEAAiE;IACjE,MAAM,IAAI,GAAsB,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACjD,MAAM,GAAG,GAAG,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QAC/E,KAAK,CAAC,SAAS,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAChD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,yEAAyE;IACzE,IAAI,KAAiD,CAAC;IACtD,IAAI,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9E,6EAA6E;QAC7E,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,CAA8H,aAAa,CAAC,CAAC;QACrK,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAuB,oBAAoB,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QACtK,KAAK,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QAChK,MAAM,EAAE,CAAC;IACX,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACpH,KAAK,CAAC,SAAS,CAAC,oBAAoB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACrD,KAAK,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;QAC7H,KAAK,CAAC,SAAS,CAAC,mBAAmB,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QACtD,KAAK,CAAC,SAAS,CAAC,kBAAkB,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED,wEAAwE;IACxE,MAAM,EAAE,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC3D,MAAM,MAAM,GAAG,SAAS,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC;QACrD,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAAC,MAAM,EAAE,CAAC;YAAC,OAAO;QAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACvF,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACvG,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC9B,KAAK,CAAC,UAAU,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IACH,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,aAAa,EAAE,2BAA2B,EAAE,SAAS,CAAC,CAAC;IAEtH,iEAAiE;IACjE,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,EAAE;QAAE,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAEtE,mEAAmE;IACnE,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzH,MAAM,EAAE,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACtD,MAAM,MAAM,GAAG,SAAS,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC;QACjD,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAAC,MAAM,EAAE,CAAC;YAAC,OAAO;QAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;QACzG,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,KAAK,CAAC,UAAU,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IACH,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,aAAa,EAAE,2BAA2B,EAAE,SAAS,CAAC,CAAC;IAEtH,6EAA6E;IAC7E,MAAM,eAAe,GAAG,IAAI,GAAG,EAAwB,CAAC;IACxD,MAAM,aAAa,GAAG,IAAI,GAAG,EAA4D,CAAC;IAC1F,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAkB,SAAS,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC;QACpF,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACrC,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAsE,SAAS,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;QACnI,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,EAAE,EAAE,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;IACjJ,KAAK,MAAM,CAAC,IAAI,SAAS;QAAE,KAAK,CAAC,SAAS,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IAEpF,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,UAAU,GAAG,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACtD,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAAC;IACrE,KAAK,CAAC,SAAS,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAC;IAEhD,4EAA4E;IAC5E,2EAA2E;IAC3E,MAAM,MAAM,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,gBAAgB,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC;IAC5F,MAAM,gBAAgB,GAAG;QACvB,IAAI,EAAE,CAAK,GAAW,EAAiB,EAAE,GAAG,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAI,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QAClI,KAAK,EAAE,CAAC,GAAW,EAAE,KAAc,EAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;KAClF,CAAC;IACF,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,gBAAgB,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACjK,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC5D,KAAK,CAAC,SAAS,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IACtC,MAAM,UAAU,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAChD,KAAK,CAAC,SAAS,CAAC,mBAAmB,EAAE,UAAU,CAAC,CAAC;IACjD,KAAK,CAAC,SAAS,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,QAAQ,CAAC,0BAA0B,EAAE,yCAAyC,EAAE;YACxF,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,0BAA0B;YAC3D,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;YAC7E,SAAS,EAAE,CAAC,0BAA0B,CAAC;SACxC,CAAC,CAAC;IACL,CAAC;IACD,KAAK,CAAC,SAAS,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IAE3C,MAAM,CAAC,GAAG,UAA8E,CAAC;IACzF,OAAO;QACL,aAAa,EAAE,KAAK,CAAC,IAAI;QACzB,QAAQ,EAAE,QAAQ,CAAC,MAAM;QACzB,MAAM;QACN,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE;QAC3E,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,EAAE;QAC3G,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC;QACrC,UAAU,EAAE,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC,MAAM,EAAE;KAC1G,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,UAAkB;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IACjE,OAAO,IAAI,IAAI,EAAE,CAAC;AACpB,CAAC"}
1
+ {"version":3,"file":"video-pipeline.js","sourceRoot":"","sources":["../../../src/usecases/ingest/video-pipeline.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,17 @@ interface FileMeta {
6
6
  mtime: number;
7
7
  }
8
8
  export declare function listArtifacts(root: string): Record<string, FileMeta[]>;
9
+ export declare function readTiming(root: string): {
10
+ episodes: Array<{
11
+ episode: number;
12
+ transcodeMs?: number;
13
+ uploadMs?: number;
14
+ generateMs?: number;
15
+ uploadMB?: string;
16
+ transcoded?: boolean;
17
+ }>;
18
+ totalMs: number;
19
+ };
9
20
  export declare function readSafe(root: string, rel: string): {
10
21
  ok: true;
11
22
  text: string;
@@ -1,9 +1,12 @@
1
- // `scriptctl view --watch` — a live workspace monitor. Starts a tiny stdlib HTTP
2
- // server (no deps) that a self-refreshing HTML dashboard polls: ingest progress
3
- // (deriveIngestStatus), the artifact tree (pass files, per-episode serial context
4
- // + update md, provisional + final script), and any single file's content. The
5
- // dashboard auto-refreshes so a running `scriptctl ingest` is watched live and the
6
- // per-episode context/decision md stream in as episodes finish. Runs until Ctrl-C.
1
+ // `scriptctl view --watch` — a live workspace monitor for TEXT or VIDEO ingest.
2
+ // Starts a tiny stdlib HTTP server (no deps) that a self-refreshing HTML dashboard
3
+ // polls: ingest progress (deriveIngestStatus), the artifact tree (text serial
4
+ // context/window md + provisional/final script, OR video per-episode transcript +
5
+ // context-fed-to-model + parsed json + registry + timing.jsonl), and any single
6
+ // file's content. The dashboard auto-refreshes so a running `scriptctl ingest` is
7
+ // watched live and each unit's products stream in as they finish. Runs until Ctrl-C.
8
+ // Text and video workspaces use disjoint layouts, so the artifact groups union
9
+ // cleanly — a workspace only populates the groups its pipeline produces.
7
10
  import * as http from "node:http";
8
11
  import * as fs from "node:fs";
9
12
  import * as path from "node:path";
@@ -34,15 +37,68 @@ export function listArtifacts(root) {
34
37
  return names.filter(filter).sort().map((n) => meta(`${dir}/${n}`)).filter((m) => !!m);
35
38
  };
36
39
  const only = (arr) => arr.filter((m) => !!m);
40
+ const epFile = (suffix) => dirFiles("ep", (n) => n.endsWith(suffix) && !n.endsWith(".error.json"));
37
41
  return {
38
42
  结果: only([meta("script.json"), meta("validation.json"), meta("review.html"), meta("timings.json")]),
43
+ // Text serial artifacts (empty for a video workspace).
39
44
  上下文: dirFiles("serial", (n) => n.startsWith("context_") && n.endsWith(".md")),
40
45
  每窗更新: dirFiles("serial", (n) => n.startsWith("win_") && n.endsWith(".md")),
41
46
  篇章梗概: dirFiles("serial", (n) => n.startsWith("arc_") && n.endsWith(".md")),
42
- 中间产物: only([meta("script.initial.json"), meta("provisional_assets.json"), meta("notes.json"), meta("manifest.json")]),
43
47
  前段: dirFiles("pass2", (n) => n.endsWith(".md")),
48
+ // Video serial artifacts (empty for a text workspace). Grouped by kind so an
49
+ // episode's whole story is one scan down the list.
50
+ 转录: epFile(".md").filter((m) => !m.rel.endsWith(".context.md")),
51
+ 送模上下文: epFile(".context.md"),
52
+ 解析: epFile(".json"),
53
+ 花名册: only([meta("context.json")]),
54
+ 计时: only([meta("timing.jsonl")]),
55
+ 中间产物: only([meta("script.initial.json"), meta("provisional_assets.json"), meta("notes.json"), meta("id_map.json"), meta("manifest.json")]),
44
56
  };
45
57
  }
58
+ // Parse timing.jsonl (one episode per line) into a compact summary the dashboard
59
+ // shows without shipping the whole file. Tolerant: skips malformed lines. Only the
60
+ // video pipeline writes timing.jsonl; a text workspace yields an empty summary.
61
+ export function readTiming(root) {
62
+ let text = "";
63
+ try {
64
+ text = fs.readFileSync(path.join(root, "timing.jsonl"), "utf-8");
65
+ }
66
+ catch {
67
+ return { episodes: [], totalMs: 0 };
68
+ }
69
+ const episodes = [];
70
+ let totalMs = 0;
71
+ for (const line of text.split(/\r?\n/)) {
72
+ const t = line.trim();
73
+ if (!t)
74
+ continue;
75
+ try {
76
+ const j = JSON.parse(t);
77
+ if (typeof j.episode !== "number")
78
+ continue;
79
+ const row = { episode: j.episode };
80
+ if (typeof j.transcodeMs === "number") {
81
+ row.transcodeMs = j.transcodeMs;
82
+ totalMs += j.transcodeMs;
83
+ }
84
+ if (typeof j.uploadMs === "number") {
85
+ row.uploadMs = j.uploadMs;
86
+ totalMs += j.uploadMs;
87
+ }
88
+ if (typeof j.generateMs === "number") {
89
+ row.generateMs = j.generateMs;
90
+ totalMs += j.generateMs;
91
+ }
92
+ if (typeof j.uploadMB === "string")
93
+ row.uploadMB = j.uploadMB;
94
+ if (typeof j.transcoded === "boolean")
95
+ row.transcoded = j.transcoded;
96
+ episodes.push(row);
97
+ }
98
+ catch { /* skip malformed line */ }
99
+ }
100
+ return { episodes, totalMs };
101
+ }
46
102
  // Read a workspace file, guarding against path traversal outside the root.
47
103
  export function readSafe(root, rel) {
48
104
  const abs = path.resolve(root, rel);
@@ -68,7 +124,7 @@ export async function runViewServer(opts) {
68
124
  return send(res, 200, "text/html; charset=utf-8", DASHBOARD_HTML);
69
125
  if (u.pathname === "/api/state") {
70
126
  const status = deriveIngestStatus(root);
71
- return send(res, 200, "application/json", JSON.stringify({ root, status, groups: listArtifacts(root) }));
127
+ return send(res, 200, "application/json", JSON.stringify({ root, status, groups: listArtifacts(root), timing: readTiming(root) }));
72
128
  }
73
129
  if (u.pathname === "/api/file") {
74
130
  const rel = u.searchParams.get("path") ?? "";
@@ -135,6 +191,12 @@ label{cursor:pointer;user-select:none}.empty{color:var(--dim);padding:34px;text-
135
191
  #view{padding:14px 18px;white-space:pre-wrap;word-break:break-word;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px}
136
192
  #view h1,#view h2{margin:14px 0 4px}#view h1{color:var(--acc);font-size:15px}#view h2{color:var(--warn);font-size:13px}
137
193
  #view .b{color:var(--dim)}
194
+ /* per-episode timing table (video only) */
195
+ .timing{padding:8px 16px 4px;background:var(--panel);border-bottom:1px solid var(--line);overflow:auto;max-height:132px}
196
+ table.tm{border-collapse:collapse;font-size:12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
197
+ table.tm th,table.tm td{padding:2px 10px 2px 0;text-align:right}table.tm th:first-child,table.tm td:first-child{text-align:left}
198
+ table.tm th{color:var(--dim);font-weight:600;border-bottom:1px solid var(--line)}
199
+ table.tm td.slow{color:var(--warn)}
138
200
  </style></head><body>
139
201
  <header>
140
202
  <span class="title">scriptctl ingest</span>
@@ -149,6 +211,7 @@ label{cursor:pointer;user-select:none}.empty{color:var(--dim);padding:34px;text-
149
211
  <div class="ovwrap"><span class="dim">总进度</span><div class="ovtrack"><i id="ovBar"></i></div><span class="ovpct" id="ovPct">0%</span></div>
150
212
  <div class="stages" id="stages"></div>
151
213
  </div>
214
+ <div class="timing" id="timingWrap" style="display:none"><table class="tm" id="tmTable"></table></div>
152
215
  <main>
153
216
  <aside id="side"></aside>
154
217
  <section>
@@ -160,11 +223,23 @@ label{cursor:pointer;user-select:none}.empty{color:var(--dim);padding:34px;text-
160
223
  </section>
161
224
  </main>
162
225
  <script>
163
- var NAMES={normalize:'规范化',assemble:'装配',serial:'串行解析',govern:'治理成稿',transcribe:'转写',roster:'角色合并',correct:'校正',speaker:'发声源'};
226
+ var NAMES={normalize:'规范化',assemble:'装配',serial:'串行解析',govern:'治理成稿',finalize:'治理成稿',transcribe:'转写',roster:'角色合并',correct:'校正',speaker:'发声源'};
164
227
  var cur=null, follow=true, lastLatest=null;
165
228
  var timing=null, timingAt=0; // last status.timings + client time it arrived (avoids clock skew)
166
229
  function $(s){return document.querySelector(s)}
167
- function fmtDur(ms){var s=Math.round(ms/1000);return s>=60?(Math.floor(s/60)+'m'+('0'+(s%60)).slice(-2)+'s'):s+'s'}
230
+ function fmtDur(ms){if(ms==null)return '—';var s=Math.round(ms/1000);return s>=60?(Math.floor(s/60)+'m'+('0'+(s%60)).slice(-2)+'s'):s+'s'}
231
+ // per-episode timing table (video only; hidden when there is no timing.jsonl)
232
+ function renderEpTiming(tm){
233
+ if(!tm||!tm.episodes||!tm.episodes.length){$('#timingWrap').style.display='none';return}
234
+ $('#timingWrap').style.display='block';
235
+ var rows=['<tr><th>集</th><th>转码</th><th>大小</th><th>上传</th><th>解析</th></tr>'];
236
+ tm.episodes.forEach(function(e){
237
+ var slow=e.generateMs>60000?' class="slow"':'';
238
+ rows.push('<tr><td>ep'+('00'+e.episode).slice(-3)+'</td><td>'+fmtDur(e.transcodeMs)+(e.transcoded===false?'*':'')+'</td><td>'+(e.uploadMB||'?')+'M</td><td>'+fmtDur(e.uploadMs)+'</td><td'+slow+'>'+fmtDur(e.generateMs)+'</td></tr>');
239
+ });
240
+ rows.push('<tr><td class="dim">累计</td><td></td><td></td><td></td><td class="dim">'+fmtDur(tm.totalMs)+'</td></tr>');
241
+ $('#tmTable').innerHTML=rows.join('');
242
+ }
168
243
  // tick the total elapsed locally between polls; serial ETA/rate from the summary
169
244
  function renderTiming(){
170
245
  if(!timing){$('#elapsed').textContent='—';$('#eta').textContent='';return}
@@ -181,12 +256,13 @@ function renderTiming(){
181
256
  $('#follow').onchange=function(e){follow=e.target.checked};
182
257
  function esc(s){return s.replace(/[&<>]/g,function(c){return{'&':'&amp;','<':'&lt;','>':'&gt;'}[c]})}
183
258
  function renderContent(rel,text){
259
+ if(rel.endsWith('.jsonl')){$('#view').textContent=text.split('\\n').map(function(l){try{return JSON.stringify(JSON.parse(l))}catch(e){return l}}).join('\\n');return}
184
260
  if(rel.endsWith('.json')){try{text=JSON.stringify(JSON.parse(text),null,2)}catch(e){}$('#view').textContent=text;return}
185
261
  if(rel.endsWith('.md')){
186
262
  $('#view').innerHTML=text.split('\\n').map(function(l){
187
263
  if(l.indexOf('## ')===0)return '<h2>'+esc(l.slice(3))+'</h2>';
188
264
  if(l.indexOf('# ')===0)return '<h1>'+esc(l.slice(2))+'</h1>';
189
- if(l.indexOf(' ')===0||l.indexOf('- ')===0)return '<span class="b">'+esc(l)+'</span>';
265
+ if(l.indexOf(' ')===0||l.indexOf('- ')===0||l.indexOf('> ')===0)return '<span class="b">'+esc(l)+'</span>';
190
266
  return esc(l)||'&nbsp;';
191
267
  }).join('\\n');return}
192
268
  $('#view').textContent=text;
@@ -220,13 +296,14 @@ function poll(){
220
296
  return '<div class="stage '+st+'"><div class="stage-h"><span class="dot"></span><b>'+(NAMES[p.name]||p.name)+'</b><span class="cnt">'+cnt+'</span></div><div class="track"><i style="width:'+Math.round(frac(p)*100)+'%"></i></div>'+(d?'<div class="dim" style="margin-top:4px">'+d+'</div>':'')+'</div>';
221
297
  }).join('');
222
298
  timing=s.timings||null;timingAt=Date.now();renderTiming();
299
+ renderEpTiming(d.timing);
223
300
  // sidebar
224
301
  var html='',latest=null;
225
302
  Object.keys(d.groups).forEach(function(grp){
226
303
  var files=d.groups[grp];if(!files.length)return;html+='<div class="grp">'+grp+'</div>';
227
304
  files.forEach(function(f){
228
305
  html+='<div class="f" data-rel="'+f.rel+'"><span>'+f.rel.split('/').pop()+'</span><span class="sz">'+(f.size>1024?(f.size/1024).toFixed(0)+'k':f.size)+'</span></div>';
229
- if(grp==='每窗更新'||grp==='上下文')latest=f.rel;
306
+ if(grp==='每窗更新'||grp==='上下文'||grp==='转录'||grp==='解析')latest=f.rel;
230
307
  });
231
308
  });
232
309
  $('#side').innerHTML=html;