@oh-story/dsh 0.1.9 → 0.1.11

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 (529) hide show
  1. package/README.md +14 -14
  2. package/lib/client.js +209 -73
  3. package/lib/client.js.map +3 -3
  4. package/lib/drama/manifest.json +248 -168
  5. package/lib/drama/skills/short-drama/SKILL.md +16 -4
  6. package/lib/drama/skills/short-drama/assets/project-template/short-drama.json +3 -0
  7. package/lib/drama/skills/short-drama/references/creator-documents.md +3 -0
  8. package/lib/drama/skills/short-drama/references/knowhow-index.md +15 -0
  9. package/lib/drama/skills/short-drama/scripts/creator_markdown_check.py +14 -0
  10. package/lib/drama/skills/short-drama/scripts/project_tool.py +131 -0
  11. package/lib/drama/skills/short-drama-assets/SKILL.md +2 -1
  12. package/lib/drama/skills/short-drama-assets/references/asset-review-checklist.md +2 -0
  13. package/lib/drama/skills/short-drama-assets/references/character-and-look.md +10 -0
  14. package/lib/drama/skills/short-drama-assets/references/continuity-lock.md +6 -9
  15. package/lib/drama/skills/short-drama-assets/references/era-anchors.md +37 -0
  16. package/lib/drama/skills/short-drama-assets/references/stage-contract.md +2 -0
  17. package/lib/drama/skills/short-drama-assets/references/voice-direction.md +28 -0
  18. package/lib/drama/skills/short-drama-develop/SKILL.md +10 -4
  19. package/lib/drama/skills/short-drama-develop/assets/adaptation-map.example.jsonl +1 -1
  20. package/lib/drama/skills/short-drama-develop/assets/creative-brief.md +8 -0
  21. package/lib/drama/skills/short-drama-develop/references/adaptation-craft.md +80 -13
  22. package/lib/drama/skills/short-drama-develop/references/episode-design.md +95 -12
  23. package/lib/drama/skills/short-drama-develop/references/genre-and-hook-playbook.md +9 -5
  24. package/lib/drama/skills/short-drama-develop/references/genre-cards//345/244/215/344/273/207/346/211/223/350/204/270.md +1 -1
  25. package/lib/drama/skills/short-drama-develop/references/genre-cards//347/263/273/347/273/237/346/265/201.md +51 -0
  26. package/lib/drama/skills/short-drama-develop/references/genre-cards//351/200/206/350/242/255.md +51 -0
  27. package/lib/drama/skills/short-drama-develop/references/genre-cards//351/207/215/347/224/237/347/251/277/350/266/212.md +51 -0
  28. package/lib/drama/skills/short-drama-develop/references/genre-cards.md +10 -7
  29. package/lib/drama/skills/short-drama-develop/references/premise-devices.md +15 -9
  30. package/lib/drama/skills/short-drama-develop/references/serial-character-and-memory.md +3 -2
  31. package/lib/drama/skills/short-drama-develop/references/stage-contract.md +14 -7
  32. package/lib/drama/skills/short-drama-develop/references/story-craft.md +7 -3
  33. package/lib/drama/skills/short-drama-edit/SKILL.md +65 -44
  34. package/lib/drama/skills/short-drama-edit/assets/remotion/README.md +49 -13
  35. package/lib/drama/skills/short-drama-edit/assets/remotion/package.json +4 -2
  36. package/lib/drama/skills/short-drama-edit/assets/remotion/src/Overlay.tsx +31 -0
  37. package/lib/drama/skills/short-drama-edit/assets/remotion/src/Root.tsx +5 -5
  38. package/lib/drama/skills/short-drama-edit/assets/remotion/src/Subtitles.tsx +68 -69
  39. package/lib/drama/skills/short-drama-edit/assets/remotion/src/font.ts +39 -29
  40. package/lib/drama/skills/short-drama-edit/assets/remotion/src/rules.mjs +188 -0
  41. package/lib/drama/skills/short-drama-edit/assets/remotion/src/schema.ts +26 -13
  42. package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/Card.tsx +72 -0
  43. package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/CornerChip.tsx +39 -0
  44. package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/ScreenText.tsx +36 -0
  45. package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/SystemPanel.tsx +44 -0
  46. package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/TaskPanel.tsx +100 -0
  47. package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/chrome.tsx +197 -0
  48. package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/tokens.ts +62 -0
  49. package/lib/drama/skills/short-drama-edit/assets/remotion/tsconfig.json +1 -0
  50. package/lib/drama/skills/short-drama-edit/assets//345/211/252/350/276/221/345/215/225.md +6 -4
  51. package/lib/drama/skills/short-drama-edit/references/cut-craft.md +26 -67
  52. package/lib/drama/skills/short-drama-edit/references/delivery-verify.md +31 -56
  53. package/lib/drama/skills/short-drama-edit/references/generated-footage.md +42 -78
  54. package/lib/drama/skills/short-drama-edit/references/sound-and-subtitles.md +44 -92
  55. package/lib/drama/skills/short-drama-edit/references/stage-contract.md +14 -16
  56. package/lib/drama/skills/short-drama-edit/scripts/edit_tool.py +1272 -125
  57. package/lib/drama/skills/short-drama-edit/scripts/selftest.py +113 -9
  58. package/lib/drama/skills/short-drama-image-prompts/SKILL.md +2 -0
  59. package/lib/drama/skills/short-drama-image-prompts/references/common-recipe.md +11 -0
  60. package/lib/drama/skills/short-drama-novel-analyze/SKILL.md +3 -3
  61. package/lib/drama/skills/short-drama-novel-analyze/assets/episode-candidate.example.jsonl +2 -2
  62. package/lib/drama/skills/short-drama-novel-analyze/references/adaptation-triage.md +8 -4
  63. package/lib/drama/skills/short-drama-novel-analyze/references/adaptation-value.md +10 -3
  64. package/lib/drama/skills/short-drama-novel-analyze/references/aggregation-and-entities.md +25 -1
  65. package/lib/drama/skills/short-drama-novel-analyze/references/stage-contract.md +1 -0
  66. package/lib/drama/skills/short-drama-produce/SKILL.md +5 -1
  67. package/lib/drama/skills/short-drama-produce/references/adapter-contract.md +14 -20
  68. package/lib/drama/skills/short-drama-produce/references/providers/minimax-h3-video.md +8 -26
  69. package/lib/drama/skills/short-drama-produce/references/providers/minimax-speech.md +41 -0
  70. package/lib/drama/skills/short-drama-produce/scripts/provider_adapters.py +142 -1
  71. package/lib/drama/skills/short-drama-review/SKILL.md +4 -5
  72. package/lib/drama/skills/short-drama-review/references/production-quality-gates.md +6 -19
  73. package/lib/drama/skills/short-drama-review/references/review-method.md +6 -1
  74. package/lib/drama/skills/short-drama-review/references/rubric-assets-prompts.md +11 -0
  75. package/lib/drama/skills/short-drama-review/references/rubric-story-script.md +77 -3
  76. package/lib/drama/skills/short-drama-review/references/rubric-visual-motion.md +24 -35
  77. package/lib/drama/skills/short-drama-review/references/stage-contract.md +3 -0
  78. package/lib/drama/skills/short-drama-storyboard/SKILL.md +23 -11
  79. package/lib/drama/skills/short-drama-storyboard/references/blocking-playbooks.md +1 -1
  80. package/lib/drama/skills/short-drama-storyboard/references/lighting-craft.md +39 -0
  81. package/lib/drama/skills/short-drama-storyboard/references/production-shot-grammar.md +2 -2
  82. package/lib/drama/skills/short-drama-storyboard/references/shot-craft.md +139 -34
  83. package/lib/drama/skills/short-drama-storyboard/references/stage-contract.md +5 -3
  84. package/lib/drama/skills/short-drama-video-prompts/SKILL.md +15 -12
  85. package/lib/drama/skills/short-drama-video-prompts/references/camera-audio-continuity.md +29 -0
  86. package/lib/drama/skills/short-drama-video-prompts/references/delivery-profile.md +4 -5
  87. package/lib/drama/skills/short-drama-video-prompts/references/generability.md +4 -2
  88. package/lib/drama/skills/short-drama-video-prompts/references/minimax-h3.md +52 -39
  89. package/lib/drama/skills/short-drama-video-prompts/references/motion-recipe.md +24 -21
  90. package/lib/drama/skills/short-drama-video-prompts/references/performance-action-timing.md +9 -23
  91. package/lib/drama/skills/short-drama-video-prompts/references/production-prompt-grammar.md +14 -26
  92. package/lib/drama/skills/short-drama-video-prompts/references/review-and-fixtures.md +1 -1
  93. package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.0.md +2 -3
  94. package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.5.md +34 -9
  95. package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +3 -2
  96. package/lib/drama/skills/short-drama-video-prompts/references/target-model-profile.md +8 -1
  97. package/lib/drama/skills/short-drama-video-prompts/references/wan-3.0.md +103 -0
  98. package/lib/drama/skills/short-drama-video-prompts/scripts/motion_timing_check.py +8 -7
  99. package/lib/drama/skills/short-drama-write/SKILL.md +10 -7
  100. package/lib/drama/skills/short-drama-write/references/dialogue-craft.md +1 -1
  101. package/lib/drama/skills/short-drama-write/references/script-craft.md +56 -3
  102. package/lib/drama/skills/short-drama-write/references/stage-contract.md +4 -0
  103. package/lib/drama/skills/short-drama-write/scripts/duration_estimate.py +48 -2
  104. package/lib/index.js +346 -98
  105. package/lib/index.js.map +4 -4
  106. package/lib/novel-to-game/README.md +299 -59
  107. package/lib/novel-to-game/README_ZH.md +299 -56
  108. package/lib/novel-to-game/VERSION +1 -1
  109. package/lib/novel-to-game/examples/jin-ping-mei/build/BUILD_BRIEF.md +3 -1
  110. package/lib/novel-to-game/examples/jin-ping-mei/build/app/RUN.md +11 -3
  111. package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/new-guofeng.css +397 -8
  112. package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/style.css +0 -31
  113. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/data.js +71 -73
  114. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/engine.js +78 -89
  115. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/main.js +37 -14
  116. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/text.js +5 -5
  117. package/lib/novel-to-game/examples/jin-ping-mei/build/app/package.json +2 -1
  118. package/lib/novel-to-game/examples/jin-ping-mei/qa/README.md +11 -16
  119. package/lib/novel-to-game/examples/jin-ping-mei/qa/verification.json +11 -11
  120. package/lib/novel-to-game/examples/jin-ping-mei/qa/verify_playable_model.mjs +23 -0
  121. package/lib/novel-to-game/manifest.json +77 -87
  122. package/lib/novel-to-game/skills/game-art-direction/SKILL.md +7 -12
  123. package/lib/novel-to-game/skills/game-art-direction/references/art-direction-method.md +27 -106
  124. package/lib/novel-to-game/skills/game-build/SKILL.md +13 -14
  125. package/lib/novel-to-game/skills/game-build/references/blender-asset-workflow.md +24 -0
  126. package/lib/novel-to-game/skills/game-build/references/build-brief-contract.md +45 -82
  127. package/lib/novel-to-game/skills/game-build/references/generative-media-pipeline.md +14 -45
  128. package/lib/novel-to-game/skills/game-build/references/playable-model-contract.md +30 -65
  129. package/lib/novel-to-game/skills/game-build/references/tts-production-contract.md +13 -27
  130. package/lib/novel-to-game/skills/game-concept/SKILL.md +13 -15
  131. package/lib/novel-to-game/skills/game-concept/references/concept-method.md +28 -75
  132. package/lib/novel-to-game/skills/game-qa/SKILL.md +6 -7
  133. package/lib/novel-to-game/skills/game-qa/references/test-design-method.md +9 -5
  134. package/lib/novel-to-game/skills/game-world-design/SKILL.md +12 -16
  135. package/lib/novel-to-game/skills/game-world-design/references/narrative-design-method.md +23 -72
  136. package/lib/novel-to-game/skills/game-world-design/references/numeric-design-method.md +14 -48
  137. package/lib/novel-to-game/skills/game-world-design/references/world-design-method.md +36 -103
  138. package/lib/novel-to-game/skills/novel-game-analyze/SKILL.md +4 -10
  139. package/lib/novel-to-game/skills/novel-game-analyze/references/gameability-protocol.md +4 -4
  140. package/lib/novel-to-game/skills/novel-to-game/SKILL.md +9 -21
  141. package/lib/novel-to-game/skills/novel-to-game/references/intake-method.md +5 -4
  142. package/lib/novel-to-game/skills/novel-to-game/references/pipeline-contract.md +5 -8
  143. package/lib/oh-story/manifest.json +607 -327
  144. package/lib/oh-story/roles/chapter-extractor.md +177 -237
  145. package/lib/oh-story/roles/character-designer.md +1 -2
  146. package/lib/oh-story/roles/consistency-checker.md +15 -13
  147. package/lib/oh-story/roles/narrative-writer.md +36 -38
  148. package/lib/oh-story/roles/story-architect.md +9 -61
  149. package/lib/oh-story/roles/story-explorer.md +20 -125
  150. package/lib/oh-story/roles/story-researcher.md +0 -1
  151. package/lib/oh-story/skills/story/SKILL.md +15 -9
  152. package/lib/oh-story/skills/story/VERSION +1 -1
  153. package/lib/oh-story/skills/story/references/author-memory-maintenance.md +75 -0
  154. package/lib/oh-story/skills/story/references/author-memory.md +46 -94
  155. package/lib/oh-story/skills/story/scripts/author_memory_commit.py +934 -170
  156. package/lib/oh-story/skills/story-cover/SKILL.md +10 -1
  157. package/lib/oh-story/skills/story-deslop/SKILL.md +59 -73
  158. package/lib/oh-story/skills/story-deslop/references/agent-calls.md +5 -0
  159. package/lib/oh-story/skills/story-deslop/references/anti-ai-writing.md +12 -11
  160. package/lib/oh-story/skills/story-deslop/references/author-memory-maintenance.md +75 -0
  161. package/lib/oh-story/skills/story-deslop/references/author-memory.md +46 -94
  162. package/lib/oh-story/skills/story-deslop/references/banned-words.md +2 -2
  163. package/lib/oh-story/skills/story-deslop/references/deslop-gates.md +22 -5
  164. package/lib/oh-story/skills/story-deslop/references/style-resolution.md +4 -4
  165. package/lib/oh-story/skills/story-deslop/scripts/author_memory_commit.py +934 -170
  166. package/lib/oh-story/skills/story-deslop/scripts/check-ai-patterns.js +155 -8
  167. package/lib/oh-story/skills/story-import/SKILL.md +64 -584
  168. package/lib/oh-story/skills/story-import/references/character-state-reverse.md +1 -1
  169. package/lib/oh-story/skills/story-import/references/deep-analysis.md +47 -0
  170. package/lib/oh-story/skills/story-import/references/format-and-structure.md +1 -1
  171. package/lib/oh-story/skills/story-import/references/import-report.md +64 -0
  172. package/lib/oh-story/skills/story-import/references/import-special-cases.md +34 -0
  173. package/lib/oh-story/skills/story-import/references/import-tracking.md +95 -0
  174. package/lib/oh-story/skills/story-import/references/length-routing.md +1 -1
  175. package/lib/oh-story/skills/story-import/references/outline-reverse-rules.md +79 -0
  176. package/lib/oh-story/skills/story-import/references/outline-reverse.md +24 -0
  177. package/lib/oh-story/skills/story-import/references/state-tracking.md +4 -69
  178. package/lib/oh-story/skills/story-import/references/structure-mapping-long.md +98 -92
  179. package/lib/oh-story/skills/story-import/references/structure-mapping-short.md +24 -12
  180. package/lib/oh-story/skills/story-import/references/tracking-initialization.md +1 -1
  181. package/lib/oh-story/skills/story-import/references/tracking-transaction.md +15 -11
  182. package/lib/oh-story/skills/story-import/scripts/build_outline_brief.py +332 -0
  183. package/lib/oh-story/skills/story-import/scripts/check-outline-contract.js +132 -27
  184. package/lib/oh-story/skills/story-import/scripts/tracking_commit.py +478 -15
  185. package/lib/oh-story/skills/story-import/scripts/wordcount_core.py +182 -23
  186. package/lib/oh-story/skills/story-long-analyze/SKILL.md +81 -270
  187. package/lib/oh-story/skills/story-long-analyze/references/author-facing.md +252 -0
  188. package/lib/oh-story/skills/story-long-analyze/references/deconstruction-notes.md +3 -3
  189. package/lib/oh-story/skills/story-long-analyze/references/final-checks.md +19 -0
  190. package/lib/oh-story/skills/story-long-analyze/references/index-rebuild.md +11 -0
  191. package/lib/oh-story/skills/story-long-analyze/references/inspiration-library.md +105 -0
  192. package/lib/oh-story/skills/story-long-analyze/references/pipeline-ops.md +138 -64
  193. package/lib/oh-story/skills/story-long-analyze/references/semantic-acceptance-fixtures.md +84 -0
  194. package/lib/oh-story/skills/story-long-analyze/references/stage1-golden-chapters.md +128 -0
  195. package/lib/oh-story/skills/story-long-analyze/references/stage2-extraction.md +229 -0
  196. package/lib/oh-story/skills/story-long-analyze/references/stage3-plot-rhythm.md +480 -0
  197. package/lib/oh-story/skills/story-long-analyze/references/stage4-characters-settings.md +195 -0
  198. package/lib/oh-story/skills/story-long-analyze/references/stage5-report.md +33 -0
  199. package/lib/oh-story/skills/story-long-analyze/references/style-profile-generator.md +55 -128
  200. package/lib/oh-story/skills/story-long-analyze/references/style-profile-protocol.md +6 -6
  201. package/lib/oh-story/skills/story-long-analyze/references/synthesis-inputs.md +39 -0
  202. package/lib/oh-story/skills/story-long-analyze/scripts/build_chapter_index.py +466 -0
  203. package/lib/oh-story/skills/story-long-analyze/scripts/inspect_existing_assets.py +702 -0
  204. package/lib/oh-story/skills/story-long-analyze/scripts/inspiration_index.py +864 -0
  205. package/lib/oh-story/skills/story-long-analyze/scripts/manage_analysis_run.py +1145 -0
  206. package/lib/oh-story/skills/story-long-analyze/scripts/render_relation_chart.py +425 -0
  207. package/lib/oh-story/skills/story-long-scan/SKILL.md +45 -194
  208. package/lib/oh-story/skills/story-long-scan/references/platform-ciweimao.md +19 -0
  209. package/lib/oh-story/skills/story-long-scan/references/platform-fanqie.md +45 -0
  210. package/lib/oh-story/skills/story-long-scan/references/platform-jjwxc.md +28 -0
  211. package/lib/oh-story/skills/story-long-scan/references/platform-qidian.md +35 -0
  212. package/lib/oh-story/skills/story-long-scan/references/platform-qimao.md +27 -0
  213. package/lib/oh-story/skills/story-long-scan/references/topic-decision.md +6 -2
  214. package/lib/oh-story/skills/story-long-write/SKILL.md +49 -81
  215. package/lib/oh-story/skills/story-long-write/references/agent-calls.md +47 -0
  216. package/lib/oh-story/skills/story-long-write/references/anti-ai-writing.md +12 -11
  217. package/lib/oh-story/skills/story-long-write/references/artifact-protocols.md +24 -202
  218. package/lib/oh-story/skills/story-long-write/references/author-memory-maintenance.md +75 -0
  219. package/lib/oh-story/skills/story-long-write/references/author-memory.md +46 -94
  220. package/lib/oh-story/skills/story-long-write/references/banned-words.md +2 -2
  221. package/lib/oh-story/skills/story-long-write/references/benchmark-recall.md +7 -11
  222. package/lib/oh-story/skills/story-long-write/references/character-relations.md +49 -1
  223. package/lib/oh-story/skills/story-long-write/references/cross-book-recall.md +26 -0
  224. package/lib/oh-story/skills/story-long-write/references/deslop-gates.md +171 -0
  225. package/lib/oh-story/skills/story-long-write/references/dialogue-mastery.md +4 -0
  226. package/lib/oh-story/skills/story-long-write/references/emotion-on-page.md +116 -0
  227. package/lib/oh-story/skills/story-long-write/references/emotional-arc-design.md +1 -114
  228. package/lib/oh-story/skills/story-long-write/references/emotional-methods.md +2 -2
  229. package/lib/oh-story/skills/story-long-write/references/genre-prose-cards.md +1 -1
  230. package/lib/oh-story/skills/story-long-write/references/long-chapter-quality.md +7 -15
  231. package/lib/oh-story/skills/story-long-write/references/long-format.md +0 -8
  232. package/lib/oh-story/skills/story-long-write/references/long-genre-catalog.md +1 -1
  233. package/lib/oh-story/skills/story-long-write/references/long-genre-mechanics.md +3 -3
  234. package/lib/oh-story/skills/story-long-write/references/opening-design.md +2 -2
  235. package/lib/oh-story/skills/story-long-write/references/outline-conflict.md +4 -4
  236. package/lib/oh-story/skills/story-long-write/references/outline-methods.md +7 -7
  237. package/lib/oh-story/skills/story-long-write/references/outline-rhythm.md +3 -3
  238. package/lib/oh-story/skills/story-long-write/references/outline-structure-theory.md +14 -69
  239. package/lib/oh-story/skills/story-long-write/references/plot-frameworks.md +1 -1
  240. package/lib/oh-story/skills/story-long-write/references/plot-special-topics.md +2 -2
  241. package/lib/oh-story/skills/story-long-write/references/project-files.md +19 -13
  242. package/lib/oh-story/skills/story-long-write/references/reader-contract-and-progression.md +13 -5
  243. package/lib/oh-story/skills/story-long-write/references/reference-index.md +5 -6
  244. package/lib/oh-story/skills/story-long-write/references/stop-and-fix.md +9 -0
  245. package/lib/oh-story/skills/story-long-write/references/style-combat-face.md +1 -58
  246. package/lib/oh-story/skills/story-long-write/references/style-genre-modules.md +1 -1
  247. package/lib/oh-story/skills/story-long-write/references/style-resolution.md +4 -4
  248. package/lib/oh-story/skills/story-long-write/references/tracking-initialization.md +1 -1
  249. package/lib/oh-story/skills/story-long-write/references/tracking-transaction.md +15 -11
  250. package/lib/oh-story/skills/story-long-write/references/workflow-chapter.md +81 -121
  251. package/lib/oh-story/skills/story-long-write/references/workflow-daily.md +41 -139
  252. package/lib/oh-story/skills/story-long-write/references/workflow-outline.md +157 -0
  253. package/lib/oh-story/skills/story-long-write/references/workflow-revision.md +57 -67
  254. package/lib/oh-story/skills/story-long-write/references/workflow-setup.md +112 -253
  255. package/lib/oh-story/skills/story-long-write/references/workflow-volume.md +142 -0
  256. package/lib/oh-story/skills/story-long-write/references/writer-prompt-fallback.md +6 -4
  257. package/lib/oh-story/skills/story-long-write/references/writing-craft.md +19 -65
  258. package/lib/oh-story/skills/story-long-write/scripts/author_memory_commit.py +934 -170
  259. package/lib/oh-story/skills/story-long-write/scripts/build_architect_brief.py +260 -0
  260. package/lib/oh-story/skills/story-long-write/scripts/build_writer_prompt.py +226 -25
  261. package/lib/oh-story/skills/story-long-write/scripts/check-ai-patterns.js +155 -8
  262. package/lib/oh-story/skills/story-long-write/scripts/check-outline-contract.js +132 -27
  263. package/lib/oh-story/skills/story-long-write/scripts/check-outline-copy.js +7 -2
  264. package/lib/oh-story/skills/story-long-write/scripts/outline_view.py +7 -4
  265. package/lib/oh-story/skills/story-long-write/scripts/storyctl.py +304 -46
  266. package/lib/oh-story/skills/story-long-write/scripts/tracking_commit.py +478 -15
  267. package/lib/oh-story/skills/story-long-write/scripts/wordcount_core.py +182 -23
  268. package/lib/oh-story/skills/story-review/SKILL.md +31 -302
  269. package/lib/oh-story/skills/story-review/references/agent-prompts.md +184 -0
  270. package/lib/oh-story/skills/story-review/references/anti-ai-writing.md +12 -11
  271. package/lib/oh-story/skills/story-review/references/author-memory-maintenance.md +75 -0
  272. package/lib/oh-story/skills/story-review/references/author-memory.md +46 -94
  273. package/lib/oh-story/skills/story-review/references/banned-words.md +2 -2
  274. package/lib/oh-story/skills/story-review/references/batch-review.md +19 -0
  275. package/lib/oh-story/skills/story-review/references/character-relations.md +49 -1
  276. package/lib/oh-story/skills/story-review/references/dialogue-mastery.md +4 -0
  277. package/lib/oh-story/skills/story-review/references/review-quality.md +6 -11
  278. package/lib/oh-story/skills/story-review/references/review-tracking.md +10 -0
  279. package/lib/oh-story/skills/story-review/references/solo.md +52 -0
  280. package/lib/oh-story/skills/story-review/references/style-resolution.md +4 -4
  281. package/lib/oh-story/skills/story-review/references/tracking-initialization.md +1 -1
  282. package/lib/oh-story/skills/story-review/references/tracking-transaction.md +15 -11
  283. package/lib/oh-story/skills/story-review/scripts/author_memory_commit.py +934 -170
  284. package/lib/oh-story/skills/story-review/scripts/check-ai-patterns.js +155 -8
  285. package/lib/oh-story/skills/story-review/scripts/tracking_commit.py +478 -15
  286. package/lib/oh-story/skills/story-review/scripts/wordcount_core.py +182 -23
  287. package/lib/oh-story/skills/story-setup/SKILL.md +71 -452
  288. package/lib/oh-story/skills/story-setup/references/agent-references/agent-quality.md +4 -4
  289. package/lib/oh-story/skills/story-setup/references/agent-references/anti-ai-writing.md +12 -11
  290. package/lib/oh-story/skills/story-setup/references/agent-references/banned-words.md +2 -2
  291. package/lib/oh-story/skills/story-setup/references/agent-references/benchmark-style-load.md +107 -0
  292. package/lib/oh-story/skills/story-setup/references/agent-references/character-relations.md +49 -1
  293. package/lib/oh-story/skills/story-setup/references/agent-references/deslop-gates.md +22 -5
  294. package/lib/oh-story/skills/story-setup/references/agent-references/dialogue-mastery.md +4 -0
  295. package/lib/oh-story/skills/story-setup/references/agent-references/emotion-on-page.md +116 -0
  296. package/lib/oh-story/skills/story-setup/references/agent-references/emotional-arc-design.md +1 -114
  297. package/lib/oh-story/skills/story-setup/references/agent-references/format-and-structure.md +1 -1
  298. package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards.md +1 -1
  299. package/lib/oh-story/skills/story-setup/references/agent-references/long-emotional-methods.md +2 -2
  300. package/lib/oh-story/skills/story-setup/references/agent-references/long-genre-catalog.md +1 -1
  301. package/lib/oh-story/skills/story-setup/references/agent-references/long-genre-mechanics.md +3 -3
  302. package/lib/oh-story/skills/story-setup/references/agent-references/long-quality.md +7 -5
  303. package/lib/oh-story/skills/story-setup/references/agent-references/opening-design.md +2 -2
  304. package/lib/oh-story/skills/story-setup/references/agent-references/outline-conflict.md +4 -4
  305. package/lib/oh-story/skills/story-setup/references/agent-references/outline-methods.md +7 -7
  306. package/lib/oh-story/skills/story-setup/references/agent-references/outline-rhythm.md +3 -3
  307. package/lib/oh-story/skills/story-setup/references/agent-references/short-emotional-methods.md +1 -1
  308. package/lib/oh-story/skills/story-setup/references/agent-references/short-genre-formulas.md +0 -15
  309. package/lib/oh-story/skills/story-setup/references/agent-references/short-reversal.md +1 -1
  310. package/lib/oh-story/skills/story-setup/references/agent-references/style-combat-face.md +1 -58
  311. package/lib/oh-story/skills/story-setup/references/agent-references/style-genre-modules.md +1 -1
  312. package/lib/oh-story/skills/story-setup/references/agent-references/style-resolution.md +4 -4
  313. package/lib/oh-story/skills/story-setup/references/agent-references/writing-craft.md +19 -65
  314. package/lib/oh-story/skills/story-setup/references/diagnostics.md +4 -4
  315. package/lib/oh-story/skills/story-short-analyze/SKILL.md +56 -110
  316. package/lib/oh-story/skills/story-short-analyze/references/analysis-character-relations.md +1 -1
  317. package/lib/oh-story/skills/story-short-analyze/references/analysis-method.md +42 -0
  318. package/lib/oh-story/skills/story-short-analyze/references/optional-modules.md +97 -0
  319. package/lib/oh-story/skills/story-short-analyze/references/output-contract.md +9 -47
  320. package/lib/oh-story/skills/story-short-analyze/references/quality-checklist.md +80 -0
  321. package/lib/oh-story/skills/story-short-analyze/references/source-story-quality.md +4 -4
  322. package/lib/oh-story/skills/story-short-analyze/references/stage2-3-structure-emotion.md +308 -0
  323. package/lib/oh-story/skills/story-short-analyze/references/stage4-6-reversal-summary.md +611 -0
  324. package/lib/oh-story/skills/story-short-scan/SKILL.md +35 -65
  325. package/lib/oh-story/skills/story-short-scan/references/manual-rank-input.md +36 -0
  326. package/lib/oh-story/skills/story-short-scan/references/platform-dianzhong.md +24 -0
  327. package/lib/oh-story/skills/story-short-scan/references/platform-heiyan.md +21 -0
  328. package/lib/oh-story/skills/story-short-scan/references/topic-match.md +38 -0
  329. package/lib/oh-story/skills/story-short-write/SKILL.md +23 -175
  330. package/lib/oh-story/skills/story-short-write/references/agent-calls.md +13 -0
  331. package/lib/oh-story/skills/story-short-write/references/author-memory-maintenance.md +75 -0
  332. package/lib/oh-story/skills/story-short-write/references/author-memory.md +46 -94
  333. package/lib/oh-story/skills/story-short-write/references/banned-words.md +2 -2
  334. package/lib/oh-story/skills/story-short-write/references/benchmark-recall.md +1 -21
  335. package/lib/oh-story/skills/story-short-write/references/dialogue-mastery.md +4 -0
  336. package/lib/oh-story/skills/story-short-write/references/emotional-methods.md +1 -1
  337. package/lib/oh-story/skills/story-short-write/references/genre-writing-formulas.md +0 -15
  338. package/lib/oh-story/skills/story-short-write/references/output-contract.md +9 -47
  339. package/lib/oh-story/skills/story-short-write/references/reference-index.md +17 -47
  340. package/lib/oh-story/skills/story-short-write/references/scene-craft.md +40 -0
  341. package/lib/oh-story/skills/story-short-write/references/short-craft.md +7 -43
  342. package/lib/oh-story/skills/story-short-write/references/short-format.md +3 -3
  343. package/lib/oh-story/skills/story-short-write/references/short-prose-quality.md +2 -1
  344. package/lib/oh-story/skills/story-short-write/references/short-reversal.md +1 -1
  345. package/lib/oh-story/skills/story-short-write/references/style-resolution.md +4 -4
  346. package/lib/oh-story/skills/story-short-write/references/submission-craft.md +1 -1
  347. package/lib/oh-story/skills/story-short-write/references/villain-and-reveal.md +5 -10
  348. package/lib/oh-story/skills/story-short-write/references/workflow-design.md +21 -13
  349. package/lib/oh-story/skills/story-short-write/references/workflow-draft.md +116 -0
  350. package/lib/oh-story/skills/story-short-write/references/workflow-revision.md +99 -0
  351. package/lib/oh-story/skills/story-short-write/references/writing-workflow.md +7 -119
  352. package/lib/oh-story/skills/story-short-write/scripts/author_memory_commit.py +934 -170
  353. package/lib/oh-story/skills/story-short-write/scripts/check-ai-patterns.js +155 -8
  354. package/lib/oh-story/skills/story-short-write/scripts/check-outline-copy.js +7 -2
  355. package/lib/types/client/drama-production-view.d.ts.map +1 -1
  356. package/lib/types/client/file-activity.d.ts +19 -1
  357. package/lib/types/client/file-activity.d.ts.map +1 -1
  358. package/lib/types/client/index.d.ts.map +1 -1
  359. package/lib/types/client/production-prompts.d.ts +7 -0
  360. package/lib/types/client/production-prompts.d.ts.map +1 -1
  361. package/lib/types/client/production-runtime.d.ts +16 -0
  362. package/lib/types/client/production-runtime.d.ts.map +1 -1
  363. package/lib/types/client/video-studio.d.ts.map +1 -1
  364. package/lib/types/drama-adapters.d.ts +5 -3
  365. package/lib/types/drama-adapters.d.ts.map +1 -1
  366. package/lib/types/native-hooks.d.ts +53 -1
  367. package/lib/types/native-hooks.d.ts.map +1 -1
  368. package/lib/types/role-identity.d.ts +17 -0
  369. package/lib/types/role-identity.d.ts.map +1 -0
  370. package/lib/types/role-tool.d.ts.map +1 -1
  371. package/lib/types/skill-provider.d.ts.map +1 -1
  372. package/lib/types/video-project.d.ts.map +1 -1
  373. package/lib/types/workspace-route.d.ts.map +1 -1
  374. package/lib/video-recap/CHANGELOG.md +60 -1
  375. package/lib/video-recap/README.en.md +348 -137
  376. package/lib/video-recap/README.md +340 -136
  377. package/lib/video-recap/manifest.json +406 -251
  378. package/lib/video-recap/skills/video-assemble/SKILL.md +30 -15
  379. package/lib/video-recap/skills/video-assemble/references/audio-modes.md +63 -0
  380. package/lib/video-recap/skills/video-assemble/references/explicit-audio-mix.md +75 -0
  381. package/lib/video-recap/skills/video-assemble/references/foreground-compose.md +118 -0
  382. package/lib/video-recap/skills/video-assemble/references/narration-adoption.md +103 -0
  383. package/lib/video-recap/skills/video-assemble/references/packaging.md +45 -0
  384. package/lib/video-recap/skills/video-assemble/references/pair-media.md +74 -0
  385. package/lib/video-recap/skills/video-assemble/references/source-score.md +147 -0
  386. package/lib/video-recap/skills/video-assemble/references/subtitle-track.md +202 -0
  387. package/lib/video-recap/skills/video-assemble/scripts/adoption/__init__.py +1 -0
  388. package/lib/video-recap/skills/video-assemble/scripts/adoption/audio_mix_binding.py +279 -0
  389. package/lib/video-recap/skills/video-assemble/scripts/adoption/frozen_audio.py +187 -0
  390. package/lib/video-recap/skills/video-assemble/scripts/adoption/narration_binding.py +323 -0
  391. package/lib/video-recap/skills/video-assemble/scripts/adoption/strict_inputs.py +109 -0
  392. package/lib/video-recap/skills/video-assemble/scripts/adoption/strict_publish.py +130 -0
  393. package/lib/video-recap/skills/video-assemble/scripts/artifacts.py +10 -46
  394. package/lib/video-recap/skills/video-assemble/scripts/assemble.py +378 -119
  395. package/lib/video-recap/skills/video-assemble/scripts/assemble_constants.py +29 -12
  396. package/lib/video-recap/skills/video-assemble/scripts/assembly_contract.py +95 -44
  397. package/lib/video-recap/skills/video-assemble/scripts/assembly_settings.py +75 -32
  398. package/lib/video-recap/skills/video-assemble/scripts/audio_mix.py +11 -11
  399. package/lib/video-recap/skills/video-assemble/scripts/compose_foreground.py +293 -0
  400. package/lib/video-recap/skills/video-assemble/scripts/export_jianying.py +71 -78
  401. package/lib/video-recap/skills/video-assemble/scripts/jianying/__init__.py +1 -0
  402. package/lib/video-recap/skills/video-assemble/scripts/{jianying_builders.py → jianying/builders.py} +39 -67
  403. package/lib/video-recap/skills/video-assemble/scripts/{jianying_model.py → jianying/model.py} +3 -11
  404. package/lib/video-recap/skills/video-assemble/scripts/{jianying_optional.py → jianying/optional.py} +1 -1
  405. package/lib/video-recap/skills/video-assemble/scripts/jianying/schema.py +53 -0
  406. package/lib/video-recap/skills/video-assemble/scripts/{jianying_templates.py → jianying/templates.py} +1 -1
  407. package/lib/video-recap/skills/video-assemble/scripts/{jianying_timeline_contract.py → jianying/timeline_contract.py} +34 -13
  408. package/lib/video-recap/skills/video-assemble/scripts/{jianying_writer.py → jianying/writer.py} +7 -17
  409. package/lib/video-recap/skills/video-assemble/scripts/lib.py +37 -4
  410. package/lib/video-recap/skills/video-assemble/scripts/media.py +12 -21
  411. package/lib/video-recap/skills/video-assemble/scripts/narration_audio.py +64 -34
  412. package/lib/video-recap/skills/video-assemble/scripts/packaging.py +122 -0
  413. package/lib/video-recap/skills/video-assemble/scripts/pair_media.py +216 -0
  414. package/lib/video-recap/skills/video-assemble/scripts/render_preflight.py +1 -3
  415. package/lib/video-recap/skills/video-assemble/scripts/source_score.py +469 -0
  416. package/lib/video-recap/skills/video-assemble/scripts/source_subtitles.py +25 -9
  417. package/lib/video-recap/skills/video-assemble/scripts/subtitles/__init__.py +1 -0
  418. package/lib/video-recap/skills/video-assemble/scripts/{subtitle_core.py → subtitles/core.py} +13 -6
  419. package/lib/video-recap/skills/video-assemble/scripts/{subtitle_render.py → subtitles/render.py} +5 -4
  420. package/lib/video-recap/skills/video-assemble/scripts/subtitles/track.py +324 -0
  421. package/lib/video-recap/skills/video-assemble/scripts/subtitles/track_binding.py +200 -0
  422. package/lib/video-recap/skills/video-assemble/scripts/timeline.py +30 -46
  423. package/lib/video-recap/skills/video-assemble/scripts/timeline_emit.py +91 -7
  424. package/lib/video-recap/skills/video-assemble/scripts/visual_render.py +22 -8
  425. package/lib/video-recap/skills/video-cut/SKILL.md +34 -16
  426. package/lib/video-recap/skills/video-cut/references/shot-review.md +50 -0
  427. package/lib/video-recap/skills/video-cut/scripts/cut.py +2 -28
  428. package/lib/video-recap/skills/video-cut/scripts/cut_cli.py +58 -62
  429. package/lib/video-recap/skills/video-cut/scripts/cut_contract.py +21 -106
  430. package/lib/video-recap/skills/video-cut/scripts/cut_render.py +14 -9
  431. package/lib/video-recap/skills/video-cut/scripts/lib.py +39 -0
  432. package/lib/video-recap/skills/video-cut/scripts/narration_mapping.py +2 -155
  433. package/lib/video-recap/skills/video-cut/scripts/narrative_selection.py +244 -0
  434. package/lib/video-recap/skills/video-cut/scripts/shot_review.py +357 -0
  435. package/lib/video-recap/skills/video-recap/SKILL.md +86 -42
  436. package/lib/video-recap/skills/video-recap/references/audio-routing.md +126 -0
  437. package/lib/video-recap/skills/video-recap/references/config-playbook.md +12 -8
  438. package/lib/video-recap/skills/video-recap/references/data-schema.md +44 -33
  439. package/lib/video-recap/skills/video-recap/references/resource-library.md +151 -0
  440. package/lib/video-recap/skills/video-recap/references/shift-left-qc-schema.md +1 -1
  441. package/lib/video-recap/skills/video-recap/scripts/doctor.py +123 -30
  442. package/lib/video-recap/skills/video-recap/scripts/final_qc.py +22 -75
  443. package/lib/video-recap/skills/video-recap/scripts/lib.py +3 -3
  444. package/lib/video-recap/skills/video-recap/scripts/library.py +509 -0
  445. package/lib/video-recap/skills/video-recap/scripts/materials.py +63 -91
  446. package/lib/video-recap/skills/video-recap/scripts/mimo_qc.py +8 -70
  447. package/lib/video-recap/skills/video-recap/scripts/project_binding.py +286 -0
  448. package/lib/video-recap/skills/video-recap/scripts/qc/__init__.py +1 -0
  449. package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_client.py → qc/mimo_client.py} +1 -1
  450. package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_evidence.py → qc/mimo_evidence.py} +33 -66
  451. package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_observations.py → qc/mimo_observations.py} +3 -11
  452. package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_payload.py → qc/mimo_payload.py} +4 -7
  453. package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_report.py → qc/mimo_report.py} +17 -28
  454. package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_runner.py → qc/mimo_runner.py} +2 -2
  455. package/lib/video-recap/skills/video-recap/scripts/qc_contract.py +0 -19
  456. package/lib/video-recap/skills/video-recap/scripts/recap_cli.py +119 -50
  457. package/lib/video-recap/skills/video-recap/scripts/recap_inspect.py +32 -114
  458. package/lib/video-recap/skills/video-recap/scripts/recap_review.py +9 -23
  459. package/lib/video-recap/skills/video-recap/scripts/recap_runner.py +387 -334
  460. package/lib/video-recap/skills/video-recap/scripts/recap_runtime.py +23 -23
  461. package/lib/video-recap/skills/video-recap/scripts/recap_source.py +278 -0
  462. package/lib/video-recap/skills/video-recap/scripts/recap_stage_qc.py +25 -12
  463. package/lib/video-recap/skills/video-recap/scripts/recap_timeline.py +59 -52
  464. package/lib/video-recap/skills/video-recap/scripts/resource_lock.py +162 -0
  465. package/lib/video-recap/skills/video-script/SKILL.md +16 -13
  466. package/lib/video-recap/skills/video-script/references/creative-editing-playbook.md +9 -5
  467. package/lib/video-recap/skills/video-script/references/promotional-copy.md +68 -0
  468. package/lib/video-recap/skills/video-script/references/research-guide.md +1 -1
  469. package/lib/video-recap/skills/video-script/scripts/evidence_bundle.py +24 -76
  470. package/lib/video-recap/skills/video-script/scripts/lib.py +10 -87
  471. package/lib/video-recap/skills/video-script/scripts/narration_lint.py +63 -39
  472. package/lib/video-recap/skills/video-script/scripts/review.py +0 -2
  473. package/lib/video-recap/skills/video-script/scripts/review_grounding.py +35 -59
  474. package/lib/video-recap/skills/video-script/scripts/review_response.py +66 -128
  475. package/lib/video-recap/skills/video-script/scripts/review_runner.py +12 -20
  476. package/lib/video-recap/skills/video-script/scripts/speech_ownership.py +4 -4
  477. package/lib/video-recap/skills/video-script/scripts/validate.py +53 -42
  478. package/lib/video-recap/skills/video-understanding/SKILL.md +6 -4
  479. package/lib/video-recap/skills/video-understanding/references/data-schema.md +50 -156
  480. package/lib/video-recap/skills/video-understanding/references/research-guide.md +4 -4
  481. package/lib/video-recap/skills/video-understanding/scripts/asr.py +85 -65
  482. package/lib/video-recap/skills/video-understanding/scripts/asr_timing_evidence.py +270 -0
  483. package/lib/video-recap/skills/video-understanding/scripts/brief.py +2 -5
  484. package/lib/video-recap/skills/video-understanding/scripts/briefing/__init__.py +1 -0
  485. package/lib/video-recap/skills/{video-script/scripts/agent_brief.py → video-understanding/scripts/briefing/builder.py} +38 -35
  486. package/lib/video-recap/skills/video-understanding/scripts/{brief_context.py → briefing/context.py} +4 -35
  487. package/lib/video-recap/skills/{video-script/scripts/brief_inputs.py → video-understanding/scripts/briefing/inputs.py} +9 -31
  488. package/lib/video-recap/skills/{video-script/scripts/brief_timeline.py → video-understanding/scripts/briefing/timeline.py} +5 -6
  489. package/lib/video-recap/skills/video-understanding/scripts/consolidate.py +65 -116
  490. package/lib/video-recap/skills/video-understanding/scripts/detect.py +31 -40
  491. package/lib/video-recap/skills/video-understanding/scripts/lib.py +30 -86
  492. package/lib/video-recap/skills/video-understanding/scripts/narration_lint.py +63 -39
  493. package/lib/video-recap/skills/video-understanding/scripts/speech_ownership.py +4 -4
  494. package/lib/video-recap/skills/video-understanding/scripts/storyboard.py +17 -79
  495. package/lib/video-recap/skills/video-understanding/scripts/understanding_brief.py +14 -40
  496. package/lib/video-recap/skills/video-understanding/scripts/understanding_cache.py +64 -46
  497. package/lib/video-recap/skills/video-understanding/scripts/understanding_runner.py +31 -11
  498. package/lib/video-recap/skills/video-understanding/scripts/understanding_storyboard.py +19 -14
  499. package/lib/video-recap/skills/video-understanding/scripts/vlm.py +80 -108
  500. package/lib/video-recap/skills/video-voiceover/SKILL.md +29 -19
  501. package/lib/video-recap/skills/video-voiceover/references/index-tts.md +31 -0
  502. package/lib/video-recap/skills/video-voiceover/scripts/approved_text_policy.py +123 -0
  503. package/lib/video-recap/skills/video-voiceover/scripts/dub.py +51 -59
  504. package/lib/video-recap/skills/video-voiceover/scripts/lib.py +8 -44
  505. package/lib/video-recap/skills/video-voiceover/scripts/providers/__init__.py +1 -0
  506. package/lib/video-recap/skills/video-voiceover/scripts/providers/index_tts.py +184 -0
  507. package/lib/video-recap/skills/video-voiceover/scripts/voiceover.py +212 -134
  508. package/package.json +45 -45
  509. package/lib/novel-to-game/skills/game-world-design/references/dialogue-design-method.md +0 -58
  510. package/lib/novel-to-game/skills/game-world-design/references/game-writing-craft.md +0 -53
  511. package/lib/novel-to-game/skills/novel-to-game/references/intake-benchmark-reference.md +0 -38
  512. package/lib/oh-story/skills/story-long-analyze/references/material-decomposition.md +0 -530
  513. package/lib/oh-story/skills/story-long-analyze/references/output-templates.md +0 -559
  514. package/lib/oh-story/skills/story-long-scan/references/scan-output-format.md +0 -207
  515. package/lib/oh-story/skills/story-long-write/references/state-tracking.md +0 -108
  516. package/lib/oh-story/skills/story-short-analyze/references/material-decomposition.md +0 -678
  517. package/lib/oh-story/skills/story-short-analyze/references/output-templates.md +0 -561
  518. package/lib/video-recap/skills/video-assemble/scripts/jianying_schema.py +0 -98
  519. package/lib/video-recap/skills/video-recap/references/creative-editing-playbook.md +0 -225
  520. package/lib/video-recap/skills/video-recap/references/research-guide.md +0 -74
  521. package/lib/video-recap/skills/video-recap/references/timeline-and-jianying.md +0 -250
  522. package/lib/video-recap/skills/video-script/scripts/brief_context.py +0 -348
  523. package/lib/video-recap/skills/video-script/scripts/narration.py +0 -12
  524. package/lib/video-recap/skills/video-understanding/scripts/agent_brief.py +0 -399
  525. package/lib/video-recap/skills/video-understanding/scripts/brief_inputs.py +0 -290
  526. package/lib/video-recap/skills/video-understanding/scripts/brief_timeline.py +0 -327
  527. /package/lib/video-recap/skills/video-assemble/scripts/{jianying_tracks.py → jianying/tracks.py} +0 -0
  528. /package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_contract.py → qc/mimo_contract.py} +0 -0
  529. /package/lib/video-recap/skills/video-voiceover/scripts/{fish_audio.py → providers/fish_audio.py} +0 -0
@@ -4,7 +4,8 @@ import json
4
4
 
5
5
  from pathlib import Path
6
6
 
7
- from lib import CONFIG, log
7
+ from lib import CONFIG, log, load_background_research
8
+ from asr_timing_evidence import asr_evidence_summary_for_brief
8
9
 
9
10
 
10
11
  from detect import detect_speech_boundary_anchors
@@ -35,14 +36,8 @@ def _research_context(work_dir):
35
36
  and read scenes with plot knowledge instead of labelling everyone "黑衣男子".
36
37
  Returns "" when no usable research file is present, so behaviour is unchanged.
37
38
  """
38
- path = Path(work_dir) / "background_research.json"
39
- if not path.exists():
40
- return ""
41
- try:
42
- data = json.loads(path.read_text(encoding="utf-8"))
43
- except (json.JSONDecodeError, OSError):
44
- return ""
45
- if not isinstance(data, dict):
39
+ data = load_background_research(work_dir)
40
+ if not data:
46
41
  return ""
47
42
  parts = []
48
43
  for key in ("synopsis", "episode_context", "worldbuilding"):
@@ -124,38 +119,16 @@ def _load_understanding_artifacts_for_brief(work_dir):
124
119
  Material-library restores are allowed to reuse expensive analysis artifacts,
125
120
  but cut pass 2 must still rebuild `agent_narration_brief.md` against the
126
121
  rendered OUTPUT timeline. This helper deliberately performs no extraction,
127
- ASR, VLM, or external API calls; it only reads already-present JSON.
122
+ ASR, VLM, or external API calls; it only reads already-present JSON. An absent
123
+ artifact contributes [] (the brief documents the thin substrate); a corrupt one raises.
128
124
  """
129
125
  work_dir = Path(work_dir)
130
- scenes = []
131
- for name in ("vlm_analysis.json", "scenes.json"):
126
+
127
+ def _own(name):
132
128
  path = work_dir / name
133
- if not path.exists():
134
- continue
135
- try:
136
- data = _load_json(path)
137
- except (OSError, ValueError, TypeError):
138
- continue
139
- if isinstance(data, list):
140
- scenes = data
141
- break
142
- asr_result = []
143
- if (work_dir / "asr_result.json").exists():
144
- try:
145
- data = _load_json(work_dir / "asr_result.json")
146
- except (OSError, ValueError, TypeError):
147
- data = []
148
- if isinstance(data, list):
149
- asr_result = data
150
- silence_periods = []
151
- if (work_dir / "silence_periods.json").exists():
152
- try:
153
- data = _load_json(work_dir / "silence_periods.json")
154
- except (OSError, ValueError, TypeError):
155
- data = []
156
- if isinstance(data, list):
157
- silence_periods = data
158
- return scenes, asr_result, silence_periods
129
+ return _load_json(path) if path.exists() else []
130
+
131
+ return _own("vlm_analysis.json"), _own("asr_result.json"), _own("silence_periods.json")
159
132
 
160
133
 
161
134
  def _write_brief_from_existing_artifacts(video, work_dir, args, video_duration):
@@ -166,7 +139,7 @@ def _write_brief_from_existing_artifacts(video, work_dir, args, video_duration):
166
139
  if not (Path(work_dir) / "speech_boundary_anchors.json").exists():
167
140
  detect_speech_boundary_anchors(work_dir, asr_result)
168
141
  overview_path = Path(work_dir) / "mimo_video_overview.json"
169
- if CONFIG.get("mimo_video_overview", False):
142
+ if CONFIG["mimo_video_overview"]:
170
143
  scenes = _merge_overview_into_scenes(scenes, overview_path)
171
144
 
172
145
  source_storyboard = None
@@ -193,8 +166,9 @@ def _write_brief_from_existing_artifacts(video, work_dir, args, video_duration):
193
166
  video_duration,
194
167
  work_dir,
195
168
  args.style,
196
- mimo_overview_enabled=CONFIG.get("mimo_video_overview", False),
169
+ mimo_overview_enabled=CONFIG["mimo_video_overview"],
197
170
  mimo_overview_video_path=video,
171
+ asr_evidence=asr_evidence_summary_for_brief(work_dir, video),
198
172
  )
199
173
  _prepend_storyboard_brief_header(
200
174
  brief_path, source_storyboard, edited_storyboard, cut_mode=cut_mode
@@ -1,13 +1,12 @@
1
1
  """Own understanding-stage cache keys, provenance, and statuses."""
2
2
 
3
- import hashlib
4
-
5
3
  import json
6
4
 
7
5
  from pathlib import Path
8
6
 
7
+ from asr_timing_evidence import EVIDENCE_FILENAME, validate_asr_timing_evidence
9
8
  from extract import FRAME_TIME_CONVENTION_VERSION
10
- from lib import CONFIG, log, file_fingerprint, load_prompt
9
+ from lib import CONFIG, log, file_identity, load_prompt
11
10
 
12
11
 
13
12
  from vlm import (
@@ -34,14 +33,23 @@ def _load_json(path):
34
33
  return json.loads(Path(path).read_text(encoding="utf-8"))
35
34
 
36
35
 
37
- def _artifact_fingerprint(path):
36
+ def _video_input(video_path):
37
+ """The source video as a cache input: resolved path plus {size, mtime_ns}, so two
38
+ different files written in the same timestamp tick never share a stage output."""
39
+ return {"path": str(Path(video_path).resolve()), **file_identity(video_path)}
40
+
41
+
42
+ def _artifact_identity(path):
43
+ """{size, mtime_ns} of an input artifact, or None when it does not exist."""
38
44
  path = Path(path)
39
- return file_fingerprint(path) if path.exists() else None
45
+ return file_identity(path) if path.exists() else None
40
46
 
41
47
 
42
48
  def _stage_cache_valid(artifact_path, expected_meta):
49
+ """A stage output is reusable when it exists, is non-empty, its sidecar equals the
50
+ expected inputs/settings dict, and the output itself is the one the sidecar recorded."""
43
51
  artifact_path = Path(artifact_path)
44
- if not artifact_path.exists():
52
+ if not artifact_path.exists() or artifact_path.stat().st_size == 0:
45
53
  return False
46
54
  meta_path = _artifact_meta_path(artifact_path)
47
55
  if not meta_path.exists():
@@ -50,18 +58,17 @@ def _stage_cache_valid(artifact_path, expected_meta):
50
58
  meta = _load_json(meta_path)
51
59
  except (OSError, ValueError, TypeError):
52
60
  return False
53
- recorded = meta.get("artifact_fingerprint") if isinstance(meta, dict) else None
54
- if not recorded or recorded != _artifact_fingerprint(artifact_path):
61
+ if not isinstance(meta, dict) or meta.get("artifact") != file_identity(artifact_path):
55
62
  return False
56
63
  expected = dict(expected_meta)
57
- expected["artifact_fingerprint"] = recorded
64
+ expected["artifact"] = meta["artifact"]
58
65
  return meta == expected
59
66
 
60
67
 
61
68
  def _write_stage_meta(artifact_path, meta):
62
69
  meta_path = _artifact_meta_path(artifact_path)
63
70
  payload = dict(meta)
64
- payload["artifact_fingerprint"] = _artifact_fingerprint(artifact_path)
71
+ payload["artifact"] = _artifact_identity(artifact_path)
65
72
  meta_path.write_text(
66
73
  json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8"
67
74
  )
@@ -93,7 +100,7 @@ def _write_mimo_overview_status(
93
100
  "mimo_video_overview.status.json",
94
101
  {
95
102
  "stage": "mimo_video_overview",
96
- "enabled": bool(CONFIG.get("mimo_video_overview", False))
103
+ "enabled": bool(CONFIG["mimo_video_overview"])
97
104
  if enabled is None
98
105
  else bool(enabled),
99
106
  "status": status,
@@ -116,23 +123,19 @@ def _merge_overview_into_scenes(scenes, overview_path):
116
123
  `frame_facts` is untouched, `assess_understanding_substrate` (which grades on frame_facts +
117
124
  ASR) cannot regress; richer descriptions can only help.
118
125
  """
119
- overview = _load_json(overview_path) if Path(overview_path).exists() else None
120
- if not isinstance(overview, dict):
126
+ if not Path(overview_path).exists():
121
127
  return scenes
128
+ overview = _load_json(overview_path)
122
129
  by_scene = {}
123
- for chunk in overview.get("chunks") or []:
124
- if not isinstance(chunk, dict):
125
- continue
126
- content = str(chunk.get("content", "")).strip()
127
- if content and _is_mimo_chunk_usable(content):
128
- by_scene.setdefault(chunk.get("scene_id"), []).append(content)
130
+ for chunk in overview["chunks"]:
131
+ content = chunk["content"].strip()
132
+ if _is_mimo_chunk_usable(content):
133
+ by_scene.setdefault(chunk["scene_id"], []).append(content)
129
134
  if not by_scene:
130
135
  return scenes
131
136
  enriched = 0
132
- for scene in scenes or []:
133
- if not isinstance(scene, dict):
134
- continue
135
- contents = by_scene.get(scene.get("scene_id"))
137
+ for scene in scenes:
138
+ contents = by_scene.get(scene["scene_id"])
136
139
  if not contents:
137
140
  continue
138
141
  scene.setdefault("frame_description", scene.get("description", ""))
@@ -184,7 +187,7 @@ def _scene_cache_payload(video_path):
184
187
  return {
185
188
  "schema_version": 1,
186
189
  "stage": "scenes",
187
- "source_video_fingerprint": file_fingerprint(video_path),
190
+ "inputs": {"video": _video_input(video_path)},
188
191
  "settings": {
189
192
  "scene_threshold": CONFIG.get("scene_threshold"),
190
193
  "scene_junk_filter": CONFIG.get("scene_junk_filter"),
@@ -200,7 +203,7 @@ def _asr_cache_payload(video_path, *, skip_asr=False):
200
203
  return {
201
204
  "schema_version": 1,
202
205
  "stage": "asr",
203
- "source_video_fingerprint": file_fingerprint(video_path),
206
+ "inputs": {"video": _video_input(video_path)},
204
207
  "settings": {
205
208
  "skip_asr": bool(skip_asr),
206
209
  "mimo_asr_api_key_present": bool(CONFIG.get("mimo_asr_api_key")),
@@ -213,12 +216,34 @@ def _asr_cache_payload(video_path, *, skip_asr=False):
213
216
  }
214
217
 
215
218
 
219
+ def _asr_cache_state(artifact_path, expected_meta, video_path):
220
+ """Classify an ASR cache without upgrading stale evidence into new authority."""
221
+ artifact_path = Path(artifact_path)
222
+ if not _stage_cache_valid(artifact_path, expected_meta):
223
+ return "MISS"
224
+ evidence_path = artifact_path.parent / EVIDENCE_FILENAME
225
+ if not evidence_path.exists():
226
+ return "LEGACY_UNVERIFIED"
227
+ if validate_asr_timing_evidence(evidence_path, video_path, artifact_path):
228
+ evidence = _load_json(evidence_path)
229
+ if evidence.get("status") == "LEGACY_UNVERIFIED":
230
+ return "LEGACY_UNVERIFIED"
231
+ # An all-empty transcription is an unexplained outcome, not proven silence; treating it
232
+ # as fresh would make one bad run a permanent cache hit.
233
+ if evidence.get("status") in {"UNAVAILABLE_NO_DURATION", "EMPTY_UNKNOWN"}:
234
+ return "MISS"
235
+ return "FRESH"
236
+ return "MISS"
237
+
238
+
216
239
  def _silence_cache_payload(video_path, asr_json):
217
240
  return {
218
241
  "schema_version": 1,
219
242
  "stage": "silence",
220
- "source_video_fingerprint": file_fingerprint(video_path),
221
- "asr_result_fingerprint": _artifact_fingerprint(asr_json),
243
+ "inputs": {
244
+ "video": _video_input(video_path),
245
+ "asr_result": _artifact_identity(asr_json),
246
+ },
222
247
  "asr_meta": _load_json(_artifact_meta_path(asr_json))
223
248
  if _artifact_meta_path(asr_json).exists()
224
249
  else None,
@@ -238,7 +263,8 @@ def _silence_cache_payload(video_path, asr_json):
238
263
  }
239
264
 
240
265
 
241
- def _vlm_prompt_fingerprint():
266
+ def _vlm_prompt_payload():
267
+ """The exact prompt/context text the VLM stage sends; compared by equality."""
242
268
  prompt = load_prompt("VLM_DEPTH_PROMPT")
243
269
  if not prompt:
244
270
  prompt = (
@@ -249,33 +275,28 @@ def _vlm_prompt_fingerprint():
249
275
  context = CONFIG.get("context_info", "")
250
276
  if context:
251
277
  prompt = f"已知信息:{context}\n\n{prompt}"
252
- return {
253
- "prompt_text_fingerprint": _text_fingerprint(prompt),
254
- "context_info_fingerprint": _text_fingerprint(context),
255
- }
256
-
257
-
258
- def _text_fingerprint(value):
259
- return hashlib.md5(str(value or "").encode("utf-8")).hexdigest()
278
+ return {"prompt_text": prompt, "context_info": context}
260
279
 
261
280
 
262
281
  def _vlm_cache_payload(video_path, work_dir, scenes_json, frames):
263
282
  return {
264
283
  "schema_version": 1,
265
284
  "stage": "vlm",
266
- "source_video_fingerprint": file_fingerprint(video_path),
267
- "scenes_fingerprint": _artifact_fingerprint(scenes_json),
285
+ "inputs": {
286
+ "video": _video_input(video_path),
287
+ "scenes": _artifact_identity(scenes_json),
288
+ "background_research": _artifact_identity(
289
+ Path(work_dir) / "background_research.json"
290
+ ),
291
+ },
268
292
  "frames": _frame_cache_payload(video_path, CONFIG.get("fps"), frames),
269
- "prompt": _vlm_prompt_fingerprint(),
293
+ "prompt": _vlm_prompt_payload(),
270
294
  "settings": {
271
295
  "fps": CONFIG.get("fps"),
272
296
  "vlm_model": CONFIG.get("vlm_model"),
273
297
  "api_url": CONFIG.get("api_url"),
274
298
  "mimo_disable_thinking": CONFIG.get("mimo_disable_thinking", True),
275
299
  "mimo_media_resolution": CONFIG.get("mimo_media_resolution"),
276
- "background_research_fingerprint": _artifact_fingerprint(
277
- Path(work_dir) / "background_research.json"
278
- ),
279
300
  },
280
301
  }
281
302
 
@@ -290,13 +311,10 @@ def _frame_cache_payload(video_path, fps, frames):
290
311
  # v2: frame number→time is (n-1)/fps, not n/fps. Bumping invalidates frames/VLM
291
312
  # artifacts produced under the old off-by-one so they are recomputed, not reused.
292
313
  "schema_version": FRAME_TIME_CONVENTION_VERSION,
293
- "source_video_fingerprint": file_fingerprint(video_path),
314
+ "inputs": {"video": _video_input(video_path)},
294
315
  "fps": float(fps),
295
316
  "frame_count": len(frames),
296
317
  "frames": frame_names,
297
- "frame_fingerprints": {
298
- name: file_fingerprint(frame) for name, frame in zip(frame_names, frames)
299
- },
300
318
  }
301
319
 
302
320
 
@@ -14,6 +14,7 @@ from extract import extract_frames
14
14
  from detect import detect_scenes, detect_silence_periods, detect_speech_boundary_anchors
15
15
 
16
16
  from asr import transcribe_audio
17
+ from asr_timing_evidence import write_asr_timing_evidence, asr_evidence_summary_for_brief
17
18
 
18
19
  from vlm import (
19
20
  analyze_scenes,
@@ -27,6 +28,7 @@ from brief import build_agent_brief, assess_understanding_substrate
27
28
  from understanding_brief import _research_context, _write_brief_from_existing_artifacts
28
29
  from understanding_cache import (
29
30
  _asr_cache_payload,
31
+ _asr_cache_state,
30
32
  _frames_cache_valid,
31
33
  _load_json,
32
34
  _merge_overview_into_scenes,
@@ -112,7 +114,6 @@ def main():
112
114
  CONFIG["target_duration"] = args.target_duration
113
115
  if args.mimo_video_overview:
114
116
  CONFIG["mimo_video_overview"] = True
115
- scene_threshold = CONFIG.get("scene_threshold")
116
117
 
117
118
  video_duration = get_video_duration(video)
118
119
  if CONFIG["fps"] <= 0:
@@ -145,21 +146,39 @@ def main():
145
146
  scenes = _load_json(scenes_json)
146
147
  log(f"跳过场景检测(已存在 {len(scenes)} 个场景)")
147
148
  else:
148
- scenes = detect_scenes(video, work_dir, scene_threshold)
149
+ scenes = detect_scenes(video, work_dir, CONFIG["scene_threshold"])
149
150
  _write_stage_meta(scenes_json, scenes_meta)
150
151
 
151
152
  # Step 3: ASR
152
153
  asr_meta = _asr_cache_payload(video, skip_asr=args.skip_asr)
154
+ cache_state = None
155
+ if not args.skip_asr and not args.force:
156
+ cache_state = _asr_cache_state(asr_json, asr_meta, video)
153
157
  if args.skip_asr:
154
158
  asr_result = []
155
159
  asr_json.write_text(
156
160
  json.dumps(asr_result, ensure_ascii=False, indent=2), encoding="utf-8"
157
161
  )
158
162
  _write_stage_meta(asr_json, asr_meta)
163
+ write_asr_timing_evidence(
164
+ work_dir, video, "EXPLICITLY_SKIPPED", final_segments=asr_result
165
+ )
159
166
  log("跳过 ASR(--skip-asr)")
160
- elif not args.force and _stage_cache_valid(asr_json, asr_meta):
167
+ elif cache_state in {
168
+ "FRESH",
169
+ "LEGACY_UNVERIFIED",
170
+ }:
161
171
  asr_result = _load_json(asr_json)
162
- log(f"跳过 ASR(已存在 {len(asr_result)} 段)")
172
+ if cache_state == "LEGACY_UNVERIFIED":
173
+ write_asr_timing_evidence(
174
+ work_dir,
175
+ video,
176
+ "LEGACY_UNVERIFIED",
177
+ final_segments=asr_result,
178
+ )
179
+ log(f"复用旧 ASR({len(asr_result)} 段;时间/声学证据未经验证)")
180
+ else:
181
+ log(f"跳过 ASR(证据匹配,已存在 {len(asr_result)} 段)")
163
182
  else:
164
183
  try:
165
184
  asr_result = transcribe_audio(video, work_dir)
@@ -188,13 +207,13 @@ def main():
188
207
  vlm_analysis = _load_json(vlm_json)
189
208
  log(f"跳过 VLM 分析(已存在 {len(vlm_analysis)} 个场景)")
190
209
  else:
191
- if not CONFIG.get("api_key"):
192
- key_name = CONFIG.get("api_key_source", "MIMO_API_KEY")
210
+ if not CONFIG["api_key"]:
211
+ key_name = CONFIG["api_env_var"]
193
212
  raise SystemExit(f"请设置 {key_name} 环境变量(VLM 画面分析需要)")
194
213
  log("VLM API 连通性预检...")
195
214
  api_call(
196
215
  {
197
- "model": CONFIG.get("vlm_model", ""),
216
+ "model": CONFIG["vlm_model"],
198
217
  "messages": [{"role": "user", "content": "hi"}],
199
218
  "max_tokens": 5,
200
219
  }
@@ -204,8 +223,8 @@ def main():
204
223
 
205
224
  # Step 4.1: optional MiMo scene-chunk video understanding
206
225
  overview_path = work_dir / "mimo_video_overview.json"
207
- if CONFIG.get("mimo_video_overview", False):
208
- if not CONFIG.get("mimo_video_api_key"):
226
+ if CONFIG["mimo_video_overview"]:
227
+ if not CONFIG["mimo_video_api_key"]:
209
228
  log("跳过 MiMo 分片视频概览:未设置 MIMO_API_KEY")
210
229
  overview_path.unlink(missing_ok=True)
211
230
  _write_mimo_overview_status(
@@ -227,7 +246,7 @@ def main():
227
246
  log(f"MiMo 分片视频概览失败(忽略): {e}")
228
247
  _write_mimo_overview_status(work_dir, "failed", e, None)
229
248
  else:
230
- if overview_path.exists() and overview:
249
+ if overview:
231
250
  _write_mimo_overview_status(
232
251
  work_dir, "ok", "MiMo 分片视频概览完成", overview_path.name
233
252
  )
@@ -341,8 +360,9 @@ def main():
341
360
  video_duration,
342
361
  work_dir,
343
362
  args.style,
344
- mimo_overview_enabled=CONFIG.get("mimo_video_overview", False),
363
+ mimo_overview_enabled=CONFIG["mimo_video_overview"],
345
364
  mimo_overview_video_path=video,
365
+ asr_evidence=asr_evidence_summary_for_brief(work_dir, video),
346
366
  )
347
367
  # C1: post-process the RETURNED brief FILE (not brief.py) so the brief⇄narration twin stays
348
368
  # byte-identical. Prepends a storyboard header pointing the agent at the sheet(s).
@@ -2,14 +2,15 @@
2
2
 
3
3
  from pathlib import Path
4
4
 
5
- from lib import CONFIG, log, file_fingerprint
5
+ from lib import CONFIG, log
6
6
 
7
7
 
8
8
  from storyboard import build_source_storyboard, build_edited_storyboard
9
9
 
10
10
 
11
11
  from understanding_cache import (
12
- _artifact_fingerprint,
12
+ _artifact_identity,
13
+ _video_input,
13
14
  _frames_manifest_path,
14
15
  _load_json,
15
16
  _stage_cache_valid,
@@ -19,8 +20,8 @@ from understanding_cache import (
19
20
 
20
21
  def _storyboard_sample_policy():
21
22
  return {
22
- "max_tiles": CONFIG.get("storyboard_max_tiles", 30),
23
- "columns": CONFIG.get("storyboard_columns", 6),
23
+ "max_tiles": CONFIG["storyboard_max_tiles"],
24
+ "columns": CONFIG["storyboard_columns"],
24
25
  }
25
26
 
26
27
 
@@ -31,9 +32,11 @@ def _edited_storyboard_meta(clip_plan_validated_json, frames_manifest_path):
31
32
  return {
32
33
  "schema_version": 1,
33
34
  "stage": "edited_storyboard",
34
- "clip_plan_validated_fp": _artifact_fingerprint(clip_plan_validated_json),
35
+ "inputs": {
36
+ "clip_plan_validated": _artifact_identity(clip_plan_validated_json),
37
+ "frames_manifest": _artifact_identity(frames_manifest_path),
38
+ },
35
39
  "fps": float(CONFIG.get("fps") or 0),
36
- "frames_manifest_fp": _artifact_fingerprint(frames_manifest_path),
37
40
  "sample_policy": _storyboard_sample_policy(),
38
41
  }
39
42
 
@@ -44,10 +47,10 @@ def _generate_source_storyboard(
44
47
  """Generate (or reuse cached) the source storyboard. Advisory: returns dict|None, never raises.
45
48
 
46
49
  Cached via _write_stage_meta/_stage_cache_valid on storyboard/source_storyboard.json; the
47
- meta includes fps + the frames-manifest fp so an fps-change resume rebuilds (Principle 5).
50
+ meta includes fps + the frames-manifest identity so an fps-change resume rebuilds (Principle 5).
48
51
  If frames/ is absent (cache hit skipped extraction / cleaned) → skip + log; pipeline continues.
49
52
  """
50
- if not CONFIG.get("storyboard", True):
53
+ if not CONFIG["storyboard"]:
51
54
  return None
52
55
  frames_dir = Path(work_dir) / "frames"
53
56
  if not frames_dir.is_dir() or not any(frames_dir.glob("frame_*.jpg")):
@@ -57,10 +60,12 @@ def _generate_source_storyboard(
57
60
  meta = {
58
61
  "schema_version": 1,
59
62
  "stage": "source_storyboard",
60
- "video_fp": file_fingerprint(video_path),
63
+ "inputs": {
64
+ "video": _video_input(video_path),
65
+ "scenes": _artifact_identity(scenes_json),
66
+ "frames_manifest": _artifact_identity(_frames_manifest_path(work_dir)),
67
+ },
61
68
  "fps": float(CONFIG.get("fps") or 0),
62
- "scenes_fp": _artifact_fingerprint(scenes_json),
63
- "frames_manifest_fp": _artifact_fingerprint(_frames_manifest_path(work_dir)),
64
69
  "sample_policy": _storyboard_sample_policy(),
65
70
  }
66
71
  if not force and _stage_cache_valid(json_path, meta):
@@ -73,7 +78,7 @@ def _generate_source_storyboard(
73
78
  else:
74
79
  log("storyboard 跳过 source(缓存匹配)")
75
80
  return cached
76
- result = build_source_storyboard(work_dir, video_path, scenes, CONFIG.get("fps"))
81
+ result = build_source_storyboard(work_dir, video_path, scenes, CONFIG["fps"])
77
82
  if result is not None and json_path.exists():
78
83
  _write_stage_meta(json_path, meta)
79
84
  return result
@@ -84,7 +89,7 @@ def _generate_edited_storyboard(work_dir, source_video_path, *, force=False):
84
89
  file-presence (NOT on edit_mode — recap.py forwards --edit-mode cut in BOTH passes, so the
85
90
  validated plan presence is the only reliable pass2 signal). Advisory: returns dict|None.
86
91
  """
87
- if not CONFIG.get("storyboard", True):
92
+ if not CONFIG["storyboard"]:
88
93
  return None
89
94
  clip_plan_validated_json = Path(work_dir) / "clip_plan_validated.json"
90
95
  if not clip_plan_validated_json.exists():
@@ -113,7 +118,7 @@ def _generate_edited_storyboard(work_dir, source_video_path, *, force=False):
113
118
  log("storyboard 跳过 edited:clip_plan_validated.json 无法解析")
114
119
  return None
115
120
  result = build_edited_storyboard(
116
- work_dir, source_video_path, clip_plan_validated, CONFIG.get("fps")
121
+ work_dir, source_video_path, clip_plan_validated, CONFIG["fps"]
117
122
  )
118
123
  if result is not None and json_path.exists():
119
124
  _write_stage_meta(json_path, meta)