@lingjingai/scriptctl 0.42.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 (64) hide show
  1. package/changes/0.43.0.md +21 -0
  2. package/dist/cli.js +0 -1
  3. package/dist/cli.js.map +1 -1
  4. package/dist/domain/ingest/video-apply.d.ts +0 -33
  5. package/dist/domain/ingest/video-apply.js +8 -159
  6. package/dist/domain/ingest/video-apply.js.map +1 -1
  7. package/dist/domain/ingest/video-context.d.ts +51 -0
  8. package/dist/domain/ingest/video-context.js +293 -0
  9. package/dist/domain/ingest/video-context.js.map +1 -0
  10. package/dist/domain/ingest/video-serial-md.d.ts +60 -0
  11. package/dist/domain/ingest/video-serial-md.js +277 -0
  12. package/dist/domain/ingest/video-serial-md.js.map +1 -0
  13. package/dist/help-text.js +13 -10
  14. package/dist/help-text.js.map +1 -1
  15. package/dist/infra/ingest/video-transcode.d.ts +7 -0
  16. package/dist/infra/ingest/video-transcode.js +86 -0
  17. package/dist/infra/ingest/video-transcode.js.map +1 -0
  18. package/dist/infra/llm/gemini-video-model.js +14 -2
  19. package/dist/infra/llm/gemini-video-model.js.map +1 -1
  20. package/dist/llm/config.js +1 -2
  21. package/dist/llm/config.js.map +1 -1
  22. package/dist/llm/registry.d.ts +1 -7
  23. package/dist/llm/registry.js +5 -13
  24. package/dist/llm/registry.js.map +1 -1
  25. package/dist/llm/tasks/ingest/video-serial.d.ts +9 -0
  26. package/dist/llm/tasks/ingest/video-serial.js +120 -0
  27. package/dist/llm/tasks/ingest/video-serial.js.map +1 -0
  28. package/dist/llm/types.d.ts +1 -1
  29. package/dist/llm/types.js.map +1 -1
  30. package/dist/usecases/ingest/command.js +0 -3
  31. package/dist/usecases/ingest/command.js.map +1 -1
  32. package/dist/usecases/ingest/status.js +8 -20
  33. package/dist/usecases/ingest/status.js.map +1 -1
  34. package/dist/usecases/ingest/video-pipeline.d.ts +0 -6
  35. package/dist/usecases/ingest/video-pipeline.js +145 -127
  36. package/dist/usecases/ingest/video-pipeline.js.map +1 -1
  37. package/dist/usecases/ingest/view-server.d.ts +11 -0
  38. package/dist/usecases/ingest/view-server.js +89 -12
  39. package/dist/usecases/ingest/view-server.js.map +1 -1
  40. package/package.json +1 -1
  41. package/dist/domain/ingest/video-aggregate.d.ts +0 -23
  42. package/dist/domain/ingest/video-aggregate.js +0 -89
  43. package/dist/domain/ingest/video-aggregate.js.map +0 -1
  44. package/dist/domain/ingest/video-md-parser.d.ts +0 -2
  45. package/dist/domain/ingest/video-md-parser.js +0 -233
  46. package/dist/domain/ingest/video-md-parser.js.map +0 -1
  47. package/dist/llm/tasks/ingest/plot-speaker.d.ts +0 -11
  48. package/dist/llm/tasks/ingest/plot-speaker.js +0 -72
  49. package/dist/llm/tasks/ingest/plot-speaker.js.map +0 -1
  50. package/dist/llm/tasks/ingest/roster-merge.d.ts +0 -46
  51. package/dist/llm/tasks/ingest/roster-merge.js +0 -235
  52. package/dist/llm/tasks/ingest/roster-merge.js.map +0 -1
  53. package/dist/llm/tasks/ingest/state-merge.d.ts +0 -10
  54. package/dist/llm/tasks/ingest/state-merge.js +0 -84
  55. package/dist/llm/tasks/ingest/state-merge.js.map +0 -1
  56. package/dist/llm/tasks/ingest/video-correct.d.ts +0 -30
  57. package/dist/llm/tasks/ingest/video-correct.js +0 -144
  58. package/dist/llm/tasks/ingest/video-correct.js.map +0 -1
  59. package/dist/llm/tasks/ingest/video-transcribe.d.ts +0 -4
  60. package/dist/llm/tasks/ingest/video-transcribe.js +0 -105
  61. package/dist/llm/tasks/ingest/video-transcribe.js.map +0 -1
  62. package/dist/usecases/ingest/video-pass3.d.ts +0 -26
  63. package/dist/usecases/ingest/video-pass3.js +0 -0
  64. package/dist/usecases/ingest/video-pass3.js.map +0 -1
@@ -0,0 +1,293 @@
1
+ // Serial video-ingest running context (§10.2 rewrite). Pure & deterministic —
2
+ // no LLM. As episodes are parsed one at a time, this carries a global entity
3
+ // registry (canonical + provisional identities with visual anchors, plot role,
4
+ // known outfit states) plus a compacting plot digest and open story threads.
5
+ // renderContext() serializes it into the markdown block fed back into the next
6
+ // episode's parse so the model resolves identity by plot — not by re-matching
7
+ // faces in isolation. Provisional identities carry an anchor until a later,
8
+ // better-informed episode reveals who they are (resolve → resolvesTo), which the
9
+ // deterministic finalize sweep (buildAliasMap → renameDocs) folds into real ids.
10
+ export function emptyContext() {
11
+ return { lastEpisode: 0, registry: [], digests: [], openThreads: [] };
12
+ }
13
+ const norm = (s) => s.normalize("NFC").replace(/\s+/g, " ").trim();
14
+ const clip = (s, n) => (s.length > n ? `${s.slice(0, n)}…` : s);
15
+ const RECENT_N = 3; // recent episodes kept with full synopsis
16
+ const CHAR_BUDGET = 12000; // renderContext output ceiling; shrink the window to fit
17
+ function pushUniq(arr, v) {
18
+ const s = (v ?? "").trim();
19
+ if (s && !arr.includes(s))
20
+ arr.push(s);
21
+ }
22
+ // Merge fresh evidence into an existing registry entity: unions aliases/states,
23
+ // bumps lastEpisode. `overwrite` controls scalar fields (anchor/appearance/role):
24
+ // - false (a re-registration of a known name via 新增): fill empties only, never
25
+ // clobber what we already know.
26
+ // - true (an explicit 修正 correction): the model deliberately looked again and
27
+ // gives a better value → replace even a non-empty field.
28
+ function enrichEntity(e, d, episode, overwrite = false) {
29
+ const set = (has, val) => {
30
+ const v = (val ?? "").trim();
31
+ if (!v)
32
+ return has;
33
+ return overwrite || !has ? v : has;
34
+ };
35
+ e.anchor = set(e.anchor, d.anchor) ?? e.anchor;
36
+ const appearance = set(e.appearance, d.appearance);
37
+ if (appearance)
38
+ e.appearance = appearance;
39
+ e.role = set(e.role, d.role) ?? e.role;
40
+ for (const a of d.add_aliases ?? [])
41
+ pushUniq(e.aliases, a);
42
+ for (const s of d.add_states ?? [])
43
+ pushUniq(e.states, s);
44
+ e.lastEpisode = episode;
45
+ }
46
+ // Fold one episode's serial output into the context. Mutates and returns ctx
47
+ // (called once per episode in the serial loop).
48
+ export function applyDelta(ctx, out, episode) {
49
+ const find = (name) => ctx.registry.find((e) => norm(e.name) === norm(name));
50
+ for (const ne of out.registry_delta.new_entities) {
51
+ const name = ne.name.trim();
52
+ if (!name)
53
+ continue;
54
+ const existing = find(name);
55
+ if (existing) {
56
+ enrichEntity(existing, { anchor: ne.anchor, appearance: ne.appearance, role: ne.role, add_aliases: ne.aliases, add_states: ne.states }, episode);
57
+ continue;
58
+ }
59
+ const states = [];
60
+ for (const s of ne.states ?? [])
61
+ pushUniq(states, s);
62
+ const aliases = [];
63
+ for (const a of ne.aliases ?? [])
64
+ pushUniq(aliases, a);
65
+ ctx.registry.push({
66
+ name,
67
+ kind: ne.kind,
68
+ status: ne.status,
69
+ importance: ne.importance,
70
+ anchor: (ne.anchor ?? "").trim(),
71
+ ...(ne.appearance ? { appearance: ne.appearance.trim() } : {}),
72
+ role: (ne.role ?? "").trim(),
73
+ aliases,
74
+ states,
75
+ firstEpisode: episode,
76
+ lastEpisode: episode,
77
+ });
78
+ }
79
+ // enrich = the 修正 section: an explicit correction of a known entity → overwrite.
80
+ for (const en of out.registry_delta.enrich) {
81
+ const e = find(en.name);
82
+ if (!e)
83
+ continue;
84
+ enrichEntity(e, en, episode, true);
85
+ }
86
+ for (const rs of out.registry_delta.resolve) {
87
+ const e = find(rs.provisional_name);
88
+ const to = rs.canonical_name.trim();
89
+ if (e && to && norm(to) !== norm(e.name))
90
+ e.resolvesTo = to;
91
+ }
92
+ let seq = 0;
93
+ for (const op of out.open_threads.opened) {
94
+ const text = op.text.trim();
95
+ if (text)
96
+ ctx.openThreads.push({ id: `t${episode}_${++seq}`, text, sinceEpisode: episode });
97
+ }
98
+ for (const cl of out.open_threads.closed) {
99
+ const ref = cl.ref.trim();
100
+ if (ref)
101
+ ctx.openThreads = ctx.openThreads.filter((t) => t.id !== ref && t.text !== ref);
102
+ }
103
+ ctx.digests.push({ episode, synopsis: (out.synopsis ?? "").trim() });
104
+ ctx.lastEpisode = episode;
105
+ return ctx;
106
+ }
107
+ // ===== renderContext (compaction folded in) =====
108
+ function renderActor(e, hard) {
109
+ const L = [];
110
+ const tag = e.status === "provisional" ? "·待定 ⚠" : `·${e.importance}`;
111
+ L.push(`### ${e.name} ${tag}`);
112
+ if (e.role)
113
+ L.push(`- 作用: ${clip(e.role, hard ? 40 : 200)}`);
114
+ if (e.anchor)
115
+ L.push(`- 锚点: ${e.anchor}`);
116
+ if (e.appearance)
117
+ L.push(`- 外观: ${clip(e.appearance, hard ? 40 : 90)}`);
118
+ if (e.aliases.length)
119
+ L.push(`- 曾用称呼: ${e.aliases.join("、")}`);
120
+ if (e.states.length)
121
+ L.push(`- 已知造型: ${e.states.join(" / ")}`);
122
+ L.push(`- 出现: ep ${e.firstEpisode}–${e.lastEpisode}`);
123
+ if (e.status === "provisional")
124
+ L.push(`- 身份未确认:本集若看清他是谁,用 resolve 回填 {provisional_name:"${e.name}", canonical_name:"真名"}`);
125
+ return L;
126
+ }
127
+ function renderAsset(e, hard) {
128
+ const desc = clip(e.appearance || e.anchor || e.role || "", hard ? 30 : 60);
129
+ return `- ${e.name} ·${e.importance}${desc ? `:${desc}` : ""}`;
130
+ }
131
+ function render(ctx, recentN, hard) {
132
+ const L = [];
133
+ L.push(`# 已知设定(解析第 ${ctx.lastEpisode + 1} 集时对照本表)`, "");
134
+ L.push("认得出的人/物沿用其**规范名**,别自己新起名;锚点用于在画面里重新指认某个人。", "");
135
+ const actors = ctx.registry.filter((e) => e.kind === "actor");
136
+ const locations = ctx.registry.filter((e) => e.kind === "location");
137
+ const props = ctx.registry.filter((e) => e.kind === "prop");
138
+ if (actors.length) {
139
+ L.push("## 人物", "");
140
+ for (const e of actors)
141
+ L.push(...renderActor(e, hard), "");
142
+ }
143
+ if (locations.length || props.length) {
144
+ L.push("## 场景 / 道具", "");
145
+ for (const e of locations)
146
+ L.push(renderAsset(e, hard));
147
+ for (const e of props)
148
+ L.push(renderAsset(e, hard));
149
+ L.push("");
150
+ }
151
+ if (ctx.digests.length) {
152
+ L.push("## 剧情进展", "");
153
+ for (const d of [...ctx.digests].sort((a, b) => a.episode - b.episode)) {
154
+ const detailed = d.episode > ctx.lastEpisode - recentN;
155
+ L.push(detailed ? `第${d.episode}集:${d.synopsis}` : `第${d.episode}集:${clip(d.synopsis, hard ? 40 : 80)}`);
156
+ }
157
+ L.push("");
158
+ }
159
+ if (ctx.openThreads.length) {
160
+ L.push("## 未闭合线索(若本集交代了,用 open_threads.closed 引用其 [id] 关闭)", "");
161
+ for (const t of ctx.openThreads)
162
+ L.push(`- [${t.id}] ${t.text}`);
163
+ L.push("");
164
+ }
165
+ return L.join("\n");
166
+ }
167
+ // Serialize the context for the next episode's prompt. Registry + open threads
168
+ // are load-bearing identity anchors and are NEVER compacted; only the plot
169
+ // digest window shrinks to fit CHAR_BUDGET (recent N full, older one-lined).
170
+ export function renderContext(ctx) {
171
+ for (let n = RECENT_N; n >= 1; n--) {
172
+ const out = render(ctx, n, false);
173
+ if (out.length <= CHAR_BUDGET)
174
+ return out;
175
+ }
176
+ return render(ctx, 1, true); // n==1 still over budget → hard-trim digests/appearance
177
+ }
178
+ // ===== provisional → real name backfill (finalize) =====
179
+ // Flatten resolve chains (湿发男→A→江总→江文博 ⇒ 湿发男→江文博) into a one-hop
180
+ // alias map. Mirrors video-pass3 resolveFinal's transitive closure.
181
+ export function buildAliasMap(registry) {
182
+ const direct = new Map();
183
+ for (const e of registry)
184
+ if (e.resolvesTo && norm(e.resolvesTo) !== norm(e.name))
185
+ direct.set(e.name, e.resolvesTo);
186
+ const resolve = (n, seen = new Set()) => {
187
+ if (!direct.has(n) || seen.has(n))
188
+ return n;
189
+ seen.add(n);
190
+ return resolve(direct.get(n), seen);
191
+ };
192
+ const flat = new Map();
193
+ for (const k of direct.keys()) {
194
+ const v = resolve(k);
195
+ if (v !== k)
196
+ flat.set(k, v);
197
+ }
198
+ return flat;
199
+ }
200
+ // The video path bypasses runGovern (which used to inject importance + aliases),
201
+ // so stamp both deterministically from the registry before governDeterministic.
202
+ // Importance: unmatched assets default to "featured" (never silently hidden),
203
+ // matching apply-plan. Aliases: registry surface names + resolved provisional
204
+ // descriptors are folded onto the canonical asset (renameDocs collapsed them to
205
+ // one name, so assignProvisionalIds saw no aliases).
206
+ export function stampImportance(script, registry) {
207
+ const imp = new Map();
208
+ const surfaceFor = new Map(); // canonical norm name → surface aliases
209
+ const addSurface = (canon, alias) => {
210
+ const k = norm(canon);
211
+ const a = alias.trim();
212
+ if (!a || norm(a) === k)
213
+ return;
214
+ if (!surfaceFor.has(k))
215
+ surfaceFor.set(k, new Set());
216
+ surfaceFor.get(k).add(a);
217
+ };
218
+ const flat = buildAliasMap(registry); // provisional name → resolved real name
219
+ for (const e of registry) {
220
+ imp.set(norm(e.name), e.importance);
221
+ for (const a of e.aliases)
222
+ imp.set(norm(a), e.importance);
223
+ const canon = flat.get(e.name) ?? e.name;
224
+ for (const a of e.aliases)
225
+ addSurface(canon, a);
226
+ if (e.resolvesTo)
227
+ addSurface(canon, e.name); // provisional descriptor → alias of the real one
228
+ }
229
+ const stamp = (list, nameKey) => {
230
+ for (const a of list ?? []) {
231
+ const canonName = String(a[nameKey] ?? "");
232
+ const names = [canonName, ...(a.aliases ?? [])];
233
+ let found;
234
+ for (const nm of names) {
235
+ const v = imp.get(norm(nm));
236
+ if (v) {
237
+ found = v;
238
+ break;
239
+ }
240
+ }
241
+ a.importance = found ?? "featured";
242
+ const surf = surfaceFor.get(norm(canonName));
243
+ if (surf?.size)
244
+ a.aliases = [...new Set([...(a.aliases ?? []), ...surf])];
245
+ }
246
+ };
247
+ stamp(script.actors, "actor_name");
248
+ stamp(script.locations, "location_name");
249
+ stamp(script.props, "prop_name");
250
+ return script;
251
+ }
252
+ // ===== serial output → per-episode working doc =====
253
+ // Map the serial parse output onto the established VideoEpisodeDoc shape. Only
254
+ // scenes + synopsis are populated (docsToNameScript consumes just those); the
255
+ // roster arrays stay empty since identity now lives in the running context.
256
+ export function deltaToDoc(out, episode) {
257
+ const scenes = out.scenes.map((s, i) => {
258
+ const env = {};
259
+ if (s.environment?.space)
260
+ env.space = s.environment.space;
261
+ if (s.environment?.time)
262
+ env.time = s.environment.time;
263
+ const anchors = (s.anchors ?? []).map((a) => ({
264
+ kind: a.kind,
265
+ ...(a.speaker ? { speaker: a.speaker } : {}),
266
+ ...(a.emotion ? { emotion: a.emotion } : {}),
267
+ ...(a.ts ? { ts: a.ts } : {}),
268
+ content: a.content ?? "",
269
+ }));
270
+ return {
271
+ index: i + 1,
272
+ environment: env,
273
+ ...(s.timeRange ? { timeRange: s.timeRange } : {}),
274
+ ...(s.location ? { location: s.location } : {}),
275
+ characters: (s.characters ?? []).filter((c) => c.name).map((c) => (c.state ? { name: c.name, state: c.state } : { name: c.name })),
276
+ props: (s.props ?? []).filter(Boolean),
277
+ anchors,
278
+ };
279
+ });
280
+ return {
281
+ episode,
282
+ synopsis: (out.synopsis ?? "").trim(),
283
+ scenes,
284
+ actors: [],
285
+ locations: [],
286
+ props: [],
287
+ speakers: [],
288
+ actorStates: [],
289
+ locationStates: [],
290
+ propStates: [],
291
+ };
292
+ }
293
+ //# sourceMappingURL=video-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-context.js","sourceRoot":"","sources":["../../../src/domain/ingest/video-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ export interface SerialScene {
2
+ environment: {
3
+ space?: string;
4
+ time?: string;
5
+ };
6
+ timeRange?: string;
7
+ location?: string;
8
+ characters: Array<{
9
+ name: string;
10
+ state?: string;
11
+ }>;
12
+ props: string[];
13
+ anchors: Array<{
14
+ kind: "act" | "dlg" | "think";
15
+ speaker?: string;
16
+ emotion?: string;
17
+ ts?: string;
18
+ content: string;
19
+ }>;
20
+ }
21
+ export interface SerialEntity {
22
+ name: string;
23
+ kind: "actor" | "location" | "prop";
24
+ status: "canonical" | "provisional";
25
+ importance: "featured" | "background";
26
+ anchor?: string;
27
+ appearance?: string;
28
+ role?: string;
29
+ states?: string[];
30
+ aliases?: string[];
31
+ }
32
+ export interface SerialOutput {
33
+ synopsis: string;
34
+ scenes: SerialScene[];
35
+ registry_delta: {
36
+ new_entities: SerialEntity[];
37
+ enrich: Array<{
38
+ name: string;
39
+ anchor?: string;
40
+ appearance?: string;
41
+ role?: string;
42
+ add_aliases?: string[];
43
+ add_states?: string[];
44
+ }>;
45
+ resolve: Array<{
46
+ provisional_name: string;
47
+ canonical_name: string;
48
+ reason: string;
49
+ }>;
50
+ };
51
+ open_threads: {
52
+ opened: Array<{
53
+ text: string;
54
+ }>;
55
+ closed: Array<{
56
+ ref: string;
57
+ }>;
58
+ };
59
+ }
60
+ export declare function parseSerialMd(md: string, _episode: number): SerialOutput;
@@ -0,0 +1,277 @@
1
+ // Deterministic parser: serial-pass markdown → SerialOutput (§10.2). No LLM.
2
+ // The serial Gemini pass emits ONE markdown document carrying both the episode
3
+ // screenplay (梗概 + 剧本 with MM:SS timestamps + typed-speaker anchors) and
4
+ // the registry-maintenance block in a fixed syntax (资产 roster with status /
5
+ // importance / 造型 / 别名, 还原 for provisional→real, 线索 for open threads).
6
+ // This parser turns it into the SerialOutput contract that applyDelta / deltaToDoc
7
+ // consume. Lenient by design — never throws on a malformed line; runVideoSerial
8
+ // rejects an empty/scene-less transcript upstream.
9
+ const TS_RE = /^\[((?:\d{1,2}:)?\d{1,2}:\d{2}(?:\.\d{1,3})?)\]\s*/;
10
+ const BAR = /\s*[||]\s*/; // half/full-width divider
11
+ // Timestamps are MM:SS (minute:second). The prompt no longer asks for sub-second,
12
+ // but stay lenient: drop any fractional part the model still emits so downstream
13
+ // always sees MM:SS (or HH:MM:SS if hours were present).
14
+ const dropFraction = (ts) => ts.replace(/\.\d+$/, "");
15
+ const splitList = (s) => s.split(/[,,//、]/).map((x) => x.trim()).filter(Boolean);
16
+ function parseCharList(s) {
17
+ return s.split(/[,,、]/).map((x) => x.trim()).filter(Boolean).map((tok) => {
18
+ const m = tok.match(/^(.+?)\s*[((]\s*(.+?)\s*[))]\s*$/);
19
+ return m ? { name: m[1].trim(), state: m[2].trim() } : { name: tok };
20
+ });
21
+ }
22
+ function parseAnchor(line) {
23
+ const m = line.match(/^>\s*\[(act|dlg|think)([^\]]*)\]\s*(.*)$/);
24
+ if (!m)
25
+ return null;
26
+ const kind = m[1];
27
+ const spec = m[2].replace(/^\|/, "");
28
+ let content = m[3].trim();
29
+ let ts;
30
+ const tm = content.match(TS_RE);
31
+ if (tm) {
32
+ ts = dropFraction(tm[1]);
33
+ content = content.replace(TS_RE, "").trim();
34
+ }
35
+ const parts = spec.split("|").map((x) => x.trim()).filter(Boolean);
36
+ const a = { kind, content };
37
+ if (ts)
38
+ a.ts = ts;
39
+ if (kind === "dlg" || kind === "think") {
40
+ if (parts[0])
41
+ a.speaker = parts[0];
42
+ if (parts[1])
43
+ a.emotion = parts[1];
44
+ }
45
+ return a;
46
+ }
47
+ const oneImp = (v) => (v.trim() === "background" ? "background" : "featured");
48
+ const oneStatus = (v) => (v.trim() === "provisional" ? "provisional" : "canonical");
49
+ export function parseSerialMd(md, _episode) {
50
+ const lines = md.split(/\r?\n/);
51
+ const out = {
52
+ synopsis: "",
53
+ scenes: [],
54
+ registry_delta: { new_entities: [], enrich: [], resolve: [] },
55
+ open_threads: { opened: [], closed: [] },
56
+ };
57
+ let section = null;
58
+ let scene = null;
59
+ let cur = null;
60
+ const synBuf = [];
61
+ const pushScene = () => { if (scene) {
62
+ out.scenes.push(scene);
63
+ scene = null;
64
+ } };
65
+ const pushCur = () => { if (cur) {
66
+ out.registry_delta.new_entities.push(cur);
67
+ cur = null;
68
+ } };
69
+ for (const raw of lines) {
70
+ const t = raw.replace(/\s+$/, "").trim();
71
+ // Section headers. "# 资产维护" (or legacy "# 资产") closes the script region;
72
+ // the roster is now incremental: 新增* register unknowns, 修正 enriches known
73
+ // entities in-place, 还原 resolves provisionals. Legacy full-roster headers
74
+ // (## 人物 / ## 场景 / ## 道具 without 新增) still parse as new entities.
75
+ if (/^#\s*剧本/.test(t)) {
76
+ section = "script";
77
+ pushCur();
78
+ continue;
79
+ }
80
+ if (/^#\s*资产/.test(t)) {
81
+ section = null;
82
+ pushScene();
83
+ pushCur();
84
+ continue;
85
+ }
86
+ if (/^##\s*梗概/.test(t)) {
87
+ section = "synopsis";
88
+ continue;
89
+ }
90
+ if (/^##\s*(?:新增)?人物/.test(t)) {
91
+ section = "actors";
92
+ pushCur();
93
+ continue;
94
+ }
95
+ if (/^##\s*(?:新增)?道具/.test(t)) {
96
+ section = "props";
97
+ pushCur();
98
+ continue;
99
+ }
100
+ if (/^##\s*(修正|更正|补充)/.test(t)) {
101
+ section = "correct";
102
+ pushCur();
103
+ continue;
104
+ }
105
+ if (/^##\s*(还原|身份还原)/.test(t)) {
106
+ section = "resolve";
107
+ pushCur();
108
+ continue;
109
+ }
110
+ if (/^##\s*(线索|未闭合线索)/.test(t)) {
111
+ section = "threads";
112
+ pushCur();
113
+ continue;
114
+ }
115
+ if (/^##\s*(?:新增)?场景/.test(t) && section !== "script") {
116
+ section = "locations";
117
+ pushCur();
118
+ continue;
119
+ }
120
+ // In-script scene header: ## 场景 N
121
+ if (section === "script" && /^##\s*场景/.test(t)) {
122
+ pushScene();
123
+ scene = { environment: {}, characters: [], props: [], anchors: [] };
124
+ continue;
125
+ }
126
+ if (section === "synopsis") {
127
+ if (t)
128
+ synBuf.push(t);
129
+ continue;
130
+ }
131
+ if (section === "script" && scene) {
132
+ if (/^-\s*时空[::]/.test(t)) {
133
+ const [space, time] = t.replace(/^-\s*时空[::]\s*/, "").trim().split(/\s+/);
134
+ scene.environment = {};
135
+ if (space)
136
+ scene.environment.space = space;
137
+ if (time)
138
+ scene.environment.time = time;
139
+ }
140
+ else if (/^-\s*时间[::]/.test(t)) {
141
+ scene.timeRange = t.replace(/^-\s*时间[::]\s*/, "").trim().replace(/(\d{1,2}:\d{2})\.\d+/g, "$1");
142
+ }
143
+ else if (/^-\s*地点[::]/.test(t)) {
144
+ scene.location = t.replace(/^-\s*地点[::]\s*/, "").trim();
145
+ }
146
+ else if (/^-\s*角色[::]/.test(t)) {
147
+ scene.characters = parseCharList(t.replace(/^-\s*角色[::]\s*/, ""));
148
+ }
149
+ else if (/^-\s*道具[::]/.test(t)) {
150
+ const v = t.replace(/^-\s*道具[::]\s*/, "").trim();
151
+ scene.props = /^无$/.test(v) ? [] : v.split(/[,,]/).map((x) => x.trim()).filter(Boolean);
152
+ }
153
+ else if (/^>/.test(t)) {
154
+ const a = parseAnchor(t);
155
+ if (a)
156
+ scene.anchors.push(a);
157
+ }
158
+ else if (t && scene.anchors.length) {
159
+ scene.anchors[scene.anchors.length - 1].content += "\n" + t;
160
+ }
161
+ continue;
162
+ }
163
+ // 人物 roster: multi-line blocks. Header: `- 名 | status | importance`.
164
+ if (section === "actors") {
165
+ const isField = /^-\s*(外观|锚点|作用|声线|造型|别名)[::]/.test(t);
166
+ const head = t.match(/^-\s+(.+)$/);
167
+ if (head && !isField) {
168
+ pushCur();
169
+ const segs = head[1].split(BAR).map((x) => x.trim());
170
+ cur = {
171
+ name: segs[0].trim(),
172
+ kind: "actor",
173
+ status: segs[1] ? oneStatus(segs[1]) : "canonical",
174
+ importance: segs[2] ? oneImp(segs[2]) : "featured",
175
+ states: [],
176
+ aliases: [],
177
+ };
178
+ continue;
179
+ }
180
+ if (cur) {
181
+ const f = t.match(/^-?\s*(外观|锚点|作用|声线|造型|别名)[::]\s*(.*)$/);
182
+ if (f) {
183
+ const val = f[2].trim();
184
+ if (f[1] === "外观")
185
+ cur.appearance = val;
186
+ else if (f[1] === "锚点")
187
+ cur.anchor = val;
188
+ else if (f[1] === "作用")
189
+ cur.role = val;
190
+ else if (f[1] === "造型")
191
+ cur.states = splitList(val);
192
+ else if (f[1] === "别名")
193
+ cur.aliases = splitList(val);
194
+ }
195
+ }
196
+ continue;
197
+ }
198
+ // 场景 / 道具 under 资产: `- 名 | importance: desc`.
199
+ if ((section === "locations" || section === "props") && /^-/.test(t)) {
200
+ const body = t.replace(/^-\s*/, "");
201
+ const m = body.match(/^(.+?)(?:[||]\s*(featured|background)\s*)?[::]\s*(.*)$/);
202
+ let name = "", imp = "featured", desc = "";
203
+ if (m) {
204
+ name = m[1].trim();
205
+ if (m[2])
206
+ imp = oneImp(m[2]);
207
+ desc = m[3].trim();
208
+ }
209
+ else {
210
+ const segs = body.split(BAR).map((x) => x.trim());
211
+ name = segs[0] ?? "";
212
+ if (segs[1])
213
+ imp = oneImp(segs[1]);
214
+ }
215
+ if (name)
216
+ out.registry_delta.new_entities.push({ name, kind: section === "locations" ? "location" : "prop", status: "canonical", importance: imp, ...(desc ? { appearance: desc } : {}), states: [], aliases: [] });
217
+ continue;
218
+ }
219
+ // 修正: `- 名 | 外观: X | 锚点: Y | 作用: Z | 造型: A/B | 别名: C`
220
+ // Enrich a KNOWN entity in place (only changed fields). First segment = name.
221
+ if (section === "correct" && /^-/.test(t)) {
222
+ const segs = t.replace(/^-\s*/, "").split(BAR).map((x) => x.trim()).filter(Boolean);
223
+ const name = segs[0];
224
+ if (name) {
225
+ const en = { name };
226
+ for (const f of segs.slice(1)) {
227
+ const fm = f.match(/^(外观|锚点|作用|造型|别名)[::]\s*(.*)$/);
228
+ if (!fm)
229
+ continue;
230
+ const val = fm[2].trim();
231
+ if (!val)
232
+ continue;
233
+ if (fm[1] === "外观")
234
+ en.appearance = val;
235
+ else if (fm[1] === "锚点")
236
+ en.anchor = val;
237
+ else if (fm[1] === "作用")
238
+ en.role = val;
239
+ else if (fm[1] === "造型")
240
+ en.add_states = splitList(val);
241
+ else if (fm[1] === "别名")
242
+ en.add_aliases = splitList(val);
243
+ }
244
+ if (Object.keys(en).length > 1)
245
+ out.registry_delta.enrich.push(en);
246
+ }
247
+ continue;
248
+ }
249
+ // 还原: `- 湿发男 => 陈默 | 依据: ...`
250
+ if (section === "resolve" && /^-/.test(t)) {
251
+ const m = t.replace(/^-\s*/, "").match(/^(.+?)\s*(?:=>|→|➡|=>)\s*(.+?)(?:\s*[||]\s*(?:依据|理由)?[::]?\s*(.*))?$/);
252
+ if (m && m[1] && m[2])
253
+ out.registry_delta.resolve.push({ provisional_name: m[1].trim(), canonical_name: m[2].trim(), reason: (m[3] ?? "").trim() });
254
+ continue;
255
+ }
256
+ // 线索: `+ 新悬念` opened; `- [id]` closed.
257
+ if (section === "threads") {
258
+ if (/^\+/.test(t)) {
259
+ const text = t.replace(/^\+\s*/, "").trim();
260
+ if (text)
261
+ out.open_threads.opened.push({ text });
262
+ continue;
263
+ }
264
+ const cm = t.match(/^-\s*\[([^\]]+)\]/);
265
+ if (cm) {
266
+ out.open_threads.closed.push({ ref: cm[1].trim() });
267
+ continue;
268
+ }
269
+ continue;
270
+ }
271
+ }
272
+ pushScene();
273
+ pushCur();
274
+ out.synopsis = synBuf.join("");
275
+ return out;
276
+ }
277
+ //# sourceMappingURL=video-serial-md.js.map