@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
@@ -1,290 +0,0 @@
1
- """Validate optional ASR, MiMo, and stage-status inputs for the brief."""
2
-
3
- import hashlib
4
- import json
5
- from pathlib import Path
6
-
7
- from lib import CONFIG, file_fingerprint, stable_hash
8
- from brief_context import _clean_asr_prompt_fingerprint, _consolidation_model
9
-
10
- # Shared with consolidate.py, which this byte-identical copy cannot import (the sibling
11
- # skill ships no consolidate.py). Keep both literals in sync.
12
- _ASR_SPAN_TOL = 0.05
13
-
14
- _MIMO_REJECTION_MARKERS = (
15
- "request was rejected",
16
- "considered high risk",
17
- "high risk",
18
- "content policy",
19
- "cannot process",
20
- "无法处理",
21
- "内容审核",
22
- "违规",
23
- )
24
-
25
-
26
- def _load_clean_asr(work_dir, asr_result):
27
- """Return consolidate.py's cleaned ASR segments, or None to fall back to raw asr_result.
28
-
29
- Accepted only when the file is at least as fresh as asr_result.json, its provenance
30
- (source_md5 / model / prompt_md5) matches, and every segment keeps its original span
31
- within _ASR_SPAN_TOL."""
32
- if not asr_result:
33
- return None
34
- work_dir = Path(work_dir)
35
- clean_path = work_dir / "asr_clean.json"
36
- src_path = work_dir / "asr_result.json"
37
- try:
38
- fresh = (
39
- clean_path.exists()
40
- and clean_path.stat().st_mtime >= src_path.stat().st_mtime
41
- )
42
- except OSError:
43
- return None
44
- if not fresh:
45
- return None
46
- try:
47
- payload = json.loads(clean_path.read_text(encoding="utf-8"))
48
- source_md5 = hashlib.md5(src_path.read_bytes()).hexdigest()
49
- except (OSError, json.JSONDecodeError):
50
- return None
51
- if not isinstance(payload, dict):
52
- return None
53
- provenance = {
54
- "source_md5": source_md5,
55
- "model": _consolidation_model(),
56
- "prompt_md5": _clean_asr_prompt_fingerprint(),
57
- }
58
- if not payload.items() >= provenance.items():
59
- return None
60
- segments = payload.get("segments")
61
- if not isinstance(segments, list) or len(segments) != len(asr_result):
62
- return None
63
- for orig, clean in zip(asr_result, segments):
64
- if (
65
- not isinstance(clean, dict)
66
- or not isinstance(clean.get("start"), (int, float))
67
- or not isinstance(clean.get("end"), (int, float))
68
- ):
69
- return None
70
- if (
71
- abs(clean["start"] - orig["start"]) > _ASR_SPAN_TOL
72
- or abs(clean["end"] - orig["end"]) > _ASR_SPAN_TOL
73
- ):
74
- return None
75
- return segments
76
-
77
-
78
- def _is_mimo_chunk_usable(content):
79
- """A chunk is usable only if MiMo returned real analysis (not empty / a moderation refusal)."""
80
- text = (content or "").strip()
81
- if not text:
82
- return False
83
- low = text.lower()
84
- return not any(marker in low for marker in _MIMO_REJECTION_MARKERS)
85
-
86
-
87
- def _mimo_video_settings_fingerprint():
88
- """Non-secret MiMo video-overview settings that affect generated content."""
89
- return {
90
- "model": CONFIG["mimo_video_model"],
91
- "mimo_video_api_url": CONFIG["mimo_video_api_url"],
92
- "mimo_video_fps": CONFIG["mimo_video_fps"],
93
- "mimo_media_resolution": CONFIG["mimo_media_resolution"],
94
- "mimo_video_chunk_max_seconds": CONFIG["mimo_video_chunk_max_seconds"],
95
- "mimo_video_chunk_min_seconds": CONFIG["mimo_video_chunk_min_seconds"],
96
- "mimo_video_base64_max_mb": CONFIG["mimo_video_base64_max_mb"],
97
- "mimo_video_prompt": CONFIG["mimo_video_prompt"],
98
- "mimo_disable_thinking": CONFIG["mimo_disable_thinking"],
99
- }
100
-
101
-
102
- def _mimo_chunk_cache_key(chunk):
103
- """Stable identifier for a MiMo chunk (index + scene span) for partial-cache reuse."""
104
- return f"{chunk['chunk_id']}|{chunk['scene_id']}|{chunk['start']:.3f}-{chunk['end']:.3f}"
105
-
106
-
107
- def _mimo_cached_chunks_fingerprint(done):
108
- return stable_hash(done)
109
-
110
-
111
- def _mimo_overview_payload_fingerprint(overview):
112
- payload = dict(overview)
113
- payload.pop("overview_fingerprint", None)
114
- return stable_hash(payload)
115
-
116
-
117
- def _mimo_video_chunks(scenes):
118
- """Split scene spans into MiMo video chunks. scenes.json rows carry no scene_id, so the
119
- row index stands in for it there."""
120
- max_seconds = CONFIG["mimo_video_chunk_max_seconds"]
121
- min_seconds = CONFIG["mimo_video_chunk_min_seconds"]
122
- chunks = []
123
- for scene_index, scene in enumerate(scenes):
124
- start, end = scene["start"], scene["end"]
125
- scene_id = scene.get("scene_id", scene_index)
126
- cursor = start
127
- while cursor < end:
128
- chunk_end = min(end, cursor + max_seconds)
129
- if end - chunk_end < min_seconds and chunk_end < end:
130
- chunk_end = end
131
- chunks.append(
132
- {
133
- "chunk_id": len(chunks),
134
- "scene_id": scene_id,
135
- "start": round(cursor, 3),
136
- "end": round(chunk_end, 3),
137
- }
138
- )
139
- cursor = chunk_end
140
- return chunks
141
-
142
-
143
- def _mimo_overview_matches_current_inputs(overview, scenes, video_path=None):
144
- """True only when mimo_video_overview.json was produced from the current settings,
145
- source video and scene plan, and none of its chunks was moderation-rejected.
146
- Provenance keys are read with .get: a stale or partial file simply does not match."""
147
- if not isinstance(overview, dict) or overview.get("input") != "scene_chunks":
148
- return False
149
- settings = _mimo_video_settings_fingerprint()
150
- expected_keys = [
151
- _mimo_chunk_cache_key(chunk) for chunk in _mimo_video_chunks(scenes)
152
- ]
153
- chunks = overview.get("chunks")
154
- if not isinstance(chunks, list) or not all(
155
- isinstance(chunk, dict)
156
- and isinstance(chunk.get("content"), str)
157
- and _is_mimo_chunk_usable(chunk["content"])
158
- for chunk in chunks
159
- ):
160
- return False
161
- if video_path is not None:
162
- try:
163
- if overview.get("source_video_fingerprint") != file_fingerprint(video_path):
164
- return False
165
- except OSError:
166
- return False
167
- try:
168
- cached_keys = [_mimo_chunk_cache_key(chunk) for chunk in chunks]
169
- except (KeyError, TypeError, ValueError):
170
- return False
171
- return (
172
- overview.get("settings") == settings
173
- and overview.get("overview_fingerprint")
174
- == _mimo_overview_payload_fingerprint(overview)
175
- and overview.get("chunks_fingerprint")
176
- == _mimo_cached_chunks_fingerprint(chunks)
177
- and cached_keys == expected_keys
178
- )
179
-
180
-
181
- def _load_mimo_overview_for_brief(work_dir, scenes, enabled=None, video_path=None):
182
- """The current MiMo overview for the brief, or None when disabled, absent or stale."""
183
- if not (CONFIG["mimo_video_overview"] if enabled is None else enabled):
184
- return None
185
- path = Path(work_dir) / "mimo_video_overview.json"
186
- if not path.exists():
187
- return None
188
- try:
189
- overview = json.loads(path.read_text(encoding="utf-8"))
190
- except (OSError, json.JSONDecodeError):
191
- return None
192
- if not _mimo_overview_matches_current_inputs(
193
- overview, scenes, video_path=video_path
194
- ):
195
- return None
196
- return overview
197
-
198
-
199
- def _load_optional_stage_status(work_dir, filename):
200
- """Optional-stage status sidecar, or None when the stage never ran."""
201
- path = Path(work_dir) / filename
202
- if not path.exists():
203
- return None
204
- try:
205
- status = json.loads(path.read_text(encoding="utf-8"))
206
- except (OSError, json.JSONDecodeError):
207
- return None
208
- if not (
209
- isinstance(status, dict)
210
- and isinstance(status.get("enabled"), bool)
211
- and isinstance(status.get("status"), str)
212
- and isinstance(status.get("message"), str)
213
- ):
214
- return None
215
- return status
216
-
217
-
218
- def _optional_stage_warning(stage, status, message):
219
- line = f"- {stage}: {status}"
220
- return f"{line} — {message[:180]}" if message else line
221
-
222
-
223
- def _format_optional_stage_warnings(
224
- work_dir,
225
- *,
226
- mimo_overview_enabled=None,
227
- mimo_overview=None,
228
- consolidation_index=None,
229
- ):
230
- """Surface fail-open optional-stage loss near the top of the brief."""
231
- work_dir = Path(work_dir)
232
- warnings = []
233
-
234
- overview_enabled = (
235
- CONFIG["mimo_video_overview"]
236
- if mimo_overview_enabled is None
237
- else mimo_overview_enabled
238
- )
239
- overview_status = _load_optional_stage_status(
240
- work_dir, "mimo_video_overview.status.json"
241
- )
242
- if (
243
- overview_status is not None
244
- and overview_status["enabled"]
245
- and overview_status["status"] in {"failed", "skipped_no_key"}
246
- ):
247
- warnings.append(
248
- _optional_stage_warning(
249
- "mimo_video_overview",
250
- overview_status["status"],
251
- overview_status["message"],
252
- )
253
- )
254
- elif overview_enabled and not mimo_overview:
255
- warnings.append(
256
- _optional_stage_warning(
257
- "mimo_video_overview",
258
- "missing_artifact",
259
- "enabled but no valid mimo_video_overview.json is available to this brief",
260
- )
261
- )
262
-
263
- consolidation_status = _load_optional_stage_status(
264
- work_dir, "consolidation.status.json"
265
- )
266
- if consolidation_status is not None and consolidation_status["enabled"]:
267
- if consolidation_status["status"] == "failed":
268
- warnings.append(
269
- _optional_stage_warning(
270
- "consolidation", "failed", consolidation_status["message"]
271
- )
272
- )
273
- elif consolidation_status.get("do_index") is True and not consolidation_index:
274
- warnings.append(
275
- _optional_stage_warning(
276
- "consolidation",
277
- "missing_index",
278
- "enabled but no valid understanding_index.json is available to this brief",
279
- )
280
- )
281
-
282
- if not warnings:
283
- return []
284
- return [
285
- "## Optional stage warnings",
286
- "",
287
- "These stages are fail-open; continue, but do not assume their missing context exists.",
288
- *warnings,
289
- "",
290
- ]
@@ -1,327 +0,0 @@
1
- """Remap cut evidence and format output-timeline brief directives."""
2
-
3
- import json
4
- import math
5
- import re
6
- from pathlib import Path
7
-
8
- from lib import CONFIG, stable_hash
9
-
10
-
11
- def _parse_target_seconds(value):
12
- """Parse a cut-mode target duration ("30m" / "600" / "1h5m" / "00:30:00") to seconds.
13
-
14
- None or blank means the knob is unset (None). Any other value that does not parse to
15
- a positive duration is a typo in user input and raises ValueError.
16
- """
17
- if value is None:
18
- return None
19
- if isinstance(value, (int, float)):
20
- seconds = float(value)
21
- else:
22
- text = str(value).strip().lower()
23
- if not text:
24
- return None
25
- if ":" in text:
26
- parts = [float(p) for p in text.split(":")]
27
- if len(parts) == 2:
28
- seconds = parts[0] * 60 + parts[1]
29
- elif len(parts) == 3:
30
- seconds = parts[0] * 3600 + parts[1] * 60 + parts[2]
31
- else:
32
- raise ValueError(f"unparseable target duration: {value!r}")
33
- if any(p < 0 for p in parts):
34
- raise ValueError(f"unparseable target duration: {value!r}")
35
- else:
36
- factors = {"ms": 0.001, "s": 1, "m": 60, "h": 3600}
37
- seconds = 0.0
38
- pos = 0
39
- for m in re.finditer(r"([0-9]+(?:\.[0-9]+)?)(ms|s|m|h)?", text):
40
- if m.start() != pos:
41
- break
42
- pos = m.end()
43
- seconds += float(m.group(1)) * factors[m.group(2) or "s"]
44
- if pos == 0 or pos != len(text):
45
- raise ValueError(f"unparseable target duration: {value!r}")
46
- if not seconds > 0:
47
- raise ValueError(f"target duration must be positive: {value!r}")
48
- return seconds
49
-
50
-
51
- def _format_research_directive(work_dir, substrate):
52
- """A loud, actionable research-first directive — but ONLY when the substrate is too thin
53
- for real commentary (no dialogue/story spine) and no background_research.json exists yet.
54
-
55
- The narration's quality ceiling is how much story context the agent has: with only frame
56
- descriptions it can only narrate pixels, so research the title FIRST (see
57
- references/research-guide.md). Fires only for thin/empty substrate — NOT merely because a
58
- title was given — so a dialogue-rich titled run is never nagged.
59
- """
60
- if (Path(work_dir) / "background_research.json").exists():
61
- return [] # already researched; _format_background_research surfaces it
62
- if substrate["level"] not in ("thin", "empty"):
63
- return [] # rich enough to write from dialogue/spine; do not nag
64
- context = CONFIG["context_info"].strip()
65
- return [
66
- "## ⚑ Research the story FIRST (do this before writing narration)",
67
- "",
68
- "Reason: the understanding substrate is thin — no dialogue/story spine, only frame",
69
- "descriptions, so without research the narration can only describe pixels.",
70
- "1. Pull the title/keywords from `--context`, the filename, or the user's description"
71
- + (f" (context: {context})." if context else "."),
72
- "2. Use any available web-search/browser tool to look up synopsis, characters, and",
73
- " relationships (see `references/research-guide.md`).",
74
- "3. Write `work_dir/background_research.json`, then re-read this brief and write narration",
75
- " that names people and reads the picture through the plot.",
76
- "4. If no tool/network or nothing found: skip — keep beats sparse and strictly grounded in",
77
- " the visible ASR/frame evidence rather than inventing drama.",
78
- "",
79
- ]
80
-
81
-
82
- def _load_cut_output_spans_for_brief(work_dir, *, required=False):
83
- """Load fresh source→output spans for cut pass 2 brief evidence.
84
-
85
- Pass 2 narration is authored against edited_source.mp4's OUTPUT timeline, so
86
- ASR chunks and timeline_fusion must use the same OUTPUT clock. Before pass 2
87
- (no edited_source.mp4 yet), callers may fall back to source-time evidence; once
88
- pass 2 exists, missing/stale validated spans are a hard contract failure.
89
- """
90
-
91
- def fail(reason):
92
- if required:
93
- raise SystemExit(
94
- "cut pass2 brief requires fresh clip_plan_validated.json with explicit "
95
- f"source/output spans ({reason})"
96
- )
97
- return None
98
-
99
- work_dir = Path(work_dir)
100
- if not (work_dir / "edited_source.mp4").exists():
101
- return None
102
- validated_path = work_dir / "clip_plan_validated.json"
103
- if not validated_path.exists():
104
- return fail("missing clip_plan_validated.json")
105
- plan = json.loads(validated_path.read_text(encoding="utf-8"))
106
- raw_path = work_dir / "clip_plan.json"
107
- if raw_path.exists() and plan["raw_plan_fingerprint"] != stable_hash(
108
- json.loads(raw_path.read_text(encoding="utf-8"))
109
- ):
110
- return fail("stale clip_plan_validated.json")
111
- spans = []
112
- for clip in plan["clips"]:
113
- span = {
114
- key: clip[key]
115
- for key in ("source_start", "source_end", "output_start", "output_end")
116
- }
117
- if not all(math.isfinite(value) for value in span.values()):
118
- return fail("non-finite clip span")
119
- if span["source_end"] <= span["source_start"] or span["output_end"] <= span["output_start"]:
120
- return fail("non-positive clip span")
121
- spans.append(span)
122
- return spans or fail("no clips")
123
-
124
-
125
- def _source_output_overlaps_for_brief(start, end, spans):
126
- overlaps = []
127
- for span in spans:
128
- source_start = max(start, span["source_start"])
129
- source_end = min(end, span["source_end"])
130
- if source_end <= source_start:
131
- continue
132
- output_start = span["output_start"] + (source_start - span["source_start"])
133
- output_end = span["output_start"] + (source_end - span["source_start"])
134
- overlaps.append(
135
- {
136
- "source_start": source_start,
137
- "source_end": source_end,
138
- "output_start": output_start,
139
- "output_end": output_end,
140
- }
141
- )
142
- return overlaps
143
-
144
-
145
- def _remap_frame_facts_for_brief(frame_facts, overlap):
146
- out = {}
147
- for raw_ts, vals in frame_facts.items():
148
- ts = float(raw_ts)
149
- if not (overlap["source_start"] <= ts <= overlap["source_end"]):
150
- continue
151
- out_ts = overlap["output_start"] + (ts - overlap["source_start"])
152
- out[f"{out_ts:.3f}"] = vals
153
- return out
154
-
155
-
156
- def _remap_scenes_to_output_for_brief(scenes, spans):
157
- out = []
158
- for scene in scenes:
159
- overlaps = _source_output_overlaps_for_brief(scene["start"], scene["end"], spans)
160
- for part_idx, overlap in enumerate(overlaps):
161
- item = dict(scene)
162
- item["start"] = round(overlap["output_start"], 3)
163
- item["end"] = round(overlap["output_end"], 3)
164
- item["frame_facts"] = _remap_frame_facts_for_brief(
165
- scene.get("frame_facts", {}), overlap
166
- )
167
- if len(overlaps) > 1:
168
- item["scene_id"] = f"{scene['scene_id']}.{part_idx}"
169
- out.append(item)
170
- out.sort(key=lambda x: (x["start"], x["end"]))
171
- return out
172
-
173
-
174
- def _remap_segments_to_output_for_brief(segments, spans):
175
- out = []
176
- for seg in segments:
177
- for overlap in _source_output_overlaps_for_brief(seg["start"], seg["end"], spans):
178
- item = dict(seg)
179
- item["start"] = round(overlap["output_start"], 3)
180
- item["end"] = round(overlap["output_end"], 3)
181
- if "duration" in item:
182
- item["duration"] = round(item["end"] - item["start"], 3)
183
- out.append(item)
184
- out.sort(key=lambda x: (x["start"], x["end"]))
185
- return out
186
-
187
-
188
- def _remap_brief_evidence_to_output_timeline(
189
- work_dir, scenes_analysis, asr_result, silence_periods, *, required=False
190
- ):
191
- spans = _load_cut_output_spans_for_brief(work_dir, required=required)
192
- if not spans:
193
- return scenes_analysis, asr_result, silence_periods
194
- return (
195
- _remap_scenes_to_output_for_brief(scenes_analysis, spans),
196
- _remap_segments_to_output_for_brief(asr_result, spans),
197
- _remap_segments_to_output_for_brief(silence_periods, spans),
198
- )
199
-
200
-
201
- def _read_json(path, default):
202
- """JSON artifact, or `default` when the optional file was never written."""
203
- return json.loads(path.read_text(encoding="utf-8")) if path.exists() else default
204
-
205
-
206
- def _sentence_entry_anchors_for_brief(work_dir, edit_mode):
207
- """Load sentence anchors and remap them to cut OUTPUT time when needed."""
208
- work_dir = Path(work_dir)
209
- anchors = [
210
- dict(item)
211
- for item in _read_json(
212
- work_dir / "speech_boundary_anchors.json", {"sentence_anchors": []}
213
- )["sentence_anchors"]
214
- ]
215
- if edit_mode != "cut" or not (work_dir / "edited_source.mp4").exists():
216
- return anchors
217
-
218
- spans = _load_cut_output_spans_for_brief(work_dir, required=True)
219
- remapped = []
220
- for anchor in anchors:
221
- source_time = anchor["time"]
222
- for span in spans:
223
- if span["source_start"] - 0.05 <= source_time <= span["source_end"] + 0.05:
224
- item = dict(anchor)
225
- item["source_time"] = round(source_time, 3)
226
- item["time"] = round(
227
- span["output_start"] + source_time - span["source_start"], 3
228
- )
229
- # Preserve the measured safe pause in OUTPUT time too, so cut-mode lint
230
- # compares one clock.
231
- source_pause_start = max(
232
- span["source_start"], min(anchor.get("pause_start", source_time - 0.12), source_time)
233
- )
234
- item["source_pause_start"] = round(source_pause_start, 3)
235
- item["pause_start"] = round(
236
- span["output_start"] + source_pause_start - span["source_start"], 3
237
- )
238
- remapped.append(item)
239
-
240
- speech_rows = [
241
- row for row in _read_json(work_dir / "asr_result.json", []) if row["text"]
242
- ]
243
- quiet_rows = [
244
- row
245
- for row in _read_json(work_dir / "silence_periods.json", [])
246
- if not row["has_speech"]
247
- ]
248
- out_payload = {
249
- "schema_version": 2,
250
- "artifact": "speech_boundary_anchors_output.json",
251
- "timeline": "cut_output",
252
- "source_artifact": "speech_boundary_anchors.json",
253
- "clip_plan_fingerprint": stable_hash(
254
- json.loads((work_dir / "clip_plan_validated.json").read_text(encoding="utf-8"))
255
- ),
256
- "sentence_anchors": sorted(remapped, key=lambda item: item["time"]),
257
- "speech_spans": _remap_segments_to_output_for_brief(speech_rows, spans),
258
- "quiet_windows": _remap_segments_to_output_for_brief(quiet_rows, spans),
259
- }
260
- (work_dir / "speech_boundary_anchors_output.json").write_text(
261
- json.dumps(out_payload, ensure_ascii=False, indent=2), encoding="utf-8"
262
- )
263
- return out_payload["sentence_anchors"]
264
-
265
-
266
- def _format_sentence_entry_anchors_for_brief(work_dir, edit_mode):
267
- anchors = [
268
- anchor
269
- for anchor in _sentence_entry_anchors_for_brief(work_dir, edit_mode)
270
- if anchor["confidence"] in {"high", "medium"}
271
- ]
272
- if not anchors:
273
- return []
274
- lines = [
275
- "## 原声句末安全切入点",
276
- "",
277
- "这些时间是 ASR 句末标点与短声学停顿对齐后的旁白安全入口。旁白在原声已开始后切入时,"
278
- "必须从其中一个点开始;否则会在 TTS 前被 `interrupts_source_sentence` 硬阻断。",
279
- "- 调整方式:优先把 `start` 移到建议锚点;放不下时缩短文本、移动整块或删除该旁白,不能让脚本静默挪音频。",
280
- '- 原声句子完整性是硬约束:切入块写 `"source_entry_policy": "sentence_boundary"`;'
281
- "不存在 `intentional_interrupt` 绕过方式。没有后续可靠句末锚点时,移动、缩短或删除旁白块。",
282
- ]
283
- for anchor in anchors:
284
- source_suffix = (
285
- f" (SOURCE {anchor['source_time']:.2f}s)" if "source_time" in anchor else ""
286
- )
287
- text_tail = str(anchor.get("text_tail", "")).strip()
288
- lines.append(
289
- f"- {anchor['time']:.2f}s [{anchor['confidence']}]{source_suffix} {text_tail}".rstrip()
290
- )
291
- lines.append("")
292
- return lines
293
-
294
-
295
- def _format_output_clip_list(work_dir):
296
- """List the kept clips on the OUTPUT timeline (cut-first/narrate-second pass 2), so the
297
- agent narrates against the real rendered cut instead of the source timeline."""
298
- path = Path(work_dir) / "clip_plan_validated.json"
299
- if not path.exists():
300
- return []
301
- plan = json.loads(path.read_text(encoding="utf-8"))
302
- out = ["## Kept clips on the OUTPUT timeline", ""]
303
- for c in plan["clips"]:
304
- reason = c.get("reason", "")
305
- out.append(
306
- f"- OUTPUT {c['output_start']:.1f}–{c['output_end']:.1f}s ← SOURCE[{c.get('source_id', '0')}] "
307
- f"{c['source_start']:.1f}–{c['source_end']:.1f}s (clip_id={c.get('clip_id', '?')})"
308
- + (f" — {reason}" if reason else "")
309
- )
310
- out.append("")
311
- return out if len(out) > 2 else []
312
-
313
-
314
- def _write_deslop_qc_requirements(work_dir):
315
- """Write the stable deslop QC contract consumed by deslop_qc.py.
316
-
317
- style_card_required defaults to False (advisory): a missing style_card.json is a
318
- warning, not a render-blocking error. A future opt-in run can set it True to make
319
- style_card.json a hard requirement — deslop_qc.py reads that field.
320
- """
321
- payload = {
322
- "schema_version": 1,
323
- "style_card_required": False,
324
- }
325
- path = Path(work_dir) / "deslop_qc_requirements.json"
326
- path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
327
- return path