@oh-story/dsh 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -14
- package/lib/client.js +209 -73
- package/lib/client.js.map +3 -3
- package/lib/drama/manifest.json +248 -168
- package/lib/drama/skills/short-drama/SKILL.md +16 -4
- package/lib/drama/skills/short-drama/assets/project-template/short-drama.json +3 -0
- package/lib/drama/skills/short-drama/references/creator-documents.md +3 -0
- package/lib/drama/skills/short-drama/references/knowhow-index.md +15 -0
- package/lib/drama/skills/short-drama/scripts/creator_markdown_check.py +14 -0
- package/lib/drama/skills/short-drama/scripts/project_tool.py +131 -0
- package/lib/drama/skills/short-drama-assets/SKILL.md +2 -1
- package/lib/drama/skills/short-drama-assets/references/asset-review-checklist.md +2 -0
- package/lib/drama/skills/short-drama-assets/references/character-and-look.md +10 -0
- package/lib/drama/skills/short-drama-assets/references/continuity-lock.md +6 -9
- package/lib/drama/skills/short-drama-assets/references/era-anchors.md +37 -0
- package/lib/drama/skills/short-drama-assets/references/stage-contract.md +2 -0
- package/lib/drama/skills/short-drama-assets/references/voice-direction.md +28 -0
- package/lib/drama/skills/short-drama-develop/SKILL.md +10 -4
- package/lib/drama/skills/short-drama-develop/assets/adaptation-map.example.jsonl +1 -1
- package/lib/drama/skills/short-drama-develop/assets/creative-brief.md +8 -0
- package/lib/drama/skills/short-drama-develop/references/adaptation-craft.md +80 -13
- package/lib/drama/skills/short-drama-develop/references/episode-design.md +95 -12
- package/lib/drama/skills/short-drama-develop/references/genre-and-hook-playbook.md +9 -5
- package/lib/drama/skills/short-drama-develop/references/genre-cards//345/244/215/344/273/207/346/211/223/350/204/270.md +1 -1
- package/lib/drama/skills/short-drama-develop/references/genre-cards//347/263/273/347/273/237/346/265/201.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//351/200/206/350/242/255.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//351/207/215/347/224/237/347/251/277/350/266/212.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards.md +10 -7
- package/lib/drama/skills/short-drama-develop/references/premise-devices.md +15 -9
- package/lib/drama/skills/short-drama-develop/references/serial-character-and-memory.md +3 -2
- package/lib/drama/skills/short-drama-develop/references/stage-contract.md +14 -7
- package/lib/drama/skills/short-drama-develop/references/story-craft.md +7 -3
- package/lib/drama/skills/short-drama-edit/SKILL.md +65 -44
- package/lib/drama/skills/short-drama-edit/assets/remotion/README.md +49 -13
- package/lib/drama/skills/short-drama-edit/assets/remotion/package.json +4 -2
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/Overlay.tsx +31 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/Root.tsx +5 -5
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/Subtitles.tsx +68 -69
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/font.ts +39 -29
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/rules.mjs +188 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/schema.ts +26 -13
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/Card.tsx +72 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/CornerChip.tsx +39 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/ScreenText.tsx +36 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/SystemPanel.tsx +44 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/TaskPanel.tsx +100 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/chrome.tsx +197 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/tokens.ts +62 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/tsconfig.json +1 -0
- package/lib/drama/skills/short-drama-edit/assets//345/211/252/350/276/221/345/215/225.md +6 -4
- package/lib/drama/skills/short-drama-edit/references/cut-craft.md +26 -67
- package/lib/drama/skills/short-drama-edit/references/delivery-verify.md +31 -56
- package/lib/drama/skills/short-drama-edit/references/generated-footage.md +42 -78
- package/lib/drama/skills/short-drama-edit/references/sound-and-subtitles.md +44 -92
- package/lib/drama/skills/short-drama-edit/references/stage-contract.md +14 -16
- package/lib/drama/skills/short-drama-edit/scripts/edit_tool.py +1272 -125
- package/lib/drama/skills/short-drama-edit/scripts/selftest.py +113 -9
- package/lib/drama/skills/short-drama-image-prompts/SKILL.md +2 -0
- package/lib/drama/skills/short-drama-image-prompts/references/common-recipe.md +11 -0
- package/lib/drama/skills/short-drama-novel-analyze/SKILL.md +3 -3
- package/lib/drama/skills/short-drama-novel-analyze/assets/episode-candidate.example.jsonl +2 -2
- package/lib/drama/skills/short-drama-novel-analyze/references/adaptation-triage.md +8 -4
- package/lib/drama/skills/short-drama-novel-analyze/references/adaptation-value.md +10 -3
- package/lib/drama/skills/short-drama-novel-analyze/references/aggregation-and-entities.md +25 -1
- package/lib/drama/skills/short-drama-novel-analyze/references/stage-contract.md +1 -0
- package/lib/drama/skills/short-drama-produce/SKILL.md +5 -1
- package/lib/drama/skills/short-drama-produce/references/adapter-contract.md +14 -20
- package/lib/drama/skills/short-drama-produce/references/providers/minimax-h3-video.md +8 -26
- package/lib/drama/skills/short-drama-produce/references/providers/minimax-speech.md +41 -0
- package/lib/drama/skills/short-drama-produce/scripts/provider_adapters.py +142 -1
- package/lib/drama/skills/short-drama-review/SKILL.md +4 -5
- package/lib/drama/skills/short-drama-review/references/production-quality-gates.md +6 -19
- package/lib/drama/skills/short-drama-review/references/review-method.md +6 -1
- package/lib/drama/skills/short-drama-review/references/rubric-assets-prompts.md +11 -0
- package/lib/drama/skills/short-drama-review/references/rubric-story-script.md +77 -3
- package/lib/drama/skills/short-drama-review/references/rubric-visual-motion.md +24 -35
- package/lib/drama/skills/short-drama-review/references/stage-contract.md +3 -0
- package/lib/drama/skills/short-drama-storyboard/SKILL.md +23 -11
- package/lib/drama/skills/short-drama-storyboard/references/blocking-playbooks.md +1 -1
- package/lib/drama/skills/short-drama-storyboard/references/lighting-craft.md +39 -0
- package/lib/drama/skills/short-drama-storyboard/references/production-shot-grammar.md +2 -2
- package/lib/drama/skills/short-drama-storyboard/references/shot-craft.md +139 -34
- package/lib/drama/skills/short-drama-storyboard/references/stage-contract.md +5 -3
- package/lib/drama/skills/short-drama-video-prompts/SKILL.md +15 -12
- package/lib/drama/skills/short-drama-video-prompts/references/camera-audio-continuity.md +29 -0
- package/lib/drama/skills/short-drama-video-prompts/references/delivery-profile.md +4 -5
- package/lib/drama/skills/short-drama-video-prompts/references/generability.md +4 -2
- package/lib/drama/skills/short-drama-video-prompts/references/minimax-h3.md +52 -39
- package/lib/drama/skills/short-drama-video-prompts/references/motion-recipe.md +24 -21
- package/lib/drama/skills/short-drama-video-prompts/references/performance-action-timing.md +9 -23
- package/lib/drama/skills/short-drama-video-prompts/references/production-prompt-grammar.md +14 -26
- package/lib/drama/skills/short-drama-video-prompts/references/review-and-fixtures.md +1 -1
- package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.0.md +2 -3
- package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.5.md +34 -9
- package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +3 -2
- package/lib/drama/skills/short-drama-video-prompts/references/target-model-profile.md +8 -1
- package/lib/drama/skills/short-drama-video-prompts/references/wan-3.0.md +103 -0
- package/lib/drama/skills/short-drama-video-prompts/scripts/motion_timing_check.py +8 -7
- package/lib/drama/skills/short-drama-write/SKILL.md +10 -7
- package/lib/drama/skills/short-drama-write/references/dialogue-craft.md +1 -1
- package/lib/drama/skills/short-drama-write/references/script-craft.md +56 -3
- package/lib/drama/skills/short-drama-write/references/stage-contract.md +4 -0
- package/lib/drama/skills/short-drama-write/scripts/duration_estimate.py +48 -2
- package/lib/index.js +346 -98
- package/lib/index.js.map +4 -4
- package/lib/novel-to-game/README.md +299 -59
- package/lib/novel-to-game/README_ZH.md +299 -56
- package/lib/novel-to-game/VERSION +1 -1
- package/lib/novel-to-game/examples/jin-ping-mei/build/BUILD_BRIEF.md +3 -1
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/RUN.md +11 -3
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/new-guofeng.css +397 -8
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/style.css +0 -31
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/data.js +71 -73
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/engine.js +78 -89
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/main.js +37 -14
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/text.js +5 -5
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/package.json +2 -1
- package/lib/novel-to-game/examples/jin-ping-mei/qa/README.md +11 -16
- package/lib/novel-to-game/examples/jin-ping-mei/qa/verification.json +11 -11
- package/lib/novel-to-game/examples/jin-ping-mei/qa/verify_playable_model.mjs +23 -0
- package/lib/novel-to-game/manifest.json +77 -87
- package/lib/novel-to-game/skills/game-art-direction/SKILL.md +7 -12
- package/lib/novel-to-game/skills/game-art-direction/references/art-direction-method.md +27 -106
- package/lib/novel-to-game/skills/game-build/SKILL.md +13 -14
- package/lib/novel-to-game/skills/game-build/references/blender-asset-workflow.md +24 -0
- package/lib/novel-to-game/skills/game-build/references/build-brief-contract.md +45 -82
- package/lib/novel-to-game/skills/game-build/references/generative-media-pipeline.md +14 -45
- package/lib/novel-to-game/skills/game-build/references/playable-model-contract.md +30 -65
- package/lib/novel-to-game/skills/game-build/references/tts-production-contract.md +13 -27
- package/lib/novel-to-game/skills/game-concept/SKILL.md +13 -15
- package/lib/novel-to-game/skills/game-concept/references/concept-method.md +28 -75
- package/lib/novel-to-game/skills/game-qa/SKILL.md +6 -7
- package/lib/novel-to-game/skills/game-qa/references/test-design-method.md +9 -5
- package/lib/novel-to-game/skills/game-world-design/SKILL.md +12 -16
- package/lib/novel-to-game/skills/game-world-design/references/narrative-design-method.md +23 -72
- package/lib/novel-to-game/skills/game-world-design/references/numeric-design-method.md +14 -48
- package/lib/novel-to-game/skills/game-world-design/references/world-design-method.md +36 -103
- package/lib/novel-to-game/skills/novel-game-analyze/SKILL.md +4 -10
- package/lib/novel-to-game/skills/novel-game-analyze/references/gameability-protocol.md +4 -4
- package/lib/novel-to-game/skills/novel-to-game/SKILL.md +9 -21
- package/lib/novel-to-game/skills/novel-to-game/references/intake-method.md +5 -4
- package/lib/novel-to-game/skills/novel-to-game/references/pipeline-contract.md +5 -8
- package/lib/oh-story/manifest.json +607 -327
- package/lib/oh-story/roles/chapter-extractor.md +177 -237
- package/lib/oh-story/roles/character-designer.md +1 -2
- package/lib/oh-story/roles/consistency-checker.md +15 -13
- package/lib/oh-story/roles/narrative-writer.md +36 -38
- package/lib/oh-story/roles/story-architect.md +9 -61
- package/lib/oh-story/roles/story-explorer.md +20 -125
- package/lib/oh-story/roles/story-researcher.md +0 -1
- package/lib/oh-story/skills/story/SKILL.md +15 -9
- package/lib/oh-story/skills/story/VERSION +1 -1
- package/lib/oh-story/skills/story/references/author-memory-maintenance.md +75 -0
- package/lib/oh-story/skills/story/references/author-memory.md +46 -94
- package/lib/oh-story/skills/story/scripts/author_memory_commit.py +934 -170
- package/lib/oh-story/skills/story-cover/SKILL.md +10 -1
- package/lib/oh-story/skills/story-deslop/SKILL.md +59 -73
- package/lib/oh-story/skills/story-deslop/references/agent-calls.md +5 -0
- package/lib/oh-story/skills/story-deslop/references/anti-ai-writing.md +12 -11
- package/lib/oh-story/skills/story-deslop/references/author-memory-maintenance.md +75 -0
- package/lib/oh-story/skills/story-deslop/references/author-memory.md +46 -94
- package/lib/oh-story/skills/story-deslop/references/banned-words.md +2 -2
- package/lib/oh-story/skills/story-deslop/references/deslop-gates.md +22 -5
- package/lib/oh-story/skills/story-deslop/references/style-resolution.md +4 -4
- package/lib/oh-story/skills/story-deslop/scripts/author_memory_commit.py +934 -170
- package/lib/oh-story/skills/story-deslop/scripts/check-ai-patterns.js +155 -8
- package/lib/oh-story/skills/story-import/SKILL.md +64 -584
- package/lib/oh-story/skills/story-import/references/character-state-reverse.md +1 -1
- package/lib/oh-story/skills/story-import/references/deep-analysis.md +47 -0
- package/lib/oh-story/skills/story-import/references/format-and-structure.md +1 -1
- package/lib/oh-story/skills/story-import/references/import-report.md +64 -0
- package/lib/oh-story/skills/story-import/references/import-special-cases.md +34 -0
- package/lib/oh-story/skills/story-import/references/import-tracking.md +95 -0
- package/lib/oh-story/skills/story-import/references/length-routing.md +1 -1
- package/lib/oh-story/skills/story-import/references/outline-reverse-rules.md +79 -0
- package/lib/oh-story/skills/story-import/references/outline-reverse.md +24 -0
- package/lib/oh-story/skills/story-import/references/state-tracking.md +4 -69
- package/lib/oh-story/skills/story-import/references/structure-mapping-long.md +98 -92
- package/lib/oh-story/skills/story-import/references/structure-mapping-short.md +24 -12
- package/lib/oh-story/skills/story-import/references/tracking-initialization.md +1 -1
- package/lib/oh-story/skills/story-import/references/tracking-transaction.md +15 -11
- package/lib/oh-story/skills/story-import/scripts/build_outline_brief.py +332 -0
- package/lib/oh-story/skills/story-import/scripts/check-outline-contract.js +132 -27
- package/lib/oh-story/skills/story-import/scripts/tracking_commit.py +478 -15
- package/lib/oh-story/skills/story-import/scripts/wordcount_core.py +182 -23
- package/lib/oh-story/skills/story-long-analyze/SKILL.md +81 -270
- package/lib/oh-story/skills/story-long-analyze/references/author-facing.md +252 -0
- package/lib/oh-story/skills/story-long-analyze/references/deconstruction-notes.md +3 -3
- package/lib/oh-story/skills/story-long-analyze/references/final-checks.md +19 -0
- package/lib/oh-story/skills/story-long-analyze/references/index-rebuild.md +11 -0
- package/lib/oh-story/skills/story-long-analyze/references/inspiration-library.md +105 -0
- package/lib/oh-story/skills/story-long-analyze/references/pipeline-ops.md +138 -64
- package/lib/oh-story/skills/story-long-analyze/references/semantic-acceptance-fixtures.md +84 -0
- package/lib/oh-story/skills/story-long-analyze/references/stage1-golden-chapters.md +128 -0
- package/lib/oh-story/skills/story-long-analyze/references/stage2-extraction.md +229 -0
- package/lib/oh-story/skills/story-long-analyze/references/stage3-plot-rhythm.md +480 -0
- package/lib/oh-story/skills/story-long-analyze/references/stage4-characters-settings.md +195 -0
- package/lib/oh-story/skills/story-long-analyze/references/stage5-report.md +33 -0
- package/lib/oh-story/skills/story-long-analyze/references/style-profile-generator.md +55 -128
- package/lib/oh-story/skills/story-long-analyze/references/style-profile-protocol.md +6 -6
- package/lib/oh-story/skills/story-long-analyze/references/synthesis-inputs.md +39 -0
- package/lib/oh-story/skills/story-long-analyze/scripts/build_chapter_index.py +466 -0
- package/lib/oh-story/skills/story-long-analyze/scripts/inspect_existing_assets.py +702 -0
- package/lib/oh-story/skills/story-long-analyze/scripts/inspiration_index.py +864 -0
- package/lib/oh-story/skills/story-long-analyze/scripts/manage_analysis_run.py +1145 -0
- package/lib/oh-story/skills/story-long-analyze/scripts/render_relation_chart.py +425 -0
- package/lib/oh-story/skills/story-long-scan/SKILL.md +45 -194
- package/lib/oh-story/skills/story-long-scan/references/platform-ciweimao.md +19 -0
- package/lib/oh-story/skills/story-long-scan/references/platform-fanqie.md +45 -0
- package/lib/oh-story/skills/story-long-scan/references/platform-jjwxc.md +28 -0
- package/lib/oh-story/skills/story-long-scan/references/platform-qidian.md +35 -0
- package/lib/oh-story/skills/story-long-scan/references/platform-qimao.md +27 -0
- package/lib/oh-story/skills/story-long-scan/references/topic-decision.md +6 -2
- package/lib/oh-story/skills/story-long-write/SKILL.md +49 -81
- package/lib/oh-story/skills/story-long-write/references/agent-calls.md +47 -0
- package/lib/oh-story/skills/story-long-write/references/anti-ai-writing.md +12 -11
- package/lib/oh-story/skills/story-long-write/references/artifact-protocols.md +24 -202
- package/lib/oh-story/skills/story-long-write/references/author-memory-maintenance.md +75 -0
- package/lib/oh-story/skills/story-long-write/references/author-memory.md +46 -94
- package/lib/oh-story/skills/story-long-write/references/banned-words.md +2 -2
- package/lib/oh-story/skills/story-long-write/references/benchmark-recall.md +7 -11
- package/lib/oh-story/skills/story-long-write/references/character-relations.md +49 -1
- package/lib/oh-story/skills/story-long-write/references/cross-book-recall.md +26 -0
- package/lib/oh-story/skills/story-long-write/references/deslop-gates.md +171 -0
- package/lib/oh-story/skills/story-long-write/references/dialogue-mastery.md +4 -0
- package/lib/oh-story/skills/story-long-write/references/emotion-on-page.md +116 -0
- package/lib/oh-story/skills/story-long-write/references/emotional-arc-design.md +1 -114
- package/lib/oh-story/skills/story-long-write/references/emotional-methods.md +2 -2
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/long-chapter-quality.md +7 -15
- package/lib/oh-story/skills/story-long-write/references/long-format.md +0 -8
- package/lib/oh-story/skills/story-long-write/references/long-genre-catalog.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/long-genre-mechanics.md +3 -3
- package/lib/oh-story/skills/story-long-write/references/opening-design.md +2 -2
- package/lib/oh-story/skills/story-long-write/references/outline-conflict.md +4 -4
- package/lib/oh-story/skills/story-long-write/references/outline-methods.md +7 -7
- package/lib/oh-story/skills/story-long-write/references/outline-rhythm.md +3 -3
- package/lib/oh-story/skills/story-long-write/references/outline-structure-theory.md +14 -69
- package/lib/oh-story/skills/story-long-write/references/plot-frameworks.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/plot-special-topics.md +2 -2
- package/lib/oh-story/skills/story-long-write/references/project-files.md +19 -13
- package/lib/oh-story/skills/story-long-write/references/reader-contract-and-progression.md +13 -5
- package/lib/oh-story/skills/story-long-write/references/reference-index.md +5 -6
- package/lib/oh-story/skills/story-long-write/references/stop-and-fix.md +9 -0
- package/lib/oh-story/skills/story-long-write/references/style-combat-face.md +1 -58
- package/lib/oh-story/skills/story-long-write/references/style-genre-modules.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/style-resolution.md +4 -4
- package/lib/oh-story/skills/story-long-write/references/tracking-initialization.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/tracking-transaction.md +15 -11
- package/lib/oh-story/skills/story-long-write/references/workflow-chapter.md +81 -121
- package/lib/oh-story/skills/story-long-write/references/workflow-daily.md +41 -139
- package/lib/oh-story/skills/story-long-write/references/workflow-outline.md +157 -0
- package/lib/oh-story/skills/story-long-write/references/workflow-revision.md +57 -67
- package/lib/oh-story/skills/story-long-write/references/workflow-setup.md +112 -253
- package/lib/oh-story/skills/story-long-write/references/workflow-volume.md +142 -0
- package/lib/oh-story/skills/story-long-write/references/writer-prompt-fallback.md +6 -4
- package/lib/oh-story/skills/story-long-write/references/writing-craft.md +19 -65
- package/lib/oh-story/skills/story-long-write/scripts/author_memory_commit.py +934 -170
- package/lib/oh-story/skills/story-long-write/scripts/build_architect_brief.py +260 -0
- package/lib/oh-story/skills/story-long-write/scripts/build_writer_prompt.py +226 -25
- package/lib/oh-story/skills/story-long-write/scripts/check-ai-patterns.js +155 -8
- package/lib/oh-story/skills/story-long-write/scripts/check-outline-contract.js +132 -27
- package/lib/oh-story/skills/story-long-write/scripts/check-outline-copy.js +7 -2
- package/lib/oh-story/skills/story-long-write/scripts/outline_view.py +7 -4
- package/lib/oh-story/skills/story-long-write/scripts/storyctl.py +304 -46
- package/lib/oh-story/skills/story-long-write/scripts/tracking_commit.py +478 -15
- package/lib/oh-story/skills/story-long-write/scripts/wordcount_core.py +182 -23
- package/lib/oh-story/skills/story-review/SKILL.md +31 -302
- package/lib/oh-story/skills/story-review/references/agent-prompts.md +184 -0
- package/lib/oh-story/skills/story-review/references/anti-ai-writing.md +12 -11
- package/lib/oh-story/skills/story-review/references/author-memory-maintenance.md +75 -0
- package/lib/oh-story/skills/story-review/references/author-memory.md +46 -94
- package/lib/oh-story/skills/story-review/references/banned-words.md +2 -2
- package/lib/oh-story/skills/story-review/references/batch-review.md +19 -0
- package/lib/oh-story/skills/story-review/references/character-relations.md +49 -1
- package/lib/oh-story/skills/story-review/references/dialogue-mastery.md +4 -0
- package/lib/oh-story/skills/story-review/references/review-quality.md +6 -11
- package/lib/oh-story/skills/story-review/references/review-tracking.md +10 -0
- package/lib/oh-story/skills/story-review/references/solo.md +52 -0
- package/lib/oh-story/skills/story-review/references/style-resolution.md +4 -4
- package/lib/oh-story/skills/story-review/references/tracking-initialization.md +1 -1
- package/lib/oh-story/skills/story-review/references/tracking-transaction.md +15 -11
- package/lib/oh-story/skills/story-review/scripts/author_memory_commit.py +934 -170
- package/lib/oh-story/skills/story-review/scripts/check-ai-patterns.js +155 -8
- package/lib/oh-story/skills/story-review/scripts/tracking_commit.py +478 -15
- package/lib/oh-story/skills/story-review/scripts/wordcount_core.py +182 -23
- package/lib/oh-story/skills/story-setup/SKILL.md +71 -452
- package/lib/oh-story/skills/story-setup/references/agent-references/agent-quality.md +4 -4
- package/lib/oh-story/skills/story-setup/references/agent-references/anti-ai-writing.md +12 -11
- package/lib/oh-story/skills/story-setup/references/agent-references/banned-words.md +2 -2
- package/lib/oh-story/skills/story-setup/references/agent-references/benchmark-style-load.md +107 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/character-relations.md +49 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/deslop-gates.md +22 -5
- package/lib/oh-story/skills/story-setup/references/agent-references/dialogue-mastery.md +4 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/emotion-on-page.md +116 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/emotional-arc-design.md +1 -114
- package/lib/oh-story/skills/story-setup/references/agent-references/format-and-structure.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/long-emotional-methods.md +2 -2
- package/lib/oh-story/skills/story-setup/references/agent-references/long-genre-catalog.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/long-genre-mechanics.md +3 -3
- package/lib/oh-story/skills/story-setup/references/agent-references/long-quality.md +7 -5
- package/lib/oh-story/skills/story-setup/references/agent-references/opening-design.md +2 -2
- package/lib/oh-story/skills/story-setup/references/agent-references/outline-conflict.md +4 -4
- package/lib/oh-story/skills/story-setup/references/agent-references/outline-methods.md +7 -7
- package/lib/oh-story/skills/story-setup/references/agent-references/outline-rhythm.md +3 -3
- package/lib/oh-story/skills/story-setup/references/agent-references/short-emotional-methods.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/short-genre-formulas.md +0 -15
- package/lib/oh-story/skills/story-setup/references/agent-references/short-reversal.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/style-combat-face.md +1 -58
- package/lib/oh-story/skills/story-setup/references/agent-references/style-genre-modules.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/style-resolution.md +4 -4
- package/lib/oh-story/skills/story-setup/references/agent-references/writing-craft.md +19 -65
- package/lib/oh-story/skills/story-setup/references/diagnostics.md +4 -4
- package/lib/oh-story/skills/story-short-analyze/SKILL.md +56 -110
- package/lib/oh-story/skills/story-short-analyze/references/analysis-character-relations.md +1 -1
- package/lib/oh-story/skills/story-short-analyze/references/analysis-method.md +42 -0
- package/lib/oh-story/skills/story-short-analyze/references/optional-modules.md +97 -0
- package/lib/oh-story/skills/story-short-analyze/references/output-contract.md +9 -47
- package/lib/oh-story/skills/story-short-analyze/references/quality-checklist.md +80 -0
- package/lib/oh-story/skills/story-short-analyze/references/source-story-quality.md +4 -4
- package/lib/oh-story/skills/story-short-analyze/references/stage2-3-structure-emotion.md +308 -0
- package/lib/oh-story/skills/story-short-analyze/references/stage4-6-reversal-summary.md +611 -0
- package/lib/oh-story/skills/story-short-scan/SKILL.md +35 -65
- package/lib/oh-story/skills/story-short-scan/references/manual-rank-input.md +36 -0
- package/lib/oh-story/skills/story-short-scan/references/platform-dianzhong.md +24 -0
- package/lib/oh-story/skills/story-short-scan/references/platform-heiyan.md +21 -0
- package/lib/oh-story/skills/story-short-scan/references/topic-match.md +38 -0
- package/lib/oh-story/skills/story-short-write/SKILL.md +23 -175
- package/lib/oh-story/skills/story-short-write/references/agent-calls.md +13 -0
- package/lib/oh-story/skills/story-short-write/references/author-memory-maintenance.md +75 -0
- package/lib/oh-story/skills/story-short-write/references/author-memory.md +46 -94
- package/lib/oh-story/skills/story-short-write/references/banned-words.md +2 -2
- package/lib/oh-story/skills/story-short-write/references/benchmark-recall.md +1 -21
- package/lib/oh-story/skills/story-short-write/references/dialogue-mastery.md +4 -0
- package/lib/oh-story/skills/story-short-write/references/emotional-methods.md +1 -1
- package/lib/oh-story/skills/story-short-write/references/genre-writing-formulas.md +0 -15
- package/lib/oh-story/skills/story-short-write/references/output-contract.md +9 -47
- package/lib/oh-story/skills/story-short-write/references/reference-index.md +17 -47
- package/lib/oh-story/skills/story-short-write/references/scene-craft.md +40 -0
- package/lib/oh-story/skills/story-short-write/references/short-craft.md +7 -43
- package/lib/oh-story/skills/story-short-write/references/short-format.md +3 -3
- package/lib/oh-story/skills/story-short-write/references/short-prose-quality.md +2 -1
- package/lib/oh-story/skills/story-short-write/references/short-reversal.md +1 -1
- package/lib/oh-story/skills/story-short-write/references/style-resolution.md +4 -4
- package/lib/oh-story/skills/story-short-write/references/submission-craft.md +1 -1
- package/lib/oh-story/skills/story-short-write/references/villain-and-reveal.md +5 -10
- package/lib/oh-story/skills/story-short-write/references/workflow-design.md +21 -13
- package/lib/oh-story/skills/story-short-write/references/workflow-draft.md +116 -0
- package/lib/oh-story/skills/story-short-write/references/workflow-revision.md +99 -0
- package/lib/oh-story/skills/story-short-write/references/writing-workflow.md +7 -119
- package/lib/oh-story/skills/story-short-write/scripts/author_memory_commit.py +934 -170
- package/lib/oh-story/skills/story-short-write/scripts/check-ai-patterns.js +155 -8
- package/lib/oh-story/skills/story-short-write/scripts/check-outline-copy.js +7 -2
- package/lib/types/client/drama-production-view.d.ts.map +1 -1
- package/lib/types/client/file-activity.d.ts +19 -1
- package/lib/types/client/file-activity.d.ts.map +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/production-prompts.d.ts +7 -0
- package/lib/types/client/production-prompts.d.ts.map +1 -1
- package/lib/types/client/production-runtime.d.ts +16 -0
- package/lib/types/client/production-runtime.d.ts.map +1 -1
- package/lib/types/client/video-studio.d.ts.map +1 -1
- package/lib/types/drama-adapters.d.ts +5 -3
- package/lib/types/drama-adapters.d.ts.map +1 -1
- package/lib/types/native-hooks.d.ts +53 -1
- package/lib/types/native-hooks.d.ts.map +1 -1
- package/lib/types/role-identity.d.ts +17 -0
- package/lib/types/role-identity.d.ts.map +1 -0
- package/lib/types/role-tool.d.ts.map +1 -1
- package/lib/types/skill-provider.d.ts.map +1 -1
- package/lib/types/video-project.d.ts.map +1 -1
- package/lib/types/workspace-route.d.ts.map +1 -1
- package/lib/video-recap/CHANGELOG.md +60 -1
- package/lib/video-recap/README.en.md +348 -137
- package/lib/video-recap/README.md +340 -136
- package/lib/video-recap/manifest.json +406 -251
- package/lib/video-recap/skills/video-assemble/SKILL.md +30 -15
- package/lib/video-recap/skills/video-assemble/references/audio-modes.md +63 -0
- package/lib/video-recap/skills/video-assemble/references/explicit-audio-mix.md +75 -0
- package/lib/video-recap/skills/video-assemble/references/foreground-compose.md +118 -0
- package/lib/video-recap/skills/video-assemble/references/narration-adoption.md +103 -0
- package/lib/video-recap/skills/video-assemble/references/packaging.md +45 -0
- package/lib/video-recap/skills/video-assemble/references/pair-media.md +74 -0
- package/lib/video-recap/skills/video-assemble/references/source-score.md +147 -0
- package/lib/video-recap/skills/video-assemble/references/subtitle-track.md +202 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/__init__.py +1 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/audio_mix_binding.py +279 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/frozen_audio.py +187 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/narration_binding.py +323 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/strict_inputs.py +109 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/strict_publish.py +130 -0
- package/lib/video-recap/skills/video-assemble/scripts/artifacts.py +10 -46
- package/lib/video-recap/skills/video-assemble/scripts/assemble.py +378 -119
- package/lib/video-recap/skills/video-assemble/scripts/assemble_constants.py +29 -12
- package/lib/video-recap/skills/video-assemble/scripts/assembly_contract.py +95 -44
- package/lib/video-recap/skills/video-assemble/scripts/assembly_settings.py +75 -32
- package/lib/video-recap/skills/video-assemble/scripts/audio_mix.py +11 -11
- package/lib/video-recap/skills/video-assemble/scripts/compose_foreground.py +293 -0
- package/lib/video-recap/skills/video-assemble/scripts/export_jianying.py +71 -78
- package/lib/video-recap/skills/video-assemble/scripts/jianying/__init__.py +1 -0
- package/lib/video-recap/skills/video-assemble/scripts/{jianying_builders.py → jianying/builders.py} +39 -67
- package/lib/video-recap/skills/video-assemble/scripts/{jianying_model.py → jianying/model.py} +3 -11
- package/lib/video-recap/skills/video-assemble/scripts/{jianying_optional.py → jianying/optional.py} +1 -1
- package/lib/video-recap/skills/video-assemble/scripts/jianying/schema.py +53 -0
- package/lib/video-recap/skills/video-assemble/scripts/{jianying_templates.py → jianying/templates.py} +1 -1
- package/lib/video-recap/skills/video-assemble/scripts/{jianying_timeline_contract.py → jianying/timeline_contract.py} +34 -13
- package/lib/video-recap/skills/video-assemble/scripts/{jianying_writer.py → jianying/writer.py} +7 -17
- package/lib/video-recap/skills/video-assemble/scripts/lib.py +37 -4
- package/lib/video-recap/skills/video-assemble/scripts/media.py +12 -21
- package/lib/video-recap/skills/video-assemble/scripts/narration_audio.py +64 -34
- package/lib/video-recap/skills/video-assemble/scripts/packaging.py +122 -0
- package/lib/video-recap/skills/video-assemble/scripts/pair_media.py +216 -0
- package/lib/video-recap/skills/video-assemble/scripts/render_preflight.py +1 -3
- package/lib/video-recap/skills/video-assemble/scripts/source_score.py +469 -0
- package/lib/video-recap/skills/video-assemble/scripts/source_subtitles.py +25 -9
- package/lib/video-recap/skills/video-assemble/scripts/subtitles/__init__.py +1 -0
- package/lib/video-recap/skills/video-assemble/scripts/{subtitle_core.py → subtitles/core.py} +13 -6
- package/lib/video-recap/skills/video-assemble/scripts/{subtitle_render.py → subtitles/render.py} +5 -4
- package/lib/video-recap/skills/video-assemble/scripts/subtitles/track.py +324 -0
- package/lib/video-recap/skills/video-assemble/scripts/subtitles/track_binding.py +200 -0
- package/lib/video-recap/skills/video-assemble/scripts/timeline.py +30 -46
- package/lib/video-recap/skills/video-assemble/scripts/timeline_emit.py +91 -7
- package/lib/video-recap/skills/video-assemble/scripts/visual_render.py +22 -8
- package/lib/video-recap/skills/video-cut/SKILL.md +34 -16
- package/lib/video-recap/skills/video-cut/references/shot-review.md +50 -0
- package/lib/video-recap/skills/video-cut/scripts/cut.py +2 -28
- package/lib/video-recap/skills/video-cut/scripts/cut_cli.py +58 -62
- package/lib/video-recap/skills/video-cut/scripts/cut_contract.py +21 -106
- package/lib/video-recap/skills/video-cut/scripts/cut_render.py +14 -9
- package/lib/video-recap/skills/video-cut/scripts/lib.py +39 -0
- package/lib/video-recap/skills/video-cut/scripts/narration_mapping.py +2 -155
- package/lib/video-recap/skills/video-cut/scripts/narrative_selection.py +244 -0
- package/lib/video-recap/skills/video-cut/scripts/shot_review.py +357 -0
- package/lib/video-recap/skills/video-recap/SKILL.md +86 -42
- package/lib/video-recap/skills/video-recap/references/audio-routing.md +126 -0
- package/lib/video-recap/skills/video-recap/references/config-playbook.md +12 -8
- package/lib/video-recap/skills/video-recap/references/data-schema.md +44 -33
- package/lib/video-recap/skills/video-recap/references/resource-library.md +151 -0
- package/lib/video-recap/skills/video-recap/references/shift-left-qc-schema.md +1 -1
- package/lib/video-recap/skills/video-recap/scripts/doctor.py +123 -30
- package/lib/video-recap/skills/video-recap/scripts/final_qc.py +22 -75
- package/lib/video-recap/skills/video-recap/scripts/lib.py +3 -3
- package/lib/video-recap/skills/video-recap/scripts/library.py +509 -0
- package/lib/video-recap/skills/video-recap/scripts/materials.py +63 -91
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc.py +8 -70
- package/lib/video-recap/skills/video-recap/scripts/project_binding.py +286 -0
- package/lib/video-recap/skills/video-recap/scripts/qc/__init__.py +1 -0
- package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_client.py → qc/mimo_client.py} +1 -1
- package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_evidence.py → qc/mimo_evidence.py} +33 -66
- package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_observations.py → qc/mimo_observations.py} +3 -11
- package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_payload.py → qc/mimo_payload.py} +4 -7
- package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_report.py → qc/mimo_report.py} +17 -28
- package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_runner.py → qc/mimo_runner.py} +2 -2
- package/lib/video-recap/skills/video-recap/scripts/qc_contract.py +0 -19
- package/lib/video-recap/skills/video-recap/scripts/recap_cli.py +119 -50
- package/lib/video-recap/skills/video-recap/scripts/recap_inspect.py +32 -114
- package/lib/video-recap/skills/video-recap/scripts/recap_review.py +9 -23
- package/lib/video-recap/skills/video-recap/scripts/recap_runner.py +387 -334
- package/lib/video-recap/skills/video-recap/scripts/recap_runtime.py +23 -23
- package/lib/video-recap/skills/video-recap/scripts/recap_source.py +278 -0
- package/lib/video-recap/skills/video-recap/scripts/recap_stage_qc.py +25 -12
- package/lib/video-recap/skills/video-recap/scripts/recap_timeline.py +59 -52
- package/lib/video-recap/skills/video-recap/scripts/resource_lock.py +162 -0
- package/lib/video-recap/skills/video-script/SKILL.md +16 -13
- package/lib/video-recap/skills/video-script/references/creative-editing-playbook.md +9 -5
- package/lib/video-recap/skills/video-script/references/promotional-copy.md +68 -0
- package/lib/video-recap/skills/video-script/references/research-guide.md +1 -1
- package/lib/video-recap/skills/video-script/scripts/evidence_bundle.py +24 -76
- package/lib/video-recap/skills/video-script/scripts/lib.py +10 -87
- package/lib/video-recap/skills/video-script/scripts/narration_lint.py +63 -39
- package/lib/video-recap/skills/video-script/scripts/review.py +0 -2
- package/lib/video-recap/skills/video-script/scripts/review_grounding.py +35 -59
- package/lib/video-recap/skills/video-script/scripts/review_response.py +66 -128
- package/lib/video-recap/skills/video-script/scripts/review_runner.py +12 -20
- package/lib/video-recap/skills/video-script/scripts/speech_ownership.py +4 -4
- package/lib/video-recap/skills/video-script/scripts/validate.py +53 -42
- package/lib/video-recap/skills/video-understanding/SKILL.md +6 -4
- package/lib/video-recap/skills/video-understanding/references/data-schema.md +50 -156
- package/lib/video-recap/skills/video-understanding/references/research-guide.md +4 -4
- package/lib/video-recap/skills/video-understanding/scripts/asr.py +85 -65
- package/lib/video-recap/skills/video-understanding/scripts/asr_timing_evidence.py +270 -0
- package/lib/video-recap/skills/video-understanding/scripts/brief.py +2 -5
- package/lib/video-recap/skills/video-understanding/scripts/briefing/__init__.py +1 -0
- package/lib/video-recap/skills/{video-script/scripts/agent_brief.py → video-understanding/scripts/briefing/builder.py} +38 -35
- package/lib/video-recap/skills/video-understanding/scripts/{brief_context.py → briefing/context.py} +4 -35
- package/lib/video-recap/skills/{video-script/scripts/brief_inputs.py → video-understanding/scripts/briefing/inputs.py} +9 -31
- package/lib/video-recap/skills/{video-script/scripts/brief_timeline.py → video-understanding/scripts/briefing/timeline.py} +5 -6
- package/lib/video-recap/skills/video-understanding/scripts/consolidate.py +65 -116
- package/lib/video-recap/skills/video-understanding/scripts/detect.py +31 -40
- package/lib/video-recap/skills/video-understanding/scripts/lib.py +30 -86
- package/lib/video-recap/skills/video-understanding/scripts/narration_lint.py +63 -39
- package/lib/video-recap/skills/video-understanding/scripts/speech_ownership.py +4 -4
- package/lib/video-recap/skills/video-understanding/scripts/storyboard.py +17 -79
- package/lib/video-recap/skills/video-understanding/scripts/understanding_brief.py +14 -40
- package/lib/video-recap/skills/video-understanding/scripts/understanding_cache.py +64 -46
- package/lib/video-recap/skills/video-understanding/scripts/understanding_runner.py +31 -11
- package/lib/video-recap/skills/video-understanding/scripts/understanding_storyboard.py +19 -14
- package/lib/video-recap/skills/video-understanding/scripts/vlm.py +80 -108
- package/lib/video-recap/skills/video-voiceover/SKILL.md +29 -19
- package/lib/video-recap/skills/video-voiceover/references/index-tts.md +31 -0
- package/lib/video-recap/skills/video-voiceover/scripts/approved_text_policy.py +123 -0
- package/lib/video-recap/skills/video-voiceover/scripts/dub.py +51 -59
- package/lib/video-recap/skills/video-voiceover/scripts/lib.py +8 -44
- package/lib/video-recap/skills/video-voiceover/scripts/providers/__init__.py +1 -0
- package/lib/video-recap/skills/video-voiceover/scripts/providers/index_tts.py +184 -0
- package/lib/video-recap/skills/video-voiceover/scripts/voiceover.py +212 -134
- package/package.json +45 -45
- package/lib/novel-to-game/skills/game-world-design/references/dialogue-design-method.md +0 -58
- package/lib/novel-to-game/skills/game-world-design/references/game-writing-craft.md +0 -53
- package/lib/novel-to-game/skills/novel-to-game/references/intake-benchmark-reference.md +0 -38
- package/lib/oh-story/skills/story-long-analyze/references/material-decomposition.md +0 -530
- package/lib/oh-story/skills/story-long-analyze/references/output-templates.md +0 -559
- package/lib/oh-story/skills/story-long-scan/references/scan-output-format.md +0 -207
- package/lib/oh-story/skills/story-long-write/references/state-tracking.md +0 -108
- package/lib/oh-story/skills/story-short-analyze/references/material-decomposition.md +0 -678
- package/lib/oh-story/skills/story-short-analyze/references/output-templates.md +0 -561
- package/lib/video-recap/skills/video-assemble/scripts/jianying_schema.py +0 -98
- package/lib/video-recap/skills/video-recap/references/creative-editing-playbook.md +0 -225
- package/lib/video-recap/skills/video-recap/references/research-guide.md +0 -74
- package/lib/video-recap/skills/video-recap/references/timeline-and-jianying.md +0 -250
- package/lib/video-recap/skills/video-script/scripts/brief_context.py +0 -348
- package/lib/video-recap/skills/video-script/scripts/narration.py +0 -12
- package/lib/video-recap/skills/video-understanding/scripts/agent_brief.py +0 -399
- package/lib/video-recap/skills/video-understanding/scripts/brief_inputs.py +0 -290
- package/lib/video-recap/skills/video-understanding/scripts/brief_timeline.py +0 -327
- /package/lib/video-recap/skills/video-assemble/scripts/{jianying_tracks.py → jianying/tracks.py} +0 -0
- /package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_contract.py → qc/mimo_contract.py} +0 -0
- /package/lib/video-recap/skills/video-voiceover/scripts/{fish_audio.py → providers/fish_audio.py} +0 -0
|
@@ -6,6 +6,7 @@ const { loadStyleWhitelist, maskStyleText } = require('./style-whitelist.js');
|
|
|
6
6
|
const path = require('path');
|
|
7
7
|
|
|
8
8
|
const USAGE = `Usage: node check-ai-patterns.js [--check] [--json] [--fail-on=blocking|all] <file...>
|
|
9
|
+
node check-ai-patterns.js --list-review-classes
|
|
9
10
|
|
|
10
11
|
Detect high-risk AI-flavor prose patterns that need human rewrite:
|
|
11
12
|
- negative setup followed by positive flip in the same sentence
|
|
@@ -33,8 +34,10 @@ Detect high-risk AI-flavor prose patterns that need human rewrite:
|
|
|
33
34
|
|
|
34
35
|
Book-local .deslop-whitelist literal spans are excluded from style scanning (no regex or ancestor inheritance).
|
|
35
36
|
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.
|
|
36
|
-
或 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 的长推理/氛围段可保留)。
|
|
37
|
+
或 advisory (period-stutter / long-paragraph / micro-action-tic / negation-pair-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 的长推理/氛围段可保留)。
|
|
37
38
|
--fail-on=blocking 只在出现 blocking finding 时退出 1;默认 --fail-on=all 有任何 finding 即退出 1。
|
|
39
|
+
Each finding also carries review: mechanical(表面形态确定、就地改写即可)或 semantic(可能承担叙事功能,需读上下文判断是否保留);blocking 一律 mechanical。--list-review-classes 输出完整分类表(JSON)。
|
|
40
|
+
HTML comments (<!-- ... -->, e.g. the 去味:跳过 exemption marker) are metadata, not prose, and are never scanned.
|
|
38
41
|
|
|
39
42
|
The script reports findings only. It never rewrites text, because the safe fix is
|
|
40
43
|
contextual: usually delete the negative setup, write the positive term directly,
|
|
@@ -58,6 +61,10 @@ const LONG_PARAGRAPH_CHARS = 200;
|
|
|
58
61
|
// 单次出现是正常中文。
|
|
59
62
|
const MICRO_TIC_PATTERN = /了(?:[一两三几半])?[下阵圈道声眼口气会]/g;
|
|
60
63
|
const MICRO_TIC_MIN_HITS = 5;
|
|
64
|
+
// 「没A,也没B」「不A,也不B」否定对偶:七猫人类长篇约 0.07 处/千字,模型稿 0.4-1.5 处/千字;
|
|
65
|
+
// 写人物没做什么是英文式节奏,一章 3 处以上报一条提示。
|
|
66
|
+
const NEGATION_PAIR_PATTERN = /(?:没有|没|不)[^,。!?;,!?\n]{1,10}[,,;]\s*[^,。!?;,!?\n]{0,6}?也(?:没有|没|不)/g;
|
|
67
|
+
const NEGATION_PAIR_MIN_HITS = 3;
|
|
61
68
|
const MICRO_TIC_PER_KILO = 6;
|
|
62
69
|
|
|
63
70
|
// 套式反应细节:不是禁写身体,而是提示成片出现的“部位 + 轻微动作/状态”、
|
|
@@ -239,7 +246,7 @@ const REVERSE_NOT_IS_PREV_EXCLUDE = new Set([...COMPACT_EITHER_OR_PREV, '还', '
|
|
|
239
246
|
const TRAILER_ENDING_PATTERN = /没人知道|谁也不知道|谁也没想到|殊不知|(?:这)?才刚刚开(?:始|头)|正(?:朝着|向着)[^。!?!?\n]{0,24}(?:压|涌|袭|逼)(?:了?过去|了?过来|来)|(?<!正式)拉开(?:序幕|帷幕)|即将(?:开始|来临|降临)/g;
|
|
240
247
|
const TRAILER_ENDING_WINDOW_CHARS = 600;
|
|
241
248
|
|
|
242
|
-
//
|
|
249
|
+
// 章尾状态总结体:把细纲「结尾设定」原样写成总结句收章(「这一夜注定无人入眠」
|
|
243
250
|
// 「这一切都结束了」「新的人生才刚刚开始」「命运的齿轮」)。与 trailer-ending 共用文末窗口,
|
|
244
251
|
// 区别是它盖章过去、trailer-ending 预告将来;收的都是 banned-words 已按名禁掉的形态。
|
|
245
252
|
// 不收「(这|那)一刻…终于明白」:真人语料里那是正常的认知节拍,短篇第一人称审判句还是卖点
|
|
@@ -266,6 +273,58 @@ const QUOTE_EMPHASIS_MIN_HITS = 3;
|
|
|
266
273
|
const QUOTE_EMPHASIS_MAX_VISIBLE = 4;
|
|
267
274
|
const QUOTE_EMPHASIS_SPEECH_VERB_PATTERN = /[说道问喊答念叫回吼骂写读唱嘀咕]/;
|
|
268
275
|
|
|
276
|
+
// review 分类:下游按它分流。mechanical = 命中的表面形态本身就是问题,写作端就地改写即可;
|
|
277
|
+
// semantic = 同一形态可能承担叙事功能,要读上下文判断保留还是改(交语义审查)。blocking 只能是
|
|
278
|
+
// mechanical(blocking 的含义就是不需判断、必须清零)。新增 finding type 必须在此登记,否则运行期
|
|
279
|
+
// 直接报错退出(scripts/test-ai-patterns.sh 另从源码抽 type 与本表双向核对)。
|
|
280
|
+
// type review 理由
|
|
281
|
+
// not-is-comparison mechanical 固定句式模板「不是A,而是B」,blocking
|
|
282
|
+
// voice-contrast mechanical 固定反差模板「声音不大…却」,blocking
|
|
283
|
+
// negation-parade mechanical 固定否定排比模板,blocking
|
|
284
|
+
// reverse-not-is mechanical 固定反序对比模板「是A,不是B」,blocking
|
|
285
|
+
// trailer-ending mechanical 文末窗口固定预告短语,blocking
|
|
286
|
+
// trailer-summary mechanical 文末窗口固定总结短语,blocking
|
|
287
|
+
// em-dash mechanical 标点,blocking
|
|
288
|
+
// long-paragraph mechanical 段长阈值,断段即可
|
|
289
|
+
// period-stutter mechanical 连续短句计数,合句即可
|
|
290
|
+
// micro-action-tic mechanical 固定补语「了下/了一下」密度
|
|
291
|
+
// negation-pair-tic semantic 「没A,也没B」否定对偶,留真正要强调的
|
|
292
|
+
// cliche-density-tic mechanical 固定禁用词表密度
|
|
293
|
+
// stock-reaction-tic semantic 身体反应可能承担物理后果或情绪,要逐处做删除测试
|
|
294
|
+
// action-list-tic semantic 打斗/追逐等功能性动作编排可保留
|
|
295
|
+
// abstract-summary-tic semantic 作者总结/上帝视角,是否越位要看语境
|
|
296
|
+
// metaphor-density-tic semantic 比喻是否服务画面、删哪几个要读上下文
|
|
297
|
+
// reasoning-chain-tic semantic 替读者推理的解释链,长推理段可能是正当的
|
|
298
|
+
// system-notice-formality-tic semantic 系统/规则文本本就可以公文腔,看体裁功能
|
|
299
|
+
// overcompressed-prose-tic semantic 短段过密可能是节奏选择,禁止机械注水
|
|
300
|
+
// low-connective-density-tic semantic 同上,连接词补不补要看读感
|
|
301
|
+
// quote-emphasis-tic semantic 标语/转述载体的引号是正常写法
|
|
302
|
+
// formulaic-parallelism semantic 工整并列可能承担辩解或悬念排除
|
|
303
|
+
const REVIEW_CLASSES = Object.freeze({
|
|
304
|
+
'not-is-comparison': 'mechanical',
|
|
305
|
+
'voice-contrast': 'mechanical',
|
|
306
|
+
'negation-parade': 'mechanical',
|
|
307
|
+
'reverse-not-is': 'mechanical',
|
|
308
|
+
'trailer-ending': 'mechanical',
|
|
309
|
+
'trailer-summary': 'mechanical',
|
|
310
|
+
'em-dash': 'mechanical',
|
|
311
|
+
'long-paragraph': 'mechanical',
|
|
312
|
+
'period-stutter': 'mechanical',
|
|
313
|
+
'micro-action-tic': 'mechanical',
|
|
314
|
+
'negation-pair-tic': 'semantic',
|
|
315
|
+
'cliche-density-tic': 'mechanical',
|
|
316
|
+
'stock-reaction-tic': 'semantic',
|
|
317
|
+
'action-list-tic': 'semantic',
|
|
318
|
+
'abstract-summary-tic': 'semantic',
|
|
319
|
+
'metaphor-density-tic': 'semantic',
|
|
320
|
+
'reasoning-chain-tic': 'semantic',
|
|
321
|
+
'system-notice-formality-tic': 'semantic',
|
|
322
|
+
'overcompressed-prose-tic': 'semantic',
|
|
323
|
+
'low-connective-density-tic': 'semantic',
|
|
324
|
+
'quote-emphasis-tic': 'semantic',
|
|
325
|
+
'formulaic-parallelism': 'semantic',
|
|
326
|
+
});
|
|
327
|
+
|
|
269
328
|
const options = {
|
|
270
329
|
json: false,
|
|
271
330
|
files: [],
|
|
@@ -276,6 +335,9 @@ for (let i = 2; i < process.argv.length; i += 1) {
|
|
|
276
335
|
const arg = process.argv[i];
|
|
277
336
|
if (arg === '--check') {
|
|
278
337
|
// Accepted for symmetry with normalize-punctuation.js; detection is always check-only.
|
|
338
|
+
} else if (arg === '--list-review-classes') {
|
|
339
|
+
process.stdout.write(`${JSON.stringify(REVIEW_CLASSES, null, 2)}\n`);
|
|
340
|
+
process.exit(0);
|
|
279
341
|
} else if (arg === '--json') {
|
|
280
342
|
options.json = true;
|
|
281
343
|
} else if (arg.startsWith('--fail-on=')) {
|
|
@@ -313,7 +375,7 @@ for (const file of options.files) {
|
|
|
313
375
|
let whitelist;
|
|
314
376
|
try { whitelist = loadStyleWhitelist(fullPath); }
|
|
315
377
|
catch (error) { die(`${file}: unable to read .deslop-whitelist (${error.message})`); }
|
|
316
|
-
const findings = scanDocument(maskStyleText(input, whitelist)).map((finding) => ({ file, ...finding }));
|
|
378
|
+
const findings = scanDocument(maskStyleText(input, whitelist)).map((finding) => ({ file, ...finding, review: reviewClass(finding.type) }));
|
|
317
379
|
allFindings.push(...findings);
|
|
318
380
|
}
|
|
319
381
|
|
|
@@ -330,6 +392,15 @@ if (failed) process.exit(2);
|
|
|
330
392
|
const hasBlocking = allFindings.some((f) => f.severity === 'blocking');
|
|
331
393
|
if (options.failOn === 'blocking' ? hasBlocking : allFindings.length > 0) process.exit(1);
|
|
332
394
|
|
|
395
|
+
function reviewClass(type) {
|
|
396
|
+
const review = REVIEW_CLASSES[type];
|
|
397
|
+
if (!review) {
|
|
398
|
+
console.error(`internal error: finding type '${type}' has no review class (add it to REVIEW_CLASSES)`);
|
|
399
|
+
process.exit(2);
|
|
400
|
+
}
|
|
401
|
+
return review;
|
|
402
|
+
}
|
|
403
|
+
|
|
333
404
|
function escapeRegExp(text) {
|
|
334
405
|
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
335
406
|
}
|
|
@@ -344,11 +415,15 @@ function die(message) {
|
|
|
344
415
|
process.exit(2);
|
|
345
416
|
}
|
|
346
417
|
|
|
347
|
-
|
|
418
|
+
// unclosedOpenings:到文末都没闭合的 `<!--` 位置("行号:列号")。未闭合的注释不是注释,
|
|
419
|
+
// 否则一个漏写的 `-->` 会把后面整章藏起来;这些位置按正文扫描,只把 `<!--` 本身抹掉。
|
|
420
|
+
function scanDocument(input, unclosedOpenings = new Set()) {
|
|
348
421
|
const lines = input.split(/\r?\n/);
|
|
349
422
|
const findings = [];
|
|
350
423
|
let fence = null;
|
|
351
424
|
let inFrontMatter = hasYamlFrontMatter(lines);
|
|
425
|
+
let commentOpen = false;
|
|
426
|
+
let commentStart = null;
|
|
352
427
|
let block = [];
|
|
353
428
|
const proseLines = [];
|
|
354
429
|
|
|
@@ -375,14 +450,25 @@ function scanDocument(input) {
|
|
|
375
450
|
continue;
|
|
376
451
|
}
|
|
377
452
|
|
|
378
|
-
if (fenceMarker) {
|
|
453
|
+
if (fenceMarker && !commentOpen) {
|
|
379
454
|
flushBlock();
|
|
380
455
|
fence = fenceMarker;
|
|
381
456
|
continue;
|
|
382
457
|
}
|
|
383
458
|
|
|
384
|
-
|
|
385
|
-
|
|
459
|
+
// HTML 注释(如 `<!-- 去味:跳过 -->` 豁免标记)是元信息不是正文:注释段等长换成空格
|
|
460
|
+
// 保列号,整行都是注释的直接跳过;注释可跨行。
|
|
461
|
+
const masked = maskHtmlComments(line, commentOpen, index, unclosedOpenings);
|
|
462
|
+
commentOpen = masked.open;
|
|
463
|
+
if (masked.openedAt !== null) commentStart = masked.openedAt;
|
|
464
|
+
if (masked.text !== line && !masked.text.trim()) continue;
|
|
465
|
+
|
|
466
|
+
block.push({ text: masked.text, lineNo: index + 1 });
|
|
467
|
+
proseLines.push({ text: masked.text, lineNo: index + 1 });
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (commentOpen && commentStart !== null) {
|
|
471
|
+
return scanDocument(input, new Set([...unclosedOpenings, commentStart]));
|
|
386
472
|
}
|
|
387
473
|
|
|
388
474
|
flushBlock();
|
|
@@ -432,6 +518,7 @@ function scanProsePatterns(proseLines) {
|
|
|
432
518
|
findings.push(...findQuoteEmphasisTic(proseLines));
|
|
433
519
|
findings.push(...findPeriodStutter(proseLines));
|
|
434
520
|
findings.push(...findMicroActionTic(proseLines));
|
|
521
|
+
findings.push(...findNegationPairTic(proseLines));
|
|
435
522
|
findings.push(...findStockReactionTic(proseLines));
|
|
436
523
|
findings.push(...findActionListTic(proseLines));
|
|
437
524
|
findings.push(...findAbstractSummaryTic(proseLines));
|
|
@@ -638,7 +725,7 @@ function findTrailerEnding(proseLines) {
|
|
|
638
725
|
column: summaryMatch.index + 1,
|
|
639
726
|
type: 'trailer-summary',
|
|
640
727
|
severity: 'blocking',
|
|
641
|
-
message: '
|
|
728
|
+
message: '章尾状态总结体:「这一夜注定…/这一切都结束了/新的人生才刚刚开始/命运的齿轮」是把细纲的结尾设定原样写成了总结句;结尾设定要落成最后一个具体动作、画面或台词,别替读者盖章。',
|
|
642
729
|
excerpt: compact(text.slice(summaryMatch.index, summaryMatch.index + summaryMatch[0].length)),
|
|
643
730
|
});
|
|
644
731
|
}
|
|
@@ -691,6 +778,34 @@ function findQuoteEmphasisTic(proseLines) {
|
|
|
691
778
|
}];
|
|
692
779
|
}
|
|
693
780
|
|
|
781
|
+
// 否定对偶:统计引号外叙述里「没A,也没B」式句子,全文只报一条。
|
|
782
|
+
function findNegationPairTic(proseLines) {
|
|
783
|
+
let hits = 0;
|
|
784
|
+
let firstLine = null;
|
|
785
|
+
const samples = [];
|
|
786
|
+
for (const { text, lineNo } of proseLines) {
|
|
787
|
+
const trimmed = text.trim();
|
|
788
|
+
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
|
|
789
|
+
const narrative = stripQuoted(trimmed);
|
|
790
|
+
NEGATION_PAIR_PATTERN.lastIndex = 0;
|
|
791
|
+
let match;
|
|
792
|
+
while ((match = NEGATION_PAIR_PATTERN.exec(narrative)) !== null) {
|
|
793
|
+
hits += 1;
|
|
794
|
+
if (firstLine === null) firstLine = lineNo;
|
|
795
|
+
if (samples.length < 4) samples.push(match[0]);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
if (hits < NEGATION_PAIR_MIN_HITS) return [];
|
|
799
|
+
return [{
|
|
800
|
+
line: firstLine,
|
|
801
|
+
column: 1,
|
|
802
|
+
type: 'negation-pair-tic',
|
|
803
|
+
severity: 'advisory',
|
|
804
|
+
message: `否定对偶偏多:「没A,也没B」式叙述 ${hits} 处;写人物没做什么是英文式节奏,改成他做了什么(留一两处真正要强调的)。`,
|
|
805
|
+
excerpt: compact(samples.join(' | ')),
|
|
806
|
+
}];
|
|
807
|
+
}
|
|
808
|
+
|
|
694
809
|
// 微动作复读:统计引号外叙述里「了X量词」轻量补语的密度。次数与每千字密度双门槛,
|
|
695
810
|
// 全文只报一条(这是分布级指纹,不是逐处问题)。
|
|
696
811
|
function findMicroActionTic(proseLines) {
|
|
@@ -1242,6 +1357,38 @@ function countTerms(text, terms) {
|
|
|
1242
1357
|
return count;
|
|
1243
1358
|
}
|
|
1244
1359
|
|
|
1360
|
+
// 把行内 HTML 注释(含 `<!--`、`-->` 本身)换成等长空格;openBefore 表示上一行留下未闭合注释。
|
|
1361
|
+
// unclosedOpenings 里的 `<!--` 到文末都没闭合:只抹掉这四个字符,后面照常当正文。
|
|
1362
|
+
// openedAt 是本行最后一个开始注释的 `<!--` 位置("行号:列号"),没有则为 null。
|
|
1363
|
+
function maskHtmlComments(line, openBefore, lineIndex = 0, unclosedOpenings = new Set()) {
|
|
1364
|
+
let out = '';
|
|
1365
|
+
let open = openBefore;
|
|
1366
|
+
let cursor = 0;
|
|
1367
|
+
let openedAt = null;
|
|
1368
|
+
while (cursor < line.length) {
|
|
1369
|
+
if (open) {
|
|
1370
|
+
const close = line.indexOf('-->', cursor);
|
|
1371
|
+
const end = close === -1 ? line.length : close + 3;
|
|
1372
|
+
out += ' '.repeat(end - cursor);
|
|
1373
|
+
cursor = end;
|
|
1374
|
+
if (close !== -1) open = false;
|
|
1375
|
+
continue;
|
|
1376
|
+
}
|
|
1377
|
+
const start = line.indexOf('<!--', cursor);
|
|
1378
|
+
if (start === -1) {
|
|
1379
|
+
out += line.slice(cursor);
|
|
1380
|
+
break;
|
|
1381
|
+
}
|
|
1382
|
+
out += line.slice(cursor, start) + ' ';
|
|
1383
|
+
cursor = start + 4;
|
|
1384
|
+
const key = `${lineIndex}:${start}`;
|
|
1385
|
+
if (unclosedOpenings.has(key)) continue;
|
|
1386
|
+
open = true;
|
|
1387
|
+
openedAt = key;
|
|
1388
|
+
}
|
|
1389
|
+
return { text: out, open, openedAt };
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1245
1392
|
function parseFenceMarker(trimmedLine) {
|
|
1246
1393
|
const match = /^(?:`{3,}|~{3,})/.exec(trimmedLine);
|
|
1247
1394
|
if (!match) return null;
|
|
@@ -18,11 +18,13 @@
|
|
|
18
18
|
const fs = require('fs')
|
|
19
19
|
const path = require('path')
|
|
20
20
|
|
|
21
|
-
// 权威模板:references/workflow-
|
|
21
|
+
// 权威模板:references/workflow-outline.md 的细纲模板
|
|
22
|
+
// 必填只留有证据或事故撑腰的核心字段;阶段位置、章节定位、结构公式、本章标价、闭环状态、
|
|
23
|
+
// 写手自由区、契约风险、镜头准入、信息差触发点与「分辨率」列是可选的阅读体验字段——
|
|
24
|
+
// 写了照样消费,没写不拦(#383 隔离实验:只补目标情绪与主角目标就复现了补满全部字段的收益)。
|
|
22
25
|
const FIELDS = [
|
|
23
|
-
'核心事件', '字数目标', '字数口径', '
|
|
24
|
-
'主角目标/关键选择', '
|
|
25
|
-
'本章标价', '闭环状态', '本章禁止提前释放', '写手自由区', '契约风险',
|
|
26
|
+
'核心事件', '字数目标', '字数口径', '单元ID/位置', '目标情绪',
|
|
27
|
+
'主角目标/关键选择', '章首钩子', '爽点', '本章禁止提前释放',
|
|
26
28
|
]
|
|
27
29
|
const SUBSECTIONS = ['内容概括', '情节安排', '人物关系和出场顺序', '情节细化']
|
|
28
30
|
const FIVE_ACT = ['起因', '发展', '转折', '高潮', '结尾']
|
|
@@ -30,6 +32,69 @@ const PLOT_HEADER_FIRST = /^(?:#|序号)$/
|
|
|
30
32
|
// 这两个字段实测直接影响正文质量,必须有实际内容
|
|
31
33
|
const INTENT_FIELDS = ['目标情绪', '主角目标/关键选择']
|
|
32
34
|
const CALIBER = 'visible_chars_v1'
|
|
35
|
+
// 可选字段「契约风险」只收三档;值未知可写 [待补充]。旧稿里的「风险等级」按同一字段认(旧名)。
|
|
36
|
+
const CONTRACT_RISK_LEVELS = ['契约安全', '需补强', '契约破坏']
|
|
37
|
+
|
|
38
|
+
// 「字数目标」「字数范围」「字数口径」的写法语法与 wordcount_core.py 逐字同构(scripts/test-storyctl.py 双跑同一批写法),
|
|
39
|
+
// 细纲验收通过的写法,storyctl chapter check 不能再拒。值里一个数字都没有的目标/范围行是说明文字,不参与取值。
|
|
40
|
+
const NUMBER = '([1-9][0-9]{0,2}(?:[,,][0-9]{3})+|[1-9][0-9]*)'
|
|
41
|
+
const NOTE = '(?:[((][^()()]*[))])?'
|
|
42
|
+
const TARGET_VALUE = new RegExp(`^(?:约|大约)?[ \\t]*${NUMBER}[ \\t]*字?(?:左右)?[ \\t]*${NOTE}$`)
|
|
43
|
+
const RANGE_VALUE = new RegExp(`^${NUMBER}[ \\t]*字?[ \\t]*(?:-|~|~|—|–|-|至|到)[ \\t]*${NUMBER}[ \\t]*字?[ \\t]*${NOTE}$`)
|
|
44
|
+
const METRIC_VALUE = new RegExp(`^([A-Za-z0-9_-]+)[ \\t]*${NOTE}$`)
|
|
45
|
+
const HAS_DIGIT = /[0-90-9]/
|
|
46
|
+
|
|
47
|
+
function fieldValues(text, label) {
|
|
48
|
+
const pattern = new RegExp(`^[ \\t>]*(?:[-*+][ \\t]*)?(?:\\*\\*)?${label}(?:\\*\\*)?[ \\t]*[::][ \\t]*(.*?)[ \\t]*$`, 'gm')
|
|
49
|
+
const values = []
|
|
50
|
+
let match
|
|
51
|
+
const normalized = text.replace(/\r\n?/g, '\n').replace(/^\uFEFF/, '')
|
|
52
|
+
while ((match = pattern.exec(normalized)) !== null) values.push(match[1].replace(/\*\*/g, '').trim())
|
|
53
|
+
return values
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const numericFieldValues = (text, label) => fieldValues(text, label).filter((value) => HAS_DIGIT.test(value))
|
|
57
|
+
const toNumber = (raw) => Number(raw.replace(/[,,]/g, ''))
|
|
58
|
+
|
|
59
|
+
function parseWordcountTarget(text) {
|
|
60
|
+
const raw = numericFieldValues(text, '字数目标')
|
|
61
|
+
if (!raw.length) return { status: 'missing', value: null, raw }
|
|
62
|
+
const matches = raw.map((value) => value.match(TARGET_VALUE))
|
|
63
|
+
if (!matches.every(Boolean)) return { status: 'invalid', value: null, raw }
|
|
64
|
+
const values = [...new Set(matches.map((match) => toNumber(match[1])))]
|
|
65
|
+
if (values.length !== 1) return { status: 'conflict', value: null, raw }
|
|
66
|
+
return { status: 'ok', value: values[0], raw }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function parseWordcountRange(text) {
|
|
70
|
+
const raw = numericFieldValues(text, '字数范围')
|
|
71
|
+
if (!raw.length) return { status: 'missing', value: null, raw }
|
|
72
|
+
const matches = raw.map((value) => value.match(RANGE_VALUE))
|
|
73
|
+
if (!matches.every(Boolean)) return { status: 'invalid', value: null, raw }
|
|
74
|
+
const pairs = [...new Set(matches.map((match) => `${toNumber(match[1])}-${toNumber(match[2])}`))]
|
|
75
|
+
if (pairs.length !== 1) return { status: 'invalid', value: null, raw }
|
|
76
|
+
const [min, max] = pairs[0].split('-').map(Number)
|
|
77
|
+
if (min > max) return { status: 'invalid', value: null, raw }
|
|
78
|
+
return { status: 'ok', value: { min, max }, raw }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function parseWordcountCaliber(text) {
|
|
82
|
+
const raw = fieldValues(text, '字数口径')
|
|
83
|
+
const matches = raw.map((value) => value.match(METRIC_VALUE))
|
|
84
|
+
return raw.length > 0 && matches.every(Boolean) && new Set(matches.map((match) => match[1])).size === 1 && matches[0][1] === CALIBER
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function parseContractRisk(text) {
|
|
88
|
+
let raw = fieldValues(text, '契约风险')
|
|
89
|
+
if (!raw.length) raw = fieldValues(text, '风险等级')
|
|
90
|
+
if (!raw.length) return null
|
|
91
|
+
const value = raw[raw.length - 1].replace(/`/g, '')
|
|
92
|
+
if (/^\[待补充\]$/.test(value)) return { status: 'unknown', level: null, detail: '', raw: value }
|
|
93
|
+
const level = CONTRACT_RISK_LEVELS.find((name) => value.startsWith(name))
|
|
94
|
+
if (!level) return { status: 'invalid', level: null, detail: '', raw: value }
|
|
95
|
+
const detail = value.slice(level.length).replace(/^[\s;;,,。::—\-((]+/, '').replace(/[))]$/, '').trim()
|
|
96
|
+
return { status: 'ok', level, detail, raw: value }
|
|
97
|
+
}
|
|
33
98
|
|
|
34
99
|
function fieldPattern(name) {
|
|
35
100
|
// 允许 -/*/+ 项目符号、可选 ** 加粗、全角或半角冒号
|
|
@@ -54,7 +119,7 @@ function makeCheck(id, ok, file, evidence, expected, repair, severity = 'blockin
|
|
|
54
119
|
file,
|
|
55
120
|
evidence,
|
|
56
121
|
expected,
|
|
57
|
-
references: ['references/workflow-
|
|
122
|
+
references: ['references/workflow-outline.md'],
|
|
58
123
|
repair,
|
|
59
124
|
}
|
|
60
125
|
}
|
|
@@ -101,7 +166,7 @@ function checkSettingRefs(text, name, file, projectRoot) {
|
|
|
101
166
|
name,
|
|
102
167
|
missing.length ? `引用的路径不是可用文件:${missing.join('、')}` : `${refs.size} 处项目内引用全部存在`,
|
|
103
168
|
'细纲引用的每个项目内 .md 文件都真实存在——不许把槽位指向查无实据的权威文件',
|
|
104
|
-
'
|
|
169
|
+
'修正引用路径;或按新增物三级先把缺的设定落档(「写了要报」直接补并登记、「先问作者」进排纲底稿的供给自查提案),再在细纲引用。'
|
|
105
170
|
)
|
|
106
171
|
}
|
|
107
172
|
|
|
@@ -173,8 +238,8 @@ function verify(file, projectRoot = null) {
|
|
|
173
238
|
let header = null
|
|
174
239
|
for (const line of lines) {
|
|
175
240
|
const cells = parseTableRow(line)
|
|
176
|
-
//
|
|
177
|
-
// 两种都收:功能标签固定在第 3
|
|
241
|
+
// 现行模板默认四列(# / 情节点 / 功能标签 / 执行边界(禁+放)),需要时在功能标签后加「分辨率」列成五列。
|
|
242
|
+
// 两种都收:功能标签固定在第 3 列,执行边界一律取最后一列。
|
|
178
243
|
if (cells && (cells.length === 4 || cells.length === 5) && PLOT_HEADER_FIRST.test(cells[0])) {
|
|
179
244
|
header = cells
|
|
180
245
|
break
|
|
@@ -189,21 +254,21 @@ function verify(file, projectRoot = null) {
|
|
|
189
254
|
headerOk,
|
|
190
255
|
name,
|
|
191
256
|
header ? `表头:${header.join(' | ')}` : '未找到 | # | 情节点 | 功能标签 | [分辨率] | 执行边界 | 表头',
|
|
192
|
-
'
|
|
193
|
-
'
|
|
257
|
+
'情节细化使用表格:# / 情节点(谁做了什么) / 功能标签 / 执行边界(禁+放);需要时可在功能标签后加「分辨率」列',
|
|
258
|
+
'只把情节点序列改成这张表,逐点补功能标签与执行边界;不增删情节点本身。'
|
|
194
259
|
))
|
|
195
260
|
|
|
196
|
-
//
|
|
197
|
-
// 全是禁令的情节点表实测会把整章压成同一个温度(015
|
|
198
|
-
if (headerOk && header.length === 5) {
|
|
261
|
+
// 「放」半边:五列表或表头写明「禁+放」的四列表,执行边界必须至少一个点解除限制,
|
|
262
|
+
// 全是禁令的情节点表实测会把整章压成同一个温度(015 章十一个点全「不许」)。表头没写「禁+放」的四列表不追溯。
|
|
263
|
+
if (headerOk && (header.length === 5 || /放/.test(header[header.length - 1]))) {
|
|
199
264
|
const rows = []
|
|
200
265
|
for (const line of lines) {
|
|
201
266
|
const cells = parseTableRow(line)
|
|
202
|
-
if (cells && cells.length ===
|
|
267
|
+
if (cells && cells.length === header.length && /^\d+$/.test(cells[0])) rows.push(cells)
|
|
203
268
|
}
|
|
204
269
|
if (rows.length) {
|
|
205
270
|
const released = rows.filter((cells) => {
|
|
206
|
-
const match = cells[
|
|
271
|
+
const match = cells[cells.length - 1].match(/(?:^|[。;;\s])放\s*[::]([^]*?)(?=(?:禁|放)\s*[::]|$)/)
|
|
207
272
|
if (!match) return false
|
|
208
273
|
const value = match[1].replace(/[\s。;;,,、\[\]【】]/g, '')
|
|
209
274
|
return value.length > 0 && !/^(?:无|暂无|待补充|待定|无缺口)$/.test(value)
|
|
@@ -249,22 +314,45 @@ function verify(file, projectRoot = null) {
|
|
|
249
314
|
|
|
250
315
|
checks.push(checkSettingRefs(text, name, file, projectRoot))
|
|
251
316
|
|
|
252
|
-
const
|
|
253
|
-
const
|
|
254
|
-
const
|
|
317
|
+
const targetParse = parseWordcountTarget(text)
|
|
318
|
+
const rangeParse = parseWordcountRange(text)
|
|
319
|
+
const target = targetParse.value
|
|
320
|
+
const caliberOk = parseWordcountCaliber(text)
|
|
321
|
+
const targetLabel = { ok: target, missing: '未识别', invalid: `写法认不出(${targetParse.raw.join('、')})`, conflict: `多个不同的值(${targetParse.raw.join('、')})` }[targetParse.status]
|
|
322
|
+
const rangeLabel = rangeParse.status === 'invalid' ? `;字数范围写法不对(${rangeParse.raw.join('、')})` : (rangeParse.value ? `;字数范围:${rangeParse.value.min}-${rangeParse.value.max}` : '')
|
|
255
323
|
checks.push(makeCheck(
|
|
256
324
|
'outline.wordcount-target',
|
|
257
|
-
|
|
325
|
+
targetParse.status === 'ok' && target >= 500 && target <= 20000 && caliberOk && rangeParse.status !== 'invalid',
|
|
258
326
|
name,
|
|
259
|
-
`字数目标:${
|
|
260
|
-
`字数目标为 500-20000
|
|
261
|
-
'
|
|
327
|
+
`字数目标:${targetLabel};字数口径 ${CALIBER}:${caliberOk}${rangeLabel}`,
|
|
328
|
+
`字数目标为 500-20000 的正整数(可写「2300 字」「约 2300」「2,300」,可带括号备注),并声明 字数口径:${CALIBER};作者给了上下限时另写一行「字数范围:2000-2600」`,
|
|
329
|
+
'只补字数目标、字数范围或字数口径行,不调整情节安排。'
|
|
262
330
|
))
|
|
263
331
|
|
|
264
|
-
|
|
332
|
+
const risk = parseContractRisk(text)
|
|
333
|
+
if (risk) {
|
|
334
|
+
checks.push(makeCheck(
|
|
335
|
+
'outline.contract-risk',
|
|
336
|
+
risk.status !== 'invalid',
|
|
337
|
+
name,
|
|
338
|
+
risk.status === 'invalid' ? `契约风险写的是「${risk.raw}」` : `契约风险:${risk.level || '[待补充]'}`,
|
|
339
|
+
`契约风险只写 ${CONTRACT_RISK_LEVELS.join(' / ')} 三档之一(需补强时后面写补强方式),未定写 [待补充]`,
|
|
340
|
+
'只把契约风险改成三档之一,不改其他字段。'
|
|
341
|
+
))
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return report(file, checks, {
|
|
345
|
+
wordcount: {
|
|
346
|
+
target,
|
|
347
|
+
target_status: targetParse.status,
|
|
348
|
+
range: rangeParse.value,
|
|
349
|
+
range_status: rangeParse.status,
|
|
350
|
+
},
|
|
351
|
+
contract_risk: risk ? { level: risk.level, detail: risk.detail, status: risk.status } : null,
|
|
352
|
+
})
|
|
265
353
|
}
|
|
266
354
|
|
|
267
|
-
function report(file, checks) {
|
|
355
|
+
function report(file, checks, extra = {}) {
|
|
268
356
|
const failures = checks.filter((check) => !check.ok && check.severity === 'blocking')
|
|
269
357
|
const advisories = checks.filter((check) => !check.ok && check.severity === 'advisory')
|
|
270
358
|
return {
|
|
@@ -272,6 +360,7 @@ function report(file, checks) {
|
|
|
272
360
|
verifier: 'story-long-write.outline-contract',
|
|
273
361
|
file: path.resolve(file),
|
|
274
362
|
ok: failures.length === 0,
|
|
363
|
+
...extra,
|
|
275
364
|
checks,
|
|
276
365
|
failures,
|
|
277
366
|
advisories,
|
|
@@ -303,8 +392,24 @@ function resolveChapter(project, chapter) {
|
|
|
303
392
|
return { file: path.join(dir, hit) }
|
|
304
393
|
}
|
|
305
394
|
|
|
306
|
-
// --supply
|
|
395
|
+
// --supply:批末验证供给自查已落盘。新书写在卷纲旁的 排纲底稿_{单元ID}.md;老卷纲写在单元卡块内。
|
|
396
|
+
function hasSupplyHeading(text) {
|
|
397
|
+
return text.split(/\r?\n/).some((line) => {
|
|
398
|
+
const heading = line.replace(/\*\*/g, '').match(/^#{1,6}\s+(.+)$/)
|
|
399
|
+
return Boolean(heading) && /^供给自查(?:\s|[((]|$)/.test(heading[1])
|
|
400
|
+
})
|
|
401
|
+
}
|
|
402
|
+
|
|
307
403
|
function verifySupply(volumeFile, unitId) {
|
|
404
|
+
const draftFile = path.join(path.dirname(volumeFile), `排纲底稿_${unitId}.md`)
|
|
405
|
+
const draft = readUtf8(draftFile)
|
|
406
|
+
if (draft.ok) {
|
|
407
|
+
const ok = hasSupplyHeading(draft.text)
|
|
408
|
+
return {
|
|
409
|
+
schema_version: 1, verifier: 'story-long-write.outline-supply', file: path.resolve(draftFile), unit: unitId, ok,
|
|
410
|
+
evidence: ok ? '排纲底稿含「供给自查」小节' : `${path.basename(draftFile)} 里没有「供给自查」小节——每批出细纲前须做供给自查(含「无缺口」情形),见 workflow-outline.md 步骤 3`,
|
|
411
|
+
}
|
|
412
|
+
}
|
|
308
413
|
const read = readUtf8(volumeFile)
|
|
309
414
|
if (!read.ok) {
|
|
310
415
|
return { schema_version: 1, verifier: 'story-long-write.outline-supply', file: path.resolve(volumeFile), unit: unitId, ok: false, evidence: read.error || '卷纲文件为空' }
|
|
@@ -345,7 +450,7 @@ function verifySupply(volumeFile, unitId) {
|
|
|
345
450
|
file: path.resolve(volumeFile),
|
|
346
451
|
unit: unitId,
|
|
347
452
|
ok,
|
|
348
|
-
evidence: ok ? '单元卡含「供给自查」小节' :
|
|
453
|
+
evidence: ok ? '单元卡含「供给自查」小节' : `没有 排纲底稿_${unitId}.md,剧情单元 ${unitId} 的卡内也没有「供给自查」小节——每批出细纲前须做供给自查(含「无缺口」情形),见 workflow-outline.md 步骤 3`,
|
|
349
454
|
}
|
|
350
455
|
}
|
|
351
456
|
|
|
@@ -412,4 +517,4 @@ function main(argv) {
|
|
|
412
517
|
|
|
413
518
|
if (require.main === module) process.exitCode = main(process.argv.slice(2))
|
|
414
519
|
|
|
415
|
-
module.exports = { verify, FIELDS, SUBSECTIONS, FIVE_ACT }
|
|
520
|
+
module.exports = { verify, parseWordcountTarget, parseWordcountRange, parseContractRisk, FIELDS, SUBSECTIONS, FIVE_ACT }
|
|
@@ -284,10 +284,15 @@ function checkOne(proseFile, explicitOutline) {
|
|
|
284
284
|
}
|
|
285
285
|
|
|
286
286
|
const rate = ((copied * 100) / P.length).toFixed(1)
|
|
287
|
+
// 短篇没有细纲:锚句登记在 小节大纲.md 末尾,措辞按短篇说,长篇原文不变
|
|
288
|
+
const isShort = path.basename(outlineFile) === '小节大纲.md'
|
|
289
|
+
const guidance = isShort
|
|
290
|
+
? `逐条对照原文判断:确属把小节大纲叙述搬进正文就重写——大纲只锁功能与结果,句子在正文现场写;誓词、关键原话、固定专名等功能性重合可保留。每条都要有结论,不为归零机械改写。保留项由主会话登记进小节大纲.md 末尾「复沓锚句:」行下(每行一条原话,缩进写)再复检——子代理只重写正文或标 \`[需复核]\` 交回,不改小节大纲。`
|
|
291
|
+
: `逐条对照原文判断:确属把细纲叙述搬进正文就重写——细纲只锁功能与结果,句子在正文现场写;系统面板、誓词、案卷原话、固定专名等功能性重合可保留。每条都要有结论,不为归零机械改写。保留项由主会话补进细纲「复沓锚句」——子代理只重写正文或标 \`[需复核]\` 交回,不改大纲细纲。`
|
|
287
292
|
const out = [
|
|
288
|
-
`===
|
|
293
|
+
`=== ${isShort ? '小节大纲' : '细纲'}照搬检测(${path.basename(proseFile)})===`,
|
|
289
294
|
`正文 ${P.length} 字,与 ${path.basename(outlineFile)} 连续重合 >${MIN_RUN - 1} 字的片段 ${hits.length} 处,共 ${copied} 字(${rate}%)。`,
|
|
290
|
-
|
|
295
|
+
guidance,
|
|
291
296
|
]
|
|
292
297
|
hits
|
|
293
298
|
.sort((a, b) => b.len - a.len)
|
|
@@ -35,7 +35,8 @@ UNIT_IN_TITLE = re.compile(r"(?<![\w-])([LD]\d+-\d+|U\d+)(?![\w-])")
|
|
|
35
35
|
# 批次底稿里出现跨章祈使=这条约束在写作期还有效,而写作档不给底稿 → 必须下沉
|
|
36
36
|
IMPERATIVE = re.compile(r"全程不许|一律不许|往后任何章|此后不再|往后每|从此不|终局前不")
|
|
37
37
|
CH_RANGE = re.compile(r"章节范围[::]\s*第\s*(\d+)\s*[-–—~至]\s*(\d+)\s*章")
|
|
38
|
-
|
|
38
|
+
# 情绪弧线逐章行:首列写「12」或模板里的「第12章」都认
|
|
39
|
+
ARC_ROW = re.compile(r"^\|\s*第?\s*(\d+)\s*章?\s*\|")
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
def read(path):
|
|
@@ -217,9 +218,11 @@ def main():
|
|
|
217
218
|
parser.add_argument("--check", action="store_true")
|
|
218
219
|
parser.add_argument("--history", action="store_true")
|
|
219
220
|
parser.add_argument("--strict", action="store_true", help="新建卷纲校验:缺作用域也视为错误")
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
221
|
+
# 排纲底稿现在放在卷纲外的 大纲/排纲底稿_{单元ID}.md,默认输出就是写作要的闭包。
|
|
222
|
+
# --stage outline 只为老卷纲保留:它们的供给自查等底稿还写在卷纲里(作用域:批次底稿)。
|
|
223
|
+
parser.add_argument("--stage", choices=["outline", "write"], default="write",
|
|
224
|
+
help="write(默认)=卷级常任+单元级;"
|
|
225
|
+
"outline=另带老卷纲里仍在用的批次底稿段")
|
|
223
226
|
args = parser.parse_args()
|
|
224
227
|
|
|
225
228
|
if hasattr(sys.stdout, "reconfigure"):
|