@officexapp/vidfarm-devcli 0.21.10
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/.agents/skills/dollarplatoon-skill/SKILL.md +1227 -0
- package/.agents/skills/editor-capabilities/SKILL.md +182 -0
- package/.agents/skills/editor-capabilities/references/re-theme-walkthrough.md +58 -0
- package/.agents/skills/embedded-captions/CATALOG.md +93 -0
- package/.agents/skills/embedded-captions/SKILL.md +286 -0
- package/.agents/skills/embedded-captions/assets/brand/CDPR-fankit-terms.txt +35 -0
- package/.agents/skills/embedded-captions/assets/brand/cyberpunk-widths.json +115 -0
- package/.agents/skills/embedded-captions/assets/fonts/char-widths.json +2211 -0
- package/.agents/skills/embedded-captions/assets/strokefonts/HersheyScript1.svg +242 -0
- package/.agents/skills/embedded-captions/assets/strokefonts/HersheyScriptMed.svg +242 -0
- package/.agents/skills/embedded-captions/dna/README.md +148 -0
- package/.agents/skills/embedded-captions/dna/chrome.json +68 -0
- package/.agents/skills/embedded-captions/dna/cream.json +69 -0
- package/.agents/skills/embedded-captions/dna/documentary.json +62 -0
- package/.agents/skills/embedded-captions/dna/editorial.json +70 -0
- package/.agents/skills/embedded-captions/dna/glitch.json +82 -0
- package/.agents/skills/embedded-captions/dna/ink.json +65 -0
- package/.agents/skills/embedded-captions/dna/keynote.json +62 -0
- package/.agents/skills/embedded-captions/dna/loud.json +75 -0
- package/.agents/skills/embedded-captions/dna/neon.json +58 -0
- package/.agents/skills/embedded-captions/dna/velocity.json +89 -0
- package/.agents/skills/embedded-captions/modes/cinematic/README.md +48 -0
- package/.agents/skills/embedded-captions/modes/cinematic/_archive/champion/spec.md +98 -0
- package/.agents/skills/embedded-captions/modes/cinematic/_archive/champion/template.html +188 -0
- package/.agents/skills/embedded-captions/modes/cinematic/_archive/memory-wall/spec.md +134 -0
- package/.agents/skills/embedded-captions/modes/cinematic/_archive/memory-wall/template.html +179 -0
- package/.agents/skills/embedded-captions/modes/cinematic/_archive/portrait-header/spec.md +81 -0
- package/.agents/skills/embedded-captions/modes/cinematic/_archive/portrait-header/template.html +170 -0
- package/.agents/skills/embedded-captions/modes/cinematic/cinematic-cream/spec.md +16 -0
- package/.agents/skills/embedded-captions/modes/cinematic/cinematic-cream/template.html +226 -0
- package/.agents/skills/embedded-captions/modes/cinematic/engine.html +355 -0
- package/.agents/skills/embedded-captions/modes/standard/_anatomy.md +233 -0
- package/.agents/skills/embedded-captions/modes/standard/_motion.md +192 -0
- package/.agents/skills/embedded-captions/modes/standard/fonts/build-fonts-css.cjs +97 -0
- package/.agents/skills/embedded-captions/references/aesthetic-principles.md +168 -0
- package/.agents/skills/embedded-captions/references/anti-patterns.md +188 -0
- package/.agents/skills/embedded-captions/references/bespoke-vs-presets.md +178 -0
- package/.agents/skills/embedded-captions/references/caption-grouping.md +130 -0
- package/.agents/skills/embedded-captions/references/composition-craft.md +522 -0
- package/.agents/skills/embedded-captions/references/direction-catalog.md +138 -0
- package/.agents/skills/embedded-captions/references/example-renders/champion.html +371 -0
- package/.agents/skills/embedded-captions/references/example-renders/memory-wall.html +334 -0
- package/.agents/skills/embedded-captions/references/failure-modes.md +145 -0
- package/.agents/skills/embedded-captions/references/layout-heuristics.md +238 -0
- package/.agents/skills/embedded-captions/references/motion-vocabulary.md +148 -0
- package/.agents/skills/embedded-captions/references/rail.md +68 -0
- package/.agents/skills/embedded-captions/references/reference-bar.md +47 -0
- package/.agents/skills/embedded-captions/references/scene-types.md +94 -0
- package/.agents/skills/embedded-captions/references/test-set.md +66 -0
- package/.agents/skills/embedded-captions/references/typographic-moves.md +266 -0
- package/.agents/skills/embedded-captions/references/typography-presets.md +63 -0
- package/.agents/skills/embedded-captions/scripts/audio-envelope.cjs +95 -0
- package/.agents/skills/embedded-captions/scripts/check-occlusion.cjs +250 -0
- package/.agents/skills/embedded-captions/scripts/check-overflow.cjs +194 -0
- package/.agents/skills/embedded-captions/scripts/check-rail-climax.cjs +233 -0
- package/.agents/skills/embedded-captions/scripts/check-timing.cjs +173 -0
- package/.agents/skills/embedded-captions/scripts/fill-timings.cjs +124 -0
- package/.agents/skills/embedded-captions/scripts/fit-fonts.cjs +158 -0
- package/.agents/skills/embedded-captions/scripts/gen-stroke-path.py +46 -0
- package/.agents/skills/embedded-captions/scripts/inject-fonts.cjs +169 -0
- package/.agents/skills/embedded-captions/scripts/lib-dna.cjs +201 -0
- package/.agents/skills/embedded-captions/scripts/make-cinematic.cjs +1205 -0
- package/.agents/skills/embedded-captions/scripts/make-composition.cjs +404 -0
- package/.agents/skills/embedded-captions/scripts/make-theme.cjs +8781 -0
- package/.agents/skills/embedded-captions/scripts/matte.cjs +294 -0
- package/.agents/skills/embedded-captions/scripts/measure-layout.cjs +293 -0
- package/.agents/skills/embedded-captions/scripts/prepare.sh +39 -0
- package/.agents/skills/embedded-captions/scripts/preview-frames.cjs +268 -0
- package/.agents/skills/embedded-captions/scripts/render-and-composite.sh +509 -0
- package/.agents/skills/embedded-captions/scripts/render-theme.sh +34 -0
- package/.agents/skills/embedded-captions/scripts/safe-zones.cjs +813 -0
- package/.agents/skills/embedded-captions/scripts/transcribe.cjs +349 -0
- package/.agents/skills/embedded-captions/themes/PORTING.md +49 -0
- package/.agents/skills/embedded-captions/themes/README.md +244 -0
- package/.agents/skills/embedded-captions/themes/anchor.json +27 -0
- package/.agents/skills/embedded-captions/themes/arcade.json +51 -0
- package/.agents/skills/embedded-captions/themes/aurora.json +41 -0
- package/.agents/skills/embedded-captions/themes/biolume.json +35 -0
- package/.agents/skills/embedded-captions/themes/brush.json +74 -0
- package/.agents/skills/embedded-captions/themes/chalkboard.json +52 -0
- package/.agents/skills/embedded-captions/themes/dossier.json +56 -0
- package/.agents/skills/embedded-captions/themes/graffiti.json +62 -0
- package/.agents/skills/embedded-captions/themes/hologram.json +41 -0
- package/.agents/skills/embedded-captions/themes/inkwater.json +43 -0
- package/.agents/skills/embedded-captions/themes/laser.json +46 -0
- package/.agents/skills/embedded-captions/themes/lastpage.json +33 -0
- package/.agents/skills/embedded-captions/themes/neonsign.json +53 -0
- package/.agents/skills/embedded-captions/themes/nightcity.json +56 -0
- package/.agents/skills/embedded-captions/themes/ordnance.json +54 -0
- package/.agents/skills/embedded-captions/themes/papercut.json +37 -0
- package/.agents/skills/embedded-captions/themes/popup.json +46 -0
- package/.agents/skills/embedded-captions/themes/ransom.json +62 -0
- package/.agents/skills/embedded-captions/themes/scoreboard.json +54 -0
- package/.agents/skills/embedded-captions/themes/spectrum.json +46 -0
- package/.agents/skills/embedded-captions/themes/stardust.json +29 -0
- package/.agents/skills/embedded-captions/themes/stomp.json +43 -0
- package/.agents/skills/embedded-captions/themes/terminal.json +49 -0
- package/.agents/skills/embedded-captions/themes/thunder.json +44 -0
- package/.agents/skills/embedded-captions/themes/transit.json +44 -0
- package/.agents/skills/embedded-captions/themes/vhs.json +47 -0
- package/.agents/skills/faceless-explainer/SKILL.md +209 -0
- package/.agents/skills/faceless-explainer/references/cut-catalog.md +215 -0
- package/.agents/skills/faceless-explainer/references/motion-language.md +156 -0
- package/.agents/skills/faceless-explainer/references/story-design.md +248 -0
- package/.agents/skills/faceless-explainer/references/visual-design.md +146 -0
- package/.agents/skills/faceless-explainer/scripts/assemble-index.mjs +570 -0
- package/.agents/skills/faceless-explainer/scripts/audio.mjs +260 -0
- package/.agents/skills/faceless-explainer/scripts/build-frame.mjs +536 -0
- package/.agents/skills/faceless-explainer/scripts/captions.mjs +508 -0
- package/.agents/skills/faceless-explainer/scripts/lib/assets.mjs +55 -0
- package/.agents/skills/faceless-explainer/scripts/lib/dimensions.mjs +45 -0
- package/.agents/skills/faceless-explainer/scripts/lib/storyboard.mjs +249 -0
- package/.agents/skills/faceless-explainer/scripts/lib/tokens.mjs +204 -0
- package/.agents/skills/faceless-explainer/scripts/lib/transition-registry.mjs +38 -0
- package/.agents/skills/faceless-explainer/scripts/lib/transitions.json +71 -0
- package/.agents/skills/faceless-explainer/scripts/transitions.mjs +320 -0
- package/.agents/skills/faceless-explainer/sub-agents/frame-worker.md +75 -0
- package/.agents/skills/farmville-saas-ux/SKILL.md +156 -0
- package/.agents/skills/farmville-saas-ux/assets/starter.html +294 -0
- package/.agents/skills/farmville-saas-ux/references/components.md +340 -0
- package/.agents/skills/farmville-saas-ux/references/porting-guide.md +121 -0
- package/.agents/skills/farmville-saas-ux/references/tokens.md +271 -0
- package/.agents/skills/flockposter/LICENSE +17 -0
- package/.agents/skills/flockposter/README.md +72 -0
- package/.agents/skills/flockposter/SKILL.md +562 -0
- package/.agents/skills/flockposter/examples/cli-instagram-reel.sh +21 -0
- package/.agents/skills/flockposter/examples/cli-multi-platform.json +69 -0
- package/.agents/skills/flockposter/examples/cli-tiktok-upload-only.sh +22 -0
- package/.agents/skills/flockposter/examples/cli-x-thread.sh +17 -0
- package/.agents/skills/flockposter/examples/cli-youtube-short.sh +21 -0
- package/.agents/skills/flockposter/examples/public-api-instagram-reel.json +28 -0
- package/.agents/skills/general-video/SKILL.md +143 -0
- package/.agents/skills/hyperframes/SKILL.md +160 -0
- package/.agents/skills/hyperframes-animation/SKILL.md +84 -0
- package/.agents/skills/hyperframes-animation/adapters/animate-text.md +64 -0
- package/.agents/skills/hyperframes-animation/adapters/animejs.md +114 -0
- package/.agents/skills/hyperframes-animation/adapters/css-animations.md +143 -0
- package/.agents/skills/hyperframes-animation/adapters/gsap-easing-and-stagger.md +118 -0
- package/.agents/skills/hyperframes-animation/adapters/gsap-timeline-and-labels.md +96 -0
- package/.agents/skills/hyperframes-animation/adapters/gsap-transforms-and-perf.md +96 -0
- package/.agents/skills/hyperframes-animation/adapters/gsap.md +105 -0
- package/.agents/skills/hyperframes-animation/adapters/html-in-canvas-patterns.md +507 -0
- package/.agents/skills/hyperframes-animation/adapters/lottie.md +117 -0
- package/.agents/skills/hyperframes-animation/adapters/three.md +131 -0
- package/.agents/skills/hyperframes-animation/adapters/typegpu.md +178 -0
- package/.agents/skills/hyperframes-animation/adapters/waapi.md +101 -0
- package/.agents/skills/hyperframes-animation/blueprints/comparison-split.md +27 -0
- package/.agents/skills/hyperframes-animation/blueprints/constellation-hub.md +44 -0
- package/.agents/skills/hyperframes-animation/blueprints/cta-morph-press.md +28 -0
- package/.agents/skills/hyperframes-animation/blueprints/cursor-ui-demo.md +57 -0
- package/.agents/skills/hyperframes-animation/blueprints/dataviz-countup.md +46 -0
- package/.agents/skills/hyperframes-animation/blueprints/device-surface-showcase.md +53 -0
- package/.agents/skills/hyperframes-animation/blueprints/grid-card-assemble.md +66 -0
- package/.agents/skills/hyperframes-animation/blueprints/kinetic-type-beats.md +78 -0
- package/.agents/skills/hyperframes-animation/blueprints/logo-assemble-lockup.md +69 -0
- package/.agents/skills/hyperframes-animation/blueprints/overwhelm-surround.md +28 -0
- package/.agents/skills/hyperframes-animation/blueprints/spatial-pan-stations.md +37 -0
- package/.agents/skills/hyperframes-animation/blueprints/ticker-takeover.md +29 -0
- package/.agents/skills/hyperframes-animation/blueprints/titlecard-reveal.md +42 -0
- package/.agents/skills/hyperframes-animation/blueprints/typewriter-reveal.md +51 -0
- package/.agents/skills/hyperframes-animation/blueprints/video-text-pivot.md +30 -0
- package/.agents/skills/hyperframes-animation/blueprints-index.md +146 -0
- package/.agents/skills/hyperframes-animation/examples/assets/avatars/02.avif +0 -0
- package/.agents/skills/hyperframes-animation/examples/assets/brands/github.avif +0 -0
- package/.agents/skills/hyperframes-animation/examples/assets/brands/nvidia.avif +0 -0
- package/.agents/skills/hyperframes-animation/examples/assets/brands/visa.avif +0 -0
- package/.agents/skills/hyperframes-animation/examples/assets/brands/zoominfo.avif +0 -0
- package/.agents/skills/hyperframes-animation/examples/brand-reveal-assemble-zoom.html +382 -0
- package/.agents/skills/hyperframes-animation/examples/comparison-split-cards.html +649 -0
- package/.agents/skills/hyperframes-animation/examples/concept-demo-decode-pan.html +520 -0
- package/.agents/skills/hyperframes-animation/examples/cta-morph-press.html +468 -0
- package/.agents/skills/hyperframes-animation/examples/cta-orbit-collapse.html +1298 -0
- package/.agents/skills/hyperframes-animation/examples/demo-page-scroll-spotlight.html +759 -0
- package/.agents/skills/hyperframes-animation/examples/hook-counter-burst.html +729 -0
- package/.agents/skills/hyperframes-animation/examples/messaging-multi-phrase.html +352 -0
- package/.agents/skills/hyperframes-animation/examples/metric-video-text-pivot.html +779 -0
- package/.agents/skills/hyperframes-animation/examples/problem-mockup-overwhelm.html +1374 -0
- package/.agents/skills/hyperframes-animation/examples/proof-logo-chain.html +861 -0
- package/.agents/skills/hyperframes-animation/examples/takeover-ticker-displace.html +347 -0
- package/.agents/skills/hyperframes-animation/examples/workflow-approve-press.html +606 -0
- package/.agents/skills/hyperframes-animation/rules/3d-page-scroll.md +227 -0
- package/.agents/skills/hyperframes-animation/rules/3d-text-depth-layers.md +297 -0
- package/.agents/skills/hyperframes-animation/rules/ai-tracking-box.md +382 -0
- package/.agents/skills/hyperframes-animation/rules/ambient-glow-bloom.md +305 -0
- package/.agents/skills/hyperframes-animation/rules/asr-keyword-glow.md +286 -0
- package/.agents/skills/hyperframes-animation/rules/avatar-cloud-network.md +371 -0
- package/.agents/skills/hyperframes-animation/rules/camera-cursor-tracking.md +246 -0
- package/.agents/skills/hyperframes-animation/rules/card-morph-anchor.md +267 -0
- package/.agents/skills/hyperframes-animation/rules/center-outward-expansion.md +227 -0
- package/.agents/skills/hyperframes-animation/rules/context-sensitive-cursor.md +257 -0
- package/.agents/skills/hyperframes-animation/rules/coordinate-target-zoom.md +332 -0
- package/.agents/skills/hyperframes-animation/rules/counting-dynamic-scale.md +283 -0
- package/.agents/skills/hyperframes-animation/rules/css-marker-patterns.md +373 -0
- package/.agents/skills/hyperframes-animation/rules/cursor-click-ripple.md +262 -0
- package/.agents/skills/hyperframes-animation/rules/depth-of-field-blur.md +313 -0
- package/.agents/skills/hyperframes-animation/rules/depth-scatter-assemble.md +303 -0
- package/.agents/skills/hyperframes-animation/rules/discrete-text-sequence.md +273 -0
- package/.agents/skills/hyperframes-animation/rules/dynamic-content-sequencing.md +307 -0
- package/.agents/skills/hyperframes-animation/rules/gsap-effects.md +299 -0
- package/.agents/skills/hyperframes-animation/rules/hacker-flip-3d.md +223 -0
- package/.agents/skills/hyperframes-animation/rules/kinetic-beat-slam.md +183 -0
- package/.agents/skills/hyperframes-animation/rules/motion-blur-streak.md +328 -0
- package/.agents/skills/hyperframes-animation/rules/multi-phase-camera.md +273 -0
- package/.agents/skills/hyperframes-animation/rules/orbit-3d-entry.md +301 -0
- package/.agents/skills/hyperframes-animation/rules/physics-press-reaction.md +350 -0
- package/.agents/skills/hyperframes-animation/rules/press-release-spring.md +296 -0
- package/.agents/skills/hyperframes-animation/rules/reactive-displacement.md +277 -0
- package/.agents/skills/hyperframes-animation/rules/scale-swap-transition.md +298 -0
- package/.agents/skills/hyperframes-animation/rules/sine-wave-loop.md +278 -0
- package/.agents/skills/hyperframes-animation/rules/split-tilt-cards.md +277 -0
- package/.agents/skills/hyperframes-animation/rules/spring-pop-entrance.md +273 -0
- package/.agents/skills/hyperframes-animation/rules/stat-bars-and-fills.md +156 -0
- package/.agents/skills/hyperframes-animation/rules/svg-icon-enrichment.md +329 -0
- package/.agents/skills/hyperframes-animation/rules/svg-path-draw.md +274 -0
- package/.agents/skills/hyperframes-animation/rules/vertical-spring-ticker.md +239 -0
- package/.agents/skills/hyperframes-animation/rules/viewport-change.md +349 -0
- package/.agents/skills/hyperframes-animation/rules-index.md +86 -0
- package/.agents/skills/hyperframes-animation/scripts/animation-map.mjs +606 -0
- package/.agents/skills/hyperframes-animation/scripts/package-loader.mjs +288 -0
- package/.agents/skills/hyperframes-animation/scripts/package-loader.test.mjs +62 -0
- package/.agents/skills/hyperframes-animation/techniques.md +507 -0
- package/.agents/skills/hyperframes-animation/transitions/TRANSITION-REGISTRY.md +167 -0
- package/.agents/skills/hyperframes-animation/transitions/catalog.md +127 -0
- package/.agents/skills/hyperframes-animation/transitions/css-3d.md +12 -0
- package/.agents/skills/hyperframes-animation/transitions/css-blur.md +51 -0
- package/.agents/skills/hyperframes-animation/transitions/css-cover.md +43 -0
- package/.agents/skills/hyperframes-animation/transitions/css-destruction.md +95 -0
- package/.agents/skills/hyperframes-animation/transitions/css-dissolve.md +66 -0
- package/.agents/skills/hyperframes-animation/transitions/css-distortion.md +45 -0
- package/.agents/skills/hyperframes-animation/transitions/css-grid.md +10 -0
- package/.agents/skills/hyperframes-animation/transitions/css-light.md +49 -0
- package/.agents/skills/hyperframes-animation/transitions/css-mechanical.md +30 -0
- package/.agents/skills/hyperframes-animation/transitions/css-other.md +25 -0
- package/.agents/skills/hyperframes-animation/transitions/css-push.md +41 -0
- package/.agents/skills/hyperframes-animation/transitions/css-radial.md +37 -0
- package/.agents/skills/hyperframes-animation/transitions/css-scale.md +24 -0
- package/.agents/skills/hyperframes-animation/transitions/overview.md +153 -0
- package/.agents/skills/hyperframes-cli/SKILL.md +113 -0
- package/.agents/skills/hyperframes-cli/references/doctor-browser.md +45 -0
- package/.agents/skills/hyperframes-cli/references/init-and-scaffold.md +55 -0
- package/.agents/skills/hyperframes-cli/references/lambda.md +132 -0
- package/.agents/skills/hyperframes-cli/references/lint-validate-inspect.md +121 -0
- package/.agents/skills/hyperframes-cli/references/preview-render.md +149 -0
- package/.agents/skills/hyperframes-cli/references/upgrade-info-misc.md +75 -0
- package/.agents/skills/hyperframes-core/SKILL.md +78 -0
- package/.agents/skills/hyperframes-core/references/composition-patterns.md +263 -0
- package/.agents/skills/hyperframes-core/references/data-attributes.md +70 -0
- package/.agents/skills/hyperframes-core/references/determinism-rules.md +68 -0
- package/.agents/skills/hyperframes-core/references/full-screen-motion.md +62 -0
- package/.agents/skills/hyperframes-core/references/minimal-composition.md +66 -0
- package/.agents/skills/hyperframes-core/references/script-format.md +49 -0
- package/.agents/skills/hyperframes-core/references/storyboard-format.md +95 -0
- package/.agents/skills/hyperframes-core/references/sub-compositions.md +237 -0
- package/.agents/skills/hyperframes-core/references/subagent-dispatch.md +41 -0
- package/.agents/skills/hyperframes-core/references/tailwind.md +125 -0
- package/.agents/skills/hyperframes-core/references/tracks-and-clips.md +76 -0
- package/.agents/skills/hyperframes-core/references/variables-and-media.md +90 -0
- package/.agents/skills/hyperframes-creative/SKILL.md +70 -0
- package/.agents/skills/hyperframes-creative/frame-presets/biennale-yellow/FRAME.md +289 -0
- package/.agents/skills/hyperframes-creative/frame-presets/biennale-yellow/caption-skin.html +221 -0
- package/.agents/skills/hyperframes-creative/frame-presets/biennale-yellow/frame-showcase.html +1214 -0
- package/.agents/skills/hyperframes-creative/frame-presets/blockframe/FRAME.md +275 -0
- package/.agents/skills/hyperframes-creative/frame-presets/blockframe/caption-skin.html +224 -0
- package/.agents/skills/hyperframes-creative/frame-presets/blockframe/frame-showcase.html +1347 -0
- package/.agents/skills/hyperframes-creative/frame-presets/blue-professional/FRAME.md +307 -0
- package/.agents/skills/hyperframes-creative/frame-presets/blue-professional/caption-skin.html +223 -0
- package/.agents/skills/hyperframes-creative/frame-presets/blue-professional/frame-showcase.html +1372 -0
- package/.agents/skills/hyperframes-creative/frame-presets/bold-poster/FRAME.md +275 -0
- package/.agents/skills/hyperframes-creative/frame-presets/bold-poster/caption-skin.html +230 -0
- package/.agents/skills/hyperframes-creative/frame-presets/bold-poster/frame-showcase.html +1140 -0
- package/.agents/skills/hyperframes-creative/frame-presets/broadside/FRAME.md +284 -0
- package/.agents/skills/hyperframes-creative/frame-presets/broadside/caption-skin.html +225 -0
- package/.agents/skills/hyperframes-creative/frame-presets/broadside/frame-showcase.html +1166 -0
- package/.agents/skills/hyperframes-creative/frame-presets/capsule/FRAME.md +284 -0
- package/.agents/skills/hyperframes-creative/frame-presets/capsule/caption-skin.html +224 -0
- package/.agents/skills/hyperframes-creative/frame-presets/capsule/frame-showcase.html +1465 -0
- package/.agents/skills/hyperframes-creative/frame-presets/cartesian/FRAME.md +278 -0
- package/.agents/skills/hyperframes-creative/frame-presets/cartesian/caption-skin.html +222 -0
- package/.agents/skills/hyperframes-creative/frame-presets/cartesian/frame-showcase.html +1263 -0
- package/.agents/skills/hyperframes-creative/frame-presets/claude/FRAME.md +277 -0
- package/.agents/skills/hyperframes-creative/frame-presets/claude/caption-skin.html +224 -0
- package/.agents/skills/hyperframes-creative/frame-presets/claude/frame-showcase.html +1439 -0
- package/.agents/skills/hyperframes-creative/frame-presets/cobalt-grid/FRAME.md +265 -0
- package/.agents/skills/hyperframes-creative/frame-presets/cobalt-grid/caption-skin.html +238 -0
- package/.agents/skills/hyperframes-creative/frame-presets/cobalt-grid/frame-showcase.html +1468 -0
- package/.agents/skills/hyperframes-creative/frame-presets/coral/FRAME.md +314 -0
- package/.agents/skills/hyperframes-creative/frame-presets/coral/caption-skin.html +226 -0
- package/.agents/skills/hyperframes-creative/frame-presets/coral/frame-showcase.html +1268 -0
- package/.agents/skills/hyperframes-creative/frame-presets/creative-mode/FRAME.md +333 -0
- package/.agents/skills/hyperframes-creative/frame-presets/creative-mode/caption-skin.html +227 -0
- package/.agents/skills/hyperframes-creative/frame-presets/creative-mode/frame-showcase.html +1330 -0
- package/.agents/skills/hyperframes-creative/frame-presets/daisy-days/FRAME.md +274 -0
- package/.agents/skills/hyperframes-creative/frame-presets/daisy-days/caption-skin.html +230 -0
- package/.agents/skills/hyperframes-creative/frame-presets/daisy-days/frame-showcase.html +1444 -0
- package/.agents/skills/hyperframes-creative/frame-presets/editorial-forest/FRAME.md +265 -0
- package/.agents/skills/hyperframes-creative/frame-presets/editorial-forest/caption-skin.html +223 -0
- package/.agents/skills/hyperframes-creative/frame-presets/editorial-forest/frame-showcase.html +1273 -0
- package/.agents/skills/hyperframes-creative/palettes/bold-energetic.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/clean-corporate.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/dark-premium.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/jewel-rich.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/monochrome.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/nature-earth.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/neon-electric.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/pastel-soft.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/warm-editorial.md +14 -0
- package/.agents/skills/hyperframes-creative/references/audio-reactive.md +76 -0
- package/.agents/skills/hyperframes-creative/references/beat-direction.md +164 -0
- package/.agents/skills/hyperframes-creative/references/composition-patterns.md +199 -0
- package/.agents/skills/hyperframes-creative/references/data-in-motion.md +19 -0
- package/.agents/skills/hyperframes-creative/references/design-adherence.md +19 -0
- package/.agents/skills/hyperframes-creative/references/design-picker.md +123 -0
- package/.agents/skills/hyperframes-creative/references/design-spec.md +55 -0
- package/.agents/skills/hyperframes-creative/references/house-style.md +73 -0
- package/.agents/skills/hyperframes-creative/references/motion-principles.md +150 -0
- package/.agents/skills/hyperframes-creative/references/narration.md +92 -0
- package/.agents/skills/hyperframes-creative/references/prompt-expansion.md +68 -0
- package/.agents/skills/hyperframes-creative/references/typography.md +218 -0
- package/.agents/skills/hyperframes-creative/references/video-composition.md +63 -0
- package/.agents/skills/hyperframes-creative/references/visual-styles.md +457 -0
- package/.agents/skills/hyperframes-creative/scripts/contrast-report.mjs +353 -0
- package/.agents/skills/hyperframes-creative/scripts/extract-audio-data.py +188 -0
- package/.agents/skills/hyperframes-creative/scripts/package-loader.mjs +288 -0
- package/.agents/skills/hyperframes-creative/scripts/package-loader.test.mjs +62 -0
- package/.agents/skills/hyperframes-creative/templates/design-picker.html +1432 -0
- package/.agents/skills/hyperframes-keyframes/SKILL.md +237 -0
- package/.agents/skills/hyperframes-keyframes/agents/openai.yaml +4 -0
- package/.agents/skills/hyperframes-keyframes/references/keyframe-patterns.md +106 -0
- package/.agents/skills/motion-graphics/SKILL.md +172 -0
- package/.agents/skills/motion-graphics/agents/builder.md +40 -0
- package/.agents/skills/motion-graphics/agents/director.md +53 -0
- package/.agents/skills/motion-graphics/agents/finalize.md +17 -0
- package/.agents/skills/motion-graphics/catalog-map.md +40 -0
- package/.agents/skills/motion-graphics/categories/asset-fusion/module.md +37 -0
- package/.agents/skills/motion-graphics/categories/charts/module.md +21 -0
- package/.agents/skills/motion-graphics/categories/kinetic-type/module.md +19 -0
- package/.agents/skills/motion-graphics/categories/logo-reveal/module.md +17 -0
- package/.agents/skills/motion-graphics/categories/lower-thirds/module.md +16 -0
- package/.agents/skills/motion-graphics/categories/maps/bake-basemap.mjs +273 -0
- package/.agents/skills/motion-graphics/categories/maps/module.md +61 -0
- package/.agents/skills/motion-graphics/categories/news/module.md +56 -0
- package/.agents/skills/motion-graphics/categories/stat/module.md +21 -0
- package/.agents/skills/motion-graphics/categories/tweet/module.md +16 -0
- package/.agents/skills/motion-graphics/categories/webpage/module.md +21 -0
- package/.agents/skills/motion-graphics/grounding/PROTOCOL.md +64 -0
- package/.agents/skills/motion-graphics/grounding/locate.mjs +227 -0
- package/.agents/skills/motion-graphics/phases/source/guide.md +21 -0
- package/.agents/skills/motion-graphics/references/builder-contract.md +38 -0
- package/.agents/skills/motion-graphics/references/motion-vocabulary.md +43 -0
- package/.agents/skills/motion-graphics/references/shot-plan-ir.md +54 -0
- package/.agents/skills/motion-graphics/samples/asset-fusion/_ref-circle-highlight.html +306 -0
- package/.agents/skills/music/SKILL.md +416 -0
- package/.agents/skills/music/references/api_reference.md +519 -0
- package/.agents/skills/music/references/installation.md +65 -0
- package/.agents/skills/product-launch-video/SKILL.md +208 -0
- package/.agents/skills/product-launch-video/references/cut-catalog.md +220 -0
- package/.agents/skills/product-launch-video/references/motion-language.md +156 -0
- package/.agents/skills/product-launch-video/references/story-design.md +373 -0
- package/.agents/skills/product-launch-video/references/visual-design.md +126 -0
- package/.agents/skills/product-launch-video/scripts/assemble-index.mjs +570 -0
- package/.agents/skills/product-launch-video/scripts/audio.mjs +260 -0
- package/.agents/skills/product-launch-video/scripts/build-frame.mjs +536 -0
- package/.agents/skills/product-launch-video/scripts/captions.mjs +508 -0
- package/.agents/skills/product-launch-video/scripts/lib/assets.mjs +55 -0
- package/.agents/skills/product-launch-video/scripts/lib/dimensions.mjs +45 -0
- package/.agents/skills/product-launch-video/scripts/lib/pad-frame-duration.mjs +36 -0
- package/.agents/skills/product-launch-video/scripts/lib/pad-frame-duration.test.mjs +76 -0
- package/.agents/skills/product-launch-video/scripts/lib/storyboard.mjs +249 -0
- package/.agents/skills/product-launch-video/scripts/lib/tokens.mjs +204 -0
- package/.agents/skills/product-launch-video/scripts/lib/transition-registry.mjs +38 -0
- package/.agents/skills/product-launch-video/scripts/lib/transitions.json +71 -0
- package/.agents/skills/product-launch-video/scripts/stage-assets.mjs +39 -0
- package/.agents/skills/product-launch-video/scripts/transitions.mjs +327 -0
- package/.agents/skills/product-launch-video/sub-agents/frame-worker.md +75 -0
- package/.agents/skills/slideshow/SKILL.md +550 -0
- package/.agents/skills/slideshow/references/standalone-harness.md +1020 -0
- package/.agents/skills/talking-head-recut/NOTICE.md +39 -0
- package/.agents/skills/talking-head-recut/SKILL.md +1195 -0
- package/.agents/skills/talking-head-recut/assets/vendor/gsap.min.js +10 -0
- package/.agents/skills/talking-head-recut/references/DESIGN_INDEX.md +145 -0
- package/.agents/skills/talking-head-recut/references/frames/clean.html +92 -0
- package/.agents/skills/talking-head-recut/references/frames/hairline.html +171 -0
- package/.agents/skills/talking-head-recut/references/frames/polaroid.html +131 -0
- package/.agents/skills/talking-head-recut/references/layouts/overlay.html +164 -0
- package/.agents/skills/talking-head-recut/references/layouts/pip.html +143 -0
- package/.agents/skills/talking-head-recut/references/layouts/split.html +121 -0
- package/.agents/skills/talking-head-recut/references/layouts/stack.html +109 -0
- package/.agents/skills/talking-head-recut/references/styles/academic.html +172 -0
- package/.agents/skills/talking-head-recut/references/styles/audit.html +170 -0
- package/.agents/skills/talking-head-recut/references/styles/editorial.html +189 -0
- package/.agents/skills/talking-head-recut/references/styles/geom.html +181 -0
- package/.agents/skills/talking-head-recut/references/styles/minimal.html +130 -0
- package/.agents/skills/talking-head-recut/references/styles/spotlight.html +142 -0
- package/.agents/skills/talking-head-recut/references/styles/swiss.html +188 -0
- package/.agents/skills/talking-head-recut/references/styles/terminal.html +196 -0
- package/.agents/skills/talking-head-recut/references/styles/whiteboard.html +170 -0
- package/.agents/skills/talking-head-recut/references/styles/xhs.html +206 -0
- package/.agents/skills/text-to-speech/SKILL.md +226 -0
- package/.agents/skills/text-to-speech/references/installation.md +90 -0
- package/.agents/skills/text-to-speech/references/streaming.md +307 -0
- package/.agents/skills/text-to-speech/references/voice-settings.md +115 -0
- package/.agents/skills/vidfarm-director/SKILL.md +179 -0
- package/.agents/skills/vidfarm-director/recipes/find-and-fork-template.md +16 -0
- package/.agents/skills/vidfarm-director/recipes/local-edit-render-approve.md +13 -0
- package/.agents/skills/vidfarm-director/recipes/onboard-a-new-director.md +13 -0
- package/.agents/skills/vidfarm-director/recipes/retheme-template.md +17 -0
- package/.agents/skills/vidfarm-director/references/assets-and-sourcing.md +117 -0
- package/.agents/skills/vidfarm-director/references/automation-and-local-dev.md +276 -0
- package/.agents/skills/vidfarm-director/references/core-workflows.md +301 -0
- package/.agents/skills/vidfarm-director/references/editor-workflows.md +367 -0
- package/.agents/skills/vidfarm-director/references/onboarding.md +28 -0
- package/.agents/skills/vidfarm-director/references/primitives.md +307 -0
- package/.agents/skills/vidfarm-director/references/rest-api.md +84 -0
- package/.agents/skills/vidfarm-media/SKILL.md +158 -0
- package/.agents/skills/vidfarm-media/references/tts.md +111 -0
- package/.agents/skills/vidfarm-media/scripts/audio.mjs +628 -0
- package/.agents/skills/vidfarm-media/scripts/wait-bgm.mjs +31 -0
- package/.agents/skills/website-to-video/SKILL.md +145 -0
- package/.agents/skills/website-to-video/assets/sfx/CREDITS.md +35 -0
- package/.agents/skills/website-to-video/assets/sfx/manifest.json +97 -0
- package/.agents/skills/website-to-video/references/beat-builder-guide.md +263 -0
- package/.agents/skills/website-to-video/references/capabilities.md +713 -0
- package/.agents/skills/website-to-video/references/step-0-capture.md +55 -0
- package/.agents/skills/website-to-video/references/step-1-design.md +333 -0
- package/.agents/skills/website-to-video/references/step-2-brief.md +178 -0
- package/.agents/skills/website-to-video/references/step-3-storyboard.md +572 -0
- package/.agents/skills/website-to-video/references/step-4-vo.md +225 -0
- package/.agents/skills/website-to-video/references/step-5-build.md +483 -0
- package/.agents/skills/website-to-video/references/step-6-validate.md +341 -0
- package/.agents/skills/website-to-video/scripts/w2h-verify.mjs +759 -0
- package/README.md +97 -0
- package/SKILL.director.md +1644 -0
- package/SKILL.md +83 -0
- package/demo/README.md +28 -0
- package/demo/dist/app.css +1 -0
- package/demo/dist/app.js +968 -0
- package/demo/dist/chunks/chunk-3OT2D42H.js +1 -0
- package/demo/dist/chunks/chunk-DXB73IDG.js +1 -0
- package/demo/dist/chunks/domEditingLayers-AT7G6F4L-ZTHJHB7R.js +1 -0
- package/demo/dist/chunks/hyperframes-player-7HKH6NSO.js +459 -0
- package/demo/dist/chunks/lib-XAQ37YOE.js +1 -0
- package/demo/dist/chunks/src-TJ2QYA4U.js +207 -0
- package/demo/dist/favicon.ico +0 -0
- package/demo/dist/icons/timeline/audio.svg +7 -0
- package/demo/dist/icons/timeline/captions.svg +5 -0
- package/demo/dist/icons/timeline/composition.svg +12 -0
- package/demo/dist/icons/timeline/image.svg +18 -0
- package/demo/dist/icons/timeline/music.svg +10 -0
- package/demo/dist/icons/timeline/text.svg +3 -0
- package/demo/dist/index.html +16 -0
- package/dist/src/cli.js +7258 -0
- package/dist/src/devcli/auth-store.js +67 -0
- package/dist/src/devcli/captions.js +310 -0
- package/dist/src/devcli/clip-store.js +368 -0
- package/dist/src/devcli/clips.js +1138 -0
- package/dist/src/devcli/composition-edit.js +1292 -0
- package/dist/src/devcli/cost-mode.js +149 -0
- package/dist/src/devcli/doctor.js +192 -0
- package/dist/src/devcli/hyperframes-cli.js +118 -0
- package/dist/src/devcli/local-backend.js +167 -0
- package/dist/src/devcli/local-frontend-server.js +681 -0
- package/dist/src/devcli/local-render.js +136 -0
- package/dist/src/devcli/skills.js +476 -0
- package/dist/src/devcli/speech.js +178 -0
- package/dist/src/devcli/stills.js +249 -0
- package/dist/src/devcli/telemetry.js +236 -0
- package/dist/src/devcli/timeline-edit.js +490 -0
- package/dist/src/devcli/transitions.js +205 -0
- package/dist/src/hyperframes/composition.js +780 -0
- package/dist/src/lib/crypto.js +45 -0
- package/dist/src/lib/dev-log.js +54 -0
- package/dist/src/lib/display-name.js +11 -0
- package/dist/src/lib/ids.js +24 -0
- package/dist/src/lib/images.js +19 -0
- package/dist/src/lib/json.js +15 -0
- package/dist/src/lib/package-root.js +47 -0
- package/dist/src/lib/render-media-prep.js +293 -0
- package/dist/src/lib/template-paths.js +28 -0
- package/dist/src/lib/time.js +7 -0
- package/dist/src/lib/url-clean.js +85 -0
- package/dist/src/services/captions.js +123 -0
- package/dist/src/services/clip-curation/cost.js +116 -0
- package/dist/src/services/clip-curation/ffmpeg.js +352 -0
- package/dist/src/services/clip-curation/gemini.js +418 -0
- package/dist/src/services/clip-curation/hunt.js +470 -0
- package/dist/src/services/clip-curation/index.js +19 -0
- package/dist/src/services/clip-curation/local-agent.js +248 -0
- package/dist/src/services/clip-curation/media-select.js +152 -0
- package/dist/src/services/clip-curation/presets.js +20 -0
- package/dist/src/services/clip-curation/presets.v1.json +59 -0
- package/dist/src/services/clip-curation/query.js +167 -0
- package/dist/src/services/clip-curation/refine.js +165 -0
- package/dist/src/services/clip-curation/scan.js +189 -0
- package/dist/src/services/clip-curation/source-naming.js +131 -0
- package/dist/src/services/clip-curation/taxonomy.js +73 -0
- package/dist/src/services/clip-curation/taxonomy.v1.json +102 -0
- package/dist/src/services/clip-curation/types.js +7 -0
- package/dist/src/services/composition-lint.js +199 -0
- package/dist/src/services/provider-errors.js +128 -0
- package/dist/src/services/speech.js +629 -0
- package/package.json +154 -0
- package/public/assets/discover-client-app.js +1 -0
- package/public/assets/favicon.ico +0 -0
- package/public/assets/file-directory-app.js +89 -0
- package/public/assets/homepage-app.js +54 -0
- package/public/assets/homepage-client-app.js +80 -0
- package/public/assets/landing-page-client-app.js +87 -0
- package/public/assets/logo-vidfarm.png +0 -0
- package/public/assets/page-runtime-client-app.js +94 -0
- package/public/assets/placeholders/scene-placeholder.png +0 -0
- package/public/serve-shells/editor.html +3146 -0
- package/public/serve-shells/library-files.html +3450 -0
- package/public/serve-shells/library-raws.html +4404 -0
- package/public/serve-shells/tools-clipper.html +3991 -0
- package/public/serve-shells/tools-image.html +5584 -0
- package/public/serve-shells/tools-video.html +4404 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// Local speech engine — devcli-only. `vidfarm tts` / `vidfarm stt` run
|
|
2
|
+
// LOCAL-FIRST on the user's own AI key (GEMINI_API_KEY / OPENAI_API_KEY /
|
|
3
|
+
// OPENROUTER_API_KEY, or the --gemini-key/--openai-key/--openrouter-key flags)
|
|
4
|
+
// by calling the shared speech provider layer (src/services/speech.ts)
|
|
5
|
+
// directly: local ffmpeg for the video→audio demux, the user's key for the
|
|
6
|
+
// model call — no cloud job, no wallet, no REST route. The REST primitive
|
|
7
|
+
// routes (/api/v1/primitives/audio/speech|transcribe) are the explicit
|
|
8
|
+
// `--cloud` BACKUP, mirroring `vidfarm clips scan`.
|
|
9
|
+
//
|
|
10
|
+
// Unlike clip tagging, speech can NOT ride on a claude/codex CLI agent — the
|
|
11
|
+
// agent CLIs have no audio I/O (the same reason embeddings need a real key in
|
|
12
|
+
// local-agent.ts) — so "local" here means a raw provider key, not the agent.
|
|
13
|
+
import { spawn } from "node:child_process";
|
|
14
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
15
|
+
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
16
|
+
import os from "node:os";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import { buildSrtFromSegments, defaultSpeechModelFor, generateSpeechWithKey, transcribeSpeechWithKey } from "../services/speech.js";
|
|
19
|
+
import { resolveFfmpeg } from "../services/clip-curation/ffmpeg.js";
|
|
20
|
+
// Mirrors the env-var fallbacks used by `vidfarm clips` so one exported key
|
|
21
|
+
// powers every local-first devcli surface.
|
|
22
|
+
const PROVIDER_ENV = {
|
|
23
|
+
gemini: ["GEMINI_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
|
|
24
|
+
openai: ["OPENAI_API_KEY"],
|
|
25
|
+
openrouter: ["OPENROUTER_API_KEY"]
|
|
26
|
+
};
|
|
27
|
+
const PROVIDER_FLAG = {
|
|
28
|
+
gemini: "gemini-key",
|
|
29
|
+
openai: "openai-key",
|
|
30
|
+
openrouter: "openrouter-key"
|
|
31
|
+
};
|
|
32
|
+
// Same inline-audio ceiling as the cloud stt primitive (~40min of 64kbps mono).
|
|
33
|
+
export const MAX_LOCAL_TRANSCRIBE_AUDIO_BYTES = 20 * 1024 * 1024;
|
|
34
|
+
/**
|
|
35
|
+
* Find a usable local provider key: an explicit --provider narrows the search,
|
|
36
|
+
* otherwise the first provider (in `preference` order) with a flag/env key
|
|
37
|
+
* wins. Returns null when nothing local is configured (callers point the user
|
|
38
|
+
* at env keys or --cloud).
|
|
39
|
+
*/
|
|
40
|
+
export function resolveLocalSpeechAuth(values, preference, requestedProvider) {
|
|
41
|
+
const providers = requestedProvider
|
|
42
|
+
? [normalizeSpeechProvider(requestedProvider)]
|
|
43
|
+
: preference;
|
|
44
|
+
for (const provider of providers) {
|
|
45
|
+
const flagged = values[PROVIDER_FLAG[provider]];
|
|
46
|
+
if (typeof flagged === "string" && flagged.trim()) {
|
|
47
|
+
return { provider, apiKey: flagged.trim() };
|
|
48
|
+
}
|
|
49
|
+
for (const envName of PROVIDER_ENV[provider]) {
|
|
50
|
+
const fromEnv = process.env[envName]?.trim();
|
|
51
|
+
if (fromEnv) {
|
|
52
|
+
return { provider, apiKey: fromEnv };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
export function normalizeSpeechProvider(value) {
|
|
59
|
+
const normalized = value.trim().toLowerCase();
|
|
60
|
+
if (normalized === "gemini" || normalized === "openai" || normalized === "openrouter") {
|
|
61
|
+
return normalized;
|
|
62
|
+
}
|
|
63
|
+
throw new Error(`Unsupported speech provider "${value}". Use gemini, openai, or openrouter.`);
|
|
64
|
+
}
|
|
65
|
+
/** Local TTS: text → audio bytes on the user's own key. */
|
|
66
|
+
export async function localGenerateSpeech(input) {
|
|
67
|
+
const model = input.model?.trim() || defaultSpeechModelFor("tts", input.auth.provider);
|
|
68
|
+
if (!model) {
|
|
69
|
+
throw new Error(`No TTS model available for provider ${input.auth.provider}.`);
|
|
70
|
+
}
|
|
71
|
+
const result = await generateSpeechWithKey({
|
|
72
|
+
provider: input.auth.provider,
|
|
73
|
+
model,
|
|
74
|
+
text: input.text,
|
|
75
|
+
voice: input.voice,
|
|
76
|
+
instructions: input.instructions,
|
|
77
|
+
responseFormat: input.responseFormat,
|
|
78
|
+
apiKey: input.auth.apiKey
|
|
79
|
+
});
|
|
80
|
+
return { ...result, provider: input.auth.provider, model };
|
|
81
|
+
}
|
|
82
|
+
/** Local STT: audio bytes → transcript (diarized on gemini) on the user's own key.
|
|
83
|
+
* wordTimestamps requests word-level timings (real on openai/whisper-1; other
|
|
84
|
+
* providers stay segment-level and downstream callers estimate word windows). */
|
|
85
|
+
export async function localTranscribeSpeech(input) {
|
|
86
|
+
const model = input.model?.trim() || defaultSpeechModelFor("stt", input.auth.provider);
|
|
87
|
+
if (!model) {
|
|
88
|
+
throw new Error(`No STT model available for provider ${input.auth.provider}.`);
|
|
89
|
+
}
|
|
90
|
+
const result = await transcribeSpeechWithKey({
|
|
91
|
+
provider: input.auth.provider,
|
|
92
|
+
model,
|
|
93
|
+
audio: input.audio,
|
|
94
|
+
contentType: input.contentType,
|
|
95
|
+
prompt: input.prompt,
|
|
96
|
+
language: input.language,
|
|
97
|
+
diarize: input.diarize,
|
|
98
|
+
wordTimestamps: input.wordTimestamps,
|
|
99
|
+
apiKey: input.auth.apiKey
|
|
100
|
+
});
|
|
101
|
+
return { ...result, provider: input.auth.provider, model, srt: buildSrtFromSegments(result.segments) };
|
|
102
|
+
}
|
|
103
|
+
const AUDIO_EXTENSION_CONTENT_TYPES = {
|
|
104
|
+
mp3: "audio/mpeg",
|
|
105
|
+
wav: "audio/wav",
|
|
106
|
+
m4a: "audio/mp4",
|
|
107
|
+
aac: "audio/mp4",
|
|
108
|
+
ogg: "audio/ogg",
|
|
109
|
+
oga: "audio/ogg",
|
|
110
|
+
flac: "audio/flac"
|
|
111
|
+
};
|
|
112
|
+
function audioExtensionOf(target) {
|
|
113
|
+
const match = /\.(mp3|wav|m4a|aac|ogg|oga|flac)(\?|#|$)/i.exec(target);
|
|
114
|
+
return match ? match[1].toLowerCase() : null;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Turn a local path OR http(s) URL — video or audio — into speech-provider
|
|
118
|
+
* ready audio bytes. Plain audio files pass through untouched; everything else
|
|
119
|
+
* (video, unknown containers) is demuxed to small mono mp3 by LOCAL ffmpeg
|
|
120
|
+
* (bundled ffmpeg-static, or PATH), which reads URLs directly.
|
|
121
|
+
*/
|
|
122
|
+
export async function loadSpeechAudioLocally(target) {
|
|
123
|
+
const isUrl = /^https?:\/\//i.test(target);
|
|
124
|
+
if (!isUrl && !existsSync(target)) {
|
|
125
|
+
throw new Error(`No such local file: ${target}`);
|
|
126
|
+
}
|
|
127
|
+
const audioExtension = audioExtensionOf(target);
|
|
128
|
+
if (audioExtension) {
|
|
129
|
+
if (isUrl) {
|
|
130
|
+
const response = await fetch(target);
|
|
131
|
+
if (!response.ok) {
|
|
132
|
+
throw new Error(`Could not fetch source audio (${response.status}).`);
|
|
133
|
+
}
|
|
134
|
+
const contentType = response.headers.get("content-type")?.split(";")[0]?.trim() || AUDIO_EXTENSION_CONTENT_TYPES[audioExtension];
|
|
135
|
+
return { bytes: new Uint8Array(await response.arrayBuffer()), contentType, demuxed: false };
|
|
136
|
+
}
|
|
137
|
+
return { bytes: readFileSync(target), contentType: AUDIO_EXTENSION_CONTENT_TYPES[audioExtension], demuxed: false };
|
|
138
|
+
}
|
|
139
|
+
const ffmpeg = await resolveFfmpeg();
|
|
140
|
+
const tempDir = await mkdtemp(path.join(os.tmpdir(), "vidfarm-stt-"));
|
|
141
|
+
const outputPath = path.join(tempDir, "audio.mp3");
|
|
142
|
+
try {
|
|
143
|
+
await runFfmpegDemux(ffmpeg, target, outputPath);
|
|
144
|
+
return { bytes: await readFile(outputPath), contentType: "audio/mpeg", demuxed: true };
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function runFfmpegDemux(bin, input, outputPath) {
|
|
151
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
152
|
+
const child = spawn(bin, [
|
|
153
|
+
"-hide_banner",
|
|
154
|
+
"-y",
|
|
155
|
+
"-i", input,
|
|
156
|
+
"-vn",
|
|
157
|
+
"-ac", "1",
|
|
158
|
+
"-b:a", "64k",
|
|
159
|
+
outputPath
|
|
160
|
+
], { stdio: ["ignore", "ignore", "pipe"] });
|
|
161
|
+
let stderr = "";
|
|
162
|
+
child.stderr.on("data", (chunk) => (stderr += chunk.toString()));
|
|
163
|
+
child.on("error", (error) => {
|
|
164
|
+
rejectPromise(error.code === "ENOENT"
|
|
165
|
+
? new Error("ffmpeg not found. Install ffmpeg (or `npm i ffmpeg-static`), or run with --cloud to demux on the platform.")
|
|
166
|
+
: error);
|
|
167
|
+
});
|
|
168
|
+
child.on("close", (code) => {
|
|
169
|
+
if (code === 0) {
|
|
170
|
+
resolvePromise();
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
rejectPromise(new Error(`ffmpeg demux exited ${code}: ${stderr.slice(-400)}`));
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=speech.js.map
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
// `vidfarm stills` — render PNG still frames of the CURRENT composition
|
|
2
|
+
// in-process, without a full MP4 render. This is the coding agent's visual
|
|
3
|
+
// self-verification loop: edit composition.html, render 3-8 stills, look at
|
|
4
|
+
// them, iterate.
|
|
5
|
+
//
|
|
6
|
+
// Implementation mirrors HyperframesService.renderStill (src/services/
|
|
7
|
+
// hyperframes.ts): stage the composition as a HyperFrames project dir, drive
|
|
8
|
+
// @hyperframes/producer's createRenderJob/executeRenderJob with the
|
|
9
|
+
// "png-sequence" format, then pick the captured frames nearest each requested
|
|
10
|
+
// timestamp. Deliberately NOT importing HyperframesService — that class drags
|
|
11
|
+
// in config.ts (which mkdirs at import) and the whole cloud-render surface;
|
|
12
|
+
// this is a lean local-file implementation.
|
|
13
|
+
//
|
|
14
|
+
// Cost control: png-sequence captures EVERY frame on the fps grid, so we
|
|
15
|
+
// (a) cap the staged composition's duration at the last requested timestamp
|
|
16
|
+
// and (b) render on a coarse integer fps grid (4fps → 0.25s accuracy, dropped
|
|
17
|
+
// to 2/1fps for long timelines) instead of the composition's native 30fps.
|
|
18
|
+
// Requested timestamps are snapped to that grid; the actually-captured time
|
|
19
|
+
// is reported next to each written PNG.
|
|
20
|
+
import { copyFileSync, cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
21
|
+
import os from "node:os";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
import { parseHTML } from "linkedom";
|
|
24
|
+
import { inspectComposition } from "./composition-edit.js";
|
|
25
|
+
const MAX_DEFAULT_STILLS = 8;
|
|
26
|
+
const MAX_GRID_FRAMES = 600;
|
|
27
|
+
// The in-process producer shells out to ffmpeg/ffprobe resolved from
|
|
28
|
+
// HYPERFRAMES_FFMPEG_PATH / HYPERFRAMES_FFPROBE_PATH (then PATH). Point it at
|
|
29
|
+
// the bundled static binaries, same as src/services/hyperframes.ts does.
|
|
30
|
+
async function ensureProducerFfmpegEnv() {
|
|
31
|
+
if (!process.env.HYPERFRAMES_FFMPEG_PATH?.trim()) {
|
|
32
|
+
try {
|
|
33
|
+
const mod = (await import("ffmpeg-static"));
|
|
34
|
+
const resolved = typeof mod === "string" ? mod : mod.default;
|
|
35
|
+
if (typeof resolved === "string" && resolved && existsSync(resolved)) {
|
|
36
|
+
process.env.HYPERFRAMES_FFMPEG_PATH = resolved;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch { /* PATH fallback */ }
|
|
40
|
+
}
|
|
41
|
+
if (!process.env.HYPERFRAMES_FFPROBE_PATH?.trim()) {
|
|
42
|
+
try {
|
|
43
|
+
const mod = (await import("ffprobe-static"));
|
|
44
|
+
const resolved = (mod.path ?? mod.default?.path);
|
|
45
|
+
if (typeof resolved === "string" && resolved && existsSync(resolved)) {
|
|
46
|
+
process.env.HYPERFRAMES_FFPROBE_PATH = resolved;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch { /* PATH fallback */ }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Default timestamps when --at is omitted: the midpoint of each distinct
|
|
54
|
+
* scene clip on the LOWEST video track (capped at 8), else 0 / mid / end of
|
|
55
|
+
* the composition.
|
|
56
|
+
*/
|
|
57
|
+
export function defaultStillTimestamps(layers, durationSeconds) {
|
|
58
|
+
const isSceneClip = (layer) => layer.duration > 0 && (layer.is_timeline_proxy ||
|
|
59
|
+
layer.kind === "video" ||
|
|
60
|
+
layer.kind === "scene" ||
|
|
61
|
+
(layer.src !== null && /\.(mp4|mov|webm|m4v|mkv)(\?|#|$)/i.test(layer.src)) ||
|
|
62
|
+
// Canvas-filling clips of any kind read as scenes (image scenes,
|
|
63
|
+
// solid/title cards) — overlays/captions are never full-canvas.
|
|
64
|
+
layer.is_full_canvas);
|
|
65
|
+
const scenes = layers.filter(isSceneClip);
|
|
66
|
+
if (scenes.length > 0) {
|
|
67
|
+
const lowestTrack = Math.min(...scenes.map((layer) => layer.track));
|
|
68
|
+
const seen = new Set();
|
|
69
|
+
const midpoints = [];
|
|
70
|
+
for (const layer of scenes.filter((l) => l.track === lowestTrack).sort((a, b) => a.start - b.start)) {
|
|
71
|
+
const key = layer.key || `${layer.start}-${layer.duration}`;
|
|
72
|
+
if (seen.has(key))
|
|
73
|
+
continue;
|
|
74
|
+
seen.add(key);
|
|
75
|
+
midpoints.push(layer.start + layer.duration / 2);
|
|
76
|
+
if (midpoints.length >= MAX_DEFAULT_STILLS)
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
if (midpoints.length > 0)
|
|
80
|
+
return midpoints;
|
|
81
|
+
}
|
|
82
|
+
if (durationSeconds <= 0)
|
|
83
|
+
return [0];
|
|
84
|
+
return [...new Set([0, durationSeconds / 2, Math.max(0, durationSeconds - 0.5)])];
|
|
85
|
+
}
|
|
86
|
+
// Pick the coarsest integer fps grid that keeps capture cheap while staying
|
|
87
|
+
// within 0.25s of any requested timestamp where possible.
|
|
88
|
+
function pickGridFps(maxTimestamp) {
|
|
89
|
+
for (const fps of [4, 2, 1]) {
|
|
90
|
+
if ((maxTimestamp + 1) * fps <= MAX_GRID_FRAMES)
|
|
91
|
+
return fps;
|
|
92
|
+
}
|
|
93
|
+
return 1;
|
|
94
|
+
}
|
|
95
|
+
// Cap the staged copy's root data-duration so the producer never captures
|
|
96
|
+
// frames past the last requested still.
|
|
97
|
+
function capCompositionDuration(html, capSeconds) {
|
|
98
|
+
const { document } = parseHTML(html);
|
|
99
|
+
const root = document.querySelector("[data-composition-id]");
|
|
100
|
+
if (!root)
|
|
101
|
+
throw new Error("Composition root ([data-composition-id]) not found in composition.html.");
|
|
102
|
+
const existing = Number.parseFloat(root.getAttribute("data-duration") ?? "");
|
|
103
|
+
const capped = Number.isFinite(existing) && existing > 0 ? Math.min(existing, capSeconds) : capSeconds;
|
|
104
|
+
root.setAttribute("data-duration", String(Number(capped.toFixed(3))));
|
|
105
|
+
return `<!doctype html>\n${document.documentElement.outerHTML}`;
|
|
106
|
+
}
|
|
107
|
+
// Same guard as renderLocal: libx264-adjacent tooling (and the runtime's
|
|
108
|
+
// canvas sizing) prefers even data-width/data-height.
|
|
109
|
+
function forceEvenDimensions(html) {
|
|
110
|
+
return html.replace(/\bdata-(width|height)=(["'])(\d+)\2/gi, (match, dim, quote, value) => {
|
|
111
|
+
const n = Number.parseInt(value, 10);
|
|
112
|
+
if (!Number.isFinite(n) || n % 2 === 0)
|
|
113
|
+
return match;
|
|
114
|
+
return `data-${dim}=${quote}${n - 1}${quote}`;
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Stage the composition as a HyperFrames project dir: the (duration-capped)
|
|
119
|
+
* composition.html becomes index.html, and every sibling file/dir is copied in
|
|
120
|
+
* so relative asset references keep resolving. Mirrors stageProject in
|
|
121
|
+
* src/services/hyperframes.ts, but against a local composition dir.
|
|
122
|
+
*/
|
|
123
|
+
function stageCompositionProject(htmlPath, stagedHtml) {
|
|
124
|
+
const sourceDir = path.dirname(htmlPath);
|
|
125
|
+
const projectDir = mkdtempSync(path.join(os.tmpdir(), "vidfarm-stills-"));
|
|
126
|
+
writeFileSync(path.join(projectDir, "index.html"), stagedHtml, "utf8");
|
|
127
|
+
for (const entry of readdirSync(sourceDir)) {
|
|
128
|
+
if (entry === path.basename(htmlPath) || entry === "index.html" || entry === "stills")
|
|
129
|
+
continue;
|
|
130
|
+
const from = path.join(sourceDir, entry);
|
|
131
|
+
try {
|
|
132
|
+
const info = statSync(from);
|
|
133
|
+
if (info.isDirectory()) {
|
|
134
|
+
cpSync(from, path.join(projectDir, entry), { recursive: true, force: true });
|
|
135
|
+
}
|
|
136
|
+
else if (info.isFile()) {
|
|
137
|
+
copyFileSync(from, path.join(projectDir, entry));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// best-effort: a missing/unreadable sibling never blocks the stills
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return projectDir;
|
|
145
|
+
}
|
|
146
|
+
export async function renderCompositionStills(input) {
|
|
147
|
+
const html = readFileSync(input.htmlPath, "utf8");
|
|
148
|
+
if (!html.includes("data-composition-id=")) {
|
|
149
|
+
throw new Error(`stills requires composition HTML with data-composition-id (${input.htmlPath}).`);
|
|
150
|
+
}
|
|
151
|
+
const info = inspectComposition(html);
|
|
152
|
+
const durationSeconds = info.duration_seconds > 0 ? info.duration_seconds : 1;
|
|
153
|
+
const requested = (input.at && input.at.length > 0
|
|
154
|
+
? input.at
|
|
155
|
+
: defaultStillTimestamps(info.layers, durationSeconds))
|
|
156
|
+
.map((t) => Math.min(Math.max(0, t), Math.max(0, durationSeconds - 0.01)))
|
|
157
|
+
.sort((a, b) => a - b);
|
|
158
|
+
if (requested.length === 0)
|
|
159
|
+
throw new Error("stills: no timestamps to render.");
|
|
160
|
+
const gridFps = pickGridFps(requested[requested.length - 1]);
|
|
161
|
+
const capSeconds = Math.min(durationSeconds, requested[requested.length - 1] + 2 / gridFps);
|
|
162
|
+
await ensureProducerFfmpegEnv();
|
|
163
|
+
const stagedHtml = forceEvenDimensions(capCompositionDuration(html, capSeconds));
|
|
164
|
+
const projectDir = stageCompositionProject(input.htmlPath, stagedHtml);
|
|
165
|
+
const framesDir = mkdtempSync(path.join(os.tmpdir(), "vidfarm-stills-frames-"));
|
|
166
|
+
const outDir = path.resolve(input.outDir ?? path.join(path.dirname(input.htmlPath), "stills"));
|
|
167
|
+
mkdirSync(outDir, { recursive: true });
|
|
168
|
+
// Declarative vidfarm compositions carry no scripts (cloud saves strip
|
|
169
|
+
// them), so they can never satisfy the engine's window.__timelines
|
|
170
|
+
// sub-composition poll — which otherwise stalls capture-session init for the
|
|
171
|
+
// full 45s playerReadyTimeout before proceeding anyway. When the html has no
|
|
172
|
+
// timeline registration at all, cap that wait via the engine's env knob.
|
|
173
|
+
// Compositions that DO register GSAP timelines keep the default.
|
|
174
|
+
const priorReadyTimeout = process.env.PRODUCER_PLAYER_READY_TIMEOUT_MS;
|
|
175
|
+
if (!priorReadyTimeout?.trim() && !stagedHtml.includes("__timelines")) {
|
|
176
|
+
process.env.PRODUCER_PLAYER_READY_TIMEOUT_MS = "10000";
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
// Same producer entry points renderStill uses; "png-sequence" writes the
|
|
180
|
+
// frames dir as frame_000001.png … at 1/gridFps intervals.
|
|
181
|
+
const { createRenderJob, executeRenderJob } = await import("@hyperframes/producer");
|
|
182
|
+
// Quiet mode (--json) swaps in a no-op logger so stdout stays parseable —
|
|
183
|
+
// the producer's default logger writes progress lines to stdout.
|
|
184
|
+
const silentLogger = { error() { }, warn() { }, info() { }, debug() { } };
|
|
185
|
+
const job = createRenderJob({
|
|
186
|
+
fps: gridFps,
|
|
187
|
+
quality: "high",
|
|
188
|
+
format: "png-sequence",
|
|
189
|
+
...(input.quiet ? { logger: silentLogger } : {})
|
|
190
|
+
});
|
|
191
|
+
let lastStatus = null;
|
|
192
|
+
const executeRender = () => executeRenderJob(job, projectDir, framesDir, (progressJob) => {
|
|
193
|
+
if (!input.quiet && progressJob.status !== lastStatus) {
|
|
194
|
+
lastStatus = progressJob.status;
|
|
195
|
+
console.log(`\x1b[2m ${progressJob.status}\x1b[0m`);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
// The engine also logs init/browser lines via console.log directly (they
|
|
199
|
+
// bypass the producer logger); in quiet mode reroute console stdout to
|
|
200
|
+
// stderr for the duration of the render so stdout stays pure JSON.
|
|
201
|
+
const originalConsole = { log: console.log, info: console.info, debug: console.debug };
|
|
202
|
+
if (input.quiet) {
|
|
203
|
+
const toStderr = (...args) => {
|
|
204
|
+
process.stderr.write(`${args.map((value) => (typeof value === "string" ? value : JSON.stringify(value))).join(" ")}\n`);
|
|
205
|
+
};
|
|
206
|
+
console.log = toStderr;
|
|
207
|
+
console.info = toStderr;
|
|
208
|
+
console.debug = toStderr;
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
await executeRender();
|
|
212
|
+
}
|
|
213
|
+
finally {
|
|
214
|
+
console.log = originalConsole.log;
|
|
215
|
+
console.info = originalConsole.info;
|
|
216
|
+
console.debug = originalConsole.debug;
|
|
217
|
+
}
|
|
218
|
+
const frameFiles = readdirSync(framesDir)
|
|
219
|
+
.filter((name) => name.toLowerCase().endsWith(".png"))
|
|
220
|
+
.sort();
|
|
221
|
+
if (frameFiles.length === 0) {
|
|
222
|
+
throw new Error("stills render produced no frames — check the composition with `vidfarm lint` first.");
|
|
223
|
+
}
|
|
224
|
+
const stills = [];
|
|
225
|
+
for (const t of requested) {
|
|
226
|
+
const frameIndex = Math.min(frameFiles.length - 1, Math.max(0, Math.round(t * gridFps)));
|
|
227
|
+
const capturedSec = Number((frameIndex / gridFps).toFixed(3));
|
|
228
|
+
const stillName = `still-${capturedSec.toFixed(2).padStart(6, "0")}s.png`;
|
|
229
|
+
const dest = path.join(outDir, stillName);
|
|
230
|
+
copyFileSync(path.join(framesDir, frameFiles[frameIndex]), dest);
|
|
231
|
+
stills.push({ requested_sec: Number(t.toFixed(3)), captured_sec: capturedSec, path: dest });
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
ok: true,
|
|
235
|
+
composition: input.htmlPath,
|
|
236
|
+
out_dir: outDir,
|
|
237
|
+
grid_fps: gridFps,
|
|
238
|
+
duration_seconds: durationSeconds,
|
|
239
|
+
stills
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
finally {
|
|
243
|
+
if (!priorReadyTimeout?.trim())
|
|
244
|
+
delete process.env.PRODUCER_PLAYER_READY_TIMEOUT_MS;
|
|
245
|
+
rmSync(framesDir, { recursive: true, force: true });
|
|
246
|
+
rmSync(projectDir, { recursive: true, force: true });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=stills.js.map
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
// Opt-out crash telemetry for the vidfarm devcli — the `vidfarm ...` commands
|
|
2
|
+
// AND the local `serve` editor server. Unlike the backend/browser Sentry setups
|
|
3
|
+
// (which run on OUR infrastructure), this runs on END USERS' machines, so it is
|
|
4
|
+
// built defensively:
|
|
5
|
+
//
|
|
6
|
+
// * DEDICATED DSN — never the backend or browser project. Ships EMPTY, i.e.
|
|
7
|
+
// fully DISABLED, until VIDFARM_DEVCLI_SENTRY_DSN (or the DEVCLI_SENTRY_DSN
|
|
8
|
+
// constant below) points at a Sentry project created specifically for the
|
|
9
|
+
// CLI. That keeps devcli crashes out of product error streams and means the
|
|
10
|
+
// published package never carries a DSN that could be abused for quota spam.
|
|
11
|
+
// * OPT-OUT — honors DO_NOT_TRACK (https://consoledonottrack.com) and
|
|
12
|
+
// VIDFARM_TELEMETRY=off|0|false|no|disabled.
|
|
13
|
+
// * CRASH-ONLY — deliberate `throw new Error("...")` user errors (bad args,
|
|
14
|
+
// HTTP 4xx, missing files) and transient network failures are NOT reported;
|
|
15
|
+
// only unexpected bugs (TypeError/RangeError/… and non-Error throws) are.
|
|
16
|
+
// * SCRUBBED — beforeSend strips home-dir paths, api keys, auth headers, and
|
|
17
|
+
// known env secrets before anything leaves the machine; PII is off; console
|
|
18
|
+
// breadcrumbs (which can carry prompts / composition text) are dropped.
|
|
19
|
+
// * FLUSHED — flushTelemetry() drains the queue before the short-lived CLI exits.
|
|
20
|
+
//
|
|
21
|
+
// Every entry point is wrapped so telemetry can NEVER break a user's command.
|
|
22
|
+
import { readFileSync } from "node:fs";
|
|
23
|
+
import os from "node:os";
|
|
24
|
+
import path from "node:path";
|
|
25
|
+
import { fileURLToPath } from "node:url";
|
|
26
|
+
import * as Sentry from "@sentry/node";
|
|
27
|
+
// Set this to a DSN for a Sentry project dedicated to the devcli (NOT the
|
|
28
|
+
// backend or browser project). Left empty so the published package is silent
|
|
29
|
+
// until such a project exists; VIDFARM_DEVCLI_SENTRY_DSN overrides it at runtime.
|
|
30
|
+
const DEVCLI_SENTRY_DSN = "";
|
|
31
|
+
let initialized = false;
|
|
32
|
+
// Env vars whose values must never leave the machine, even if they surface in
|
|
33
|
+
// an error message or stack. Values are collected at init and redacted verbatim.
|
|
34
|
+
const SECRET_ENV_KEYS = [
|
|
35
|
+
"VIDFARM_API_KEY",
|
|
36
|
+
"VIDFARM_STAGING_BOOTSTRAP_API_KEY",
|
|
37
|
+
"OPENAI_API_KEY",
|
|
38
|
+
"OPENROUTER_API_KEY",
|
|
39
|
+
"GEMINI_API_KEY",
|
|
40
|
+
"PERPLEXITY_API_KEY",
|
|
41
|
+
"GHOSTCUT_KEY",
|
|
42
|
+
"GHOSTCUT_SECRET",
|
|
43
|
+
"ENCRYPTION_SECRET",
|
|
44
|
+
"API_KEY_SALT",
|
|
45
|
+
"WEBHOOK_SECRET",
|
|
46
|
+
"RESEND_API_KEY",
|
|
47
|
+
"AWS_ACCESS_KEY_ID",
|
|
48
|
+
"AWS_SECRET_ACCESS_KEY"
|
|
49
|
+
];
|
|
50
|
+
const HOME_DIR = safeHomedir();
|
|
51
|
+
let secretValues = [];
|
|
52
|
+
// Token-shaped strings redacted regardless of source (belt-and-suspenders on top
|
|
53
|
+
// of the exact env-value match above).
|
|
54
|
+
const TOKEN_PATTERNS = [
|
|
55
|
+
/\b(?:vf|sk|rk|pk|key)_[A-Za-z0-9_-]{8,}\b/g, // vidfarm / provider-style keys
|
|
56
|
+
/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, // JWT
|
|
57
|
+
/\bAKIA[0-9A-Z]{16}\b/g, // AWS access key id
|
|
58
|
+
/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi
|
|
59
|
+
];
|
|
60
|
+
// Transient / environmental failures we never want to page on — they are the
|
|
61
|
+
// user's network, not our bug.
|
|
62
|
+
const BENIGN_MESSAGE = /(fetch failed|ECONNREFUSED|ECONNRESET|ENOTFOUND|ETIMEDOUT|EAI_AGAIN|socket hang up|getaddrinfo|network|and requires a connection)/i;
|
|
63
|
+
function safeHomedir() {
|
|
64
|
+
try {
|
|
65
|
+
return os.homedir() || "";
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return "";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function isOptedOut() {
|
|
72
|
+
// DO_NOT_TRACK: any value other than unset / "0" / "false" means opt out.
|
|
73
|
+
const dnt = process.env.DO_NOT_TRACK?.trim();
|
|
74
|
+
if (dnt && dnt !== "0" && dnt.toLowerCase() !== "false")
|
|
75
|
+
return true;
|
|
76
|
+
const flag = process.env.VIDFARM_TELEMETRY?.trim().toLowerCase();
|
|
77
|
+
if (flag && ["0", "off", "false", "no", "disabled"].includes(flag))
|
|
78
|
+
return true;
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
function resolveDsn() {
|
|
82
|
+
return (process.env.VIDFARM_DEVCLI_SENTRY_DSN?.trim() || DEVCLI_SENTRY_DSN || "").trim();
|
|
83
|
+
}
|
|
84
|
+
function readPackageVersion() {
|
|
85
|
+
try {
|
|
86
|
+
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
87
|
+
for (let i = 0; i < 6; i++) {
|
|
88
|
+
try {
|
|
89
|
+
const parsed = JSON.parse(readFileSync(path.join(dir, "package.json"), "utf8"));
|
|
90
|
+
if (parsed.name === "@officexapp/vidfarm-devcli" && parsed.version) {
|
|
91
|
+
return `vidfarm-devcli@${parsed.version}`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// keep walking up
|
|
96
|
+
}
|
|
97
|
+
const parent = path.dirname(dir);
|
|
98
|
+
if (parent === dir)
|
|
99
|
+
break;
|
|
100
|
+
dir = parent;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// ignore — release tag is best-effort
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
function scrubString(input) {
|
|
109
|
+
let s = input;
|
|
110
|
+
if (HOME_DIR && s.includes(HOME_DIR))
|
|
111
|
+
s = s.split(HOME_DIR).join("~");
|
|
112
|
+
for (const secret of secretValues) {
|
|
113
|
+
if (secret && s.includes(secret))
|
|
114
|
+
s = s.split(secret).join("[REDACTED]");
|
|
115
|
+
}
|
|
116
|
+
for (const re of TOKEN_PATTERNS)
|
|
117
|
+
s = s.replace(re, "[REDACTED]");
|
|
118
|
+
// `--api-key <value>` on the command line and `header: value` shaped pairs.
|
|
119
|
+
s = s.replace(/(--api-key[=\s]+)\S+/gi, "$1[REDACTED]");
|
|
120
|
+
s = s.replace(/((?:vidfarm-api-key|authorization|x-api-key)["']?\s*[:=]\s*["']?)[^"'\s,}]+/gi, "$1[REDACTED]");
|
|
121
|
+
return s;
|
|
122
|
+
}
|
|
123
|
+
function scrubDeep(value, depth) {
|
|
124
|
+
if (value == null || depth > 8)
|
|
125
|
+
return value;
|
|
126
|
+
if (typeof value === "string")
|
|
127
|
+
return scrubString(value);
|
|
128
|
+
if (Array.isArray(value)) {
|
|
129
|
+
for (let i = 0; i < value.length; i++)
|
|
130
|
+
value[i] = scrubDeep(value[i], depth + 1);
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
if (typeof value === "object") {
|
|
134
|
+
const record = value;
|
|
135
|
+
for (const key of Object.keys(record))
|
|
136
|
+
record[key] = scrubDeep(record[key], depth + 1);
|
|
137
|
+
return record;
|
|
138
|
+
}
|
|
139
|
+
return value;
|
|
140
|
+
}
|
|
141
|
+
/** Deliberate `throw new Error("...")` user errors have name "Error"; genuine
|
|
142
|
+
* bugs surface as TypeError/RangeError/ReferenceError/… or as non-Error throws.
|
|
143
|
+
* Transient network failures are treated as expected. */
|
|
144
|
+
export function isUnexpectedCrash(error) {
|
|
145
|
+
if (!(error instanceof Error))
|
|
146
|
+
return true;
|
|
147
|
+
if (BENIGN_MESSAGE.test(error.message))
|
|
148
|
+
return false;
|
|
149
|
+
return error.name !== "Error";
|
|
150
|
+
}
|
|
151
|
+
export function isTelemetryEnabled() {
|
|
152
|
+
return initialized;
|
|
153
|
+
}
|
|
154
|
+
export function initTelemetry(commandName) {
|
|
155
|
+
try {
|
|
156
|
+
if (initialized)
|
|
157
|
+
return;
|
|
158
|
+
if (isOptedOut())
|
|
159
|
+
return;
|
|
160
|
+
const dsn = resolveDsn();
|
|
161
|
+
if (!dsn)
|
|
162
|
+
return;
|
|
163
|
+
secretValues = SECRET_ENV_KEYS.map((key) => process.env[key]?.trim() ?? "").filter((v) => v.length >= 8);
|
|
164
|
+
Sentry.init({
|
|
165
|
+
dsn,
|
|
166
|
+
environment: "devcli",
|
|
167
|
+
release: process.env.VIDFARM_DEVCLI_RELEASE?.trim() || readPackageVersion(),
|
|
168
|
+
// Short-lived CLI: no performance tracing, no log capture (logs can carry
|
|
169
|
+
// prompts / composition text), tiny breadcrumb budget.
|
|
170
|
+
tracesSampleRate: 0,
|
|
171
|
+
enableLogs: false,
|
|
172
|
+
sendDefaultPii: false,
|
|
173
|
+
maxBreadcrumbs: 20,
|
|
174
|
+
beforeBreadcrumb(breadcrumb) {
|
|
175
|
+
if (breadcrumb.category === "console")
|
|
176
|
+
return null;
|
|
177
|
+
try {
|
|
178
|
+
return scrubDeep(breadcrumb, 0);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return null; // if scrubbing fails, drop rather than risk leaking
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
beforeSend(event) {
|
|
185
|
+
try {
|
|
186
|
+
if (event.request) {
|
|
187
|
+
delete event.request.data;
|
|
188
|
+
delete event.request.cookies;
|
|
189
|
+
delete event.request.headers;
|
|
190
|
+
}
|
|
191
|
+
return scrubDeep(event, 0);
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return null; // scrub failed → drop the event entirely, never leak raw
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
Sentry.setTags({
|
|
199
|
+
"vidfarm.surface": "devcli",
|
|
200
|
+
"vidfarm.node": process.version,
|
|
201
|
+
"vidfarm.platform": `${process.platform}-${process.arch}`,
|
|
202
|
+
...(commandName ? { "vidfarm.command": commandName } : {})
|
|
203
|
+
});
|
|
204
|
+
initialized = true;
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// Telemetry must never break the CLI.
|
|
208
|
+
initialized = false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/** Report an unexpected top-level CLI crash (no-op for expected user errors,
|
|
212
|
+
* transient network errors, or when telemetry is disabled), then flush. */
|
|
213
|
+
export async function reportCliCrash(error) {
|
|
214
|
+
try {
|
|
215
|
+
if (!initialized)
|
|
216
|
+
return;
|
|
217
|
+
if (!isUnexpectedCrash(error))
|
|
218
|
+
return;
|
|
219
|
+
Sentry.captureException(error);
|
|
220
|
+
await flushTelemetry();
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// swallow — never let telemetry change the exit path
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
export async function flushTelemetry(timeoutMs = 2000) {
|
|
227
|
+
try {
|
|
228
|
+
if (!initialized)
|
|
229
|
+
return;
|
|
230
|
+
await Sentry.flush(timeoutMs);
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
// swallow
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=telemetry.js.map
|