@lingjingai/scriptctl 0.28.3 → 0.29.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 (117) hide show
  1. package/changes/0.28.4.md +13 -0
  2. package/changes/0.29.0.md +17 -0
  3. package/dist/cli.js +25 -3
  4. package/dist/cli.js.map +1 -1
  5. package/dist/common.d.ts +1 -0
  6. package/dist/common.js +3 -0
  7. package/dist/common.js.map +1 -1
  8. package/dist/domain/direct/runner.d.ts +23 -0
  9. package/dist/domain/direct/runner.js +72 -0
  10. package/dist/domain/direct/runner.js.map +1 -0
  11. package/dist/domain/direct/stage.d.ts +86 -0
  12. package/dist/domain/direct/stage.js +131 -0
  13. package/dist/domain/direct/stage.js.map +1 -0
  14. package/dist/domain/direct/stages/asset-curation.d.ts +2 -0
  15. package/dist/domain/direct/stages/asset-curation.js +9 -0
  16. package/dist/domain/direct/stages/asset-curation.js.map +1 -0
  17. package/dist/domain/direct/stages/batch-extract.d.ts +2 -0
  18. package/dist/domain/direct/stages/batch-extract.js +12 -0
  19. package/dist/domain/direct/stages/batch-extract.js.map +1 -0
  20. package/dist/domain/direct/stages/batch-plan.d.ts +2 -0
  21. package/dist/domain/direct/stages/batch-plan.js +9 -0
  22. package/dist/domain/direct/stages/batch-plan.js.map +1 -0
  23. package/dist/domain/direct/stages/episode-merge.d.ts +2 -0
  24. package/dist/domain/direct/stages/episode-merge.js +11 -0
  25. package/dist/domain/direct/stages/episode-merge.js.map +1 -0
  26. package/dist/domain/direct/stages/episode-plan.d.ts +2 -0
  27. package/dist/domain/direct/stages/episode-plan.js +9 -0
  28. package/dist/domain/direct/stages/episode-plan.js.map +1 -0
  29. package/dist/domain/direct/stages/episode-synopsis.d.ts +2 -0
  30. package/dist/domain/direct/stages/episode-synopsis.js +12 -0
  31. package/dist/domain/direct/stages/episode-synopsis.js.map +1 -0
  32. package/dist/domain/direct/stages/episode-titles.d.ts +2 -0
  33. package/dist/domain/direct/stages/episode-titles.js +12 -0
  34. package/dist/domain/direct/stages/episode-titles.js.map +1 -0
  35. package/dist/domain/direct/stages/index.d.ts +17 -0
  36. package/dist/domain/direct/stages/index.js +37 -0
  37. package/dist/domain/direct/stages/index.js.map +1 -0
  38. package/dist/domain/direct/stages/metadata.d.ts +2 -0
  39. package/dist/domain/direct/stages/metadata.js +11 -0
  40. package/dist/domain/direct/stages/metadata.js.map +1 -0
  41. package/dist/domain/direct/stages/script-merge.d.ts +2 -0
  42. package/dist/domain/direct/stages/script-merge.js +15 -0
  43. package/dist/domain/direct/stages/script-merge.js.map +1 -0
  44. package/dist/domain/direct/stages/script-synopsis.d.ts +2 -0
  45. package/dist/domain/direct/stages/script-synopsis.js +12 -0
  46. package/dist/domain/direct/stages/script-synopsis.js.map +1 -0
  47. package/dist/domain/direct/stages/source-prepare.d.ts +2 -0
  48. package/dist/domain/direct/stages/source-prepare.js +9 -0
  49. package/dist/domain/direct/stages/source-prepare.js.map +1 -0
  50. package/dist/domain/direct/stages/validate.d.ts +2 -0
  51. package/dist/domain/direct/stages/validate.js +10 -0
  52. package/dist/domain/direct/stages/validate.js.map +1 -0
  53. package/dist/domain/direct-core.js +15 -1
  54. package/dist/domain/direct-core.js.map +1 -1
  55. package/dist/help-text.js +1 -1
  56. package/dist/infra/local-script-output-store.d.ts +2 -1
  57. package/dist/infra/local-script-output-store.js +11 -0
  58. package/dist/infra/local-script-output-store.js.map +1 -1
  59. package/dist/infra/providers.js +13 -4
  60. package/dist/infra/providers.js.map +1 -1
  61. package/dist/infra/script-output-api.d.ts +27 -4
  62. package/dist/infra/script-output-api.js +130 -106
  63. package/dist/infra/script-output-api.js.map +1 -1
  64. package/dist/infra/script-output-store.d.ts +24 -0
  65. package/dist/infra/script-output-store.js.map +1 -1
  66. package/dist/usecases/direct.d.ts +14 -0
  67. package/dist/usecases/direct.js +725 -360
  68. package/dist/usecases/direct.js.map +1 -1
  69. package/dist/usecases/parse.js +2 -2
  70. package/dist/usecases/parse.js.map +1 -1
  71. package/dist/usecases/script/actions.js.map +1 -1
  72. package/dist/usecases/script/actor.js.map +1 -1
  73. package/dist/usecases/script/actors.js.map +1 -1
  74. package/dist/usecases/script/add-actor.js.map +1 -1
  75. package/dist/usecases/script/add-episode.js.map +1 -1
  76. package/dist/usecases/script/add-location.js.map +1 -1
  77. package/dist/usecases/script/add-prop.js.map +1 -1
  78. package/dist/usecases/script/add-speaker.js.map +1 -1
  79. package/dist/usecases/script/alias.js.map +1 -1
  80. package/dist/usecases/script/assets.js.map +1 -1
  81. package/dist/usecases/script/context.js.map +1 -1
  82. package/dist/usecases/script/create.js.map +1 -1
  83. package/dist/usecases/script/delete.js.map +1 -1
  84. package/dist/usecases/script/describe.js.map +1 -1
  85. package/dist/usecases/script/dialogue.js.map +1 -1
  86. package/dist/usecases/script/do.js.map +1 -1
  87. package/dist/usecases/script/episodes.js.map +1 -1
  88. package/dist/usecases/script/export.js.map +1 -1
  89. package/dist/usecases/script/insert.js.map +1 -1
  90. package/dist/usecases/script/issues.js.map +1 -1
  91. package/dist/usecases/script/lib.js.map +1 -1
  92. package/dist/usecases/script/locations.js.map +1 -1
  93. package/dist/usecases/script/merge.js.map +1 -1
  94. package/dist/usecases/script/move.js.map +1 -1
  95. package/dist/usecases/script/overlap.js.map +1 -1
  96. package/dist/usecases/script/props.js.map +1 -1
  97. package/dist/usecases/script/refs.js.map +1 -1
  98. package/dist/usecases/script/rename.js.map +1 -1
  99. package/dist/usecases/script/replace.js.map +1 -1
  100. package/dist/usecases/script/role.js.map +1 -1
  101. package/dist/usecases/script/scenes.js.map +1 -1
  102. package/dist/usecases/script/script-patch.js.map +1 -1
  103. package/dist/usecases/script/script-validate.js.map +1 -1
  104. package/dist/usecases/script/session.d.ts +1 -0
  105. package/dist/usecases/script/session.js +15 -4
  106. package/dist/usecases/script/session.js.map +1 -1
  107. package/dist/usecases/script/speakers.js.map +1 -1
  108. package/dist/usecases/script/split.js.map +1 -1
  109. package/dist/usecases/script/state-add.js.map +1 -1
  110. package/dist/usecases/script/state-change.js.map +1 -1
  111. package/dist/usecases/script/state-delete.js.map +1 -1
  112. package/dist/usecases/script/state-rename.js.map +1 -1
  113. package/dist/usecases/script/summary.js.map +1 -1
  114. package/dist/usecases/script/transition.js.map +1 -1
  115. package/dist/usecases/script/type.js.map +1 -1
  116. package/dist/usecases/script/worldview.js.map +1 -1
  117. package/package.json +2 -1
@@ -0,0 +1,12 @@
1
+ import { stageBatchExtract } from "../../../usecases/direct.js";
2
+ // LLM-extract each batch concurrently, persisting per-batch result/error files
3
+ // (the resume unit). Reads: source.txt + episode_plan.json + batch_plan.json.
4
+ // Writes: batch_results/<key>.json|.error.json. `output: null` — completion is
5
+ // per-batch, not a single artifact, so the runner never skips it wholesale;
6
+ // reuse is decided per batch inside the stage (classifyBatch).
7
+ export const batchExtractStage = {
8
+ name: "batch-extract",
9
+ output: null,
10
+ run: (ctx) => stageBatchExtract(ctx),
11
+ };
12
+ //# sourceMappingURL=batch-extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-extract.js","sourceRoot":"","sources":["../../../../src/domain/direct/stages/batch-extract.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAEhE,+EAA+E;AAC/E,8EAA8E;AAC9E,+EAA+E;AAC/E,4EAA4E;AAC5E,+DAA+D;AAC/D,MAAM,CAAC,MAAM,iBAAiB,GAAU;IACtC,IAAI,EAAE,eAAe;IACrB,MAAM,EAAE,IAAI;IACZ,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC;CACrC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Stage } from "../stage.js";
2
+ export declare const batchPlanStage: Stage;
@@ -0,0 +1,9 @@
1
+ import { stageBatchPlan } from "../../../usecases/direct.js";
2
+ // Split each episode into natural extraction batches (deterministic). Reads:
3
+ // source.txt + episode_plan.json. Writes: batch_plan.json.
4
+ export const batchPlanStage = {
5
+ name: "batch-plan",
6
+ output: "batch_plan.json",
7
+ run: (ctx) => stageBatchPlan(ctx),
8
+ };
9
+ //# sourceMappingURL=batch-plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-plan.js","sourceRoot":"","sources":["../../../../src/domain/direct/stages/batch-plan.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,6EAA6E;AAC7E,2DAA2D;AAC3D,MAAM,CAAC,MAAM,cAAc,GAAU;IACnC,IAAI,EAAE,YAAY;IAClB,MAAM,EAAE,iBAAiB;IACzB,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC;CAClC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Stage } from "../stage.js";
2
+ export declare const episodeMergeStage: Stage;
@@ -0,0 +1,11 @@
1
+ import { stageEpisodeMerge } from "../../../usecases/direct.js";
2
+ // Merge each episode's batch results into one episode result (deterministic).
3
+ // Reads: batch_results/ + plans. Writes: in-memory merged results carried on
4
+ // ctx.state (persisted by the episode-synopsis stage, matching the god-command
5
+ // order). `output: null` — the persisted artifact is written by the next stage.
6
+ export const episodeMergeStage = {
7
+ name: "episode-merge",
8
+ output: null,
9
+ run: (ctx) => stageEpisodeMerge(ctx),
10
+ };
11
+ //# sourceMappingURL=episode-merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"episode-merge.js","sourceRoot":"","sources":["../../../../src/domain/direct/stages/episode-merge.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAEhE,8EAA8E;AAC9E,6EAA6E;AAC7E,+EAA+E;AAC/E,gFAAgF;AAChF,MAAM,CAAC,MAAM,iBAAiB,GAAU;IACtC,IAAI,EAAE,eAAe;IACrB,MAAM,EAAE,IAAI;IACZ,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC;CACrC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Stage } from "../stage.js";
2
+ export declare const episodePlanStage: Stage;
@@ -0,0 +1,9 @@
1
+ import { stageEpisodePlan } from "../../../usecases/direct.js";
2
+ // Split source.txt into episodes (deterministic). Reads: source.txt. Writes:
3
+ // episode_plan.json.
4
+ export const episodePlanStage = {
5
+ name: "episode-plan",
6
+ output: "episode_plan.json",
7
+ run: (ctx) => stageEpisodePlan(ctx),
8
+ };
9
+ //# sourceMappingURL=episode-plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"episode-plan.js","sourceRoot":"","sources":["../../../../src/domain/direct/stages/episode-plan.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAE/D,6EAA6E;AAC7E,qBAAqB;AACrB,MAAM,CAAC,MAAM,gBAAgB,GAAU;IACrC,IAAI,EAAE,cAAc;IACpB,MAAM,EAAE,mBAAmB;IAC3B,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC;CACpC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Stage } from "../stage.js";
2
+ export declare const episodeSynopsisStage: Stage;
@@ -0,0 +1,12 @@
1
+ import { stageEpisodeSynopsis } from "../../../usecases/direct.js";
2
+ // Resolve each episode's synopsis (reduce-1: passthrough / reuse / skip / LLM
3
+ // stitch) then persist episode_results/ep_NNN.json. Reads: merged results +
4
+ // prior persisted syn. Writes: episode_results/*.json. Also raises the resumable
5
+ // "incomplete" stop when an episode still has unextracted batches. `output: null`
6
+ // — completion is per-episode, decided inside the stage.
7
+ export const episodeSynopsisStage = {
8
+ name: "episode-synopsis",
9
+ output: null,
10
+ run: (ctx) => stageEpisodeSynopsis(ctx),
11
+ };
12
+ //# sourceMappingURL=episode-synopsis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"episode-synopsis.js","sourceRoot":"","sources":["../../../../src/domain/direct/stages/episode-synopsis.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAEnE,8EAA8E;AAC9E,4EAA4E;AAC5E,iFAAiF;AACjF,kFAAkF;AAClF,yDAAyD;AACzD,MAAM,CAAC,MAAM,oBAAoB,GAAU;IACzC,IAAI,EAAE,kBAAkB;IACxB,MAAM,EAAE,IAAI;IACZ,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,oBAAoB,CAAC,GAAG,CAAC;CACxC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Stage } from "../stage.js";
2
+ export declare const episodeTitlesStage: Stage;
@@ -0,0 +1,12 @@
1
+ import { stageEpisodeTitles } from "../../../usecases/direct.js";
2
+ // LLM-enrich the plan's missing episode titles (soft-degrade to deterministic
3
+ // titles). Reads: source.txt + episode_plan.json. Writes: episode_plan.json
4
+ // (titles filled in place). `output: null` — the plan artifact already exists
5
+ // from episode-plan, so completion isn't captured by file presence; the runner
6
+ // never skips titles wholesale.
7
+ export const episodeTitlesStage = {
8
+ name: "episode-titles",
9
+ output: null,
10
+ run: (ctx) => stageEpisodeTitles(ctx),
11
+ };
12
+ //# sourceMappingURL=episode-titles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"episode-titles.js","sourceRoot":"","sources":["../../../../src/domain/direct/stages/episode-titles.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEjE,8EAA8E;AAC9E,4EAA4E;AAC5E,8EAA8E;AAC9E,+EAA+E;AAC/E,gCAAgC;AAChC,MAAM,CAAC,MAAM,kBAAkB,GAAU;IACvC,IAAI,EAAE,gBAAgB;IACtB,MAAM,EAAE,IAAI;IACZ,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC;CACtC,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { Stage, StageName } from "../stage.js";
2
+ import { sourcePrepareStage } from "./source-prepare.js";
3
+ import { episodePlanStage } from "./episode-plan.js";
4
+ import { episodeTitlesStage } from "./episode-titles.js";
5
+ import { batchPlanStage } from "./batch-plan.js";
6
+ import { batchExtractStage } from "./batch-extract.js";
7
+ import { episodeMergeStage } from "./episode-merge.js";
8
+ import { episodeSynopsisStage } from "./episode-synopsis.js";
9
+ import { scriptMergeStage } from "./script-merge.js";
10
+ import { assetCurationStage } from "./asset-curation.js";
11
+ import { metadataStage } from "./metadata.js";
12
+ import { scriptSynopsisStage } from "./script-synopsis.js";
13
+ import { validateStage } from "./validate.js";
14
+ export declare const STAGES: readonly Stage[];
15
+ export declare function stageByName(name: string): Stage | undefined;
16
+ export declare function stageNames(): StageName[];
17
+ export { sourcePrepareStage, episodePlanStage, episodeTitlesStage, batchPlanStage, batchExtractStage, episodeMergeStage, episodeSynopsisStage, scriptMergeStage, assetCurationStage, metadataStage, scriptSynopsisStage, validateStage, };
@@ -0,0 +1,37 @@
1
+ import { sourcePrepareStage } from "./source-prepare.js";
2
+ import { episodePlanStage } from "./episode-plan.js";
3
+ import { episodeTitlesStage } from "./episode-titles.js";
4
+ import { batchPlanStage } from "./batch-plan.js";
5
+ import { batchExtractStage } from "./batch-extract.js";
6
+ import { episodeMergeStage } from "./episode-merge.js";
7
+ import { episodeSynopsisStage } from "./episode-synopsis.js";
8
+ import { scriptMergeStage } from "./script-merge.js";
9
+ import { assetCurationStage } from "./asset-curation.js";
10
+ import { metadataStage } from "./metadata.js";
11
+ import { scriptSynopsisStage } from "./script-synopsis.js";
12
+ import { validateStage } from "./validate.js";
13
+ // The full direct pipeline, in execution order. This is the single source of
14
+ // truth for stage ordering — runStages walks it, runOne indexes into it, and
15
+ // `direct run <stage>` validates against it.
16
+ export const STAGES = [
17
+ sourcePrepareStage,
18
+ episodePlanStage,
19
+ episodeTitlesStage,
20
+ batchPlanStage,
21
+ batchExtractStage,
22
+ episodeMergeStage,
23
+ episodeSynopsisStage,
24
+ scriptMergeStage,
25
+ assetCurationStage,
26
+ metadataStage,
27
+ scriptSynopsisStage,
28
+ validateStage,
29
+ ];
30
+ export function stageByName(name) {
31
+ return STAGES.find((s) => s.name === name);
32
+ }
33
+ export function stageNames() {
34
+ return STAGES.map((s) => s.name);
35
+ }
36
+ export { sourcePrepareStage, episodePlanStage, episodeTitlesStage, batchPlanStage, batchExtractStage, episodeMergeStage, episodeSynopsisStage, scriptMergeStage, assetCurationStage, metadataStage, scriptSynopsisStage, validateStage, };
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/domain/direct/stages/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,6EAA6E;AAC7E,6EAA6E;AAC7E,6CAA6C;AAC7C,MAAM,CAAC,MAAM,MAAM,GAAqB;IACtC,kBAAkB;IAClB,gBAAgB;IAChB,kBAAkB;IAClB,cAAc;IACd,iBAAiB;IACjB,iBAAiB;IACjB,oBAAoB;IACpB,gBAAgB;IAChB,kBAAkB;IAClB,aAAa;IACb,mBAAmB;IACnB,aAAa;CACd,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,aAAa,GACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Stage } from "../stage.js";
2
+ export declare const metadataStage: Stage;
@@ -0,0 +1,11 @@
1
+ import { stageMetadata } from "../../../usecases/direct.js";
2
+ // LLM metadata extraction (worldview / role_type / asset descriptions), applied
3
+ // onto the script. Honors --skip-metadata. Reads: source.txt + ctx.state.script.
4
+ // Writes: asset_metadata.json (+ mutates the in-memory script). `output: null` —
5
+ // --skip-metadata deletes the artifact, so file presence isn't a skip signal.
6
+ export const metadataStage = {
7
+ name: "metadata",
8
+ output: null,
9
+ run: (ctx) => stageMetadata(ctx),
10
+ };
11
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../../src/domain/direct/stages/metadata.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,gFAAgF;AAChF,iFAAiF;AACjF,iFAAiF;AACjF,8EAA8E;AAC9E,MAAM,CAAC,MAAM,aAAa,GAAU;IAClC,IAAI,EAAE,UAAU;IAChB,MAAM,EAAE,IAAI;IACZ,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC;CACjC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Stage } from "../stage.js";
2
+ export declare const scriptMergeStage: Stage;
@@ -0,0 +1,15 @@
1
+ import { stageScriptMerge } from "../../../usecases/direct.js";
2
+ // Merge all episode results into one script + asset normalization report
3
+ // (deterministic). Reads: episode_results/. Writes: ctx.state.script (persisted
4
+ // later by script-synopsis) + asset_normalization.json. `output: null` — the
5
+ // script must be re-derived from episode_results on EVERY run (a reused or
6
+ // edited batch changes its episode result, which has to flow back into the
7
+ // script), so this stage is never skipped on artifact presence. Presence of
8
+ // asset_normalization.json is therefore NOT a completion signal; script.initial
9
+ // .json is written later by script-synopsis, matching the god-command order.
10
+ export const scriptMergeStage = {
11
+ name: "script-merge",
12
+ output: null,
13
+ run: (ctx) => stageScriptMerge(ctx),
14
+ };
15
+ //# sourceMappingURL=script-merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-merge.js","sourceRoot":"","sources":["../../../../src/domain/direct/stages/script-merge.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAE/D,yEAAyE;AACzE,gFAAgF;AAChF,6EAA6E;AAC7E,2EAA2E;AAC3E,2EAA2E;AAC3E,4EAA4E;AAC5E,gFAAgF;AAChF,6EAA6E;AAC7E,MAAM,CAAC,MAAM,gBAAgB,GAAU;IACrC,IAAI,EAAE,cAAc;IACpB,MAAM,EAAE,IAAI;IACZ,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC;CACpC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Stage } from "../stage.js";
2
+ export declare const scriptSynopsisStage: Stage;
@@ -0,0 +1,12 @@
1
+ import { stageScriptSynopsis } from "../../../usecases/direct.js";
2
+ // Whole-script overview (reduce-2): synopsis/theme/logline/style/main_characters,
3
+ // soft-degrading on provider failure. Persists script.initial.json (the write
4
+ // point inherited from the god-command). Reads: ctx.state.script. Writes:
5
+ // synopsis.json + script.initial.json. `output: null` — degraded/skip outcomes
6
+ // mean presence of script.initial.json isn't a clean skip signal.
7
+ export const scriptSynopsisStage = {
8
+ name: "script-synopsis",
9
+ output: null,
10
+ run: (ctx) => stageScriptSynopsis(ctx),
11
+ };
12
+ //# sourceMappingURL=script-synopsis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-synopsis.js","sourceRoot":"","sources":["../../../../src/domain/direct/stages/script-synopsis.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,kFAAkF;AAClF,8EAA8E;AAC9E,0EAA0E;AAC1E,+EAA+E;AAC/E,kEAAkE;AAClE,MAAM,CAAC,MAAM,mBAAmB,GAAU;IACxC,IAAI,EAAE,iBAAiB;IACvB,MAAM,EAAE,IAAI;IACZ,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,mBAAmB,CAAC,GAAG,CAAC;CACvC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Stage } from "../stage.js";
2
+ export declare const sourcePrepareStage: Stage;
@@ -0,0 +1,9 @@
1
+ import { stageSourcePrepare } from "../../../usecases/direct.js";
2
+ // Convert the raw source file into source.txt (+ source_manifest.json). Reads:
3
+ // the --source-path file. Writes: workspace/source.txt, source_manifest.json.
4
+ export const sourcePrepareStage = {
5
+ name: "source-prepare",
6
+ output: "source_manifest.json",
7
+ run: (ctx) => stageSourcePrepare(ctx),
8
+ };
9
+ //# sourceMappingURL=source-prepare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-prepare.js","sourceRoot":"","sources":["../../../../src/domain/direct/stages/source-prepare.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEjE,+EAA+E;AAC/E,8EAA8E;AAC9E,MAAM,CAAC,MAAM,kBAAkB,GAAU;IACvC,IAAI,EAAE,gBAAgB;IACtB,MAAM,EAAE,sBAAsB;IAC9B,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC;CACtC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Stage } from "../stage.js";
2
+ export declare const validateStage: Stage;
@@ -0,0 +1,10 @@
1
+ import { stageValidate } from "../../../usecases/direct.js";
2
+ // Validate the assembled script.initial.json. Reads: script.initial.json.
3
+ // Writes: validation.json. `output: null` — validation is cheap and always
4
+ // re-run so status reflects the latest script.
5
+ export const validateStage = {
6
+ name: "validate",
7
+ output: null,
8
+ run: (ctx) => stageValidate(ctx),
9
+ };
10
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../src/domain/direct/stages/validate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,0EAA0E;AAC1E,2EAA2E;AAC3E,+CAA+C;AAC/C,MAAM,CAAC,MAAM,aAAa,GAAU;IAClC,IAAI,EAAE,UAAU;IAChB,MAAM,EAAE,IAAI;IACZ,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC;CACjC,CAAC"}
@@ -417,11 +417,25 @@ export function buildEpisodePlan(sourceText) {
417
417
  let confidence;
418
418
  let strategy;
419
419
  if (matches.length > 0) {
420
+ // Episode identity must be unique: ep_NNN is the dedup key for episode_results
421
+ // and the status table. Sources sometimes reuse a number (two different
422
+ // chapters both headed 第35集) — trust document order over the broken label and
423
+ // reassign the duplicate to the next free integer so neither segment's content
424
+ // is overwritten downstream. A well-formed source (sequential numbers) is
425
+ // unaffected: parseEpNumber already equals the position.
426
+ const usedEpNums = new Set();
420
427
  for (let idx = 0; idx < matches.length; idx++) {
421
428
  const match = matches[idx];
422
429
  const groups = match.groups ?? {};
423
430
  const raw = groups["zh"] || groups["ep"] || String(idx + 1);
424
- const epNum = parseEpNumber(raw) ?? idx + 1;
431
+ let epNum = parseEpNumber(raw) ?? idx + 1;
432
+ if (usedEpNums.has(epNum)) {
433
+ let next = idx + 1;
434
+ while (usedEpNums.has(next))
435
+ next++;
436
+ epNum = next;
437
+ }
438
+ usedEpNums.add(epNum);
425
439
  const end = idx + 1 < matches.length ? matches[idx + 1].index : sourceText.length;
426
440
  const header = match[0].trim();
427
441
  const rawTitle = extractEpisodeTitleCandidate(header);