@oh-story/dsh 0.1.7 → 0.1.9
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 +30 -15
- package/lib/client.js +93 -16
- package/lib/client.js.map +2 -2
- package/lib/drama/manifest.json +165 -69
- package/lib/drama/skills/short-drama/SKILL.md +5 -1
- package/lib/drama/skills/short-drama/scripts/creator_markdown_check.py +126 -9
- package/lib/drama/skills/short-drama/scripts/project_tool.py +11 -0
- package/lib/drama/skills/short-drama-assets/references/character-and-look.md +18 -0
- package/lib/drama/skills/short-drama-assets/references/continuity-lock.md +10 -1
- package/lib/drama/skills/short-drama-edit/SKILL.md +148 -0
- package/lib/drama/skills/short-drama-edit/agents/openai.yaml +4 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/README.md +60 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/package.json +15 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/remotion.config.ts +6 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/Root.tsx +26 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/Subtitles.tsx +88 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/font.ts +46 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/index.ts +4 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/schema.ts +32 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/tsconfig.json +13 -0
- package/lib/drama/skills/short-drama-edit/assets//345/211/252/350/276/221/345/215/225.md +43 -0
- package/lib/drama/skills/short-drama-edit/references/cut-craft.md +81 -0
- package/lib/drama/skills/short-drama-edit/references/delivery-verify.md +58 -0
- package/lib/drama/skills/short-drama-edit/references/generated-footage.md +96 -0
- package/lib/drama/skills/short-drama-edit/references/sound-and-subtitles.md +113 -0
- package/lib/drama/skills/short-drama-edit/references/stage-contract.md +55 -0
- package/lib/drama/skills/short-drama-edit/scripts/edit_tool.py +1041 -0
- package/lib/drama/skills/short-drama-edit/scripts/selftest.py +456 -0
- package/lib/drama/skills/short-drama-image-prompts/assets/image-prompts.md +5 -0
- package/lib/drama/skills/short-drama-image-prompts/assets/lookdev-prompts.md +3 -0
- package/lib/drama/skills/short-drama-novel-analyze/references/aggregation-and-entities.md +2 -2
- package/lib/drama/skills/short-drama-novel-analyze/references/chapter-extraction.md +4 -1
- package/lib/drama/skills/short-drama-produce/SKILL.md +24 -3
- package/lib/drama/skills/short-drama-produce/references/adapter-contract.md +28 -0
- package/lib/drama/skills/short-drama-produce/references/providers/minimax-h3-video.md +24 -5
- package/lib/drama/skills/short-drama-produce/references/providers/seedance.md +7 -0
- package/lib/drama/skills/short-drama-produce/scripts/fixture_adapter.py +18 -1
- package/lib/drama/skills/short-drama-produce/scripts/production_tool.py +181 -2
- package/lib/drama/skills/short-drama-produce/scripts/provider_adapters.py +57 -2
- package/lib/drama/skills/short-drama-review/SKILL.md +3 -0
- package/lib/drama/skills/short-drama-review/references/production-quality-gates.md +20 -0
- package/lib/drama/skills/short-drama-review/references/rubric-visual-motion.md +36 -0
- package/lib/drama/skills/short-drama-storyboard/SKILL.md +7 -0
- package/lib/drama/skills/short-drama-storyboard/assets/keyframe-prompts.md +4 -0
- package/lib/drama/skills/short-drama-storyboard/references/shot-craft.md +39 -0
- package/lib/drama/skills/short-drama-storyboard/references/stage-contract.md +2 -0
- package/lib/drama/skills/short-drama-video-prompts/SKILL.md +7 -1
- package/lib/drama/skills/short-drama-video-prompts/references/minimax-h3.md +101 -6
- package/lib/drama/skills/short-drama-video-prompts/references/motion-recipe.md +7 -1
- package/lib/drama/skills/short-drama-video-prompts/references/performance-action-timing.md +35 -0
- package/lib/drama/skills/short-drama-video-prompts/references/production-prompt-grammar.md +3 -1
- package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.0.md +13 -3
- package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.5.md +35 -4
- package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +1 -1
- package/lib/drama/skills/short-drama-write/SKILL.md +13 -2
- package/lib/drama/skills/short-drama-write/references/screenplay-format.md +6 -0
- package/lib/drama/skills/short-drama-write/references/stage-contract.md +1 -0
- package/lib/index.js +4 -2
- package/lib/index.js.map +2 -2
- package/lib/novel-to-game/VERSION +1 -1
- package/lib/novel-to-game/manifest.json +28 -28
- package/lib/novel-to-game/skills/game-art-direction/SKILL.md +6 -27
- package/lib/novel-to-game/skills/game-build/SKILL.md +12 -29
- package/lib/novel-to-game/skills/game-concept/SKILL.md +10 -26
- package/lib/novel-to-game/skills/game-qa/SKILL.md +5 -15
- package/lib/novel-to-game/skills/game-qa/references/test-design-method.md +1 -1
- package/lib/novel-to-game/skills/game-world-design/SKILL.md +19 -28
- package/lib/novel-to-game/skills/game-world-design/references/dialogue-design-method.md +1 -2
- package/lib/novel-to-game/skills/novel-game-analyze/SKILL.md +6 -9
- package/lib/novel-to-game/skills/novel-to-game/SKILL.md +6 -11
- package/lib/novel-to-game/skills/novel-to-game/references/intake-benchmark-reference.md +0 -4
- package/lib/novel-to-game/skills/novel-to-game/references/intake-method.md +1 -3
- package/lib/novel-to-game/skills/novel-to-game/references/pipeline-contract.md +3 -5
- package/lib/oh-story/manifest.json +292 -172
- package/lib/oh-story/roles/character-designer.md +1 -1
- package/lib/oh-story/roles/narrative-writer.md +56 -242
- package/lib/oh-story/roles/story-architect.md +1 -1
- package/lib/oh-story/skills/story/SKILL.md +1 -1
- package/lib/oh-story/skills/story/VERSION +1 -1
- package/lib/oh-story/skills/story/references/author-memory.md +10 -8
- package/lib/oh-story/skills/story-deslop/SKILL.md +20 -182
- package/lib/oh-story/skills/story-deslop/references/anti-ai-writing.md +19 -47
- package/lib/oh-story/skills/story-deslop/references/author-memory.md +10 -8
- package/lib/oh-story/skills/story-deslop/references/banned-words.md +3 -1
- package/lib/oh-story/skills/story-deslop/references/deslop-gates.md +154 -0
- package/lib/oh-story/skills/story-deslop/references/style-resolution.md +27 -0
- package/lib/oh-story/skills/story-deslop/scripts/check-ai-patterns.js +6 -1
- package/lib/oh-story/skills/story-deslop/scripts/check-degeneration.js +39 -20
- package/lib/oh-story/skills/story-deslop/scripts/normalize-punctuation.js +10 -5
- package/lib/oh-story/skills/story-deslop/scripts/style-whitelist.js +39 -0
- package/lib/oh-story/skills/story-import/SKILL.md +2 -2
- package/lib/oh-story/skills/story-import/references/format-and-structure.md +2 -2
- package/lib/oh-story/skills/story-import/references/tracking-initialization.md +31 -0
- package/lib/oh-story/skills/story-import/references/tracking-transaction.md +2 -29
- package/lib/oh-story/skills/story-import/scripts/check-outline-contract.js +176 -12
- package/lib/oh-story/skills/story-long-analyze/SKILL.md +1 -1
- package/lib/oh-story/skills/story-long-write/SKILL.md +20 -193
- package/lib/oh-story/skills/story-long-write/references/anti-ai-writing.md +19 -47
- package/lib/oh-story/skills/story-long-write/references/artifact-protocols.md +62 -7
- package/lib/oh-story/skills/story-long-write/references/author-memory.md +10 -8
- package/lib/oh-story/skills/story-long-write/references/banned-words.md +3 -1
- package/lib/oh-story/skills/story-long-write/references/benchmark-recall.md +20 -0
- package/lib/oh-story/skills/story-long-write/references/dialogue-mastery.md +6 -4
- package/lib/oh-story/skills/story-long-write/references/long-chapter-quality.md +2 -2
- package/lib/oh-story/skills/story-long-write/references/long-format.md +2 -0
- package/lib/oh-story/skills/story-long-write/references/outline-structure-theory.md +2 -0
- package/lib/oh-story/skills/story-long-write/references/project-files.md +108 -0
- package/lib/oh-story/skills/story-long-write/references/reference-index.md +87 -0
- package/lib/oh-story/skills/story-long-write/references/style-combat-face.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/style-craft.md +9 -29
- 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 +27 -0
- package/lib/oh-story/skills/story-long-write/references/tracking-initialization.md +31 -0
- package/lib/oh-story/skills/story-long-write/references/tracking-transaction.md +2 -29
- package/lib/oh-story/skills/story-long-write/references/workflow-chapter.md +51 -52
- package/lib/oh-story/skills/story-long-write/references/workflow-daily.md +8 -7
- package/lib/oh-story/skills/story-long-write/references/workflow-setup.md +36 -15
- package/lib/oh-story/skills/story-long-write/references/writer-prompt-fallback.md +22 -0
- package/lib/oh-story/skills/story-long-write/references/writing-craft.md +69 -2
- package/lib/oh-story/skills/story-long-write/scripts/build_writer_prompt.py +410 -0
- package/lib/oh-story/skills/story-long-write/scripts/check-ai-patterns.js +6 -1
- package/lib/oh-story/skills/story-long-write/scripts/check-degeneration.js +39 -20
- package/lib/oh-story/skills/story-long-write/scripts/check-outline-contract.js +176 -12
- package/lib/oh-story/skills/story-long-write/scripts/check-outline-copy.js +90 -23
- package/lib/oh-story/skills/story-long-write/scripts/normalize-punctuation.js +10 -5
- package/lib/oh-story/skills/story-long-write/scripts/outline_view.py +283 -0
- package/lib/oh-story/skills/story-long-write/scripts/style-whitelist.js +39 -0
- package/lib/oh-story/skills/story-review/SKILL.md +13 -3
- package/lib/oh-story/skills/story-review/references/anti-ai-writing.md +19 -47
- package/lib/oh-story/skills/story-review/references/author-memory.md +10 -8
- package/lib/oh-story/skills/story-review/references/banned-words.md +3 -1
- package/lib/oh-story/skills/story-review/references/dialogue-mastery.md +6 -4
- package/lib/oh-story/skills/story-review/references/review-quality.md +2 -2
- package/lib/oh-story/skills/story-review/references/style-resolution.md +27 -0
- package/lib/oh-story/skills/story-review/references/tracking-initialization.md +31 -0
- package/lib/oh-story/skills/story-review/references/tracking-transaction.md +2 -29
- package/lib/oh-story/skills/story-review/scripts/check-ai-patterns.js +6 -1
- package/lib/oh-story/skills/story-review/scripts/check-degeneration.js +39 -20
- package/lib/oh-story/skills/story-review/scripts/normalize-punctuation.js +10 -5
- package/lib/oh-story/skills/story-review/scripts/style-whitelist.js +39 -0
- package/lib/oh-story/skills/story-setup/SKILL.md +17 -10
- package/lib/oh-story/skills/story-setup/references/agent-references/anti-ai-writing.md +19 -47
- package/lib/oh-story/skills/story-setup/references/agent-references/banned-words.md +3 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/deslop-gates.md +154 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/dialogue-mastery.md +6 -4
- package/lib/oh-story/skills/story-setup/references/agent-references/format-and-structure.md +2 -2
- package/lib/oh-story/skills/story-setup/references/agent-references/short-genre-formulas.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/style-combat-face.md +1 -1
- 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 +27 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/writing-craft.md +69 -2
- package/lib/oh-story/skills/story-setup/references/diagnostics.md +38 -0
- package/lib/oh-story/skills/story-short-analyze/references/analysis-writing-techniques.md +1 -1
- package/lib/oh-story/skills/story-short-analyze/references/source-story-quality.md +2 -2
- package/lib/oh-story/skills/story-short-write/SKILL.md +18 -186
- package/lib/oh-story/skills/story-short-write/references/author-memory.md +10 -8
- package/lib/oh-story/skills/story-short-write/references/banned-words.md +3 -1
- package/lib/oh-story/skills/story-short-write/references/benchmark-recall.md +60 -0
- package/lib/oh-story/skills/story-short-write/references/dialogue-mastery.md +6 -4
- package/lib/oh-story/skills/story-short-write/references/genre-styles//344/270/226/346/203/205/346/211/223/350/204/270.md +2 -2
- package/lib/oh-story/skills/story-short-write/references/genre-styles//345/217/214/347/224/267/344/270/273.md +1 -1
- package/lib/oh-story/skills/story-short-write/references/genre-styles//345/244/215/344/273/207/346/211/223/350/204/270.md +3 -3
- package/lib/oh-story/skills/story-short-write/references/genre-styles//345/256/205/346/226/227/345/256/253/346/226/227.md +3 -3
- package/lib/oh-story/skills/story-short-write/references/genre-styles//346/200/273/350/243/201/350/261/252/351/227/250.md +3 -3
- package/lib/oh-story/skills/story-short-write/references/genre-styles//346/202/254/347/226/221.md +5 -5
- package/lib/oh-story/skills/story-short-write/references/genre-styles//346/260/221/344/277/227/346/200/252/350/260/210.md +4 -4
- package/lib/oh-story/skills/story-short-write/references/genre-styles//347/224/234/345/256/240.md +5 -5
- package/lib/oh-story/skills/story-short-write/references/genre-styles//350/277/275/345/246/273/347/201/253/350/221/254/345/234/272.md +3 -3
- package/lib/oh-story/skills/story-short-write/references/genre-writing-formulas.md +1 -1
- package/lib/oh-story/skills/story-short-write/references/genre-writing-techniques.md +1 -1
- package/lib/oh-story/skills/story-short-write/references/reference-index.md +53 -0
- package/lib/oh-story/skills/story-short-write/references/short-craft.md +12 -14
- package/lib/oh-story/skills/story-short-write/references/short-deslop.md +10 -10
- package/lib/oh-story/skills/story-short-write/references/short-format.md +3 -1
- package/lib/oh-story/skills/story-short-write/references/short-prose-quality.md +2 -2
- package/lib/oh-story/skills/story-short-write/references/style-resolution.md +27 -0
- package/lib/oh-story/skills/story-short-write/references/workflow-design.md +77 -0
- package/lib/oh-story/skills/story-short-write/references/writing-workflow.md +5 -5
- package/lib/oh-story/skills/story-short-write/scripts/check-ai-patterns.js +6 -1
- package/lib/oh-story/skills/story-short-write/scripts/check-degeneration.js +39 -20
- package/lib/oh-story/skills/story-short-write/scripts/check-delivery-contract.js +34 -5
- package/lib/oh-story/skills/story-short-write/scripts/check-outline-copy.js +90 -23
- package/lib/oh-story/skills/story-short-write/scripts/normalize-punctuation.js +10 -5
- package/lib/oh-story/skills/story-short-write/scripts/style-whitelist.js +39 -0
- package/lib/types/client/drama-production-view.d.ts.map +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/production-prompts.d.ts.map +1 -1
- package/lib/types/client/production-runtime.d.ts +17 -0
- package/lib/types/client/production-runtime.d.ts.map +1 -1
- package/lib/types/skill-provider.d.ts.map +1 -1
- package/lib/video-recap/CHANGELOG.md +31 -1
- package/lib/video-recap/manifest.json +162 -162
- package/lib/video-recap/skills/video-assemble/scripts/artifacts.py +4 -9
- package/lib/video-recap/skills/video-assemble/scripts/assemble.py +47 -60
- package/lib/video-recap/skills/video-assemble/scripts/assembly_contract.py +77 -115
- package/lib/video-recap/skills/video-assemble/scripts/assembly_settings.py +41 -40
- package/lib/video-recap/skills/video-assemble/scripts/audio_automation.py +22 -32
- package/lib/video-recap/skills/video-assemble/scripts/audio_mix.py +102 -192
- package/lib/video-recap/skills/video-assemble/scripts/jianying_builders.py +14 -35
- package/lib/video-recap/skills/video-assemble/scripts/jianying_model.py +14 -12
- package/lib/video-recap/skills/video-assemble/scripts/jianying_optional.py +8 -9
- package/lib/video-recap/skills/video-assemble/scripts/jianying_schema.py +3 -14
- package/lib/video-recap/skills/video-assemble/scripts/jianying_timeline_contract.py +23 -12
- package/lib/video-recap/skills/video-assemble/scripts/jianying_tracks.py +1 -4
- package/lib/video-recap/skills/video-assemble/scripts/jianying_writer.py +24 -25
- package/lib/video-recap/skills/video-assemble/scripts/lib.py +31 -85
- package/lib/video-recap/skills/video-assemble/scripts/media.py +100 -144
- package/lib/video-recap/skills/video-assemble/scripts/narration_audio.py +101 -195
- package/lib/video-recap/skills/video-assemble/scripts/render_preflight.py +10 -21
- package/lib/video-recap/skills/video-assemble/scripts/source_subtitles.py +90 -169
- package/lib/video-recap/skills/video-assemble/scripts/subtitle_core.py +69 -122
- package/lib/video-recap/skills/video-assemble/scripts/subtitle_render.py +10 -17
- package/lib/video-recap/skills/video-assemble/scripts/timeline.py +33 -48
- package/lib/video-recap/skills/video-assemble/scripts/timeline_emit.py +14 -20
- package/lib/video-recap/skills/video-assemble/scripts/visual_render.py +135 -213
- package/lib/video-recap/skills/video-cut/scripts/cut_cli.py +49 -57
- package/lib/video-recap/skills/video-cut/scripts/cut_contract.py +38 -74
- package/lib/video-recap/skills/video-cut/scripts/cut_render.py +46 -95
- package/lib/video-recap/skills/video-cut/scripts/lib.py +23 -25
- package/lib/video-recap/skills/video-cut/scripts/media_geometry.py +70 -173
- package/lib/video-recap/skills/video-cut/scripts/narration_mapping.py +28 -53
- package/lib/video-recap/skills/video-cut/scripts/sentence_boundaries.py +162 -322
- package/lib/video-recap/skills/video-recap/references/timeline-and-jianying.md +6 -7
- package/lib/video-recap/skills/video-recap/scripts/doctor.py +104 -124
- package/lib/video-recap/skills/video-recap/scripts/final_qc.py +255 -412
- package/lib/video-recap/skills/video-recap/scripts/lib.py +30 -52
- package/lib/video-recap/skills/video-recap/scripts/materials.py +97 -120
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc_client.py +7 -12
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc_evidence.py +46 -97
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc_observations.py +18 -36
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc_payload.py +29 -47
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc_report.py +43 -76
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc_runner.py +2 -1
- package/lib/video-recap/skills/video-recap/scripts/qc_contract.py +2 -1
- package/lib/video-recap/skills/video-recap/scripts/recap_cli.py +2 -2
- package/lib/video-recap/skills/video-recap/scripts/recap_inspect.py +129 -145
- package/lib/video-recap/skills/video-recap/scripts/recap_review.py +27 -20
- package/lib/video-recap/skills/video-recap/scripts/recap_runner.py +20 -31
- package/lib/video-recap/skills/video-recap/scripts/recap_runtime.py +31 -106
- package/lib/video-recap/skills/video-recap/scripts/recap_stage_qc.py +43 -113
- package/lib/video-recap/skills/video-recap/scripts/recap_timeline.py +196 -377
- package/lib/video-recap/skills/video-script/scripts/agent_brief.py +1 -1
- package/lib/video-recap/skills/video-script/scripts/agent_text.py +63 -172
- package/lib/video-recap/skills/video-script/scripts/brief_context.py +80 -135
- package/lib/video-recap/skills/video-script/scripts/brief_inputs.py +125 -167
- package/lib/video-recap/skills/video-script/scripts/brief_timeline.py +93 -208
- package/lib/video-recap/skills/video-script/scripts/deslop_qc.py +20 -46
- package/lib/video-recap/skills/video-script/scripts/lib.py +30 -26
- package/lib/video-recap/skills/video-script/scripts/narration_lint.py +145 -140
- package/lib/video-recap/skills/video-script/scripts/review_response.py +12 -42
- package/lib/video-recap/skills/video-script/scripts/review_runner.py +0 -6
- package/lib/video-recap/skills/video-script/scripts/speech_ownership.py +39 -100
- package/lib/video-recap/skills/video-script/scripts/timeline_fusion.py +33 -124
- package/lib/video-recap/skills/video-understanding/scripts/agent_brief.py +1 -1
- package/lib/video-recap/skills/video-understanding/scripts/agent_text.py +63 -172
- package/lib/video-recap/skills/video-understanding/scripts/asr.py +1 -2
- package/lib/video-recap/skills/video-understanding/scripts/brief_context.py +80 -135
- package/lib/video-recap/skills/video-understanding/scripts/brief_inputs.py +125 -167
- package/lib/video-recap/skills/video-understanding/scripts/brief_timeline.py +93 -208
- package/lib/video-recap/skills/video-understanding/scripts/consolidate.py +1 -1
- package/lib/video-recap/skills/video-understanding/scripts/deslop_qc.py +20 -46
- package/lib/video-recap/skills/video-understanding/scripts/lib.py +31 -26
- package/lib/video-recap/skills/video-understanding/scripts/narration_lint.py +145 -140
- package/lib/video-recap/skills/video-understanding/scripts/speech_ownership.py +39 -100
- package/lib/video-recap/skills/video-understanding/scripts/timeline_fusion.py +33 -124
- package/lib/video-recap/skills/video-understanding/scripts/vlm.py +1 -4
- package/lib/video-recap/skills/video-voiceover/scripts/dub.py +7 -13
- package/lib/video-recap/skills/video-voiceover/scripts/fish_audio.py +12 -30
- package/lib/video-recap/skills/video-voiceover/scripts/lib.py +98 -131
- package/lib/video-recap/skills/video-voiceover/scripts/tts_audio.py +17 -28
- package/lib/video-recap/skills/video-voiceover/scripts/voiceover.py +151 -240
- package/package.json +41 -41
|
@@ -169,7 +169,7 @@ Resource-backed segments must define exactly one of:
|
|
|
169
169
|
"resource_id": "...",
|
|
170
170
|
"main_config": {"type": "sticker", "path": "/local/file"},
|
|
171
171
|
"resources": [
|
|
172
|
-
"/local/file",
|
|
172
|
+
{"source_path": "/local/file"},
|
|
173
173
|
{"source_path": "/local/package-dir", "target_path": "package-dir"}
|
|
174
174
|
],
|
|
175
175
|
"cover_img": "/local/cover.png",
|
|
@@ -180,14 +180,13 @@ Resource-backed segments must define exactly one of:
|
|
|
180
180
|
```
|
|
181
181
|
|
|
182
182
|
`resource_package` resolves a top-level `resource_packages` entry with the same
|
|
183
|
-
shape as `resource_config`.
|
|
184
|
-
Jackson `JyResource`
|
|
185
|
-
|
|
186
|
-
`resource_config` itself may be an object or a local JSON-file path.
|
|
183
|
+
canonical snake_case object shape as `resource_config`. `main_config` must be an
|
|
184
|
+
object; callers adapt any external Jackson `JyResource` or JSON-file input before
|
|
185
|
+
passing it to this skill.
|
|
187
186
|
|
|
188
187
|
`resources` is an explicit local-file contract, never a filesystem guess. A
|
|
189
|
-
|
|
190
|
-
|
|
188
|
+
descriptor must contain `source_path` and may additionally set `resource_kind`
|
|
189
|
+
and a safe package-relative `target_path`. ZIP input is
|
|
191
190
|
validated against path traversal, extracted under
|
|
192
191
|
`Resources/local/<kind>/<archive-stem>`, and keeps its internal layout. Exact
|
|
193
192
|
declared path values in material JSON, including rich-text JSON strings, are
|
|
@@ -7,12 +7,10 @@ from __future__ import annotations
|
|
|
7
7
|
|
|
8
8
|
import argparse
|
|
9
9
|
import json
|
|
10
|
-
import os
|
|
11
10
|
import shutil
|
|
12
11
|
import subprocess
|
|
13
12
|
import sys
|
|
14
13
|
from pathlib import Path
|
|
15
|
-
from typing import Any, cast
|
|
16
14
|
|
|
17
15
|
from lib import CONFIG
|
|
18
16
|
|
|
@@ -23,25 +21,17 @@ TTS_PROVIDERS = {"auto", "mimo-tts", "fish-audio"}
|
|
|
23
21
|
|
|
24
22
|
|
|
25
23
|
def _command_path(name: str) -> str | None:
|
|
26
|
-
"""Return resolved command path, accepting absolute/relative executable paths."""
|
|
27
|
-
if not name:
|
|
28
|
-
return None
|
|
29
|
-
if os.path.sep in name or (os.path.altsep and os.path.altsep in name):
|
|
30
|
-
path = Path(name).expanduser()
|
|
31
|
-
return str(path) if path.exists() and os.access(path, os.X_OK) else None
|
|
32
24
|
return shutil.which(name)
|
|
33
25
|
|
|
34
26
|
|
|
35
|
-
def _run(cmd: list[str], *, timeout: int = 20) -> subprocess.CompletedProcess[str]:
|
|
36
|
-
return subprocess.run(cmd, text=True, capture_output=True, timeout=timeout)
|
|
37
|
-
|
|
38
|
-
|
|
39
27
|
def _ffmpeg_filters() -> set[str]:
|
|
40
28
|
ffmpeg = _command_path("ffmpeg")
|
|
41
29
|
if not ffmpeg:
|
|
42
30
|
return set()
|
|
43
31
|
try:
|
|
44
|
-
result =
|
|
32
|
+
result = subprocess.run(
|
|
33
|
+
[ffmpeg, "-hide_banner", "-filters"], text=True, capture_output=True, timeout=20
|
|
34
|
+
)
|
|
45
35
|
except (OSError, subprocess.SubprocessError):
|
|
46
36
|
return set()
|
|
47
37
|
if result.returncode != 0:
|
|
@@ -64,15 +54,15 @@ def ffmpeg_has_subtitles_filter() -> bool:
|
|
|
64
54
|
|
|
65
55
|
|
|
66
56
|
def _asr_status() -> dict[str, object]:
|
|
67
|
-
configured = bool(CONFIG
|
|
57
|
+
configured = bool(CONFIG["mimo_asr_api_key"])
|
|
68
58
|
return {
|
|
69
59
|
"configured": configured,
|
|
70
60
|
"available": configured,
|
|
71
|
-
"mimo_asr_model":
|
|
72
|
-
"mimo_asr_api_url":
|
|
73
|
-
"mimo_asr_api_url_source": CONFIG
|
|
74
|
-
"mimo_asr_language":
|
|
75
|
-
"mimo_asr_api_key_source": CONFIG
|
|
61
|
+
"mimo_asr_model": CONFIG["mimo_asr_model"],
|
|
62
|
+
"mimo_asr_api_url": CONFIG["mimo_asr_api_url"],
|
|
63
|
+
"mimo_asr_api_url_source": CONFIG["mimo_asr_api_url_source"],
|
|
64
|
+
"mimo_asr_language": CONFIG["mimo_asr_language"],
|
|
65
|
+
"mimo_asr_api_key_source": CONFIG["mimo_asr_api_key_source"],
|
|
76
66
|
"note": "ASR uses MiMo (mimo-v2.5-asr); set MIMO_API_KEY, or run with --skip-asr.",
|
|
77
67
|
}
|
|
78
68
|
|
|
@@ -86,16 +76,16 @@ def _capability(name: str, summary: str, *, detail: str = "", action: str = "")
|
|
|
86
76
|
return item
|
|
87
77
|
|
|
88
78
|
|
|
89
|
-
def _build_capability_menu(checks: dict
|
|
79
|
+
def _build_capability_menu(checks: dict) -> dict[str, list[dict[str, str]]]:
|
|
90
80
|
"""Human-ready preflight summary grouped by what can run, what blocks, and what degrades.
|
|
91
81
|
|
|
92
82
|
This is intentionally a small rollup over the existing `checks` tree. It does not replace
|
|
93
83
|
the raw machine checks, install anything, or introduce provider ranking.
|
|
94
84
|
"""
|
|
95
|
-
system =
|
|
96
|
-
api =
|
|
97
|
-
asr =
|
|
98
|
-
tts =
|
|
85
|
+
system = checks["system_tools"]
|
|
86
|
+
api = checks["api_config"]
|
|
87
|
+
asr = checks["asr"]
|
|
88
|
+
tts = checks["tts"]
|
|
99
89
|
|
|
100
90
|
menu: dict[str, list[dict[str, str]]] = {
|
|
101
91
|
"ready": [],
|
|
@@ -104,13 +94,13 @@ def _build_capability_menu(checks: dict[str, object]) -> dict[str, list[dict[str
|
|
|
104
94
|
"optional_upgrades": [],
|
|
105
95
|
}
|
|
106
96
|
|
|
107
|
-
ffmpeg_ready =
|
|
108
|
-
ffprobe_ready =
|
|
109
|
-
subtitles_ready =
|
|
110
|
-
api_key_set =
|
|
111
|
-
asr_ready =
|
|
112
|
-
tts_ready =
|
|
113
|
-
vlm_ready =
|
|
97
|
+
ffmpeg_ready = system["ffmpeg"]
|
|
98
|
+
ffprobe_ready = system["ffprobe"]
|
|
99
|
+
subtitles_ready = system["burn_subtitles_ready"]
|
|
100
|
+
api_key_set = api["api_key_set"]
|
|
101
|
+
asr_ready = asr["available"]
|
|
102
|
+
tts_ready = tts["available"]
|
|
103
|
+
vlm_ready = api["mimo_video_configured"]
|
|
114
104
|
normal_core_ready = ffmpeg_ready and ffprobe_ready and api_key_set and vlm_ready and tts_ready
|
|
115
105
|
|
|
116
106
|
if ffmpeg_ready and ffprobe_ready:
|
|
@@ -136,7 +126,7 @@ def _build_capability_menu(checks: dict[str, object]) -> dict[str, list[dict[str
|
|
|
136
126
|
_capability(
|
|
137
127
|
"mimo_credentials",
|
|
138
128
|
"MiMo API key is configured",
|
|
139
|
-
detail=f"Source: {api
|
|
129
|
+
detail=f"Source: {api['api_key_source']}",
|
|
140
130
|
)
|
|
141
131
|
)
|
|
142
132
|
else:
|
|
@@ -153,7 +143,7 @@ def _build_capability_menu(checks: dict[str, object]) -> dict[str, list[dict[str
|
|
|
153
143
|
_capability(
|
|
154
144
|
"mimo_vlm",
|
|
155
145
|
"MiMo VLM/video understanding is configured",
|
|
156
|
-
detail=f"Model: {api
|
|
146
|
+
detail=f"Model: {api['vlm_model']}",
|
|
157
147
|
)
|
|
158
148
|
)
|
|
159
149
|
elif api_key_set:
|
|
@@ -165,13 +155,13 @@ def _build_capability_menu(checks: dict[str, object]) -> dict[str, list[dict[str
|
|
|
165
155
|
)
|
|
166
156
|
)
|
|
167
157
|
|
|
168
|
-
tts_provider =
|
|
158
|
+
tts_provider = tts["provider"]
|
|
169
159
|
if tts_ready:
|
|
170
160
|
menu["ready"].append(
|
|
171
161
|
_capability(
|
|
172
162
|
"fish_audio_tts" if tts_provider == "fish-audio" else "mimo_tts",
|
|
173
163
|
f"{tts_provider} is configured",
|
|
174
|
-
detail=f"Model: {tts
|
|
164
|
+
detail=f"Model: {tts['model']}",
|
|
175
165
|
)
|
|
176
166
|
)
|
|
177
167
|
elif api_key_set:
|
|
@@ -192,7 +182,7 @@ def _build_capability_menu(checks: dict[str, object]) -> dict[str, list[dict[str
|
|
|
192
182
|
_capability(
|
|
193
183
|
"mimo_asr",
|
|
194
184
|
"MiMo ASR is configured",
|
|
195
|
-
detail=f"Language: {asr
|
|
185
|
+
detail=f"Language: {asr['mimo_asr_language']}; model: {asr['mimo_asr_model']}",
|
|
196
186
|
)
|
|
197
187
|
)
|
|
198
188
|
else:
|
|
@@ -200,7 +190,7 @@ def _build_capability_menu(checks: dict[str, object]) -> dict[str, list[dict[str
|
|
|
200
190
|
_capability(
|
|
201
191
|
"mimo_asr",
|
|
202
192
|
"ASR is unavailable; run only with --skip-asr",
|
|
203
|
-
action=
|
|
193
|
+
action=asr["note"],
|
|
204
194
|
)
|
|
205
195
|
)
|
|
206
196
|
|
|
@@ -266,12 +256,10 @@ def build_report(*, tts_provider: str | None = None) -> dict[str, object]:
|
|
|
266
256
|
filters = _ffmpeg_filters()
|
|
267
257
|
ffmpeg_path = _command_path("ffmpeg") or ""
|
|
268
258
|
ffprobe_path = _command_path("ffprobe") or ""
|
|
269
|
-
mimo_video_configured = bool(CONFIG
|
|
270
|
-
mimo_tts_configured = bool(CONFIG
|
|
271
|
-
fish_tts_configured = bool(CONFIG
|
|
272
|
-
requested_tts_provider =
|
|
273
|
-
tts_provider or CONFIG.get("tts_provider") or "auto"
|
|
274
|
-
).strip().lower()
|
|
259
|
+
mimo_video_configured = bool(CONFIG["mimo_video_api_key"])
|
|
260
|
+
mimo_tts_configured = bool(CONFIG["mimo_tts_api_key"])
|
|
261
|
+
fish_tts_configured = bool(CONFIG["fish_api_key"])
|
|
262
|
+
requested_tts_provider = tts_provider or CONFIG["tts_provider"]
|
|
275
263
|
effective_tts_provider = requested_tts_provider
|
|
276
264
|
if requested_tts_provider == "auto":
|
|
277
265
|
effective_tts_provider = (
|
|
@@ -281,55 +269,52 @@ def build_report(*, tts_provider: str | None = None) -> dict[str, object]:
|
|
|
281
269
|
fish_tts_configured if effective_tts_provider == "fish-audio" else mimo_tts_configured
|
|
282
270
|
)
|
|
283
271
|
subtitle_filter = "subtitles" in filters
|
|
284
|
-
|
|
285
|
-
checks: dict[str, object] = {
|
|
272
|
+
checks = {
|
|
286
273
|
"system_tools": {
|
|
287
274
|
"ffmpeg": bool(ffmpeg_path),
|
|
288
275
|
"ffmpeg_path": ffmpeg_path,
|
|
289
276
|
"ffprobe": bool(ffprobe_path),
|
|
290
277
|
"ffprobe_path": ffprobe_path,
|
|
291
278
|
"ffmpeg_subtitles_filter": subtitle_filter,
|
|
292
|
-
"ffmpeg_ass_filter":
|
|
279
|
+
"ffmpeg_ass_filter": "ass" in filters,
|
|
293
280
|
"burn_subtitles_ready": bool(ffmpeg_path and subtitle_filter),
|
|
294
281
|
},
|
|
295
282
|
"tts": {
|
|
296
283
|
"provider": effective_tts_provider,
|
|
297
284
|
"requested_provider": requested_tts_provider,
|
|
298
285
|
"mimo_tts_configured": mimo_tts_configured,
|
|
299
|
-
"mimo_tts_api_url": CONFIG
|
|
300
|
-
"mimo_tts_api_url_source": CONFIG
|
|
301
|
-
"mimo_tts_model": CONFIG
|
|
302
|
-
"mimo_tts_model_source": CONFIG
|
|
303
|
-
"mimo_tts_voice": CONFIG
|
|
304
|
-
"mimo_tts_voice_source": CONFIG
|
|
286
|
+
"mimo_tts_api_url": CONFIG["mimo_tts_api_url"],
|
|
287
|
+
"mimo_tts_api_url_source": CONFIG["mimo_tts_api_url_source"],
|
|
288
|
+
"mimo_tts_model": CONFIG["mimo_tts_model"],
|
|
289
|
+
"mimo_tts_model_source": CONFIG["mimo_tts_model_source"],
|
|
290
|
+
"mimo_tts_voice": CONFIG["mimo_tts_voice"],
|
|
291
|
+
"mimo_tts_voice_source": CONFIG["mimo_tts_voice_source"],
|
|
305
292
|
"fish_tts_configured": fish_tts_configured,
|
|
306
|
-
"fish_tts_api_url": CONFIG
|
|
307
|
-
"fish_tts_model": CONFIG
|
|
308
|
-
"fish_tts_reference_id_set": bool(CONFIG
|
|
309
|
-
"fish_tts_reference_id_source": CONFIG
|
|
310
|
-
"fish_tts_reference_id_source", "default"
|
|
311
|
-
),
|
|
293
|
+
"fish_tts_api_url": CONFIG["fish_tts_api_url"],
|
|
294
|
+
"fish_tts_model": CONFIG["fish_tts_model"],
|
|
295
|
+
"fish_tts_reference_id_set": bool(CONFIG["fish_tts_reference_id"]),
|
|
296
|
+
"fish_tts_reference_id_source": CONFIG["fish_tts_reference_id_source"],
|
|
312
297
|
"model": (
|
|
313
|
-
CONFIG
|
|
298
|
+
CONFIG["fish_tts_model"]
|
|
314
299
|
if effective_tts_provider == "fish-audio"
|
|
315
|
-
else CONFIG
|
|
300
|
+
else CONFIG["mimo_tts_model"]
|
|
316
301
|
),
|
|
317
302
|
"available": tts_configured,
|
|
318
303
|
},
|
|
319
304
|
"asr": _asr_status(),
|
|
320
305
|
"api_config": {
|
|
321
|
-
"api_provider": CONFIG
|
|
322
|
-
"api_url":
|
|
323
|
-
"api_url_source": CONFIG
|
|
324
|
-
"api_key_source": CONFIG
|
|
325
|
-
"api_key_set": bool(CONFIG
|
|
326
|
-
"vlm_model": CONFIG
|
|
327
|
-
"vlm_model_source": CONFIG
|
|
328
|
-
"vlm_workers": CONFIG
|
|
306
|
+
"api_provider": CONFIG["api_provider"],
|
|
307
|
+
"api_url": CONFIG["api_url"],
|
|
308
|
+
"api_url_source": CONFIG["api_url_source"],
|
|
309
|
+
"api_key_source": CONFIG["api_key_source"],
|
|
310
|
+
"api_key_set": bool(CONFIG["api_key"]),
|
|
311
|
+
"vlm_model": CONFIG["vlm_model"],
|
|
312
|
+
"vlm_model_source": CONFIG["vlm_model_source"],
|
|
313
|
+
"vlm_workers": CONFIG["vlm_workers"],
|
|
329
314
|
"mimo_video_configured": mimo_video_configured,
|
|
330
|
-
"mimo_video_api_url": CONFIG
|
|
331
|
-
"mimo_video_model": CONFIG
|
|
332
|
-
"mimo_video_model_source": CONFIG
|
|
315
|
+
"mimo_video_api_url": CONFIG["mimo_video_api_url"],
|
|
316
|
+
"mimo_video_model": CONFIG["mimo_video_model"],
|
|
317
|
+
"mimo_video_model_source": CONFIG["mimo_video_model_source"],
|
|
333
318
|
},
|
|
334
319
|
"python": {
|
|
335
320
|
"executable": sys.executable,
|
|
@@ -339,28 +324,25 @@ def build_report(*, tts_provider: str | None = None) -> dict[str, object]:
|
|
|
339
324
|
|
|
340
325
|
failures: list[str] = []
|
|
341
326
|
warnings: list[str] = []
|
|
342
|
-
tools =
|
|
343
|
-
api_config = cast(dict[str, Any], checks["api_config"])
|
|
344
|
-
asr_check = cast(dict[str, Any], checks["asr"])
|
|
327
|
+
tools = checks["system_tools"]
|
|
345
328
|
for name in ("ffmpeg", "ffprobe"):
|
|
346
|
-
if not tools
|
|
329
|
+
if not tools[name]:
|
|
347
330
|
failures.append(f"Missing system tool: {name}")
|
|
348
331
|
if requested_tts_provider not in TTS_PROVIDERS:
|
|
349
332
|
failures.append(
|
|
350
333
|
"TTS_PROVIDER must be one of: auto, mimo-tts, fish-audio"
|
|
351
334
|
)
|
|
352
|
-
if tools
|
|
335
|
+
if tools["ffmpeg"] and not tools["ffmpeg_subtitles_filter"]:
|
|
353
336
|
warnings.append("ffmpeg lacks subtitles/libass filter; --burn-subtitles will fail")
|
|
354
|
-
if not api_config
|
|
337
|
+
if not checks["api_config"]["api_key_set"]:
|
|
355
338
|
failures.append("MIMO_API_KEY is not set; the default ASR / VLM path requires MiMo")
|
|
356
|
-
if not
|
|
339
|
+
if not checks["asr"]["available"]:
|
|
357
340
|
warnings.append("ASR not configured (MIMO_API_KEY); pipeline can run with --skip-asr")
|
|
358
|
-
capability_menu = _build_capability_menu(checks)
|
|
359
341
|
return {
|
|
360
342
|
"ok": not failures,
|
|
361
343
|
"repo_root": str(SCRIPT_DIR.parents[2]),
|
|
362
344
|
"checks": checks,
|
|
363
|
-
"capability_menu":
|
|
345
|
+
"capability_menu": _build_capability_menu(checks),
|
|
364
346
|
"failures": failures,
|
|
365
347
|
"warnings": warnings,
|
|
366
348
|
}
|
|
@@ -372,88 +354,86 @@ def _status_icon(ok: bool, *, warning: bool = False) -> str:
|
|
|
372
354
|
return "!" if warning else "✗"
|
|
373
355
|
|
|
374
356
|
|
|
375
|
-
def _print_human(report: dict
|
|
376
|
-
checks =
|
|
357
|
+
def _print_human(report: dict) -> None:
|
|
358
|
+
checks = report["checks"]
|
|
377
359
|
print("video-recap doctor")
|
|
378
360
|
print(f"Repo root: {report['repo_root']}")
|
|
379
361
|
|
|
380
|
-
system =
|
|
362
|
+
system = checks["system_tools"]
|
|
381
363
|
print("\n[system]")
|
|
382
|
-
print(f"{_status_icon(
|
|
383
|
-
print(f"{_status_icon(
|
|
364
|
+
print(f"{_status_icon(system['ffmpeg'])} ffmpeg: {system['ffmpeg_path'] or 'not found'}")
|
|
365
|
+
print(f"{_status_icon(system['ffprobe'])} ffprobe: {system['ffprobe_path'] or 'not found'}")
|
|
384
366
|
print(
|
|
385
|
-
f"{_status_icon(
|
|
367
|
+
f"{_status_icon(system['ffmpeg_subtitles_filter'], warning=True)} "
|
|
386
368
|
f"ffmpeg subtitles/libass filter: "
|
|
387
|
-
f"{'available' if system
|
|
369
|
+
f"{'available' if system['ffmpeg_subtitles_filter'] else 'missing'}"
|
|
388
370
|
)
|
|
389
371
|
|
|
390
|
-
api =
|
|
372
|
+
api = checks["api_config"]
|
|
391
373
|
print("\n[api]")
|
|
392
|
-
print(f"✓ API provider: {api
|
|
393
|
-
print(f"✓ API URL: {api
|
|
374
|
+
print(f"✓ API provider: {api['api_provider']}")
|
|
375
|
+
print(f"✓ API URL: {api['api_url']} (source: {api['api_url_source']})")
|
|
394
376
|
print(
|
|
395
|
-
f"{_status_icon(
|
|
396
|
-
f"{api
|
|
377
|
+
f"{_status_icon(api['api_key_set'])} "
|
|
378
|
+
f"{api['api_key_source']}: {'set' if api['api_key_set'] else 'not set'}"
|
|
397
379
|
)
|
|
398
|
-
print(f"✓ VLM model: {api
|
|
399
|
-
print(f"✓ VLM_WORKERS: {api
|
|
380
|
+
print(f"✓ VLM model: {api['vlm_model']} (source: {api['vlm_model_source']})")
|
|
381
|
+
print(f"✓ VLM_WORKERS: {api['vlm_workers']}")
|
|
400
382
|
|
|
401
|
-
asr =
|
|
383
|
+
asr = checks["asr"]
|
|
402
384
|
print("\n[asr]")
|
|
403
385
|
print(
|
|
404
|
-
f"{_status_icon(
|
|
405
|
-
f"MiMo ASR: {'configured' if asr
|
|
406
|
-
f"(key: {asr
|
|
386
|
+
f"{_status_icon(asr['available'], warning=True)} "
|
|
387
|
+
f"MiMo ASR: {'configured' if asr['available'] else 'not configured'} "
|
|
388
|
+
f"(key: {asr['mimo_asr_api_key_source']})"
|
|
407
389
|
)
|
|
408
|
-
print(f"✓ ASR model: {asr
|
|
409
|
-
print(f"✓ ASR API URL: {asr
|
|
410
|
-
print(f"✓ ASR language: {asr
|
|
411
|
-
if not asr
|
|
412
|
-
print(f" note: {asr
|
|
390
|
+
print(f"✓ ASR model: {asr['mimo_asr_model']}")
|
|
391
|
+
print(f"✓ ASR API URL: {asr['mimo_asr_api_url']} (source: {asr['mimo_asr_api_url_source']})")
|
|
392
|
+
print(f"✓ ASR language: {asr['mimo_asr_language']}")
|
|
393
|
+
if not asr["available"]:
|
|
394
|
+
print(f" note: {asr['note']}")
|
|
413
395
|
|
|
414
|
-
tts =
|
|
396
|
+
tts = checks["tts"]
|
|
415
397
|
print("\n[tts]")
|
|
416
398
|
print(
|
|
417
|
-
f"{_status_icon(
|
|
418
|
-
f"{'configured' if tts
|
|
399
|
+
f"{_status_icon(tts['available'])} {tts['provider']}: "
|
|
400
|
+
f"{'configured' if tts['available'] else 'not configured'}"
|
|
419
401
|
)
|
|
420
|
-
print(f"✓ TTS model: {tts
|
|
421
|
-
if tts
|
|
402
|
+
print(f"✓ TTS model: {tts['model']}")
|
|
403
|
+
if tts["provider"] == "fish-audio":
|
|
422
404
|
print(
|
|
423
405
|
"✓ TTS voice reference ID: "
|
|
424
|
-
f"{'set' if tts
|
|
425
|
-
f"(source: {tts
|
|
406
|
+
f"{'set' if tts['fish_tts_reference_id_set'] else 'not set'} "
|
|
407
|
+
f"(source: {tts['fish_tts_reference_id_source']})"
|
|
426
408
|
)
|
|
427
|
-
print(f"✓ TTS API URL: {tts
|
|
409
|
+
print(f"✓ TTS API URL: {tts['fish_tts_api_url']}")
|
|
428
410
|
else:
|
|
429
|
-
print(f"✓ TTS voice: {tts
|
|
430
|
-
print(f"✓ TTS API URL: {tts
|
|
411
|
+
print(f"✓ TTS voice: {tts['mimo_tts_voice']} (source: {tts['mimo_tts_voice_source']})")
|
|
412
|
+
print(f"✓ TTS API URL: {tts['mimo_tts_api_url']} (source: {tts['mimo_tts_api_url_source']})")
|
|
431
413
|
|
|
432
|
-
menu =
|
|
414
|
+
menu = report["capability_menu"]
|
|
433
415
|
print("\n[capability menu]")
|
|
434
416
|
for group in ("ready", "blocked", DEGRADED_GROUP, "optional_upgrades"):
|
|
435
417
|
print(f"{group}:")
|
|
436
|
-
items = menu
|
|
418
|
+
items = menu[group]
|
|
437
419
|
if not items:
|
|
438
420
|
print(" - none")
|
|
439
421
|
continue
|
|
440
422
|
for item in items:
|
|
441
|
-
line = f" - {item
|
|
442
|
-
if
|
|
423
|
+
line = f" - {item['name']}: {item['summary']}"
|
|
424
|
+
if "detail" in item:
|
|
443
425
|
line += f" ({item['detail']})"
|
|
444
426
|
print(line)
|
|
445
|
-
if
|
|
427
|
+
if "action" in item:
|
|
446
428
|
print(f" action: {item['action']}")
|
|
447
429
|
|
|
448
|
-
|
|
449
|
-
failures = cast(list[str], report.get("failures") or [])
|
|
450
|
-
if warnings:
|
|
430
|
+
if report["warnings"]:
|
|
451
431
|
print("\nWarnings:")
|
|
452
|
-
for warning in warnings:
|
|
432
|
+
for warning in report["warnings"]:
|
|
453
433
|
print(f"- {warning}")
|
|
454
|
-
if failures:
|
|
434
|
+
if report["failures"]:
|
|
455
435
|
print("\nStatus: FAILED")
|
|
456
|
-
for failure in failures:
|
|
436
|
+
for failure in report["failures"]:
|
|
457
437
|
print(f"- {failure}")
|
|
458
438
|
else:
|
|
459
439
|
print("\nStatus: OK")
|