dsh-hyperframes 0.3.2 → 0.4.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/README.en.md +4 -3
- package/README.md +5 -4
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -0
- package/package.json +2 -2
- package/skills/embedded-captions/SKILL.md +28 -3
- package/skills/embedded-captions/references/aesthetic-principles.md +2 -3
- package/skills/embedded-captions/references/rail.md +1 -1
- package/skills/embedded-captions/scripts/check-occlusion.cjs +4 -1
- package/skills/embedded-captions/scripts/check-overflow.cjs +1 -0
- package/skills/embedded-captions/scripts/check-rail-climax.cjs +5 -1
- package/skills/embedded-captions/scripts/fixtures/heroless/theme.json +11 -0
- package/skills/embedded-captions/scripts/hf-cli.cjs +33 -0
- package/skills/embedded-captions/scripts/make-theme.cjs +95 -57
- package/skills/embedded-captions/scripts/make-theme.test.mjs +131 -0
- package/skills/embedded-captions/scripts/matte.cjs +1 -13
- package/skills/embedded-captions/scripts/measure-layout.cjs +2 -1
- package/skills/embedded-captions/scripts/preview-frames.cjs +39 -11
- package/skills/embedded-captions/scripts/preview-frames.test.mjs +24 -0
- package/skills/embedded-captions/scripts/render-and-composite.sh +8 -52
- package/skills/embedded-captions/scripts/safe-zones.cjs +4 -1
- package/skills/embedded-captions/scripts/transcribe.cjs +5 -14
- package/skills/embedded-captions/scripts/transcribe.test.mjs +41 -0
- package/skills/faceless-explainer/SKILL.md +20 -16
- package/skills/faceless-explainer/references/story-design.md +1 -1
- package/skills/faceless-explainer/scripts/assemble-index.mjs +6 -4
- package/skills/faceless-explainer/scripts/assemble-index.test.mjs +57 -2
- package/skills/faceless-explainer/scripts/audio.mjs +2 -0
- package/skills/faceless-explainer/scripts/build-frame.mjs +6 -3
- package/skills/faceless-explainer/scripts/captions.mjs +7 -4
- package/skills/faceless-explainer/scripts/frame-packets.mjs +4 -4
- package/skills/faceless-explainer/scripts/lib/bgm-volume.mjs +4 -0
- package/skills/faceless-explainer/scripts/lib/captured-fonts.mjs +58 -0
- package/skills/{hyperframes-core → faceless-explainer}/scripts/lib/frame-packets-core.mjs +5 -23
- package/skills/faceless-explainer/scripts/lib/storyboard.mjs +1 -1
- package/skills/faceless-explainer/scripts/lib/transitions.json +3 -3
- package/skills/faceless-explainer/scripts/transitions.mjs +1 -0
- package/skills/faceless-explainer/scripts/transitions.test.mjs +2 -0
- package/skills/faceless-explainer/sub-agents/frame-worker.md +1 -1
- package/skills/figma/SKILL.md +2 -0
- package/skills/general-video/SKILL.md +13 -11
- package/skills/general-video/scripts/frame-packets.mjs +4 -4
- package/skills/general-video/scripts/lib/frame-packets-core.mjs +194 -0
- package/skills/general-video/sub-agents/frame-worker.md +1 -1
- package/skills/hyperframes/SKILL.md +40 -30
- package/skills/{hyperframes-core → hyperframes}/references/brief-contract.md +15 -15
- package/skills/{hyperframes-core → hyperframes}/references/brief-format.md +8 -8
- package/skills/hyperframes/references/capability-menu.md +2 -2
- package/skills/{hyperframes-core → hyperframes}/references/frame-worker-core.md +1 -1
- package/skills/hyperframes/references/intent-interview.md +16 -16
- package/skills/hyperframes/references/plugin-installation.md +43 -0
- package/skills/{hyperframes-core → hyperframes}/references/production-loop.md +11 -11
- package/skills/hyperframes/references/review-loop.md +37 -0
- package/skills/hyperframes/references/route-briefs.md +1 -1
- package/skills/hyperframes/references/routes/motion-graphics.md +1 -1
- package/skills/{hyperframes-core → hyperframes}/references/script-format.md +3 -3
- package/skills/hyperframes/references/skill-lifecycle.md +2 -0
- package/skills/{hyperframes-core → hyperframes}/references/storyboard-format.md +3 -34
- package/skills/hyperframes/scripts/lib/frame-packets-core.mjs +194 -0
- package/skills/hyperframes/scripts/plugin-cli.mjs +88 -0
- package/skills/hyperframes/scripts/plugin-cli.test.mjs +117 -0
- package/skills/hyperframes-animation/SKILL.md +5 -1
- package/skills/hyperframes-animation/adapters/gsap.md +1 -1
- package/skills/hyperframes-animation/adapters/lottie.md +15 -2
- package/skills/hyperframes-animation/adapters/three.md +14 -0
- package/skills/hyperframes-animation/blueprints/titlecard-reveal.md +1 -1
- package/skills/hyperframes-animation/references/motion-blur.md +133 -0
- package/skills/hyperframes-animation/rules/cursor-click-ripple.md +1 -1
- package/skills/hyperframes-animation/rules/dynamic-content-sequencing.md +1 -1
- package/skills/hyperframes-animation/rules/hacker-flip-3d.md +1 -1
- package/skills/hyperframes-animation/rules/kinetic-beat-slam.md +2 -2
- package/skills/hyperframes-animation/rules/motion-blur-streak.md +1 -1
- package/skills/hyperframes-animation/rules/vertical-spring-ticker.md +1 -1
- package/skills/hyperframes-animation/scripts/package-loader.mjs +47 -16
- package/skills/hyperframes-animation/scripts/package-loader.test.mjs +52 -0
- package/skills/hyperframes-animation/techniques.md +1 -1
- package/skills/hyperframes-animation/transitions/TRANSITION-REGISTRY.md +3 -3
- package/skills/hyperframes-animation/transitions/css-push.md +4 -4
- package/skills/hyperframes-audio/SKILL.md +30 -22
- package/skills/hyperframes-audio/scripts/carve.mjs +6 -3
- package/skills/hyperframes-audio/scripts/carve.test.mjs +16 -1
- package/skills/hyperframes-cli/SKILL.md +44 -35
- package/skills/hyperframes-cli/references/init-and-scaffold.md +8 -6
- package/skills/hyperframes-cli/references/lint-validate-inspect.md +3 -3
- package/skills/hyperframes-cli/references/preview-render.md +35 -32
- package/skills/hyperframes-cli/references/upgrade-info-misc.md +50 -1
- package/skills/hyperframes-core/SKILL.md +30 -24
- package/skills/hyperframes-core/references/composition-patterns.md +3 -42
- package/skills/hyperframes-core/references/creator-editing-recipes.md +131 -7
- package/skills/hyperframes-core/references/data-attributes.md +11 -11
- package/skills/hyperframes-core/references/determinism-rules.md +2 -19
- package/skills/hyperframes-core/references/full-screen-motion.md +0 -9
- package/skills/hyperframes-core/references/minimal-composition.md +2 -2
- package/skills/hyperframes-core/references/sub-compositions.md +3 -66
- package/skills/hyperframes-core/references/tailwind.md +1 -20
- package/skills/hyperframes-core/references/tracks-and-clips.md +2 -6
- package/skills/hyperframes-core/references/variables-and-media.md +3 -3
- package/skills/hyperframes-creative/SKILL.md +2 -0
- package/skills/hyperframes-creative/references/house-style.md +15 -15
- package/skills/hyperframes-creative/references/story-spine.md +3 -1
- package/skills/hyperframes-creative/references/storyboard-recipe.md +57 -0
- package/skills/hyperframes-creative/references/typography.md +1 -1
- package/skills/hyperframes-creative/scripts/package-loader.mjs +47 -16
- package/skills/hyperframes-creative/scripts/package-loader.test.mjs +52 -0
- package/skills/hyperframes-keyframes/SKILL.md +4 -2
- package/skills/hyperframes-registry/SKILL.md +3 -1
- package/skills/hyperframes-registry/references/contributing.md +8 -2
- package/skills/hyperframes-registry/references/discovery.md +20 -34
- package/skills/hyperframes-studio/SKILL.md +77 -0
- package/skills/media-use/SKILL.md +14 -12
- package/skills/media-use/audio/references/captions/authoring.md +4 -0
- package/skills/media-use/audio/references/remove-background.md +1 -1
- package/skills/media-use/audio/references/tts-to-captions.md +11 -2
- package/skills/media-use/audio/references/tts.md +84 -6
- package/skills/media-use/audio/scripts/audio.mjs +15 -6
- package/skills/media-use/audio/scripts/gemini-pipeline.test.mjs +113 -0
- package/skills/media-use/audio/scripts/lib/audio-meta.mjs +39 -0
- package/skills/media-use/audio/scripts/lib/audio-meta.test.mjs +136 -0
- package/skills/media-use/audio/scripts/lib/bgm-volume.mjs +4 -0
- package/skills/media-use/audio/scripts/lib/bgm.mjs +2 -6
- package/skills/media-use/audio/scripts/lib/gemini-auth.mjs +43 -0
- package/skills/media-use/audio/scripts/lib/gemini-auth.py +52 -0
- package/skills/media-use/audio/scripts/lib/gemini-auth.test.mjs +86 -0
- package/skills/media-use/audio/scripts/lib/gemini-auth_test.py +90 -0
- package/skills/media-use/audio/scripts/lib/gemini-tts.mjs +122 -0
- package/skills/media-use/audio/scripts/lib/gemini-tts.test.mjs +243 -0
- package/skills/media-use/audio/scripts/lib/heygen.mjs +2 -1
- package/skills/media-use/audio/scripts/lib/tts.mjs +15 -3
- package/skills/media-use/audio/scripts/wait-bgm.mjs +8 -4
- package/skills/media-use/audio/scripts/wait-bgm.test.mjs +65 -0
- package/skills/media-use/references/audio.md +3 -2
- package/skills/media-use/references/grading.md +7 -7
- package/skills/media-use/references/media-treatment-recipes.md +1 -1
- package/skills/media-use/references/memory.md +2 -2
- package/skills/media-use/references/meta.md +2 -2
- package/skills/media-use/references/operations.md +15 -13
- package/skills/media-use/references/resolve.md +22 -11
- package/skills/media-use/references/setup-providers.md +11 -11
- package/skills/media-use/scripts/audio-duck.mjs +19 -27
- package/skills/media-use/scripts/compatibility.test.mjs +96 -0
- package/skills/media-use/scripts/lib/config-lock.mjs +45 -0
- package/skills/media-use/scripts/lib/duck.mjs +16 -10
- package/skills/media-use/scripts/lib/media-fetch.mjs +85 -0
- package/skills/media-use/scripts/lib/media-home.mjs +20 -0
- package/skills/media-use/scripts/lib/npx-sync.mjs +28 -2
- package/skills/media-use/scripts/lib/prefs-store.mjs +2 -2
- package/skills/media-use/scripts/lib/recipe-store.mjs +2 -2
- package/skills/media-use/scripts/lib/telemetry.mjs +29 -41
- package/skills/media-use/scripts/lib/transcriptCutFade.mjs +21 -0
- package/skills/media-use/scripts/prefs.mjs +1 -1
- package/skills/media-use/scripts/recipe.mjs +1 -1
- package/skills/media-use/scripts/resolve-plugin.test.mjs +62 -0
- package/skills/media-use/scripts/resolve.mjs +27 -1267
- package/skills/media-use/scripts/transcribe.mjs +39 -25
- package/skills/media-use/scripts/transcribe.test.mjs +112 -0
- package/skills/media-use/scripts/transcript-cut.mjs +39 -8
- package/skills/media-use/scripts/transcript-cut.test.mjs +117 -0
- package/skills/motion-graphics/SKILL.md +3 -1
- package/skills/motion-graphics/agents/builder.md +1 -0
- package/skills/motion-graphics/agents/director.md +2 -1
- package/skills/motion-graphics/catalog-map.md +25 -13
- package/skills/motion-graphics/categories/charts/module.md +2 -1
- package/skills/motion-graphics/categories/lower-thirds/module.md +4 -0
- package/skills/motion-graphics/categories/news/module.md +1 -1
- package/skills/motion-graphics/references/motion-vocabulary.md +4 -0
- package/skills/music-to-video/SKILL.md +8 -6
- package/skills/music-to-video/references/montage.md +3 -6
- package/skills/music-to-video/references/motion-primitives/3d-card-flip/index.html +10 -111
- package/skills/music-to-video/references/motion-primitives/3d-card-flip/scene.html +119 -0
- package/skills/music-to-video/references/motion-primitives/bg-flow-field/index.html +11 -284
- package/skills/music-to-video/references/motion-primitives/bg-flow-field/scene.html +294 -0
- package/skills/music-to-video/references/motion-primitives/binary-decrypt/index.html +10 -76
- package/skills/music-to-video/references/motion-primitives/binary-decrypt/scene.html +85 -0
- package/skills/music-to-video/references/motion-primitives/blur-resolve/index.html +10 -52
- package/skills/music-to-video/references/motion-primitives/blur-resolve/scene.html +60 -0
- package/skills/music-to-video/references/motion-primitives/braam-punch/index.html +10 -92
- package/skills/music-to-video/references/motion-primitives/braam-punch/scene.html +100 -0
- package/skills/music-to-video/references/motion-primitives/chromatic-split/index.html +10 -103
- package/skills/music-to-video/references/motion-primitives/chromatic-split/scene.html +111 -0
- package/skills/music-to-video/references/motion-primitives/chrome-sweep/index.html +10 -60
- package/skills/music-to-video/references/motion-primitives/chrome-sweep/scene.html +68 -0
- package/skills/music-to-video/references/motion-primitives/counting-punch/index.html +10 -110
- package/skills/music-to-video/references/motion-primitives/counting-punch/scene.html +119 -0
- package/skills/music-to-video/references/motion-primitives/crash-zoom-in/index.html +10 -112
- package/skills/music-to-video/references/motion-primitives/crash-zoom-in/scene.html +120 -0
- package/skills/music-to-video/references/motion-primitives/datamosh-smear/index.html +10 -121
- package/skills/music-to-video/references/motion-primitives/datamosh-smear/scene.html +131 -0
- package/skills/music-to-video/references/motion-primitives/directional-fill/index.html +10 -90
- package/skills/music-to-video/references/motion-primitives/directional-fill/scene.html +103 -0
- package/skills/music-to-video/references/motion-primitives/dolly-zoom/index.html +10 -94
- package/skills/music-to-video/references/motion-primitives/dolly-zoom/scene.html +102 -0
- package/skills/music-to-video/references/motion-primitives/electric-arc/index.html +10 -100
- package/skills/music-to-video/references/motion-primitives/electric-arc/scene.html +105 -0
- package/skills/music-to-video/references/motion-primitives/flash-cut/index.html +10 -89
- package/skills/music-to-video/references/motion-primitives/flash-cut/scene.html +97 -0
- package/skills/music-to-video/references/motion-primitives/gooey-metaball/index.html +10 -197
- package/skills/music-to-video/references/motion-primitives/gooey-metaball/scene.html +206 -0
- package/skills/music-to-video/references/motion-primitives/hard-cut/index.html +10 -74
- package/skills/music-to-video/references/motion-primitives/hard-cut/scene.html +82 -0
- package/skills/music-to-video/references/motion-primitives/hypercut-whip/index.html +10 -36
- package/skills/music-to-video/references/motion-primitives/hypercut-whip/scene.html +44 -0
- package/skills/music-to-video/references/motion-primitives/iris-open/index.html +10 -61
- package/skills/music-to-video/references/motion-primitives/iris-open/scene.html +69 -0
- package/skills/music-to-video/references/motion-primitives/kinetic-letter-in/index.html +10 -55
- package/skills/music-to-video/references/motion-primitives/kinetic-letter-in/scene.html +64 -0
- package/skills/music-to-video/references/motion-primitives/liquid-morph/index.html +10 -88
- package/skills/music-to-video/references/motion-primitives/liquid-morph/scene.html +96 -0
- package/skills/music-to-video/references/motion-primitives/mask-reveal/index.html +10 -66
- package/skills/music-to-video/references/motion-primitives/mask-reveal/scene.html +74 -0
- package/skills/music-to-video/references/motion-primitives/mosaic-pack/index.html +10 -81
- package/skills/music-to-video/references/motion-primitives/mosaic-pack/scene.html +89 -0
- package/skills/music-to-video/references/motion-primitives/neon-flicker/index.html +10 -65
- package/skills/music-to-video/references/motion-primitives/neon-flicker/scene.html +73 -0
- package/skills/music-to-video/references/motion-primitives/outline-to-fill/index.html +10 -74
- package/skills/music-to-video/references/motion-primitives/outline-to-fill/scene.html +82 -0
- package/skills/music-to-video/references/motion-primitives/palette-flip/index.html +10 -89
- package/skills/music-to-video/references/motion-primitives/palette-flip/scene.html +97 -0
- package/skills/music-to-video/references/motion-primitives/particle-burst/index.html +10 -98
- package/skills/music-to-video/references/motion-primitives/particle-burst/scene.html +106 -0
- package/skills/music-to-video/references/motion-primitives/pixel-dissolve/index.html +10 -78
- package/skills/music-to-video/references/motion-primitives/pixel-dissolve/scene.html +86 -0
- package/skills/music-to-video/references/motion-primitives/radial-burst-lines/index.html +10 -117
- package/skills/music-to-video/references/motion-primitives/radial-burst-lines/scene.html +130 -0
- package/skills/music-to-video/references/motion-primitives/screen-shake/index.html +10 -70
- package/skills/music-to-video/references/motion-primitives/screen-shake/scene.html +78 -0
- package/skills/music-to-video/references/motion-primitives/slot-machine-reveal/index.html +10 -87
- package/skills/music-to-video/references/motion-primitives/slot-machine-reveal/scene.html +100 -0
- package/skills/music-to-video/references/motion-primitives/spotlight-sweep/index.html +10 -94
- package/skills/music-to-video/references/motion-primitives/spotlight-sweep/scene.html +102 -0
- package/skills/music-to-video/references/motion-primitives/staggered-exit/index.html +10 -74
- package/skills/music-to-video/references/motion-primitives/staggered-exit/scene.html +82 -0
- package/skills/music-to-video/references/motion-primitives/text-spectral-rays/index.html +11 -271
- package/skills/music-to-video/references/motion-primitives/text-spectral-rays/scene.html +280 -0
- package/skills/music-to-video/references/motion-primitives/text-wave-distort/index.html +10 -92
- package/skills/music-to-video/references/motion-primitives/text-wave-distort/scene.html +106 -0
- package/skills/music-to-video/references/motion-primitives/tile-mosaic/index.html +10 -101
- package/skills/music-to-video/references/motion-primitives/tile-mosaic/scene.html +109 -0
- package/skills/music-to-video/references/motion-primitives/typewriter-reveal/index.html +10 -79
- package/skills/music-to-video/references/motion-primitives/typewriter-reveal/scene.html +91 -0
- package/skills/music-to-video/references/motion-primitives/word-grid-burst/index.html +10 -83
- package/skills/music-to-video/references/motion-primitives/word-grid-burst/scene.html +96 -0
- package/skills/music-to-video/references/planning.md +2 -2
- package/skills/music-to-video/scripts/lib/storyboard.mjs +1 -1
- package/skills/music-to-video/sub-agents/frame-worker.md +2 -2
- package/skills/pr-to-video/SKILL.md +20 -16
- package/skills/pr-to-video/references/code-vocabulary.md +14 -12
- package/skills/pr-to-video/references/story-design.md +1 -1
- package/skills/pr-to-video/scripts/assemble-index.mjs +6 -4
- package/skills/pr-to-video/scripts/assemble-index.test.mjs +57 -2
- package/skills/pr-to-video/scripts/audio.mjs +2 -0
- package/skills/pr-to-video/scripts/build-frame.mjs +6 -3
- package/skills/pr-to-video/scripts/captions.mjs +7 -4
- package/skills/pr-to-video/scripts/captions.test.mjs +41 -0
- package/skills/pr-to-video/scripts/frame-packets.mjs +4 -4
- package/skills/pr-to-video/scripts/lib/bgm-volume.mjs +4 -0
- package/skills/pr-to-video/scripts/lib/captured-fonts.mjs +58 -0
- package/skills/pr-to-video/scripts/lib/frame-packets-core.mjs +194 -0
- package/skills/pr-to-video/scripts/lib/storyboard.mjs +1 -1
- package/skills/pr-to-video/scripts/lib/transitions.json +3 -3
- package/skills/pr-to-video/scripts/transitions.mjs +7 -5
- package/skills/pr-to-video/sub-agents/frame-worker.md +1 -1
- package/skills/product-launch-video/SKILL.md +20 -16
- package/skills/product-launch-video/references/story-design.md +1 -1
- package/skills/product-launch-video/scripts/assemble-index.mjs +6 -4
- package/skills/product-launch-video/scripts/assemble-index.test.mjs +57 -2
- package/skills/product-launch-video/scripts/audio.mjs +2 -0
- package/skills/product-launch-video/scripts/audio.test.mjs +16 -0
- package/skills/product-launch-video/scripts/build-frame-subsets.test.mjs +152 -0
- package/skills/product-launch-video/scripts/build-frame.mjs +6 -3
- package/skills/product-launch-video/scripts/captions.mjs +7 -4
- package/skills/product-launch-video/scripts/frame-packets.mjs +4 -4
- package/skills/product-launch-video/scripts/lib/bgm-volume.mjs +4 -0
- package/skills/product-launch-video/scripts/lib/captured-fonts.mjs +58 -0
- package/skills/product-launch-video/scripts/lib/frame-packets-core.mjs +194 -0
- package/skills/product-launch-video/scripts/lib/storyboard.mjs +1 -1
- package/skills/product-launch-video/scripts/lib/transitions.json +3 -3
- package/skills/product-launch-video/scripts/transitions.mjs +7 -5
- package/skills/product-launch-video/scripts/transitions.test.mjs +68 -0
- package/skills/product-launch-video/sub-agents/frame-worker.md +1 -1
- package/skills/remotion-to-hyperframes/SKILL.md +7 -4
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/expected.json +5 -5
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/hf-src/compositions/title.html +31 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/hf-src/index.html +10 -25
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/README.md +8 -8
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/expected.json +9 -9
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/compositions/scene-1.html +35 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/compositions/scene-2.html +35 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/compositions/scene-3.html +36 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/index.html +28 -71
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/expected.json +3 -3
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/compositions/scene-1.html +52 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/compositions/scene-2.html +99 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/compositions/scene-3.html +55 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/index.html +13 -212
- package/skills/remotion-to-hyperframes/references/api-map.md +16 -16
- package/skills/remotion-to-hyperframes/references/limitations.md +7 -7
- package/skills/remotion-to-hyperframes/references/lottie.md +5 -7
- package/skills/remotion-to-hyperframes/references/media.md +3 -3
- package/skills/remotion-to-hyperframes/references/parameters.md +5 -0
- package/skills/remotion-to-hyperframes/references/sequencing.md +71 -18
- package/skills/slideshow/SKILL.md +4 -1
- package/skills/slideshow/references/standalone-harness.md +0 -3
- package/skills/talking-head-recut/SKILL.md +10 -1
- package/skills/hyperframes-core/references/review-loop.md +0 -41
- package/skills/media-use/scripts/lib/adopt.mjs +0 -128
- package/skills/media-use/scripts/lib/adopt.test.mjs +0 -95
- package/skills/media-use/scripts/lib/bgm-provider.mjs +0 -20
- package/skills/media-use/scripts/lib/brand-provider.mjs +0 -59
- package/skills/media-use/scripts/lib/bundled-sfx-provider.mjs +0 -108
- package/skills/media-use/scripts/lib/bundled-sfx-provider.test.mjs +0 -85
- package/skills/media-use/scripts/lib/cache.mjs +0 -150
- package/skills/media-use/scripts/lib/candidates.mjs +0 -91
- package/skills/media-use/scripts/lib/candidates.test.mjs +0 -155
- package/skills/media-use/scripts/lib/codex-provider.mjs +0 -161
- package/skills/media-use/scripts/lib/codex-provider.test.mjs +0 -34
- package/skills/media-use/scripts/lib/coverage.test.mjs +0 -117
- package/skills/media-use/scripts/lib/cube-build.mjs +0 -181
- package/skills/media-use/scripts/lib/cube-build.test.mjs +0 -80
- package/skills/media-use/scripts/lib/cube-validate.mjs +0 -198
- package/skills/media-use/scripts/lib/cube-validate.test.mjs +0 -125
- package/skills/media-use/scripts/lib/cutlist.test.mjs +0 -148
- package/skills/media-use/scripts/lib/duck.test.mjs +0 -118
- package/skills/media-use/scripts/lib/error-diffusion.test.mjs +0 -102
- package/skills/media-use/scripts/lib/freeze.mjs +0 -70
- package/skills/media-use/scripts/lib/freeze.test.mjs +0 -46
- package/skills/media-use/scripts/lib/grade-analyzer.mjs +0 -264
- package/skills/media-use/scripts/lib/grade-analyzer.test.mjs +0 -285
- package/skills/media-use/scripts/lib/heygen-cli.mjs +0 -191
- package/skills/media-use/scripts/lib/heygen-cli.test.mjs +0 -301
- package/skills/media-use/scripts/lib/heygen-search.mjs +0 -45
- package/skills/media-use/scripts/lib/heygen-search.test.mjs +0 -49
- package/skills/media-use/scripts/lib/heygen-video-provider.mjs +0 -127
- package/skills/media-use/scripts/lib/heygen-video-provider.test.mjs +0 -344
- package/skills/media-use/scripts/lib/image-provider.mjs +0 -44
- package/skills/media-use/scripts/lib/local-models.mjs +0 -318
- package/skills/media-use/scripts/lib/local-models.test.mjs +0 -220
- package/skills/media-use/scripts/lib/local-run.mjs +0 -78
- package/skills/media-use/scripts/lib/local-run.test.mjs +0 -121
- package/skills/media-use/scripts/lib/logo-provider.mjs +0 -222
- package/skills/media-use/scripts/lib/logo-provider.test.mjs +0 -137
- package/skills/media-use/scripts/lib/ltx-video-provider.mjs +0 -94
- package/skills/media-use/scripts/lib/ltx-video-provider.test.mjs +0 -316
- package/skills/media-use/scripts/lib/lut-preset-provider.mjs +0 -266
- package/skills/media-use/scripts/lib/lut-preset-provider.test.mjs +0 -176
- package/skills/media-use/scripts/lib/manifest.test.mjs +0 -388
- package/skills/media-use/scripts/lib/match.mjs +0 -47
- package/skills/media-use/scripts/lib/mflux-provider.mjs +0 -128
- package/skills/media-use/scripts/lib/mflux-provider.test.mjs +0 -174
- package/skills/media-use/scripts/lib/misses.mjs +0 -49
- package/skills/media-use/scripts/lib/misses.test.mjs +0 -78
- package/skills/media-use/scripts/lib/npx-sync.test.mjs +0 -50
- package/skills/media-use/scripts/lib/parakeet-words.test.mjs +0 -44
- package/skills/media-use/scripts/lib/prefs-store.test.mjs +0 -189
- package/skills/media-use/scripts/lib/probe.mjs +0 -39
- package/skills/media-use/scripts/lib/probe.test.mjs +0 -31
- package/skills/media-use/scripts/lib/providers.mjs +0 -5
- package/skills/media-use/scripts/lib/recipe-store.test.mjs +0 -367
- package/skills/media-use/scripts/lib/registry.mjs +0 -218
- package/skills/media-use/scripts/lib/registry.test.mjs +0 -261
- package/skills/media-use/scripts/lib/search.mjs +0 -24
- package/skills/media-use/scripts/lib/search.test.mjs +0 -32
- package/skills/media-use/scripts/lib/sfx-provider.mjs +0 -23
- package/skills/media-use/scripts/lib/specs.mjs +0 -132
- package/skills/media-use/scripts/lib/specs.test.mjs +0 -157
- package/skills/media-use/scripts/lib/stats.mjs +0 -117
- package/skills/media-use/scripts/lib/stats.test.mjs +0 -165
- package/skills/media-use/scripts/lib/telemetry.test.mjs +0 -373
- package/skills/media-use/scripts/lib/tts-local-provider.mjs +0 -92
- package/skills/media-use/scripts/lib/tts-local-provider.test.mjs +0 -72
- package/skills/media-use/scripts/lib/usage.mjs +0 -57
- package/skills/media-use/scripts/lib/usage.test.mjs +0 -54
- package/skills/media-use/scripts/lib/voice-provider.mjs +0 -57
- package/skills/media-use/scripts/lib/voice-provider.test.mjs +0 -46
- package/skills/media-use/scripts/resolve.test.mjs +0 -1120
- /package/skills/{hyperframes-core → hyperframes}/references/subagent-dispatch.md +0 -0
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
// Provider registry — the v2 contract.
|
|
2
|
-
//
|
|
3
|
-
// Each media type maps to an ORDERED list of provider entries. Providers are
|
|
4
|
-
// tried in order; the first to return a non-null result wins, which keeps
|
|
5
|
-
// resolution deterministic (same request -> same provider -> same file ->
|
|
6
|
-
// reproducible renders). heygen-CLI is always first for the types it serves.
|
|
7
|
-
//
|
|
8
|
-
// An entry exposes any of three capability methods — search / generate /
|
|
9
|
-
// process — plus { name }. media-use holds no keys; each external tool owns its
|
|
10
|
-
// own auth. Providers, by type:
|
|
11
|
-
// - heygen CLI: catalog + TTS, first for every type it serves (OAuth free
|
|
12
|
-
// allowance first, then the user's HeyGen billing path)
|
|
13
|
-
// - mflux: local FLUX-class image gen, spec-selected to the machine's RAM
|
|
14
|
-
// (free, private, offline once cached)
|
|
15
|
-
// - codex CLI: image gen on the user's ChatGPT sub — the better-quality upsell
|
|
16
|
-
// and the fallback when no local model fits
|
|
17
|
-
// - Kokoro (via the hyperframes CLI): local voiceover, free/private fallback
|
|
18
|
-
// when HeyGen credentials are absent or --local-only is requested
|
|
19
|
-
//
|
|
20
|
-
// Generation is local-first, cloud-upsell. `ctx.provider` forces one provider
|
|
21
|
-
// (e.g. "make an image with codex").
|
|
22
|
-
|
|
23
|
-
import { bgmProvider } from "./bgm-provider.mjs";
|
|
24
|
-
import { sfxProvider } from "./sfx-provider.mjs";
|
|
25
|
-
import { bundledSfxProvider } from "./bundled-sfx-provider.mjs";
|
|
26
|
-
import { imageProvider, iconProvider } from "./image-provider.mjs";
|
|
27
|
-
import { brandProvider } from "./brand-provider.mjs";
|
|
28
|
-
import {
|
|
29
|
-
svglSearch,
|
|
30
|
-
simpleIconsSearch,
|
|
31
|
-
githubAvatarSearch,
|
|
32
|
-
faviconSearch,
|
|
33
|
-
} from "./logo-provider.mjs";
|
|
34
|
-
import { heygenTtsGenerate } from "./voice-provider.mjs";
|
|
35
|
-
import { heygenVideoGenerate } from "./heygen-video-provider.mjs";
|
|
36
|
-
import { ltxVideoGenerate } from "./ltx-video-provider.mjs";
|
|
37
|
-
import { localTtsGenerate } from "./tts-local-provider.mjs";
|
|
38
|
-
import { codexImageGenerate } from "./codex-provider.mjs";
|
|
39
|
-
import { mfluxImageGenerate } from "./mflux-provider.mjs";
|
|
40
|
-
|
|
41
|
-
// Provider markers: `network` = hits a remote service (skipped by --local-only).
|
|
42
|
-
// `paid` = may cost wallet credits after any OAuth/web-plan free allowance
|
|
43
|
-
// (documentation for the agent's cost judgment, X4: agent-initiated paid should
|
|
44
|
-
// confirm). HeyGen catalog SEARCH is free; HeyGen TTS is free for eligible
|
|
45
|
-
// OAuth CLI users up to the monthly allowance, then follows the user's billing.
|
|
46
|
-
const A = (name, caps) => ({ name, ...caps }); // local, free
|
|
47
|
-
const N = (name, caps) => ({ name, network: true, ...caps }); // remote, free
|
|
48
|
-
const P = (name, caps) => ({ name, network: true, paid: true, ...caps }); // remote, paid
|
|
49
|
-
|
|
50
|
-
// heygen-CLI first. All remote providers are skipped by --local-only.
|
|
51
|
-
const REGISTRY = {
|
|
52
|
-
bgm: [N("heygen.audio.sounds", { search: bgmProvider.search })],
|
|
53
|
-
sfx: [
|
|
54
|
-
N("heygen.audio.sounds", { search: sfxProvider.search }),
|
|
55
|
-
A("bundled.sfx", { search: bundledSfxProvider.search }),
|
|
56
|
-
],
|
|
57
|
-
image: [
|
|
58
|
-
N("heygen.asset.search", { search: imageProvider.search }),
|
|
59
|
-
// Catalog miss -> generate. Local first (best FLUX-class model the machine's
|
|
60
|
-
// RAM can run, spec-selected; free, private, kept under --local-only), then
|
|
61
|
-
// the codex CLI on the user's ChatGPT sub as the better-quality upsell and
|
|
62
|
-
// the fallback when no local model fits.
|
|
63
|
-
A("mflux.local", { generate: mfluxImageGenerate }),
|
|
64
|
-
N("codex.image_gen", { generate: codexImageGenerate }),
|
|
65
|
-
],
|
|
66
|
-
icon: [N("heygen.asset.search", { search: iconProvider.search })],
|
|
67
|
-
logo: [
|
|
68
|
-
// Official brand marks. Tiers verified by a 54-brand stress test (100%
|
|
69
|
-
// cascade hit); HeyGen asset search is deliberately absent — it returns
|
|
70
|
-
// generic look-alike icons for brand queries. All free, all network →
|
|
71
|
-
// --local-only leaves only the cache rungs.
|
|
72
|
-
N("svgl", { search: svglSearch }),
|
|
73
|
-
N("simple-icons", { search: simpleIconsSearch }),
|
|
74
|
-
N("github.avatar", { search: githubAvatarSearch }),
|
|
75
|
-
N("favicon.ddg", { search: faviconSearch }),
|
|
76
|
-
],
|
|
77
|
-
voice: [
|
|
78
|
-
// HeyGen TTS first when credentialed so CLI/OAuth users consume the free
|
|
79
|
-
// web-plan allowance (10 min/month) before any paid path. --local-only skips
|
|
80
|
-
// it and keeps Kokoro as the private/offline fallback.
|
|
81
|
-
// Deliberately kept `paid` (X4 confirm-before-call) even though the first
|
|
82
|
-
// 10 min/month are free: the client can't know the remaining allowance, so
|
|
83
|
-
// confirming is safer than risking a silent charge once it's spent. (A
|
|
84
|
-
// tri-state "quota-first, paid after" would need backend quota state.)
|
|
85
|
-
P("heygen.tts", { generate: heygenTtsGenerate }),
|
|
86
|
-
A("kokoro.local", { generate: localTtsGenerate }),
|
|
87
|
-
],
|
|
88
|
-
video: [
|
|
89
|
-
// HeyGen avatar video first when credentialed; --local-only skips it and
|
|
90
|
-
// keeps LTX as the local fallback.
|
|
91
|
-
P("heygen.video", { generate: heygenVideoGenerate }),
|
|
92
|
-
A("ltx.local", { generate: ltxVideoGenerate }),
|
|
93
|
-
],
|
|
94
|
-
brand: [
|
|
95
|
-
// Local design spec, not heygen — reads frame.md / design.md tokens.
|
|
96
|
-
A("design_spec", { search: brandProvider.search }),
|
|
97
|
-
],
|
|
98
|
-
grade: [
|
|
99
|
-
// Local deterministic cascade handled by resolve.mjs so grade records can
|
|
100
|
-
// carry an inline block as well as an optional frozen .cube file.
|
|
101
|
-
A("color_grade.local", { search: async () => null, generate: async () => null }),
|
|
102
|
-
],
|
|
103
|
-
lut: [
|
|
104
|
-
// Lower-level local LUT generation/freezing path handled by resolve.mjs.
|
|
105
|
-
A("cube_lut.local", { search: async () => null, generate: async () => null }),
|
|
106
|
-
],
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
function listFor(type) {
|
|
110
|
-
const list = REGISTRY[type];
|
|
111
|
-
if (!list) throw new Error(`unknown media type: ${type}`);
|
|
112
|
-
return list;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/** Ordered providers for a type. */
|
|
116
|
-
export function getProviders(type) {
|
|
117
|
-
return listFor(type);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/** All declared media types. */
|
|
121
|
-
export function listTypes() {
|
|
122
|
-
return Object.keys(REGISTRY);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/** Provider names available for a type, in cascade order (for --provider validation). */
|
|
126
|
-
export function providerNamesFor(type) {
|
|
127
|
-
return listFor(type).map((p) => p.name);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* name -> cost tier ("local" | "network_free" | "network_paid") over a collection
|
|
132
|
-
* of ordered provider lists, i.e. the A / N / P distinction the constructors above
|
|
133
|
-
* already declare. Exported so the conflict rule below is testable against a
|
|
134
|
-
* fixture; production reads the REGISTRY-wide index built from it.
|
|
135
|
-
*
|
|
136
|
-
* A name declared under two media types must carry the same tier in both. If it
|
|
137
|
-
* didn't, "did this resolve cost credit" would depend on which type happened to
|
|
138
|
-
* serve it, and the telemetry property would mean nothing — so this throws at
|
|
139
|
-
* import rather than silently picking one.
|
|
140
|
-
*/
|
|
141
|
-
export function buildProviderTierIndex(providerLists) {
|
|
142
|
-
const tiers = new Map();
|
|
143
|
-
for (const list of providerLists) {
|
|
144
|
-
for (const p of list) {
|
|
145
|
-
const tier = p.paid ? "network_paid" : p.network ? "network_free" : "local";
|
|
146
|
-
const prior = tiers.get(p.name);
|
|
147
|
-
if (prior && prior !== tier)
|
|
148
|
-
throw new Error(
|
|
149
|
-
`provider "${p.name}" is declared ${prior} under one media type and ${tier} under another`,
|
|
150
|
-
);
|
|
151
|
-
tiers.set(p.name, tier);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return tiers;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const PROVIDER_TIERS = buildProviderTierIndex(Object.values(REGISTRY));
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Cost tier of a provider by name, or undefined for a name the registry doesn't
|
|
161
|
-
* declare. The registry stays the single owner of "does this cost credit", so
|
|
162
|
-
* dashboards and callers never re-derive it from provider-name string matching.
|
|
163
|
-
*/
|
|
164
|
-
export function providerTierFor(name) {
|
|
165
|
-
return PROVIDER_TIERS.get(name);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Does an override token (full name like "codex.image_gen" or a prefix like
|
|
170
|
-
* "codex") match any provider declared for the type? Same match rule as
|
|
171
|
-
* runProviders, so validation and dispatch never disagree.
|
|
172
|
-
*/
|
|
173
|
-
export function providerMatches(type, want) {
|
|
174
|
-
return providerNamesFor(type).some((n) => n === want || n.startsWith(`${want}.`));
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Back-compat shim for the v1 single-provider API. Returns the first declared
|
|
179
|
-
* provider for the type (tagged with `type`); throws for an unknown type.
|
|
180
|
-
* Kept for v1 callers only — new code should use getProviders/runCapability.
|
|
181
|
-
*/
|
|
182
|
-
export function getProvider(type) {
|
|
183
|
-
const first = listFor(type)[0] || {};
|
|
184
|
-
return { ...first, type };
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Run a capability across an explicit ordered provider list. Tries each in
|
|
189
|
-
* order, returns the first non-null result, skips providers that don't expose
|
|
190
|
-
* the capability. Pure over its input — the unit-testable core of the cascade.
|
|
191
|
-
*
|
|
192
|
-
* Offline guard: a `network` provider is skipped when `ctx.localOnly` is set —
|
|
193
|
-
* unconditionally, even under a `ctx.provider` override. --local-only is a hard
|
|
194
|
-
* safety flag: it must never make a network call. Forcing a network provider
|
|
195
|
-
* while offline yields a clean miss (the caller explains the conflict), never a
|
|
196
|
-
* silent network request.
|
|
197
|
-
* Provider override: `ctx.provider` (a full name like "codex.image_gen" or a
|
|
198
|
-
* prefix like "codex") pins resolution to matching providers only — this is how
|
|
199
|
-
* a user "make an image WITH codex" forces the upsell instead of taking the
|
|
200
|
-
* free-first default.
|
|
201
|
-
*/
|
|
202
|
-
export async function runProviders(providers, capability, intent, ctx) {
|
|
203
|
-
const want = ctx?.provider;
|
|
204
|
-
for (const p of providers) {
|
|
205
|
-
if (want && p.name !== want && !p.name.startsWith(`${want}.`)) continue;
|
|
206
|
-
if (p.network && ctx?.localOnly) continue; // --local-only wins, even over --provider
|
|
207
|
-
const fn = p[capability];
|
|
208
|
-
if (typeof fn !== "function") continue;
|
|
209
|
-
const res = await fn(intent, ctx);
|
|
210
|
-
if (res) return res;
|
|
211
|
-
}
|
|
212
|
-
return null;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/** Run a capability over the providers for a type (deterministic, heygen-first). */
|
|
216
|
-
export async function runCapability(type, capability, intent, ctx) {
|
|
217
|
-
return runProviders(getProviders(type), capability, intent, ctx);
|
|
218
|
-
}
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import { strict as assert } from "node:assert";
|
|
2
|
-
import { test } from "node:test";
|
|
3
|
-
import {
|
|
4
|
-
getProviders,
|
|
5
|
-
getProvider,
|
|
6
|
-
listTypes,
|
|
7
|
-
providerMatches,
|
|
8
|
-
providerNamesFor,
|
|
9
|
-
runProviders,
|
|
10
|
-
runCapability,
|
|
11
|
-
providerTierFor,
|
|
12
|
-
buildProviderTierIndex,
|
|
13
|
-
} from "./registry.mjs";
|
|
14
|
-
|
|
15
|
-
// --- registry shape -------------------------------------------------------
|
|
16
|
-
|
|
17
|
-
test("listTypes exposes the v2 media types", () => {
|
|
18
|
-
const types = listTypes();
|
|
19
|
-
for (const t of [
|
|
20
|
-
"bgm",
|
|
21
|
-
"sfx",
|
|
22
|
-
"image",
|
|
23
|
-
"icon",
|
|
24
|
-
"logo",
|
|
25
|
-
"voice",
|
|
26
|
-
"video",
|
|
27
|
-
"brand",
|
|
28
|
-
"grade",
|
|
29
|
-
"lut",
|
|
30
|
-
]) {
|
|
31
|
-
assert.ok(types.includes(t), `missing type: ${t}`);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test("heygen provider is first for every type it serves", () => {
|
|
36
|
-
for (const t of ["bgm", "sfx", "image", "icon"]) {
|
|
37
|
-
const first = getProviders(t)[0];
|
|
38
|
-
assert.ok(first, `no enabled provider for ${t}`);
|
|
39
|
-
assert.match(first.name, /^heygen/, `${t} first provider is ${first.name}`);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test("sanctioned providers only: heygen, local mflux/kokoro/ltx, codex, design spec, logo tiers", () => {
|
|
44
|
-
const allowed =
|
|
45
|
-
/^heygen|^bundled\.sfx$|^mflux\.local$|^kokoro\.local$|^ltx\.local$|^codex\.image_gen$|^design_spec$|^svgl$|^simple-icons$|^github\.avatar$|^favicon\.ddg$|^color_grade\.local$|^cube_lut\.local$/;
|
|
46
|
-
for (const t of listTypes()) {
|
|
47
|
-
for (const p of getProviders(t)) {
|
|
48
|
-
assert.ok(allowed.test(p.name), `${t} lists unsanctioned provider: ${p.name}`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test("image cascade: heygen catalog, then local mflux, then the codex upsell", () => {
|
|
54
|
-
const ps = getProviders("image");
|
|
55
|
-
assert.match(ps[0].name, /^heygen/, "heygen catalog first");
|
|
56
|
-
const names = ps.map((p) => p.name);
|
|
57
|
-
const mflux = ps.find((p) => p.name === "mflux.local");
|
|
58
|
-
const codex = ps.find((p) => p.name === "codex.image_gen");
|
|
59
|
-
assert.ok(mflux && typeof mflux.generate === "function", "local mflux registered");
|
|
60
|
-
assert.ok(codex && typeof codex.generate === "function", "codex upsell registered");
|
|
61
|
-
assert.ok(names.indexOf("mflux.local") < names.indexOf("codex.image_gen"), "local before codex");
|
|
62
|
-
assert.ok(!mflux.network, "local mflux is kept under --local-only");
|
|
63
|
-
assert.ok(codex.network, "codex is network (skipped under --local-only)");
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test("voice cascade: HeyGen TTS first, Kokoro remains the local fallback", () => {
|
|
67
|
-
const ps = getProviders("voice");
|
|
68
|
-
assert.equal(ps[0].name, "heygen.tts", "HeyGen TTS is first when credentials exist");
|
|
69
|
-
assert.ok(ps[0].network, "HeyGen TTS is network (skipped under --local-only)");
|
|
70
|
-
assert.ok(ps[0].paid, "HeyGen TTS may bill after the OAuth free allowance");
|
|
71
|
-
assert.equal(ps[1].name, "kokoro.local", "local Kokoro is the offline fallback");
|
|
72
|
-
assert.ok(!ps[1].network, "local Kokoro kept under --local-only");
|
|
73
|
-
assert.ok(!ps[1].paid, "local Kokoro is free");
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test("video cascade: HeyGen first, LTX local fallback, generate-only", async () => {
|
|
77
|
-
assert.deepEqual(providerNamesFor("video"), ["heygen.video", "ltx.local"]);
|
|
78
|
-
assert.equal(providerMatches("video", "ltx.local"), true);
|
|
79
|
-
|
|
80
|
-
const ps = getProviders("video");
|
|
81
|
-
assert.ok(ps[0].network, "HeyGen video is network (skipped under --local-only)");
|
|
82
|
-
assert.ok(ps[0].paid, "HeyGen video may bill after the OAuth free allowance");
|
|
83
|
-
assert.ok(!ps[1].network, "local LTX is kept under --local-only");
|
|
84
|
-
assert.equal(await runCapability("video", "search", "x", {}), null);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test("sfx cascade: HeyGen catalog first, bundled library remains the local fallback", () => {
|
|
88
|
-
const ps = getProviders("sfx");
|
|
89
|
-
assert.equal(ps[0].name, "heygen.audio.sounds");
|
|
90
|
-
assert.ok(ps[0].network, "HeyGen SFX catalog is network-only");
|
|
91
|
-
assert.equal(ps[1].name, "bundled.sfx");
|
|
92
|
-
assert.equal(typeof ps[1].search, "function");
|
|
93
|
-
assert.ok(!ps[1].network, "bundled SFX remain available offline");
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test("ctx.provider forces one generator (e.g. 'make an image WITH codex')", async () => {
|
|
97
|
-
const providers = [
|
|
98
|
-
{ name: "heygen.asset.search", network: true, search: async () => null },
|
|
99
|
-
{ name: "mflux.local", generate: async () => ({ hit: "local" }) },
|
|
100
|
-
{ name: "codex.image_gen", network: true, generate: async () => ({ hit: "codex" }) },
|
|
101
|
-
];
|
|
102
|
-
// no override: local wins (first generate to return non-null)
|
|
103
|
-
assert.deepEqual(await runProviders(providers, "generate", "x", {}), { hit: "local" });
|
|
104
|
-
// override to codex: skip local, use codex even though local would have worked
|
|
105
|
-
assert.deepEqual(await runProviders(providers, "generate", "x", { provider: "codex" }), {
|
|
106
|
-
hit: "codex",
|
|
107
|
-
});
|
|
108
|
-
// override matches the full name too
|
|
109
|
-
assert.deepEqual(
|
|
110
|
-
await runProviders(providers, "generate", "x", { provider: "codex.image_gen" }),
|
|
111
|
-
{ hit: "codex" },
|
|
112
|
-
);
|
|
113
|
-
// --local-only wins even over a forced network provider: no network call,
|
|
114
|
-
// clean miss (the caller surfaces the conflict). A forced LOCAL provider under
|
|
115
|
-
// --local-only still runs.
|
|
116
|
-
assert.equal(
|
|
117
|
-
await runProviders(providers, "generate", "x", { provider: "codex", localOnly: true }),
|
|
118
|
-
null,
|
|
119
|
-
);
|
|
120
|
-
assert.deepEqual(
|
|
121
|
-
await runProviders(providers, "generate", "x", { provider: "mflux", localOnly: true }),
|
|
122
|
-
{ hit: "local" },
|
|
123
|
-
);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
test("getProvider returns the first provider with its type, throws for unknown", () => {
|
|
127
|
-
const p = getProvider("bgm");
|
|
128
|
-
assert.equal(p.type, "bgm");
|
|
129
|
-
assert.equal(typeof p.search, "function");
|
|
130
|
-
assert.throws(() => getProvider("unknown_type"), /unknown media type/);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test("getProviders throws for unknown type", () => {
|
|
134
|
-
assert.throws(() => getProviders("nope"), /unknown media type/);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// --- deterministic capability execution (runProviders core) ---------------
|
|
138
|
-
|
|
139
|
-
test("runProviders calls providers in order and returns the first non-null", async () => {
|
|
140
|
-
const calls = [];
|
|
141
|
-
const providers = [
|
|
142
|
-
{
|
|
143
|
-
name: "a",
|
|
144
|
-
enabled: true,
|
|
145
|
-
search: async () => {
|
|
146
|
-
calls.push("a");
|
|
147
|
-
return null;
|
|
148
|
-
},
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
name: "b",
|
|
152
|
-
enabled: true,
|
|
153
|
-
search: async () => {
|
|
154
|
-
calls.push("b");
|
|
155
|
-
return { hit: "b" };
|
|
156
|
-
},
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
name: "c",
|
|
160
|
-
enabled: true,
|
|
161
|
-
search: async () => {
|
|
162
|
-
calls.push("c");
|
|
163
|
-
return { hit: "c" };
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
];
|
|
167
|
-
const res = await runProviders(providers, "search", "x", {});
|
|
168
|
-
assert.deepEqual(res, { hit: "b" });
|
|
169
|
-
assert.deepEqual(calls, ["a", "b"], "must stop at first non-null, never call c");
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
test("runProviders skips providers missing the requested capability", async () => {
|
|
173
|
-
const providers = [
|
|
174
|
-
{ name: "a", enabled: true /* no search */ },
|
|
175
|
-
{ name: "b", enabled: true, search: async () => ({ hit: "b" }) },
|
|
176
|
-
];
|
|
177
|
-
const res = await runProviders(providers, "search", "x", {});
|
|
178
|
-
assert.deepEqual(res, { hit: "b" });
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
test("runProviders returns null when no provider yields a result", async () => {
|
|
182
|
-
const providers = [{ name: "a", enabled: true, search: async () => null }];
|
|
183
|
-
assert.equal(await runProviders(providers, "search", "x", {}), null);
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
test("runCapability('bgm','process') is null — process slot is graceful when unfilled", async () => {
|
|
187
|
-
assert.equal(await runCapability("bgm", "process", "x", {}), null);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
// --- provider cost tier (telemetry) ---------------------------------------
|
|
191
|
-
|
|
192
|
-
test("providerTierFor reports the registry's own A/N/P declaration", () => {
|
|
193
|
-
assert.equal(providerTierFor("heygen.tts"), "network_paid");
|
|
194
|
-
assert.equal(providerTierFor("heygen.video"), "network_paid");
|
|
195
|
-
assert.equal(providerTierFor("heygen.audio.sounds"), "network_free");
|
|
196
|
-
assert.equal(providerTierFor("heygen.asset.search"), "network_free");
|
|
197
|
-
assert.equal(providerTierFor("codex.image_gen"), "network_free");
|
|
198
|
-
assert.equal(providerTierFor("bundled.sfx"), "local");
|
|
199
|
-
assert.equal(providerTierFor("kokoro.local"), "local");
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
test("providerTierFor agrees across every type that declares the same name", () => {
|
|
203
|
-
// heygen.audio.sounds serves both bgm and sfx; heygen.asset.search serves both
|
|
204
|
-
// image and icon. A name whose tier depended on the media type would make the
|
|
205
|
-
// telemetry property meaningless.
|
|
206
|
-
const byName = new Map();
|
|
207
|
-
for (const type of listTypes()) {
|
|
208
|
-
for (const name of providerNamesFor(type)) {
|
|
209
|
-
const tier = providerTierFor(name);
|
|
210
|
-
assert.ok(tier, `every declared provider has a tier (${type}/${name})`);
|
|
211
|
-
const prior = byName.get(name);
|
|
212
|
-
if (prior) assert.equal(tier, prior, `${name} must carry one tier across types`);
|
|
213
|
-
byName.set(name, tier);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
test("providerTierFor returns undefined for a name the registry does not declare", () => {
|
|
219
|
-
assert.equal(providerTierFor("does.not.exist"), undefined);
|
|
220
|
-
assert.equal(providerTierFor(undefined), undefined);
|
|
221
|
-
assert.equal(providerTierFor(null), undefined);
|
|
222
|
-
assert.equal(providerTierFor(""), undefined);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
test("buildProviderTierIndex throws when one name carries two tiers", () => {
|
|
226
|
-
assert.throws(
|
|
227
|
-
() =>
|
|
228
|
-
buildProviderTierIndex([
|
|
229
|
-
[{ name: "dual", network: true }],
|
|
230
|
-
[{ name: "dual", network: true, paid: true }],
|
|
231
|
-
]),
|
|
232
|
-
/declared network_free under one media type and network_paid under another/,
|
|
233
|
-
);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
test("buildProviderTierIndex accepts the same name repeated at the same tier", () => {
|
|
237
|
-
const index = buildProviderTierIndex([
|
|
238
|
-
[{ name: "same", network: true }],
|
|
239
|
-
[{ name: "same", network: true }],
|
|
240
|
-
]);
|
|
241
|
-
assert.equal(index.get("same"), "network_free");
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
test("--local-only skips every network provider (even free remote ones)", async () => {
|
|
245
|
-
let remoteRan = false;
|
|
246
|
-
const providers = [
|
|
247
|
-
{
|
|
248
|
-
name: "heygen",
|
|
249
|
-
network: true,
|
|
250
|
-
search: async () => {
|
|
251
|
-
remoteRan = true;
|
|
252
|
-
return { hit: "net" };
|
|
253
|
-
},
|
|
254
|
-
},
|
|
255
|
-
{ name: "local", search: async () => ({ hit: "local" }) },
|
|
256
|
-
];
|
|
257
|
-
assert.deepEqual(await runProviders(providers, "search", "x", { localOnly: true }), {
|
|
258
|
-
hit: "local",
|
|
259
|
-
});
|
|
260
|
-
assert.equal(remoteRan, false, "the remote provider must not be called offline");
|
|
261
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// Paginated text search over a manifest (project or global) by id / description
|
|
2
|
-
// / entity. Plain substring match — no vector DB (B4): the agent's own file
|
|
3
|
-
// search covers semantics; this just keeps result pages small enough to not
|
|
4
|
-
// blow the context window.
|
|
5
|
-
|
|
6
|
-
const PAGE = 10;
|
|
7
|
-
|
|
8
|
-
export function searchRecords(records, query, { page = 1, pageSize = PAGE } = {}) {
|
|
9
|
-
const q = String(query || "")
|
|
10
|
-
.trim()
|
|
11
|
-
.toLowerCase();
|
|
12
|
-
const matched = q
|
|
13
|
-
? records.filter((r) =>
|
|
14
|
-
[r.id, r.description, r.entity, r.type].some(
|
|
15
|
-
(f) => f && String(f).toLowerCase().includes(q),
|
|
16
|
-
),
|
|
17
|
-
)
|
|
18
|
-
: records.slice();
|
|
19
|
-
const total = matched.length;
|
|
20
|
-
const pages = Math.max(1, Math.ceil(total / pageSize));
|
|
21
|
-
const p = Math.min(Math.max(1, page), pages);
|
|
22
|
-
const start = (p - 1) * pageSize;
|
|
23
|
-
return { results: matched.slice(start, start + pageSize), total, page: p, pages, pageSize };
|
|
24
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { strict as assert } from "node:assert";
|
|
2
|
-
import { test } from "node:test";
|
|
3
|
-
import { searchRecords } from "./search.mjs";
|
|
4
|
-
|
|
5
|
-
const recs = Array.from({ length: 23 }, (_, i) => ({
|
|
6
|
-
id: `bgm_${i}`,
|
|
7
|
-
type: i % 2 ? "bgm" : "sfx",
|
|
8
|
-
description: i === 5 ? "energetic tech whoosh" : `track ${i}`,
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
test("matches id / description / type, case-insensitively", () => {
|
|
12
|
-
assert.equal(searchRecords(recs, "ENERGETIC").results.length, 1);
|
|
13
|
-
assert.equal(searchRecords(recs, "energetic").results[0].id, "bgm_5");
|
|
14
|
-
assert.ok(searchRecords(recs, "sfx").total > 0);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test("caps page size and reports pagination", () => {
|
|
18
|
-
const r = searchRecords(recs, "", { pageSize: 10 });
|
|
19
|
-
assert.equal(r.results.length, 10, "never returns more than a page");
|
|
20
|
-
assert.equal(r.total, 23);
|
|
21
|
-
assert.equal(r.pages, 3);
|
|
22
|
-
assert.equal(r.page, 1);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test("page navigation returns the right slice, clamps out-of-range", () => {
|
|
26
|
-
assert.equal(searchRecords(recs, "", { page: 3, pageSize: 10 }).results.length, 3);
|
|
27
|
-
assert.equal(searchRecords(recs, "", { page: 99, pageSize: 10 }).page, 3, "clamped to last page");
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test("empty query returns everything (paginated)", () => {
|
|
31
|
-
assert.equal(searchRecords(recs, "").total, 23);
|
|
32
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { heygenSearch } from "./heygen-search.mjs";
|
|
2
|
-
|
|
3
|
-
export const sfxProvider = {
|
|
4
|
-
async search(intent) {
|
|
5
|
-
const results = heygenSearch("audio sounds list", intent, {
|
|
6
|
-
type: "sound_effects",
|
|
7
|
-
minScore: 0.4,
|
|
8
|
-
});
|
|
9
|
-
if (!results) return null;
|
|
10
|
-
const best = results[0];
|
|
11
|
-
return {
|
|
12
|
-
url: best.audio_url,
|
|
13
|
-
source: "search",
|
|
14
|
-
// ext derived from audio_url by resolve.mjs — catalog SFX are .mp3 or .wav
|
|
15
|
-
metadata: {
|
|
16
|
-
description: best.description || best.name || intent,
|
|
17
|
-
duration: best.duration || null,
|
|
18
|
-
provider: "heygen.audio.sounds",
|
|
19
|
-
provenance: { track_id: best.id, score: best.score, query: intent },
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
},
|
|
23
|
-
};
|