@oh-story/dsh 0.1.0
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/LICENSE +21 -0
- package/README.md +38 -0
- package/cordis.patch.yml +3 -0
- package/lib/client.js +1201 -0
- package/lib/client.js.map +7 -0
- package/lib/drama/LICENSE.upstream +21 -0
- package/lib/drama/manifest.json +1012 -0
- package/lib/drama/skills/short-drama/SKILL.md +153 -0
- package/lib/drama/skills/short-drama/agents/openai.yaml +4 -0
- package/lib/drama/skills/short-drama/assets/creator-decision.example.jsonl +4 -0
- package/lib/drama/skills/short-drama/assets/production-observation.example.jsonl +2 -0
- package/lib/drama/skills/short-drama/assets/project-template/short-drama.json +36 -0
- package/lib/drama/skills/short-drama/assets/reference-observation.example.jsonl +2 -0
- package/lib/drama/skills/short-drama/references/audience-reveal.md +74 -0
- package/lib/drama/skills/short-drama/references/contract-and-ownership.md +94 -0
- package/lib/drama/skills/short-drama/references/creator-workflow.md +82 -0
- package/lib/drama/skills/short-drama/references/form-cards/Q/347/211/210/350/241/250/350/276/276.md +73 -0
- package/lib/drama/skills/short-drama/references/form-cards//344/272/214/347/273/264/345/212/250/346/200/201/346/274/253.md +74 -0
- package/lib/drama/skills/short-drama/references/form-cards//345/233/275/346/274/253/344/272/214/346/254/241/345/205/203.md +79 -0
- package/lib/drama/skills/short-drama/references/form-cards//345/256/236/346/213/215.md +75 -0
- package/lib/drama/skills/short-drama/references/form-cards//346/260/264/345/242/250/347/254/224/350/247/246.md +85 -0
- package/lib/drama/skills/short-drama/references/form-cards//351/243/216/346/240/274/345/214/226/344/270/211/347/273/264.md +72 -0
- package/lib/drama/skills/short-drama/references/knowhow-index.md +80 -0
- package/lib/drama/skills/short-drama/references/lifecycle-commands.md +130 -0
- package/lib/drama/skills/short-drama/references/look-development.md +52 -0
- package/lib/drama/skills/short-drama/references/pickup-and-alternate.md +58 -0
- package/lib/drama/skills/short-drama/references/production-form-profiles.md +126 -0
- package/lib/drama/skills/short-drama/references/reference-roles.md +142 -0
- package/lib/drama/skills/short-drama/references/runtime-preflight.md +27 -0
- package/lib/drama/skills/short-drama/scripts/project_tool.py +1963 -0
- package/lib/drama/skills/short-drama/scripts/selftest.py +287 -0
- package/lib/drama/skills/short-drama-assets/SKILL.md +187 -0
- package/lib/drama/skills/short-drama-assets/agents/openai.yaml +4 -0
- package/lib/drama/skills/short-drama-assets/assets/character-look.example.jsonl +3 -0
- package/lib/drama/skills/short-drama-assets/assets/continuity.example.jsonl +4 -0
- package/lib/drama/skills/short-drama-assets/assets/decisions.example.jsonl +5 -0
- package/lib/drama/skills/short-drama-assets/assets/location-view.example.jsonl +3 -0
- package/lib/drama/skills/short-drama-assets/assets/occurrences.example.jsonl +5 -0
- package/lib/drama/skills/short-drama-assets/assets/prop-state.example.jsonl +3 -0
- package/lib/drama/skills/short-drama-assets/examples/minimal/characters.jsonl +2 -0
- package/lib/drama/skills/short-drama-assets/examples/minimal/looks.jsonl +2 -0
- package/lib/drama/skills/short-drama-assets/references/asset-review-checklist.md +89 -0
- package/lib/drama/skills/short-drama-assets/references/character-and-look.md +164 -0
- package/lib/drama/skills/short-drama-assets/references/continuity-delta.md +123 -0
- package/lib/drama/skills/short-drama-assets/references/identity-vs-variant.md +146 -0
- package/lib/drama/skills/short-drama-assets/references/location-and-view.md +84 -0
- package/lib/drama/skills/short-drama-assets/references/occurrence-extraction.md +111 -0
- package/lib/drama/skills/short-drama-assets/references/prop-and-state.md +107 -0
- package/lib/drama/skills/short-drama-assets/references/stage-contract.md +136 -0
- package/lib/drama/skills/short-drama-assets/references/voice-direction.md +171 -0
- package/lib/drama/skills/short-drama-assets/scripts/asset_check.py +267 -0
- package/lib/drama/skills/short-drama-assets/scripts/selftest.py +89 -0
- package/lib/drama/skills/short-drama-develop/SKILL.md +157 -0
- package/lib/drama/skills/short-drama-develop/agents/openai.yaml +4 -0
- package/lib/drama/skills/short-drama-develop/assets/adaptation-map.example.jsonl +1 -0
- package/lib/drama/skills/short-drama-develop/assets/creative-brief.md +120 -0
- package/lib/drama/skills/short-drama-develop/assets/episode-map.jsonl +1 -0
- package/lib/drama/skills/short-drama-develop/assets/story-engine.md +181 -0
- package/lib/drama/skills/short-drama-develop/references/adaptation-craft.md +219 -0
- package/lib/drama/skills/short-drama-develop/references/creative-reference-intake.md +57 -0
- package/lib/drama/skills/short-drama-develop/references/director-brief-craft.md +113 -0
- package/lib/drama/skills/short-drama-develop/references/episode-design.md +509 -0
- package/lib/drama/skills/short-drama-develop/references/genre-and-hook-playbook.md +240 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//344/272/262/345/255/220/351/232/220/347/247/230.md +112 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//344/273/231/344/276/240/344/277/256/347/234/237.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//345/212/250/344/275/234/344/273/273/345/212/241.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//345/217/244/350/243/205/346/235/203/350/260/213.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//345/244/215/344/273/207/346/211/223/350/204/270.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//345/256/266/345/272/255/345/205/263/347/263/273.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//346/202/254/347/226/221/350/247/204/345/210/231.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//347/224/237/346/264/273/346/265/201.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//347/240/264/351/225/234/351/207/215/345/234/206.md +109 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//350/201/214/345/234/272/345/226/234/345/211/247.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//350/261/252/351/227/250/345/251/232/346/201/213.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//350/272/253/344/273/275/351/224/231/344/275/215.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards.md +92 -0
- package/lib/drama/skills/short-drama-develop/references/mechanism-loop.md +282 -0
- package/lib/drama/skills/short-drama-develop/references/multi-episode-intake.md +128 -0
- package/lib/drama/skills/short-drama-develop/references/premise-devices.md +211 -0
- package/lib/drama/skills/short-drama-develop/references/reveal-reversal-payoff.md +99 -0
- package/lib/drama/skills/short-drama-develop/references/serial-character-and-memory.md +293 -0
- package/lib/drama/skills/short-drama-develop/references/stage-contract.md +88 -0
- package/lib/drama/skills/short-drama-develop/references/story-craft.md +359 -0
- package/lib/drama/skills/short-drama-develop/scripts/episode_intake.py +699 -0
- package/lib/drama/skills/short-drama-develop/scripts/selftest.py +47 -0
- package/lib/drama/skills/short-drama-image-prompts/SKILL.md +181 -0
- package/lib/drama/skills/short-drama-image-prompts/agents/openai.yaml +4 -0
- package/lib/drama/skills/short-drama-image-prompts/assets/image-prompt-spec.jsonl.md +187 -0
- package/lib/drama/skills/short-drama-image-prompts/assets/image-prompts.md +37 -0
- package/lib/drama/skills/short-drama-image-prompts/assets/lookdev-frame-spec.jsonl.md +128 -0
- package/lib/drama/skills/short-drama-image-prompts/assets/lookdev-prompts.md +31 -0
- package/lib/drama/skills/short-drama-image-prompts/examples/minimal-image-prompt-specs.jsonl +2 -0
- package/lib/drama/skills/short-drama-image-prompts/references/character-and-look.md +154 -0
- package/lib/drama/skills/short-drama-image-prompts/references/common-recipe.md +231 -0
- package/lib/drama/skills/short-drama-image-prompts/references/edit-and-revision.md +122 -0
- package/lib/drama/skills/short-drama-image-prompts/references/location-plate.md +152 -0
- package/lib/drama/skills/short-drama-image-prompts/references/look-and-state-variant.md +96 -0
- package/lib/drama/skills/short-drama-image-prompts/references/lookdev-frame.md +38 -0
- package/lib/drama/skills/short-drama-image-prompts/references/production-sheet-recipes.md +177 -0
- package/lib/drama/skills/short-drama-image-prompts/references/prop-plate.md +140 -0
- package/lib/drama/skills/short-drama-image-prompts/references/review-and-fixtures.md +92 -0
- package/lib/drama/skills/short-drama-image-prompts/references/stage-contract.md +89 -0
- package/lib/drama/skills/short-drama-image-prompts/scripts/image_prompt_check.py +443 -0
- package/lib/drama/skills/short-drama-image-prompts/scripts/selftest.py +93 -0
- package/lib/drama/skills/short-drama-novel-analyze/SKILL.md +245 -0
- package/lib/drama/skills/short-drama-novel-analyze/agents/openai.yaml +4 -0
- package/lib/drama/skills/short-drama-novel-analyze/assets/episode-candidate.example.jsonl +3 -0
- package/lib/drama/skills/short-drama-novel-analyze/references/adaptation-triage.md +116 -0
- package/lib/drama/skills/short-drama-novel-analyze/references/adaptation-value.md +124 -0
- package/lib/drama/skills/short-drama-novel-analyze/references/aggregation-and-entities.md +155 -0
- package/lib/drama/skills/short-drama-novel-analyze/references/chapter-extraction.md +141 -0
- package/lib/drama/skills/short-drama-novel-analyze/references/stage-contract.md +67 -0
- package/lib/drama/skills/short-drama-novel-analyze/scripts/novel_index.py +651 -0
- package/lib/drama/skills/short-drama-novel-analyze/scripts/selftest.py +51 -0
- package/lib/drama/skills/short-drama-produce/SKILL.md +103 -0
- package/lib/drama/skills/short-drama-produce/agents/openai.yaml +4 -0
- package/lib/drama/skills/short-drama-produce/references/adapter-contract.md +140 -0
- package/lib/drama/skills/short-drama-produce/references/providers/gpt-image-2.md +24 -0
- package/lib/drama/skills/short-drama-produce/references/providers/minimax-music.md +25 -0
- package/lib/drama/skills/short-drama-produce/references/providers/seedance.md +40 -0
- package/lib/drama/skills/short-drama-produce/scripts/fixture_adapter.py +60 -0
- package/lib/drama/skills/short-drama-produce/scripts/production_tool.py +1635 -0
- package/lib/drama/skills/short-drama-produce/scripts/provider_adapters.py +964 -0
- package/lib/drama/skills/short-drama-produce/scripts/selftest.py +134 -0
- package/lib/drama/skills/short-drama-review/SKILL.md +178 -0
- package/lib/drama/skills/short-drama-review/agents/openai.yaml +4 -0
- package/lib/drama/skills/short-drama-review/assets/finding-template.jsonl +2 -0
- package/lib/drama/skills/short-drama-review/assets/supersession-decision.example.json +42 -0
- package/lib/drama/skills/short-drama-review/assets/verdict-template.json +32 -0
- package/lib/drama/skills/short-drama-review/examples/minimal-findings.jsonl +2 -0
- package/lib/drama/skills/short-drama-review/examples/minimal-verdict.json +34 -0
- package/lib/drama/skills/short-drama-review/references/anti-template-repair.md +114 -0
- package/lib/drama/skills/short-drama-review/references/production-quality-gates.md +270 -0
- package/lib/drama/skills/short-drama-review/references/project-calibration.md +85 -0
- package/lib/drama/skills/short-drama-review/references/review-method.md +82 -0
- package/lib/drama/skills/short-drama-review/references/rubric-assets-prompts.md +115 -0
- package/lib/drama/skills/short-drama-review/references/rubric-source-analysis.md +108 -0
- package/lib/drama/skills/short-drama-review/references/rubric-story-script.md +164 -0
- package/lib/drama/skills/short-drama-review/references/rubric-visual-motion.md +166 -0
- package/lib/drama/skills/short-drama-review/references/stage-contract.md +87 -0
- package/lib/drama/skills/short-drama-review/scripts/review_check.py +325 -0
- package/lib/drama/skills/short-drama-review/scripts/selftest.py +87 -0
- package/lib/drama/skills/short-drama-storyboard/SKILL.md +264 -0
- package/lib/drama/skills/short-drama-storyboard/agents/openai.yaml +4 -0
- package/lib/drama/skills/short-drama-storyboard/assets/coverage-audition.example.jsonl +2 -0
- package/lib/drama/skills/short-drama-storyboard/assets/coverage-template.json +49 -0
- package/lib/drama/skills/short-drama-storyboard/assets/keyframe-prompts.md +32 -0
- package/lib/drama/skills/short-drama-storyboard/assets/keyframe-template.jsonl +2 -0
- package/lib/drama/skills/short-drama-storyboard/assets/revision-lineage.fragment.json +12 -0
- package/lib/drama/skills/short-drama-storyboard/assets/scene-visual-plan.example.jsonl +2 -0
- package/lib/drama/skills/short-drama-storyboard/assets/shot-template.jsonl +2 -0
- package/lib/drama/skills/short-drama-storyboard/references/blocking-playbooks.md +241 -0
- package/lib/drama/skills/short-drama-storyboard/references/coverage-audition.md +39 -0
- package/lib/drama/skills/short-drama-storyboard/references/keyframe-craft.md +169 -0
- package/lib/drama/skills/short-drama-storyboard/references/production-shot-grammar.md +264 -0
- package/lib/drama/skills/short-drama-storyboard/references/review-and-fixtures.md +70 -0
- package/lib/drama/skills/short-drama-storyboard/references/scene-visual-plan.md +39 -0
- package/lib/drama/skills/short-drama-storyboard/references/screenplay-to-keyframe-example.md +157 -0
- package/lib/drama/skills/short-drama-storyboard/references/shot-craft.md +192 -0
- package/lib/drama/skills/short-drama-storyboard/references/shot-revision-identity.md +29 -0
- package/lib/drama/skills/short-drama-storyboard/references/stage-contract.md +110 -0
- package/lib/drama/skills/short-drama-storyboard/scripts/selftest.py +191 -0
- package/lib/drama/skills/short-drama-storyboard/scripts/storyboard_check.py +824 -0
- package/lib/drama/skills/short-drama-video-prompts/SKILL.md +245 -0
- package/lib/drama/skills/short-drama-video-prompts/agents/openai.yaml +4 -0
- package/lib/drama/skills/short-drama-video-prompts/assets/coverage-scope.fragment.json +21 -0
- package/lib/drama/skills/short-drama-video-prompts/assets/delivery-container.jsonl.md +101 -0
- package/lib/drama/skills/short-drama-video-prompts/assets/motion-spec.jsonl.md +212 -0
- package/lib/drama/skills/short-drama-video-prompts/assets/motion-terminal.example.jsonl +2 -0
- package/lib/drama/skills/short-drama-video-prompts/assets/music-spec.jsonl.md +31 -0
- package/lib/drama/skills/short-drama-video-prompts/assets/performance.fragment.json +38 -0
- package/lib/drama/skills/short-drama-video-prompts/assets/video-prompts.md +46 -0
- package/lib/drama/skills/short-drama-video-prompts/examples/minimal-music-specs.jsonl +2 -0
- package/lib/drama/skills/short-drama-video-prompts/references/camera-audio-continuity.md +240 -0
- package/lib/drama/skills/short-drama-video-prompts/references/delivery-profile.md +255 -0
- package/lib/drama/skills/short-drama-video-prompts/references/generability.md +93 -0
- package/lib/drama/skills/short-drama-video-prompts/references/motion-recipe.md +304 -0
- package/lib/drama/skills/short-drama-video-prompts/references/performance-action-timing.md +191 -0
- package/lib/drama/skills/short-drama-video-prompts/references/production-prompt-grammar.md +312 -0
- package/lib/drama/skills/short-drama-video-prompts/references/review-and-fixtures.md +168 -0
- package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +110 -0
- package/lib/drama/skills/short-drama-video-prompts/scripts/container_check.py +329 -0
- package/lib/drama/skills/short-drama-video-prompts/scripts/motion_timing_check.py +450 -0
- package/lib/drama/skills/short-drama-video-prompts/scripts/music_spec_check.py +327 -0
- package/lib/drama/skills/short-drama-video-prompts/scripts/selftest.py +82 -0
- package/lib/drama/skills/short-drama-write/SKILL.md +284 -0
- package/lib/drama/skills/short-drama-write/agents/openai.yaml +4 -0
- package/lib/drama/skills/short-drama-write/assets/beats.jsonl +2 -0
- package/lib/drama/skills/short-drama-write/assets/episode-card-standalone.json +120 -0
- package/lib/drama/skills/short-drama-write/assets/episode-card.json +55 -0
- package/lib/drama/skills/short-drama-write/assets/screenplay.md +36 -0
- package/lib/drama/skills/short-drama-write/assets/voice-record-sheet.jsonl.md +89 -0
- package/lib/drama/skills/short-drama-write/references/dialogue-craft.md +519 -0
- package/lib/drama/skills/short-drama-write/references/production-format-dialect.md +273 -0
- package/lib/drama/skills/short-drama-write/references/scene-handoff-capsule.md +51 -0
- package/lib/drama/skills/short-drama-write/references/scene-sound-dramaturgy.md +43 -0
- package/lib/drama/skills/short-drama-write/references/screenplay-format.md +260 -0
- package/lib/drama/skills/short-drama-write/references/script-craft.md +558 -0
- package/lib/drama/skills/short-drama-write/references/stage-contract.md +94 -0
- package/lib/drama/skills/short-drama-write/references/substitutable-realization.md +107 -0
- package/lib/drama/skills/short-drama-write/scripts/duration_estimate.py +309 -0
- package/lib/drama/skills/short-drama-write/scripts/screenplay_index.py +1091 -0
- package/lib/drama/skills/short-drama-write/scripts/selftest.py +229 -0
- package/lib/drama/skills/short-drama-write/scripts/voice_sheet_check.py +416 -0
- package/lib/index.js +756 -0
- package/lib/index.js.map +7 -0
- package/lib/oh-story/LICENSE.upstream +21 -0
- package/lib/oh-story/manifest.json +1351 -0
- package/lib/oh-story/roles/chapter-extractor.md +314 -0
- package/lib/oh-story/roles/character-designer.md +169 -0
- package/lib/oh-story/roles/consistency-checker.md +190 -0
- package/lib/oh-story/roles/narrative-writer.md +294 -0
- package/lib/oh-story/roles/story-architect.md +195 -0
- package/lib/oh-story/roles/story-explorer.md +364 -0
- package/lib/oh-story/roles/story-researcher.md +304 -0
- package/lib/oh-story/skills/browser-cdp/SKILL.md +175 -0
- package/lib/oh-story/skills/story/SKILL.md +116 -0
- package/lib/oh-story/skills/story/VERSION +1 -0
- package/lib/oh-story/skills/story-cover/SKILL.md +327 -0
- package/lib/oh-story/skills/story-cover/references/cover-styles.md +210 -0
- package/lib/oh-story/skills/story-deslop/SKILL.md +445 -0
- package/lib/oh-story/skills/story-deslop/references/anti-ai-writing.md +582 -0
- package/lib/oh-story/skills/story-deslop/references/banned-words.md +147 -0
- package/lib/oh-story/skills/story-deslop/scripts/check-ai-patterns.js +1371 -0
- package/lib/oh-story/skills/story-deslop/scripts/check-degeneration.js +330 -0
- package/lib/oh-story/skills/story-deslop/scripts/check-outline-copy.js +241 -0
- package/lib/oh-story/skills/story-deslop/scripts/normalize-punctuation.js +410 -0
- package/lib/oh-story/skills/story-import/SKILL.md +634 -0
- package/lib/oh-story/skills/story-import/references/character-state-reverse.md +82 -0
- package/lib/oh-story/skills/story-import/references/format-and-structure.md +169 -0
- package/lib/oh-story/skills/story-import/references/length-routing.md +134 -0
- package/lib/oh-story/skills/story-import/references/state-tracking.md +108 -0
- package/lib/oh-story/skills/story-import/references/structure-mapping-long.md +442 -0
- package/lib/oh-story/skills/story-import/references/structure-mapping-short.md +175 -0
- package/lib/oh-story/skills/story-import/references/tracking-transaction.md +161 -0
- package/lib/oh-story/skills/story-import/scripts/tracking_commit.py +1139 -0
- package/lib/oh-story/skills/story-long-analyze/SKILL.md +329 -0
- package/lib/oh-story/skills/story-long-analyze/references/deconstruction-notes.md +270 -0
- package/lib/oh-story/skills/story-long-analyze/references/material-decomposition.md +530 -0
- package/lib/oh-story/skills/story-long-analyze/references/output-templates.md +559 -0
- package/lib/oh-story/skills/story-long-analyze/references/pipeline-ops.md +80 -0
- package/lib/oh-story/skills/story-long-analyze/references/style-profile-generator.md +149 -0
- package/lib/oh-story/skills/story-long-analyze/references/style-profile-protocol.md +133 -0
- package/lib/oh-story/skills/story-long-scan/SKILL.md +342 -0
- package/lib/oh-story/skills/story-long-scan/references/genre-trends.md +197 -0
- package/lib/oh-story/skills/story-long-scan/references/publishing-guide.md +114 -0
- package/lib/oh-story/skills/story-long-scan/references/reader-profiling.md +105 -0
- package/lib/oh-story/skills/story-long-scan/references/scan-output-format.md +207 -0
- package/lib/oh-story/skills/story-long-scan/references/topic-decision.md +78 -0
- package/lib/oh-story/skills/story-long-write/SKILL.md +327 -0
- package/lib/oh-story/skills/story-long-write/references/anti-ai-writing.md +582 -0
- package/lib/oh-story/skills/story-long-write/references/artifact-protocols.md +302 -0
- package/lib/oh-story/skills/story-long-write/references/banned-words.md +147 -0
- package/lib/oh-story/skills/story-long-write/references/character-basics.md +445 -0
- package/lib/oh-story/skills/story-long-write/references/character-design-methods.md +428 -0
- package/lib/oh-story/skills/story-long-write/references/character-relations.md +385 -0
- package/lib/oh-story/skills/story-long-write/references/commercial-core-methods.md +502 -0
- package/lib/oh-story/skills/story-long-write/references/cross-book-recall.md +62 -0
- package/lib/oh-story/skills/story-long-write/references/dialogue-mastery.md +282 -0
- package/lib/oh-story/skills/story-long-write/references/emotional-arc-design.md +426 -0
- package/lib/oh-story/skills/story-long-write/references/emotional-methods.md +209 -0
- package/lib/oh-story/skills/story-long-write/references/female-audience-writing.md +188 -0
- package/lib/oh-story/skills/story-long-write/references/format-and-structure.md +169 -0
- package/lib/oh-story/skills/story-long-write/references/genre-catalog.md +480 -0
- package/lib/oh-story/skills/story-long-write/references/genre-core-mechanics.md +415 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//344/270/234/346/226/271/344/273/231/344/276/240.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//344/274/240/347/273/237/347/216/204/345/271/273.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//345/216/206/345/217/262/345/217/244/344/273/243.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//345/216/206/345/217/262/350/204/221/346/264/236.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//345/217/214/347/224/267/344/270/273.md +53 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//345/217/244/350/250/200/350/204/221/346/264/236.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//345/217/244/351/243/216/344/270/226/346/203/205.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//345/245/263/351/242/221/346/202/254/347/226/221.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//345/245/263/351/242/221/347/247/215/347/224/260.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//345/256/253/346/226/227/345/256/205/346/226/227.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//345/271/264/344/273/243.md +53 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//345/277/253/347/251/277.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//346/202/254/347/226/221/347/201/265/345/274/202.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//346/202/254/347/226/221/350/204/221/346/264/236.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//346/210/230/347/245/236/350/265/230/345/251/277.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//346/212/227/346/210/230/350/260/215/346/210/230.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//346/230/237/345/205/211/347/222/200/347/222/250.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//346/260/221/345/233/275/350/250/200/346/203/205.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//346/270/270/346/210/217/344/275/223/350/202/262.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//347/216/204/345/271/273/350/204/221/346/264/236.md +53 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//347/216/204/345/271/273/350/250/200/346/203/205.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//347/216/260/350/250/200/350/204/221/346/264/236.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//347/247/221/345/271/273/346/234/253/344/270/226.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//350/201/214/345/234/272/345/251/232/346/201/213.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//350/245/277/346/226/271/345/245/207/345/271/273.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//350/261/252/351/227/250/346/200/273/350/243/201.md +53 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//351/203/275/345/270/202/344/277/256/347/234/237.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//351/203/275/345/270/202/346/227/245/345/270/270.md +53 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//351/203/275/345/270/202/347/247/215/347/224/260.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//351/203/275/345/270/202/350/204/221/346/264/236.md +53 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//351/203/275/345/270/202/351/253/230/346/255/246.md +53 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards//351/235/222/346/230/245/347/224/234/345/256/240.md +51 -0
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards.md +91 -0
- package/lib/oh-story/skills/story-long-write/references/genre-readers.md +235 -0
- package/lib/oh-story/skills/story-long-write/references/genre-writing-formulas.md +444 -0
- package/lib/oh-story/skills/story-long-write/references/hooks-chapter.md +225 -0
- package/lib/oh-story/skills/story-long-write/references/hooks-paragraph.md +146 -0
- package/lib/oh-story/skills/story-long-write/references/hooks-suspense.md +352 -0
- package/lib/oh-story/skills/story-long-write/references/opening-design.md +349 -0
- package/lib/oh-story/skills/story-long-write/references/outline-conflict.md +457 -0
- package/lib/oh-story/skills/story-long-write/references/outline-methods.md +287 -0
- package/lib/oh-story/skills/story-long-write/references/outline-rhythm.md +389 -0
- package/lib/oh-story/skills/story-long-write/references/outline-structure-theory.md +326 -0
- package/lib/oh-story/skills/story-long-write/references/plot-core-methods.md +522 -0
- package/lib/oh-story/skills/story-long-write/references/plot-emotion-system.md +354 -0
- package/lib/oh-story/skills/story-long-write/references/plot-frameworks.md +711 -0
- package/lib/oh-story/skills/story-long-write/references/plot-special-topics.md +622 -0
- package/lib/oh-story/skills/story-long-write/references/quality-checklist.md +184 -0
- package/lib/oh-story/skills/story-long-write/references/reader-contract-and-progression.md +109 -0
- package/lib/oh-story/skills/story-long-write/references/reversal-toolkit.md +349 -0
- package/lib/oh-story/skills/story-long-write/references/state-tracking.md +108 -0
- package/lib/oh-story/skills/story-long-write/references/style-combat-face.md +409 -0
- package/lib/oh-story/skills/story-long-write/references/style-craft.md +347 -0
- package/lib/oh-story/skills/story-long-write/references/style-genre-modules.md +510 -0
- package/lib/oh-story/skills/story-long-write/references/tracking-transaction.md +161 -0
- package/lib/oh-story/skills/story-long-write/references/workflow-chapter.md +140 -0
- package/lib/oh-story/skills/story-long-write/references/workflow-daily.md +171 -0
- package/lib/oh-story/skills/story-long-write/references/workflow-revision.md +99 -0
- package/lib/oh-story/skills/story-long-write/references/workflow-setup.md +284 -0
- package/lib/oh-story/skills/story-long-write/references/writing-craft.md +421 -0
- package/lib/oh-story/skills/story-long-write/scripts/check-ai-patterns.js +1371 -0
- package/lib/oh-story/skills/story-long-write/scripts/check-degeneration.js +330 -0
- package/lib/oh-story/skills/story-long-write/scripts/check-outline-copy.js +241 -0
- package/lib/oh-story/skills/story-long-write/scripts/normalize-punctuation.js +410 -0
- package/lib/oh-story/skills/story-long-write/scripts/tracking_commit.py +1139 -0
- package/lib/oh-story/skills/story-review/SKILL.md +483 -0
- package/lib/oh-story/skills/story-review/references/anti-ai-writing.md +582 -0
- package/lib/oh-story/skills/story-review/references/banned-words.md +147 -0
- package/lib/oh-story/skills/story-review/references/character-relations.md +385 -0
- package/lib/oh-story/skills/story-review/references/dialogue-mastery.md +282 -0
- package/lib/oh-story/skills/story-review/references/plot-core-methods.md +522 -0
- package/lib/oh-story/skills/story-review/references/quality-checklist.md +250 -0
- package/lib/oh-story/skills/story-review/references/quality-rubric.md +55 -0
- package/lib/oh-story/skills/story-review/references/rubrics/fanqie.md +18 -0
- package/lib/oh-story/skills/story-review/references/rubrics/qidian.md +19 -0
- package/lib/oh-story/skills/story-review/references/rubrics/zhihu.md +20 -0
- package/lib/oh-story/skills/story-review/references/tracking-transaction.md +161 -0
- package/lib/oh-story/skills/story-review/scripts/check-ai-patterns.js +1371 -0
- package/lib/oh-story/skills/story-review/scripts/check-degeneration.js +330 -0
- package/lib/oh-story/skills/story-review/scripts/normalize-punctuation.js +410 -0
- package/lib/oh-story/skills/story-review/scripts/tracking_commit.py +1139 -0
- package/lib/oh-story/skills/story-setup/SKILL.md +495 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/anti-ai-writing.md +582 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/banned-words.md +147 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/character-basics.md +445 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/character-design-methods.md +428 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/character-relations.md +385 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/dialogue-mastery.md +282 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/emotional-arc-design.md +426 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/emotional-methods.md +179 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/format-and-structure.md +169 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-catalog.md +480 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-core-mechanics.md +415 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//344/270/234/346/226/271/344/273/231/344/276/240.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//344/274/240/347/273/237/347/216/204/345/271/273.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//345/216/206/345/217/262/345/217/244/344/273/243.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//345/216/206/345/217/262/350/204/221/346/264/236.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//345/217/214/347/224/267/344/270/273.md +53 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//345/217/244/350/250/200/350/204/221/346/264/236.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//345/217/244/351/243/216/344/270/226/346/203/205.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//345/245/263/351/242/221/346/202/254/347/226/221.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//345/245/263/351/242/221/347/247/215/347/224/260.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//345/256/253/346/226/227/345/256/205/346/226/227.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//345/271/264/344/273/243.md +53 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//345/277/253/347/251/277.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//346/202/254/347/226/221/347/201/265/345/274/202.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//346/202/254/347/226/221/350/204/221/346/264/236.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//346/210/230/347/245/236/350/265/230/345/251/277.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//346/212/227/346/210/230/350/260/215/346/210/230.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//346/230/237/345/205/211/347/222/200/347/222/250.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//346/260/221/345/233/275/350/250/200/346/203/205.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//346/270/270/346/210/217/344/275/223/350/202/262.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//347/216/204/345/271/273/350/204/221/346/264/236.md +53 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//347/216/204/345/271/273/350/250/200/346/203/205.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//347/216/260/350/250/200/350/204/221/346/264/236.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//347/247/221/345/271/273/346/234/253/344/270/226.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//350/201/214/345/234/272/345/251/232/346/201/213.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//350/245/277/346/226/271/345/245/207/345/271/273.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//350/261/252/351/227/250/346/200/273/350/243/201.md +53 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//351/203/275/345/270/202/344/277/256/347/234/237.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//351/203/275/345/270/202/346/227/245/345/270/270.md +53 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//351/203/275/345/270/202/347/247/215/347/224/260.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//351/203/275/345/270/202/350/204/221/346/264/236.md +53 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//351/203/275/345/270/202/351/253/230/346/255/246.md +53 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards//351/235/222/346/230/245/347/224/234/345/256/240.md +51 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards.md +91 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-readers.md +235 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-writing-formulas.md +444 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/hooks-chapter.md +225 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/hooks-suspense.md +352 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/opening-design.md +349 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/outline-conflict.md +457 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/outline-methods.md +287 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/outline-rhythm.md +389 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/plot-core-methods.md +522 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/quality-checklist.md +247 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/reversal-toolkit.md +349 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/style-combat-face.md +409 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/style-genre-modules.md +510 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/writing-craft.md +421 -0
- package/lib/oh-story/skills/story-short-analyze/SKILL.md +278 -0
- package/lib/oh-story/skills/story-short-analyze/references/anti-ai-writing.md +582 -0
- package/lib/oh-story/skills/story-short-analyze/references/banned-words.md +147 -0
- package/lib/oh-story/skills/story-short-analyze/references/character-basics.md +453 -0
- package/lib/oh-story/skills/story-short-analyze/references/character-design-methods.md +438 -0
- package/lib/oh-story/skills/story-short-analyze/references/character-relations.md +395 -0
- package/lib/oh-story/skills/story-short-analyze/references/deconstruction-examples.md +79 -0
- package/lib/oh-story/skills/story-short-analyze/references/genre-catalog.md +490 -0
- package/lib/oh-story/skills/story-short-analyze/references/genre-core-mechanics.md +425 -0
- package/lib/oh-story/skills/story-short-analyze/references/genre-readers.md +245 -0
- package/lib/oh-story/skills/story-short-analyze/references/genre-writing-formulas.md +453 -0
- package/lib/oh-story/skills/story-short-analyze/references/genre-writing-techniques.md +475 -0
- package/lib/oh-story/skills/story-short-analyze/references/hooks-chapter.md +225 -0
- package/lib/oh-story/skills/story-short-analyze/references/hooks-paragraph.md +146 -0
- package/lib/oh-story/skills/story-short-analyze/references/hooks-suspense.md +352 -0
- package/lib/oh-story/skills/story-short-analyze/references/material-decomposition.md +685 -0
- package/lib/oh-story/skills/story-short-analyze/references/output-contract.md +165 -0
- package/lib/oh-story/skills/story-short-analyze/references/output-templates.md +561 -0
- package/lib/oh-story/skills/story-short-analyze/references/quality-checklist.md +242 -0
- package/lib/oh-story/skills/story-short-analyze/references/real-market-data.md +90 -0
- package/lib/oh-story/skills/story-short-analyze/references/zhihu-style.md +54 -0
- package/lib/oh-story/skills/story-short-scan/SKILL.md +212 -0
- package/lib/oh-story/skills/story-short-scan/references/real-market-data.md +90 -0
- package/lib/oh-story/skills/story-short-write/SKILL.md +433 -0
- package/lib/oh-story/skills/story-short-write/references/banned-words.md +147 -0
- package/lib/oh-story/skills/story-short-write/references/cross-book-recall.md +62 -0
- package/lib/oh-story/skills/story-short-write/references/dialogue-mastery.md +282 -0
- package/lib/oh-story/skills/story-short-write/references/emotional-methods.md +179 -0
- package/lib/oh-story/skills/story-short-write/references/genre-styles//344/270/226/346/203/205/346/211/223/350/204/270.md +159 -0
- package/lib/oh-story/skills/story-short-write/references/genre-styles//345/217/214/347/224/267/344/270/273.md +156 -0
- package/lib/oh-story/skills/story-short-write/references/genre-styles//345/244/215/344/273/207/346/211/223/350/204/270.md +163 -0
- package/lib/oh-story/skills/story-short-write/references/genre-styles//345/256/205/346/226/227/345/256/253/346/226/227.md +167 -0
- package/lib/oh-story/skills/story-short-write/references/genre-styles//346/200/273/350/243/201/350/261/252/351/227/250.md +178 -0
- package/lib/oh-story/skills/story-short-write/references/genre-styles//346/202/254/347/226/221.md +166 -0
- package/lib/oh-story/skills/story-short-write/references/genre-styles//346/260/221/344/277/227/346/200/252/350/260/210.md +159 -0
- package/lib/oh-story/skills/story-short-write/references/genre-styles//346/262/231/351/233/225/350/204/221/346/264/236.md +151 -0
- package/lib/oh-story/skills/story-short-write/references/genre-styles//347/224/234/345/256/240.md +153 -0
- package/lib/oh-story/skills/story-short-write/references/genre-styles//350/277/275/345/246/273/347/201/253/350/221/254/345/234/272.md +210 -0
- package/lib/oh-story/skills/story-short-write/references/genre-writing-formulas.md +444 -0
- package/lib/oh-story/skills/story-short-write/references/genre-writing-techniques.md +488 -0
- package/lib/oh-story/skills/story-short-write/references/hooks-chapter.md +225 -0
- package/lib/oh-story/skills/story-short-write/references/hooks-paragraph.md +146 -0
- package/lib/oh-story/skills/story-short-write/references/hooks-suspense.md +352 -0
- package/lib/oh-story/skills/story-short-write/references/output-contract.md +165 -0
- package/lib/oh-story/skills/story-short-write/references/quality-checklist.md +222 -0
- package/lib/oh-story/skills/story-short-write/references/reversal-toolkit.md +349 -0
- package/lib/oh-story/skills/story-short-write/references/short-craft.md +185 -0
- package/lib/oh-story/skills/story-short-write/references/short-deslop.md +133 -0
- package/lib/oh-story/skills/story-short-write/references/short-format.md +167 -0
- package/lib/oh-story/skills/story-short-write/references/submission-craft.md +35 -0
- package/lib/oh-story/skills/story-short-write/references/villain-and-reveal.md +158 -0
- package/lib/oh-story/skills/story-short-write/references/writing-workflow.md +153 -0
- package/lib/oh-story/skills/story-short-write/scripts/check-ai-patterns.js +1371 -0
- package/lib/oh-story/skills/story-short-write/scripts/check-degeneration.js +330 -0
- package/lib/oh-story/skills/story-short-write/scripts/check-outline-copy.js +241 -0
- package/lib/oh-story/skills/story-short-write/scripts/normalize-punctuation.js +410 -0
- package/lib/types/client/file-activity.d.ts +30 -0
- package/lib/types/client/file-activity.d.ts.map +1 -0
- package/lib/types/client/file-tree.d.ts +20 -0
- package/lib/types/client/file-tree.d.ts.map +1 -0
- package/lib/types/client/index.d.ts +12 -0
- package/lib/types/client/index.d.ts.map +1 -0
- package/lib/types/client/jsonl-preview.d.ts +15 -0
- package/lib/types/client/jsonl-preview.d.ts.map +1 -0
- package/lib/types/client/markdown-preview.d.ts +38 -0
- package/lib/types/client/markdown-preview.d.ts.map +1 -0
- package/lib/types/index.d.ts +25 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/native-hooks.d.ts +16 -0
- package/lib/types/native-hooks.d.ts.map +1 -0
- package/lib/types/role-provider.d.ts +6 -0
- package/lib/types/role-provider.d.ts.map +1 -0
- package/lib/types/role-tool.d.ts +10 -0
- package/lib/types/role-tool.d.ts.map +1 -0
- package/lib/types/skill-provider.d.ts +15 -0
- package/lib/types/skill-provider.d.ts.map +1 -0
- package/lib/types/workspace-request-trust.d.ts +13 -0
- package/lib/types/workspace-request-trust.d.ts.map +1 -0
- package/lib/types/workspace-route.d.ts +10 -0
- package/lib/types/workspace-route.d.ts.map +1 -0
- package/lib/types/workspace-security.d.ts +9 -0
- package/lib/types/workspace-security.d.ts.map +1 -0
- package/package.json +107 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Check explicit motion segment timing against accepted shot duration (`VID-04`).
|
|
3
|
+
|
|
4
|
+
`VID-04` is arithmetic, and it is violated in two directions that fail
|
|
5
|
+
differently:
|
|
6
|
+
|
|
7
|
+
* **Overflow** — segments extend past the accepted duration. Whatever falls
|
|
8
|
+
outside is truncated, taking the closing action, the verbatim dialogue tail
|
|
9
|
+
and the end pose with it.
|
|
10
|
+
* **Shortfall** — segments stop short. The unallocated remainder does not
|
|
11
|
+
render as a held frame; the execution end fills it with motion, expression or
|
|
12
|
+
camera movement that has no upstream source at all.
|
|
13
|
+
|
|
14
|
+
Both are the same rule, so both are reported under the same ID with distinct
|
|
15
|
+
diagnostic codes. Relative timing plans are out of scope by contract: only a
|
|
16
|
+
plan that declares itself `explicit` makes a checkable arithmetic claim.
|
|
17
|
+
|
|
18
|
+
The script reads accepted creator files and writes nothing.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import argparse
|
|
24
|
+
import json
|
|
25
|
+
import math
|
|
26
|
+
import re
|
|
27
|
+
import sys
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
from typing import Any
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# Creators run these scripts on whatever interpreter their machine provides, so
|
|
33
|
+
# an unsupported version must say so instead of failing inside an import.
|
|
34
|
+
MINIMUM_PYTHON = (3, 9)
|
|
35
|
+
if sys.version_info < MINIMUM_PYTHON:
|
|
36
|
+
raise SystemExit(
|
|
37
|
+
"short-drama needs Python {}.{} or newer; this interpreter is {}.{}".format(
|
|
38
|
+
*MINIMUM_PYTHON, sys.version_info.major, sys.version_info.minor
|
|
39
|
+
)
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
SCHEMA_VERSION = "1.0.0"
|
|
43
|
+
# A .jsonl file opens with a header record declaring the upstream snapshots its
|
|
44
|
+
# references name. The header is a declaration, not one of the file's records.
|
|
45
|
+
SOURCES_RECORD_TYPE = "sources"
|
|
46
|
+
# Seconds are authored by hand, so compare with a tolerance rather than by
|
|
47
|
+
# equality: 0.1 + 0.2 != 0.3 in binary floating point, and a rule that fires on
|
|
48
|
+
# that would be noise. A millisecond is far below anything a shot can express.
|
|
49
|
+
TOLERANCE_SECONDS = 1e-6
|
|
50
|
+
# An interval reads `0.0-1.5`. Accept the en dash and the CJK wave dash too:
|
|
51
|
+
# creators type these on Chinese input methods and the distinction carries no
|
|
52
|
+
# meaning here.
|
|
53
|
+
INTERVAL_RE = re.compile(
|
|
54
|
+
r"^\s*(?P<start>\d+(?:\.\d+)?)\s*[-–—~~]\s*(?P<end>\d+(?:\.\d+)?)\s*(?:s|秒)?\s*$"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class CheckError(ValueError):
|
|
59
|
+
"""The inputs cannot be checked at all, as opposed to failing a check."""
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _reject_json_constant(value: str) -> None:
|
|
63
|
+
raise CheckError(f"non-finite JSON number is not allowed: {value}")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _finite_number(value: Any) -> float | None:
|
|
67
|
+
if isinstance(value, bool) or not isinstance(value, (int, float)):
|
|
68
|
+
return None
|
|
69
|
+
number = float(value)
|
|
70
|
+
return number if math.isfinite(number) else None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _load_jsonl(path: Path) -> list[dict[str, Any]]:
|
|
74
|
+
records: list[dict[str, Any]] = []
|
|
75
|
+
try:
|
|
76
|
+
text = path.read_text(encoding="utf-8")
|
|
77
|
+
except OSError as error:
|
|
78
|
+
raise CheckError(f"cannot read {path}: {error}") from error
|
|
79
|
+
for number, line in enumerate(text.splitlines(), start=1):
|
|
80
|
+
stripped = line.strip()
|
|
81
|
+
if not stripped or stripped.startswith("#"):
|
|
82
|
+
continue
|
|
83
|
+
try:
|
|
84
|
+
record = json.loads(stripped, parse_constant=_reject_json_constant)
|
|
85
|
+
except json.JSONDecodeError as error:
|
|
86
|
+
raise CheckError(f"{path.name} line {number} is not valid JSON: {error}") from error
|
|
87
|
+
if not isinstance(record, dict):
|
|
88
|
+
raise CheckError(f"{path.name} line {number} is not a JSON object")
|
|
89
|
+
records.append(record)
|
|
90
|
+
if records and records[0].get("record_type") == SOURCES_RECORD_TYPE:
|
|
91
|
+
del records[0]
|
|
92
|
+
return records
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _finding(code: str, motion_id: str, message: str, **extra: Any) -> dict[str, Any]:
|
|
96
|
+
return {
|
|
97
|
+
"code": code,
|
|
98
|
+
"rule": "VID-04",
|
|
99
|
+
"severity": "error",
|
|
100
|
+
"motion_id": motion_id,
|
|
101
|
+
"message": message,
|
|
102
|
+
**extra,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _parse_interval(value: Any) -> tuple[float, float] | None:
|
|
107
|
+
"""Return an explicit ``(start, end)`` window, or None when unparseable."""
|
|
108
|
+
|
|
109
|
+
if isinstance(value, dict):
|
|
110
|
+
start = _finite_number(value.get("start_seconds"))
|
|
111
|
+
end = _finite_number(value.get("end_seconds"))
|
|
112
|
+
if start is not None and end is not None:
|
|
113
|
+
return start, end
|
|
114
|
+
return None
|
|
115
|
+
if isinstance(value, str):
|
|
116
|
+
match = INTERVAL_RE.match(value)
|
|
117
|
+
if match:
|
|
118
|
+
return float(match.group("start")), float(match.group("end"))
|
|
119
|
+
return None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _union_length(windows: list[tuple[float, float]]) -> float:
|
|
123
|
+
"""Total time occupied by ``windows``, counting overlap once."""
|
|
124
|
+
|
|
125
|
+
total = 0.0
|
|
126
|
+
cursor: float | None = None
|
|
127
|
+
span_end = 0.0
|
|
128
|
+
for start, end in sorted(windows):
|
|
129
|
+
if cursor is None or start > span_end:
|
|
130
|
+
if cursor is not None:
|
|
131
|
+
total += span_end - cursor
|
|
132
|
+
cursor, span_end = start, end
|
|
133
|
+
else:
|
|
134
|
+
span_end = max(span_end, end)
|
|
135
|
+
if cursor is not None:
|
|
136
|
+
total += span_end - cursor
|
|
137
|
+
return total
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _accepted_duration(
|
|
141
|
+
spec: dict[str, Any], shots_by_id: dict[str, dict[str, Any]]
|
|
142
|
+
) -> tuple[float | None, str | None]:
|
|
143
|
+
"""Resolve the accepted shot duration and any conflict with the projection.
|
|
144
|
+
|
|
145
|
+
``boundary_refs.duration.value_seconds`` is a read-only projection of the
|
|
146
|
+
shot record. When both are present and disagree, the projection is stale and
|
|
147
|
+
the arithmetic below would be checked against a number the storyboard never
|
|
148
|
+
accepted, so that is reported instead of silently preferring one.
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
boundary = spec.get("boundary_refs")
|
|
152
|
+
duration_ref = boundary.get("duration") if isinstance(boundary, dict) else None
|
|
153
|
+
projected: float | None = None
|
|
154
|
+
record_id: str | None = None
|
|
155
|
+
if isinstance(duration_ref, dict):
|
|
156
|
+
projected = _finite_number(duration_ref.get("value_seconds"))
|
|
157
|
+
if isinstance(duration_ref.get("record_id"), str):
|
|
158
|
+
record_id = duration_ref["record_id"]
|
|
159
|
+
|
|
160
|
+
shot_ref = spec.get("shot_ref")
|
|
161
|
+
if record_id is None and isinstance(shot_ref, dict):
|
|
162
|
+
if isinstance(shot_ref.get("record_id"), str):
|
|
163
|
+
record_id = shot_ref["record_id"]
|
|
164
|
+
|
|
165
|
+
authoritative: float | None = None
|
|
166
|
+
if record_id is not None:
|
|
167
|
+
shot = shots_by_id.get(record_id)
|
|
168
|
+
if isinstance(shot, dict):
|
|
169
|
+
authoritative = _finite_number(shot.get("duration_seconds"))
|
|
170
|
+
elif projected is not None:
|
|
171
|
+
# A reference naming no shot used to fall through to
|
|
172
|
+
# `resolved = projected`, so the arithmetic was then checked against
|
|
173
|
+
# the spec's own self-declared number and the staleness guard never
|
|
174
|
+
# ran -- one mistyped character switched off VID-04. Only reported
|
|
175
|
+
# when a projection exists: with neither a shot nor a projection
|
|
176
|
+
# there is nothing to be wrong about, and `unmeasured` stays the
|
|
177
|
+
# honest answer.
|
|
178
|
+
return None, (
|
|
179
|
+
f"duration reference {record_id} resolves to no shot, so the "
|
|
180
|
+
f"projected {projected}s is checked against nothing"
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
if projected is not None and authoritative is not None:
|
|
184
|
+
if abs(projected - authoritative) > TOLERANCE_SECONDS:
|
|
185
|
+
return None, (
|
|
186
|
+
f"projected duration {projected}s does not match accepted "
|
|
187
|
+
f"{record_id} duration {authoritative}s"
|
|
188
|
+
)
|
|
189
|
+
return authoritative, None
|
|
190
|
+
resolved = authoritative if authoritative is not None else projected
|
|
191
|
+
return resolved, None
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def check(
|
|
195
|
+
specs: list[dict[str, Any]], shots: list[dict[str, Any]]
|
|
196
|
+
) -> dict[str, Any]:
|
|
197
|
+
shots_by_id = {
|
|
198
|
+
shot["shot_id"]: shot
|
|
199
|
+
for shot in shots
|
|
200
|
+
if isinstance(shot.get("shot_id"), str)
|
|
201
|
+
}
|
|
202
|
+
findings: list[dict[str, Any]] = []
|
|
203
|
+
checked = 0
|
|
204
|
+
# Reported, not a finding: a relative plan makes no arithmetic claim, so it
|
|
205
|
+
# is out of scope rather than passing. Keeping the count visible stops a
|
|
206
|
+
# file of entirely relative plans from reading as a clean explicit check.
|
|
207
|
+
relative: list[str] = []
|
|
208
|
+
unmeasured: list[str] = []
|
|
209
|
+
|
|
210
|
+
for index, spec in enumerate(specs):
|
|
211
|
+
motion_id = spec.get("motion_id")
|
|
212
|
+
if not isinstance(motion_id, str) or not motion_id:
|
|
213
|
+
raise CheckError(f"motion spec {index} has no motion_id")
|
|
214
|
+
|
|
215
|
+
plan = spec.get("timing_plan")
|
|
216
|
+
mode = plan.get("mode") if isinstance(plan, dict) else None
|
|
217
|
+
segments = [
|
|
218
|
+
entry.get("timing")
|
|
219
|
+
for entry in spec.get("ordered_subject_motion") or []
|
|
220
|
+
if isinstance(entry, dict)
|
|
221
|
+
]
|
|
222
|
+
explicit_segments = [
|
|
223
|
+
timing
|
|
224
|
+
for timing in segments
|
|
225
|
+
if isinstance(timing, dict) and timing.get("mode") == "explicit"
|
|
226
|
+
]
|
|
227
|
+
# Whether the projection matches the shot is a fact about the data, not
|
|
228
|
+
# about the timing mode, so it is checked before the mode gate below.
|
|
229
|
+
# Gated behind `explicit` it never ran on a file of relative plans --
|
|
230
|
+
# which is every spec in the recorded run -- and a projection authored
|
|
231
|
+
# wrong from the start was carried downstream unchallenged.
|
|
232
|
+
duration, conflict = _accepted_duration(spec, shots_by_id)
|
|
233
|
+
if conflict is not None:
|
|
234
|
+
findings.append(_finding("VID_DURATION_PROJECTION_STALE", motion_id, conflict))
|
|
235
|
+
continue
|
|
236
|
+
|
|
237
|
+
if mode != "explicit":
|
|
238
|
+
# A relative plan makes no arithmetic claim, so it is out of scope
|
|
239
|
+
# by contract rather than passing. Explicit segments underneath one
|
|
240
|
+
# are a contradiction the creator has to resolve — silently doing
|
|
241
|
+
# the arithmetic anyway would judge a plan the docs promise not to.
|
|
242
|
+
if explicit_segments:
|
|
243
|
+
findings.append(
|
|
244
|
+
_finding(
|
|
245
|
+
"VID_TIMING_MODE_INCONSISTENT",
|
|
246
|
+
motion_id,
|
|
247
|
+
f"timing_plan mode is {mode!r} but "
|
|
248
|
+
f"{len(explicit_segments)} segment(s) declare explicit timing",
|
|
249
|
+
)
|
|
250
|
+
)
|
|
251
|
+
else:
|
|
252
|
+
relative.append(motion_id)
|
|
253
|
+
continue
|
|
254
|
+
|
|
255
|
+
if duration is None:
|
|
256
|
+
# Cannot be judged either way, and staying silent here is the
|
|
257
|
+
# failure mode this script exists to remove.
|
|
258
|
+
unmeasured.append(motion_id)
|
|
259
|
+
continue
|
|
260
|
+
|
|
261
|
+
windows: list[tuple[float, float]] = []
|
|
262
|
+
unparseable: list[Any] = []
|
|
263
|
+
for timing in explicit_segments:
|
|
264
|
+
interval = _parse_interval(timing.get("value"))
|
|
265
|
+
if interval is None:
|
|
266
|
+
unparseable.append(timing.get("value"))
|
|
267
|
+
else:
|
|
268
|
+
windows.append(interval)
|
|
269
|
+
if unparseable:
|
|
270
|
+
findings.append(
|
|
271
|
+
_finding(
|
|
272
|
+
"VID_EXPLICIT_TIMING_UNPARSEABLE",
|
|
273
|
+
motion_id,
|
|
274
|
+
"explicit segment timing is not a readable seconds interval",
|
|
275
|
+
values=unparseable,
|
|
276
|
+
)
|
|
277
|
+
)
|
|
278
|
+
continue
|
|
279
|
+
if not windows:
|
|
280
|
+
findings.append(
|
|
281
|
+
_finding(
|
|
282
|
+
"VID_EXPLICIT_TIMING_UNPARSEABLE",
|
|
283
|
+
motion_id,
|
|
284
|
+
"timing_plan declares explicit mode but no segment carries an interval",
|
|
285
|
+
)
|
|
286
|
+
)
|
|
287
|
+
continue
|
|
288
|
+
|
|
289
|
+
inverted = [
|
|
290
|
+
f"{start}-{end}"
|
|
291
|
+
for start, end in windows
|
|
292
|
+
if start < 0 or end < 0 or end < start
|
|
293
|
+
]
|
|
294
|
+
if inverted:
|
|
295
|
+
findings.append(
|
|
296
|
+
_finding(
|
|
297
|
+
"VID_EXPLICIT_TIMING_UNPARSEABLE",
|
|
298
|
+
motion_id,
|
|
299
|
+
"explicit segment ends before it starts",
|
|
300
|
+
values=inverted,
|
|
301
|
+
)
|
|
302
|
+
)
|
|
303
|
+
continue
|
|
304
|
+
|
|
305
|
+
checked += 1
|
|
306
|
+
ordered = sorted(windows)
|
|
307
|
+
declared_overlap = bool(
|
|
308
|
+
isinstance(plan, dict) and plan.get("declares_overlap") is True
|
|
309
|
+
)
|
|
310
|
+
overlaps = [
|
|
311
|
+
f"{ordered[position - 1][0]}-{ordered[position - 1][1]} / {start}-{end}"
|
|
312
|
+
for position, (start, end) in enumerate(ordered)
|
|
313
|
+
if position and start < ordered[position - 1][1] - TOLERANCE_SECONDS
|
|
314
|
+
]
|
|
315
|
+
if overlaps and not declared_overlap:
|
|
316
|
+
findings.append(
|
|
317
|
+
_finding(
|
|
318
|
+
"VID_EXPLICIT_TIMING_UNDECLARED_OVERLAP",
|
|
319
|
+
motion_id,
|
|
320
|
+
"segments overlap without an explicit overlap declaration",
|
|
321
|
+
values=overlaps,
|
|
322
|
+
)
|
|
323
|
+
)
|
|
324
|
+
continue
|
|
325
|
+
|
|
326
|
+
# The two failure directions are measured from different quantities on
|
|
327
|
+
# purpose. Comparing one total against the duration hides the plan that
|
|
328
|
+
# commits both at once: 0.0-2.0 plus 3.0-5.0 covers exactly 4.0s of a
|
|
329
|
+
# 4.0s shot, so the totals match — while a segment runs a second past
|
|
330
|
+
# the end (truncated) and the 2-3s window sits unallocated (filled with
|
|
331
|
+
# unsourced motion). Overflow is therefore read off the endpoint, and
|
|
332
|
+
# shortfall off the union clipped to the shot.
|
|
333
|
+
covered = _union_length(ordered)
|
|
334
|
+
# max(), not ordered[-1][1]: sorting (start, end) tuples orders by
|
|
335
|
+
# start, so the last element is the latest-starting segment, whose end
|
|
336
|
+
# can sit well inside an earlier segment that encloses it. A sustained
|
|
337
|
+
# motion spanning the shot with beats inside it — exactly what
|
|
338
|
+
# motion-recipe.md tells creators to mark `declares_overlap` — would
|
|
339
|
+
# otherwise have its overrun read off one of the inner beats.
|
|
340
|
+
last_end = max((end for _, end in ordered), default=0.0)
|
|
341
|
+
inside = _union_length(
|
|
342
|
+
[
|
|
343
|
+
(max(start, 0.0), min(end, duration))
|
|
344
|
+
for start, end in ordered
|
|
345
|
+
if min(end, duration) > max(start, 0.0)
|
|
346
|
+
]
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
if last_end - duration > TOLERANCE_SECONDS:
|
|
350
|
+
findings.append(
|
|
351
|
+
_finding(
|
|
352
|
+
"VID_EXPLICIT_TIMING_OVERFLOW",
|
|
353
|
+
motion_id,
|
|
354
|
+
f"explicit timing runs to {last_end}s on an accepted {duration}s shot; "
|
|
355
|
+
"everything past the end is truncated",
|
|
356
|
+
accepted_duration_seconds=duration,
|
|
357
|
+
endpoint_seconds=round(last_end, 6),
|
|
358
|
+
overflow_seconds=round(last_end - duration, 6),
|
|
359
|
+
)
|
|
360
|
+
)
|
|
361
|
+
unallocated = duration - inside
|
|
362
|
+
if unallocated > TOLERANCE_SECONDS:
|
|
363
|
+
findings.append(
|
|
364
|
+
_finding(
|
|
365
|
+
"VID_EXPLICIT_TIMING_SHORTFALL",
|
|
366
|
+
motion_id,
|
|
367
|
+
f"explicit timing leaves {round(unallocated, 6)}s of an accepted "
|
|
368
|
+
f"{duration}s shot unallocated; the remainder will be filled with "
|
|
369
|
+
"unsourced motion",
|
|
370
|
+
accepted_duration_seconds=duration,
|
|
371
|
+
allocated_seconds=round(inside, 6),
|
|
372
|
+
unallocated_seconds=round(unallocated, 6),
|
|
373
|
+
)
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
declared_total = (
|
|
377
|
+
plan.get("declared_total_or_endpoint_seconds") if isinstance(plan, dict) else None
|
|
378
|
+
)
|
|
379
|
+
# The field is named `declared_total_or_endpoint_seconds`, so both
|
|
380
|
+
# readings are legitimate and they differ whenever overlap is declared.
|
|
381
|
+
# Matching either is a pass; insisting on one would make a correct plan
|
|
382
|
+
# fail under the other spelling.
|
|
383
|
+
declared_number = _finite_number(declared_total)
|
|
384
|
+
if declared_total is not None and declared_number is None:
|
|
385
|
+
findings.append(
|
|
386
|
+
_finding(
|
|
387
|
+
"VID_DECLARED_TOTAL_MISMATCH",
|
|
388
|
+
motion_id,
|
|
389
|
+
"timing_plan declared total must be a finite non-negative number",
|
|
390
|
+
)
|
|
391
|
+
)
|
|
392
|
+
elif declared_number is not None and declared_number < 0:
|
|
393
|
+
findings.append(
|
|
394
|
+
_finding(
|
|
395
|
+
"VID_DECLARED_TOTAL_MISMATCH",
|
|
396
|
+
motion_id,
|
|
397
|
+
"timing_plan declared total must be a finite non-negative number",
|
|
398
|
+
declared_seconds=declared_number,
|
|
399
|
+
)
|
|
400
|
+
)
|
|
401
|
+
elif declared_number is not None and not any(
|
|
402
|
+
abs(declared_number - candidate) <= TOLERANCE_SECONDS
|
|
403
|
+
for candidate in (covered, last_end)
|
|
404
|
+
):
|
|
405
|
+
findings.append(
|
|
406
|
+
_finding(
|
|
407
|
+
"VID_DECLARED_TOTAL_MISMATCH",
|
|
408
|
+
motion_id,
|
|
409
|
+
f"timing_plan declares {declared_total}s, which is neither the "
|
|
410
|
+
f"{round(covered, 6)}s its segments occupy nor their "
|
|
411
|
+
f"{round(last_end, 6)}s endpoint",
|
|
412
|
+
declared_seconds=declared_number,
|
|
413
|
+
covered_seconds=round(covered, 6),
|
|
414
|
+
endpoint_seconds=round(last_end, 6),
|
|
415
|
+
)
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
return {
|
|
419
|
+
"schema_version": SCHEMA_VERSION,
|
|
420
|
+
"motion_specs": len(specs),
|
|
421
|
+
"explicit_checked": checked,
|
|
422
|
+
"relative_plans": relative,
|
|
423
|
+
"unmeasured_specs": unmeasured,
|
|
424
|
+
"findings": findings,
|
|
425
|
+
"status": "pass" if not findings else "fail",
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
430
|
+
parser = argparse.ArgumentParser(
|
|
431
|
+
description="Check explicit motion timing against accepted shot duration (VID-04)."
|
|
432
|
+
)
|
|
433
|
+
parser.add_argument("motion_specs", type=Path, help="the episode motion specs JSONL")
|
|
434
|
+
parser.add_argument("--shots", type=Path, required=True)
|
|
435
|
+
return parser
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def main(argv: list[str] | None = None) -> int:
|
|
439
|
+
args = build_parser().parse_args(argv)
|
|
440
|
+
try:
|
|
441
|
+
result = check(_load_jsonl(args.motion_specs), _load_jsonl(args.shots))
|
|
442
|
+
except CheckError as error:
|
|
443
|
+
print(f"{type(error).__name__}: {error}", file=sys.stderr)
|
|
444
|
+
return 2
|
|
445
|
+
print(json.dumps(result, ensure_ascii=True, sort_keys=True, allow_nan=False))
|
|
446
|
+
return 0 if result["status"] == "pass" else 1
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
if __name__ == "__main__":
|
|
450
|
+
raise SystemExit(main())
|