@oh-story/dsh 0.1.10 → 0.1.12
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 +11 -11
- package/lib/client.js +7 -3
- package/lib/client.js.map +2 -2
- package/lib/drama/manifest.json +212 -142
- package/lib/drama/skills/short-drama/SKILL.md +14 -2
- 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/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/era-anchors.md +37 -0
- package/lib/drama/skills/short-drama-assets/references/stage-contract.md +2 -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 +43 -20
- 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 +4 -2
- package/lib/drama/skills/short-drama-edit/references/cut-craft.md +3 -1
- package/lib/drama/skills/short-drama-edit/references/delivery-verify.md +6 -2
- package/lib/drama/skills/short-drama-edit/references/generated-footage.md +12 -6
- package/lib/drama/skills/short-drama-edit/references/sound-and-subtitles.md +13 -8
- package/lib/drama/skills/short-drama-edit/references/stage-contract.md +2 -0
- package/lib/drama/skills/short-drama-edit/scripts/edit_tool.py +1153 -121
- package/lib/drama/skills/short-drama-edit/scripts/selftest.py +49 -9
- 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-review/SKILL.md +2 -2
- 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 +15 -0
- package/lib/drama/skills/short-drama-review/references/stage-contract.md +3 -0
- package/lib/drama/skills/short-drama-storyboard/SKILL.md +13 -5
- package/lib/drama/skills/short-drama-storyboard/references/blocking-playbooks.md +1 -1
- 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 +82 -14
- package/lib/drama/skills/short-drama-storyboard/references/stage-contract.md +4 -2
- package/lib/drama/skills/short-drama-video-prompts/SKILL.md +5 -3
- package/lib/drama/skills/short-drama-video-prompts/references/camera-audio-continuity.md +12 -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 +40 -1
- package/lib/drama/skills/short-drama-video-prompts/references/motion-recipe.md +20 -14
- package/lib/drama/skills/short-drama-video-prompts/references/performance-action-timing.md +1 -1
- package/lib/drama/skills/short-drama-video-prompts/references/production-prompt-grammar.md +8 -7
- package/lib/drama/skills/short-drama-video-prompts/references/review-and-fixtures.md +1 -1
- package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +1 -0
- 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 +8 -3
- 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 +71 -21
- package/lib/index.js.map +3 -3
- package/lib/oh-story/manifest.json +545 -310
- package/lib/oh-story/roles/chapter-extractor.md +11 -11
- package/lib/oh-story/roles/character-designer.md +1 -2
- package/lib/oh-story/roles/consistency-checker.md +11 -9
- package/lib/oh-story/roles/narrative-writer.md +24 -25
- 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 +6 -6
- 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 +40 -118
- package/lib/oh-story/skills/story/scripts/author_memory_commit.py +3 -3
- package/lib/oh-story/skills/story-deslop/SKILL.md +24 -25
- 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 +1 -1
- 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 +40 -118
- package/lib/oh-story/skills/story-deslop/references/banned-words.md +2 -2
- package/lib/oh-story/skills/story-deslop/references/deslop-gates.md +21 -4
- 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 +3 -3
- package/lib/oh-story/skills/story-deslop/scripts/check-ai-patterns.js +155 -8
- package/lib/oh-story/skills/story-import/SKILL.md +63 -579
- 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/structure-mapping-long.md +95 -91
- 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 +11 -9
- 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 +101 -14
- package/lib/oh-story/skills/story-import/scripts/tracking_commit.py +278 -23
- package/lib/oh-story/skills/story-import/scripts/wordcount_core.py +179 -23
- package/lib/oh-story/skills/story-long-analyze/SKILL.md +28 -50
- package/lib/oh-story/skills/story-long-analyze/references/author-facing.md +12 -5
- package/lib/oh-story/skills/story-long-analyze/references/deconstruction-notes.md +1 -1
- 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/pipeline-ops.md +21 -55
- 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 +17 -0
- package/lib/oh-story/skills/story-long-analyze/references/style-profile-protocol.md +1 -1
- package/lib/oh-story/skills/story-long-analyze/references/synthesis-inputs.md +39 -0
- package/lib/oh-story/skills/story-long-analyze/scripts/manage_analysis_run.py +47 -8
- package/lib/oh-story/skills/story-long-scan/SKILL.md +41 -193
- 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 +32 -73
- 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 +1 -1
- package/lib/oh-story/skills/story-long-write/references/artifact-protocols.md +18 -201
- 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 +40 -118
- 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 +6 -10
- package/lib/oh-story/skills/story-long-write/references/character-relations.md +49 -1
- package/lib/oh-story/skills/story-long-write/references/deslop-gates.md +171 -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/genre-prose-cards.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/long-chapter-quality.md +3 -2
- 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 +10 -6
- package/lib/oh-story/skills/story-long-write/references/reader-contract-and-progression.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/reference-index.md +4 -4
- 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 +11 -9
- package/lib/oh-story/skills/story-long-write/references/workflow-chapter.md +33 -44
- package/lib/oh-story/skills/story-long-write/references/workflow-daily.md +18 -51
- 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 +53 -67
- package/lib/oh-story/skills/story-long-write/references/workflow-setup.md +112 -251
- 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 +5 -3
- package/lib/oh-story/skills/story-long-write/references/writing-craft.md +18 -56
- package/lib/oh-story/skills/story-long-write/scripts/author_memory_commit.py +3 -3
- 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 +96 -16
- 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 +101 -14
- 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 +2 -1
- package/lib/oh-story/skills/story-long-write/scripts/storyctl.py +250 -50
- package/lib/oh-story/skills/story-long-write/scripts/tracking_commit.py +278 -23
- package/lib/oh-story/skills/story-long-write/scripts/wordcount_core.py +179 -23
- package/lib/oh-story/skills/story-review/SKILL.md +19 -273
- 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 +1 -1
- 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 +40 -118
- 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/review-quality.md +2 -1
- 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 +11 -9
- package/lib/oh-story/skills/story-review/scripts/author_memory_commit.py +3 -3
- 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 +278 -23
- package/lib/oh-story/skills/story-review/scripts/wordcount_core.py +179 -23
- package/lib/oh-story/skills/story-setup/SKILL.md +69 -458
- 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 +1 -1
- 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 +21 -4
- 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-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 +18 -56
- package/lib/oh-story/skills/story-setup/references/diagnostics.md +3 -3
- package/lib/oh-story/skills/story-short-analyze/SKILL.md +37 -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/{material-decomposition.md → stage4-6-reversal-summary.md} +303 -374
- package/lib/oh-story/skills/story-short-scan/SKILL.md +30 -64
- 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 -34
- 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 +40 -118
- 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/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 -49
- 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 +19 -12
- package/lib/oh-story/skills/story-short-write/references/workflow-draft.md +22 -32
- package/lib/oh-story/skills/story-short-write/references/workflow-revision.md +84 -17
- 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 +3 -3
- 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/video-studio.d.ts.map +1 -1
- package/lib/types/native-hooks.d.ts +2 -2
- package/lib/types/native-hooks.d.ts.map +1 -1
- 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-understanding/scripts/{agent_brief.py → briefing/builder.py} +38 -35
- package/lib/video-recap/skills/{video-script/scripts/brief_context.py → video-understanding/scripts/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-understanding/scripts/{brief_timeline.py → 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 +41 -41
- package/lib/oh-story/skills/story-long-analyze/references/material-decomposition.md +0 -538
- package/lib/oh-story/skills/story-long-analyze/references/output-templates.md +0 -603
- package/lib/oh-story/skills/story-long-scan/references/scan-output-format.md +0 -207
- 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/agent_brief.py +0 -399
- package/lib/video-recap/skills/video-script/scripts/brief_timeline.py +0 -327
- package/lib/video-recap/skills/video-script/scripts/narration.py +0 -12
- package/lib/video-recap/skills/video-understanding/scripts/brief_context.py +0 -348
- package/lib/video-recap/skills/video-understanding/scripts/brief_inputs.py +0 -290
- /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
|
@@ -58,8 +58,31 @@ CONTEXT_HEADINGS = (
|
|
|
58
58
|
FORESHADOW_STATUSES = ("已埋", "已回收", "已过期", "放弃")
|
|
59
59
|
FORESHADOW_IMPORTANCE = ("高", "中", "低")
|
|
60
60
|
REVEAL_STATUSES = ("未揭示", "部分揭示", "已揭示")
|
|
61
|
+
# 伏笔与时间线条目里模型常用的同义写法:含义明确的直接改成正式名,不让一次提交为措辞失败。
|
|
62
|
+
ACTION_ALIASES = {
|
|
63
|
+
"add": "upsert", "new": "upsert", "create": "upsert", "update": "upsert", "plant": "upsert",
|
|
64
|
+
"advance": "upsert", "resolve": "upsert", "insert": "upsert",
|
|
65
|
+
"新增": "upsert", "埋设": "upsert", "更新": "upsert", "推进": "upsert", "回收": "upsert",
|
|
66
|
+
"remove": "delete", "删除": "delete",
|
|
67
|
+
}
|
|
68
|
+
# 带状态含义的伏笔动作词:它们也映射成 upsert,但动作词本身说了伏笔走到哪一步。
|
|
69
|
+
# status 缺省时按动作词补上(意图只有这一个来源,不会猜错);status 与动作词矛盾时退回,
|
|
70
|
+
# 因为无法判断是动作词用错还是状态写错——静默改任何一边都可能把没回收的伏笔记成已回收。
|
|
71
|
+
FORESHADOW_ACTION_STATUS = {
|
|
72
|
+
"resolve": "已回收", "回收": "已回收",
|
|
73
|
+
"advance": "已埋", "推进": "已埋",
|
|
74
|
+
}
|
|
75
|
+
FORESHADOW_KEY_ALIASES = {
|
|
76
|
+
"planned_chapter": "planned_resolution_chapter", "planned_payoff_chapter": "planned_resolution_chapter",
|
|
77
|
+
"payoff_chapter": "planned_resolution_chapter", "resolution_chapter": "planned_resolution_chapter",
|
|
78
|
+
"resolve_chapter": "planned_resolution_chapter", "plant_chapter": "planted_chapter",
|
|
79
|
+
"planted": "planted_chapter", "description": "summary", "content": "summary",
|
|
80
|
+
}
|
|
81
|
+
TIMELINE_KEY_ALIASES = {"time": "story_time", "fact": "objective_fact", "reveal": "reveal_status"}
|
|
61
82
|
INVALID_FILE_CHARS = re.compile(r"[<>:\"/\\|?*\x00-\x1f]")
|
|
62
83
|
FORESHADOW_ID = re.compile(r"^F\d{3,}$")
|
|
84
|
+
SNAPSHOT_TEXT_FIELDS = ("identity", "location", "goal", "state")
|
|
85
|
+
SNAPSHOT_LIST_FIELDS = ("abilities_resources", "relationships", "knowledge", "open_threads")
|
|
63
86
|
EVENT_ID = re.compile(r"^E\d{3,}$")
|
|
64
87
|
WINDOWS_RESERVED_NAMES = {
|
|
65
88
|
"CON",
|
|
@@ -112,9 +135,34 @@ def as_int(value: object, label: str, *, minimum: int = 0) -> int:
|
|
|
112
135
|
return value
|
|
113
136
|
|
|
114
137
|
|
|
138
|
+
def as_chapter(value: object, label: str, *, minimum: int = 1) -> int:
|
|
139
|
+
"""章号:模型常写成 "22"。纯数字字符串按整数收,语义不变;其余照旧报错。"""
|
|
140
|
+
if isinstance(value, str) and value.strip().isdecimal():
|
|
141
|
+
value = int(value.strip())
|
|
142
|
+
return as_int(value, label, minimum=minimum)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def with_aliases(row: dict[str, Any], aliases: dict[str, str]) -> dict[str, Any]:
|
|
146
|
+
"""把含义明确的同义字段名改成正式字段名;正式字段已在时不动,留给未知字段报错。"""
|
|
147
|
+
row = dict(row)
|
|
148
|
+
for alias, canonical in aliases.items():
|
|
149
|
+
if alias in row and canonical not in row:
|
|
150
|
+
row[canonical] = row.pop(alias)
|
|
151
|
+
return row
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def normalize_action(value: object, label: str, *, allow_delete: bool) -> str:
|
|
155
|
+
action = clean_text(value, label, max_bytes=24)
|
|
156
|
+
action = ACTION_ALIASES.get(action.lower(), action.lower())
|
|
157
|
+
allowed = ("upsert", "delete") if allow_delete else ("upsert",)
|
|
158
|
+
require(action in allowed, f"{label} is invalid: use {' or '.join(allowed)}")
|
|
159
|
+
return action
|
|
160
|
+
|
|
161
|
+
|
|
115
162
|
def require_known_keys(mapping: dict[str, Any], allowed: set[str], label: str) -> None:
|
|
116
163
|
unknown = set(mapping) - allowed
|
|
117
|
-
require(not unknown, f"{label} contains unsupported fields: {', '.join(sorted(unknown))}"
|
|
164
|
+
require(not unknown, f"{label} contains unsupported fields: {', '.join(sorted(unknown))}"
|
|
165
|
+
f"(只收 {', '.join(sorted(allowed))})")
|
|
118
166
|
|
|
119
167
|
|
|
120
168
|
# 事务校验期间收集全部超长字段,一次报完;None 表示逐条立即报错(初始化、状态读取等路径)。
|
|
@@ -311,8 +359,22 @@ def validate_position(value: object, label: str = "context.position") -> dict[st
|
|
|
311
359
|
}
|
|
312
360
|
|
|
313
361
|
|
|
362
|
+
def joined_text(value: object) -> object:
|
|
363
|
+
"""单句字段写成了字符串列表时按「;」连成一句,内容不丢。"""
|
|
364
|
+
if isinstance(value, list) and value and all(isinstance(item, str) for item in value):
|
|
365
|
+
return ";".join(value)
|
|
366
|
+
return value
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def as_text_list(value: object) -> object:
|
|
370
|
+
"""列表字段只写了一句时当作一项。"""
|
|
371
|
+
return [value] if isinstance(value, str) and value.strip() else value
|
|
372
|
+
|
|
373
|
+
|
|
314
374
|
def normalize_snapshot(value: object, label: str) -> dict[str, Any]:
|
|
315
375
|
snapshot = as_mapping(value, label)
|
|
376
|
+
snapshot = {key: joined_text(item) if key in SNAPSHOT_TEXT_FIELDS else as_text_list(item)
|
|
377
|
+
if key in SNAPSHOT_LIST_FIELDS else item for key, item in snapshot.items()}
|
|
316
378
|
require_known_keys(
|
|
317
379
|
snapshot,
|
|
318
380
|
{"identity", "location", "goal", "state", "abilities_resources", "relationships", "knowledge", "open_threads"},
|
|
@@ -379,23 +441,33 @@ def normalize_foreshadow_change(
|
|
|
379
441
|
allow_delete: bool,
|
|
380
442
|
through_chapter: int,
|
|
381
443
|
) -> dict[str, Any]:
|
|
382
|
-
row = as_mapping(value, label)
|
|
444
|
+
row = with_aliases(as_mapping(value, label), FORESHADOW_KEY_ALIASES)
|
|
383
445
|
require_known_keys(
|
|
384
446
|
row,
|
|
385
447
|
{"action", "id", "summary", "planted_chapter", "planned_resolution_chapter", "status", "importance"},
|
|
386
448
|
label,
|
|
387
449
|
)
|
|
388
|
-
|
|
389
|
-
|
|
450
|
+
raw_action = row.get("action", "upsert")
|
|
451
|
+
action = normalize_action(raw_action, f"{label}.action", allow_delete=allow_delete)
|
|
390
452
|
identifier = clean_text(row.get("id"), f"{label}.id", max_bytes=24)
|
|
391
453
|
require(FORESHADOW_ID.fullmatch(identifier) is not None, f"{label}.id must look like F001")
|
|
392
454
|
if action == "delete":
|
|
393
455
|
return {"action": action, "id": identifier}
|
|
394
|
-
|
|
456
|
+
implied = FORESHADOW_ACTION_STATUS.get(" ".join(str(raw_action).split()).lower())
|
|
457
|
+
if implied is not None:
|
|
458
|
+
if row.get("status") in (None, ""):
|
|
459
|
+
row["status"] = implied
|
|
460
|
+
right = "回收了就写 status=已回收" if implied == "已回收" else "只是推进、还没回收就写 status=已埋"
|
|
461
|
+
require(
|
|
462
|
+
row["status"] == implied,
|
|
463
|
+
f"{label}.action={raw_action} 与 status={row['status']} 矛盾:{right};"
|
|
464
|
+
"不是这个意思就把 action 改成 upsert 并写实际状态",
|
|
465
|
+
)
|
|
466
|
+
planted_chapter = as_chapter(row.get("planted_chapter"), f"{label}.planted_chapter")
|
|
395
467
|
require(planted_chapter <= through_chapter, f"{label}.planted_chapter cannot be in the future")
|
|
396
468
|
planned_raw = row.get("planned_resolution_chapter")
|
|
397
469
|
planned_chapter = (
|
|
398
|
-
None if planned_raw
|
|
470
|
+
None if planned_raw in (None, "") else as_chapter(planned_raw, f"{label}.planned_resolution_chapter")
|
|
399
471
|
)
|
|
400
472
|
require(
|
|
401
473
|
planned_chapter is None or planned_chapter >= planted_chapter,
|
|
@@ -471,14 +543,13 @@ def normalize_timeline_change(
|
|
|
471
543
|
allow_delete: bool,
|
|
472
544
|
through_chapter: int,
|
|
473
545
|
) -> dict[str, Any]:
|
|
474
|
-
event = as_mapping(value, label)
|
|
546
|
+
event = with_aliases(as_mapping(value, label), TIMELINE_KEY_ALIASES)
|
|
475
547
|
require_known_keys(
|
|
476
548
|
event,
|
|
477
549
|
{"action", "id", "story_time", "objective_fact", "reader_knowledge", "reveal_status", "reveal_chapter", "characters"},
|
|
478
550
|
label,
|
|
479
551
|
)
|
|
480
|
-
action =
|
|
481
|
-
require(action in ({"upsert", "delete"} if allow_delete else {"upsert"}), f"{label}.action is invalid")
|
|
552
|
+
action = normalize_action(event.get("action", "upsert"), f"{label}.action", allow_delete=allow_delete)
|
|
482
553
|
identifier = clean_text(event.get("id"), f"{label}.id", max_bytes=24)
|
|
483
554
|
require(EVENT_ID.fullmatch(identifier) is not None, f"{label}.id must look like E001")
|
|
484
555
|
if action == "delete":
|
|
@@ -486,7 +557,7 @@ def normalize_timeline_change(
|
|
|
486
557
|
reveal_status = clean_text(event.get("reveal_status"), f"{label}.reveal_status", max_bytes=24)
|
|
487
558
|
require(reveal_status in REVEAL_STATUSES, f"{label}.reveal_status must be one of {REVEAL_STATUSES}")
|
|
488
559
|
reveal_raw = event.get("reveal_chapter")
|
|
489
|
-
reveal_chapter = None if reveal_raw
|
|
560
|
+
reveal_chapter = None if reveal_raw in (None, "") else as_chapter(reveal_raw, f"{label}.reveal_chapter")
|
|
490
561
|
if reveal_status == "未揭示":
|
|
491
562
|
require(reveal_chapter is None, f"{label} must not put a future reveal chapter in established timeline facts")
|
|
492
563
|
else:
|
|
@@ -708,7 +779,8 @@ def normalize_delta(
|
|
|
708
779
|
# 本章退役的角色记录最后一次变化即可,不必再交一份马上要删的快照。
|
|
709
780
|
require(
|
|
710
781
|
not is_core or name in snapshots or portable_name_key(name) in retiring,
|
|
711
|
-
f"core character {name} changed but has no current snapshot"
|
|
782
|
+
f"core character {name} changed but has no current snapshot: 把 draft 输出 current_snapshots 里"
|
|
783
|
+
f"「{name}」的快照整份改成本章结束时的状态,放进 character_snapshots",
|
|
712
784
|
)
|
|
713
785
|
character_changes.append(
|
|
714
786
|
{"name": name, "change": clean_text(change.get("change"), f"delta.character_changes[{index}].change", max_bytes=360)}
|
|
@@ -755,11 +827,18 @@ def normalize_delta(
|
|
|
755
827
|
}
|
|
756
828
|
|
|
757
829
|
|
|
830
|
+
def render_commitments(commitments: list[str]) -> list[str]:
|
|
831
|
+
# 常见情形一行用「;」连写;有承诺原文自带「;」时连写就拆不回来,改成逐条缩进子项。
|
|
832
|
+
if any(";" in item for item in commitments):
|
|
833
|
+
return ["- 下一章承诺:"] + [f" - {item}" for item in commitments]
|
|
834
|
+
return ["- 下一章承诺:" + (";".join(commitments) or "无")]
|
|
835
|
+
|
|
836
|
+
|
|
758
837
|
def render_delta(chapter: int, title: str, delta: dict[str, Any], core_names: set[str]) -> str:
|
|
759
838
|
lines = [
|
|
760
839
|
f"# 第{chapter:03d}章 · {title}",
|
|
761
840
|
f"- 结果:{delta['result']}",
|
|
762
|
-
|
|
841
|
+
*render_commitments(delta["next_chapter_commitments"]),
|
|
763
842
|
"",
|
|
764
843
|
"## 角色变化",
|
|
765
844
|
]
|
|
@@ -938,6 +1017,11 @@ def normalize_transaction(project: Path, state: dict[str, Any], document: object
|
|
|
938
1017
|
return transaction
|
|
939
1018
|
|
|
940
1019
|
|
|
1020
|
+
# 本文件在 story-long-write / story-review / story-import 三份逐字相同;只有 story-long-write 带 storyctl.py。
|
|
1021
|
+
RECOUNT_HINT = ("修订请用 story-long-write 的 storyctl.py chapter commit(带外用 chapter accept-current-length)"
|
|
1022
|
+
"提交同一份事务,它会重新计数并清理本章工作目录")
|
|
1023
|
+
|
|
1024
|
+
|
|
941
1025
|
def _normalize_transaction(project: Path, state: dict[str, Any], document: object) -> dict[str, Any]:
|
|
942
1026
|
root = as_mapping(document, "transaction")
|
|
943
1027
|
require_known_keys(
|
|
@@ -978,6 +1062,15 @@ def _normalize_transaction(project: Path, state: dict[str, Any], document: objec
|
|
|
978
1062
|
wordcount = wordcount_value(
|
|
979
1063
|
wordcount_core.validate_current_wordcount_record, project, chapter, wordcount_input
|
|
980
1064
|
)
|
|
1065
|
+
elif mode == "revision" and str(chapter) in state["wordcount_records"]:
|
|
1066
|
+
# 已提交字数记录的章节:正文或目标改过却绕开 storyctl 提交修订,会留下过期的 actual/body_sha256。
|
|
1067
|
+
# 只核对记录钉住的正文与目标;细纲事后补的「字数范围」不算过期。
|
|
1068
|
+
try:
|
|
1069
|
+
drift = wordcount_core.wordcount_record_drift(project, chapter, state["wordcount_records"][str(chapter)])
|
|
1070
|
+
except wordcount_core.WordcountError as exc:
|
|
1071
|
+
raise TrackingError(f"第{chapter}章的字数记录无法核对({exc});{RECOUNT_HINT}") from exc
|
|
1072
|
+
if drift:
|
|
1073
|
+
raise TrackingError(f"第{chapter}章{'和'.join(drift)}已改;{RECOUNT_HINT}")
|
|
981
1074
|
return {
|
|
982
1075
|
"mode": mode,
|
|
983
1076
|
"chapter": chapter,
|
|
@@ -1171,6 +1264,11 @@ def _apply_transaction_locked(project: Path, document: object) -> dict[str, Any]
|
|
|
1171
1264
|
state = load_state(project)
|
|
1172
1265
|
transaction = normalize_transaction(project, state, document)
|
|
1173
1266
|
next_state = merge_transaction(state, transaction)
|
|
1267
|
+
path = delta_path(tracking, transaction["chapter"])
|
|
1268
|
+
previous_record = parse_chapter_record(path) if transaction["mode"] == "revision" else None
|
|
1269
|
+
if previous_record is not None:
|
|
1270
|
+
# 退役只在 append 发生;修订重写旧章记录时把当初的退役登记原样带过来,不让它随修订消失。
|
|
1271
|
+
transaction["delta"]["retired_context_items"] = previous_record["retired"]
|
|
1174
1272
|
|
|
1175
1273
|
delta_payload = render_delta(
|
|
1176
1274
|
transaction["chapter"],
|
|
@@ -1181,7 +1279,6 @@ def _apply_transaction_locked(project: Path, document: object) -> dict[str, Any]
|
|
|
1181
1279
|
)
|
|
1182
1280
|
views = render_views(next_state)
|
|
1183
1281
|
next_state_payload = json_payload(next_state)
|
|
1184
|
-
path = delta_path(tracking, transaction["chapter"])
|
|
1185
1282
|
if transaction["mode"] == "append" and path.exists():
|
|
1186
1283
|
require(
|
|
1187
1284
|
path.read_text(encoding="utf-8") == delta_payload,
|
|
@@ -1193,9 +1290,21 @@ def _apply_transaction_locked(project: Path, document: object) -> dict[str, Any]
|
|
|
1193
1290
|
# 唯一权威文件最后落盘;在此之前失败可用同一事务直接重跑。
|
|
1194
1291
|
atomic_write_text(state_path(project), next_state_payload)
|
|
1195
1292
|
warn_sizes(views, delta_payload)
|
|
1293
|
+
if previous_record is not None:
|
|
1294
|
+
warn_emptied_record(transaction["chapter"], previous_record, transaction["delta"])
|
|
1196
1295
|
return next_state
|
|
1197
1296
|
|
|
1198
1297
|
|
|
1298
|
+
def warn_emptied_record(chapter: int, previous: dict[str, Any], delta: dict[str, Any]) -> None:
|
|
1299
|
+
labels = {"character_changes": "角色变化", "foreshadow_changes": "伏笔变化", "timeline_events": "时间与揭示",
|
|
1300
|
+
"constraints": "连贯性约束", "next_chapter_commitments": "下一章承诺"}
|
|
1301
|
+
emptied = [f"{label}(原有 {len(previous[key])} 项)" for key, label in labels.items()
|
|
1302
|
+
if previous[key] and not delta[key]]
|
|
1303
|
+
if emptied:
|
|
1304
|
+
emit(f"WARNING: 第{chapter}章修订把逐章记录的 " + "、".join(emptied)
|
|
1305
|
+
+ " 清空了;修订的 delta 是本章完整记录,不是只写改动。不是有意删除就用 draft 重新预填后再提交。", error=True)
|
|
1306
|
+
|
|
1307
|
+
|
|
1199
1308
|
def apply_transaction(project: Path, document: object) -> dict[str, Any]:
|
|
1200
1309
|
with project_write_lock(project):
|
|
1201
1310
|
return _apply_transaction_locked(project, document)
|
|
@@ -1241,11 +1350,123 @@ DRAFT_LIMITS = {
|
|
|
1241
1350
|
}
|
|
1242
1351
|
|
|
1243
1352
|
|
|
1353
|
+
RECORD_SECTIONS = {"角色变化": "character_changes", "伏笔变化": "foreshadow_changes",
|
|
1354
|
+
"时间与揭示": "timeline_events", "连贯性约束": "constraints", "本章退役登记": "retired"}
|
|
1355
|
+
|
|
1356
|
+
|
|
1357
|
+
def parse_chapter_record(path: Path) -> dict[str, Any] | None:
|
|
1358
|
+
"""读回本工具自己渲染的逐章记录(render_delta 的固定格式),供修订草稿预填与修订提交核对。
|
|
1359
|
+
这是对自家确定性输出的逆运算,不是解析手写 Markdown;读不到返回 None。"""
|
|
1360
|
+
try:
|
|
1361
|
+
text = path.read_text(encoding="utf-8")
|
|
1362
|
+
except (OSError, UnicodeError):
|
|
1363
|
+
return None
|
|
1364
|
+
record: dict[str, Any] = {"title": "", "result": "", "next_chapter_commitments": [],
|
|
1365
|
+
**{key: [] for key in RECORD_SECTIONS.values()}}
|
|
1366
|
+
section = None
|
|
1367
|
+
in_commitments = False
|
|
1368
|
+
for line in text.splitlines():
|
|
1369
|
+
heading = re.match(r"^# 第\d+章 · (.+)$", line)
|
|
1370
|
+
if heading and not record["title"]:
|
|
1371
|
+
record["title"] = heading.group(1).strip()
|
|
1372
|
+
continue
|
|
1373
|
+
if line.startswith("## "):
|
|
1374
|
+
section = RECORD_SECTIONS.get(line[3:].strip())
|
|
1375
|
+
in_commitments = False
|
|
1376
|
+
continue
|
|
1377
|
+
if in_commitments and line.startswith(" - "):
|
|
1378
|
+
record["next_chapter_commitments"].append(line[4:])
|
|
1379
|
+
continue
|
|
1380
|
+
in_commitments = False
|
|
1381
|
+
if not line.startswith("- "):
|
|
1382
|
+
continue
|
|
1383
|
+
item = line[2:]
|
|
1384
|
+
if section is None:
|
|
1385
|
+
if item.startswith("结果:"):
|
|
1386
|
+
record["result"] = item[len("结果:"):]
|
|
1387
|
+
elif item.startswith("下一章承诺:"):
|
|
1388
|
+
value = item[len("下一章承诺:"):]
|
|
1389
|
+
# 空值 = 逐条子项格式(render_commitments),后面的缩进行逐条读回。
|
|
1390
|
+
in_commitments = value == ""
|
|
1391
|
+
record["next_chapter_commitments"] = [] if value in ("无", "") else value.split(";")
|
|
1392
|
+
continue
|
|
1393
|
+
if item == "无" and section != "retired":
|
|
1394
|
+
continue
|
|
1395
|
+
record[section].append(item)
|
|
1396
|
+
return record
|
|
1397
|
+
|
|
1398
|
+
|
|
1399
|
+
def record_prefill(state: dict[str, Any], record: dict[str, Any]) -> tuple[dict[str, Any], dict[str, Any], list[str]]:
|
|
1400
|
+
"""把已提交的逐章记录还原成修订 delta:结果、承诺、约束、角色变化按记录原文;伏笔与时间线
|
|
1401
|
+
取受影响 ID 的当前值(修订提交的就是截至最新章的当前值)。另返回记录里核心角色的当前快照。"""
|
|
1402
|
+
notes: list[str] = []
|
|
1403
|
+
changes = []
|
|
1404
|
+
for line in record["character_changes"]:
|
|
1405
|
+
parts = line.split("|", 2)
|
|
1406
|
+
if len(parts) == 3:
|
|
1407
|
+
changes.append({"name": parts[0], "change": parts[2]})
|
|
1408
|
+
snapshots = {item["name"]: copy.deepcopy(state["characters"][item["name"]])
|
|
1409
|
+
for item in changes if item["name"] in state["characters"]}
|
|
1410
|
+
|
|
1411
|
+
def rows(lines: list[str], current: dict[str, Any], label: str) -> list[dict[str, Any]]:
|
|
1412
|
+
prefilled = []
|
|
1413
|
+
for line in lines:
|
|
1414
|
+
parts = line.split("|")
|
|
1415
|
+
identifier = parts[0]
|
|
1416
|
+
if len(parts) > 1 and parts[1] == "删除当前登记":
|
|
1417
|
+
if identifier in current:
|
|
1418
|
+
notes.append(f"{label} {identifier} 本章删过、后来又登记了,没有预填删除,确需删除自行加回")
|
|
1419
|
+
else:
|
|
1420
|
+
prefilled.append({"action": "delete", "id": identifier})
|
|
1421
|
+
elif identifier in current:
|
|
1422
|
+
prefilled.append({"action": "upsert", **{key: copy.deepcopy(value) for key, value in current[identifier].items()
|
|
1423
|
+
if key not in ("updated_chapter", "first_recorded_chapter")}})
|
|
1424
|
+
else:
|
|
1425
|
+
notes.append(f"{label} {identifier} 已在后续章节删除,没有预填")
|
|
1426
|
+
return prefilled
|
|
1427
|
+
|
|
1428
|
+
delta = {
|
|
1429
|
+
"result": record["result"],
|
|
1430
|
+
"character_changes": changes,
|
|
1431
|
+
"foreshadow_changes": rows(record["foreshadow_changes"], state["foreshadow"], "伏笔"),
|
|
1432
|
+
"timeline_events": rows(record["timeline_events"], state["timeline"], "时间线事件"),
|
|
1433
|
+
"constraints": list(record["constraints"]),
|
|
1434
|
+
"next_chapter_commitments": list(record["next_chapter_commitments"]),
|
|
1435
|
+
}
|
|
1436
|
+
return delta, snapshots, notes
|
|
1437
|
+
|
|
1438
|
+
|
|
1439
|
+
def entry_shapes(chapter: int) -> dict[str, Any]:
|
|
1440
|
+
"""draft 当场给出每类条目的形状:模型填 delta 时手里只有空数组,字段名、整数、枚举都靠猜,
|
|
1441
|
+
首次提交几乎都因此被退回。取值从校验用的同一组常量生成,不另立一套。"""
|
|
1442
|
+
return {
|
|
1443
|
+
"delta.character_changes[]": {"name": "角色名", "change": "一句话:本章起了什么变化"},
|
|
1444
|
+
"delta.foreshadow_changes[]": {
|
|
1445
|
+
"action": "upsert(撤掉整条写 delete,只带 id)", "id": "F007", "summary": "伏笔一句话",
|
|
1446
|
+
"planted_chapter": chapter, "planned_resolution_chapter": "计划回收章的整数,未定写 null",
|
|
1447
|
+
"status": "|".join(FORESHADOW_STATUSES), "importance": "|".join(FORESHADOW_IMPORTANCE),
|
|
1448
|
+
},
|
|
1449
|
+
"delta.timeline_events[]": {
|
|
1450
|
+
"action": "upsert(撤掉整条写 delete,只带 id)", "id": "E012", "story_time": "故事内时间",
|
|
1451
|
+
"objective_fact": "客观发生了什么", "reader_knowledge": "读者此刻知道/以为什么",
|
|
1452
|
+
"reveal_status": "|".join(REVEAL_STATUSES),
|
|
1453
|
+
"reveal_chapter": f"已揭示或部分揭示时写揭示章的整数(不晚于 {chapter}),未揭示写 null",
|
|
1454
|
+
"characters": ["角色名"],
|
|
1455
|
+
},
|
|
1456
|
+
"character_snapshots.{角色名}": {
|
|
1457
|
+
**{key: "一句话" for key in SNAPSHOT_TEXT_FIELDS},
|
|
1458
|
+
**{key: ["一条一句"] for key in SNAPSHOT_LIST_FIELDS},
|
|
1459
|
+
},
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
|
|
1244
1463
|
def draft_transaction(project: Path, chapter: int) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any]]:
|
|
1245
|
-
"""按当前 state
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
所以不预填,上一章的值另行返回作参考。
|
|
1464
|
+
"""按当前 state 预填一份逐章事务:修订号、模式、章名和整份提交的上下文当前值都填好。
|
|
1465
|
+
新章(append)调用方只写本章变化;另返回在场核心角色的当前快照,供有变化时整份改写后放进事务。
|
|
1466
|
+
新章的故事时间与场景留空:它们必须是本章结束时的位置,沿用上一章的值能静默提交,
|
|
1467
|
+
所以不预填,上一章的值另行返回作参考。
|
|
1468
|
+
修订(revision)的 delta 是修订后本章的完整记录,所以按已提交的逐章记录预填,调用方在上面改;
|
|
1469
|
+
第三项返回 {"notes": [...], "prefilled": bool}:没能预填的条目,以及逐章记录是否读到。"""
|
|
1249
1470
|
state = load_state(project)
|
|
1250
1471
|
last = state["last_committed_chapter"]
|
|
1251
1472
|
require(1 <= chapter <= last + 1, f"draft chapter must be between 1 and {last + 1}")
|
|
@@ -1263,9 +1484,21 @@ def draft_transaction(project: Path, chapter: int) -> tuple[dict[str, Any], dict
|
|
|
1263
1484
|
"result": "", "character_changes": [], "foreshadow_changes": [], "timeline_events": [],
|
|
1264
1485
|
"constraints": [], "next_chapter_commitments": [],
|
|
1265
1486
|
}
|
|
1487
|
+
snapshots_prefill: dict[str, Any] = {}
|
|
1488
|
+
notes: list[str] = []
|
|
1489
|
+
prefilled = False
|
|
1266
1490
|
if mode == "append":
|
|
1267
1491
|
delta.update({"retired_context_items": [], "retired_characters": []})
|
|
1268
1492
|
context["position"].update({"story_time": "", "scene": ""})
|
|
1493
|
+
else:
|
|
1494
|
+
record = parse_chapter_record(delta_path(tracking_root(project), chapter))
|
|
1495
|
+
if record is not None:
|
|
1496
|
+
prefilled = True
|
|
1497
|
+
delta, snapshots_prefill, notes = record_prefill(state, record)
|
|
1498
|
+
title = title or record["title"]
|
|
1499
|
+
if chapter == last:
|
|
1500
|
+
# 最新章的承诺原样在 state 里,比从记录行按「;」拆回更准。
|
|
1501
|
+
delta["next_chapter_commitments"] = list(state["context"]["next_chapter_commitments"])
|
|
1269
1502
|
document = {
|
|
1270
1503
|
"schema_version": INPUT_SCHEMA_VERSION,
|
|
1271
1504
|
"mode": mode,
|
|
@@ -1275,11 +1508,13 @@ def draft_transaction(project: Path, chapter: int) -> tuple[dict[str, Any], dict
|
|
|
1275
1508
|
"delta": delta,
|
|
1276
1509
|
"context": {key: context[key] for key in
|
|
1277
1510
|
("position", "long_term_constraints", "active_character_names", "continuity_risks")},
|
|
1278
|
-
"character_snapshots":
|
|
1511
|
+
"character_snapshots": snapshots_prefill,
|
|
1279
1512
|
}
|
|
1280
1513
|
snapshots = {name: state["characters"][name] for name in context["active_character_names"]
|
|
1281
1514
|
if name in state["characters"]}
|
|
1282
|
-
|
|
1515
|
+
if mode == "revision":
|
|
1516
|
+
return document, snapshots, {"notes": notes, "prefilled": prefilled}
|
|
1517
|
+
return document, snapshots, previous_position
|
|
1283
1518
|
|
|
1284
1519
|
|
|
1285
1520
|
def rebuild_stale_draft(document: dict[str, Any], existing: dict[str, Any], append: bool,
|
|
@@ -1375,7 +1610,10 @@ def main() -> int:
|
|
|
1375
1610
|
args = build_parser().parse_args()
|
|
1376
1611
|
try:
|
|
1377
1612
|
if args.command == "draft":
|
|
1378
|
-
document, snapshots,
|
|
1613
|
+
document, snapshots, extra = draft_transaction(args.project, args.chapter)
|
|
1614
|
+
previous_position = extra if document["mode"] == "append" else {}
|
|
1615
|
+
prefill_notes = extra.get("notes", []) if document["mode"] == "revision" else []
|
|
1616
|
+
record_prefilled = bool(extra.get("prefilled")) if document["mode"] == "revision" else False
|
|
1379
1617
|
out = args.out or args.project / ".story" / "work" / f"第{args.chapter:03d}章" / "tracking.json"
|
|
1380
1618
|
out.parent.mkdir(parents=True, exist_ok=True)
|
|
1381
1619
|
refreshed = ""
|
|
@@ -1392,9 +1630,25 @@ def main() -> int:
|
|
|
1392
1630
|
refreshed = rebuild_stale_draft(document, existing, bool(previous_position),
|
|
1393
1631
|
load_state(args.project)["characters"])
|
|
1394
1632
|
out.write_text(json.dumps(document, ensure_ascii=False, indent=1) + "\n", encoding="utf-8")
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1633
|
+
if document["mode"] == "revision" and not record_prefilled:
|
|
1634
|
+
fill = (f"这是修订,但本章逐章记录缺失或读不了({delta_path(Path('追踪'), args.chapter).as_posix()}),delta 没有预填:"
|
|
1635
|
+
"按修订后正文把本章完整记录整份写上(结果、承诺、角色变化、伏笔、时间线、约束),没写的项不会进记录。"
|
|
1636
|
+
"角色快照、伏笔、时间线写截至最新已写章的当前值;context 原样保留全部当前条目(修订不能退役)。"
|
|
1637
|
+
"正文改过就用 story-long-write 的 storyctl.py chapter commit 提交(重新计数并清理本章工作目录)。"
|
|
1638
|
+
"不要从脚本源码或 state 文件里另找格式。")
|
|
1639
|
+
elif document["mode"] == "revision":
|
|
1640
|
+
fill = ("这是修订:delta 是修订后本章的完整记录,已按本章现有逐章记录预填(伏笔与时间线取当前值,"
|
|
1641
|
+
"记录里的核心角色快照已放进 character_snapshots)。对照修订后正文逐项改:仍成立的原样保留,"
|
|
1642
|
+
"被推翻的删掉或改写,新增的补上;不要清空后只写改动,没写的项会从本章记录里消失。"
|
|
1643
|
+
"角色快照、伏笔、时间线改成截至最新已写章的当前值;context 原样保留全部当前条目(修订不能退役)。"
|
|
1644
|
+
"正文改过就用 story-long-write 的 storyctl.py chapter commit 提交(重新计数并清理本章工作目录)。"
|
|
1645
|
+
"不要从脚本源码或 state 文件里另找格式。")
|
|
1646
|
+
if prefill_notes:
|
|
1647
|
+
fill += "没能预填:" + ";".join(prefill_notes) + "。"
|
|
1648
|
+
else:
|
|
1649
|
+
fill = ("只填 delta 里本章的变化;context 其余字段已是当前值,要撤下的长期约束或连贯性风险从 context 删掉并把原文放进 "
|
|
1650
|
+
"delta.retired_context_items(仅 append);本章有变化的核心角色把下面的当前快照整份改好放进 character_snapshots,"
|
|
1651
|
+
"并在 character_changes 写一句变化。每类条目照 shapes 的形状写,不要从脚本源码或 state 文件里另找格式。")
|
|
1398
1652
|
blank = not (document["context"]["position"].get("story_time") or document["context"]["position"].get("scene"))
|
|
1399
1653
|
if previous_position and blank:
|
|
1400
1654
|
fill = ("context.position 的 story_time 与 scene 留空,填本章结束时的故事时间与场景(上一章结束时见 "
|
|
@@ -1405,6 +1659,7 @@ def main() -> int:
|
|
|
1405
1659
|
"expected_state_revision": document["expected_state_revision"],
|
|
1406
1660
|
"fill": (f"{refreshed};要从头生成加 --force。" if refreshed else "") + fill,
|
|
1407
1661
|
"limits_chars": DRAFT_LIMITS,
|
|
1662
|
+
"shapes": entry_shapes(args.chapter),
|
|
1408
1663
|
"current_snapshots": snapshots,
|
|
1409
1664
|
}
|
|
1410
1665
|
if previous_position:
|