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,128 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from "node:child_process";
|
|
2
|
-
import { existsSync, unlinkSync } from "node:fs";
|
|
3
|
-
import { tmpdir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
import { describeDownload, probeSpecs } from "./specs.mjs";
|
|
6
|
-
import { buildArgv, selectModelLadder } from "./local-models.mjs";
|
|
7
|
-
|
|
8
|
-
// Local image generation via mflux (FLUX-on-MLX), the Mac-native runner.
|
|
9
|
-
// Spec-gated: selectModelLadder("imagegen", specs) returns every FLUX-class
|
|
10
|
-
// model the machine's AVAILABLE RAM can actually run (medium FLUX-schnell
|
|
11
|
-
// --low-ram on ~24GB, up to Qwen-Image on 64GB+), best first. When nothing
|
|
12
|
-
// local fits, or no fitting tier can actually run here, this returns null so
|
|
13
|
-
// the registry falls through to the codex image upsell.
|
|
14
|
-
//
|
|
15
|
-
// The official FLUX repos are HF-gated, so the model entries point --path at
|
|
16
|
-
// non-gated community 4-bit re-uploads; the repo is resolved to a local snapshot
|
|
17
|
-
// (hf download, idempotent) because a bare repo id breaks mlx unflatten.
|
|
18
|
-
|
|
19
|
-
// Resolve an HF repo to its local snapshot dir. `hf download` is idempotent and
|
|
20
|
-
// prints the snapshot path as its last line.
|
|
21
|
-
function resolveSnapshot(repo, execFn, pathExists) {
|
|
22
|
-
const out = execFn("hf", ["download", repo], {
|
|
23
|
-
encoding: "utf8",
|
|
24
|
-
timeout: 1_800_000,
|
|
25
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
26
|
-
});
|
|
27
|
-
const path = out?.trim().split(/\r?\n/).pop()?.trim();
|
|
28
|
-
return path && pathExists(path) ? path : null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export async function mfluxImageGenerate(
|
|
32
|
-
intent,
|
|
33
|
-
ctx,
|
|
34
|
-
execFn = execFileSync,
|
|
35
|
-
pathExists = existsSync,
|
|
36
|
-
unlinkFn = unlinkSync,
|
|
37
|
-
) {
|
|
38
|
-
const specs = ctx?.specs || probeSpecs();
|
|
39
|
-
const ladder = selectModelLadder("imagegen", specs, { preferTier: ctx?.preferTier });
|
|
40
|
-
if (!ladder.length) return null; // no local model fits -> codex upsell/fallback
|
|
41
|
-
|
|
42
|
-
// Each attempt mints its own timestamped output path, so a partial artifact
|
|
43
|
-
// from a failed tier is orphaned rather than overwritten - and a lower tier
|
|
44
|
-
// then succeeding hides it. Discard it before demoting. Best-effort: a
|
|
45
|
-
// partial we cannot remove must never mask the real failure.
|
|
46
|
-
const discardPartial = (path) => {
|
|
47
|
-
try {
|
|
48
|
-
if (pathExists(path)) unlinkFn(path);
|
|
49
|
-
} catch {
|
|
50
|
-
// nothing actionable: the generate failure below is the real story
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
// Best tier first, demoting past any tier that cannot run here (runner off
|
|
55
|
-
// PATH, a snapshot that won't download, an OOM) rather than failing local
|
|
56
|
-
// image gen outright. Every demotion is reported, so a quietly smaller model
|
|
57
|
-
// is never mistaken for the tier the machine nominally qualified for.
|
|
58
|
-
for (const model of ladder) {
|
|
59
|
-
const bin = model.invoke.trim().split(/\s+/)[0];
|
|
60
|
-
// Not installed? Surface the exact enable-command (before the model
|
|
61
|
-
// download) so the agent learns the free local path is available instead of
|
|
62
|
-
// silently taking the codex upsell.
|
|
63
|
-
try {
|
|
64
|
-
execFn("which", [bin], { stdio: ["ignore", "ignore", "ignore"] });
|
|
65
|
-
} catch {
|
|
66
|
-
console.error(
|
|
67
|
-
`media-use: local image gen not enabled (\`${bin}\` not on PATH). Install for free on-device FLUX: ${model.install}. Heads up: ${model.id} ${describeDownload(model.sizeMB)}.`,
|
|
68
|
-
);
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const outPath = join(tmpdir(), `media-use-mflux-${process.pid}-${Date.now()}.png`);
|
|
73
|
-
const vars = {
|
|
74
|
-
prompt: intent,
|
|
75
|
-
w: ctx?.width || 512,
|
|
76
|
-
h: ctx?.height || 512,
|
|
77
|
-
seed: ctx?.seed ?? 42,
|
|
78
|
-
out: outPath,
|
|
79
|
-
};
|
|
80
|
-
if (model.repo && model.invoke.includes("{model_path}")) {
|
|
81
|
-
let snap = null;
|
|
82
|
-
let why = `could not resolve a local snapshot of ${model.repo}`;
|
|
83
|
-
try {
|
|
84
|
-
snap = resolveSnapshot(model.repo, execFn, pathExists);
|
|
85
|
-
} catch (err) {
|
|
86
|
-
why = `hf download failed: ${err.stderr?.toString().trim().slice(-200) || err.message}`;
|
|
87
|
-
}
|
|
88
|
-
if (!snap) {
|
|
89
|
-
console.error(`media-use: local image gen (${model.id}): ${why}`);
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
vars.model_path = snap;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const argv = buildArgv(model.invoke, vars);
|
|
96
|
-
argv.shift(); // drop the bin (already validated)
|
|
97
|
-
try {
|
|
98
|
-
execFn(bin, argv, {
|
|
99
|
-
encoding: "utf8",
|
|
100
|
-
timeout: 1_800_000,
|
|
101
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
102
|
-
});
|
|
103
|
-
} catch (err) {
|
|
104
|
-
discardPartial(outPath);
|
|
105
|
-
console.error(
|
|
106
|
-
`media-use: local image gen (${model.id}) failed: ${err.stderr?.toString().trim().slice(-200) || err.message}`,
|
|
107
|
-
);
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
if (!pathExists(outPath)) {
|
|
111
|
-
console.error(
|
|
112
|
-
`media-use: local image gen (${model.id}) exited cleanly but wrote no output file`,
|
|
113
|
-
);
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
return {
|
|
117
|
-
localPath: outPath,
|
|
118
|
-
ext: ".png",
|
|
119
|
-
source: "generated",
|
|
120
|
-
metadata: {
|
|
121
|
-
description: intent,
|
|
122
|
-
provider: `mflux.${model.id}`,
|
|
123
|
-
provenance: { model: model.id, tier: model.tier, prompt: intent },
|
|
124
|
-
},
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import { test } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { mfluxImageGenerate } from "./mflux-provider.mjs";
|
|
4
|
-
|
|
5
|
-
// 40GB clears the 32GB klein tier and the 8GB schnell tier below it; the 64GB
|
|
6
|
-
// qwen tier stays out of reach. Two rungs is what makes demotion observable.
|
|
7
|
-
const bothTiersSpecs = { availableRamMB: 40000, gpu: { present: true } };
|
|
8
|
-
const SNAPSHOT = "/tmp/hf-snapshot";
|
|
9
|
-
|
|
10
|
-
// exec stub covering all three shells-out mflux does: the PATH probe, the
|
|
11
|
-
// idempotent `hf download`, and the generate itself.
|
|
12
|
-
function stubExec({ failGenerateFor = [], failWhichFor = [] } = {}) {
|
|
13
|
-
const calls = [];
|
|
14
|
-
const exec = (...call) => {
|
|
15
|
-
calls.push(call);
|
|
16
|
-
const [bin, argv] = call;
|
|
17
|
-
if (bin === "which") {
|
|
18
|
-
if (failWhichFor.includes(argv[0])) throw new Error("not found");
|
|
19
|
-
return "";
|
|
20
|
-
}
|
|
21
|
-
if (bin === "hf") return `Fetching 6 files...\n${SNAPSHOT}\n`;
|
|
22
|
-
if (failGenerateFor.some((id) => argv.join(" ").includes(id))) {
|
|
23
|
-
const err = new Error("exit 1");
|
|
24
|
-
err.stderr = "mlx.core.metal: out of memory";
|
|
25
|
-
throw err;
|
|
26
|
-
}
|
|
27
|
-
return "";
|
|
28
|
-
};
|
|
29
|
-
return { calls, exec };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const generateCalls = (calls) =>
|
|
33
|
-
calls.filter(([bin]) => bin !== "which" && bin !== "hf").map(([, argv]) => argv.join(" "));
|
|
34
|
-
|
|
35
|
-
test("no local model fits: falls through to the upsell without shelling out", async () => {
|
|
36
|
-
const { calls, exec } = stubExec();
|
|
37
|
-
|
|
38
|
-
const result = await mfluxImageGenerate(
|
|
39
|
-
"a red bicycle",
|
|
40
|
-
{ specs: { availableRamMB: 100, gpu: { present: true } } },
|
|
41
|
-
exec,
|
|
42
|
-
() => true,
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
assert.equal(result, null);
|
|
46
|
-
assert.deepEqual(calls, []);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test("a top tier that cannot run demotes to the next fitting tier", async (t) => {
|
|
50
|
-
const errors = [];
|
|
51
|
-
t.mock.method(console, "error", (message) => errors.push(message));
|
|
52
|
-
const { calls, exec } = stubExec({ failGenerateFor: ["flux2-klein-4b"] });
|
|
53
|
-
|
|
54
|
-
const result = await mfluxImageGenerate(
|
|
55
|
-
"a red bicycle",
|
|
56
|
-
{ specs: bothTiersSpecs },
|
|
57
|
-
exec,
|
|
58
|
-
() => true,
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
assert.ok(result, "the schnell tier still produced an image");
|
|
62
|
-
assert.equal(result.metadata.provider, "mflux.flux-schnell-mflux-q4");
|
|
63
|
-
const generated = generateCalls(calls);
|
|
64
|
-
assert.equal(generated.length, 2, "klein attempted first, then schnell");
|
|
65
|
-
assert.match(generated[0], /flux2-klein-4b/);
|
|
66
|
-
assert.match(generated[1], /--model schnell/);
|
|
67
|
-
assert.equal(errors.length, 1, "the demotion is reported, not silent");
|
|
68
|
-
assert.match(errors[0], /flux2-klein-mflux-q4\) failed/);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test("a snapshot that will not resolve demotes rather than failing outright", async (t) => {
|
|
72
|
-
const errors = [];
|
|
73
|
-
t.mock.method(console, "error", (message) => errors.push(message));
|
|
74
|
-
const calls = [];
|
|
75
|
-
const exec = (...call) => {
|
|
76
|
-
calls.push(call);
|
|
77
|
-
const [bin, argv] = call;
|
|
78
|
-
if (bin === "which") return "";
|
|
79
|
-
// klein's weights won't download; schnell's do
|
|
80
|
-
if (bin === "hf") {
|
|
81
|
-
if (argv[1].includes("FLUX.2-klein")) throw new Error("403 Forbidden");
|
|
82
|
-
return `${SNAPSHOT}\n`;
|
|
83
|
-
}
|
|
84
|
-
return "";
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const result = await mfluxImageGenerate(
|
|
88
|
-
"a red bicycle",
|
|
89
|
-
{ specs: bothTiersSpecs },
|
|
90
|
-
exec,
|
|
91
|
-
() => true,
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
assert.ok(result, "demoted past the ungettable weights");
|
|
95
|
-
assert.equal(result.metadata.provider, "mflux.flux-schnell-mflux-q4");
|
|
96
|
-
assert.equal(errors.length, 1);
|
|
97
|
-
assert.match(errors[0], /hf download failed/);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
test("runner missing from PATH reports the install hint per tier and returns null", async (t) => {
|
|
101
|
-
const errors = [];
|
|
102
|
-
t.mock.method(console, "error", (message) => errors.push(message));
|
|
103
|
-
const { exec } = stubExec({ failWhichFor: ["mflux-generate"] });
|
|
104
|
-
|
|
105
|
-
const result = await mfluxImageGenerate(
|
|
106
|
-
"a red bicycle",
|
|
107
|
-
{ specs: bothTiersSpecs },
|
|
108
|
-
exec,
|
|
109
|
-
() => true,
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
assert.equal(result, null);
|
|
113
|
-
assert.equal(errors.length, 2, "both fitting tiers reported");
|
|
114
|
-
assert.match(errors[0], /uv pip install mflux/);
|
|
115
|
-
// each hint states that tier's download cost before the user commits
|
|
116
|
-
assert.match(errors[0], /GB of weights to/);
|
|
117
|
-
assert.match(errors[1], /GB of weights to/);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// Same per-attempt temp path, same orphaning risk as the LTX provider: a
|
|
121
|
-
// partial png from a failed tier must not survive a lower tier succeeding.
|
|
122
|
-
const outputOf = (argv) => argv[argv.indexOf("--output") + 1];
|
|
123
|
-
const attemptedOutputs = (calls) =>
|
|
124
|
-
calls.filter(([bin]) => bin !== "which" && bin !== "hf").map(([, argv]) => outputOf(argv));
|
|
125
|
-
|
|
126
|
-
test("a failed attempt's partial output is discarded before demoting", async (t) => {
|
|
127
|
-
t.mock.method(console, "error", () => {});
|
|
128
|
-
const unlinked = [];
|
|
129
|
-
const { calls, exec } = stubExec({ failGenerateFor: ["flux2-klein-4b"] });
|
|
130
|
-
|
|
131
|
-
const result = await mfluxImageGenerate(
|
|
132
|
-
"a red bicycle",
|
|
133
|
-
{ specs: bothTiersSpecs },
|
|
134
|
-
exec,
|
|
135
|
-
() => true,
|
|
136
|
-
(path) => unlinked.push(path),
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
assert.ok(result, "the schnell tier still produced an image");
|
|
140
|
-
assert.deepEqual(unlinked, [attemptedOutputs(calls)[0]], "the failed klein partial is removed");
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
test("every tier failing discards every partial, one per attempt", async (t) => {
|
|
144
|
-
t.mock.method(console, "error", () => {});
|
|
145
|
-
const unlinked = [];
|
|
146
|
-
const { calls, exec } = stubExec({ failGenerateFor: ["flux2-klein-4b", "schnell"] });
|
|
147
|
-
|
|
148
|
-
const result = await mfluxImageGenerate(
|
|
149
|
-
"a red bicycle",
|
|
150
|
-
{ specs: bothTiersSpecs },
|
|
151
|
-
exec,
|
|
152
|
-
() => true,
|
|
153
|
-
(path) => unlinked.push(path),
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
assert.equal(result, null);
|
|
157
|
-
assert.deepEqual(unlinked, attemptedOutputs(calls), "nothing is left behind");
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
test("a successful generation is never discarded", async () => {
|
|
161
|
-
const unlinked = [];
|
|
162
|
-
const { exec } = stubExec();
|
|
163
|
-
|
|
164
|
-
const result = await mfluxImageGenerate(
|
|
165
|
-
"a red bicycle",
|
|
166
|
-
{ specs: bothTiersSpecs },
|
|
167
|
-
exec,
|
|
168
|
-
() => true,
|
|
169
|
-
(path) => unlinked.push(path),
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
assert.ok(result);
|
|
173
|
-
assert.deepEqual(unlinked, [], "the returned artifact must survive");
|
|
174
|
-
});
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
|
|
5
|
-
const MISSES_FILE = "misses.jsonl";
|
|
6
|
-
|
|
7
|
-
function missesPath() {
|
|
8
|
-
return join(homedir(), ".media", MISSES_FILE);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function recordMiss({ type, intent, provider_override, local_only }) {
|
|
12
|
-
try {
|
|
13
|
-
const dir = join(homedir(), ".media");
|
|
14
|
-
mkdirSync(dir, { recursive: true });
|
|
15
|
-
appendFileSync(
|
|
16
|
-
join(dir, MISSES_FILE),
|
|
17
|
-
JSON.stringify({
|
|
18
|
-
ts: new Date().toISOString(),
|
|
19
|
-
type,
|
|
20
|
-
intent,
|
|
21
|
-
provider_override: !!provider_override,
|
|
22
|
-
local_only: !!local_only,
|
|
23
|
-
}) + "\n",
|
|
24
|
-
);
|
|
25
|
-
} catch {
|
|
26
|
-
// local miss logging is best-effort; never surface into resolve
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function readMisses() {
|
|
31
|
-
const p = missesPath();
|
|
32
|
-
try {
|
|
33
|
-
if (!existsSync(p)) return [];
|
|
34
|
-
const raw = readFileSync(p, "utf8");
|
|
35
|
-
const records = [];
|
|
36
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
37
|
-
const trimmed = line.trim();
|
|
38
|
-
if (!trimmed) continue;
|
|
39
|
-
try {
|
|
40
|
-
records.push(JSON.parse(trimmed));
|
|
41
|
-
} catch {
|
|
42
|
-
// skip malformed local lines, don't crash stats
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return records;
|
|
46
|
-
} catch {
|
|
47
|
-
return [];
|
|
48
|
-
}
|
|
49
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { strict as assert } from "node:assert";
|
|
2
|
-
import { test } from "node:test";
|
|
3
|
-
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
import { readMisses, recordMiss } from "./misses.mjs";
|
|
7
|
-
|
|
8
|
-
function sandbox() {
|
|
9
|
-
const root = mkdtempSync(join(tmpdir(), "mu-misses-"));
|
|
10
|
-
const home = join(root, "home");
|
|
11
|
-
mkdirSync(home, { recursive: true });
|
|
12
|
-
process.env.HOME = home;
|
|
13
|
-
return { root, home };
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function restoreEnv(saved) {
|
|
17
|
-
for (const k of Object.keys(process.env)) if (!(k in saved)) delete process.env[k];
|
|
18
|
-
Object.assign(process.env, saved);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
test("recordMiss appends a well-formed local miss", () => {
|
|
22
|
-
const savedEnv = { ...process.env };
|
|
23
|
-
const { root, home } = sandbox();
|
|
24
|
-
try {
|
|
25
|
-
recordMiss({ type: "bgm", intent: "moody synth pulse", provider_override: true });
|
|
26
|
-
const misses = readMisses();
|
|
27
|
-
assert.equal(misses.length, 1);
|
|
28
|
-
assert.equal(misses[0].type, "bgm");
|
|
29
|
-
assert.equal(misses[0].intent, "moody synth pulse");
|
|
30
|
-
assert.equal(misses[0].provider_override, true);
|
|
31
|
-
assert.equal(misses[0].local_only, false);
|
|
32
|
-
assert.ok(!Number.isNaN(Date.parse(misses[0].ts)));
|
|
33
|
-
|
|
34
|
-
const raw = readFileSync(join(home, ".media/misses.jsonl"), "utf8");
|
|
35
|
-
assert.match(raw, /moody synth pulse/);
|
|
36
|
-
} finally {
|
|
37
|
-
restoreEnv(savedEnv);
|
|
38
|
-
rmSync(root, { recursive: true, force: true });
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test("recordMiss swallows filesystem failures", () => {
|
|
43
|
-
const savedEnv = { ...process.env };
|
|
44
|
-
const { root, home } = sandbox();
|
|
45
|
-
try {
|
|
46
|
-
writeFileSync(join(home, ".media"), "not a directory");
|
|
47
|
-
assert.doesNotThrow(() =>
|
|
48
|
-
recordMiss({ type: "image", intent: "unwritable", local_only: true }),
|
|
49
|
-
);
|
|
50
|
-
assert.equal(existsSync(join(home, ".media/misses.jsonl")), false);
|
|
51
|
-
} finally {
|
|
52
|
-
restoreEnv(savedEnv);
|
|
53
|
-
rmSync(root, { recursive: true, force: true });
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test("readMisses skips corrupt lines", () => {
|
|
58
|
-
const savedEnv = { ...process.env };
|
|
59
|
-
const { root, home } = sandbox();
|
|
60
|
-
try {
|
|
61
|
-
mkdirSync(join(home, ".media"), { recursive: true });
|
|
62
|
-
writeFileSync(
|
|
63
|
-
join(home, ".media/misses.jsonl"),
|
|
64
|
-
[
|
|
65
|
-
JSON.stringify({ ts: "2026-07-09T00:00:00.000Z", type: "bgm", intent: "one" }),
|
|
66
|
-
"{not json",
|
|
67
|
-
JSON.stringify({ ts: "2026-07-09T00:00:01.000Z", type: "sfx", intent: "two" }),
|
|
68
|
-
].join("\n"),
|
|
69
|
-
);
|
|
70
|
-
assert.deepEqual(
|
|
71
|
-
readMisses().map((miss) => miss.intent),
|
|
72
|
-
["one", "two"],
|
|
73
|
-
);
|
|
74
|
-
} finally {
|
|
75
|
-
restoreEnv(savedEnv);
|
|
76
|
-
rmSync(root, { recursive: true, force: true });
|
|
77
|
-
}
|
|
78
|
-
});
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { test } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { resolveNpxInvocation } from "./npx-sync.mjs";
|
|
4
|
-
|
|
5
|
-
// Coverage parity with tts-local-provider.test.mjs, for the whisper.cpp
|
|
6
|
-
// fallback's call-site shape (transcribe.mjs runWhisper): the same three
|
|
7
|
-
// branches, but with the hard-fail contract — no fallback provider exists,
|
|
8
|
-
// so an unresolvable npx must throw actionably instead of returning null.
|
|
9
|
-
|
|
10
|
-
const envWithNpxCli = {
|
|
11
|
-
npm_execpath: "C:/Program Files/nodejs/node_modules/npm/bin/npm-cli.js",
|
|
12
|
-
npm_node_execpath: "C:/Program Files/nodejs/node.exe",
|
|
13
|
-
};
|
|
14
|
-
const npxCliPath = "C:/Program Files/nodejs/node_modules/npm/bin/npx-cli.js";
|
|
15
|
-
const pathExists = (path) => path === npxCliPath;
|
|
16
|
-
|
|
17
|
-
const WHISPER_ARGV = ["hyperframes", "transcribe", "C:\\media\\input.wav", "--dir", "C:\\work"];
|
|
18
|
-
const WHISPER_OPTS = { stdio: ["ignore", "pipe", "pipe"], timeout: 1_800_000 };
|
|
19
|
-
|
|
20
|
-
test("win32: routes the whisper fallback through node + npx-cli, never bare npx", () => {
|
|
21
|
-
const resolved = resolveNpxInvocation(
|
|
22
|
-
WHISPER_ARGV,
|
|
23
|
-
WHISPER_OPTS,
|
|
24
|
-
"win32",
|
|
25
|
-
envWithNpxCli,
|
|
26
|
-
pathExists,
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
assert.equal(resolved.cmd, envWithNpxCli.npm_node_execpath);
|
|
30
|
-
assert.equal(resolved.args[0], npxCliPath);
|
|
31
|
-
assert.deepEqual(resolved.args.slice(1, 3), ["hyperframes", "transcribe"]);
|
|
32
|
-
// execFileSync options survive the rerouting (the timeout bounds the
|
|
33
|
-
// whisper build/model download; the pipes surface its errors).
|
|
34
|
-
assert.deepEqual(resolved.opts.stdio, ["ignore", "pipe", "pipe"]);
|
|
35
|
-
assert.equal(resolved.opts.timeout, 1_800_000);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test("win32 without a resolvable npx-cli: throws the actionable install hint", () => {
|
|
39
|
-
assert.throws(
|
|
40
|
-
() => resolveNpxInvocation(WHISPER_ARGV, WHISPER_OPTS, "win32", {}, () => false),
|
|
41
|
-
/npx-cli\.js was not found/,
|
|
42
|
-
);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test("non-win32: spawns plain npx unchanged", () => {
|
|
46
|
-
const resolved = resolveNpxInvocation(WHISPER_ARGV, WHISPER_OPTS, "darwin", {}, () => false);
|
|
47
|
-
|
|
48
|
-
assert.equal(resolved.cmd, "npx");
|
|
49
|
-
assert.deepEqual(resolved.args, WHISPER_ARGV);
|
|
50
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { strict as assert } from "node:assert";
|
|
2
|
-
import { test } from "node:test";
|
|
3
|
-
import { mergeTokensToWords } from "./parakeet-words.mjs";
|
|
4
|
-
|
|
5
|
-
test("mergeTokensToWords joins sub-word tokens on the space boundary", () => {
|
|
6
|
-
const parakeet = {
|
|
7
|
-
text: "Hello everyone. Um,",
|
|
8
|
-
sentences: [
|
|
9
|
-
{
|
|
10
|
-
tokens: [
|
|
11
|
-
{ text: " H", start: 0.0, end: 0.24 },
|
|
12
|
-
{ text: "ello", start: 0.24, end: 0.48 },
|
|
13
|
-
{ text: " everyone.", start: 0.48, end: 1.28 },
|
|
14
|
-
{ text: " Um,", start: 1.28, end: 1.92 },
|
|
15
|
-
],
|
|
16
|
-
},
|
|
17
|
-
],
|
|
18
|
-
};
|
|
19
|
-
const { words } = mergeTokensToWords(parakeet);
|
|
20
|
-
assert.deepEqual(words, [
|
|
21
|
-
{ text: "Hello", start: 0.0, end: 0.48 },
|
|
22
|
-
{ text: "everyone.", start: 0.48, end: 1.28 },
|
|
23
|
-
{ text: "Um,", start: 1.28, end: 1.92 },
|
|
24
|
-
]);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test("mergeTokensToWords spans multiple sentences and drops empties", () => {
|
|
28
|
-
const parakeet = {
|
|
29
|
-
text: "Hi there",
|
|
30
|
-
sentences: [
|
|
31
|
-
{ tokens: [{ text: "Hi", start: 0, end: 0.2 }] },
|
|
32
|
-
{ tokens: [{ text: " there", start: 0.5, end: 0.9 }] },
|
|
33
|
-
],
|
|
34
|
-
};
|
|
35
|
-
const { words } = mergeTokensToWords(parakeet);
|
|
36
|
-
assert.equal(words.length, 2);
|
|
37
|
-
assert.equal(words[1].text, "there");
|
|
38
|
-
assert.equal(words[1].start, 0.5);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test("mergeTokensToWords tolerates missing sentences/tokens", () => {
|
|
42
|
-
assert.deepEqual(mergeTokensToWords({}).words, []);
|
|
43
|
-
assert.deepEqual(mergeTokensToWords({ sentences: [{}] }).words, []);
|
|
44
|
-
});
|