@oh-story/dsh 0.1.4 → 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 (479) hide show
  1. package/README.md +56 -12
  2. package/lib/client.js +2692 -268
  3. package/lib/client.js.map +4 -4
  4. package/lib/drama/manifest.json +136 -101
  5. package/lib/drama/skills/short-drama/SKILL.md +61 -1
  6. package/lib/drama/skills/short-drama/references/contract-and-ownership.md +7 -4
  7. package/lib/drama/skills/short-drama/references/creator-documents.md +133 -8
  8. package/lib/drama/skills/short-drama/references/creator-workflow.md +38 -2
  9. package/lib/drama/skills/short-drama/references/knowhow-index.md +3 -0
  10. package/lib/drama/skills/short-drama/references/reference-roles.md +10 -7
  11. package/lib/drama/skills/short-drama/references/runtime-preflight.md +3 -0
  12. package/lib/drama/skills/short-drama/scripts/creator_markdown_check.py +1002 -0
  13. package/lib/drama/skills/short-drama/scripts/project_tool.py +485 -5
  14. package/lib/drama/skills/short-drama-assets/SKILL.md +13 -3
  15. package/lib/drama/skills/short-drama-assets/references/continuity-lock.md +116 -0
  16. package/lib/drama/skills/short-drama-assets/references/identity-vs-variant.md +2 -1
  17. package/lib/drama/skills/short-drama-assets/references/prop-and-state.md +19 -0
  18. package/lib/drama/skills/short-drama-assets/references/stage-contract.md +2 -0
  19. package/lib/drama/skills/short-drama-assets/scripts/asset_check.py +1 -1
  20. package/lib/drama/skills/short-drama-image-prompts/SKILL.md +6 -2
  21. package/lib/drama/skills/short-drama-image-prompts/references/common-recipe.md +4 -3
  22. package/lib/drama/skills/short-drama-image-prompts/references/lookdev-frame.md +1 -1
  23. package/lib/drama/skills/short-drama-image-prompts/references/review-and-fixtures.md +1 -1
  24. package/lib/drama/skills/short-drama-image-prompts/references/stage-contract.md +3 -1
  25. package/lib/drama/skills/short-drama-image-prompts/scripts/image_prompt_check.py +8 -8
  26. package/lib/drama/skills/short-drama-image-prompts/scripts/selftest.py +4 -2
  27. package/lib/drama/skills/short-drama-produce/SKILL.md +46 -10
  28. package/lib/drama/skills/short-drama-produce/references/adapter-contract.md +65 -8
  29. package/lib/drama/skills/short-drama-produce/references/providers/minimax-h3-video.md +85 -0
  30. package/lib/drama/skills/short-drama-produce/references/providers/seedance.md +27 -10
  31. package/lib/drama/skills/short-drama-produce/scripts/production_tool.py +362 -3
  32. package/lib/drama/skills/short-drama-produce/scripts/provider_adapters.py +627 -40
  33. package/lib/drama/skills/short-drama-produce/scripts/selftest.py +5 -4
  34. package/lib/drama/skills/short-drama-review/references/rubric-visual-motion.md +12 -0
  35. package/lib/drama/skills/short-drama-review/scripts/review_check.py +1 -1
  36. package/lib/drama/skills/short-drama-storyboard/SKILL.md +76 -7
  37. package/lib/drama/skills/short-drama-storyboard/assets/shot-template.jsonl +1 -1
  38. package/lib/drama/skills/short-drama-storyboard/references/keyframe-craft.md +6 -2
  39. package/lib/drama/skills/short-drama-storyboard/references/production-shot-grammar.md +19 -4
  40. package/lib/drama/skills/short-drama-storyboard/references/review-and-fixtures.md +5 -2
  41. package/lib/drama/skills/short-drama-storyboard/references/screenplay-to-keyframe-example.md +16 -0
  42. package/lib/drama/skills/short-drama-storyboard/references/stage-contract.md +8 -3
  43. package/lib/drama/skills/short-drama-storyboard/scripts/storyboard_check.py +1 -1
  44. package/lib/drama/skills/short-drama-video-prompts/SKILL.md +81 -13
  45. package/lib/drama/skills/short-drama-video-prompts/assets/motion-spec.jsonl.md +6 -1
  46. package/lib/drama/skills/short-drama-video-prompts/assets/video-prompts.md +17 -1
  47. package/lib/drama/skills/short-drama-video-prompts/references/delivery-profile.md +21 -1
  48. package/lib/drama/skills/short-drama-video-prompts/references/minimax-h3.md +154 -0
  49. package/lib/drama/skills/short-drama-video-prompts/references/motion-recipe.md +24 -6
  50. package/lib/drama/skills/short-drama-video-prompts/references/production-prompt-grammar.md +11 -7
  51. package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.0.md +41 -0
  52. package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.5.md +66 -0
  53. package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +5 -2
  54. package/lib/drama/skills/short-drama-video-prompts/references/target-model-profile.md +115 -0
  55. package/lib/drama/skills/short-drama-video-prompts/scripts/container_check.py +1 -1
  56. package/lib/drama/skills/short-drama-video-prompts/scripts/music_spec_check.py +1 -1
  57. package/lib/drama/skills/short-drama-write/SKILL.md +3 -2
  58. package/lib/drama/skills/short-drama-write/scripts/duration_estimate.py +1 -1
  59. package/lib/drama/skills/short-drama-write/scripts/screenplay_index.py +2 -2
  60. package/lib/drama/skills/short-drama-write/scripts/voice_sheet_check.py +1 -1
  61. package/lib/index.js +865 -33
  62. package/lib/index.js.map +4 -4
  63. package/lib/novel-to-game/LICENSE +21 -0
  64. package/lib/novel-to-game/README.md +180 -0
  65. package/lib/novel-to-game/README_ZH.md +178 -0
  66. package/lib/novel-to-game/VERSION +1 -0
  67. package/lib/novel-to-game/examples/jin-ping-mei/build/BUILD_BRIEF.md +217 -0
  68. package/lib/novel-to-game/examples/jin-ping-mei/build/app/.vercelignore +3 -0
  69. package/lib/novel-to-game/examples/jin-ping-mei/build/app/RUN.md +130 -0
  70. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/compound_new_guofeng.webp +0 -0
  71. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/finale/fate_coda.webp +0 -0
  72. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/finale/meng.webp +0 -0
  73. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/finale/pan.webp +0 -0
  74. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/finale/pinger.webp +0 -0
  75. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/finale/xuee.webp +0 -0
  76. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/finale/yue.webp +0 -0
  77. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/inner_court_accord_five.webp +0 -0
  78. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/inner_court_afterglow_five.webp +0 -0
  79. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/inner_court_alliance.webp +0 -0
  80. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/public_day10.webp +0 -0
  81. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/public_day15.webp +0 -0
  82. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/public_day5.webp +0 -0
  83. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/title_new_guofeng.webp +0 -0
  84. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/joint/pan_pinger.webp +0 -0
  85. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/joint/pan_xuee.webp +0 -0
  86. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/joint/yue_meng.webp +0 -0
  87. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/joint/yue_pan.webp +0 -0
  88. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/joint/yue_pinger.webp +0 -0
  89. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/meng/explicit.webp +0 -0
  90. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/meng/prelude.webp +0 -0
  91. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/milestone/meng.webp +0 -0
  92. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/milestone/pan.webp +0 -0
  93. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/milestone/pinger.webp +0 -0
  94. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/milestone/xuee.webp +0 -0
  95. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/milestone/yue.webp +0 -0
  96. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/pan/explicit.webp +0 -0
  97. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/pan/prelude.webp +0 -0
  98. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/pinger/explicit.webp +0 -0
  99. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/pinger/prelude.webp +0 -0
  100. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/xuee/explicit.webp +0 -0
  101. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/xuee/prelude.webp +0 -0
  102. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/yue/explicit.webp +0 -0
  103. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/yue/prelude.webp +0 -0
  104. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/heroine/meng/night.webp +0 -0
  105. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/heroine/pan/night.webp +0 -0
  106. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/heroine/pinger/night.webp +0 -0
  107. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/heroine/xuee/night.webp +0 -0
  108. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/heroine/yue/night.webp +0 -0
  109. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/household/li_jiaoer.webp +0 -0
  110. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/scene/gate_collector.webp +0 -0
  111. package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/new-guofeng.css +1105 -0
  112. package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/style.css +2539 -0
  113. package/lib/novel-to-game/examples/jin-ping-mei/build/app/index.html +18 -0
  114. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/assets.js +147 -0
  115. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/audio.js +332 -0
  116. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/data.js +7472 -0
  117. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/engine.js +13077 -0
  118. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/main.js +3028 -0
  119. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/text.js +32 -0
  120. package/lib/novel-to-game/examples/jin-ping-mei/build/app/package.json +10 -0
  121. package/lib/novel-to-game/examples/jin-ping-mei/build/app/vercel.json +23 -0
  122. package/lib/novel-to-game/examples/jin-ping-mei/build/art/generated-art.json +161 -0
  123. package/lib/novel-to-game/examples/jin-ping-mei/example.json +12 -0
  124. package/lib/novel-to-game/examples/jin-ping-mei/qa/README.md +31 -0
  125. package/lib/novel-to-game/examples/jin-ping-mei/qa/playable-model.json +99 -0
  126. package/lib/novel-to-game/examples/jin-ping-mei/qa/verification.json +41 -0
  127. package/lib/novel-to-game/examples/jin-ping-mei/qa/verify_playable_model.mjs +129 -0
  128. package/lib/novel-to-game/manifest.json +508 -0
  129. package/lib/novel-to-game/skills/game-art-direction/SKILL.md +73 -0
  130. package/lib/novel-to-game/skills/game-art-direction/agents/openai.yaml +4 -0
  131. package/lib/novel-to-game/skills/game-art-direction/references/art-direction-method.md +119 -0
  132. package/lib/novel-to-game/skills/game-build/SKILL.md +84 -0
  133. package/lib/novel-to-game/skills/game-build/agents/openai.yaml +4 -0
  134. package/lib/novel-to-game/skills/game-build/references/build-brief-contract.md +109 -0
  135. package/lib/novel-to-game/skills/game-build/references/generative-media-pipeline.md +56 -0
  136. package/lib/novel-to-game/skills/game-build/references/playable-model-contract.md +81 -0
  137. package/lib/novel-to-game/skills/game-build/references/tts-production-contract.md +37 -0
  138. package/lib/novel-to-game/skills/game-concept/SKILL.md +72 -0
  139. package/lib/novel-to-game/skills/game-concept/agents/openai.yaml +4 -0
  140. package/lib/novel-to-game/skills/game-concept/references/concept-method.md +94 -0
  141. package/lib/novel-to-game/skills/game-qa/SKILL.md +50 -0
  142. package/lib/novel-to-game/skills/game-qa/agents/openai.yaml +4 -0
  143. package/lib/novel-to-game/skills/game-qa/references/qa-contract.md +66 -0
  144. package/lib/novel-to-game/skills/game-qa/references/test-design-method.md +45 -0
  145. package/lib/novel-to-game/skills/game-world-design/SKILL.md +63 -0
  146. package/lib/novel-to-game/skills/game-world-design/agents/openai.yaml +4 -0
  147. package/lib/novel-to-game/skills/game-world-design/references/dialogue-design-method.md +59 -0
  148. package/lib/novel-to-game/skills/game-world-design/references/game-writing-craft.md +53 -0
  149. package/lib/novel-to-game/skills/game-world-design/references/narrative-design-method.md +84 -0
  150. package/lib/novel-to-game/skills/game-world-design/references/numeric-design-method.md +56 -0
  151. package/lib/novel-to-game/skills/game-world-design/references/world-design-method.md +124 -0
  152. package/lib/novel-to-game/skills/novel-game-analyze/SKILL.md +77 -0
  153. package/lib/novel-to-game/skills/novel-game-analyze/agents/openai.yaml +4 -0
  154. package/lib/novel-to-game/skills/novel-game-analyze/references/gameability-protocol.md +65 -0
  155. package/lib/novel-to-game/skills/novel-to-game/SKILL.md +71 -0
  156. package/lib/novel-to-game/skills/novel-to-game/agents/openai.yaml +4 -0
  157. package/lib/novel-to-game/skills/novel-to-game/references/intake-benchmark-reference.md +42 -0
  158. package/lib/novel-to-game/skills/novel-to-game/references/intake-method.md +51 -0
  159. package/lib/novel-to-game/skills/novel-to-game/references/pipeline-contract.md +65 -0
  160. package/lib/oh-story/manifest.json +415 -305
  161. package/lib/oh-story/roles/consistency-checker.md +1 -1
  162. package/lib/oh-story/roles/narrative-writer.md +32 -33
  163. package/lib/oh-story/roles/story-architect.md +16 -26
  164. package/lib/oh-story/skills/browser-cdp/SKILL.md +1 -1
  165. package/lib/oh-story/skills/story/SKILL.md +16 -9
  166. package/lib/oh-story/skills/story/VERSION +1 -1
  167. package/lib/oh-story/skills/story/references/author-memory.md +163 -0
  168. package/lib/oh-story/skills/story/scripts/author_memory_commit.py +871 -0
  169. package/lib/oh-story/skills/story-cover/SKILL.md +1 -1
  170. package/lib/oh-story/skills/story-deslop/SKILL.md +10 -5
  171. package/lib/oh-story/skills/story-deslop/references/anti-ai-writing.md +2 -1
  172. package/lib/oh-story/skills/story-deslop/references/author-memory.md +163 -0
  173. package/lib/oh-story/skills/story-deslop/references/banned-words.md +6 -4
  174. package/lib/oh-story/skills/story-deslop/scripts/author_memory_commit.py +871 -0
  175. package/lib/oh-story/skills/story-deslop/scripts/check-ai-patterns.js +64 -1
  176. package/lib/oh-story/skills/story-import/SKILL.md +19 -10
  177. package/lib/oh-story/skills/story-import/references/format-and-structure.md +9 -10
  178. package/lib/oh-story/skills/story-import/references/structure-mapping-long.md +2 -2
  179. package/lib/oh-story/skills/story-import/references/structure-mapping-short.md +1 -1
  180. package/lib/oh-story/skills/story-import/references/tracking-transaction.md +14 -6
  181. package/lib/oh-story/skills/story-import/scripts/check-outline-contract.js +251 -0
  182. package/lib/oh-story/skills/story-import/scripts/tracking_commit.py +98 -9
  183. package/lib/oh-story/skills/story-import/scripts/wordcount_core.py +246 -0
  184. package/lib/oh-story/skills/story-long-analyze/SKILL.md +4 -4
  185. package/lib/oh-story/skills/story-long-scan/SKILL.md +1 -1
  186. package/lib/oh-story/skills/story-long-write/SKILL.md +35 -21
  187. package/lib/oh-story/skills/story-long-write/references/anti-ai-writing.md +2 -1
  188. package/lib/oh-story/skills/story-long-write/references/artifact-protocols.md +7 -3
  189. package/lib/oh-story/skills/story-long-write/references/author-memory.md +163 -0
  190. package/lib/oh-story/skills/story-long-write/references/banned-words.md +6 -4
  191. package/lib/oh-story/skills/story-long-write/references/cross-book-recall.md +6 -6
  192. package/lib/oh-story/skills/story-long-write/references/genre-prose-cards.md +1 -1
  193. package/lib/oh-story/skills/story-long-write/references/genre-readers.md +1 -1
  194. package/lib/oh-story/skills/{story-setup/references/agent-references/hooks-chapter.md → story-long-write/references/long-chapter-hooks.md} +5 -5
  195. package/lib/oh-story/skills/story-long-write/references/{quality-checklist.md → long-chapter-quality.md} +2 -1
  196. package/lib/oh-story/skills/story-long-write/references/long-format.md +42 -0
  197. package/lib/oh-story/skills/{story-setup/references/agent-references/genre-catalog.md → story-long-write/references/long-genre-catalog.md} +11 -97
  198. package/lib/oh-story/skills/{story-setup/references/agent-references/genre-core-mechanics.md → story-long-write/references/long-genre-mechanics.md} +1 -1
  199. package/lib/oh-story/skills/{story-short-write/references/reversal-toolkit.md → story-long-write/references/long-reversal.md} +18 -32
  200. package/lib/oh-story/skills/story-long-write/references/{hooks-suspense.md → long-suspense.md} +6 -6
  201. package/lib/oh-story/skills/story-long-write/references/opening-design.md +1 -1
  202. package/lib/oh-story/skills/story-long-write/references/outline-structure-theory.md +1 -1
  203. package/lib/oh-story/skills/story-long-write/references/style-genre-modules.md +1 -1
  204. package/lib/oh-story/skills/story-long-write/references/tracking-transaction.md +14 -6
  205. package/lib/oh-story/skills/story-long-write/references/workflow-chapter.md +32 -27
  206. package/lib/oh-story/skills/story-long-write/references/workflow-daily.md +4 -4
  207. package/lib/oh-story/skills/story-long-write/references/workflow-revision.md +2 -2
  208. package/lib/oh-story/skills/story-long-write/references/workflow-setup.md +14 -14
  209. package/lib/oh-story/skills/story-long-write/references/writing-craft.md +54 -54
  210. package/lib/oh-story/skills/story-long-write/scripts/author_memory_commit.py +871 -0
  211. package/lib/oh-story/skills/story-long-write/scripts/check-ai-patterns.js +64 -1
  212. package/lib/oh-story/skills/story-long-write/scripts/check-outline-contract.js +251 -0
  213. package/lib/oh-story/skills/story-long-write/scripts/storyctl.py +303 -0
  214. package/lib/oh-story/skills/story-long-write/scripts/tracking_commit.py +98 -9
  215. package/lib/oh-story/skills/story-long-write/scripts/wordcount_core.py +246 -0
  216. package/lib/oh-story/skills/story-review/SKILL.md +26 -17
  217. package/lib/oh-story/skills/story-review/references/anti-ai-writing.md +2 -1
  218. package/lib/oh-story/skills/story-review/references/author-memory.md +163 -0
  219. package/lib/oh-story/skills/story-review/references/banned-words.md +6 -4
  220. package/lib/oh-story/skills/story-review/references/{quality-checklist.md → review-quality.md} +22 -21
  221. package/lib/oh-story/skills/story-review/references/tracking-transaction.md +14 -6
  222. package/lib/oh-story/skills/story-review/scripts/author_memory_commit.py +871 -0
  223. package/lib/oh-story/skills/story-review/scripts/check-ai-patterns.js +64 -1
  224. package/lib/oh-story/skills/story-review/scripts/tracking_commit.py +98 -9
  225. package/lib/oh-story/skills/story-review/scripts/wordcount_core.py +246 -0
  226. package/lib/oh-story/skills/story-setup/SKILL.md +74 -33
  227. package/lib/oh-story/skills/story-setup/references/agent-references/agent-quality.md +72 -0
  228. package/lib/oh-story/skills/story-setup/references/agent-references/agent-reference-profiles.md +55 -0
  229. package/lib/oh-story/skills/story-setup/references/agent-references/anti-ai-writing.md +2 -1
  230. package/lib/oh-story/skills/story-setup/references/agent-references/banned-words.md +6 -4
  231. package/lib/oh-story/skills/story-setup/references/agent-references/format-and-structure.md +9 -10
  232. package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards.md +1 -1
  233. package/lib/oh-story/skills/story-setup/references/agent-references/genre-readers.md +1 -1
  234. package/lib/oh-story/skills/{story-short-analyze/references/hooks-chapter.md → story-setup/references/agent-references/long-chapter-hooks.md} +5 -5
  235. package/lib/oh-story/skills/story-setup/references/agent-references/long-emotional-methods.md +209 -0
  236. package/lib/oh-story/skills/{story-long-write/references/genre-catalog.md → story-setup/references/agent-references/long-genre-catalog.md} +11 -97
  237. package/lib/oh-story/skills/{story-long-write/references/genre-core-mechanics.md → story-setup/references/agent-references/long-genre-mechanics.md} +1 -1
  238. package/lib/oh-story/skills/story-setup/references/agent-references/long-quality.md +40 -0
  239. package/lib/oh-story/skills/story-setup/references/agent-references/{reversal-toolkit.md → long-reversal.md} +18 -32
  240. package/lib/oh-story/skills/{story-short-write/references/hooks-suspense.md → story-setup/references/agent-references/long-suspense.md} +6 -6
  241. package/lib/oh-story/skills/story-setup/references/agent-references/opening-design.md +1 -1
  242. package/lib/oh-story/skills/story-setup/references/agent-references/{emotional-methods.md → short-emotional-methods.md} +4 -4
  243. package/lib/oh-story/skills/{story-long-write/references/genre-writing-formulas.md → story-setup/references/agent-references/short-genre-formulas.md} +32 -44
  244. package/lib/oh-story/skills/story-setup/references/agent-references/short-quality.md +39 -0
  245. package/lib/oh-story/skills/{story-long-write/references/reversal-toolkit.md → story-setup/references/agent-references/short-reversal.md} +29 -23
  246. package/lib/oh-story/skills/story-setup/references/agent-references/{hooks-suspense.md → short-suspense.md} +31 -31
  247. package/lib/oh-story/skills/story-setup/references/agent-references/style-genre-modules.md +1 -1
  248. package/lib/oh-story/skills/story-setup/references/agent-references/writing-craft.md +55 -55
  249. package/lib/oh-story/skills/story-short-analyze/SKILL.md +28 -28
  250. package/lib/oh-story/skills/story-short-analyze/references/{character-basics.md → analysis-character-basics.md} +1 -1
  251. package/lib/oh-story/skills/story-short-analyze/references/{character-design-methods.md → analysis-character-design.md} +1 -1
  252. package/lib/oh-story/skills/story-short-analyze/references/{character-relations.md → analysis-character-relations.md} +1 -1
  253. package/lib/oh-story/skills/story-short-analyze/references/{hooks-paragraph.md → analysis-paragraph-hooks.md} +1 -1
  254. package/lib/oh-story/skills/story-short-analyze/references/{genre-readers.md → analysis-reader-profile.md} +2 -2
  255. package/lib/oh-story/skills/story-short-analyze/references/analysis-report-style.md +45 -0
  256. package/lib/oh-story/skills/story-short-analyze/references/analysis-short-genres.md +65 -0
  257. package/lib/oh-story/skills/story-short-analyze/references/analysis-short-hooks.md +77 -0
  258. package/lib/oh-story/skills/story-short-analyze/references/analysis-short-mechanics.md +82 -0
  259. package/lib/oh-story/skills/story-short-analyze/references/analysis-short-patterns.md +50 -0
  260. package/lib/oh-story/skills/story-short-analyze/references/analysis-short-suspense.md +98 -0
  261. package/lib/oh-story/skills/story-short-analyze/references/{genre-writing-techniques.md → analysis-writing-techniques.md} +21 -19
  262. package/lib/oh-story/skills/story-short-analyze/references/deconstruction-examples.md +1 -1
  263. package/lib/oh-story/skills/story-short-analyze/references/material-decomposition.md +21 -28
  264. package/lib/oh-story/skills/story-short-analyze/references/output-contract.md +1 -1
  265. package/lib/oh-story/skills/story-short-analyze/references/output-templates.md +17 -17
  266. package/lib/oh-story/skills/story-short-analyze/references/{quality-checklist.md → source-story-quality.md} +28 -49
  267. package/lib/oh-story/skills/story-short-analyze/references/zhihu-style.md +2 -2
  268. package/lib/oh-story/skills/story-short-scan/SKILL.md +1 -1
  269. package/lib/oh-story/skills/story-short-write/SKILL.md +78 -55
  270. package/lib/oh-story/skills/story-short-write/references/author-memory.md +163 -0
  271. package/lib/oh-story/skills/story-short-write/references/banned-words.md +6 -4
  272. package/lib/oh-story/skills/story-short-write/references/cross-book-recall.md +3 -3
  273. package/lib/oh-story/skills/story-short-write/references/emotional-methods.md +4 -4
  274. 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
  275. package/lib/oh-story/skills/story-short-write/references/genre-styles//345/217/214/347/224/267/344/270/273.md +2 -2
  276. 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
  277. 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
  278. 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
  279. package/lib/oh-story/skills/story-short-write/references/genre-styles//346/202/254/347/226/221.md +4 -4
  280. 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
  281. 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
  282. package/lib/oh-story/skills/story-short-write/references/genre-styles//347/224/234/345/256/240.md +4 -4
  283. 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
  284. package/lib/oh-story/skills/story-short-write/references/genre-writing-formulas.md +32 -44
  285. package/lib/oh-story/skills/story-short-write/references/genre-writing-techniques.md +20 -18
  286. package/lib/oh-story/skills/story-short-write/references/output-contract.md +1 -1
  287. package/lib/oh-story/skills/story-short-write/references/short-craft.md +18 -18
  288. package/lib/oh-story/skills/story-short-write/references/short-deslop.md +1 -1
  289. package/lib/oh-story/skills/story-short-write/references/short-format.md +38 -8
  290. package/lib/oh-story/skills/story-short-write/references/{quality-checklist.md → short-prose-quality.md} +22 -21
  291. package/lib/oh-story/skills/story-short-write/references/short-reversal.md +355 -0
  292. package/lib/oh-story/skills/{story-short-analyze/references/hooks-suspense.md → story-short-write/references/short-suspense.md} +31 -31
  293. package/lib/oh-story/skills/story-short-write/references/submission-craft.md +2 -2
  294. package/lib/oh-story/skills/story-short-write/references/writing-workflow.md +31 -22
  295. package/lib/oh-story/skills/story-short-write/scripts/author_memory_commit.py +871 -0
  296. package/lib/oh-story/skills/story-short-write/scripts/check-ai-patterns.js +64 -1
  297. package/lib/oh-story/skills/story-short-write/scripts/check-delivery-contract.js +212 -0
  298. package/lib/oh-story/skills/story-short-write/scripts/check-phase2-contract.js +363 -0
  299. package/lib/types/client/drama-production-view.d.ts +34 -0
  300. package/lib/types/client/drama-production-view.d.ts.map +1 -0
  301. package/lib/types/client/drama-production.d.ts +92 -0
  302. package/lib/types/client/drama-production.d.ts.map +1 -0
  303. package/lib/types/client/file-activity.d.ts +4 -2
  304. package/lib/types/client/file-activity.d.ts.map +1 -1
  305. package/lib/types/client/index.d.ts +1 -1
  306. package/lib/types/client/index.d.ts.map +1 -1
  307. package/lib/types/client/production-intents.d.ts +9 -0
  308. package/lib/types/client/production-intents.d.ts.map +1 -0
  309. package/lib/types/client/production-prompts.d.ts +9 -0
  310. package/lib/types/client/production-prompts.d.ts.map +1 -0
  311. package/lib/types/client/production-runtime.d.ts +58 -0
  312. package/lib/types/client/production-runtime.d.ts.map +1 -0
  313. package/lib/types/client/video-studio.d.ts +41 -0
  314. package/lib/types/client/video-studio.d.ts.map +1 -0
  315. package/lib/types/client/workbench-ui.d.ts +5 -0
  316. package/lib/types/client/workbench-ui.d.ts.map +1 -0
  317. package/lib/types/game-verification.d.ts +16 -0
  318. package/lib/types/game-verification.d.ts.map +1 -0
  319. package/lib/types/index.d.ts +3 -1
  320. package/lib/types/index.d.ts.map +1 -1
  321. package/lib/types/production-intent.d.ts +21 -0
  322. package/lib/types/production-intent.d.ts.map +1 -0
  323. package/lib/types/production-tool.d.ts +5 -0
  324. package/lib/types/production-tool.d.ts.map +1 -0
  325. package/lib/types/role-tool.d.ts.map +1 -1
  326. package/lib/types/skill-provider.d.ts +7 -0
  327. package/lib/types/skill-provider.d.ts.map +1 -1
  328. package/lib/types/video-project.d.ts +42 -0
  329. package/lib/types/video-project.d.ts.map +1 -0
  330. package/lib/types/workspace-request-trust.d.ts +6 -0
  331. package/lib/types/workspace-request-trust.d.ts.map +1 -1
  332. package/lib/types/workspace-route.d.ts +20 -0
  333. package/lib/types/workspace-route.d.ts.map +1 -1
  334. package/lib/video-recap/CHANGELOG.md +282 -0
  335. package/lib/video-recap/LICENSE +21 -0
  336. package/lib/video-recap/README.en.md +257 -0
  337. package/lib/video-recap/README.md +255 -0
  338. package/lib/video-recap/manifest.json +684 -0
  339. package/lib/video-recap/skills/video-assemble/SKILL.md +97 -0
  340. package/lib/video-recap/skills/video-assemble/references/jianying/LICENSE.duo-video +21 -0
  341. package/lib/video-recap/skills/video-assemble/references/jianying/SOURCE.md +15 -0
  342. package/lib/video-recap/skills/video-assemble/references/jianying/empty_draft_meta_info.json +69 -0
  343. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_combination_segment.json +84 -0
  344. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_combination_video_material.json +98 -0
  345. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_draft.json +204 -0
  346. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_material_video.json +83 -0
  347. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_meta_material_value.json +23 -0
  348. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_project_info.json +133 -0
  349. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_segment.json +70 -0
  350. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_text_styles.json +30 -0
  351. package/lib/video-recap/skills/video-assemble/references/jianying/empty_yj_material_audio.json +41 -0
  352. package/lib/video-recap/skills/video-assemble/references/jianying/empty_yj_material_text.json +109 -0
  353. package/lib/video-recap/skills/video-assemble/scripts/artifacts.py +88 -0
  354. package/lib/video-recap/skills/video-assemble/scripts/assemble.py +345 -0
  355. package/lib/video-recap/skills/video-assemble/scripts/assemble_constants.py +34 -0
  356. package/lib/video-recap/skills/video-assemble/scripts/assembly_contract.py +305 -0
  357. package/lib/video-recap/skills/video-assemble/scripts/assembly_settings.py +94 -0
  358. package/lib/video-recap/skills/video-assemble/scripts/audio_automation.py +205 -0
  359. package/lib/video-recap/skills/video-assemble/scripts/audio_mix.py +555 -0
  360. package/lib/video-recap/skills/video-assemble/scripts/export_jianying.py +261 -0
  361. package/lib/video-recap/skills/video-assemble/scripts/jianying_builders.py +767 -0
  362. package/lib/video-recap/skills/video-assemble/scripts/jianying_model.py +111 -0
  363. package/lib/video-recap/skills/video-assemble/scripts/jianying_optional.py +24 -0
  364. package/lib/video-recap/skills/video-assemble/scripts/jianying_schema.py +109 -0
  365. package/lib/video-recap/skills/video-assemble/scripts/jianying_templates.py +37 -0
  366. package/lib/video-recap/skills/video-assemble/scripts/jianying_timeline_contract.py +191 -0
  367. package/lib/video-recap/skills/video-assemble/scripts/jianying_tracks.py +75 -0
  368. package/lib/video-recap/skills/video-assemble/scripts/jianying_writer.py +394 -0
  369. package/lib/video-recap/skills/video-assemble/scripts/lib.py +239 -0
  370. package/lib/video-recap/skills/video-assemble/scripts/media.py +243 -0
  371. package/lib/video-recap/skills/video-assemble/scripts/narration_audio.py +477 -0
  372. package/lib/video-recap/skills/video-assemble/scripts/render_preflight.py +46 -0
  373. package/lib/video-recap/skills/video-assemble/scripts/source_subtitles.py +486 -0
  374. package/lib/video-recap/skills/video-assemble/scripts/subtitle_core.py +376 -0
  375. package/lib/video-recap/skills/video-assemble/scripts/subtitle_render.py +88 -0
  376. package/lib/video-recap/skills/video-assemble/scripts/timeline.py +248 -0
  377. package/lib/video-recap/skills/video-assemble/scripts/timeline_emit.py +89 -0
  378. package/lib/video-recap/skills/video-assemble/scripts/visual_render.py +512 -0
  379. package/lib/video-recap/skills/video-cut/SKILL.md +90 -0
  380. package/lib/video-recap/skills/video-cut/scripts/cut.py +67 -0
  381. package/lib/video-recap/skills/video-cut/scripts/cut_cli.py +320 -0
  382. package/lib/video-recap/skills/video-cut/scripts/cut_contract.py +545 -0
  383. package/lib/video-recap/skills/video-cut/scripts/cut_render.py +348 -0
  384. package/lib/video-recap/skills/video-cut/scripts/lib.py +77 -0
  385. package/lib/video-recap/skills/video-cut/scripts/media_geometry.py +341 -0
  386. package/lib/video-recap/skills/video-cut/scripts/narration_mapping.py +249 -0
  387. package/lib/video-recap/skills/video-cut/scripts/sentence_boundaries.py +745 -0
  388. package/lib/video-recap/skills/video-recap/SKILL.md +216 -0
  389. package/lib/video-recap/skills/video-recap/references/config-playbook.md +61 -0
  390. package/lib/video-recap/skills/video-recap/references/creative-editing-playbook.md +225 -0
  391. package/lib/video-recap/skills/video-recap/references/data-schema.md +534 -0
  392. package/lib/video-recap/skills/video-recap/references/research-guide.md +74 -0
  393. package/lib/video-recap/skills/video-recap/references/shift-left-qc-schema.md +23 -0
  394. package/lib/video-recap/skills/video-recap/references/timeline-and-jianying.md +251 -0
  395. package/lib/video-recap/skills/video-recap/scripts/doctor.py +483 -0
  396. package/lib/video-recap/skills/video-recap/scripts/final_qc.py +737 -0
  397. package/lib/video-recap/skills/video-recap/scripts/lib.py +242 -0
  398. package/lib/video-recap/skills/video-recap/scripts/materials.py +457 -0
  399. package/lib/video-recap/skills/video-recap/scripts/mimo_qc.py +95 -0
  400. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_client.py +18 -0
  401. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_contract.py +9 -0
  402. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_evidence.py +371 -0
  403. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_observations.py +201 -0
  404. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_payload.py +227 -0
  405. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_report.py +362 -0
  406. package/lib/video-recap/skills/video-recap/scripts/mimo_qc_runner.py +129 -0
  407. package/lib/video-recap/skills/video-recap/scripts/qc_contract.py +338 -0
  408. package/lib/video-recap/skills/video-recap/scripts/recap.py +9 -0
  409. package/lib/video-recap/skills/video-recap/scripts/recap_cli.py +140 -0
  410. package/lib/video-recap/skills/video-recap/scripts/recap_inspect.py +550 -0
  411. package/lib/video-recap/skills/video-recap/scripts/recap_review.py +77 -0
  412. package/lib/video-recap/skills/video-recap/scripts/recap_runner.py +654 -0
  413. package/lib/video-recap/skills/video-recap/scripts/recap_runtime.py +335 -0
  414. package/lib/video-recap/skills/video-recap/scripts/recap_stage_qc.py +217 -0
  415. package/lib/video-recap/skills/video-recap/scripts/recap_timeline.py +795 -0
  416. package/lib/video-recap/skills/video-script/SKILL.md +248 -0
  417. package/lib/video-recap/skills/video-script/references/creative-editing-playbook.md +225 -0
  418. package/lib/video-recap/skills/video-script/references/research-guide.md +75 -0
  419. package/lib/video-recap/skills/video-script/scripts/agent_brief.py +399 -0
  420. package/lib/video-recap/skills/video-script/scripts/agent_text.py +410 -0
  421. package/lib/video-recap/skills/video-script/scripts/brief_context.py +403 -0
  422. package/lib/video-recap/skills/video-script/scripts/brief_inputs.py +332 -0
  423. package/lib/video-recap/skills/video-script/scripts/brief_timeline.py +442 -0
  424. package/lib/video-recap/skills/video-script/scripts/deslop_qc.py +237 -0
  425. package/lib/video-recap/skills/video-script/scripts/evidence_bundle.py +492 -0
  426. package/lib/video-recap/skills/video-script/scripts/lib.py +327 -0
  427. package/lib/video-recap/skills/video-script/scripts/narration.py +12 -0
  428. package/lib/video-recap/skills/video-script/scripts/narration_lint.py +678 -0
  429. package/lib/video-recap/skills/video-script/scripts/review.py +42 -0
  430. package/lib/video-recap/skills/video-script/scripts/review_grounding.py +262 -0
  431. package/lib/video-recap/skills/video-script/scripts/review_response.py +761 -0
  432. package/lib/video-recap/skills/video-script/scripts/review_runner.py +200 -0
  433. package/lib/video-recap/skills/video-script/scripts/speech_ownership.py +204 -0
  434. package/lib/video-recap/skills/video-script/scripts/timeline_fusion.py +199 -0
  435. package/lib/video-recap/skills/video-script/scripts/validate.py +164 -0
  436. package/lib/video-recap/skills/video-understanding/SKILL.md +75 -0
  437. package/lib/video-recap/skills/video-understanding/references/data-schema.md +299 -0
  438. package/lib/video-recap/skills/video-understanding/references/prompt-templates.md +37 -0
  439. package/lib/video-recap/skills/video-understanding/references/research-guide.md +74 -0
  440. package/lib/video-recap/skills/video-understanding/scripts/agent_brief.py +399 -0
  441. package/lib/video-recap/skills/video-understanding/scripts/agent_text.py +410 -0
  442. package/lib/video-recap/skills/video-understanding/scripts/asr.py +260 -0
  443. package/lib/video-recap/skills/video-understanding/scripts/brief.py +12 -0
  444. package/lib/video-recap/skills/video-understanding/scripts/brief_context.py +403 -0
  445. package/lib/video-recap/skills/video-understanding/scripts/brief_inputs.py +332 -0
  446. package/lib/video-recap/skills/video-understanding/scripts/brief_timeline.py +442 -0
  447. package/lib/video-recap/skills/video-understanding/scripts/consolidate.py +647 -0
  448. package/lib/video-recap/skills/video-understanding/scripts/deslop_qc.py +237 -0
  449. package/lib/video-recap/skills/video-understanding/scripts/detect.py +513 -0
  450. package/lib/video-recap/skills/video-understanding/scripts/extract.py +62 -0
  451. package/lib/video-recap/skills/video-understanding/scripts/lib.py +470 -0
  452. package/lib/video-recap/skills/video-understanding/scripts/narration_lint.py +678 -0
  453. package/lib/video-recap/skills/video-understanding/scripts/speech_ownership.py +204 -0
  454. package/lib/video-recap/skills/video-understanding/scripts/storyboard.py +507 -0
  455. package/lib/video-recap/skills/video-understanding/scripts/timeline_fusion.py +199 -0
  456. package/lib/video-recap/skills/video-understanding/scripts/understand.py +9 -0
  457. package/lib/video-recap/skills/video-understanding/scripts/understanding_brief.py +216 -0
  458. package/lib/video-recap/skills/video-understanding/scripts/understanding_cache.py +327 -0
  459. package/lib/video-recap/skills/video-understanding/scripts/understanding_runner.py +367 -0
  460. package/lib/video-recap/skills/video-understanding/scripts/understanding_storyboard.py +162 -0
  461. package/lib/video-recap/skills/video-understanding/scripts/vlm.py +705 -0
  462. package/lib/video-recap/skills/video-voiceover/SKILL.md +81 -0
  463. package/lib/video-recap/skills/video-voiceover/scripts/dub.py +637 -0
  464. package/lib/video-recap/skills/video-voiceover/scripts/fish_audio.py +109 -0
  465. package/lib/video-recap/skills/video-voiceover/scripts/lib.py +421 -0
  466. package/lib/video-recap/skills/video-voiceover/scripts/tts_audio.py +113 -0
  467. package/lib/video-recap/skills/video-voiceover/scripts/voiceover.py +782 -0
  468. package/package.json +55 -40
  469. package/lib/oh-story/skills/story-deslop/scripts/check-outline-copy.js +0 -241
  470. package/lib/oh-story/skills/story-long-write/references/format-and-structure.md +0 -169
  471. package/lib/oh-story/skills/story-setup/references/agent-references/genre-writing-formulas.md +0 -444
  472. package/lib/oh-story/skills/story-setup/references/agent-references/quality-checklist.md +0 -247
  473. package/lib/oh-story/skills/story-short-analyze/references/anti-ai-writing.md +0 -582
  474. package/lib/oh-story/skills/story-short-analyze/references/banned-words.md +0 -147
  475. package/lib/oh-story/skills/story-short-analyze/references/genre-catalog.md +0 -490
  476. package/lib/oh-story/skills/story-short-analyze/references/genre-core-mechanics.md +0 -425
  477. package/lib/oh-story/skills/story-short-analyze/references/genre-writing-formulas.md +0 -453
  478. /package/lib/oh-story/skills/{story-long-write/references/hooks-chapter.md → story-setup/references/agent-references/short-chapter-hooks.md} +0 -0
  479. /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
 
@@ -2,7 +2,7 @@
2
2
  name: story-import
3
3
  version: 1.0.0
4
4
  description: "逆向导入已有小说。将已写好的小说(半成品或完本)反向解析为标准项目目录结构,兼容 story-long-write / story-short-write 后续写作流程;内部复用 story-long-analyze / story-short-analyze 的拆解管道,按篇幅自动分流。触发方式:/story-import、「导入小说」「反向解析」「导入」「把我的书导进来」。"
5
- metadata: {"openclaw":{"source":"https://github.com/worldwonderer/oh-story-claudecode"}}
5
+ metadata: {"openclaw":{"source":"https://github.com/zenstory-ai/oh-story-claudecode"}}
6
6
  ---
7
7
  # story-import:逆向导入已有小说
8
8
 
@@ -12,9 +12,9 @@ metadata: {"openclaw":{"source":"https://github.com/worldwonderer/oh-story-claud
12
12
 
13
13
  ---
14
14
 
15
- > Agent 兼容性:检查专业 agent 是否可用时,按 `.claude/agents/{agent}.md` → `.opencode/agents/{agent}.md` → `.codex/agents/{agent}.toml` 的顺序查找。Codex 原生子代理调用优先使用同名 `agent_type`;如果当前 Codex 运行时返回 `unknown agent_type` 或未暴露 custom-agent registry,必须降级为 solo/direct。检测到 `.zcode/` 时同样直接 solo/direct,因为 ZCode 3.3.4 不执行项目 custom agents;报告 `Fallback: project custom agents unavailable -> solo`。Claude/OpenCode 兼容面保留 `subagent_type`。
15
+ > Agent 兼容性:只检查当前运行时的 canonical 目录:Claude `.claude/agents/{agent}.md`、OpenCode `.opencode/agents/{agent}.md`、Codex `.codex/agents/{agent}.toml`、Antigravity `.agents/agents/agent-name/agent.md`(`agent-name` 为目标 agent 名),不得因其他端文件存在而误判。Codex 使用同名 `agent_type`;Antigravity 使用 `invoke_subagent` + `TypeName`。对应运行时未暴露 custom-agent registry / `invoke_subagent` 或返回未知 agent 时,必须降级 solo/direct。检测到 `.zcode/` 时同样直接 solo/direct,因为 ZCode 3.3.4 不执行项目 custom agents;报告 `Fallback: project custom agents unavailable -> solo`。Claude/OpenCode 兼容面保留 `subagent_type`。
16
16
  >
17
- > Spawn 版本提示(不阻断 spawn):先读取项目根 `.story-deployed` 的 `agents_version`。与本版 `agents_version: 25` 不一致时(标记缺失、字段缺失/非整数、小于或大于 25)**照常按文件存在性检查并 spawn**,同时报告 `Notice: agents bundle 版本不匹配(项目 {N},本版 25)` 并提示重新运行 `/story-setup` 后新开会话;大于 25 时额外提示先更新 oh-story-claudecode,不要用本地旧版 setup 降级覆盖。只有 agent 文件缺失、或运行时不暴露 custom agent 时才降级 solo/direct,报告 `Fallback: ... -> solo`。
17
+ > Spawn 版本提示(不阻断 spawn):先读取项目根 `.story-deployed` 的 `agents_version`。与本版 `agents_version: 29` 不一致时(标记缺失、字段缺失/非整数、小于或大于 29)**照常按文件存在性检查并 spawn**,同时报告 `Notice: agents bundle 版本不匹配(项目 {N},本版 29)` 并提示重新运行 `/story-setup` 后新开会话;大于 29 时额外提示先更新 oh-story-claudecode,不要用本地旧版 setup 降级覆盖。只有 agent 文件缺失、或运行时不暴露 custom agent 时才降级 solo/direct,报告 `Fallback: ... -> solo`。
18
18
 
19
19
  ## 核心原则
20
20
 
@@ -102,7 +102,7 @@ metadata: {"openclaw":{"source":"https://github.com/worldwonderer/oh-story-claud
102
102
  在进入 Phase 2 之前,先检测项目是否已部署 story-setup 基础设施:
103
103
 
104
104
  - 先读取 `.story-deployed` 并执行顶部 Spawn 版本门禁;旧版 `chapter-extractor` 文件即使仍在磁盘上也不可复用。
105
- - 只有 `agents_version: 25` 通过后,才按 `.claude/agents/chapter-extractor.md` → `.opencode/agents/chapter-extractor.md` → `.codex/agents/chapter-extractor.toml` 检查 Phase 2 长篇并行 agent。
105
+ - 只有 `agents_version: 28` 通过后,才在当前运行时的 canonical 目录检查 Phase 2 `chapter-extractor`:Claude/OpenCode/Antigravity 为同名 Markdown,Codex 为同名 TOML。
106
106
  - 如果 `.story-deployed` 的 `target_cli` 包含 `zcode`,项目 agents 缺失是 ZCode 3.3.4 的预期状态:不要提示重复部署,直接以串行 solo/direct 进入分析并报告 fallback。
107
107
 
108
108
  **部署标记缺失、版本无效/过期,或当前端的 agent 不可用,且不是已部署 ZCode 项目时**,提示用户:
@@ -334,12 +334,21 @@ story-short-analyze 的拆解管道(Stage 2-6)本身**无 Stage 1 停靠点*
334
334
 
335
335
  **细纲**:从章节摘要反推生成 `大纲/细纲_第XXX章.md`:
336
336
 
337
+ 每章先通过 story-long-write 的 Wordcount Core 运行 `wordcount measure`,将 JSON 的 `actual` 作为已写章节的历史长度快照。这里记录的是原文在 `visible_chars_v1` 下的实际长度,不是让模型重新决定创作目标。依次探测 `python3`、`python`、`py -3`;找不到 Python 3 或 CLI 时返回 `TOOL_UNAVAILABLE` 并停止导入,不得用模型估算或静默跳过。
338
+
339
+ ```bash
340
+ {PYTHON} {story-long-write skill 根}/scripts/storyctl.py wordcount measure \
341
+ --file "{原文章节文件}" \
342
+ --chapter {N}
343
+ ```
344
+
337
345
  ```markdown
338
346
  ## 细纲(第 N 章)
339
347
 
340
348
  ### 第 N 章:{章名}
341
349
  - 核心事件:{从摘要中提取}
342
- - 字数目标:{原文实际字数}
350
+ - 字数目标:{storyctl 返回的 actual} 字
351
+ - 字数口径:visible_chars_v1
343
352
  - 目标情绪:{从章节基调/情绪曲线提取;未知写 [待补充]}
344
353
  - 章首钩子:[待补充]
345
354
  - 爽点:{从情节点推断;无明确证据写 [待补充]}
@@ -366,9 +375,9 @@ story-short-analyze 的拆解管道(Stage 2-6)本身**无 Stage 1 停靠点*
366
375
  #### 情节细化
367
376
  - 情节点序列(逐行填下表;从摘要情节点反推):
368
377
 
369
- | # | 情节点(谁做了什么) | 功能标签 | 密/铺/疏 | 目标字数 |
370
- |---|---|---|---|---|
371
- | 1 | {} | {功能不明写 [待补充]} | {按原文该段实际篇幅归档} | {[待补充]} |
378
+ | # | 情节点(谁做了什么) | 功能标签 | 执行边界 |
379
+ |---|---|---|---|
380
+ | 1 | {} | {功能不明写 [待补充]} | {从原文确认本点没有释放什么;未知写 [待补充]} |
372
381
  - 行动成本(可无)/收益归属:{有证据才写;行动成本可无、不硬造;未知写 [待补充]}
373
382
 
374
383
  #### 结尾设定和钩子
@@ -476,7 +485,7 @@ story-short-analyze 的拆解管道(Stage 2-6)本身**无 Stage 1 停靠点*
476
485
 
477
486
  #### Step 3:小节大纲生成
478
487
 
479
- 从 `情节节点.md` 的功能分段反推 `{标题}/小节大纲.md`,按开头段/铺垫段/升级段/反转段/结尾段映射;短篇只做轻量蓝图:每节写 `结构段/五段功能`、主事件、3-5 个子事件、目标情绪、人物/关系变化、因果/逻辑链、结尾承接/小钩子。钩子或关系无法判断时标 `[待补充]`,不套用长篇完整章节蓝图。
488
+ 从 `情节节点.md` 的功能分段反推 `{标题}/小节大纲.md`,按开头段/铺垫段/升级段/反转段/结尾段映射;短篇只做轻量蓝图:每节写 `结构段/五段功能`、主事件、一个或多个真实推进、目标情绪、人物/关系变化、因果/逻辑链、结尾承接/小钩子。相关情节点可由同一动作链或对话同时兑现,不为凑数量拆成多个子事件。钩子或关系无法判断时标 `[待补充]`,不套用长篇完整章节蓝图。
480
489
 
481
490
  #### Step 4:外部对标引用视图(可选)
482
491
 
@@ -554,7 +563,7 @@ story-short-analyze 的拆解管道(Stage 2-6)本身**无 Stage 1 停靠点*
554
563
 
555
564
  - 设置 `.active-book` 指向导入的书名/标题目录
556
565
  - 确认项目可以被对应写作 skill 识别(长篇 → story-long-write,短篇 → story-short-write)
557
- - 可选验证:如果项目已部署 story-explorer agent(优先检查 `.claude/agents/` 下的 `story-explorer.md` 是否存在;不存在时再检查 `.opencode/agents/`,再不存在时检查 `.codex/agents/`),可 spawn `Agent(subagent_type: "story-explorer", prompt: "项目目录:{dir}\n查询类型:progress\n查询参数:导入验证")` 交叉验证迁移数据完整性
566
+ - 可选验证:如果当前运行时的 canonical 目录已部署 story-explorer agent,可 spawn 交叉验证迁移数据完整性;Antigravity 检查 `.agents/agents/story-explorer/agent.md` 并用 `invoke_subagent` + `TypeName: "story-explorer"`。Prompt:`项目目录:{dir}\n查询类型:progress\n查询参数:导入验证`
558
567
 
559
568
  > setup 环境检测已在 Phase 1「环境检测前置」完成,此处不再重复检测。
560
569
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 写作前必读。以下格式是当前仓库约定的默认正文交付格式;用户或目标平台有明确要求时,以用户/平台要求覆盖。
4
4
  >
5
- > **适用范围**:段落格式(戏剧单元/镜头优先,短段为底色,长段用于完整推理、氛围和情绪链)和对话格式适用于所有体裁。小节(beat)结构和字数标准仅适用于短篇。长篇小说字数以本章细纲的 `字数目标` 与统一 90% 放行下限为准。
5
+ > **适用范围**:段落格式(戏剧单元/镜头优先,短段为底色,长段用于完整推理、氛围和情绪链)和对话格式适用于所有体裁。小节(beat)结构仅适用于短篇;小节不设统一最低字数。长篇按 `visible_chars_v1` 测量同口径细纲 `字数目标`:内部带 ±12%,用户带 ±15%。
6
6
 
7
7
  ---
8
8
 
@@ -119,19 +119,19 @@
119
119
  ### 基本规则
120
120
 
121
121
  - 用数字编号(`1` `2` `3`)分割小节,每个小节是一个完整的叙事 beat
122
- - 每小节 800-1500 字(爽文可压缩至 500-800 字/节,见 genre-writing-formulas.md)
123
- - 8-15 个小节覆盖全文(按目标字数反推;8000÷1000≈8节,12000÷800≈15节)
122
+ - 小节长度服从其叙事职责,不设统一最低字数;整篇按锁定的交付范围控制,长篇章节按细纲「字数目标」处理
123
+ - 小节数由情节阶段和转场需要决定;不为平均分配字数拆分完整动作链,也不把承担不同职责的小节硬合并
124
124
  - 每小节推进一个明确的情节点
125
125
 
126
126
  ### 小节内部结构
127
127
 
128
- 每个小节应该有:
128
+ 每个小节至少完成第 1 项,其余按本节职责选用:
129
129
 
130
- 1. **一个主事件** + **3-5 个子事件**(主事件推进核心情节,子事件丰富层次;初稿偏短时先回到小节/细纲补足计划内子事件、对话或冲突,再写正文;去AI味已有正文时不得新增剧情)
131
- 2. **一个情绪变化**(读者的感受如何变化)
132
- 3. **一条读者新获知的信息**
133
- 4. **3-5 轮对话交锋**(揭示关系/升级冲突,参考 writing-craft.md 对话权力博弈。特定场景如独自发现/翻阅日记可标零,按当前 skill 的细纲/设计任务要求执行)
134
- 5. **每个子事件三维度揉进**:发生+感知+反应揉进同一段正文(参考 writing-craft.md 场景写法)
130
+ 1. **一个主事件** + **一个或多个真实推进**(风险、信息、关系、资源、决定、行动或读者理解至少改变一项;相关情节点可由同一动作链或对话同时兑现,不为数量新增阻碍、对话或冲突)
131
+ 2. **情绪或压力落点**(确有变化时写清读者感受如何变化;任务、推理、手艺或等待链不强配情绪转折)
132
+ 3. **读者模型或下一步变化**(新信息、旧信息改义、决定、行动或后果均可,不强配新事实)
133
+ 4. **对白按功能使用**(需要时改变信息、策略、权力、关系或下一步行动;独自发现、核验证据、等待、手艺等场景可以无对白)
134
+ 5. **推进单元按需揉进信息维度**:发生是主干,感知和反应只在提供新信息时织入同一镜头(参考 writing-craft.md 场景写法)
135
135
 
136
136
 
137
137
  ### 小节之间的衔接
@@ -166,4 +166,3 @@
166
166
  6. **正文不使用破折号**:正文(含叙述、对话、心理描写)不使用破折号 `——`/`—` 或双连字符 `--`,改用句号、逗号、换行、动作 beat 或短句断开;不再设置“对话例外”
167
167
  7. **禁止通篇句号化或随机标点堆砌**:标点必须跟语气/人物声线/情绪功能匹配;该质问时用问号,该爆发时少量感叹;犹豫、吞咽、未说完用动作或句长变化表达,不用 `……` / `——` 硬造停顿,也不得无功能地乱撒 `?`/`!`
168
168
  8. **禁止正文混入章节元信息**:章节号只允许出现在标题/小节标记/文件名/追踪记录中。正文叙述、对话、心理描写里不得出现 `第[一二三四五六七八九十百千万两0-9]+章|上一章|上章|前一章|本章|这一章|前文|后文|伏笔|细纲|读者` 这类写作工程词;要改成角色能感知的事件锚点或相对时间,例如把“比第一章那三秒开火更疼”改成“比那三秒开火更疼”。例外:角色在故事世界内真实阅读/讨论“第X章”文本,或真实身为作者/读者并谈论读者身份时,可保留相应词。
169
-
@@ -264,14 +264,14 @@ A<->B:关系类型 | 情感 | 描述(50-200字)| 演变轨迹
264
264
  | 摘要字段 | 细纲字段 | 转换方式 |
265
265
  |---------|---------|---------|
266
266
  | 关键事件 | 核心事件 | 直接复用 |
267
- | 章节字数 | 字数目标 | 从原文统计 |
267
+ | 章节字数 | 字数目标 + 字数口径 | 对原文章节运行 `storyctl.py wordcount measure`,写入 `actual` 与 `visible_chars_v1` |
268
268
  | 章节基调 / 情绪曲线 | 目标情绪 | 从摘要提取;缺失写 `[待补充]` |
269
269
  | 第一个情节点 | 章首钩子 | 只作为证据,设计目标标 `[待补充]` |
270
270
  | 爽点类情节点 | 爽点 | 从情节点类型推断;没有则写“无显性爽点 / [待补充]” |
271
271
  | 情节点起承转合 | 内容概括(起因/发展/转折/高潮/结尾) | 按情节点顺序归纳;证据不足写 `[待补充]` |
272
272
  | 主线/支线/任务线索 | 情节安排(主线/辅线/事件线/感情线/逻辑线) | 从剧情单元索引与摘要反推;无证据的辅线/感情线写“无”或 `[待补充]`,不得杜撰 |
273
273
  | 出场角色 / 关键物件 | 人物关系和出场顺序 | 按摘要出现顺序列出;关系变化只写有证据的“前 → 后”,缺失写 `[待补充]` |
274
- | 全部情节点 | 情节细化 / 情节点序列 | 按表格逐行写(# / 情节点 / 功能标签 / 密铺疏 / 目标字数);功能不明写 `[待补充]`,密/铺/疏按原文该段实际篇幅归档 |
274
+ | 全部情节点 | 情节细化 / 情节点序列 | 按表格逐行写(# / 情节点 / 功能标签 / 执行边界);功能或边界不明写 `[待补充]`,不反推逐点字数配额 |
275
275
  | 胜负/反转/收益损失 | 行动成本(可无)/收益归属 | 有明确证据才填写;行动成本可无、不硬造;否则 `[待补充]` |
276
276
  | 最后一个情节点 / 悬念类情节点 | 结尾设定和钩子 | 收束状态可归纳;章尾钩子设计目标标 `[待补充]` |
277
277
 
@@ -125,7 +125,7 @@ Phase 3-S 短篇结构迁移的详细映射规则。将 `拆文库/{导入书名
125
125
 
126
126
  ### 小节数量推算
127
127
 
128
- 按原文实际字数估算:`总字数 ÷ 1000 ≈ 小节数`(短篇参考区间 8-15 个小节)。小节数与正文实际段落结构一致是质量清单必检项。
128
+ 以原文实际的分节标记和转场为准;原文没有显式分节时,按情节阶段和转场切分,`总字数 ÷ 1000` 只作粗略参考,不作为切分依据。小节数与正文实际段落结构一致是质量清单必检项。
129
129
 
130
130
  ---
131
131
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  | 层级 | 文件 | 语义 |
8
8
  |---|---|---|
9
- | 唯一权威 | `_tracking-state.json` | schema、最后提交章、导入截止章、状态修订号、上下文结构、全部当前角色/伏笔/时间线状态 |
9
+ | 唯一权威 | `_tracking-state.json` | schema、最后提交章、导入截止章、状态修订号、上下文结构、角色/伏笔/时间线,以及已提交章节的简短字数记录 |
10
10
  | 章节记录 | `逐章记录/第NNN章.md` | 本章对未来连续性有用的紧凑变化;目标 ≤1536 字节,硬上限 3072 字节;导入范围内修订写成覆盖记录 |
11
11
  | 派生视图 | `上下文.md`、`角色状态/{角色名}.md`、`伏笔.md`、`时间线/作者真相.md`、`时间线/读者已知.md` | 完全从 `_tracking-state.json` 生成;禁止手改,不作为程序输入 |
12
12
 
@@ -15,21 +15,27 @@ Markdown 只负责给作者和 Agent 阅读,工具不再反向解析 Markdown
15
15
 
16
16
  ## 运行工具
17
17
 
18
- 先按运行环境探测 Python 3 解释器(依次尝试 `python3`、`python`、`py -3`),再用当前 skill 根目录执行:
18
+ 先按运行环境探测 Python 3 解释器(依次尝试 `python3`、`python`、`py -3`)。追踪事务脚本使用当前 skill 根目录;字数与章节闭环统一使用 `story-long-write` skill 根目录:
19
19
 
20
20
  ```text
21
21
  {PYTHON} {当前 skill 根}/scripts/tracking_commit.py init --project {书项目根} --input {初始化事务.json}
22
- {PYTHON} {当前 skill 根}/scripts/tracking_commit.py commit --project {书项目根} --input {逐章事务.json}
23
22
  {PYTHON} {当前 skill 根}/scripts/tracking_commit.py check --project {书项目根}
23
+ {PYTHON} {story-long-write skill 根}/scripts/storyctl.py wordcount checkpoint --file {前半段临时文件} --target {目标} --chapter {N}
24
+ {PYTHON} {story-long-write skill 根}/scripts/storyctl.py chapter check --project {书项目根} --chapter {N}
25
+ {PYTHON} {story-long-write skill 根}/scripts/storyctl.py chapter commit --project {书项目根} --chapter {N} --input {逐章事务.json}
26
+ {PYTHON} {story-long-write skill 根}/scripts/storyctl.py chapter accept-current-length --project {书项目根} --chapter {N} --input {逐章事务.json}
24
27
  ```
25
28
 
26
29
  - `init`:只在 `_tracking-state.json` 不存在时执行,绝不覆盖已初始化项目。
27
- - `commit`:读取唯一权威状态,在内存中完成合并、引用检查、全部视图渲染和容量检查;随后写逐章记录与派生视图,最后原子替换 `_tracking-state.json` 作为唯一提交点。
30
+ - `wordcount checkpoint`:纯测量;返回当前实际字数、用户带与剩余用户区间,不写正文、不写 tracking、不做语义判断。每章最多调用一次。
31
+ - `chapter check`:重新读取当前正文与细纲目标,返回确定性长度状态、现有 blocking quality、`state_revision` 和当前可执行动作,不保存 approval。`under` 不提供自动补写;`over` 额外返回一次净删型 `compress-once` 及进入内带/用户带所需的机器删除区间。
32
+ - `chapter commit`:再次读取当前文件、重新计数并重跑 blocking quality;只接受用户带内章节,把简短字数记录与逐章事务一起原子提交。
33
+ - `chapter accept-current-length`:只接受带外但 quality pass 的章节;接受动作发生时重新读取、重新计数并立即原子提交,不保存可陈旧的历史决议。
28
34
  - `check`:严格验证 state schema、逐章记录连续性/规范名/体积、固定 7 栏、角色快照硬上限、派生文件集合,以及所有派生视图与 state 的逐字一致性。
29
35
 
30
- 同一本书只允许工作流串行提交,不支持多个 Agent 或终端并发写。`expected_state_revision` 用于拒绝基于旧状态构造的顺序 stale transaction,不是并发锁。
36
+ 每本书由 `追踪/.tracking-commit.lock` 串行写事务,`expected_state_revision` 再拒绝基于旧状态构造的 stale transaction。两个不同事务并发时至多一个修订成功。字数记录也在锁内对当前正文和目标重新验证,正文或目标变化会让预先构造的记录直接失败。
31
37
 
32
- 事务 JSON 在成功前必须保留。若文件写入失败,`_tracking-state.json` 尚未推进;修正环境后直接重跑**同一份** `commit`。append 重跑只接受内容完全相同的既有逐章记录,不维护 `dirty/pending/repair` 状态机。
38
+ 事务 JSON 是临时输入,不是项目产物:成功前必须保留;提交成功且紧随其后的 `check` 通过后立即删除,不能把 `init_transaction.json`、`chapter_*_transaction.json` 等输入长期留在书项目根目录。若文件写入失败,`_tracking-state.json` 尚未推进;修正环境后直接重跑**同一份** `commit`。append 重跑只接受内容完全相同的既有逐章记录,不维护 `dirty/pending/repair` 状态机。
33
39
 
34
40
  校验失败与写入失败处理方式不同:校验失败(字段非法、退役结构、容量超限)要按报错改事务本身,重跑同一份结果不变。派生视图被手改或外部改动导致 `check` 报 `derived view differs from _tracking-state.json` 时,重新提交**该章**的 `mode=revision` 事务让工具整份重建,`expected_state_revision` 取 `追踪/_tracking-state.json` 的 `state_revision` 字段——`check` 失败时只往 stderr 打 ERROR,不输出 JSON;不手改派生文件,也不删 `_tracking-state.json` 重来。手写出的逐章记录会让同章 `append` 永久报 `chapter delta N already exists with different content`——删掉那个手写文件后重跑原事务即可。
35
41
 
@@ -65,6 +71,8 @@ Markdown 只负责给作者和 Agent 阅读,工具不再反向解析 Markdown
65
71
 
66
72
  导入初始化时直接传入当前核心角色快照、伏笔当前行、时间线事件和固定 7 栏状态输入。阶段/卷级回看按需查询正文,不作为每章强一致追踪产物。
67
73
 
74
+ 调用方的逐章 JSON 不写 `wordcount`;正式入口 `chapter commit` 或 `chapter accept-current-length` 在提交当下生成并注入。最终 state 只为已提交章节保留 `metric / target / actual / status / resolution / body_sha256`,不保存 MEASURE/RESOLVE 事件、ID 链、policy fingerprint 或独立 chapter state。
75
+
68
76
  ## 逐章事务
69
77
 
70
78
  ```json
@@ -0,0 +1,251 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Deterministic 细纲 structural verifier for story-long-write.
4
+ *
5
+ * Usage:
6
+ * node scripts/check-outline-contract.js --json <细纲路径...>
7
+ * node scripts/check-outline-contract.js --json --project <书目录> --chapter N
8
+ * Exit: 0 = pass, 1 = blocking contract failures, 2 = invalid invocation.
9
+ *
10
+ * Scope is structural only: it decides whether the blueprint carries the fields,
11
+ * subsections and table shape the authoritative template names. It never judges
12
+ * whether a value is good. The contract itself sets this granularity —
13
+ * artifact-protocols.md 要求未知字段写 `[待补充]`,所以字段必须在场,值可以未知。
14
+ */
15
+
16
+ 'use strict'
17
+
18
+ const fs = require('fs')
19
+ const path = require('path')
20
+
21
+ // 权威模板:references/workflow-setup.md「细纲(全书每章)」
22
+ const FIELDS = [
23
+ '核心事件', '字数目标', '字数口径', '阶段位置', '单元ID/位置', '目标情绪',
24
+ '主角目标/关键选择', '章节定位', '本章结构公式', '章首钩子', '爽点',
25
+ '本章禁止提前释放', '契约风险',
26
+ ]
27
+ const SUBSECTIONS = ['内容概括', '情节安排', '人物关系和出场顺序', '情节细化']
28
+ const FIVE_ACT = ['起因', '发展', '转折', '高潮', '结尾']
29
+ const PLOT_HEADER_FIRST = /^(?:#|序号)$/
30
+ // 这两个字段实测直接影响正文质量,必须有实际内容
31
+ const INTENT_FIELDS = ['目标情绪', '主角目标/关键选择']
32
+ const CALIBER = 'visible_chars_v1'
33
+
34
+ function fieldPattern(name) {
35
+ // 允许 -/*/+ 项目符号、可选 ** 加粗、全角或半角冒号
36
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
37
+ return new RegExp(`^\\s*[-*+]\\s*\\*{0,2}${escaped}\\*{0,2}\\s*[::]`, 'm')
38
+ }
39
+
40
+ function readUtf8(file) {
41
+ try {
42
+ const text = fs.readFileSync(file, 'utf8').replace(/^/, '')
43
+ return { ok: text.trim().length > 0, text }
44
+ } catch (error) {
45
+ return { ok: false, text: '', error: error.message }
46
+ }
47
+ }
48
+
49
+ function makeCheck(id, ok, file, evidence, expected, repair) {
50
+ return {
51
+ id,
52
+ ok,
53
+ severity: 'blocking',
54
+ file,
55
+ evidence,
56
+ expected,
57
+ references: ['references/workflow-setup.md', 'references/artifact-protocols.md'],
58
+ repair,
59
+ }
60
+ }
61
+
62
+ function parseTableRow(line) {
63
+ const trimmed = line.trim()
64
+ if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) return null
65
+ return trimmed.slice(1, -1).split('|').map((cell) => cell.replace(/\*\*/g, '').replace(/`/g, '').trim())
66
+ }
67
+
68
+ function verify(file) {
69
+ const name = path.basename(file)
70
+ const read = readUtf8(file)
71
+ const checks = []
72
+
73
+ checks.push(makeCheck(
74
+ 'outline.readable',
75
+ read.ok,
76
+ name,
77
+ read.ok ? '文件存在且非空' : (read.error || '文件为空'),
78
+ '细纲文件存在且非空',
79
+ '只补建缺失的细纲文件,不改动同批其他章。'
80
+ ))
81
+ if (!read.ok) return report(file, checks)
82
+ const text = read.text
83
+
84
+ const missingFields = FIELDS.filter((field) => !fieldPattern(field).test(text))
85
+ checks.push(makeCheck(
86
+ 'outline.required-fields',
87
+ missingFields.length === 0,
88
+ name,
89
+ missingFields.length ? `缺字段:${missingFields.join('、')}` : `${FIELDS.length} 个字段齐全`,
90
+ `按权威模板列出全部字段:${FIELDS.join('、')};值未知时写 [待补充],不杜撰剧情`,
91
+ '只补报告里缺的字段行;确实还定不下来的写 [待补充],不为补字段新增副线或人物关系。'
92
+ ))
93
+
94
+ // 隔离实验(同章、同写作流程,只改细纲):只补这两个字段就能复现补齐全部字段的收益,
95
+ // 盲评 3/3 胜过不补;补满五个字段与只补这两个不可区分。所以这两个字段不接受占位符,
96
+ // 其余字段仍按契约允许 [待补充]。
97
+ const hollow = INTENT_FIELDS.filter((field) => {
98
+ const match = text.match(new RegExp(`^\\s*[-*+]\\s*\\*{0,2}${field.replace('/', '\\/')}\\*{0,2}\\s*[::]\\s*(.*)$`, 'm'))
99
+ if (!match) return false
100
+ const value = match[1].replace(/\[待补充\]/g, '').replace(/[\s、,,。;;]/g, '')
101
+ return value.length === 0
102
+ })
103
+ checks.push(makeCheck(
104
+ 'outline.intent-fields-substantive',
105
+ hollow.length === 0,
106
+ name,
107
+ hollow.length ? `只有占位符,没有实际内容:${hollow.join('、')}` : '目标情绪与主角目标/关键选择都写了实际内容',
108
+ '目标情绪写清前状态→后状态;主角目标/关键选择写清本章要什么、必须做出的判断。这两项不接受 [待补充]',
109
+ '只把这两个字段替换成本章的实际情绪变化与实际取舍;其余字段不动。'
110
+ ))
111
+
112
+ const missingSubs = SUBSECTIONS.filter((sub) => !new RegExp(`^#{3,4}\\s*${sub}`, 'm').test(text))
113
+ checks.push(makeCheck(
114
+ 'outline.subsections',
115
+ missingSubs.length === 0,
116
+ name,
117
+ missingSubs.length ? `缺小节:${missingSubs.join('、')}` : '四个小节齐全',
118
+ '包含 内容概括 / 情节安排 / 人物关系和出场顺序 / 情节细化 四个小节',
119
+ '只补缺失的小节标题及其条目,不重写已成立的内容。'
120
+ ))
121
+
122
+ const missingActs = FIVE_ACT.filter((act) => !fieldPattern(act).test(text))
123
+ checks.push(makeCheck(
124
+ 'outline.five-act',
125
+ missingActs.length === 0,
126
+ name,
127
+ missingActs.length ? `五段式缺:${missingActs.join('、')}` : '五段式齐全',
128
+ '内容概括写全 起因 / 发展 / 转折 / 高潮 / 结尾',
129
+ '只补缺的那一段,不改其余四段。'
130
+ ))
131
+
132
+ const lines = text.split(/\r?\n/)
133
+ let header = null
134
+ for (const line of lines) {
135
+ const cells = parseTableRow(line)
136
+ if (cells && cells.length === 4 && PLOT_HEADER_FIRST.test(cells[0])) {
137
+ header = cells
138
+ break
139
+ }
140
+ }
141
+ const headerOk = Boolean(header) && header[2].includes('功能标签') && header[3].includes('执行边界')
142
+ checks.push(makeCheck(
143
+ 'outline.plotpoint-table',
144
+ headerOk,
145
+ name,
146
+ header ? `表头:${header.join(' | ')}` : '未找到 | # | 情节点 | 功能标签 | 执行边界 | 表头',
147
+ '情节细化使用四列表格:# / 情节点(谁做了什么) / 功能标签 / 执行边界',
148
+ '只把情节点序列改成四列表格,逐点补功能标签与执行边界;不增删情节点本身。'
149
+ ))
150
+
151
+ const targetMatch = text.match(/字数目标\s*[::]\s*(?:约\s*)?([\d,,]+)/)
152
+ const target = targetMatch ? Number(targetMatch[1].replace(/[,,]/g, '')) : null
153
+ const caliberOk = new RegExp(`字数口径\\s*[::]\\s*${CALIBER}`).test(text)
154
+ checks.push(makeCheck(
155
+ 'outline.wordcount-target',
156
+ Boolean(target) && Number.isFinite(target) && target >= 500 && target <= 20000 && caliberOk,
157
+ name,
158
+ `字数目标:${target === null ? '未识别' : target};字数口径 ${CALIBER}:${caliberOk}`,
159
+ `字数目标为 500-20000 的正整数,并声明 字数口径:${CALIBER}`,
160
+ '只补字数目标或字数口径行,不调整情节安排。'
161
+ ))
162
+
163
+ return report(file, checks)
164
+ }
165
+
166
+ function report(file, checks) {
167
+ const failures = checks.filter((check) => !check.ok)
168
+ return {
169
+ schema_version: 1,
170
+ verifier: 'story-long-write.outline-contract',
171
+ file: path.resolve(file),
172
+ ok: failures.length === 0,
173
+ checks,
174
+ failures,
175
+ repair_scope: failures.map((failure) => ({
176
+ id: failure.id,
177
+ file: failure.file,
178
+ evidence: failure.evidence,
179
+ expected: failure.expected,
180
+ references: failure.references,
181
+ repair: failure.repair,
182
+ })),
183
+ }
184
+ }
185
+
186
+ function resolveChapter(project, chapter) {
187
+ const dir = path.join(project, '大纲')
188
+ let entries
189
+ try {
190
+ entries = fs.readdirSync(dir)
191
+ } catch (error) {
192
+ return { error: `无法读取 ${dir}:${error.message}` }
193
+ }
194
+ const wanted = Number(chapter)
195
+ const hit = entries.find((entry) => {
196
+ const match = entry.match(/^细纲_第0*(\d+)章.*\.md$/)
197
+ return match && Number(match[1]) === wanted
198
+ })
199
+ if (!hit) return { error: `${dir} 下没有第 ${wanted} 章细纲` }
200
+ return { file: path.join(dir, hit) }
201
+ }
202
+
203
+ function parseArgs(argv) {
204
+ const files = []
205
+ let project = null
206
+ let chapter = null
207
+ for (let index = 0; index < argv.length; index++) {
208
+ const arg = argv[index]
209
+ if (arg === '--json') continue
210
+ if (arg === '--project' || arg === '--chapter') {
211
+ if (index + 1 >= argv.length || argv[index + 1].startsWith('--')) return null
212
+ const value = argv[++index]
213
+ if (arg === '--project') project = value
214
+ else chapter = value
215
+ continue
216
+ }
217
+ if (arg.startsWith('--')) return null
218
+ files.push(arg)
219
+ }
220
+ if (project || chapter) {
221
+ if (!project || !chapter || files.length || !/^\d+$/.test(chapter)) return null
222
+ return { project, chapter }
223
+ }
224
+ if (!files.length) return null
225
+ return { files }
226
+ }
227
+
228
+ function main(argv) {
229
+ const parsed = parseArgs(argv)
230
+ if (!parsed) {
231
+ process.stderr.write('用法: node scripts/check-outline-contract.js --json <细纲路径...> | --json --project <书目录> --chapter N\n')
232
+ return 2
233
+ }
234
+ let targets = parsed.files
235
+ if (!targets) {
236
+ const resolved = resolveChapter(parsed.project, parsed.chapter)
237
+ if (resolved.error) {
238
+ process.stderr.write(`${resolved.error}\n`)
239
+ return 2
240
+ }
241
+ targets = [resolved.file]
242
+ }
243
+ const reports = targets.map((file) => verify(file))
244
+ const ok = reports.every((entry) => entry.ok)
245
+ process.stdout.write(`${JSON.stringify(reports.length === 1 ? reports[0] : reports, null, 2)}\n`)
246
+ return ok ? 0 : 1
247
+ }
248
+
249
+ if (require.main === module) process.exitCode = main(process.argv.slice(2))
250
+
251
+ module.exports = { verify, FIELDS, SUBSECTIONS, FIVE_ACT }