@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
@@ -0,0 +1,332 @@
1
+ #!/usr/bin/env python3
2
+ """build_outline_brief.py — 拼出导入长篇「逐批反推细纲」的任务包。
3
+
4
+ 用法:
5
+ python build_outline_brief.py --project <书目录> --chapters A-B [--analysis <拆文库/导入书名>]
6
+
7
+ 导入按作者时间线分时刻(见 SKILL.md「时刻表与交接」)。细纲按批反推,负载按批计、不随全书章数增长。
8
+ 有 story-architect 时主会话只跑本脚本、把任务包路径交给它(它没有执行命令的权限),没有时主会话
9
+ 自己读包写本批。任务包写在书内 `.story/work/排纲/`,是这次任务的输入数据,不是 reference。
10
+
11
+ 包里只有本批需要的东西,执行者不再整读每章约 4K 字的摘要:
12
+ - 反推规则与细纲模板:references/outline-reverse-rules.md 全文;
13
+ - 本批每章:正文路径、按 visible_chars_v1 测好的历史长度(与写作时章节检查同一口径,
14
+ story-architect 不能自己跑测量),以及从拆文库摘要里抽出的、写细纲真正要用的字段
15
+ (关键事件、因果、局面结果、涉及、信息变化、状态变化、章尾钩子,情节点只取「标题|类型|基调」);
16
+ 拆文库没有摘要时改用 `.story/work/简化摘要/第NNN章.md`(超过 200 章的书,未深拆章节的简化摘要);
17
+ - 卷纲「剧情单元(反推)」表里与本批章节重叠的行(只按表头「章节范围」那一列判断重叠)。
18
+ 本书设定与作者已定的事不进包,执行者按规则定点读项目文件与 `.story/work/导入记录.md`。
19
+
20
+ 批大小按总量定:请求 10–20 章(全书最后一批可以更少);执行者要读的总量(任务包 + 没有摘要、
21
+ 只能读正文的章)超过约 25K 字时,从请求范围末尾往前少排几章(可少于 10 章,至少 1 章)。
22
+
23
+ stdout 输出一行 JSON:任务包路径、本批实际章节范围与下一批起点、执行者要读的总量 chars(去空白)、
24
+ 本批每章长度、没找到摘要的章。
25
+ Exit: 0 = 已写出;2 = 参数错误、正文或卷纲缺失、长度测不出。
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import argparse
31
+ import json
32
+ import re
33
+ import sys
34
+ from pathlib import Path
35
+
36
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
37
+ from wordcount_core import METRIC, WordcountError, find_chapter_file, measure_wordcount # noqa: E402
38
+
39
+ RULES = Path(__file__).resolve().parent.parent / "references" / "outline-reverse-rules.md"
40
+ WORK_DIR = (".story", "work", "排纲")
41
+ BRIEF_SUMMARY_DIR = (".story", "work", "简化摘要")
42
+ MIN_BATCH, MAX_BATCH = 10, 20
43
+ LOAD_LIMIT = 25000 # 执行者一次要读的量(去空白字数);再加上 agent 模板或 SKILL 入口仍在 35K 内
44
+ # 摘要里写细纲要用的字段(与 story-long-analyze 摘要投影同名);旧版摘要的同义标签放在别名里。
45
+ SUMMARY_FIELDS = (
46
+ ("关键事件", ()),
47
+ ("因果", ()),
48
+ ("局面结果", ()),
49
+ ("涉及", ("涉及人物", "出场人物")),
50
+ ("信息变化", ()),
51
+ ("状态变化", ()),
52
+ ("章尾钩子", ("卡点与伏笔",)),
53
+ )
54
+ FIELD_NAMES = "|".join(name for field in SUMMARY_FIELDS for name in (field[0], *field[1]))
55
+ # `**标签**:`(当前投影与旧版加粗写法)或不加粗的 `- 关键事件:`(只认上面这些字段名)。
56
+ LABEL_RE = re.compile(r"^\s*(?:[-*+]\s*)?(?:\*\*([^*]+?)\*\*|(%s))\s*[::((]" % FIELD_NAMES)
57
+ POINT_HEADER_RE = re.compile(r"^P(\d+)\s+\*\*(.+?)\*\*\s*[::]\s*(.+)$")
58
+ POINT_TAG_RE = re.compile(r"^主题标签\s*[::]?\s*[^||]*?\s*[||]\s*基调\s*[::]?\s*(.*?)\s*$")
59
+ # 「章节范围」单元格的一段:第X章—第Y章 / 第X-Y章 / 第X章 / 章X-Y / X-Y。
60
+ SPAN_CELL_RE = re.compile(
61
+ r"^\s*(?:第|章)?\s*(\d+)\s*章?\s*(?:(?:-|~|~|—|–|-|至|到)+\s*第?\s*(\d+)\s*章?)?\s*$"
62
+ )
63
+
64
+
65
+ def emit(text: str, stream) -> None:
66
+ """统一按 UTF-8 写出:Windows 控制台默认 GBK/ASCII 时直接 print 中文会崩。"""
67
+ stream.buffer.write((text + "\n").encode("utf-8"))
68
+ stream.flush()
69
+
70
+
71
+ def weight(text: str) -> int:
72
+ return len(re.sub(r"\s", "", text))
73
+
74
+
75
+ def parse_range(value: str) -> tuple[int, int]:
76
+ match = re.fullmatch(r"\s*(\d+)\s*(?:-\s*(\d+))?\s*", value or "")
77
+ if not match:
78
+ raise SystemExit("ERROR: --chapters 写成 A-B,如 1-20")
79
+ first = int(match.group(1))
80
+ last = int(match.group(2) or first)
81
+ if first < 1 or last < first:
82
+ raise SystemExit("ERROR: --chapters 范围无效")
83
+ return first, last
84
+
85
+
86
+ def last_body_chapter(project: Path) -> int:
87
+ numbers = [int(m.group(1)) for p in (project / "正文").glob("第*章*.md")
88
+ if "_原稿_" not in p.name and (m := re.match(r"^第0*(\d+)章", p.name))]
89
+ return max(numbers, default=0)
90
+
91
+
92
+ def check_batch_size(first: int, last: int, final: int) -> None:
93
+ size = last - first + 1
94
+ if size > MAX_BATCH:
95
+ raise SystemExit(f"ERROR: 一批细纲最多 {MAX_BATCH} 章,拆成两批")
96
+ # 只有全书最后一批可以不足 10 章(包太大时脚本自己少排几章不受此限)。
97
+ if size < MIN_BATCH and last < final:
98
+ raise SystemExit(f"ERROR: 一批细纲至少 {MIN_BATCH} 章(全书最后一批除外),把范围扩到第{first}-{min(final, first + MIN_BATCH - 1)}章")
99
+
100
+
101
+ def shown_path(path: Path, base: Path) -> str:
102
+ """项目根下的路径写相对路径(story-architect 从项目根解析),在外面的写绝对路径。"""
103
+ try:
104
+ return path.resolve().relative_to(base.resolve()).as_posix()
105
+ except ValueError:
106
+ return str(path)
107
+
108
+
109
+ def measure(project: Path, chapter: int) -> tuple[Path, str, int]:
110
+ try:
111
+ body = find_chapter_file(project / "正文", chapter, outline=False)
112
+ text = body.read_bytes().decode("utf-8")
113
+ except (WordcountError, OSError, UnicodeError) as exc:
114
+ raise SystemExit(f"ERROR: 第{chapter}章正文读不到({exc}),先完成正文迁移")
115
+ result = measure_wordcount(text, chapter=chapter)
116
+ if result["status"] != "measured":
117
+ raise SystemExit(f"ERROR: 第{chapter}章长度测不出({result['invalid_reason']})")
118
+ return body, text, result["actual"]
119
+
120
+
121
+ # ---------- 摘要字段抽取 ----------
122
+
123
+ def label_blocks(text: str) -> dict[str, str]:
124
+ """把摘要按 `**标签**:` 切块;情节点之后的内容另行解析,不进字段块。"""
125
+ blocks: dict[str, list[str]] = {}
126
+ current = None
127
+ for line in text.replace("\r\n", "\n").split("\n"):
128
+ stripped = line.strip()
129
+ if POINT_HEADER_RE.match(stripped) or stripped.startswith("#"):
130
+ current = None
131
+ continue
132
+ match = LABEL_RE.match(line)
133
+ if match:
134
+ current = (match.group(1) or match.group(2)).strip()
135
+ rest = re.split(r"[::]", line, maxsplit=1)
136
+ blocks.setdefault(current, []).append(rest[1] if len(rest) > 1 else "")
137
+ continue
138
+ if current is not None:
139
+ blocks[current].append(line)
140
+ return {name: "\n".join(lines).strip() for name, lines in blocks.items()}
141
+
142
+
143
+ def flatten(value: str) -> str:
144
+ """列表/表格压成一行:表格只取第一列(人物名),跳过表头与分隔行。"""
145
+ rows = [line.strip() for line in value.split("\n") if line.strip()]
146
+ if rows and all(row.startswith("|") for row in rows):
147
+ names = [row.strip("|").split("|")[0].strip() for row in rows[2:]]
148
+ return "、".join(name for name in names if name)
149
+ return " ".join(re.sub(r"^(?:\d+[.、]|[-*+])\s*", "", row) for row in rows)
150
+
151
+
152
+ def summary_points(text: str) -> list[str]:
153
+ lines = text.replace("\r\n", "\n").split("\n")
154
+ points = []
155
+ for index, line in enumerate(lines):
156
+ header = POINT_HEADER_RE.match(line.strip())
157
+ if not header:
158
+ continue
159
+ kind = re.split(r"[||]", header.group(3))[0].strip()
160
+ kind = kind[2:].lstrip(" ::") if kind.startswith("类型") else kind
161
+ tone = "—"
162
+ for follow in lines[index + 1:index + 12]:
163
+ if POINT_HEADER_RE.match(follow.strip()):
164
+ break
165
+ tag = POINT_TAG_RE.match(follow.strip())
166
+ if tag:
167
+ tone = tag.group(1) or "—"
168
+ break
169
+ points.append(f"P{header.group(1)} {header.group(2).strip()}|{kind}|{tone}")
170
+ return points
171
+
172
+
173
+ def summary_lines(text: str) -> list[str]:
174
+ blocks = label_blocks(text)
175
+ out = []
176
+ for name, aliases in SUMMARY_FIELDS:
177
+ raw = next((blocks[key] for key in (name, *aliases) if blocks.get(key)), "")
178
+ out.append(f"- {name}:{flatten(raw) or '(摘要未写)'}")
179
+ points = summary_points(text)
180
+ out.append("- 情节点(标题|类型|基调):" + (";".join(points) if points else "(摘要里没有可读的情节点)"))
181
+ return out
182
+
183
+
184
+ def chapter_block(project: Path, analysis: Path, chapter: int) -> tuple[str, int, int, bool]:
185
+ """返回(本章块、历史长度、执行者还需另读的正文量、是否缺摘要)。"""
186
+ body, body_text, actual = measure(project, chapter)
187
+ head = [f"### 第{chapter}章", "",
188
+ f"- 正文:`{shown_path(body, project.parent)}`;字数目标 {actual}({METRIC})"]
189
+ summary = analysis / "章节" / f"第{chapter}章_摘要.md"
190
+ brief = project.joinpath(*BRIEF_SUMMARY_DIR) / f"第{chapter:03d}章.md"
191
+ if summary.is_file():
192
+ lines = [f"- 摘要要点(抽自 `{shown_path(summary, project.parent)}`):"] + [
193
+ " " + line for line in summary_lines(summary.read_text(encoding="utf-8").lstrip(""))]
194
+ return "\n".join(head + lines), actual, 0, False
195
+ if brief.is_file():
196
+ text = brief.read_text(encoding="utf-8").lstrip("").strip()
197
+ return "\n".join(head + ["- 简化摘要(未深拆章节):", "", text]), actual, 0, False
198
+ note = "- 摘要:未找到,读该章正文反推,证据不足处写 [待补充]"
199
+ return "\n".join(head + [note]), actual, weight(body_text), True
200
+
201
+
202
+ # ---------- 卷纲剧情单元 ----------
203
+
204
+ def parse_span_cell(cell: str) -> list[tuple[int, int]]:
205
+ """只解析「章节范围」这一格;认不出的写法返回空,不去别的列找数字。"""
206
+ spans = []
207
+ for part in re.split(r"[、,,;;/]", cell):
208
+ match = SPAN_CELL_RE.match(part)
209
+ if not match:
210
+ continue
211
+ start = int(match.group(1))
212
+ end = int(match.group(2) or start)
213
+ if start <= end:
214
+ spans.append((start, end))
215
+ return spans
216
+
217
+
218
+ def split_row(row: str) -> list[str]:
219
+ return [cell.strip() for cell in row.strip().strip("|").split("|")]
220
+
221
+
222
+ def unit_rows(project: Path, first: int, last: int) -> list[str]:
223
+ """从各卷纲的「剧情单元」表里取与本批章节重叠的行,连同表头。"""
224
+ volumes = sorted((project / "大纲").glob("卷纲_第*卷.md"))
225
+ if not volumes:
226
+ raise SystemExit("ERROR: 大纲/ 下没有卷纲,先在结构迁移时刻写定卷纲")
227
+ out: list[str] = []
228
+ for volume in volumes:
229
+ lines = volume.read_text(encoding="utf-8").splitlines()
230
+ start = next((i for i, line in enumerate(lines) if re.match(r"^#+\s*剧情单元", line)), None)
231
+ if start is None:
232
+ continue
233
+ table: list[str] = []
234
+ for line in lines[start + 1:]:
235
+ if line.lstrip().startswith("|"):
236
+ table.append(line)
237
+ elif table or line.strip():
238
+ break # 表格结束,或标题下先出现了非表格内容
239
+ if len(table) < 3:
240
+ continue
241
+ column = next((i for i, cell in enumerate(split_row(table[0])) if "章节范围" in cell), None)
242
+ if column is None:
243
+ continue
244
+ hits = []
245
+ for row in table[2:]:
246
+ cells = split_row(row)
247
+ spans = parse_span_cell(cells[column]) if column < len(cells) else []
248
+ if any(a <= last and b >= first for a, b in spans):
249
+ hits.append(row)
250
+ if hits:
251
+ out += [f"来源:`{project.name}/大纲/{volume.name}`", "", *table[:2], *hits, ""]
252
+ if not out:
253
+ raise SystemExit(f"ERROR: 卷纲「剧情单元」表里找不到覆盖第{first}-{last}章的行(表头要有「章节范围」列,写成「第X-Y章」),先补卷纲")
254
+ return out
255
+
256
+
257
+ # ---------- 拼包 ----------
258
+
259
+ def render(project: Path, first: int, last: int, blocks: list[str]) -> str:
260
+ head = (f"# 任务包:反推第{first}-{last}章细纲(导入)\n\n"
261
+ f"只交付 `{project.name}/大纲/细纲_第{first:03d}章.md` 到 `细纲_第{last:03d}章.md`,每章一个文件(已有的同名文件按本包重写覆盖);"
262
+ f"不改正文、卷纲和 `设定/`,不建 `追踪/`。证据用下方每章的摘要要点,不整读拆文库摘要;某个字段要点里没有、"
263
+ f"又必须写实际内容时,只回看该章正文的相关段落。作者已定的事在 `{project.name}/.story/work/导入记录.md`;"
264
+ "不要另读本包以外的写作技法文件。交付后只回:写了哪些文件、每章一句核心事件、"
265
+ "证据不足标了 [待补充] 的要点(没有写「无」)。\n\n"
266
+ "包里提到的检查由主会话在你交付后跑,你不执行命令;需要的测量结果已放进包里。")
267
+ parts = [head, f"\n## 本批章节\n\n路径相对项目根(`{project.parent}`)。\n\n" + "\n\n".join(blocks),
268
+ "\n## 卷纲剧情单元(覆盖本批)\n\n" + "\n".join(unit_rows(project, first, last)).rstrip(),
269
+ "\n---\n\n<!-- 资料:outline-reverse-rules.md -->\n\n" + RULES.read_text(encoding="utf-8").lstrip("").strip()]
270
+ return "\n".join(parts) + "\n"
271
+
272
+
273
+ def build(project: Path, analysis: Path, first: int, last: int) -> dict:
274
+ if not RULES.is_file():
275
+ raise SystemExit(f"ERROR: 缺少 reference:{RULES}")
276
+ fixed = weight(render(project, first, last, [])) # 包头、剧情单元行与规则:章数减少只会更少
277
+ blocks: list[str] = []
278
+ lengths: dict[int, int] = {}
279
+ missing: list[int] = []
280
+ load, extra_reading = fixed, 0
281
+ for chapter in range(first, last + 1):
282
+ block, actual, extra, absent = chapter_block(project, analysis, chapter)
283
+ cost = weight(block) + extra
284
+ if blocks and load + cost > LOAD_LIMIT:
285
+ break # 包已够大:本章留给下一批
286
+ blocks.append(block)
287
+ lengths[chapter] = actual
288
+ load += cost
289
+ extra_reading += extra
290
+ if absent:
291
+ missing.append(chapter)
292
+ end = first + len(blocks) - 1
293
+ text = render(project, first, end, blocks)
294
+ return {"text": text, "end": end, "lengths": lengths, "missing": missing,
295
+ "chars": weight(text) + extra_reading}
296
+
297
+
298
+ def main(argv=None) -> int:
299
+ parser = argparse.ArgumentParser(description="拼出导入长篇逐批反推细纲的任务包")
300
+ parser.add_argument("--project", required=True, type=Path, help="书目录({导入书名}/)")
301
+ parser.add_argument("--chapters", required=True, help="章节范围 A-B,请求 10–20 章;包过大时自动少排")
302
+ parser.add_argument("--analysis", type=Path, help="拆文库目录,默认 书目录的上一级/拆文库/{书目录名}")
303
+ args = parser.parse_args(argv)
304
+ try:
305
+ project = args.project.resolve()
306
+ if not project.is_dir():
307
+ raise SystemExit(f"ERROR: 书目录不存在:{args.project}")
308
+ first, last = parse_range(args.chapters)
309
+ final = last_body_chapter(project)
310
+ if last > final:
311
+ raise SystemExit(f"ERROR: 正文只迁到第{final}章,范围超出")
312
+ check_batch_size(first, last, final)
313
+ analysis = (args.analysis or project.parent / "拆文库" / project.name).resolve()
314
+ result = build(project, analysis, first, last)
315
+ except SystemExit as exc:
316
+ emit(str(exc), sys.stderr)
317
+ return 2
318
+ end = result["end"]
319
+ out_dir = project.joinpath(*WORK_DIR)
320
+ out_dir.mkdir(parents=True, exist_ok=True)
321
+ out = out_dir / f"导入细纲_第{first:03d}-{end:03d}章.md"
322
+ out.write_text(result["text"], encoding="utf-8")
323
+ emit(json.dumps({"brief": str(out), "chapters": f"{first}-{end}",
324
+ "next": end + 1 if end < final else None, "chars": result["chars"], "limit": LOAD_LIMIT,
325
+ "metric": METRIC, "lengths": {str(k): v for k, v in result["lengths"].items()},
326
+ "missing_summaries": result["missing"]},
327
+ ensure_ascii=False), sys.stdout)
328
+ return 0
329
+
330
+
331
+ if __name__ == "__main__":
332
+ sys.exit(main())
@@ -18,11 +18,13 @@
18
18
  const fs = require('fs')
19
19
  const path = require('path')
20
20
 
21
- // 权威模板:references/workflow-setup.md「细纲(全书每章)」
21
+ // 权威模板:references/workflow-outline.md 的细纲模板
22
+ // 必填只留有证据或事故撑腰的核心字段;阶段位置、章节定位、结构公式、本章标价、闭环状态、
23
+ // 写手自由区、契约风险、镜头准入、信息差触发点与「分辨率」列是可选的阅读体验字段——
24
+ // 写了照样消费,没写不拦(#383 隔离实验:只补目标情绪与主角目标就复现了补满全部字段的收益)。
22
25
  const FIELDS = [
23
- '核心事件', '字数目标', '字数口径', '阶段位置', '单元ID/位置', '目标情绪',
24
- '主角目标/关键选择', '章节定位', '本章结构公式', '章首钩子', '爽点',
25
- '本章标价', '闭环状态', '本章禁止提前释放', '写手自由区', '契约风险',
26
+ '核心事件', '字数目标', '字数口径', '单元ID/位置', '目标情绪',
27
+ '主角目标/关键选择', '章首钩子', '爽点', '本章禁止提前释放',
26
28
  ]
27
29
  const SUBSECTIONS = ['内容概括', '情节安排', '人物关系和出场顺序', '情节细化']
28
30
  const FIVE_ACT = ['起因', '发展', '转折', '高潮', '结尾']
@@ -30,6 +32,69 @@ const PLOT_HEADER_FIRST = /^(?:#|序号)$/
30
32
  // 这两个字段实测直接影响正文质量,必须有实际内容
31
33
  const INTENT_FIELDS = ['目标情绪', '主角目标/关键选择']
32
34
  const CALIBER = 'visible_chars_v1'
35
+ // 可选字段「契约风险」只收三档;值未知可写 [待补充]。旧稿里的「风险等级」按同一字段认(旧名)。
36
+ const CONTRACT_RISK_LEVELS = ['契约安全', '需补强', '契约破坏']
37
+
38
+ // 「字数目标」「字数范围」「字数口径」的写法语法与 wordcount_core.py 逐字同构(scripts/test-storyctl.py 双跑同一批写法),
39
+ // 细纲验收通过的写法,storyctl chapter check 不能再拒。值里一个数字都没有的目标/范围行是说明文字,不参与取值。
40
+ const NUMBER = '([1-9][0-9]{0,2}(?:[,,][0-9]{3})+|[1-9][0-9]*)'
41
+ const NOTE = '(?:[((][^()()]*[))])?'
42
+ const TARGET_VALUE = new RegExp(`^(?:约|大约)?[ \\t]*${NUMBER}[ \\t]*字?(?:左右)?[ \\t]*${NOTE}$`)
43
+ const RANGE_VALUE = new RegExp(`^${NUMBER}[ \\t]*字?[ \\t]*(?:-|~|~|—|–|-|至|到)[ \\t]*${NUMBER}[ \\t]*字?[ \\t]*${NOTE}$`)
44
+ const METRIC_VALUE = new RegExp(`^([A-Za-z0-9_-]+)[ \\t]*${NOTE}$`)
45
+ const HAS_DIGIT = /[0-90-9]/
46
+
47
+ function fieldValues(text, label) {
48
+ const pattern = new RegExp(`^[ \\t>]*(?:[-*+][ \\t]*)?(?:\\*\\*)?${label}(?:\\*\\*)?[ \\t]*[::][ \\t]*(.*?)[ \\t]*$`, 'gm')
49
+ const values = []
50
+ let match
51
+ const normalized = text.replace(/\r\n?/g, '\n').replace(/^\uFEFF/, '')
52
+ while ((match = pattern.exec(normalized)) !== null) values.push(match[1].replace(/\*\*/g, '').trim())
53
+ return values
54
+ }
55
+
56
+ const numericFieldValues = (text, label) => fieldValues(text, label).filter((value) => HAS_DIGIT.test(value))
57
+ const toNumber = (raw) => Number(raw.replace(/[,,]/g, ''))
58
+
59
+ function parseWordcountTarget(text) {
60
+ const raw = numericFieldValues(text, '字数目标')
61
+ if (!raw.length) return { status: 'missing', value: null, raw }
62
+ const matches = raw.map((value) => value.match(TARGET_VALUE))
63
+ if (!matches.every(Boolean)) return { status: 'invalid', value: null, raw }
64
+ const values = [...new Set(matches.map((match) => toNumber(match[1])))]
65
+ if (values.length !== 1) return { status: 'conflict', value: null, raw }
66
+ return { status: 'ok', value: values[0], raw }
67
+ }
68
+
69
+ function parseWordcountRange(text) {
70
+ const raw = numericFieldValues(text, '字数范围')
71
+ if (!raw.length) return { status: 'missing', value: null, raw }
72
+ const matches = raw.map((value) => value.match(RANGE_VALUE))
73
+ if (!matches.every(Boolean)) return { status: 'invalid', value: null, raw }
74
+ const pairs = [...new Set(matches.map((match) => `${toNumber(match[1])}-${toNumber(match[2])}`))]
75
+ if (pairs.length !== 1) return { status: 'invalid', value: null, raw }
76
+ const [min, max] = pairs[0].split('-').map(Number)
77
+ if (min > max) return { status: 'invalid', value: null, raw }
78
+ return { status: 'ok', value: { min, max }, raw }
79
+ }
80
+
81
+ function parseWordcountCaliber(text) {
82
+ const raw = fieldValues(text, '字数口径')
83
+ const matches = raw.map((value) => value.match(METRIC_VALUE))
84
+ return raw.length > 0 && matches.every(Boolean) && new Set(matches.map((match) => match[1])).size === 1 && matches[0][1] === CALIBER
85
+ }
86
+
87
+ function parseContractRisk(text) {
88
+ let raw = fieldValues(text, '契约风险')
89
+ if (!raw.length) raw = fieldValues(text, '风险等级')
90
+ if (!raw.length) return null
91
+ const value = raw[raw.length - 1].replace(/`/g, '')
92
+ if (/^\[待补充\]$/.test(value)) return { status: 'unknown', level: null, detail: '', raw: value }
93
+ const level = CONTRACT_RISK_LEVELS.find((name) => value.startsWith(name))
94
+ if (!level) return { status: 'invalid', level: null, detail: '', raw: value }
95
+ const detail = value.slice(level.length).replace(/^[\s;;,,。::—\-((]+/, '').replace(/[))]$/, '').trim()
96
+ return { status: 'ok', level, detail, raw: value }
97
+ }
33
98
 
34
99
  function fieldPattern(name) {
35
100
  // 允许 -/*/+ 项目符号、可选 ** 加粗、全角或半角冒号
@@ -54,7 +119,7 @@ function makeCheck(id, ok, file, evidence, expected, repair, severity = 'blockin
54
119
  file,
55
120
  evidence,
56
121
  expected,
57
- references: ['references/workflow-setup.md', 'references/artifact-protocols.md'],
122
+ references: ['references/workflow-outline.md'],
58
123
  repair,
59
124
  }
60
125
  }
@@ -101,7 +166,7 @@ function checkSettingRefs(text, name, file, projectRoot) {
101
166
  name,
102
167
  missing.length ? `引用的路径不是可用文件:${missing.join('、')}` : `${refs.size} 处项目内引用全部存在`,
103
168
  '细纲引用的每个项目内 .md 文件都真实存在——不许把槽位指向查无实据的权威文件',
104
- '修正引用路径;或按「创作自主权分级」先把缺的设定落档(B 级直接补、C 级进《供给单》提案),再在细纲引用。'
169
+ '修正引用路径;或按新增物三级先把缺的设定落档(「写了要报」直接补并登记、「先问作者」进排纲底稿的供给自查提案),再在细纲引用。'
105
170
  )
106
171
  }
107
172
 
@@ -173,8 +238,8 @@ function verify(file, projectRoot = null) {
173
238
  let header = null
174
239
  for (const line of lines) {
175
240
  const cells = parseTableRow(line)
176
- // 四列是旧表(# / 情节点 / 功能标签 / 执行边界),五列是现行模板(中间多一列「分辨率」)。
177
- // 两种都收:功能标签固定在第 3 列,执行边界一律取最后一列,旧细纲不因加列而失效。
241
+ // 现行模板默认四列(# / 情节点 / 功能标签 / 执行边界(禁+放)),需要时在功能标签后加「分辨率」列成五列。
242
+ // 两种都收:功能标签固定在第 3 列,执行边界一律取最后一列。
178
243
  if (cells && (cells.length === 4 || cells.length === 5) && PLOT_HEADER_FIRST.test(cells[0])) {
179
244
  header = cells
180
245
  break
@@ -189,21 +254,21 @@ function verify(file, projectRoot = null) {
189
254
  headerOk,
190
255
  name,
191
256
  header ? `表头:${header.join(' | ')}` : '未找到 | # | 情节点 | 功能标签 | [分辨率] | 执行边界 | 表头',
192
- '情节细化使用五列表格:# / 情节点(谁做了什么) / 功能标签 / 分辨率 / 执行边界(四列旧表仍收,但新建细纲按五列模板走)',
193
- '只把情节点序列改成五列表格,逐点补功能标签、分辨率与执行边界;不增删情节点本身。'
257
+ '情节细化使用表格:# / 情节点(谁做了什么) / 功能标签 / 执行边界(禁+放);需要时可在功能标签后加「分辨率」列',
258
+ '只把情节点序列改成这张表,逐点补功能标签与执行边界;不增删情节点本身。'
194
259
  ))
195
260
 
196
- // 「放」半边:五列表的执行边界必须至少一个点解除限制(模板既有要求),
197
- // 全是禁令的情节点表实测会把整章压成同一个温度(015 章十一个点全「不许」)。
198
- if (headerOk && header.length === 5) {
261
+ // 「放」半边:五列表或表头写明「禁+放」的四列表,执行边界必须至少一个点解除限制,
262
+ // 全是禁令的情节点表实测会把整章压成同一个温度(015 章十一个点全「不许」)。表头没写「禁+放」的四列表不追溯。
263
+ if (headerOk && (header.length === 5 || /放/.test(header[header.length - 1]))) {
199
264
  const rows = []
200
265
  for (const line of lines) {
201
266
  const cells = parseTableRow(line)
202
- if (cells && cells.length === 5 && /^\d+$/.test(cells[0])) rows.push(cells)
267
+ if (cells && cells.length === header.length && /^\d+$/.test(cells[0])) rows.push(cells)
203
268
  }
204
269
  if (rows.length) {
205
270
  const released = rows.filter((cells) => {
206
- const match = cells[4].match(/(?:^|[。;;\s])放\s*[::]([^]*?)(?=(?:禁|放)\s*[::]|$)/)
271
+ const match = cells[cells.length - 1].match(/(?:^|[。;;\s])放\s*[::]([^]*?)(?=(?:禁|放)\s*[::]|$)/)
207
272
  if (!match) return false
208
273
  const value = match[1].replace(/[\s。;;,,、\[\]【】]/g, '')
209
274
  return value.length > 0 && !/^(?:无|暂无|待补充|待定|无缺口)$/.test(value)
@@ -249,22 +314,45 @@ function verify(file, projectRoot = null) {
249
314
 
250
315
  checks.push(checkSettingRefs(text, name, file, projectRoot))
251
316
 
252
- const targetMatch = text.match(/字数目标\s*[::]\s*(?:约\s*)?([\d,,]+)/)
253
- const target = targetMatch ? Number(targetMatch[1].replace(/[,,]/g, '')) : null
254
- const caliberOk = new RegExp(`字数口径\\s*[::]\\s*${CALIBER}`).test(text)
317
+ const targetParse = parseWordcountTarget(text)
318
+ const rangeParse = parseWordcountRange(text)
319
+ const target = targetParse.value
320
+ const caliberOk = parseWordcountCaliber(text)
321
+ const targetLabel = { ok: target, missing: '未识别', invalid: `写法认不出(${targetParse.raw.join('、')})`, conflict: `多个不同的值(${targetParse.raw.join('、')})` }[targetParse.status]
322
+ const rangeLabel = rangeParse.status === 'invalid' ? `;字数范围写法不对(${rangeParse.raw.join('、')})` : (rangeParse.value ? `;字数范围:${rangeParse.value.min}-${rangeParse.value.max}` : '')
255
323
  checks.push(makeCheck(
256
324
  'outline.wordcount-target',
257
- Boolean(target) && Number.isFinite(target) && target >= 500 && target <= 20000 && caliberOk,
325
+ targetParse.status === 'ok' && target >= 500 && target <= 20000 && caliberOk && rangeParse.status !== 'invalid',
258
326
  name,
259
- `字数目标:${target === null ? '未识别' : target};字数口径 ${CALIBER}:${caliberOk}`,
260
- `字数目标为 500-20000 的正整数,并声明 字数口径:${CALIBER}`,
261
- '只补字数目标或字数口径行,不调整情节安排。'
327
+ `字数目标:${targetLabel};字数口径 ${CALIBER}:${caliberOk}${rangeLabel}`,
328
+ `字数目标为 500-20000 的正整数(可写「2300 字」「约 2300」「2,300」,可带括号备注),并声明 字数口径:${CALIBER};作者给了上下限时另写一行「字数范围:2000-2600」`,
329
+ '只补字数目标、字数范围或字数口径行,不调整情节安排。'
262
330
  ))
263
331
 
264
- return report(file, checks)
332
+ const risk = parseContractRisk(text)
333
+ if (risk) {
334
+ checks.push(makeCheck(
335
+ 'outline.contract-risk',
336
+ risk.status !== 'invalid',
337
+ name,
338
+ risk.status === 'invalid' ? `契约风险写的是「${risk.raw}」` : `契约风险:${risk.level || '[待补充]'}`,
339
+ `契约风险只写 ${CONTRACT_RISK_LEVELS.join(' / ')} 三档之一(需补强时后面写补强方式),未定写 [待补充]`,
340
+ '只把契约风险改成三档之一,不改其他字段。'
341
+ ))
342
+ }
343
+
344
+ return report(file, checks, {
345
+ wordcount: {
346
+ target,
347
+ target_status: targetParse.status,
348
+ range: rangeParse.value,
349
+ range_status: rangeParse.status,
350
+ },
351
+ contract_risk: risk ? { level: risk.level, detail: risk.detail, status: risk.status } : null,
352
+ })
265
353
  }
266
354
 
267
- function report(file, checks) {
355
+ function report(file, checks, extra = {}) {
268
356
  const failures = checks.filter((check) => !check.ok && check.severity === 'blocking')
269
357
  const advisories = checks.filter((check) => !check.ok && check.severity === 'advisory')
270
358
  return {
@@ -272,6 +360,7 @@ function report(file, checks) {
272
360
  verifier: 'story-long-write.outline-contract',
273
361
  file: path.resolve(file),
274
362
  ok: failures.length === 0,
363
+ ...extra,
275
364
  checks,
276
365
  failures,
277
366
  advisories,
@@ -303,8 +392,24 @@ function resolveChapter(project, chapter) {
303
392
  return { file: path.join(dir, hit) }
304
393
  }
305
394
 
306
- // --supply:批末验证《供给单》已落卷纲——定位单元卡块,确认其中有「供给自查」小节。
395
+ // --supply:批末验证供给自查已落盘。新书写在卷纲旁的 排纲底稿_{单元ID}.md;老卷纲写在单元卡块内。
396
+ function hasSupplyHeading(text) {
397
+ return text.split(/\r?\n/).some((line) => {
398
+ const heading = line.replace(/\*\*/g, '').match(/^#{1,6}\s+(.+)$/)
399
+ return Boolean(heading) && /^供给自查(?:\s|[((]|$)/.test(heading[1])
400
+ })
401
+ }
402
+
307
403
  function verifySupply(volumeFile, unitId) {
404
+ const draftFile = path.join(path.dirname(volumeFile), `排纲底稿_${unitId}.md`)
405
+ const draft = readUtf8(draftFile)
406
+ if (draft.ok) {
407
+ const ok = hasSupplyHeading(draft.text)
408
+ return {
409
+ schema_version: 1, verifier: 'story-long-write.outline-supply', file: path.resolve(draftFile), unit: unitId, ok,
410
+ evidence: ok ? '排纲底稿含「供给自查」小节' : `${path.basename(draftFile)} 里没有「供给自查」小节——每批出细纲前须做供给自查(含「无缺口」情形),见 workflow-outline.md 步骤 3`,
411
+ }
412
+ }
308
413
  const read = readUtf8(volumeFile)
309
414
  if (!read.ok) {
310
415
  return { schema_version: 1, verifier: 'story-long-write.outline-supply', file: path.resolve(volumeFile), unit: unitId, ok: false, evidence: read.error || '卷纲文件为空' }
@@ -345,7 +450,7 @@ function verifySupply(volumeFile, unitId) {
345
450
  file: path.resolve(volumeFile),
346
451
  unit: unitId,
347
452
  ok,
348
- evidence: ok ? '单元卡含「供给自查」小节' : `剧情单元 ${unitId} 的卡内没有「供给自查」小节——每批出细纲前须产出《供给单》(含「无缺口」情形),见 workflow-setup.md「按剧情批出细纲」步骤 3`,
453
+ evidence: ok ? '单元卡含「供给自查」小节' : `没有 排纲底稿_${unitId}.md,剧情单元 ${unitId} 的卡内也没有「供给自查」小节——每批出细纲前须做供给自查(含「无缺口」情形),见 workflow-outline.md 步骤 3`,
349
454
  }
350
455
  }
351
456
 
@@ -412,4 +517,4 @@ function main(argv) {
412
517
 
413
518
  if (require.main === module) process.exitCode = main(process.argv.slice(2))
414
519
 
415
- module.exports = { verify, FIELDS, SUBSECTIONS, FIVE_ACT }
520
+ module.exports = { verify, parseWordcountTarget, parseWordcountRange, parseContractRisk, FIELDS, SUBSECTIONS, FIVE_ACT }