@oh-story/dsh 0.1.3 → 0.1.5

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 (524) hide show
  1. package/README.md +58 -12
  2. package/lib/client.js +2970 -537
  3. package/lib/client.js.map +4 -4
  4. package/lib/drama/manifest.json +218 -178
  5. package/lib/drama/skills/short-drama/SKILL.md +110 -117
  6. package/lib/drama/skills/short-drama/references/audience-reveal.md +14 -67
  7. package/lib/drama/skills/short-drama/references/contract-and-ownership.md +26 -77
  8. package/lib/drama/skills/short-drama/references/creator-documents.md +204 -0
  9. package/lib/drama/skills/short-drama/references/creator-workflow.md +73 -63
  10. package/lib/drama/skills/short-drama/references/knowhow-index.md +5 -0
  11. package/lib/drama/skills/short-drama/references/look-development.md +2 -3
  12. package/lib/drama/skills/short-drama/references/pickup-and-alternate.md +14 -48
  13. package/lib/drama/skills/short-drama/references/production-form-profiles.md +1 -1
  14. package/lib/drama/skills/short-drama/references/reference-roles.md +32 -135
  15. package/lib/drama/skills/short-drama/references/runtime-preflight.md +16 -19
  16. package/lib/drama/skills/short-drama/scripts/creator_markdown_check.py +1002 -0
  17. package/lib/drama/skills/short-drama/scripts/project_tool.py +485 -5
  18. package/lib/drama/skills/short-drama-assets/SKILL.md +59 -170
  19. package/lib/drama/skills/short-drama-assets/references/asset-review-checklist.md +18 -25
  20. package/lib/drama/skills/short-drama-assets/references/character-and-look.md +13 -15
  21. package/lib/drama/skills/short-drama-assets/references/continuity-delta.md +11 -14
  22. package/lib/drama/skills/short-drama-assets/references/continuity-lock.md +116 -0
  23. package/lib/drama/skills/short-drama-assets/references/identity-vs-variant.md +6 -12
  24. package/lib/drama/skills/short-drama-assets/references/occurrence-extraction.md +8 -11
  25. package/lib/drama/skills/short-drama-assets/references/prop-and-state.md +21 -2
  26. package/lib/drama/skills/short-drama-assets/references/stage-contract.md +12 -105
  27. package/lib/drama/skills/short-drama-assets/references/voice-direction.md +12 -32
  28. package/lib/drama/skills/short-drama-assets/scripts/asset_check.py +1 -1
  29. package/lib/drama/skills/short-drama-image-prompts/SKILL.md +45 -155
  30. package/lib/drama/skills/short-drama-image-prompts/references/character-and-look.md +12 -13
  31. package/lib/drama/skills/short-drama-image-prompts/references/common-recipe.md +12 -13
  32. package/lib/drama/skills/short-drama-image-prompts/references/edit-and-revision.md +39 -51
  33. package/lib/drama/skills/short-drama-image-prompts/references/location-plate.md +3 -4
  34. package/lib/drama/skills/short-drama-image-prompts/references/look-and-state-variant.md +15 -14
  35. package/lib/drama/skills/short-drama-image-prompts/references/lookdev-frame.md +11 -15
  36. package/lib/drama/skills/short-drama-image-prompts/references/production-sheet-recipes.md +1 -1
  37. package/lib/drama/skills/short-drama-image-prompts/references/prop-plate.md +4 -7
  38. package/lib/drama/skills/short-drama-image-prompts/references/review-and-fixtures.md +23 -23
  39. package/lib/drama/skills/short-drama-image-prompts/references/stage-contract.md +8 -65
  40. package/lib/drama/skills/short-drama-image-prompts/scripts/image_prompt_check.py +8 -8
  41. package/lib/drama/skills/short-drama-image-prompts/scripts/selftest.py +4 -2
  42. package/lib/drama/skills/short-drama-produce/SKILL.md +67 -15
  43. package/lib/drama/skills/short-drama-produce/references/adapter-contract.md +65 -8
  44. package/lib/drama/skills/short-drama-produce/references/providers/minimax-h3-video.md +85 -0
  45. package/lib/drama/skills/short-drama-produce/references/providers/seedance.md +27 -10
  46. package/lib/drama/skills/short-drama-produce/scripts/production_tool.py +362 -3
  47. package/lib/drama/skills/short-drama-produce/scripts/provider_adapters.py +627 -40
  48. package/lib/drama/skills/short-drama-produce/scripts/selftest.py +5 -4
  49. package/lib/drama/skills/short-drama-review/SKILL.md +61 -123
  50. package/lib/drama/skills/short-drama-review/references/anti-template-repair.md +10 -15
  51. package/lib/drama/skills/short-drama-review/references/production-quality-gates.md +15 -16
  52. package/lib/drama/skills/short-drama-review/references/project-calibration.md +7 -9
  53. package/lib/drama/skills/short-drama-review/references/review-method.md +8 -9
  54. package/lib/drama/skills/short-drama-review/references/rubric-assets-prompts.md +9 -13
  55. package/lib/drama/skills/short-drama-review/references/rubric-story-script.md +104 -4
  56. package/lib/drama/skills/short-drama-review/references/rubric-visual-motion.md +27 -19
  57. package/lib/drama/skills/short-drama-review/references/stage-contract.md +4 -63
  58. package/lib/drama/skills/short-drama-review/scripts/review_check.py +1 -1
  59. package/lib/drama/skills/short-drama-storyboard/SKILL.md +116 -238
  60. package/lib/drama/skills/short-drama-storyboard/assets/shot-template.jsonl +1 -1
  61. package/lib/drama/skills/short-drama-storyboard/references/blocking-playbooks.md +9 -34
  62. package/lib/drama/skills/short-drama-storyboard/references/comic-keyframe-lexicon.md +156 -0
  63. package/lib/drama/skills/short-drama-storyboard/references/coverage-audition.md +5 -10
  64. package/lib/drama/skills/short-drama-storyboard/references/keyframe-craft.md +12 -7
  65. package/lib/drama/skills/short-drama-storyboard/references/production-shot-grammar.md +19 -4
  66. package/lib/drama/skills/short-drama-storyboard/references/review-and-fixtures.md +27 -62
  67. package/lib/drama/skills/short-drama-storyboard/references/scene-visual-plan.md +16 -25
  68. package/lib/drama/skills/short-drama-storyboard/references/screenplay-to-keyframe-example.md +21 -23
  69. package/lib/drama/skills/short-drama-storyboard/references/shot-craft.md +8 -10
  70. package/lib/drama/skills/short-drama-storyboard/references/shot-revision-identity.md +9 -13
  71. package/lib/drama/skills/short-drama-storyboard/references/stage-contract.md +16 -71
  72. package/lib/drama/skills/short-drama-storyboard/scripts/storyboard_check.py +1 -1
  73. package/lib/drama/skills/short-drama-video-prompts/SKILL.md +123 -230
  74. package/lib/drama/skills/short-drama-video-prompts/assets/motion-spec.jsonl.md +6 -1
  75. package/lib/drama/skills/short-drama-video-prompts/assets/video-prompts.md +17 -1
  76. package/lib/drama/skills/short-drama-video-prompts/references/camera-audio-continuity.md +10 -8
  77. package/lib/drama/skills/short-drama-video-prompts/references/delivery-profile.md +24 -6
  78. package/lib/drama/skills/short-drama-video-prompts/references/generability.md +2 -2
  79. package/lib/drama/skills/short-drama-video-prompts/references/minimax-h3.md +154 -0
  80. package/lib/drama/skills/short-drama-video-prompts/references/motion-recipe.md +35 -27
  81. package/lib/drama/skills/short-drama-video-prompts/references/performance-action-timing.md +8 -11
  82. package/lib/drama/skills/short-drama-video-prompts/references/production-prompt-grammar.md +13 -10
  83. package/lib/drama/skills/short-drama-video-prompts/references/review-and-fixtures.md +34 -63
  84. package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.0.md +41 -0
  85. package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.5.md +66 -0
  86. package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +17 -73
  87. package/lib/drama/skills/short-drama-video-prompts/references/target-model-profile.md +115 -0
  88. package/lib/drama/skills/short-drama-video-prompts/scripts/container_check.py +1 -1
  89. package/lib/drama/skills/short-drama-video-prompts/scripts/music_spec_check.py +1 -1
  90. package/lib/drama/skills/short-drama-write/SKILL.md +74 -268
  91. package/lib/drama/skills/short-drama-write/references/dialogue-craft.md +7 -0
  92. package/lib/drama/skills/short-drama-write/references/scene-handoff-capsule.md +17 -43
  93. package/lib/drama/skills/short-drama-write/references/screenplay-format.md +15 -15
  94. package/lib/drama/skills/short-drama-write/references/script-craft.md +208 -21
  95. package/lib/drama/skills/short-drama-write/references/stage-contract.md +11 -70
  96. package/lib/drama/skills/short-drama-write/scripts/duration_estimate.py +1 -1
  97. package/lib/drama/skills/short-drama-write/scripts/screenplay_index.py +2 -2
  98. package/lib/drama/skills/short-drama-write/scripts/voice_sheet_check.py +1 -1
  99. package/lib/index.js +971 -46
  100. package/lib/index.js.map +4 -4
  101. package/lib/novel-to-game/LICENSE +21 -0
  102. package/lib/novel-to-game/README.md +180 -0
  103. package/lib/novel-to-game/README_ZH.md +178 -0
  104. package/lib/novel-to-game/VERSION +1 -0
  105. package/lib/novel-to-game/examples/jin-ping-mei/build/BUILD_BRIEF.md +217 -0
  106. package/lib/novel-to-game/examples/jin-ping-mei/build/app/.vercelignore +3 -0
  107. package/lib/novel-to-game/examples/jin-ping-mei/build/app/RUN.md +130 -0
  108. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/compound_new_guofeng.webp +0 -0
  109. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/finale/fate_coda.webp +0 -0
  110. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/finale/meng.webp +0 -0
  111. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/finale/pan.webp +0 -0
  112. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/finale/pinger.webp +0 -0
  113. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/finale/xuee.webp +0 -0
  114. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/finale/yue.webp +0 -0
  115. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/inner_court_accord_five.webp +0 -0
  116. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/inner_court_afterglow_five.webp +0 -0
  117. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/inner_court_alliance.webp +0 -0
  118. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/public_day10.webp +0 -0
  119. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/public_day15.webp +0 -0
  120. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/public_day5.webp +0 -0
  121. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/title_new_guofeng.webp +0 -0
  122. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/joint/pan_pinger.webp +0 -0
  123. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/joint/pan_xuee.webp +0 -0
  124. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/joint/yue_meng.webp +0 -0
  125. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/joint/yue_pan.webp +0 -0
  126. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/joint/yue_pinger.webp +0 -0
  127. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/meng/explicit.webp +0 -0
  128. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/meng/prelude.webp +0 -0
  129. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/milestone/meng.webp +0 -0
  130. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/milestone/pan.webp +0 -0
  131. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/milestone/pinger.webp +0 -0
  132. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/milestone/xuee.webp +0 -0
  133. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/milestone/yue.webp +0 -0
  134. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/pan/explicit.webp +0 -0
  135. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/pan/prelude.webp +0 -0
  136. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/pinger/explicit.webp +0 -0
  137. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/pinger/prelude.webp +0 -0
  138. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/xuee/explicit.webp +0 -0
  139. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/xuee/prelude.webp +0 -0
  140. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/yue/explicit.webp +0 -0
  141. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/yue/prelude.webp +0 -0
  142. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/heroine/meng/night.webp +0 -0
  143. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/heroine/pan/night.webp +0 -0
  144. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/heroine/pinger/night.webp +0 -0
  145. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/heroine/xuee/night.webp +0 -0
  146. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/heroine/yue/night.webp +0 -0
  147. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/household/li_jiaoer.webp +0 -0
  148. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/scene/gate_collector.webp +0 -0
  149. package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/new-guofeng.css +1105 -0
  150. package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/style.css +2539 -0
  151. package/lib/novel-to-game/examples/jin-ping-mei/build/app/index.html +18 -0
  152. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/assets.js +147 -0
  153. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/audio.js +332 -0
  154. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/data.js +7472 -0
  155. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/engine.js +13077 -0
  156. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/main.js +3028 -0
  157. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/text.js +32 -0
  158. package/lib/novel-to-game/examples/jin-ping-mei/build/app/package.json +10 -0
  159. package/lib/novel-to-game/examples/jin-ping-mei/build/app/vercel.json +23 -0
  160. package/lib/novel-to-game/examples/jin-ping-mei/build/art/generated-art.json +161 -0
  161. package/lib/novel-to-game/examples/jin-ping-mei/example.json +12 -0
  162. package/lib/novel-to-game/examples/jin-ping-mei/qa/README.md +31 -0
  163. package/lib/novel-to-game/examples/jin-ping-mei/qa/playable-model.json +99 -0
  164. package/lib/novel-to-game/examples/jin-ping-mei/qa/verification.json +41 -0
  165. package/lib/novel-to-game/examples/jin-ping-mei/qa/verify_playable_model.mjs +129 -0
  166. package/lib/novel-to-game/manifest.json +508 -0
  167. package/lib/novel-to-game/skills/game-art-direction/SKILL.md +73 -0
  168. package/lib/novel-to-game/skills/game-art-direction/agents/openai.yaml +4 -0
  169. package/lib/novel-to-game/skills/game-art-direction/references/art-direction-method.md +119 -0
  170. package/lib/novel-to-game/skills/game-build/SKILL.md +84 -0
  171. package/lib/novel-to-game/skills/game-build/agents/openai.yaml +4 -0
  172. package/lib/novel-to-game/skills/game-build/references/build-brief-contract.md +109 -0
  173. package/lib/novel-to-game/skills/game-build/references/generative-media-pipeline.md +56 -0
  174. package/lib/novel-to-game/skills/game-build/references/playable-model-contract.md +81 -0
  175. package/lib/novel-to-game/skills/game-build/references/tts-production-contract.md +37 -0
  176. package/lib/novel-to-game/skills/game-concept/SKILL.md +72 -0
  177. package/lib/novel-to-game/skills/game-concept/agents/openai.yaml +4 -0
  178. package/lib/novel-to-game/skills/game-concept/references/concept-method.md +94 -0
  179. package/lib/novel-to-game/skills/game-qa/SKILL.md +50 -0
  180. package/lib/novel-to-game/skills/game-qa/agents/openai.yaml +4 -0
  181. package/lib/novel-to-game/skills/game-qa/references/qa-contract.md +66 -0
  182. package/lib/novel-to-game/skills/game-qa/references/test-design-method.md +45 -0
  183. package/lib/novel-to-game/skills/game-world-design/SKILL.md +63 -0
  184. package/lib/novel-to-game/skills/game-world-design/agents/openai.yaml +4 -0
  185. package/lib/novel-to-game/skills/game-world-design/references/dialogue-design-method.md +59 -0
  186. package/lib/novel-to-game/skills/game-world-design/references/game-writing-craft.md +53 -0
  187. package/lib/novel-to-game/skills/game-world-design/references/narrative-design-method.md +84 -0
  188. package/lib/novel-to-game/skills/game-world-design/references/numeric-design-method.md +56 -0
  189. package/lib/novel-to-game/skills/game-world-design/references/world-design-method.md +124 -0
  190. package/lib/novel-to-game/skills/novel-game-analyze/SKILL.md +77 -0
  191. package/lib/novel-to-game/skills/novel-game-analyze/agents/openai.yaml +4 -0
  192. package/lib/novel-to-game/skills/novel-game-analyze/references/gameability-protocol.md +65 -0
  193. package/lib/novel-to-game/skills/novel-to-game/SKILL.md +71 -0
  194. package/lib/novel-to-game/skills/novel-to-game/agents/openai.yaml +4 -0
  195. package/lib/novel-to-game/skills/novel-to-game/references/intake-benchmark-reference.md +42 -0
  196. package/lib/novel-to-game/skills/novel-to-game/references/intake-method.md +51 -0
  197. package/lib/novel-to-game/skills/novel-to-game/references/pipeline-contract.md +65 -0
  198. package/lib/oh-story/manifest.json +419 -309
  199. package/lib/oh-story/roles/character-designer.md +4 -4
  200. package/lib/oh-story/roles/consistency-checker.md +1 -1
  201. package/lib/oh-story/roles/narrative-writer.md +41 -42
  202. package/lib/oh-story/roles/story-architect.md +19 -23
  203. package/lib/oh-story/roles/story-explorer.md +8 -5
  204. package/lib/oh-story/skills/browser-cdp/SKILL.md +1 -1
  205. package/lib/oh-story/skills/story/SKILL.md +16 -9
  206. package/lib/oh-story/skills/story/VERSION +1 -1
  207. package/lib/oh-story/skills/story/references/author-memory.md +163 -0
  208. package/lib/oh-story/skills/story/scripts/author_memory_commit.py +871 -0
  209. package/lib/oh-story/skills/story-cover/SKILL.md +1 -1
  210. package/lib/oh-story/skills/story-deslop/SKILL.md +10 -5
  211. package/lib/oh-story/skills/story-deslop/references/anti-ai-writing.md +2 -1
  212. package/lib/oh-story/skills/story-deslop/references/author-memory.md +163 -0
  213. package/lib/oh-story/skills/story-deslop/references/banned-words.md +6 -4
  214. package/lib/oh-story/skills/story-deslop/scripts/author_memory_commit.py +871 -0
  215. package/lib/oh-story/skills/story-deslop/scripts/check-ai-patterns.js +64 -1
  216. package/lib/oh-story/skills/story-import/SKILL.md +21 -8
  217. package/lib/oh-story/skills/story-import/references/format-and-structure.md +9 -10
  218. package/lib/oh-story/skills/story-import/references/structure-mapping-long.md +2 -2
  219. package/lib/oh-story/skills/story-import/references/structure-mapping-short.md +1 -1
  220. package/lib/oh-story/skills/story-import/references/tracking-transaction.md +14 -6
  221. package/lib/oh-story/skills/story-import/scripts/check-outline-contract.js +251 -0
  222. package/lib/oh-story/skills/story-import/scripts/tracking_commit.py +98 -9
  223. package/lib/oh-story/skills/story-import/scripts/wordcount_core.py +246 -0
  224. package/lib/oh-story/skills/story-long-analyze/SKILL.md +4 -4
  225. package/lib/oh-story/skills/story-long-scan/SKILL.md +1 -1
  226. package/lib/oh-story/skills/story-long-write/SKILL.md +35 -21
  227. package/lib/oh-story/skills/story-long-write/references/anti-ai-writing.md +2 -1
  228. package/lib/oh-story/skills/story-long-write/references/artifact-protocols.md +7 -3
  229. package/lib/oh-story/skills/story-long-write/references/author-memory.md +163 -0
  230. package/lib/oh-story/skills/story-long-write/references/banned-words.md +6 -4
  231. package/lib/oh-story/skills/story-long-write/references/cross-book-recall.md +6 -6
  232. package/lib/oh-story/skills/story-long-write/references/genre-prose-cards.md +1 -1
  233. package/lib/oh-story/skills/story-long-write/references/genre-readers.md +1 -1
  234. package/lib/oh-story/skills/{story-setup/references/agent-references/hooks-chapter.md → story-long-write/references/long-chapter-hooks.md} +5 -5
  235. package/lib/oh-story/skills/story-long-write/references/{quality-checklist.md → long-chapter-quality.md} +2 -1
  236. package/lib/oh-story/skills/story-long-write/references/long-format.md +42 -0
  237. package/lib/oh-story/skills/{story-setup/references/agent-references/genre-catalog.md → story-long-write/references/long-genre-catalog.md} +11 -97
  238. package/lib/oh-story/skills/story-long-write/references/{genre-core-mechanics.md → long-genre-mechanics.md} +1 -1
  239. package/lib/oh-story/skills/story-long-write/references/{reversal-toolkit.md → long-reversal.md} +18 -32
  240. package/lib/oh-story/skills/story-long-write/references/{hooks-suspense.md → long-suspense.md} +6 -6
  241. package/lib/oh-story/skills/story-long-write/references/opening-design.md +1 -1
  242. package/lib/oh-story/skills/story-long-write/references/outline-structure-theory.md +1 -1
  243. package/lib/oh-story/skills/story-long-write/references/style-genre-modules.md +1 -1
  244. package/lib/oh-story/skills/story-long-write/references/tracking-transaction.md +14 -6
  245. package/lib/oh-story/skills/story-long-write/references/workflow-chapter.md +32 -27
  246. package/lib/oh-story/skills/story-long-write/references/workflow-daily.md +5 -4
  247. package/lib/oh-story/skills/story-long-write/references/workflow-revision.md +2 -2
  248. package/lib/oh-story/skills/story-long-write/references/workflow-setup.md +17 -11
  249. package/lib/oh-story/skills/story-long-write/references/writing-craft.md +54 -54
  250. package/lib/oh-story/skills/story-long-write/scripts/author_memory_commit.py +871 -0
  251. package/lib/oh-story/skills/story-long-write/scripts/check-ai-patterns.js +64 -1
  252. package/lib/oh-story/skills/story-long-write/scripts/check-outline-contract.js +251 -0
  253. package/lib/oh-story/skills/story-long-write/scripts/storyctl.py +303 -0
  254. package/lib/oh-story/skills/story-long-write/scripts/tracking_commit.py +98 -9
  255. package/lib/oh-story/skills/story-long-write/scripts/wordcount_core.py +246 -0
  256. package/lib/oh-story/skills/story-review/SKILL.md +26 -17
  257. package/lib/oh-story/skills/story-review/references/anti-ai-writing.md +2 -1
  258. package/lib/oh-story/skills/story-review/references/author-memory.md +163 -0
  259. package/lib/oh-story/skills/story-review/references/banned-words.md +6 -4
  260. package/lib/oh-story/skills/story-review/references/{quality-checklist.md → review-quality.md} +22 -21
  261. package/lib/oh-story/skills/story-review/references/tracking-transaction.md +14 -6
  262. package/lib/oh-story/skills/story-review/scripts/author_memory_commit.py +871 -0
  263. package/lib/oh-story/skills/story-review/scripts/check-ai-patterns.js +64 -1
  264. package/lib/oh-story/skills/story-review/scripts/tracking_commit.py +98 -9
  265. package/lib/oh-story/skills/story-review/scripts/wordcount_core.py +246 -0
  266. package/lib/oh-story/skills/story-setup/SKILL.md +85 -41
  267. package/lib/oh-story/skills/story-setup/references/agent-references/agent-quality.md +72 -0
  268. package/lib/oh-story/skills/story-setup/references/agent-references/agent-reference-profiles.md +55 -0
  269. package/lib/oh-story/skills/story-setup/references/agent-references/anti-ai-writing.md +2 -1
  270. package/lib/oh-story/skills/story-setup/references/agent-references/banned-words.md +6 -4
  271. package/lib/oh-story/skills/story-setup/references/agent-references/format-and-structure.md +9 -10
  272. package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards.md +1 -1
  273. package/lib/oh-story/skills/story-setup/references/agent-references/genre-readers.md +1 -1
  274. package/lib/oh-story/skills/{story-short-analyze/references/hooks-chapter.md → story-setup/references/agent-references/long-chapter-hooks.md} +5 -5
  275. package/lib/oh-story/skills/story-setup/references/agent-references/long-emotional-methods.md +209 -0
  276. package/lib/oh-story/skills/{story-long-write/references/genre-catalog.md → story-setup/references/agent-references/long-genre-catalog.md} +11 -97
  277. package/lib/oh-story/skills/story-setup/references/agent-references/{genre-core-mechanics.md → long-genre-mechanics.md} +1 -1
  278. package/lib/oh-story/skills/story-setup/references/agent-references/long-quality.md +40 -0
  279. package/lib/oh-story/skills/{story-short-write/references/reversal-toolkit.md → story-setup/references/agent-references/long-reversal.md} +18 -32
  280. package/lib/oh-story/skills/{story-short-write/references/hooks-suspense.md → story-setup/references/agent-references/long-suspense.md} +6 -6
  281. package/lib/oh-story/skills/story-setup/references/agent-references/opening-design.md +1 -1
  282. package/lib/oh-story/skills/story-setup/references/agent-references/{emotional-methods.md → short-emotional-methods.md} +4 -4
  283. package/lib/oh-story/skills/{story-long-write/references/genre-writing-formulas.md → story-setup/references/agent-references/short-genre-formulas.md} +32 -44
  284. package/lib/oh-story/skills/story-setup/references/agent-references/short-quality.md +39 -0
  285. package/lib/oh-story/skills/story-setup/references/agent-references/{reversal-toolkit.md → short-reversal.md} +29 -23
  286. package/lib/oh-story/skills/story-setup/references/agent-references/{hooks-suspense.md → short-suspense.md} +31 -31
  287. package/lib/oh-story/skills/story-setup/references/agent-references/style-genre-modules.md +1 -1
  288. package/lib/oh-story/skills/story-setup/references/agent-references/writing-craft.md +55 -55
  289. package/lib/oh-story/skills/story-short-analyze/SKILL.md +28 -28
  290. package/lib/oh-story/skills/story-short-analyze/references/{character-basics.md → analysis-character-basics.md} +1 -1
  291. package/lib/oh-story/skills/story-short-analyze/references/{character-design-methods.md → analysis-character-design.md} +1 -1
  292. package/lib/oh-story/skills/story-short-analyze/references/{character-relations.md → analysis-character-relations.md} +1 -1
  293. package/lib/oh-story/skills/story-short-analyze/references/{hooks-paragraph.md → analysis-paragraph-hooks.md} +1 -1
  294. package/lib/oh-story/skills/story-short-analyze/references/{genre-readers.md → analysis-reader-profile.md} +2 -2
  295. package/lib/oh-story/skills/story-short-analyze/references/analysis-report-style.md +45 -0
  296. package/lib/oh-story/skills/story-short-analyze/references/analysis-short-genres.md +65 -0
  297. package/lib/oh-story/skills/story-short-analyze/references/analysis-short-hooks.md +77 -0
  298. package/lib/oh-story/skills/story-short-analyze/references/analysis-short-mechanics.md +82 -0
  299. package/lib/oh-story/skills/story-short-analyze/references/analysis-short-patterns.md +50 -0
  300. package/lib/oh-story/skills/story-short-analyze/references/analysis-short-suspense.md +98 -0
  301. package/lib/oh-story/skills/story-short-analyze/references/{genre-writing-techniques.md → analysis-writing-techniques.md} +21 -19
  302. package/lib/oh-story/skills/story-short-analyze/references/deconstruction-examples.md +1 -1
  303. package/lib/oh-story/skills/story-short-analyze/references/material-decomposition.md +21 -28
  304. package/lib/oh-story/skills/story-short-analyze/references/output-contract.md +1 -1
  305. package/lib/oh-story/skills/story-short-analyze/references/output-templates.md +17 -17
  306. package/lib/oh-story/skills/story-short-analyze/references/{quality-checklist.md → source-story-quality.md} +28 -49
  307. package/lib/oh-story/skills/story-short-analyze/references/zhihu-style.md +2 -2
  308. package/lib/oh-story/skills/story-short-scan/SKILL.md +1 -1
  309. package/lib/oh-story/skills/story-short-write/SKILL.md +78 -55
  310. package/lib/oh-story/skills/story-short-write/references/author-memory.md +163 -0
  311. package/lib/oh-story/skills/story-short-write/references/banned-words.md +6 -4
  312. package/lib/oh-story/skills/story-short-write/references/cross-book-recall.md +3 -3
  313. package/lib/oh-story/skills/story-short-write/references/emotional-methods.md +4 -4
  314. package/lib/oh-story/skills/story-short-write/references/genre-styles//344/270/226/346/203/205/346/211/223/350/204/270.md +3 -3
  315. package/lib/oh-story/skills/story-short-write/references/genre-styles//345/217/214/347/224/267/344/270/273.md +2 -2
  316. package/lib/oh-story/skills/story-short-write/references/genre-styles//345/244/215/344/273/207/346/211/223/350/204/270.md +3 -3
  317. package/lib/oh-story/skills/story-short-write/references/genre-styles//345/256/205/346/226/227/345/256/253/346/226/227.md +6 -6
  318. package/lib/oh-story/skills/story-short-write/references/genre-styles//346/200/273/350/243/201/350/261/252/351/227/250.md +3 -3
  319. package/lib/oh-story/skills/story-short-write/references/genre-styles//346/202/254/347/226/221.md +4 -4
  320. package/lib/oh-story/skills/story-short-write/references/genre-styles//346/260/221/344/277/227/346/200/252/350/260/210.md +7 -7
  321. package/lib/oh-story/skills/story-short-write/references/genre-styles//346/262/231/351/233/225/350/204/221/346/264/236.md +5 -5
  322. package/lib/oh-story/skills/story-short-write/references/genre-styles//347/224/234/345/256/240.md +4 -4
  323. package/lib/oh-story/skills/story-short-write/references/genre-styles//350/277/275/345/246/273/347/201/253/350/221/254/345/234/272.md +3 -3
  324. package/lib/oh-story/skills/story-short-write/references/genre-writing-formulas.md +32 -44
  325. package/lib/oh-story/skills/story-short-write/references/genre-writing-techniques.md +20 -18
  326. package/lib/oh-story/skills/story-short-write/references/output-contract.md +1 -1
  327. package/lib/oh-story/skills/story-short-write/references/short-craft.md +18 -18
  328. package/lib/oh-story/skills/story-short-write/references/short-deslop.md +1 -1
  329. package/lib/oh-story/skills/story-short-write/references/short-format.md +38 -8
  330. package/lib/oh-story/skills/story-short-write/references/{quality-checklist.md → short-prose-quality.md} +22 -21
  331. package/lib/oh-story/skills/story-short-write/references/short-reversal.md +355 -0
  332. package/lib/oh-story/skills/{story-short-analyze/references/hooks-suspense.md → story-short-write/references/short-suspense.md} +31 -31
  333. package/lib/oh-story/skills/story-short-write/references/submission-craft.md +2 -2
  334. package/lib/oh-story/skills/story-short-write/references/writing-workflow.md +31 -22
  335. package/lib/oh-story/skills/story-short-write/scripts/author_memory_commit.py +871 -0
  336. package/lib/oh-story/skills/story-short-write/scripts/check-ai-patterns.js +64 -1
  337. package/lib/oh-story/skills/story-short-write/scripts/check-delivery-contract.js +212 -0
  338. package/lib/oh-story/skills/story-short-write/scripts/check-phase2-contract.js +363 -0
  339. package/lib/types/client/drama-production-view.d.ts +34 -0
  340. package/lib/types/client/drama-production-view.d.ts.map +1 -0
  341. package/lib/types/client/drama-production.d.ts +92 -0
  342. package/lib/types/client/drama-production.d.ts.map +1 -0
  343. package/lib/types/client/file-activity.d.ts +9 -2
  344. package/lib/types/client/file-activity.d.ts.map +1 -1
  345. package/lib/types/client/index.d.ts +1 -1
  346. package/lib/types/client/index.d.ts.map +1 -1
  347. package/lib/types/client/production-intents.d.ts +9 -0
  348. package/lib/types/client/production-intents.d.ts.map +1 -0
  349. package/lib/types/client/production-prompts.d.ts +9 -0
  350. package/lib/types/client/production-prompts.d.ts.map +1 -0
  351. package/lib/types/client/production-runtime.d.ts +58 -0
  352. package/lib/types/client/production-runtime.d.ts.map +1 -0
  353. package/lib/types/client/video-studio.d.ts +41 -0
  354. package/lib/types/client/video-studio.d.ts.map +1 -0
  355. package/lib/types/client/workbench-ui.d.ts +5 -0
  356. package/lib/types/client/workbench-ui.d.ts.map +1 -0
  357. package/lib/types/game-verification.d.ts +16 -0
  358. package/lib/types/game-verification.d.ts.map +1 -0
  359. package/lib/types/index.d.ts +5 -2
  360. package/lib/types/index.d.ts.map +1 -1
  361. package/lib/types/production-intent.d.ts +21 -0
  362. package/lib/types/production-intent.d.ts.map +1 -0
  363. package/lib/types/production-tool.d.ts +5 -0
  364. package/lib/types/production-tool.d.ts.map +1 -0
  365. package/lib/types/reference-tool.d.ts +6 -0
  366. package/lib/types/reference-tool.d.ts.map +1 -0
  367. package/lib/types/role-provider.d.ts.map +1 -1
  368. package/lib/types/role-tool.d.ts +3 -1
  369. package/lib/types/role-tool.d.ts.map +1 -1
  370. package/lib/types/skill-provider.d.ts +7 -0
  371. package/lib/types/skill-provider.d.ts.map +1 -1
  372. package/lib/types/video-project.d.ts +42 -0
  373. package/lib/types/video-project.d.ts.map +1 -0
  374. package/lib/types/workspace-request-trust.d.ts +6 -0
  375. package/lib/types/workspace-request-trust.d.ts.map +1 -1
  376. package/lib/types/workspace-route.d.ts +20 -0
  377. package/lib/types/workspace-route.d.ts.map +1 -1
  378. package/lib/video-recap/CHANGELOG.md +282 -0
  379. package/lib/video-recap/LICENSE +21 -0
  380. package/lib/video-recap/README.en.md +257 -0
  381. package/lib/video-recap/README.md +255 -0
  382. package/lib/video-recap/manifest.json +684 -0
  383. package/lib/video-recap/skills/video-assemble/SKILL.md +97 -0
  384. package/lib/video-recap/skills/video-assemble/references/jianying/LICENSE.duo-video +21 -0
  385. package/lib/video-recap/skills/video-assemble/references/jianying/SOURCE.md +15 -0
  386. package/lib/video-recap/skills/video-assemble/references/jianying/empty_draft_meta_info.json +69 -0
  387. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_combination_segment.json +84 -0
  388. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_combination_video_material.json +98 -0
  389. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_draft.json +204 -0
  390. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_material_video.json +83 -0
  391. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_meta_material_value.json +23 -0
  392. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_project_info.json +133 -0
  393. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_segment.json +70 -0
  394. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_text_styles.json +30 -0
  395. package/lib/video-recap/skills/video-assemble/references/jianying/empty_yj_material_audio.json +41 -0
  396. package/lib/video-recap/skills/video-assemble/references/jianying/empty_yj_material_text.json +109 -0
  397. package/lib/video-recap/skills/video-assemble/scripts/artifacts.py +88 -0
  398. package/lib/video-recap/skills/video-assemble/scripts/assemble.py +345 -0
  399. package/lib/video-recap/skills/video-assemble/scripts/assemble_constants.py +34 -0
  400. package/lib/video-recap/skills/video-assemble/scripts/assembly_contract.py +305 -0
  401. package/lib/video-recap/skills/video-assemble/scripts/assembly_settings.py +94 -0
  402. package/lib/video-recap/skills/video-assemble/scripts/audio_automation.py +205 -0
  403. package/lib/video-recap/skills/video-assemble/scripts/audio_mix.py +555 -0
  404. package/lib/video-recap/skills/video-assemble/scripts/export_jianying.py +261 -0
  405. package/lib/video-recap/skills/video-assemble/scripts/jianying_builders.py +767 -0
  406. package/lib/video-recap/skills/video-assemble/scripts/jianying_model.py +111 -0
  407. package/lib/video-recap/skills/video-assemble/scripts/jianying_optional.py +24 -0
  408. package/lib/video-recap/skills/video-assemble/scripts/jianying_schema.py +109 -0
  409. package/lib/video-recap/skills/video-assemble/scripts/jianying_templates.py +37 -0
  410. package/lib/video-recap/skills/video-assemble/scripts/jianying_timeline_contract.py +191 -0
  411. package/lib/video-recap/skills/video-assemble/scripts/jianying_tracks.py +75 -0
  412. package/lib/video-recap/skills/video-assemble/scripts/jianying_writer.py +394 -0
  413. package/lib/video-recap/skills/video-assemble/scripts/lib.py +239 -0
  414. package/lib/video-recap/skills/video-assemble/scripts/media.py +243 -0
  415. package/lib/video-recap/skills/video-assemble/scripts/narration_audio.py +477 -0
  416. package/lib/video-recap/skills/video-assemble/scripts/render_preflight.py +46 -0
  417. package/lib/video-recap/skills/video-assemble/scripts/source_subtitles.py +486 -0
  418. package/lib/video-recap/skills/video-assemble/scripts/subtitle_core.py +376 -0
  419. package/lib/video-recap/skills/video-assemble/scripts/subtitle_render.py +88 -0
  420. package/lib/video-recap/skills/video-assemble/scripts/timeline.py +248 -0
  421. package/lib/video-recap/skills/video-assemble/scripts/timeline_emit.py +89 -0
  422. package/lib/video-recap/skills/video-assemble/scripts/visual_render.py +512 -0
  423. package/lib/video-recap/skills/video-cut/SKILL.md +90 -0
  424. package/lib/video-recap/skills/video-cut/scripts/cut.py +67 -0
  425. package/lib/video-recap/skills/video-cut/scripts/cut_cli.py +320 -0
  426. package/lib/video-recap/skills/video-cut/scripts/cut_contract.py +545 -0
  427. package/lib/video-recap/skills/video-cut/scripts/cut_render.py +348 -0
  428. package/lib/video-recap/skills/video-cut/scripts/lib.py +77 -0
  429. package/lib/video-recap/skills/video-cut/scripts/media_geometry.py +341 -0
  430. package/lib/video-recap/skills/video-cut/scripts/narration_mapping.py +249 -0
  431. package/lib/video-recap/skills/video-cut/scripts/sentence_boundaries.py +745 -0
  432. package/lib/video-recap/skills/video-recap/SKILL.md +216 -0
  433. package/lib/video-recap/skills/video-recap/references/config-playbook.md +61 -0
  434. package/lib/video-recap/skills/video-recap/references/creative-editing-playbook.md +225 -0
  435. package/lib/video-recap/skills/video-recap/references/data-schema.md +534 -0
  436. package/lib/video-recap/skills/video-recap/references/research-guide.md +74 -0
  437. package/lib/video-recap/skills/video-recap/references/shift-left-qc-schema.md +23 -0
  438. package/lib/video-recap/skills/video-recap/references/timeline-and-jianying.md +251 -0
  439. package/lib/video-recap/skills/video-recap/scripts/doctor.py +483 -0
  440. package/lib/video-recap/skills/video-recap/scripts/final_qc.py +737 -0
  441. package/lib/video-recap/skills/video-recap/scripts/lib.py +242 -0
  442. package/lib/video-recap/skills/video-recap/scripts/materials.py +457 -0
  443. package/lib/video-recap/skills/video-recap/scripts/mimo_qc.py +95 -0
  444. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_client.py +18 -0
  445. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_contract.py +9 -0
  446. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_evidence.py +371 -0
  447. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_observations.py +201 -0
  448. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_payload.py +227 -0
  449. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_report.py +362 -0
  450. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_runner.py +129 -0
  451. package/lib/video-recap/skills/video-recap/scripts/qc_contract.py +338 -0
  452. package/lib/video-recap/skills/video-recap/scripts/recap.py +9 -0
  453. package/lib/video-recap/skills/video-recap/scripts/recap_cli.py +140 -0
  454. package/lib/video-recap/skills/video-recap/scripts/recap_inspect.py +550 -0
  455. package/lib/video-recap/skills/video-recap/scripts/recap_review.py +77 -0
  456. package/lib/video-recap/skills/video-recap/scripts/recap_runner.py +654 -0
  457. package/lib/video-recap/skills/video-recap/scripts/recap_runtime.py +335 -0
  458. package/lib/video-recap/skills/video-recap/scripts/recap_stage_qc.py +217 -0
  459. package/lib/video-recap/skills/video-recap/scripts/recap_timeline.py +795 -0
  460. package/lib/video-recap/skills/video-script/SKILL.md +248 -0
  461. package/lib/video-recap/skills/video-script/references/creative-editing-playbook.md +225 -0
  462. package/lib/video-recap/skills/video-script/references/research-guide.md +75 -0
  463. package/lib/video-recap/skills/video-script/scripts/agent_brief.py +399 -0
  464. package/lib/video-recap/skills/video-script/scripts/agent_text.py +410 -0
  465. package/lib/video-recap/skills/video-script/scripts/brief_context.py +403 -0
  466. package/lib/video-recap/skills/video-script/scripts/brief_inputs.py +332 -0
  467. package/lib/video-recap/skills/video-script/scripts/brief_timeline.py +442 -0
  468. package/lib/video-recap/skills/video-script/scripts/deslop_qc.py +237 -0
  469. package/lib/video-recap/skills/video-script/scripts/evidence_bundle.py +492 -0
  470. package/lib/video-recap/skills/video-script/scripts/lib.py +327 -0
  471. package/lib/video-recap/skills/video-script/scripts/narration.py +12 -0
  472. package/lib/video-recap/skills/video-script/scripts/narration_lint.py +678 -0
  473. package/lib/video-recap/skills/video-script/scripts/review.py +42 -0
  474. package/lib/video-recap/skills/video-script/scripts/review_grounding.py +262 -0
  475. package/lib/video-recap/skills/video-script/scripts/review_response.py +761 -0
  476. package/lib/video-recap/skills/video-script/scripts/review_runner.py +200 -0
  477. package/lib/video-recap/skills/video-script/scripts/speech_ownership.py +204 -0
  478. package/lib/video-recap/skills/video-script/scripts/timeline_fusion.py +199 -0
  479. package/lib/video-recap/skills/video-script/scripts/validate.py +164 -0
  480. package/lib/video-recap/skills/video-understanding/SKILL.md +75 -0
  481. package/lib/video-recap/skills/video-understanding/references/data-schema.md +299 -0
  482. package/lib/video-recap/skills/video-understanding/references/prompt-templates.md +37 -0
  483. package/lib/video-recap/skills/video-understanding/references/research-guide.md +74 -0
  484. package/lib/video-recap/skills/video-understanding/scripts/agent_brief.py +399 -0
  485. package/lib/video-recap/skills/video-understanding/scripts/agent_text.py +410 -0
  486. package/lib/video-recap/skills/video-understanding/scripts/asr.py +260 -0
  487. package/lib/video-recap/skills/video-understanding/scripts/brief.py +12 -0
  488. package/lib/video-recap/skills/video-understanding/scripts/brief_context.py +403 -0
  489. package/lib/video-recap/skills/video-understanding/scripts/brief_inputs.py +332 -0
  490. package/lib/video-recap/skills/video-understanding/scripts/brief_timeline.py +442 -0
  491. package/lib/video-recap/skills/video-understanding/scripts/consolidate.py +647 -0
  492. package/lib/video-recap/skills/video-understanding/scripts/deslop_qc.py +237 -0
  493. package/lib/video-recap/skills/video-understanding/scripts/detect.py +513 -0
  494. package/lib/video-recap/skills/video-understanding/scripts/extract.py +62 -0
  495. package/lib/video-recap/skills/video-understanding/scripts/lib.py +470 -0
  496. package/lib/video-recap/skills/video-understanding/scripts/narration_lint.py +678 -0
  497. package/lib/video-recap/skills/video-understanding/scripts/speech_ownership.py +204 -0
  498. package/lib/video-recap/skills/video-understanding/scripts/storyboard.py +507 -0
  499. package/lib/video-recap/skills/video-understanding/scripts/timeline_fusion.py +199 -0
  500. package/lib/video-recap/skills/video-understanding/scripts/understand.py +9 -0
  501. package/lib/video-recap/skills/video-understanding/scripts/understanding_brief.py +216 -0
  502. package/lib/video-recap/skills/video-understanding/scripts/understanding_cache.py +327 -0
  503. package/lib/video-recap/skills/video-understanding/scripts/understanding_runner.py +367 -0
  504. package/lib/video-recap/skills/video-understanding/scripts/understanding_storyboard.py +162 -0
  505. package/lib/video-recap/skills/video-understanding/scripts/vlm.py +705 -0
  506. package/lib/video-recap/skills/video-voiceover/SKILL.md +81 -0
  507. package/lib/video-recap/skills/video-voiceover/scripts/dub.py +637 -0
  508. package/lib/video-recap/skills/video-voiceover/scripts/fish_audio.py +109 -0
  509. package/lib/video-recap/skills/video-voiceover/scripts/lib.py +421 -0
  510. package/lib/video-recap/skills/video-voiceover/scripts/tts_audio.py +113 -0
  511. package/lib/video-recap/skills/video-voiceover/scripts/voiceover.py +782 -0
  512. package/package.json +57 -41
  513. package/lib/drama/skills/short-drama/references/lifecycle-commands.md +0 -130
  514. package/lib/oh-story/skills/story-deslop/scripts/check-outline-copy.js +0 -241
  515. package/lib/oh-story/skills/story-long-write/references/format-and-structure.md +0 -169
  516. package/lib/oh-story/skills/story-setup/references/agent-references/genre-writing-formulas.md +0 -444
  517. package/lib/oh-story/skills/story-setup/references/agent-references/quality-checklist.md +0 -247
  518. package/lib/oh-story/skills/story-short-analyze/references/anti-ai-writing.md +0 -582
  519. package/lib/oh-story/skills/story-short-analyze/references/banned-words.md +0 -147
  520. package/lib/oh-story/skills/story-short-analyze/references/genre-catalog.md +0 -490
  521. package/lib/oh-story/skills/story-short-analyze/references/genre-core-mechanics.md +0 -425
  522. package/lib/oh-story/skills/story-short-analyze/references/genre-writing-formulas.md +0 -453
  523. /package/lib/oh-story/skills/{story-long-write/references/hooks-chapter.md → story-setup/references/agent-references/short-chapter-hooks.md} +0 -0
  524. /package/lib/oh-story/skills/{story-long-write/references/hooks-paragraph.md → story-setup/references/agent-references/short-paragraph-hooks.md} +0 -0
@@ -13,6 +13,7 @@ Detect high-risk AI-flavor prose patterns that need human rewrite:
13
13
  - repeated negative setup followed by positive flip
14
14
  - em-dash (按功能改写), 碎句号 (连续短叙述句), 长段落 (按镜头断段)
15
15
  - 微动作复读 (「了下/了一下」式轻量补语高密度,电报体指纹)
16
+ - 套式反应细节 (指尖/指节/目光等无功能微动作与「平静得像在念」式语气比喻成片)
16
17
  - 抽象总结复读 (命运/棋局/这一刻终于明白/才刚刚开始,AI 结尾腔)
17
18
  - 套词密度过高 (仿佛/一丝/深吸一口气/平静无波等禁用词聚集)
18
19
  - 比喻密度过高 (像/好像/仿佛/如同等比喻标记成片复现)
@@ -30,7 +31,7 @@ Detect high-risk AI-flavor prose patterns that need human rewrite:
30
31
  - 引号强调滥用 (叙述里 1-4 字短词加引号强调,密度型)
31
32
 
32
33
  Each finding carries severity: blocking by default for generation/deslop cleanup (not-is-comparison / em-dash / voice-contrast / negation-parade / reverse-not-is / trailer-ending / trailer-summary). This is a local style/readability gate, not an AIGC detector score; functional human text can be marked for review instead of hard-edited for a detector.
33
- 或 advisory (period-stutter / long-paragraph / micro-action-tic / action-list-tic / abstract-summary-tic / cliche-density-tic / metaphor-density-tic / reasoning-chain-tic / system-notice-formality-tic / overcompressed-prose-tic / low-connective-density-tic / quote-emphasis-tic / formulaic-parallelism,是提示,justified 的长推理/氛围段可保留)。
34
+ 或 advisory (period-stutter / long-paragraph / micro-action-tic / stock-reaction-tic / action-list-tic / abstract-summary-tic / cliche-density-tic / metaphor-density-tic / reasoning-chain-tic / system-notice-formality-tic / overcompressed-prose-tic / low-connective-density-tic / quote-emphasis-tic / formulaic-parallelism,是提示,justified 的长推理/氛围段可保留)。
34
35
  --fail-on=blocking 只在出现 blocking finding 时退出 1;默认 --fail-on=all 有任何 finding 即退出 1。
35
36
 
36
37
  The script reports findings only. It never rewrites text, because the safe fix is
@@ -57,6 +58,26 @@ const MICRO_TIC_PATTERN = /了(?:[一两三几半])?[下阵圈道声眼口气会
57
58
  const MICRO_TIC_MIN_HITS = 5;
58
59
  const MICRO_TIC_PER_KILO = 6;
59
60
 
61
+ // 套式反应细节:不是禁写身体,而是提示成片出现的“部位 + 轻微动作/状态”、
62
+ // “胸口像被撞了一下”、喉结/眼圈/声音放轻等通用情绪尾巴,以及“平静语气 +
63
+ // 像在念/宣判”模板。此类句子词面变化大,不能逐词 blocking;按章聚集到 4 处才
64
+ // advisory,要求逐处做删除测试。正常受伤、打斗、生理反应若承担物理后果可保留。
65
+ const STOCK_REACTION_PATTERNS = [
66
+ /(?:指尖|手指|指节|手背|掌心|拳头|袖口|衣角|裙角|下唇|嘴唇|唇角|嘴角|眉头|眼底|眸光|目光|视线|肩膀|呼吸)[^。!?!?\n]{0,16}(?:轻轻|微微|缓缓|悄然|不自觉|无意识|下意识|攥紧|握紧|收紧|绞紧|泛白|发白|叩|敲|摩挲|抿紧|抿成|移开|垂下|躲开|一颤|颤了?一下|停了?一下|顿了?一下)/g,
67
+ /(?:语气|声音)[^。!?!?\n]{0,12}(?:平静|冷静|平淡|冷淡|淡漠|平直)[^。!?!?\n]{0,12}(?:像|仿佛|如同|好像)[^。!?!?\n]{0,16}(?:念|读|报|说|陈述|宣判|背诵)/g,
68
+ /(?:胸口|心口)[^。!?!?\n]{0,16}(?:像|仿佛|如同|好像)[^。!?!?\n]{0,16}(?:撞|锤|压|攥|堵)[^。!?!?\n]{0,8}(?:一下|一记|一拳)?/g,
69
+ /(?:声音|嗓音|语气)[^。!?!?\n]{0,12}(?:放轻|压低|发紧|发颤|很轻|轻了些)/g,
70
+ /(?:喉结|喉头|喉咙)[^。!?!?\n]{0,10}(?:滚|动|紧|堵|发涩|发干)/g,
71
+ /(?:眼眶|眼圈|鼻子)[^。!?!?\n]{0,8}(?:发红|红了|发热|发酸|一酸)/g,
72
+ /(?:抿了?下唇|抿了?抿唇|抿了?下嘴|抿着笑)/g,
73
+ ];
74
+ const STOCK_REACTION_MIN_HITS = 4;
75
+ // 校准(真人语料,<br> 已还原为换行):qimao 长篇 5584 章 + heiyan 短篇整篇 3983 篇。
76
+ // 长篇章尺度(中位约 2100 字)per-kilo 1.0→1.5 误报 0.43%→0.39%,几乎不动;
77
+ // 短篇整篇 8000-20000 字下 MIN_HITS 形同虚设、只剩密度门,1.0 时误报 5.57%,
78
+ // 1.5 降到 1.46%。故取 1.5,把两个总体拉到同一量级(四份副本共用一组阈值)。
79
+ const STOCK_REACTION_PER_KILO = 1.5;
80
+
60
81
  // 监控摄像头式动作清单:同一段连续堆叠通用动作动词(伸手/拿起/取过/挑开/放下/转身等),
61
82
  // 且用逗号/顿号串联成步骤表时,读感像无视角温度的监控记录。只做 advisory;
62
83
  // 打斗/追逐等功能性动作编排可保留或人工复核。
@@ -406,6 +427,7 @@ function scanProsePatterns(proseLines) {
406
427
  findings.push(...findQuoteEmphasisTic(proseLines));
407
428
  findings.push(...findPeriodStutter(proseLines));
408
429
  findings.push(...findMicroActionTic(proseLines));
430
+ findings.push(...findStockReactionTic(proseLines));
409
431
  findings.push(...findActionListTic(proseLines));
410
432
  findings.push(...findAbstractSummaryTic(proseLines));
411
433
  findings.push(...findClicheDensityTic(proseLines));
@@ -700,6 +722,47 @@ function findMicroActionTic(proseLines) {
700
722
  }];
701
723
  }
702
724
 
725
+ // 套式反应细节:统计引号外叙述中通用的部位/声线反应与固定语气比喻。
726
+ // 这是删除测试的候选集,不是身体描写黑名单;全篇只报一条,保留有动作后果、
727
+ // 伤势、人物习惯或情节功能的细节。
728
+ function findStockReactionTic(proseLines) {
729
+ let hits = 0;
730
+ let narrativeChars = 0;
731
+ let firstLine = null;
732
+ const samples = [];
733
+
734
+ for (const { text, lineNo } of proseLines) {
735
+ const trimmed = text.trim();
736
+ if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
737
+ const narrative = stripQuoted(trimmed);
738
+ narrativeChars += visibleLength(narrative);
739
+
740
+ for (const pattern of STOCK_REACTION_PATTERNS) {
741
+ pattern.lastIndex = 0;
742
+ let match;
743
+ while ((match = pattern.exec(narrative)) !== null) {
744
+ hits += 1;
745
+ if (firstLine === null) firstLine = lineNo;
746
+ const sample = sentenceAround(narrative, match.index);
747
+ if (samples.length < 6 && sample && !samples.includes(sample)) samples.push(sample);
748
+ }
749
+ }
750
+ }
751
+
752
+ if (narrativeChars === 0 || hits < STOCK_REACTION_MIN_HITS) return [];
753
+ const perKilo = (hits / narrativeChars) * 1000;
754
+ if (perKilo < STOCK_REACTION_PER_KILO) return [];
755
+
756
+ return [{
757
+ line: firstLine,
758
+ column: 1,
759
+ type: 'stock-reaction-tic',
760
+ severity: 'advisory',
761
+ message: `套式反应细节:指尖/指节/喉结/眼圈/声音放轻等通用反应或“平静得像在念”式语气比喻 ${hits} 处(${perKilo.toFixed(1)}/千字);逐处做删除测试,只标注情绪、不改变选择、关系、物件或动作结果的删掉,不要换部位或同义动作。`,
762
+ excerpt: compact(samples.join(' | ')),
763
+ }];
764
+ }
765
+
703
766
  function findActionListTic(proseLines) {
704
767
  const findings = [];
705
768
 
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Deterministic delivery verifier for story-short-write.
4
+ *
5
+ * Usage:
6
+ * node scripts/check-delivery-contract.js --json \
7
+ * --min-chars N --max-chars N --sections N [project-dir]
8
+ * Exit: 0 = pass, 1 = blocking delivery failures, 2 = invalid invocation.
9
+ *
10
+ * The verifier only checks user-visible size and shape. It does not score prose,
11
+ * causality, emotion, or any other semantic quality dimension.
12
+ */
13
+
14
+ 'use strict'
15
+
16
+ const fs = require('fs')
17
+ const path = require('path')
18
+
19
+ const MARKERS = [
20
+ { style: 'numeric-heading', pattern: /^###\s*\d+\.$/ },
21
+ { style: 'chapter-heading', pattern: /^###\s*第[一二三四五六七八九十百千万两〇零0-9]+章$/ },
22
+ { style: 'zhihu-numeric', pattern: /^\d+\.$/ },
23
+ ]
24
+
25
+ function readBody(file) {
26
+ try {
27
+ const text = fs.readFileSync(file, 'utf8').replace(/^\uFEFF/, '')
28
+ return { ok: text.trim().length > 0, text }
29
+ } catch (error) {
30
+ return { ok: false, text: '', error: error.message }
31
+ }
32
+ }
33
+
34
+ function visibleChars(text) {
35
+ return Array.from(text).filter((character) => !/\s/u.test(character)).length
36
+ }
37
+
38
+ function markerFor(line) {
39
+ const trimmed = line.trim()
40
+ return MARKERS.find((entry) => entry.pattern.test(trimmed)) || null
41
+ }
42
+
43
+ function makeCheck(id, ok, evidence, expected, repair) {
44
+ return {
45
+ id,
46
+ ok,
47
+ severity: 'blocking',
48
+ file: '正文.md',
49
+ evidence,
50
+ expected,
51
+ references: ['references/short-format.md'],
52
+ repair,
53
+ }
54
+ }
55
+
56
+ function verify(projectDir, contract) {
57
+ const project = path.resolve(projectDir)
58
+ const bodyFile = path.join(project, '正文.md')
59
+ const bodyRead = readBody(bodyFile)
60
+ const checks = []
61
+
62
+ checks.push(makeCheck(
63
+ 'delivery.body-readable',
64
+ bodyRead.ok,
65
+ bodyRead.ok ? '正文.md 存在且非空' : (bodyRead.error || '正文.md 为空'),
66
+ '项目目录下存在非空的 正文.md',
67
+ '只补建或恢复 正文.md;不要改动设定与大纲。'
68
+ ))
69
+ if (!bodyRead.ok) return report(project, contract, checks)
70
+
71
+ const actual = visibleChars(bodyRead.text)
72
+ checks.push(makeCheck(
73
+ 'delivery.visible-chars',
74
+ actual >= contract.minChars && actual <= contract.maxChars,
75
+ `非空白 Unicode 字符:${actual}`,
76
+ `用户要求 ${contract.minChars}-${contract.maxChars} 个非空白字符`,
77
+ actual < contract.minChars
78
+ ? '只扩写既有情节点的行动、后果或对话,不新增支线。'
79
+ : '只压缩重复解释、复述和无功能过场,不删关键证据或结算。'
80
+ ))
81
+
82
+ const lines = bodyRead.text.replace(/\r\n?/g, '\n').replace(/\n+$/, '\n').split('\n')
83
+ const markers = lines
84
+ .map((line, index) => ({ line: index + 1, marker: markerFor(line), text: line.trim() }))
85
+ .filter((entry) => entry.marker)
86
+ checks.push(makeCheck(
87
+ 'delivery.section-count',
88
+ markers.length === contract.sections,
89
+ `识别到 ${markers.length} 个小节标记:${markers.map((entry) => entry.text).join('、') || '无'}`,
90
+ `正文恰好 ${contract.sections} 节`,
91
+ '只校正缺失、多余或误写的小节标记;不要为凑节数新开支线。'
92
+ ))
93
+
94
+ const styles = new Set(markers.map((entry) => entry.marker.style))
95
+ checks.push(makeCheck(
96
+ 'delivery.section-style',
97
+ markers.length > 0 && styles.size === 1,
98
+ markers.length ? `小节标记样式:${Array.from(styles).join('、')}` : '没有可识别的小节标记',
99
+ '全文统一使用 short-format.md 允许的一种小节标记',
100
+ '只统一小节标记的样式,不改正文内容。'
101
+ ))
102
+
103
+ const numericSequence = markers.map((entry) => {
104
+ const match = entry.text.match(/\d+/)
105
+ return match ? Number(match[0]) : null
106
+ })
107
+ const sequenceOk = markers.length > 0 && (
108
+ numericSequence.every((number) => number !== null)
109
+ ? numericSequence.every((number, index) => number === index + 1)
110
+ : new Set(markers.map((entry) => entry.text)).size === markers.length
111
+ )
112
+ checks.push(makeCheck(
113
+ 'delivery.section-sequence',
114
+ sequenceOk,
115
+ `小节序列:${markers.map((entry) => entry.text).join('、') || '无'}`,
116
+ '数字小节从 1 连续递增;中文章名不得重复',
117
+ '只修正小节标记编号,不改正文内容。'
118
+ ))
119
+
120
+ const markerLines = new Set(markers.map((entry) => entry.line - 1))
121
+ const invalidBlankLines = []
122
+ for (let index = 0; index < lines.length; index++) {
123
+ if (lines[index].trim() !== '') continue
124
+ const isEdge = index === 0 || index === lines.length - 1
125
+ const touchesMarker = markerLines.has(index - 1) || markerLines.has(index + 1)
126
+ if (!isEdge && !touchesMarker) invalidBlankLines.push(index + 1)
127
+ }
128
+ checks.push(makeCheck(
129
+ 'delivery.blank-lines',
130
+ invalidBlankLines.length === 0,
131
+ invalidBlankLines.length ? `正文段落间空行:${invalidBlankLines.join('、')}` : '正文段落间无空行',
132
+ '只允许文件边缘或小节标记相邻处出现空行,正文段落之间紧密单换行',
133
+ '只删除报告行的多余空行。'
134
+ ))
135
+
136
+ return report(project, contract, checks)
137
+ }
138
+
139
+ function report(project, contract, checks) {
140
+ const failures = checks.filter((check) => !check.ok)
141
+ return {
142
+ schema_version: 1,
143
+ verifier: 'story-short-write.delivery-contract',
144
+ project,
145
+ contract: {
146
+ metric: 'non_whitespace_unicode_chars_v1',
147
+ min_chars: contract.minChars,
148
+ max_chars: contract.maxChars,
149
+ sections: contract.sections,
150
+ },
151
+ ok: failures.length === 0,
152
+ checks,
153
+ failures,
154
+ repair_scope: failures.map((failure) => ({
155
+ id: failure.id,
156
+ file: failure.file,
157
+ evidence: failure.evidence,
158
+ expected: failure.expected,
159
+ references: failure.references,
160
+ repair: failure.repair,
161
+ })),
162
+ }
163
+ }
164
+
165
+ function parsePositiveInteger(value) {
166
+ if (!/^[1-9]\d*$/.test(value || '')) return null
167
+ const number = Number(value)
168
+ return Number.isSafeInteger(number) ? number : null
169
+ }
170
+
171
+ function parseArgs(argv) {
172
+ const values = {}
173
+ const positional = []
174
+ for (let index = 0; index < argv.length; index++) {
175
+ const arg = argv[index]
176
+ if (arg === '--json') continue
177
+ if (['--min-chars', '--max-chars', '--sections'].includes(arg)) {
178
+ if (index + 1 >= argv.length || argv[index + 1].startsWith('--')) return null
179
+ values[arg] = parsePositiveInteger(argv[++index])
180
+ if (values[arg] === null) return null
181
+ continue
182
+ }
183
+ if (arg.startsWith('--')) return null
184
+ positional.push(arg)
185
+ }
186
+ if (positional.length > 1) return null
187
+ if (!values['--min-chars'] || !values['--max-chars'] || !values['--sections']) return null
188
+ if (values['--min-chars'] > values['--max-chars']) return null
189
+ return {
190
+ project: positional[0] || '.',
191
+ contract: {
192
+ minChars: values['--min-chars'],
193
+ maxChars: values['--max-chars'],
194
+ sections: values['--sections'],
195
+ },
196
+ }
197
+ }
198
+
199
+ function main(argv) {
200
+ const parsed = parseArgs(argv)
201
+ if (!parsed) {
202
+ process.stderr.write('用法: node scripts/check-delivery-contract.js --json --min-chars N --max-chars N --sections N [project-dir]\n')
203
+ return 2
204
+ }
205
+ const result = verify(parsed.project, parsed.contract)
206
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`)
207
+ return result.ok ? 0 : 1
208
+ }
209
+
210
+ if (require.main === module) process.exitCode = main(process.argv.slice(2))
211
+
212
+ module.exports = { markerFor, visibleChars, verify }
@@ -0,0 +1,363 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Phase 2 deterministic contract verifier for story-short-write.
4
+ *
5
+ * This script is intentionally mechanical: it checks whether the two Phase 2
6
+ * artifacts expose the fields and table shape required by the skill. It does
7
+ * not pretend to judge story quality or whether a reference was genuinely
8
+ * understood.
9
+ *
10
+ * Usage: node scripts/check-phase2-contract.js --json [project-dir]
11
+ * Exit: 0 = pass, 1 = blocking contract failures, 2 = invalid invocation.
12
+ */
13
+
14
+ 'use strict'
15
+
16
+ const fs = require('fs')
17
+ const path = require('path')
18
+
19
+ const OUTLINE_HEADERS = [
20
+ '结构段/五段功能',
21
+ '主事件',
22
+ '情节推进',
23
+ '情绪',
24
+ '人物/关系变化',
25
+ '因果/逻辑链',
26
+ '读者新获知什么',
27
+ '结尾承接/钩子',
28
+ '伏笔/物件',
29
+ '场景形态',
30
+ '对白作用',
31
+ '目标字数',
32
+ ]
33
+
34
+ const LEGACY_OUTLINE_HEADERS = new Map([
35
+ [2, '子事件×3-5'],
36
+ [9, '动静'],
37
+ [10, '对话密度'],
38
+ ])
39
+
40
+ const FUNCTION_TAG = /\{(?:对话|冲突|伏笔|回忆|发现|递进)\}/
41
+
42
+ function cleanCell(value) {
43
+ return value.replace(/\*\*/g, '').replace(/`/g, '').trim()
44
+ }
45
+
46
+ function parseTableLine(line) {
47
+ const trimmed = line.trim()
48
+ if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) return null
49
+ return trimmed.slice(1, -1).split('|').map(cleanCell)
50
+ }
51
+
52
+ function isSeparatorRow(cells) {
53
+ return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell))
54
+ }
55
+
56
+ function readUtf8(file) {
57
+ try {
58
+ const text = fs.readFileSync(file, 'utf8').replace(/^\uFEFF/, '')
59
+ return { ok: text.trim().length > 0, text }
60
+ } catch (error) {
61
+ return { ok: false, text: '', error: error.message }
62
+ }
63
+ }
64
+
65
+ function makeCheck(id, ok, file, evidence, expected, references, repair) {
66
+ return { id, ok, severity: 'blocking', file, evidence, expected, references, repair }
67
+ }
68
+
69
+ function verify(projectDir) {
70
+ const project = path.resolve(projectDir)
71
+ const skillRoot = path.resolve(__dirname, '..')
72
+ const settingsFile = path.join(project, '设定.md')
73
+ const outlineFile = path.join(project, '小节大纲.md')
74
+ const settingsRead = readUtf8(settingsFile)
75
+ const outlineRead = readUtf8(outlineFile)
76
+ const checks = []
77
+
78
+ checks.push(makeCheck(
79
+ 'phase2.settings-readable',
80
+ settingsRead.ok,
81
+ '设定.md',
82
+ settingsRead.ok ? '文件存在且非空' : (settingsRead.error || '文件为空'),
83
+ '项目目录下存在非空的 设定.md',
84
+ ['references/writing-workflow.md'],
85
+ '只补建或补全 设定.md,不改动已通过的 小节大纲.md。'
86
+ ))
87
+ checks.push(makeCheck(
88
+ 'phase2.outline-readable',
89
+ outlineRead.ok,
90
+ '小节大纲.md',
91
+ outlineRead.ok ? '文件存在且非空' : (outlineRead.error || '文件为空'),
92
+ '项目目录下存在非空的 小节大纲.md',
93
+ ['references/writing-workflow.md'],
94
+ '只补建或补全 小节大纲.md,不改动已通过的 设定.md。'
95
+ ))
96
+
97
+ if (!settingsRead.ok || !outlineRead.ok) return report(project, checks)
98
+
99
+ const settings = settingsRead.text
100
+ const outline = outlineRead.text
101
+
102
+ const platformMatch = settings.match(/目标平台\s*[::]\s*(知乎(?:盐选)?|小程序|番茄(?:短篇)?)/)
103
+ checks.push(makeCheck(
104
+ 'phase2.platform-declared',
105
+ Boolean(platformMatch),
106
+ '设定.md',
107
+ platformMatch ? `目标平台:${platformMatch[1]}` : '未找到可识别的目标平台字段',
108
+ '写明“目标平台:知乎盐选 / 小程序 / 番茄短篇”之一',
109
+ ['references/submission-craft.md'],
110
+ '只在 设定.md 的基本信息或 Phase 2 设计校验区补目标平台。'
111
+ ))
112
+
113
+ const genreMatch = settings.match(/(?:题材参考|题材包)\s*[::]\s*`?(references\/(?:genre-styles\/[^`\s|]+\.md|genre-writing-formulas\.md))`?/)
114
+ let genreEvidence = '未找到题材参考路径'
115
+ let genreOk = false
116
+ if (genreMatch) {
117
+ const resolved = path.resolve(skillRoot, genreMatch[1])
118
+ const insideSkill = resolved.startsWith(`${skillRoot}${path.sep}`)
119
+ genreOk = insideSkill && fs.existsSync(resolved) && fs.statSync(resolved).isFile()
120
+ genreEvidence = genreOk ? `题材参考:${genreMatch[1]}` : `题材参考不可读:${genreMatch[1]}`
121
+ }
122
+ checks.push(makeCheck(
123
+ 'phase2.genre-reference-declared',
124
+ genreOk,
125
+ '设定.md',
126
+ genreEvidence,
127
+ '写明一个真实存在的 references/genre-styles/{题材}.md;冷门题材写 references/genre-writing-formulas.md',
128
+ ['references/writing-workflow.md', 'references/short-craft.md'],
129
+ '只补题材参考路径与从该参考选出的 2-3 个核心招式,不重写故事框架。'
130
+ ))
131
+
132
+ const movesMatch = settings.match(/核心招式\s*[::]\s*([^\n]+)/)
133
+ const moves = movesMatch
134
+ ? movesMatch[1].split(/[;;]|\s\/\s/).map((item) => item.trim()).filter(Boolean)
135
+ : []
136
+ checks.push(makeCheck(
137
+ 'phase2.genre-moves-declared',
138
+ moves.length >= 2 && moves.length <= 3,
139
+ '设定.md',
140
+ moves.length ? `识别到 ${moves.length} 个核心招式` : '未找到核心招式字段',
141
+ '“核心招式:招式一;招式二[;招式三]”,共 2-3 个',
142
+ ['references/writing-workflow.md'],
143
+ '只补或收敛核心招式字段到 2-3 个,并保持已选题材参考不变。'
144
+ ))
145
+
146
+ const villainSkipped = /反派(?:设计)?\s*[::]\s*(?:无|不适用)\s*[((][^))]+[))]/.test(settings)
147
+ const villainFields = ['身份', '动机', '作恶方式', '致命弱点', '报应']
148
+ const missingVillainFields = villainFields.filter((field) => !new RegExp(`(?:^|\\n)\\s*[-*]?\\s*${field}\\s*[::]`, 'm').test(settings))
149
+ const villainOk = villainSkipped || missingVillainFields.length === 0
150
+ checks.push(makeCheck(
151
+ 'phase2.villain-contract',
152
+ villainOk,
153
+ '设定.md',
154
+ villainSkipped ? '已明确反派不适用' : (villainOk ? '反派五字段齐全' : `缺字段:${missingVillainFields.join('、')}`),
155
+ '无反派时写“反派设计:不适用(原因)”;有反派时填写身份、动机、作恶方式、致命弱点、报应',
156
+ ['references/villain-and-reveal.md'],
157
+ '只补反派缺失字段;若确无反派,改为带原因的不适用声明。'
158
+ ))
159
+
160
+ const placeholderFields = ['题材参考', '核心招式', '反派设计', '反转类型', '反转位置', '付费点', '目标平台', '目标字数']
161
+ const placeholderLines = settings.split(/\r?\n/)
162
+ .map((line, index) => ({ line: index + 1, text: line }))
163
+ .filter((entry) => placeholderFields.some((field) => entry.text.includes(`${field}:`) || entry.text.includes(`${field}:`)))
164
+ .filter((entry) => /\{[^}]*\}/.test(entry.text))
165
+ checks.push(makeCheck(
166
+ 'phase2.no-template-placeholders',
167
+ placeholderLines.length === 0,
168
+ '设定.md',
169
+ placeholderLines.length ? `仍是模板占位符的行:${placeholderLines.map((entry) => entry.line).join('、')}` : '契约字段没有未填写的 {} 占位符',
170
+ 'Phase 2 契约字段写实际设计内容,不保留 {} 模板占位符',
171
+ ['references/writing-workflow.md'],
172
+ '只把报告行的占位符替换成本篇的实际设计,不重写其他字段。'
173
+ ))
174
+
175
+ const lines = outline.split(/\r?\n/)
176
+ let headerAt = -1
177
+ let headerCells = null
178
+ for (let index = 0; index < lines.length; index++) {
179
+ const cells = parseTableLine(lines[index])
180
+ if (cells && cells[0] === OUTLINE_HEADERS[0]) {
181
+ headerAt = index
182
+ headerCells = cells
183
+ break
184
+ }
185
+ }
186
+ const currentHeader = Boolean(headerCells) && headerCells.length === OUTLINE_HEADERS.length &&
187
+ headerCells.every((cell, index) => cell === OUTLINE_HEADERS[index])
188
+ const legacyHeader = Boolean(headerCells) && headerCells.length === OUTLINE_HEADERS.length &&
189
+ headerCells.every((cell, index) => cell === (LEGACY_OUTLINE_HEADERS.get(index) || OUTLINE_HEADERS[index]))
190
+ const headerOk = currentHeader || legacyHeader
191
+ checks.push(makeCheck(
192
+ 'phase2.outline-12-columns',
193
+ headerOk,
194
+ '小节大纲.md',
195
+ headerCells
196
+ ? `表头 ${headerCells.length} 列:${headerCells.join(' | ')}${legacyHeader ? '(兼容旧项目;新建项目使用现行列名)' : ''}`
197
+ : '未找到以“结构段/五段功能”开头的 Markdown 表格',
198
+ `使用固定 12 列表头:${OUTLINE_HEADERS.join(' | ')}`,
199
+ ['references/writing-workflow.md'],
200
+ '只修表头和错位单元格,不改动各节已经成立的剧情内容。'
201
+ ))
202
+
203
+ const rows = []
204
+ if (headerAt >= 0) {
205
+ for (let index = headerAt + 1; index < lines.length; index++) {
206
+ const cells = parseTableLine(lines[index])
207
+ if (!cells) {
208
+ if (rows.length) break
209
+ continue
210
+ }
211
+ if (isSeparatorRow(cells)) continue
212
+ rows.push({ line: index + 1, cells })
213
+ }
214
+ }
215
+ const rowShapeFailures = rows.filter((row) => row.cells.length !== OUTLINE_HEADERS.length)
216
+ checks.push(makeCheck(
217
+ 'phase2.outline-data-rows',
218
+ rows.length > 0 && rowShapeFailures.length === 0,
219
+ '小节大纲.md',
220
+ rows.length === 0 ? '固定表头下没有数据行' : (rowShapeFailures.length ? `列数错误行:${rowShapeFailures.map((row) => row.line).join('、')}` : `识别到 ${rows.length} 节,均为 12 列`),
221
+ '固定表头下至少一行数据,且每节恰好 12 列',
222
+ ['references/writing-workflow.md'],
223
+ '只补缺失节或修复报告行的列错位。'
224
+ ))
225
+
226
+ const progressionFailures = []
227
+ const progressionRows = rows.filter((item) => item.cells.length === OUTLINE_HEADERS.length)
228
+ for (const row of progressionRows) {
229
+ const progression = row.cells[2].split(/\s*(?:->|→)\s*/).filter(Boolean)
230
+ if (progression.length < 1 || progression.some((item) => !FUNCTION_TAG.test(item))) {
231
+ progressionFailures.push(row.line)
232
+ }
233
+ }
234
+ checks.push(makeCheck(
235
+ 'phase2.outline-subevents',
236
+ rows.length > 0 && progressionFailures.length === 0,
237
+ '小节大纲.md',
238
+ progressionFailures.length
239
+ ? `情节推进为空或功能标签错误行:${progressionFailures.join('、')}`
240
+ : (progressionRows.length === rows.length
241
+ ? `所有 ${rows.length} 节均有至少一个带功能标签的真实推进`
242
+ : `已检查 ${progressionRows.length}/${rows.length} 行;其余行由 phase2.outline-data-rows 报告列错位`),
243
+ '每节至少一个真实推进;有先后关系时以 -> 连接,每个含 {对话/冲突/伏笔/回忆/发现/递进} 标签之一,不设固定数量',
244
+ ['references/writing-workflow.md', 'references/short-craft.md'],
245
+ '只修报告行的“情节推进”单元格,不重写其他列或其他节;不要为数量补事件。'
246
+ ))
247
+
248
+ const targetMatch = settings.match(/目标字数\s*[::]\s*(?:约\s*)?([\d,,]+)\s*(?:字)?\s*(?:[-–—~~]|到|至)\s*([\d,,]+)\s*字?/) ||
249
+ settings.match(/目标字数\s*[::]\s*(?:约\s*)?([\d,,]+)\s*字?/)
250
+ const toNumber = (value) => Number(String(value).replace(/[,,]/g, ''))
251
+ const targetLow = targetMatch ? toNumber(targetMatch[1]) : null
252
+ const targetHigh = targetMatch && targetMatch[2] !== undefined ? toNumber(targetMatch[2]) : targetLow
253
+ const statedTarget = targetLow
254
+ const rowTargets = progressionRows.map((row) => {
255
+ const match = row.cells[11].match(/([\d,,]+)/)
256
+ return match ? Number(match[1].replace(/[,,]/g, '')) : null
257
+ })
258
+ const targetSum = rowTargets.every((value) => Number.isFinite(value))
259
+ ? rowTargets.reduce((sum, value) => sum + value, 0)
260
+ : null
261
+ const isRange = targetHigh !== null && targetHigh !== targetLow
262
+ const targetOk = statedTarget !== null && statedTarget >= 1000 && targetHigh <= 200000 &&
263
+ targetHigh >= targetLow && progressionRows.length === rows.length && targetSum !== null &&
264
+ (isRange
265
+ ? targetSum >= targetLow && targetSum <= targetHigh
266
+ : Math.abs(targetSum - statedTarget) <= statedTarget * 0.05)
267
+ checks.push(makeCheck(
268
+ 'phase2.target-word-sum',
269
+ targetOk,
270
+ '设定.md、小节大纲.md',
271
+ `设定目标:${statedTarget === null ? '未识别' : (isRange ? `${targetLow}-${targetHigh}` : statedTarget)};大纲合计:${targetSum === null ? '有非数字目标字数' : targetSum}`,
272
+ '设定.md 的目标字数为 1000-200000 的正整数或区间(用户明确范围优先,未指定时默认 8000-20000);大纲每行目标字数可解析,写区间时合计落在区间内,写单值时误差不超过 5%',
273
+ ['references/writing-workflow.md', 'references/submission-craft.md'],
274
+ '只修目标字数字段或各节“目标字数”单元格,使合计匹配;不要用增删剧情绕过数字错误。'
275
+ ))
276
+
277
+ const reversalMatch = settings.match(/反转位置\s*[::]\s*第?\s*(\d+)\s*节?\s*(?:÷|\/)\s*(?:共|全文)?\s*(\d+)\s*节?\s*=\s*(\d+(?:\.\d+)?)\s*%/)
278
+ const noReversal = /反转类型\s*[::]\s*无反转/.test(settings) &&
279
+ /反转位置\s*[::]\s*不适用\s*[((][^))]+[))]/.test(settings)
280
+ let reversalOk = false
281
+ let reversalEvidence = '未找到“反转位置:第 X 节 ÷ 共 Y 节 = Z%”'
282
+ if (noReversal) {
283
+ reversalOk = true
284
+ reversalEvidence = '反转类型为无反转,位置已带原因标为不适用'
285
+ } else if (reversalMatch) {
286
+ const reveal = Number(reversalMatch[1])
287
+ const total = Number(reversalMatch[2])
288
+ const stated = Number(reversalMatch[3])
289
+ const calculated = total > 0 ? (reveal / total) * 100 : NaN
290
+ reversalOk = reveal >= 1 && reveal <= total && total === rows.length &&
291
+ Math.abs(stated - calculated) <= 0.6
292
+ reversalEvidence = `声明第 ${reveal} 节 ÷ 共 ${total} 节 = ${stated}%;大纲识别 ${rows.length} 节`
293
+ }
294
+ checks.push(makeCheck(
295
+ 'phase2.reversal-position',
296
+ reversalOk,
297
+ '设定.md',
298
+ reversalEvidence,
299
+ '有反转时写明揭穿节号、全文总节数和计算百分比;总节数须与大纲一致,计算误差不超过 0.6%。无反转时写明“反转类型:无反转”和带原因的“反转位置:不适用(…)”',
300
+ ['references/writing-workflow.md', 'references/short-reversal.md'],
301
+ '只修正反转位置计算或对应节次;位置质量按 short-reversal.md 的误判决策与揭示后果功能链判断,不为跨过固定百分比而搬节。'
302
+ ))
303
+
304
+ const paywallMatch = settings.match(/付费点\s*[::]\s*第?\s*(\d+)\s*节末/)
305
+ const paywallSection = paywallMatch ? Number(paywallMatch[1]) : null
306
+ const paywallRows = rows
307
+ .map((row, index) => ({ section: index + 1, hook: row.cells[7] || '' }))
308
+ .filter((row) => /付费点/.test(row.hook))
309
+ const paywallOk = paywallSection !== null && paywallRows.length === 1 &&
310
+ paywallRows[0].section === paywallSection
311
+ let paywallEvidence = '设定.md 未按“付费点:第 X 节末”声明'
312
+ if (paywallSection !== null && paywallRows.length === 0) {
313
+ paywallEvidence = `设定.md 声明第 ${paywallSection} 节末;大纲“结尾承接/钩子”列未标出付费点`
314
+ } else if (paywallSection !== null && paywallRows.length > 0) {
315
+ paywallEvidence = `设定.md 声明第 ${paywallSection} 节末;大纲标在第 ${paywallRows.map((row) => row.section).join('、')} 节`
316
+ }
317
+ checks.push(makeCheck(
318
+ 'phase2.paywall-in-both',
319
+ paywallOk,
320
+ '设定.md、小节大纲.md',
321
+ paywallEvidence,
322
+ '设定.md 写“付费点:第 X 节末”,且小节大纲.md 第 X 行数据的“结尾承接/钩子”单元格只标一次“付费点”',
323
+ ['references/submission-craft.md', 'references/writing-workflow.md'],
324
+ '只在缺失的文件补同一个付费断点,并确保它位于对应节末的钩子单元格。'
325
+ ))
326
+
327
+ return report(project, checks)
328
+ }
329
+
330
+ function report(project, checks) {
331
+ const failures = checks.filter((check) => !check.ok)
332
+ return {
333
+ schema_version: 1,
334
+ verifier: 'story-short-write.phase2-contract',
335
+ project,
336
+ ok: failures.length === 0,
337
+ checks,
338
+ failures,
339
+ repair_scope: failures.map((failure) => ({
340
+ id: failure.id,
341
+ file: failure.file,
342
+ evidence: failure.evidence,
343
+ expected: failure.expected,
344
+ references: failure.references,
345
+ repair: failure.repair,
346
+ })),
347
+ }
348
+ }
349
+
350
+ function main(argv) {
351
+ const args = argv.filter((arg) => arg !== '--json')
352
+ if (args.length > 1 || args.some((arg) => arg.startsWith('--'))) {
353
+ process.stderr.write('用法: node scripts/check-phase2-contract.js --json [project-dir]\n')
354
+ return 2
355
+ }
356
+ const result = verify(args[0] || '.')
357
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`)
358
+ return result.ok ? 0 : 1
359
+ }
360
+
361
+ if (require.main === module) process.exitCode = main(process.argv.slice(2))
362
+
363
+ module.exports = { OUTLINE_HEADERS, verify }