@vibeframe/cli 0.55.0 → 0.55.1
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/dist/index.js +63452 -233
- package/package.json +11 -6
- package/dist/agent/adapters/claude.d.ts +0 -15
- package/dist/agent/adapters/claude.d.ts.map +0 -1
- package/dist/agent/adapters/claude.js +0 -119
- package/dist/agent/adapters/claude.js.map +0 -1
- package/dist/agent/adapters/gemini.d.ts +0 -15
- package/dist/agent/adapters/gemini.d.ts.map +0 -1
- package/dist/agent/adapters/gemini.js +0 -132
- package/dist/agent/adapters/gemini.js.map +0 -1
- package/dist/agent/adapters/index.d.ts +0 -28
- package/dist/agent/adapters/index.d.ts.map +0 -1
- package/dist/agent/adapters/index.js +0 -43
- package/dist/agent/adapters/index.js.map +0 -1
- package/dist/agent/adapters/ollama.d.ts +0 -20
- package/dist/agent/adapters/ollama.d.ts.map +0 -1
- package/dist/agent/adapters/ollama.js +0 -186
- package/dist/agent/adapters/ollama.js.map +0 -1
- package/dist/agent/adapters/openai.d.ts +0 -15
- package/dist/agent/adapters/openai.d.ts.map +0 -1
- package/dist/agent/adapters/openai.js +0 -92
- package/dist/agent/adapters/openai.js.map +0 -1
- package/dist/agent/adapters/openrouter.d.ts +0 -16
- package/dist/agent/adapters/openrouter.d.ts.map +0 -1
- package/dist/agent/adapters/openrouter.js +0 -100
- package/dist/agent/adapters/openrouter.js.map +0 -1
- package/dist/agent/adapters/openrouter.test.d.ts +0 -5
- package/dist/agent/adapters/openrouter.test.d.ts.map +0 -1
- package/dist/agent/adapters/openrouter.test.js +0 -73
- package/dist/agent/adapters/openrouter.test.js.map +0 -1
- package/dist/agent/adapters/xai.d.ts +0 -15
- package/dist/agent/adapters/xai.d.ts.map +0 -1
- package/dist/agent/adapters/xai.js +0 -95
- package/dist/agent/adapters/xai.js.map +0 -1
- package/dist/agent/index.d.ts +0 -69
- package/dist/agent/index.d.ts.map +0 -1
- package/dist/agent/index.js +0 -180
- package/dist/agent/index.js.map +0 -1
- package/dist/agent/memory/index.d.ts +0 -70
- package/dist/agent/memory/index.d.ts.map +0 -1
- package/dist/agent/memory/index.js +0 -132
- package/dist/agent/memory/index.js.map +0 -1
- package/dist/agent/prompts/system.d.ts +0 -6
- package/dist/agent/prompts/system.d.ts.map +0 -1
- package/dist/agent/prompts/system.js +0 -103
- package/dist/agent/prompts/system.js.map +0 -1
- package/dist/agent/tools/ai-editing.d.ts +0 -15
- package/dist/agent/tools/ai-editing.d.ts.map +0 -1
- package/dist/agent/tools/ai-editing.js +0 -763
- package/dist/agent/tools/ai-editing.js.map +0 -1
- package/dist/agent/tools/ai-generation.d.ts +0 -13
- package/dist/agent/tools/ai-generation.d.ts.map +0 -1
- package/dist/agent/tools/ai-generation.js +0 -973
- package/dist/agent/tools/ai-generation.js.map +0 -1
- package/dist/agent/tools/ai-pipeline.d.ts +0 -14
- package/dist/agent/tools/ai-pipeline.d.ts.map +0 -1
- package/dist/agent/tools/ai-pipeline.js +0 -961
- package/dist/agent/tools/ai-pipeline.js.map +0 -1
- package/dist/agent/tools/ai.d.ts +0 -13
- package/dist/agent/tools/ai.d.ts.map +0 -1
- package/dist/agent/tools/ai.js +0 -19
- package/dist/agent/tools/ai.js.map +0 -1
- package/dist/agent/tools/batch.d.ts +0 -6
- package/dist/agent/tools/batch.d.ts.map +0 -1
- package/dist/agent/tools/batch.js +0 -383
- package/dist/agent/tools/batch.js.map +0 -1
- package/dist/agent/tools/e2e.test.d.ts +0 -26
- package/dist/agent/tools/e2e.test.d.ts.map +0 -1
- package/dist/agent/tools/e2e.test.js +0 -397
- package/dist/agent/tools/e2e.test.js.map +0 -1
- package/dist/agent/tools/export.d.ts +0 -6
- package/dist/agent/tools/export.d.ts.map +0 -1
- package/dist/agent/tools/export.js +0 -171
- package/dist/agent/tools/export.js.map +0 -1
- package/dist/agent/tools/filesystem.d.ts +0 -6
- package/dist/agent/tools/filesystem.d.ts.map +0 -1
- package/dist/agent/tools/filesystem.js +0 -212
- package/dist/agent/tools/filesystem.js.map +0 -1
- package/dist/agent/tools/index.d.ts +0 -66
- package/dist/agent/tools/index.d.ts.map +0 -1
- package/dist/agent/tools/index.js +0 -123
- package/dist/agent/tools/index.js.map +0 -1
- package/dist/agent/tools/integration.test.d.ts +0 -11
- package/dist/agent/tools/integration.test.d.ts.map +0 -1
- package/dist/agent/tools/integration.test.js +0 -659
- package/dist/agent/tools/integration.test.js.map +0 -1
- package/dist/agent/tools/media.d.ts +0 -6
- package/dist/agent/tools/media.d.ts.map +0 -1
- package/dist/agent/tools/media.js +0 -616
- package/dist/agent/tools/media.js.map +0 -1
- package/dist/agent/tools/project.d.ts +0 -6
- package/dist/agent/tools/project.d.ts.map +0 -1
- package/dist/agent/tools/project.js +0 -284
- package/dist/agent/tools/project.js.map +0 -1
- package/dist/agent/tools/scene.d.ts +0 -17
- package/dist/agent/tools/scene.d.ts.map +0 -1
- package/dist/agent/tools/scene.js +0 -263
- package/dist/agent/tools/scene.js.map +0 -1
- package/dist/agent/tools/scene.test.d.ts +0 -2
- package/dist/agent/tools/scene.test.d.ts.map +0 -1
- package/dist/agent/tools/scene.test.js +0 -139
- package/dist/agent/tools/scene.test.js.map +0 -1
- package/dist/agent/tools/timeline.d.ts +0 -6
- package/dist/agent/tools/timeline.d.ts.map +0 -1
- package/dist/agent/tools/timeline.js +0 -875
- package/dist/agent/tools/timeline.js.map +0 -1
- package/dist/agent/types.d.ts +0 -59
- package/dist/agent/types.d.ts.map +0 -1
- package/dist/agent/types.js +0 -5
- package/dist/agent/types.js.map +0 -1
- package/dist/commands/_shared/scene-audio-mux.d.ts +0 -75
- package/dist/commands/_shared/scene-audio-mux.d.ts.map +0 -1
- package/dist/commands/_shared/scene-audio-mux.js +0 -159
- package/dist/commands/_shared/scene-audio-mux.js.map +0 -1
- package/dist/commands/_shared/scene-audio-mux.test.d.ts +0 -7
- package/dist/commands/_shared/scene-audio-mux.test.d.ts.map +0 -1
- package/dist/commands/_shared/scene-audio-mux.test.js +0 -94
- package/dist/commands/_shared/scene-audio-mux.test.js.map +0 -1
- package/dist/commands/_shared/scene-audio-scan.d.ts +0 -94
- package/dist/commands/_shared/scene-audio-scan.d.ts.map +0 -1
- package/dist/commands/_shared/scene-audio-scan.js +0 -144
- package/dist/commands/_shared/scene-audio-scan.js.map +0 -1
- package/dist/commands/_shared/scene-audio-scan.test.d.ts +0 -6
- package/dist/commands/_shared/scene-audio-scan.test.d.ts.map +0 -1
- package/dist/commands/_shared/scene-audio-scan.test.js +0 -190
- package/dist/commands/_shared/scene-audio-scan.test.js.map +0 -1
- package/dist/commands/_shared/scene-html-emit.d.ts +0 -120
- package/dist/commands/_shared/scene-html-emit.d.ts.map +0 -1
- package/dist/commands/_shared/scene-html-emit.js +0 -422
- package/dist/commands/_shared/scene-html-emit.js.map +0 -1
- package/dist/commands/_shared/scene-html-emit.test.d.ts +0 -2
- package/dist/commands/_shared/scene-html-emit.test.d.ts.map +0 -1
- package/dist/commands/_shared/scene-html-emit.test.js +0 -396
- package/dist/commands/_shared/scene-html-emit.test.js.map +0 -1
- package/dist/commands/_shared/scene-lint.d.ts +0 -110
- package/dist/commands/_shared/scene-lint.d.ts.map +0 -1
- package/dist/commands/_shared/scene-lint.js +0 -207
- package/dist/commands/_shared/scene-lint.js.map +0 -1
- package/dist/commands/_shared/scene-lint.test.d.ts +0 -2
- package/dist/commands/_shared/scene-lint.test.d.ts.map +0 -1
- package/dist/commands/_shared/scene-lint.test.js +0 -208
- package/dist/commands/_shared/scene-lint.test.js.map +0 -1
- package/dist/commands/_shared/scene-project.d.ts +0 -101
- package/dist/commands/_shared/scene-project.d.ts.map +0 -1
- package/dist/commands/_shared/scene-project.js +0 -281
- package/dist/commands/_shared/scene-project.js.map +0 -1
- package/dist/commands/_shared/scene-project.test.d.ts +0 -2
- package/dist/commands/_shared/scene-project.test.d.ts.map +0 -1
- package/dist/commands/_shared/scene-project.test.js +0 -203
- package/dist/commands/_shared/scene-project.test.js.map +0 -1
- package/dist/commands/_shared/scene-render.d.ts +0 -85
- package/dist/commands/_shared/scene-render.d.ts.map +0 -1
- package/dist/commands/_shared/scene-render.js +0 -178
- package/dist/commands/_shared/scene-render.js.map +0 -1
- package/dist/commands/_shared/scene-render.test.d.ts +0 -2
- package/dist/commands/_shared/scene-render.test.d.ts.map +0 -1
- package/dist/commands/_shared/scene-render.test.js +0 -145
- package/dist/commands/_shared/scene-render.test.js.map +0 -1
- package/dist/commands/_shared/segments-to-scenes.d.ts +0 -85
- package/dist/commands/_shared/segments-to-scenes.d.ts.map +0 -1
- package/dist/commands/_shared/segments-to-scenes.js +0 -202
- package/dist/commands/_shared/segments-to-scenes.js.map +0 -1
- package/dist/commands/_shared/segments-to-scenes.test.d.ts +0 -2
- package/dist/commands/_shared/segments-to-scenes.test.d.ts.map +0 -1
- package/dist/commands/_shared/segments-to-scenes.test.js +0 -219
- package/dist/commands/_shared/segments-to-scenes.test.js.map +0 -1
- package/dist/commands/_shared/tts-resolve.d.ts +0 -75
- package/dist/commands/_shared/tts-resolve.d.ts.map +0 -1
- package/dist/commands/_shared/tts-resolve.js +0 -89
- package/dist/commands/_shared/tts-resolve.js.map +0 -1
- package/dist/commands/_shared/tts-resolve.test.d.ts +0 -6
- package/dist/commands/_shared/tts-resolve.test.d.ts.map +0 -1
- package/dist/commands/_shared/tts-resolve.test.js +0 -147
- package/dist/commands/_shared/tts-resolve.test.js.map +0 -1
- package/dist/commands/agent.d.ts +0 -21
- package/dist/commands/agent.d.ts.map +0 -1
- package/dist/commands/agent.js +0 -285
- package/dist/commands/agent.js.map +0 -1
- package/dist/commands/ai-analyze.d.ts +0 -106
- package/dist/commands/ai-analyze.d.ts.map +0 -1
- package/dist/commands/ai-analyze.js +0 -320
- package/dist/commands/ai-analyze.js.map +0 -1
- package/dist/commands/ai-animated-caption.d.ts +0 -64
- package/dist/commands/ai-animated-caption.d.ts.map +0 -1
- package/dist/commands/ai-animated-caption.js +0 -272
- package/dist/commands/ai-animated-caption.js.map +0 -1
- package/dist/commands/ai-audio.d.ts +0 -98
- package/dist/commands/ai-audio.d.ts.map +0 -1
- package/dist/commands/ai-audio.js +0 -1059
- package/dist/commands/ai-audio.js.map +0 -1
- package/dist/commands/ai-broll.d.ts +0 -15
- package/dist/commands/ai-broll.d.ts.map +0 -1
- package/dist/commands/ai-broll.js +0 -421
- package/dist/commands/ai-broll.js.map +0 -1
- package/dist/commands/ai-edit-cli.d.ts +0 -14
- package/dist/commands/ai-edit-cli.d.ts.map +0 -1
- package/dist/commands/ai-edit-cli.js +0 -585
- package/dist/commands/ai-edit-cli.js.map +0 -1
- package/dist/commands/ai-edit.d.ts +0 -398
- package/dist/commands/ai-edit.d.ts.map +0 -1
- package/dist/commands/ai-edit.js +0 -1060
- package/dist/commands/ai-edit.js.map +0 -1
- package/dist/commands/ai-fill-gaps.d.ts +0 -14
- package/dist/commands/ai-fill-gaps.d.ts.map +0 -1
- package/dist/commands/ai-fill-gaps.js +0 -447
- package/dist/commands/ai-fill-gaps.js.map +0 -1
- package/dist/commands/ai-helpers.d.ts +0 -20
- package/dist/commands/ai-helpers.d.ts.map +0 -1
- package/dist/commands/ai-helpers.js +0 -59
- package/dist/commands/ai-helpers.js.map +0 -1
- package/dist/commands/ai-highlights.d.ts +0 -127
- package/dist/commands/ai-highlights.d.ts.map +0 -1
- package/dist/commands/ai-highlights.js +0 -1053
- package/dist/commands/ai-highlights.js.map +0 -1
- package/dist/commands/ai-image.d.ts +0 -76
- package/dist/commands/ai-image.d.ts.map +0 -1
- package/dist/commands/ai-image.js +0 -858
- package/dist/commands/ai-image.js.map +0 -1
- package/dist/commands/ai-motion.d.ts +0 -50
- package/dist/commands/ai-motion.d.ts.map +0 -1
- package/dist/commands/ai-motion.js +0 -297
- package/dist/commands/ai-motion.js.map +0 -1
- package/dist/commands/ai-narrate.d.ts +0 -66
- package/dist/commands/ai-narrate.d.ts.map +0 -1
- package/dist/commands/ai-narrate.js +0 -332
- package/dist/commands/ai-narrate.js.map +0 -1
- package/dist/commands/ai-review.d.ts +0 -57
- package/dist/commands/ai-review.d.ts.map +0 -1
- package/dist/commands/ai-review.js +0 -270
- package/dist/commands/ai-review.js.map +0 -1
- package/dist/commands/ai-script-pipeline-cli.d.ts +0 -9
- package/dist/commands/ai-script-pipeline-cli.d.ts.map +0 -1
- package/dist/commands/ai-script-pipeline-cli.js +0 -502
- package/dist/commands/ai-script-pipeline-cli.js.map +0 -1
- package/dist/commands/ai-script-pipeline.d.ts +0 -305
- package/dist/commands/ai-script-pipeline.d.ts.map +0 -1
- package/dist/commands/ai-script-pipeline.js +0 -1546
- package/dist/commands/ai-script-pipeline.js.map +0 -1
- package/dist/commands/ai-suggest-edit.d.ts +0 -14
- package/dist/commands/ai-suggest-edit.d.ts.map +0 -1
- package/dist/commands/ai-suggest-edit.js +0 -215
- package/dist/commands/ai-suggest-edit.js.map +0 -1
- package/dist/commands/ai-video-fx.d.ts +0 -14
- package/dist/commands/ai-video-fx.d.ts.map +0 -1
- package/dist/commands/ai-video-fx.js +0 -396
- package/dist/commands/ai-video-fx.js.map +0 -1
- package/dist/commands/ai-video.d.ts +0 -91
- package/dist/commands/ai-video.d.ts.map +0 -1
- package/dist/commands/ai-video.js +0 -1055
- package/dist/commands/ai-video.js.map +0 -1
- package/dist/commands/ai-viral.d.ts +0 -15
- package/dist/commands/ai-viral.d.ts.map +0 -1
- package/dist/commands/ai-viral.js +0 -507
- package/dist/commands/ai-viral.js.map +0 -1
- package/dist/commands/ai-visual-fx.d.ts +0 -14
- package/dist/commands/ai-visual-fx.d.ts.map +0 -1
- package/dist/commands/ai-visual-fx.js +0 -521
- package/dist/commands/ai-visual-fx.js.map +0 -1
- package/dist/commands/ai.d.ts +0 -38
- package/dist/commands/ai.d.ts.map +0 -1
- package/dist/commands/ai.js +0 -225
- package/dist/commands/ai.js.map +0 -1
- package/dist/commands/ai.test.d.ts +0 -2
- package/dist/commands/ai.test.d.ts.map +0 -1
- package/dist/commands/ai.test.js +0 -557
- package/dist/commands/ai.test.js.map +0 -1
- package/dist/commands/analyze.d.ts +0 -16
- package/dist/commands/analyze.d.ts.map +0 -1
- package/dist/commands/analyze.js +0 -247
- package/dist/commands/analyze.js.map +0 -1
- package/dist/commands/audio.d.ts +0 -18
- package/dist/commands/audio.d.ts.map +0 -1
- package/dist/commands/audio.js +0 -539
- package/dist/commands/audio.js.map +0 -1
- package/dist/commands/batch.d.ts +0 -3
- package/dist/commands/batch.d.ts.map +0 -1
- package/dist/commands/batch.js +0 -419
- package/dist/commands/batch.js.map +0 -1
- package/dist/commands/batch.test.d.ts +0 -2
- package/dist/commands/batch.test.d.ts.map +0 -1
- package/dist/commands/batch.test.js +0 -203
- package/dist/commands/batch.test.js.map +0 -1
- package/dist/commands/context.d.ts +0 -7
- package/dist/commands/context.d.ts.map +0 -1
- package/dist/commands/context.js +0 -66
- package/dist/commands/context.js.map +0 -1
- package/dist/commands/demo.d.ts +0 -7
- package/dist/commands/demo.d.ts.map +0 -1
- package/dist/commands/demo.js +0 -192
- package/dist/commands/demo.js.map +0 -1
- package/dist/commands/detect.d.ts +0 -56
- package/dist/commands/detect.d.ts.map +0 -1
- package/dist/commands/detect.js +0 -464
- package/dist/commands/detect.js.map +0 -1
- package/dist/commands/doctor.d.ts +0 -6
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js +0 -322
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/edit-cmd.d.ts +0 -112
- package/dist/commands/edit-cmd.d.ts.map +0 -1
- package/dist/commands/edit-cmd.js +0 -1041
- package/dist/commands/edit-cmd.js.map +0 -1
- package/dist/commands/export.d.ts +0 -61
- package/dist/commands/export.d.ts.map +0 -1
- package/dist/commands/export.js +0 -980
- package/dist/commands/export.js.map +0 -1
- package/dist/commands/export.test.d.ts +0 -2
- package/dist/commands/export.test.d.ts.map +0 -1
- package/dist/commands/export.test.js +0 -107
- package/dist/commands/export.test.js.map +0 -1
- package/dist/commands/generate.d.ts +0 -84
- package/dist/commands/generate.d.ts.map +0 -1
- package/dist/commands/generate.js +0 -2030
- package/dist/commands/generate.js.map +0 -1
- package/dist/commands/media.d.ts +0 -3
- package/dist/commands/media.d.ts.map +0 -1
- package/dist/commands/media.js +0 -163
- package/dist/commands/media.js.map +0 -1
- package/dist/commands/output.d.ts +0 -51
- package/dist/commands/output.d.ts.map +0 -1
- package/dist/commands/output.js +0 -219
- package/dist/commands/output.js.map +0 -1
- package/dist/commands/output.test.d.ts +0 -2
- package/dist/commands/output.test.d.ts.map +0 -1
- package/dist/commands/output.test.js +0 -151
- package/dist/commands/output.test.js.map +0 -1
- package/dist/commands/pipeline.d.ts +0 -19
- package/dist/commands/pipeline.d.ts.map +0 -1
- package/dist/commands/pipeline.js +0 -345
- package/dist/commands/pipeline.js.map +0 -1
- package/dist/commands/project.d.ts +0 -3
- package/dist/commands/project.d.ts.map +0 -1
- package/dist/commands/project.js +0 -181
- package/dist/commands/project.js.map +0 -1
- package/dist/commands/project.test.d.ts +0 -2
- package/dist/commands/project.test.d.ts.map +0 -1
- package/dist/commands/project.test.js +0 -105
- package/dist/commands/project.test.js.map +0 -1
- package/dist/commands/run.d.ts +0 -15
- package/dist/commands/run.d.ts.map +0 -1
- package/dist/commands/run.js +0 -204
- package/dist/commands/run.js.map +0 -1
- package/dist/commands/sanitize.d.ts +0 -21
- package/dist/commands/sanitize.d.ts.map +0 -1
- package/dist/commands/sanitize.js +0 -56
- package/dist/commands/sanitize.js.map +0 -1
- package/dist/commands/scene.d.ts +0 -86
- package/dist/commands/scene.d.ts.map +0 -1
- package/dist/commands/scene.js +0 -728
- package/dist/commands/scene.js.map +0 -1
- package/dist/commands/scene.test.d.ts +0 -2
- package/dist/commands/scene.test.d.ts.map +0 -1
- package/dist/commands/scene.test.js +0 -219
- package/dist/commands/scene.test.js.map +0 -1
- package/dist/commands/schema.d.ts +0 -13
- package/dist/commands/schema.d.ts.map +0 -1
- package/dist/commands/schema.js +0 -218
- package/dist/commands/schema.js.map +0 -1
- package/dist/commands/setup.d.ts +0 -6
- package/dist/commands/setup.d.ts.map +0 -1
- package/dist/commands/setup.js +0 -461
- package/dist/commands/setup.js.map +0 -1
- package/dist/commands/timeline.d.ts +0 -3
- package/dist/commands/timeline.d.ts.map +0 -1
- package/dist/commands/timeline.js +0 -609
- package/dist/commands/timeline.js.map +0 -1
- package/dist/commands/timeline.test.d.ts +0 -2
- package/dist/commands/timeline.test.d.ts.map +0 -1
- package/dist/commands/timeline.test.js +0 -334
- package/dist/commands/timeline.test.js.map +0 -1
- package/dist/commands/validate.d.ts +0 -34
- package/dist/commands/validate.d.ts.map +0 -1
- package/dist/commands/validate.js +0 -70
- package/dist/commands/validate.js.map +0 -1
- package/dist/config/config.test.d.ts +0 -2
- package/dist/config/config.test.d.ts.map +0 -1
- package/dist/config/config.test.js +0 -164
- package/dist/config/config.test.js.map +0 -1
- package/dist/config/index.d.ts +0 -35
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/index.js +0 -101
- package/dist/config/index.js.map +0 -1
- package/dist/config/schema.d.ts +0 -52
- package/dist/config/schema.d.ts.map +0 -1
- package/dist/config/schema.js +0 -44
- package/dist/config/schema.js.map +0 -1
- package/dist/engine/index.d.ts +0 -3
- package/dist/engine/index.d.ts.map +0 -1
- package/dist/engine/index.js +0 -2
- package/dist/engine/index.js.map +0 -1
- package/dist/engine/project.d.ts +0 -84
- package/dist/engine/project.d.ts.map +0 -1
- package/dist/engine/project.js +0 -355
- package/dist/engine/project.js.map +0 -1
- package/dist/engine/project.test.d.ts +0 -2
- package/dist/engine/project.test.d.ts.map +0 -1
- package/dist/engine/project.test.js +0 -599
- package/dist/engine/project.test.js.map +0 -1
- package/dist/index.d.ts +0 -7
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/pipeline/executor.d.ts +0 -19
- package/dist/pipeline/executor.d.ts.map +0 -1
- package/dist/pipeline/executor.js +0 -397
- package/dist/pipeline/executor.js.map +0 -1
- package/dist/pipeline/index.d.ts +0 -4
- package/dist/pipeline/index.d.ts.map +0 -1
- package/dist/pipeline/index.js +0 -2
- package/dist/pipeline/index.js.map +0 -1
- package/dist/pipeline/renderers/__tests__/html-template.test.d.ts +0 -2
- package/dist/pipeline/renderers/__tests__/html-template.test.d.ts.map +0 -1
- package/dist/pipeline/renderers/__tests__/html-template.test.js +0 -170
- package/dist/pipeline/renderers/__tests__/html-template.test.js.map +0 -1
- package/dist/pipeline/renderers/__tests__/integration.test.d.ts +0 -2
- package/dist/pipeline/renderers/__tests__/integration.test.d.ts.map +0 -1
- package/dist/pipeline/renderers/__tests__/integration.test.js +0 -175
- package/dist/pipeline/renderers/__tests__/integration.test.js.map +0 -1
- package/dist/pipeline/renderers/chrome.d.ts +0 -26
- package/dist/pipeline/renderers/chrome.d.ts.map +0 -1
- package/dist/pipeline/renderers/chrome.js +0 -48
- package/dist/pipeline/renderers/chrome.js.map +0 -1
- package/dist/pipeline/renderers/html-clips.d.ts +0 -20
- package/dist/pipeline/renderers/html-clips.d.ts.map +0 -1
- package/dist/pipeline/renderers/html-clips.js +0 -50
- package/dist/pipeline/renderers/html-clips.js.map +0 -1
- package/dist/pipeline/renderers/html-runtime.d.ts +0 -7
- package/dist/pipeline/renderers/html-runtime.d.ts.map +0 -1
- package/dist/pipeline/renderers/html-runtime.js +0 -80
- package/dist/pipeline/renderers/html-runtime.js.map +0 -1
- package/dist/pipeline/renderers/html-template.d.ts +0 -3
- package/dist/pipeline/renderers/html-template.d.ts.map +0 -1
- package/dist/pipeline/renderers/html-template.js +0 -36
- package/dist/pipeline/renderers/html-template.js.map +0 -1
- package/dist/pipeline/renderers/hyperframes.d.ts +0 -8
- package/dist/pipeline/renderers/hyperframes.d.ts.map +0 -1
- package/dist/pipeline/renderers/hyperframes.js +0 -63
- package/dist/pipeline/renderers/hyperframes.js.map +0 -1
- package/dist/pipeline/renderers/project-builder.d.ts +0 -8
- package/dist/pipeline/renderers/project-builder.d.ts.map +0 -1
- package/dist/pipeline/renderers/project-builder.js +0 -65
- package/dist/pipeline/renderers/project-builder.js.map +0 -1
- package/dist/pipeline/renderers/types.d.ts +0 -41
- package/dist/pipeline/renderers/types.d.ts.map +0 -1
- package/dist/pipeline/renderers/types.js +0 -11
- package/dist/pipeline/renderers/types.js.map +0 -1
- package/dist/pipeline/resolver.d.ts +0 -20
- package/dist/pipeline/resolver.d.ts.map +0 -1
- package/dist/pipeline/resolver.js +0 -74
- package/dist/pipeline/resolver.js.map +0 -1
- package/dist/pipeline/types.d.ts +0 -82
- package/dist/pipeline/types.d.ts.map +0 -1
- package/dist/pipeline/types.js +0 -8
- package/dist/pipeline/types.js.map +0 -1
- package/dist/utils/api-key.d.ts +0 -33
- package/dist/utils/api-key.d.ts.map +0 -1
- package/dist/utils/api-key.js +0 -228
- package/dist/utils/api-key.js.map +0 -1
- package/dist/utils/api-key.test.d.ts +0 -2
- package/dist/utils/api-key.test.d.ts.map +0 -1
- package/dist/utils/api-key.test.js +0 -35
- package/dist/utils/api-key.test.js.map +0 -1
- package/dist/utils/audio.d.ts +0 -23
- package/dist/utils/audio.d.ts.map +0 -1
- package/dist/utils/audio.js +0 -79
- package/dist/utils/audio.js.map +0 -1
- package/dist/utils/exec-safe.d.ts +0 -22
- package/dist/utils/exec-safe.d.ts.map +0 -1
- package/dist/utils/exec-safe.js +0 -62
- package/dist/utils/exec-safe.js.map +0 -1
- package/dist/utils/first-run.d.ts +0 -17
- package/dist/utils/first-run.d.ts.map +0 -1
- package/dist/utils/first-run.js +0 -73
- package/dist/utils/first-run.js.map +0 -1
- package/dist/utils/input-validation.d.ts +0 -27
- package/dist/utils/input-validation.d.ts.map +0 -1
- package/dist/utils/input-validation.js +0 -67
- package/dist/utils/input-validation.js.map +0 -1
- package/dist/utils/provider-resolver.d.ts +0 -19
- package/dist/utils/provider-resolver.d.ts.map +0 -1
- package/dist/utils/provider-resolver.js +0 -75
- package/dist/utils/provider-resolver.js.map +0 -1
- package/dist/utils/remotion.d.ts +0 -231
- package/dist/utils/remotion.d.ts.map +0 -1
- package/dist/utils/remotion.js +0 -879
- package/dist/utils/remotion.js.map +0 -1
- package/dist/utils/subtitle.d.ts +0 -65
- package/dist/utils/subtitle.d.ts.map +0 -1
- package/dist/utils/subtitle.js +0 -135
- package/dist/utils/subtitle.js.map +0 -1
- package/dist/utils/subtitle.test.d.ts +0 -2
- package/dist/utils/subtitle.test.d.ts.map +0 -1
- package/dist/utils/subtitle.test.js +0 -175
- package/dist/utils/subtitle.test.js.map +0 -1
- package/dist/utils/tty.d.ts +0 -45
- package/dist/utils/tty.d.ts.map +0 -1
- package/dist/utils/tty.js +0 -231
- package/dist/utils/tty.js.map +0 -1
|
@@ -1,1055 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module ai-video
|
|
3
|
-
* @description Video generation and management commands for the VibeFrame CLI.
|
|
4
|
-
*
|
|
5
|
-
* ## Commands: vibe ai video, vibe ai video-status, vibe ai video-cancel,
|
|
6
|
-
* vibe ai kling, vibe ai kling-status, vibe ai video-extend
|
|
7
|
-
* ## Dependencies: Runway, Kling, Veo (Gemini)
|
|
8
|
-
*
|
|
9
|
-
* Extracted from ai.ts as part of modularisation.
|
|
10
|
-
* ai.ts calls registerVideoCommands(aiCommand).
|
|
11
|
-
* @see MODELS.md for AI model configuration
|
|
12
|
-
*/
|
|
13
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
14
|
-
import { resolve } from "node:path";
|
|
15
|
-
import chalk from "chalk";
|
|
16
|
-
import ora from "ora";
|
|
17
|
-
import { GeminiProvider, GrokProvider, KlingProvider, RunwayProvider } from "@vibeframe/ai-providers";
|
|
18
|
-
import { getApiKey } from "../utils/api-key.js";
|
|
19
|
-
import { getApiKeyFromConfig } from "../config/index.js";
|
|
20
|
-
import { uploadToImgbb } from "./ai-script-pipeline.js";
|
|
21
|
-
import { downloadVideo } from "./ai-helpers.js";
|
|
22
|
-
import { exitWithError, authError, usageError, apiError, generalError, outputResult } from "./output.js";
|
|
23
|
-
import { validateOutputPath } from "./validate.js";
|
|
24
|
-
function getStatusColor(status) {
|
|
25
|
-
switch (status) {
|
|
26
|
-
case "completed":
|
|
27
|
-
return chalk.green(status);
|
|
28
|
-
case "processing":
|
|
29
|
-
case "running":
|
|
30
|
-
case "in_progress":
|
|
31
|
-
return chalk.yellow(status);
|
|
32
|
-
case "failed":
|
|
33
|
-
case "error":
|
|
34
|
-
return chalk.red(status);
|
|
35
|
-
default:
|
|
36
|
-
return chalk.gray(status);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
export function registerVideoCommands(aiCommand) {
|
|
40
|
-
aiCommand
|
|
41
|
-
.command("video")
|
|
42
|
-
.description("Generate video using AI (Grok, Runway, Kling, or Veo)")
|
|
43
|
-
.argument("<prompt>", "Text prompt describing the video")
|
|
44
|
-
.option("-p, --provider <provider>", "Provider: grok, kling, runway, veo", "kling")
|
|
45
|
-
.option("-k, --api-key <key>", "API key (or set RUNWAY_API_SECRET / KLING_API_KEY / GOOGLE_API_KEY env)")
|
|
46
|
-
.option("-o, --output <path>", "Output file path (downloads video)")
|
|
47
|
-
.option("-i, --image <path>", "Reference image for image-to-video")
|
|
48
|
-
.option("-d, --duration <sec>", "Duration: 5 or 10 seconds", "5")
|
|
49
|
-
.option("-r, --ratio <ratio>", "Aspect ratio: 16:9, 9:16, or 1:1", "16:9")
|
|
50
|
-
.option("-s, --seed <number>", "Random seed for reproducibility (Runway only)")
|
|
51
|
-
.option("-m, --mode <mode>", "Generation mode: std or pro (Kling only)", "std")
|
|
52
|
-
.option("-n, --negative <prompt>", "Negative prompt - what to avoid (Kling/Veo)")
|
|
53
|
-
.option("--resolution <res>", "Video resolution: 720p, 1080p, 4k (Veo only)")
|
|
54
|
-
.option("--last-frame <path>", "Last frame image for frame interpolation (Veo only)")
|
|
55
|
-
.option("--ref-images <paths...>", "Reference images for character consistency (Veo 3.1 only, max 3)")
|
|
56
|
-
.option("--person <mode>", "Person generation: allow_all, allow_adult (Veo only)")
|
|
57
|
-
.option("--veo-model <model>", "Veo model: 3.0, 3.1, 3.1-fast (default: 3.1-fast)", "3.1-fast")
|
|
58
|
-
.option("--runway-model <model>", "Runway model: gen4.5 (default, text+image-to-video), gen4_turbo (image-to-video only)", "gen4.5")
|
|
59
|
-
.option("--no-wait", "Start generation and return task ID without waiting")
|
|
60
|
-
.option("--dry-run", "Preview parameters without executing")
|
|
61
|
-
.action(async (prompt, options) => {
|
|
62
|
-
try {
|
|
63
|
-
if (options.output) {
|
|
64
|
-
validateOutputPath(options.output);
|
|
65
|
-
}
|
|
66
|
-
const provider = options.provider.toLowerCase();
|
|
67
|
-
const validProviders = ["grok", "runway", "kling", "veo"];
|
|
68
|
-
if (!validProviders.includes(provider)) {
|
|
69
|
-
exitWithError(usageError(`Invalid provider: ${provider}`, `Available providers: ${validProviders.join(", ")}`));
|
|
70
|
-
}
|
|
71
|
-
if (options.dryRun) {
|
|
72
|
-
outputResult({ dryRun: true, command: "ai video", params: { prompt, provider, output: options.output, image: options.image, duration: options.duration, ratio: options.ratio, mode: options.mode, runwayModel: options.runwayModel, veoModel: options.veoModel } });
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
const envKeyMap = {
|
|
76
|
-
grok: "XAI_API_KEY",
|
|
77
|
-
runway: "RUNWAY_API_SECRET",
|
|
78
|
-
kling: "KLING_API_KEY",
|
|
79
|
-
veo: "GOOGLE_API_KEY",
|
|
80
|
-
};
|
|
81
|
-
const providerNameMap = {
|
|
82
|
-
grok: "Grok",
|
|
83
|
-
runway: "Runway",
|
|
84
|
-
kling: "Kling",
|
|
85
|
-
veo: "Veo",
|
|
86
|
-
};
|
|
87
|
-
const envKey = envKeyMap[provider];
|
|
88
|
-
const providerName = providerNameMap[provider];
|
|
89
|
-
const apiKey = await getApiKey(envKey, providerName, options.apiKey);
|
|
90
|
-
if (!apiKey) {
|
|
91
|
-
exitWithError(authError(envKey, providerName));
|
|
92
|
-
}
|
|
93
|
-
// Runway gen4_turbo requires an input image (gen4.5 supports text-to-video)
|
|
94
|
-
const runwayModel = options.runwayModel || "gen4.5";
|
|
95
|
-
if (provider === "runway" && !options.image && runwayModel === "gen4_turbo") {
|
|
96
|
-
exitWithError(usageError("Runway gen4_turbo requires an input image. Use -i <image> to specify.", "Tip: Use gen4.5 (default) for text-to-video, or provide -i <image>"));
|
|
97
|
-
}
|
|
98
|
-
const spinner = ora(`Initializing ${providerName}...`).start();
|
|
99
|
-
let referenceImage;
|
|
100
|
-
let isImageToVideo = false;
|
|
101
|
-
if (options.image) {
|
|
102
|
-
spinner.text = "Reading reference image...";
|
|
103
|
-
const imagePath = resolve(process.cwd(), options.image);
|
|
104
|
-
const imageBuffer = await readFile(imagePath);
|
|
105
|
-
const ext = options.image.toLowerCase().split(".").pop();
|
|
106
|
-
const mimeTypes = {
|
|
107
|
-
jpg: "image/jpeg",
|
|
108
|
-
jpeg: "image/jpeg",
|
|
109
|
-
png: "image/png",
|
|
110
|
-
gif: "image/gif",
|
|
111
|
-
webp: "image/webp",
|
|
112
|
-
};
|
|
113
|
-
const mimeType = mimeTypes[ext || "png"] || "image/png";
|
|
114
|
-
referenceImage = `data:${mimeType};base64,${imageBuffer.toString("base64")}`;
|
|
115
|
-
isImageToVideo = true;
|
|
116
|
-
}
|
|
117
|
-
spinner.text = "Starting video generation...";
|
|
118
|
-
let result;
|
|
119
|
-
let finalResult;
|
|
120
|
-
if (provider === "runway") {
|
|
121
|
-
const runway = new RunwayProvider();
|
|
122
|
-
await runway.initialize({ apiKey });
|
|
123
|
-
result = await runway.generateVideo(prompt, {
|
|
124
|
-
prompt,
|
|
125
|
-
referenceImage,
|
|
126
|
-
duration: parseInt(options.duration),
|
|
127
|
-
aspectRatio: options.ratio,
|
|
128
|
-
seed: options.seed ? parseInt(options.seed) : undefined,
|
|
129
|
-
});
|
|
130
|
-
if (result.status === "failed") {
|
|
131
|
-
spinner.fail(result.error || "Failed to start generation");
|
|
132
|
-
exitWithError(apiError(result.error || "Failed to start Runway generation", true));
|
|
133
|
-
}
|
|
134
|
-
console.log();
|
|
135
|
-
console.log(chalk.bold.cyan("Video Generation Started"));
|
|
136
|
-
console.log(chalk.dim("─".repeat(60)));
|
|
137
|
-
console.log(`Provider: ${chalk.bold(`Runway ${runwayModel}`)}`);
|
|
138
|
-
console.log(`Task ID: ${chalk.bold(result.id)}`);
|
|
139
|
-
if (!options.wait) {
|
|
140
|
-
spinner.succeed(chalk.green("Generation started"));
|
|
141
|
-
console.log();
|
|
142
|
-
console.log(chalk.dim("Check status with:"));
|
|
143
|
-
console.log(chalk.dim(` vibe ai video-status ${result.id}`));
|
|
144
|
-
console.log();
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
spinner.text = "Generating video (this may take 1-2 minutes)...";
|
|
148
|
-
finalResult = await runway.waitForCompletion(result.id, (status) => {
|
|
149
|
-
if (status.progress !== undefined) {
|
|
150
|
-
spinner.text = `Generating video... ${status.progress}%`;
|
|
151
|
-
}
|
|
152
|
-
}, 300000);
|
|
153
|
-
}
|
|
154
|
-
else if (provider === "kling") {
|
|
155
|
-
const kling = new KlingProvider();
|
|
156
|
-
await kling.initialize({ apiKey });
|
|
157
|
-
if (!kling.isConfigured()) {
|
|
158
|
-
spinner.fail("Invalid API key format");
|
|
159
|
-
exitWithError(authError("KLING_API_KEY", "Kling"));
|
|
160
|
-
}
|
|
161
|
-
// Kling v2.x requires image URL, not base64 — auto-upload to ImgBB
|
|
162
|
-
let klingImage = referenceImage;
|
|
163
|
-
if (klingImage && klingImage.startsWith("data:")) {
|
|
164
|
-
spinner.text = "Uploading image to ImgBB for Kling...";
|
|
165
|
-
const imgbbKey = (await getApiKeyFromConfig("imgbb")) || process.env.IMGBB_API_KEY;
|
|
166
|
-
if (!imgbbKey) {
|
|
167
|
-
spinner.fail("Kling requires image URL. Set IMGBB_API_KEY for auto-upload.");
|
|
168
|
-
exitWithError(authError("IMGBB_API_KEY", "ImgBB"));
|
|
169
|
-
}
|
|
170
|
-
// Extract raw base64 from data URI
|
|
171
|
-
const base64Data = klingImage.split(",")[1];
|
|
172
|
-
const imageBuffer = Buffer.from(base64Data, "base64");
|
|
173
|
-
const uploadResult = await uploadToImgbb(imageBuffer, imgbbKey);
|
|
174
|
-
if (!uploadResult.success || !uploadResult.url) {
|
|
175
|
-
spinner.fail(`ImgBB upload failed: ${uploadResult.error}`);
|
|
176
|
-
exitWithError(apiError(`ImgBB upload failed: ${uploadResult.error}`, true));
|
|
177
|
-
}
|
|
178
|
-
klingImage = uploadResult.url;
|
|
179
|
-
spinner.text = "Starting video generation...";
|
|
180
|
-
}
|
|
181
|
-
result = await kling.generateVideo(prompt, {
|
|
182
|
-
prompt,
|
|
183
|
-
referenceImage: klingImage,
|
|
184
|
-
duration: parseInt(options.duration),
|
|
185
|
-
aspectRatio: options.ratio,
|
|
186
|
-
negativePrompt: options.negative,
|
|
187
|
-
mode: options.mode,
|
|
188
|
-
});
|
|
189
|
-
if (result.status === "failed") {
|
|
190
|
-
spinner.fail(result.error || "Failed to start generation");
|
|
191
|
-
exitWithError(apiError(result.error || "Failed to start Kling generation", true));
|
|
192
|
-
}
|
|
193
|
-
console.log();
|
|
194
|
-
console.log(chalk.bold.cyan("Video Generation Started"));
|
|
195
|
-
console.log(chalk.dim("─".repeat(60)));
|
|
196
|
-
console.log(`Provider: ${chalk.bold("Kling AI")}`);
|
|
197
|
-
console.log(`Task ID: ${chalk.bold(result.id)}`);
|
|
198
|
-
console.log(`Type: ${isImageToVideo ? "image2video" : "text2video"}`);
|
|
199
|
-
if (!options.wait) {
|
|
200
|
-
spinner.succeed(chalk.green("Generation started"));
|
|
201
|
-
console.log();
|
|
202
|
-
console.log(chalk.dim("Check status with:"));
|
|
203
|
-
console.log(chalk.dim(` vibe ai kling-status ${result.id}${isImageToVideo ? " --type image2video" : ""}`));
|
|
204
|
-
console.log();
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
spinner.text = "Generating video (this may take 2-5 minutes)...";
|
|
208
|
-
const taskType = isImageToVideo ? "image2video" : "text2video";
|
|
209
|
-
finalResult = await kling.waitForCompletion(result.id, taskType, (status) => {
|
|
210
|
-
spinner.text = `Generating video... ${status.status}`;
|
|
211
|
-
}, 600000);
|
|
212
|
-
}
|
|
213
|
-
else if (provider === "veo") {
|
|
214
|
-
const gemini = new GeminiProvider();
|
|
215
|
-
await gemini.initialize({ apiKey });
|
|
216
|
-
// Map Veo model alias to full model ID
|
|
217
|
-
const veoModelMap = {
|
|
218
|
-
"3.0": "veo-3.0-generate-preview",
|
|
219
|
-
"3.1": "veo-3.1-generate-preview",
|
|
220
|
-
"3.1-fast": "veo-3.1-fast-generate-preview",
|
|
221
|
-
};
|
|
222
|
-
const veoModel = veoModelMap[options.veoModel] || "veo-3.1-fast-generate-preview";
|
|
223
|
-
const veoDuration = parseInt(options.duration) <= 6 ? 6 : 8;
|
|
224
|
-
// Prepare last frame if provided
|
|
225
|
-
let lastFrame;
|
|
226
|
-
if (options.lastFrame) {
|
|
227
|
-
const lastFramePath = resolve(process.cwd(), options.lastFrame);
|
|
228
|
-
const lastFrameBuffer = await readFile(lastFramePath);
|
|
229
|
-
const ext = options.lastFrame.toLowerCase().split(".").pop();
|
|
230
|
-
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
|
|
231
|
-
lastFrame = `data:${mimeType};base64,${lastFrameBuffer.toString("base64")}`;
|
|
232
|
-
}
|
|
233
|
-
// Prepare reference images if provided
|
|
234
|
-
let refImages;
|
|
235
|
-
if (options.refImages && options.refImages.length > 0) {
|
|
236
|
-
refImages = [];
|
|
237
|
-
for (const refPath of options.refImages.slice(0, 3)) {
|
|
238
|
-
const absRefPath = resolve(process.cwd(), refPath);
|
|
239
|
-
const refBuffer = await readFile(absRefPath);
|
|
240
|
-
const ext = refPath.toLowerCase().split(".").pop();
|
|
241
|
-
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
|
|
242
|
-
refImages.push({ base64: refBuffer.toString("base64"), mimeType });
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
result = await gemini.generateVideo(prompt, {
|
|
246
|
-
prompt,
|
|
247
|
-
referenceImage,
|
|
248
|
-
duration: veoDuration,
|
|
249
|
-
aspectRatio: options.ratio,
|
|
250
|
-
model: veoModel,
|
|
251
|
-
negativePrompt: options.negative,
|
|
252
|
-
resolution: options.resolution,
|
|
253
|
-
lastFrame,
|
|
254
|
-
referenceImages: refImages,
|
|
255
|
-
personGeneration: options.person,
|
|
256
|
-
});
|
|
257
|
-
if (result.status === "failed") {
|
|
258
|
-
spinner.fail(result.error || "Failed to start generation");
|
|
259
|
-
exitWithError(apiError(result.error || "Failed to start Veo generation", true));
|
|
260
|
-
}
|
|
261
|
-
console.log();
|
|
262
|
-
console.log(chalk.bold.cyan("Video Generation Started"));
|
|
263
|
-
console.log(chalk.dim("─".repeat(60)));
|
|
264
|
-
console.log(`Provider: ${chalk.bold("Google Veo 3.1")}`);
|
|
265
|
-
console.log(`Task ID: ${chalk.bold(result.id)}`);
|
|
266
|
-
if (!options.wait) {
|
|
267
|
-
spinner.succeed(chalk.green("Generation started"));
|
|
268
|
-
console.log();
|
|
269
|
-
console.log(chalk.dim("Veo generation is synchronous - video URL available above"));
|
|
270
|
-
console.log();
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
spinner.text = "Generating video (this may take 1-3 minutes)...";
|
|
274
|
-
finalResult = await gemini.waitForVideoCompletion(result.id, (status) => {
|
|
275
|
-
spinner.text = `Generating video... ${status.status}`;
|
|
276
|
-
}, 300000);
|
|
277
|
-
}
|
|
278
|
-
else if (provider === "grok") {
|
|
279
|
-
const grok = new GrokProvider();
|
|
280
|
-
await grok.initialize({ apiKey });
|
|
281
|
-
result = await grok.generateVideo(prompt, {
|
|
282
|
-
prompt,
|
|
283
|
-
referenceImage,
|
|
284
|
-
duration: parseInt(options.duration),
|
|
285
|
-
aspectRatio: options.ratio,
|
|
286
|
-
});
|
|
287
|
-
if (result.status === "failed") {
|
|
288
|
-
spinner.fail(result.error || "Failed to start generation");
|
|
289
|
-
exitWithError(apiError(result.error || "Failed to start Grok generation", true));
|
|
290
|
-
}
|
|
291
|
-
console.log();
|
|
292
|
-
console.log(chalk.bold.cyan("Video Generation Started"));
|
|
293
|
-
console.log(chalk.dim("─".repeat(60)));
|
|
294
|
-
console.log(`Provider: ${chalk.bold("Grok Imagine")}`);
|
|
295
|
-
console.log(`Task ID: ${chalk.bold(result.id)}`);
|
|
296
|
-
if (!options.wait) {
|
|
297
|
-
spinner.succeed(chalk.green("Generation started"));
|
|
298
|
-
console.log();
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
spinner.text = "Generating video (this may take 1-3 minutes)...";
|
|
302
|
-
finalResult = await grok.waitForCompletion(result.id, (status) => {
|
|
303
|
-
spinner.text = `Generating video... ${status.status}`;
|
|
304
|
-
}, 300000);
|
|
305
|
-
}
|
|
306
|
-
if (!finalResult || finalResult.status !== "completed") {
|
|
307
|
-
spinner.fail(finalResult?.error || "Generation failed");
|
|
308
|
-
exitWithError(apiError(finalResult?.error || "Video generation failed", true));
|
|
309
|
-
}
|
|
310
|
-
spinner.succeed(chalk.green("Video generated"));
|
|
311
|
-
console.log();
|
|
312
|
-
if (finalResult.videoUrl) {
|
|
313
|
-
console.log(`Video URL: ${finalResult.videoUrl}`);
|
|
314
|
-
}
|
|
315
|
-
if (finalResult.duration) {
|
|
316
|
-
console.log(`Duration: ${finalResult.duration}s`);
|
|
317
|
-
}
|
|
318
|
-
console.log();
|
|
319
|
-
if (options.output && finalResult.videoUrl) {
|
|
320
|
-
const downloadSpinner = ora("Downloading video...").start();
|
|
321
|
-
try {
|
|
322
|
-
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
323
|
-
const outputPath = resolve(process.cwd(), options.output);
|
|
324
|
-
await writeFile(outputPath, buffer);
|
|
325
|
-
downloadSpinner.succeed(chalk.green(`Saved to: ${outputPath}`));
|
|
326
|
-
}
|
|
327
|
-
catch (err) {
|
|
328
|
-
downloadSpinner.fail(chalk.red(`Failed to download video: ${err instanceof Error ? err.message : err}`));
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
catch (error) {
|
|
333
|
-
exitWithError(generalError(error instanceof Error ? error.message : "Video generation failed"));
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
aiCommand
|
|
337
|
-
.command("video-status")
|
|
338
|
-
.description("Check Runway video generation status")
|
|
339
|
-
.argument("<task-id>", "Task ID from video generation")
|
|
340
|
-
.option("-k, --api-key <key>", "Runway API key (or set RUNWAY_API_SECRET env)")
|
|
341
|
-
.option("-w, --wait", "Wait for completion")
|
|
342
|
-
.option("-o, --output <path>", "Download video when complete")
|
|
343
|
-
.action(async (taskId, options) => {
|
|
344
|
-
try {
|
|
345
|
-
if (options.output) {
|
|
346
|
-
validateOutputPath(options.output);
|
|
347
|
-
}
|
|
348
|
-
const apiKey = await getApiKey("RUNWAY_API_SECRET", "Runway", options.apiKey);
|
|
349
|
-
if (!apiKey) {
|
|
350
|
-
exitWithError(authError("RUNWAY_API_SECRET", "Runway"));
|
|
351
|
-
}
|
|
352
|
-
const spinner = ora("Checking status...").start();
|
|
353
|
-
const runway = new RunwayProvider();
|
|
354
|
-
await runway.initialize({ apiKey });
|
|
355
|
-
let result = await runway.getGenerationStatus(taskId);
|
|
356
|
-
if (options.wait && result.status !== "completed" && result.status !== "failed" && result.status !== "cancelled") {
|
|
357
|
-
spinner.text = "Waiting for completion...";
|
|
358
|
-
result = await runway.waitForCompletion(taskId, (status) => {
|
|
359
|
-
if (status.progress !== undefined) {
|
|
360
|
-
spinner.text = `Generating... ${status.progress}%`;
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
spinner.stop();
|
|
365
|
-
console.log();
|
|
366
|
-
console.log(chalk.bold.cyan("Generation Status"));
|
|
367
|
-
console.log(chalk.dim("─".repeat(60)));
|
|
368
|
-
console.log(`Task ID: ${taskId}`);
|
|
369
|
-
console.log(`Status: ${getStatusColor(result.status)}`);
|
|
370
|
-
if (result.progress !== undefined) {
|
|
371
|
-
console.log(`Progress: ${result.progress}%`);
|
|
372
|
-
}
|
|
373
|
-
if (result.videoUrl) {
|
|
374
|
-
console.log(`Video URL: ${result.videoUrl}`);
|
|
375
|
-
}
|
|
376
|
-
if (result.error) {
|
|
377
|
-
console.log(`Error: ${chalk.red(result.error)}`);
|
|
378
|
-
}
|
|
379
|
-
console.log();
|
|
380
|
-
if (options.output && result.videoUrl) {
|
|
381
|
-
const downloadSpinner = ora("Downloading video...").start();
|
|
382
|
-
try {
|
|
383
|
-
const buffer = await downloadVideo(result.videoUrl, apiKey);
|
|
384
|
-
const outputPath = resolve(process.cwd(), options.output);
|
|
385
|
-
await writeFile(outputPath, buffer);
|
|
386
|
-
downloadSpinner.succeed(chalk.green(`Saved to: ${outputPath}`));
|
|
387
|
-
}
|
|
388
|
-
catch (err) {
|
|
389
|
-
downloadSpinner.fail(chalk.red(`Failed to download video: ${err instanceof Error ? err.message : err}`));
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
catch (error) {
|
|
394
|
-
exitWithError(generalError(error instanceof Error ? error.message : "Failed to get status"));
|
|
395
|
-
}
|
|
396
|
-
});
|
|
397
|
-
aiCommand
|
|
398
|
-
.command("video-cancel")
|
|
399
|
-
.description("Cancel Runway video generation")
|
|
400
|
-
.argument("<task-id>", "Task ID to cancel")
|
|
401
|
-
.option("-k, --api-key <key>", "Runway API key (or set RUNWAY_API_SECRET env)")
|
|
402
|
-
.option("--dry-run", "Preview parameters without executing")
|
|
403
|
-
.action(async (taskId, options) => {
|
|
404
|
-
try {
|
|
405
|
-
if (options.dryRun) {
|
|
406
|
-
outputResult({ dryRun: true, command: "ai video-cancel", params: { taskId } });
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
const apiKey = await getApiKey("RUNWAY_API_SECRET", "Runway", options.apiKey);
|
|
410
|
-
if (!apiKey) {
|
|
411
|
-
exitWithError(authError("RUNWAY_API_SECRET", "Runway"));
|
|
412
|
-
}
|
|
413
|
-
const spinner = ora("Cancelling generation...").start();
|
|
414
|
-
const runway = new RunwayProvider();
|
|
415
|
-
await runway.initialize({ apiKey });
|
|
416
|
-
const success = await runway.cancelGeneration(taskId);
|
|
417
|
-
if (success) {
|
|
418
|
-
spinner.succeed(chalk.green("Generation cancelled"));
|
|
419
|
-
}
|
|
420
|
-
else {
|
|
421
|
-
spinner.fail("Failed to cancel generation");
|
|
422
|
-
exitWithError(apiError("Failed to cancel generation", true));
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
catch (error) {
|
|
426
|
-
exitWithError(generalError(error instanceof Error ? error.message : "Failed to cancel generation"));
|
|
427
|
-
}
|
|
428
|
-
});
|
|
429
|
-
aiCommand
|
|
430
|
-
.command("kling")
|
|
431
|
-
.description("Generate video using Kling AI")
|
|
432
|
-
.argument("<prompt>", "Text prompt describing the video")
|
|
433
|
-
.option("-k, --api-key <key>", "Kling API key (ACCESS_KEY:SECRET_KEY) or set KLING_API_KEY env")
|
|
434
|
-
.option("-o, --output <path>", "Output file path (downloads video)")
|
|
435
|
-
.option("-i, --image <path>", "Reference image for image-to-video")
|
|
436
|
-
.option("-d, --duration <sec>", "Duration: 5 or 10 seconds", "5")
|
|
437
|
-
.option("-r, --ratio <ratio>", "Aspect ratio: 16:9, 9:16, or 1:1", "16:9")
|
|
438
|
-
.option("-m, --mode <mode>", "Generation mode: std (standard) or pro", "pro")
|
|
439
|
-
.option("-n, --negative <prompt>", "Negative prompt (what to avoid)")
|
|
440
|
-
.option("--no-wait", "Start generation and return task ID without waiting")
|
|
441
|
-
.option("--dry-run", "Preview parameters without executing")
|
|
442
|
-
.action(async (prompt, options) => {
|
|
443
|
-
try {
|
|
444
|
-
if (options.output) {
|
|
445
|
-
validateOutputPath(options.output);
|
|
446
|
-
}
|
|
447
|
-
if (options.dryRun) {
|
|
448
|
-
outputResult({ dryRun: true, command: "ai kling", params: { prompt, output: options.output, image: options.image, duration: options.duration, ratio: options.ratio, mode: options.mode, negative: options.negative } });
|
|
449
|
-
return;
|
|
450
|
-
}
|
|
451
|
-
const apiKey = await getApiKey("KLING_API_KEY", "Kling", options.apiKey);
|
|
452
|
-
if (!apiKey) {
|
|
453
|
-
exitWithError(authError("KLING_API_KEY", "Kling"));
|
|
454
|
-
}
|
|
455
|
-
const spinner = ora("Initializing Kling AI...").start();
|
|
456
|
-
const kling = new KlingProvider();
|
|
457
|
-
await kling.initialize({ apiKey });
|
|
458
|
-
if (!kling.isConfigured()) {
|
|
459
|
-
spinner.fail("Invalid API key format");
|
|
460
|
-
exitWithError(authError("KLING_API_KEY", "Kling"));
|
|
461
|
-
}
|
|
462
|
-
let referenceImage;
|
|
463
|
-
let isImageToVideo = false;
|
|
464
|
-
if (options.image) {
|
|
465
|
-
spinner.text = "Reading reference image...";
|
|
466
|
-
const imagePath = resolve(process.cwd(), options.image);
|
|
467
|
-
const imageBuffer = await readFile(imagePath);
|
|
468
|
-
const ext = options.image.toLowerCase().split(".").pop();
|
|
469
|
-
const mimeTypes = {
|
|
470
|
-
jpg: "image/jpeg",
|
|
471
|
-
jpeg: "image/jpeg",
|
|
472
|
-
png: "image/png",
|
|
473
|
-
gif: "image/gif",
|
|
474
|
-
webp: "image/webp",
|
|
475
|
-
};
|
|
476
|
-
const mimeType = mimeTypes[ext || "png"] || "image/png";
|
|
477
|
-
referenceImage = `data:${mimeType};base64,${imageBuffer.toString("base64")}`;
|
|
478
|
-
isImageToVideo = true;
|
|
479
|
-
}
|
|
480
|
-
// Kling v2.x requires image URL, not base64 — auto-upload to ImgBB
|
|
481
|
-
let klingImage = referenceImage;
|
|
482
|
-
if (klingImage && klingImage.startsWith("data:")) {
|
|
483
|
-
spinner.text = "Uploading image to ImgBB for Kling...";
|
|
484
|
-
const imgbbKey = (await getApiKeyFromConfig("imgbb")) || process.env.IMGBB_API_KEY;
|
|
485
|
-
if (!imgbbKey) {
|
|
486
|
-
spinner.fail("Kling requires image URL. Set IMGBB_API_KEY for auto-upload.");
|
|
487
|
-
exitWithError(authError("IMGBB_API_KEY", "ImgBB"));
|
|
488
|
-
}
|
|
489
|
-
const base64Data = klingImage.split(",")[1];
|
|
490
|
-
const imageBuffer = Buffer.from(base64Data, "base64");
|
|
491
|
-
const uploadResult = await uploadToImgbb(imageBuffer, imgbbKey);
|
|
492
|
-
if (!uploadResult.success || !uploadResult.url) {
|
|
493
|
-
spinner.fail(`ImgBB upload failed: ${uploadResult.error}`);
|
|
494
|
-
exitWithError(apiError(`ImgBB upload failed: ${uploadResult.error}`, true));
|
|
495
|
-
}
|
|
496
|
-
klingImage = uploadResult.url;
|
|
497
|
-
}
|
|
498
|
-
spinner.text = "Starting video generation...";
|
|
499
|
-
const result = await kling.generateVideo(prompt, {
|
|
500
|
-
prompt,
|
|
501
|
-
referenceImage: klingImage,
|
|
502
|
-
duration: parseInt(options.duration),
|
|
503
|
-
aspectRatio: options.ratio,
|
|
504
|
-
negativePrompt: options.negative,
|
|
505
|
-
mode: options.mode,
|
|
506
|
-
});
|
|
507
|
-
if (result.status === "failed") {
|
|
508
|
-
spinner.fail(result.error || "Failed to start generation");
|
|
509
|
-
exitWithError(apiError(result.error || "Failed to start Kling generation", true));
|
|
510
|
-
}
|
|
511
|
-
console.log();
|
|
512
|
-
console.log(chalk.bold.cyan("Kling Video Generation Started"));
|
|
513
|
-
console.log(chalk.dim("─".repeat(60)));
|
|
514
|
-
console.log(`Task ID: ${chalk.bold(result.id)}`);
|
|
515
|
-
console.log(`Type: ${isImageToVideo ? "image2video" : "text2video"}`);
|
|
516
|
-
if (!options.wait) {
|
|
517
|
-
spinner.succeed(chalk.green("Generation started"));
|
|
518
|
-
console.log();
|
|
519
|
-
console.log(chalk.dim("Check status with:"));
|
|
520
|
-
console.log(chalk.dim(` vibe ai kling-status ${result.id}${isImageToVideo ? " --type image2video" : ""}`));
|
|
521
|
-
console.log();
|
|
522
|
-
return;
|
|
523
|
-
}
|
|
524
|
-
spinner.text = "Generating video (this may take 2-5 minutes)...";
|
|
525
|
-
const taskType = isImageToVideo ? "image2video" : "text2video";
|
|
526
|
-
const finalResult = await kling.waitForCompletion(result.id, taskType, (status) => {
|
|
527
|
-
spinner.text = `Generating video... ${status.status}`;
|
|
528
|
-
}, 600000);
|
|
529
|
-
if (finalResult.status !== "completed") {
|
|
530
|
-
spinner.fail(finalResult.error || "Generation failed");
|
|
531
|
-
exitWithError(apiError(finalResult.error || "Kling video generation failed", true));
|
|
532
|
-
}
|
|
533
|
-
spinner.succeed(chalk.green("Video generated"));
|
|
534
|
-
console.log();
|
|
535
|
-
if (finalResult.videoUrl) {
|
|
536
|
-
console.log(`Video URL: ${finalResult.videoUrl}`);
|
|
537
|
-
}
|
|
538
|
-
if (finalResult.duration) {
|
|
539
|
-
console.log(`Duration: ${finalResult.duration}s`);
|
|
540
|
-
}
|
|
541
|
-
console.log();
|
|
542
|
-
if (options.output && finalResult.videoUrl) {
|
|
543
|
-
const downloadSpinner = ora("Downloading video...").start();
|
|
544
|
-
try {
|
|
545
|
-
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
546
|
-
const outputPath = resolve(process.cwd(), options.output);
|
|
547
|
-
await writeFile(outputPath, buffer);
|
|
548
|
-
downloadSpinner.succeed(chalk.green(`Saved to: ${outputPath}`));
|
|
549
|
-
}
|
|
550
|
-
catch (err) {
|
|
551
|
-
downloadSpinner.fail(chalk.red(`Failed to download video: ${err instanceof Error ? err.message : err}`));
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
catch (error) {
|
|
556
|
-
exitWithError(generalError(error instanceof Error ? error.message : "Video generation failed"));
|
|
557
|
-
}
|
|
558
|
-
});
|
|
559
|
-
aiCommand
|
|
560
|
-
.command("kling-status")
|
|
561
|
-
.description("Check Kling video generation status")
|
|
562
|
-
.argument("<task-id>", "Task ID from video generation")
|
|
563
|
-
.option("-k, --api-key <key>", "Kling API key (or set KLING_API_KEY env)")
|
|
564
|
-
.option("-t, --type <type>", "Task type: text2video or image2video", "text2video")
|
|
565
|
-
.option("-w, --wait", "Wait for completion")
|
|
566
|
-
.option("-o, --output <path>", "Download video when complete")
|
|
567
|
-
.action(async (taskId, options) => {
|
|
568
|
-
try {
|
|
569
|
-
if (options.output) {
|
|
570
|
-
validateOutputPath(options.output);
|
|
571
|
-
}
|
|
572
|
-
const apiKey = await getApiKey("KLING_API_KEY", "Kling", options.apiKey);
|
|
573
|
-
if (!apiKey) {
|
|
574
|
-
exitWithError(authError("KLING_API_KEY", "Kling"));
|
|
575
|
-
}
|
|
576
|
-
const spinner = ora("Checking status...").start();
|
|
577
|
-
const kling = new KlingProvider();
|
|
578
|
-
await kling.initialize({ apiKey });
|
|
579
|
-
const taskType = options.type;
|
|
580
|
-
let result = await kling.getGenerationStatus(taskId, taskType);
|
|
581
|
-
if (options.wait && result.status !== "completed" && result.status !== "failed" && result.status !== "cancelled") {
|
|
582
|
-
spinner.text = "Waiting for completion...";
|
|
583
|
-
result = await kling.waitForCompletion(taskId, taskType, (status) => {
|
|
584
|
-
spinner.text = `Generating... ${status.status}`;
|
|
585
|
-
});
|
|
586
|
-
}
|
|
587
|
-
spinner.stop();
|
|
588
|
-
console.log();
|
|
589
|
-
console.log(chalk.bold.cyan("Kling Generation Status"));
|
|
590
|
-
console.log(chalk.dim("─".repeat(60)));
|
|
591
|
-
console.log(`Task ID: ${taskId}`);
|
|
592
|
-
console.log(`Type: ${taskType}`);
|
|
593
|
-
console.log(`Status: ${getStatusColor(result.status)}`);
|
|
594
|
-
if (result.videoUrl) {
|
|
595
|
-
console.log(`Video URL: ${result.videoUrl}`);
|
|
596
|
-
}
|
|
597
|
-
if (result.duration) {
|
|
598
|
-
console.log(`Duration: ${result.duration}s`);
|
|
599
|
-
}
|
|
600
|
-
if (result.error) {
|
|
601
|
-
console.log(`Error: ${chalk.red(result.error)}`);
|
|
602
|
-
}
|
|
603
|
-
console.log();
|
|
604
|
-
if (options.output && result.videoUrl) {
|
|
605
|
-
const downloadSpinner = ora("Downloading video...").start();
|
|
606
|
-
try {
|
|
607
|
-
const buffer = await downloadVideo(result.videoUrl, apiKey);
|
|
608
|
-
const outputPath = resolve(process.cwd(), options.output);
|
|
609
|
-
await writeFile(outputPath, buffer);
|
|
610
|
-
downloadSpinner.succeed(chalk.green(`Saved to: ${outputPath}`));
|
|
611
|
-
}
|
|
612
|
-
catch (err) {
|
|
613
|
-
downloadSpinner.fail(chalk.red(`Failed to download video: ${err instanceof Error ? err.message : err}`));
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
catch (error) {
|
|
618
|
-
exitWithError(generalError(error instanceof Error ? error.message : "Failed to get Kling status"));
|
|
619
|
-
}
|
|
620
|
-
});
|
|
621
|
-
aiCommand
|
|
622
|
-
.command("video-extend")
|
|
623
|
-
.description("Extend video duration using Kling AI (requires Kling video ID)")
|
|
624
|
-
.argument("<video-id>", "Kling video ID (from generation result)")
|
|
625
|
-
.option("-k, --api-key <key>", "Kling API key (ACCESS_KEY:SECRET_KEY) or set KLING_API_KEY env")
|
|
626
|
-
.option("-o, --output <path>", "Output file path")
|
|
627
|
-
.option("--prompt <text>", "Continuation prompt")
|
|
628
|
-
.option("-d, --duration <sec>", "Duration: 5 or 10 seconds", "5")
|
|
629
|
-
.option("-n, --negative <prompt>", "Negative prompt (what to avoid)")
|
|
630
|
-
.option("--no-wait", "Start generation and return task ID without waiting")
|
|
631
|
-
.option("--dry-run", "Preview parameters without executing")
|
|
632
|
-
.action(async (videoId, options) => {
|
|
633
|
-
try {
|
|
634
|
-
if (options.output) {
|
|
635
|
-
validateOutputPath(options.output);
|
|
636
|
-
}
|
|
637
|
-
if (options.dryRun) {
|
|
638
|
-
outputResult({ dryRun: true, command: "ai video-extend", params: { videoId, output: options.output, prompt: options.prompt, duration: options.duration, negative: options.negative } });
|
|
639
|
-
return;
|
|
640
|
-
}
|
|
641
|
-
const apiKey = await getApiKey("KLING_API_KEY", "Kling", options.apiKey);
|
|
642
|
-
if (!apiKey) {
|
|
643
|
-
exitWithError(authError("KLING_API_KEY", "Kling"));
|
|
644
|
-
}
|
|
645
|
-
const spinner = ora("Initializing Kling AI...").start();
|
|
646
|
-
const kling = new KlingProvider();
|
|
647
|
-
await kling.initialize({ apiKey });
|
|
648
|
-
if (!kling.isConfigured()) {
|
|
649
|
-
spinner.fail("Invalid API key format");
|
|
650
|
-
exitWithError(authError("KLING_API_KEY", "Kling"));
|
|
651
|
-
}
|
|
652
|
-
spinner.text = "Starting video extension...";
|
|
653
|
-
const result = await kling.extendVideo(videoId, {
|
|
654
|
-
prompt: options.prompt,
|
|
655
|
-
negativePrompt: options.negative,
|
|
656
|
-
duration: options.duration,
|
|
657
|
-
});
|
|
658
|
-
if (result.status === "failed") {
|
|
659
|
-
spinner.fail(result.error || "Failed to start extension");
|
|
660
|
-
exitWithError(apiError(result.error || "Failed to start Kling video extension", true));
|
|
661
|
-
}
|
|
662
|
-
console.log();
|
|
663
|
-
console.log(chalk.bold.cyan("Video Extension Started"));
|
|
664
|
-
console.log(chalk.dim("─".repeat(60)));
|
|
665
|
-
console.log(`Task ID: ${chalk.bold(result.id)}`);
|
|
666
|
-
if (!options.wait) {
|
|
667
|
-
spinner.succeed(chalk.green("Extension started"));
|
|
668
|
-
console.log();
|
|
669
|
-
console.log(chalk.dim("Check status with:"));
|
|
670
|
-
console.log(chalk.dim(` pnpm vibe ai video-extend-status ${result.id}`));
|
|
671
|
-
console.log();
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
spinner.text = "Extending video (this may take 2-5 minutes)...";
|
|
675
|
-
const finalResult = await kling.waitForExtendCompletion(result.id, (status) => {
|
|
676
|
-
spinner.text = `Extending video... ${status.status}`;
|
|
677
|
-
}, 600000);
|
|
678
|
-
if (finalResult.status !== "completed") {
|
|
679
|
-
spinner.fail(finalResult.error || "Extension failed");
|
|
680
|
-
exitWithError(apiError(finalResult.error || "Kling video extension failed", true));
|
|
681
|
-
}
|
|
682
|
-
spinner.succeed(chalk.green("Video extended"));
|
|
683
|
-
console.log();
|
|
684
|
-
if (finalResult.videoUrl) {
|
|
685
|
-
console.log(`Video URL: ${finalResult.videoUrl}`);
|
|
686
|
-
}
|
|
687
|
-
if (finalResult.duration) {
|
|
688
|
-
console.log(`Duration: ${finalResult.duration}s`);
|
|
689
|
-
}
|
|
690
|
-
console.log();
|
|
691
|
-
if (options.output && finalResult.videoUrl) {
|
|
692
|
-
const downloadSpinner = ora("Downloading video...").start();
|
|
693
|
-
try {
|
|
694
|
-
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
695
|
-
const outputPath = resolve(process.cwd(), options.output);
|
|
696
|
-
await writeFile(outputPath, buffer);
|
|
697
|
-
downloadSpinner.succeed(chalk.green(`Saved to: ${outputPath}`));
|
|
698
|
-
}
|
|
699
|
-
catch (err) {
|
|
700
|
-
downloadSpinner.fail(chalk.red(`Failed to download video: ${err instanceof Error ? err.message : err}`));
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
catch (error) {
|
|
705
|
-
exitWithError(generalError(error instanceof Error ? error.message : "Video extension failed"));
|
|
706
|
-
}
|
|
707
|
-
});
|
|
708
|
-
aiCommand
|
|
709
|
-
.command("veo-extend")
|
|
710
|
-
.description("Extend a Veo video using the operation name from a previous generation")
|
|
711
|
-
.argument("<operation-name>", "Veo operation name (from generation result)")
|
|
712
|
-
.option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)")
|
|
713
|
-
.option("-o, --output <path>", "Output file path")
|
|
714
|
-
.option("--prompt <text>", "Continuation prompt")
|
|
715
|
-
.option("-d, --duration <sec>", "Duration: 4, 6, or 8 seconds", "6")
|
|
716
|
-
.option("--veo-model <model>", "Veo model: 3.0, 3.1, 3.1-fast", "3.1")
|
|
717
|
-
.option("--no-wait", "Start extension and return operation name without waiting")
|
|
718
|
-
.option("--dry-run", "Preview parameters without executing")
|
|
719
|
-
.action(async (operationName, options) => {
|
|
720
|
-
try {
|
|
721
|
-
if (options.output) {
|
|
722
|
-
validateOutputPath(options.output);
|
|
723
|
-
}
|
|
724
|
-
if (options.dryRun) {
|
|
725
|
-
outputResult({ dryRun: true, command: "ai veo-extend", params: { operationName, output: options.output, prompt: options.prompt, duration: options.duration, veoModel: options.veoModel } });
|
|
726
|
-
return;
|
|
727
|
-
}
|
|
728
|
-
const apiKey = await getApiKey("GOOGLE_API_KEY", "Google", options.apiKey);
|
|
729
|
-
if (!apiKey) {
|
|
730
|
-
exitWithError(authError("GOOGLE_API_KEY", "Google"));
|
|
731
|
-
}
|
|
732
|
-
const spinner = ora("Initializing Veo...").start();
|
|
733
|
-
const gemini = new GeminiProvider();
|
|
734
|
-
await gemini.initialize({ apiKey });
|
|
735
|
-
const veoModelMap = {
|
|
736
|
-
"3.0": "veo-3.0-generate-preview",
|
|
737
|
-
"3.1": "veo-3.1-generate-preview",
|
|
738
|
-
"3.1-fast": "veo-3.1-fast-generate-preview",
|
|
739
|
-
};
|
|
740
|
-
const veoModel = veoModelMap[options.veoModel] || "veo-3.1-generate-preview";
|
|
741
|
-
spinner.text = "Starting video extension...";
|
|
742
|
-
const result = await gemini.extendVideo(operationName, options.prompt, {
|
|
743
|
-
duration: parseInt(options.duration),
|
|
744
|
-
model: veoModel,
|
|
745
|
-
});
|
|
746
|
-
if (result.status === "failed") {
|
|
747
|
-
spinner.fail(result.error || "Failed to start extension");
|
|
748
|
-
exitWithError(apiError(result.error || "Failed to start Veo video extension", true));
|
|
749
|
-
}
|
|
750
|
-
console.log();
|
|
751
|
-
console.log(chalk.bold.cyan("Veo Video Extension Started"));
|
|
752
|
-
console.log(chalk.dim("─".repeat(60)));
|
|
753
|
-
console.log(`Operation: ${chalk.bold(result.id)}`);
|
|
754
|
-
if (!options.wait) {
|
|
755
|
-
spinner.succeed(chalk.green("Extension started"));
|
|
756
|
-
console.log();
|
|
757
|
-
console.log(chalk.dim("Check status or wait with:"));
|
|
758
|
-
console.log(chalk.dim(` vibe ai veo-extend ${result.id} --wait`));
|
|
759
|
-
console.log();
|
|
760
|
-
return;
|
|
761
|
-
}
|
|
762
|
-
spinner.text = "Extending video (this may take 1-3 minutes)...";
|
|
763
|
-
const finalResult = await gemini.waitForVideoCompletion(result.id, (status) => {
|
|
764
|
-
spinner.text = `Extending video... ${status.status}`;
|
|
765
|
-
}, 300000);
|
|
766
|
-
if (finalResult.status !== "completed") {
|
|
767
|
-
spinner.fail(finalResult.error || "Extension failed");
|
|
768
|
-
exitWithError(apiError(finalResult.error || "Veo video extension failed", true));
|
|
769
|
-
}
|
|
770
|
-
spinner.succeed(chalk.green("Video extended"));
|
|
771
|
-
console.log();
|
|
772
|
-
if (finalResult.videoUrl) {
|
|
773
|
-
console.log(`Video URL: ${finalResult.videoUrl}`);
|
|
774
|
-
}
|
|
775
|
-
console.log();
|
|
776
|
-
if (options.output && finalResult.videoUrl) {
|
|
777
|
-
const downloadSpinner = ora("Downloading video...").start();
|
|
778
|
-
try {
|
|
779
|
-
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
780
|
-
const outputPath = resolve(process.cwd(), options.output);
|
|
781
|
-
await writeFile(outputPath, buffer);
|
|
782
|
-
downloadSpinner.succeed(chalk.green(`Saved to: ${outputPath}`));
|
|
783
|
-
}
|
|
784
|
-
catch (err) {
|
|
785
|
-
downloadSpinner.fail(chalk.red(`Failed to download video: ${err instanceof Error ? err.message : err}`));
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
catch (error) {
|
|
790
|
-
exitWithError(generalError(error instanceof Error ? error.message : "Video extension failed"));
|
|
791
|
-
}
|
|
792
|
-
});
|
|
793
|
-
}
|
|
794
|
-
export async function executeVideoGenerate(options) {
|
|
795
|
-
const { prompt, provider = "kling", image, duration = 5, ratio = "16:9", seed, mode = "std", negative, resolution, veoModel = "3.1-fast", output, wait = true, apiKey, } = options;
|
|
796
|
-
try {
|
|
797
|
-
const envKeyMap = { grok: "XAI_API_KEY", runway: "RUNWAY_API_SECRET", kling: "KLING_API_KEY", veo: "GOOGLE_API_KEY" };
|
|
798
|
-
const key = apiKey || process.env[envKeyMap[provider] || ""];
|
|
799
|
-
if (!key)
|
|
800
|
-
return { success: false, error: `${envKeyMap[provider]} required for ${provider}` };
|
|
801
|
-
// Read reference image if provided
|
|
802
|
-
let referenceImage;
|
|
803
|
-
if (image) {
|
|
804
|
-
const imagePath = resolve(process.cwd(), image);
|
|
805
|
-
const imageBuffer = await readFile(imagePath);
|
|
806
|
-
const ext = image.toLowerCase().split(".").pop();
|
|
807
|
-
const mimeTypes = { jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", webp: "image/webp" };
|
|
808
|
-
const mimeType = mimeTypes[ext || "png"] || "image/png";
|
|
809
|
-
referenceImage = `data:${mimeType};base64,${imageBuffer.toString("base64")}`;
|
|
810
|
-
}
|
|
811
|
-
if (provider === "runway") {
|
|
812
|
-
const runway = new RunwayProvider();
|
|
813
|
-
await runway.initialize({ apiKey: key });
|
|
814
|
-
const result = await runway.generateVideo(prompt, {
|
|
815
|
-
prompt, referenceImage,
|
|
816
|
-
duration: duration,
|
|
817
|
-
aspectRatio: ratio,
|
|
818
|
-
seed,
|
|
819
|
-
});
|
|
820
|
-
if (result.status === "failed")
|
|
821
|
-
return { success: false, error: result.error || "Runway generation failed" };
|
|
822
|
-
if (!wait)
|
|
823
|
-
return { success: true, taskId: result.id, status: "processing", provider: "runway" };
|
|
824
|
-
const finalResult = await runway.waitForCompletion(result.id, () => { }, 300000);
|
|
825
|
-
if (finalResult.status !== "completed")
|
|
826
|
-
return { success: false, error: finalResult.error || "Runway generation failed" };
|
|
827
|
-
let outputPath;
|
|
828
|
-
if (output && finalResult.videoUrl) {
|
|
829
|
-
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
830
|
-
outputPath = resolve(process.cwd(), output);
|
|
831
|
-
await writeFile(outputPath, buffer);
|
|
832
|
-
}
|
|
833
|
-
return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath, provider: "runway" };
|
|
834
|
-
}
|
|
835
|
-
else if (provider === "kling") {
|
|
836
|
-
const kling = new KlingProvider();
|
|
837
|
-
await kling.initialize({ apiKey: key });
|
|
838
|
-
if (!kling.isConfigured())
|
|
839
|
-
return { success: false, error: "Invalid Kling API key format" };
|
|
840
|
-
// Kling needs image URL — auto-upload to ImgBB if base64
|
|
841
|
-
let klingImage = referenceImage;
|
|
842
|
-
if (klingImage && klingImage.startsWith("data:")) {
|
|
843
|
-
const imgbbKey = process.env.IMGBB_API_KEY;
|
|
844
|
-
if (!imgbbKey)
|
|
845
|
-
return { success: false, error: "IMGBB_API_KEY required for Kling image-to-video" };
|
|
846
|
-
const base64Data = klingImage.split(",")[1];
|
|
847
|
-
const uploadResult = await uploadToImgbb(Buffer.from(base64Data, "base64"), imgbbKey);
|
|
848
|
-
if (!uploadResult.success || !uploadResult.url)
|
|
849
|
-
return { success: false, error: `ImgBB upload failed: ${uploadResult.error}` };
|
|
850
|
-
klingImage = uploadResult.url;
|
|
851
|
-
}
|
|
852
|
-
const result = await kling.generateVideo(prompt, {
|
|
853
|
-
prompt, referenceImage: klingImage,
|
|
854
|
-
duration: duration,
|
|
855
|
-
aspectRatio: ratio,
|
|
856
|
-
negativePrompt: negative,
|
|
857
|
-
mode: mode,
|
|
858
|
-
});
|
|
859
|
-
if (result.status === "failed")
|
|
860
|
-
return { success: false, error: result.error || "Kling generation failed" };
|
|
861
|
-
const taskType = referenceImage ? "image2video" : "text2video";
|
|
862
|
-
if (!wait)
|
|
863
|
-
return { success: true, taskId: result.id, status: "processing", provider: "kling" };
|
|
864
|
-
const finalResult = await kling.waitForCompletion(result.id, taskType, () => { }, 600000);
|
|
865
|
-
if (finalResult.status !== "completed")
|
|
866
|
-
return { success: false, error: finalResult.error || "Kling generation failed" };
|
|
867
|
-
let outputPath;
|
|
868
|
-
if (output && finalResult.videoUrl) {
|
|
869
|
-
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
870
|
-
outputPath = resolve(process.cwd(), output);
|
|
871
|
-
await writeFile(outputPath, buffer);
|
|
872
|
-
}
|
|
873
|
-
return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath, provider: "kling" };
|
|
874
|
-
}
|
|
875
|
-
else if (provider === "veo") {
|
|
876
|
-
const gemini = new GeminiProvider();
|
|
877
|
-
await gemini.initialize({ apiKey: key });
|
|
878
|
-
const veoModelMap = { "3.0": "veo-3.0-generate-preview", "3.1": "veo-3.1-generate-preview", "3.1-fast": "veo-3.1-fast-generate-preview" };
|
|
879
|
-
const model = veoModelMap[veoModel] || "veo-3.1-fast-generate-preview";
|
|
880
|
-
const veoDuration = duration <= 6 ? 6 : 8;
|
|
881
|
-
const result = await gemini.generateVideo(prompt, {
|
|
882
|
-
prompt, referenceImage,
|
|
883
|
-
duration: veoDuration,
|
|
884
|
-
aspectRatio: ratio,
|
|
885
|
-
model: model,
|
|
886
|
-
negativePrompt: negative,
|
|
887
|
-
resolution: resolution,
|
|
888
|
-
});
|
|
889
|
-
if (result.status === "failed")
|
|
890
|
-
return { success: false, error: result.error || "Veo generation failed" };
|
|
891
|
-
if (!wait)
|
|
892
|
-
return { success: true, taskId: result.id, status: "processing", provider: "veo" };
|
|
893
|
-
const finalResult = await gemini.waitForVideoCompletion(result.id, () => { }, 300000);
|
|
894
|
-
if (finalResult.status !== "completed")
|
|
895
|
-
return { success: false, error: finalResult.error || "Veo generation failed" };
|
|
896
|
-
let outputPath;
|
|
897
|
-
if (output && finalResult.videoUrl) {
|
|
898
|
-
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
899
|
-
outputPath = resolve(process.cwd(), output);
|
|
900
|
-
await writeFile(outputPath, buffer);
|
|
901
|
-
}
|
|
902
|
-
return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, outputPath, provider: "veo" };
|
|
903
|
-
}
|
|
904
|
-
else if (provider === "grok") {
|
|
905
|
-
const grok = new GrokProvider();
|
|
906
|
-
await grok.initialize({ apiKey: key });
|
|
907
|
-
const result = await grok.generateVideo(prompt, {
|
|
908
|
-
prompt, referenceImage,
|
|
909
|
-
duration,
|
|
910
|
-
aspectRatio: ratio,
|
|
911
|
-
});
|
|
912
|
-
if (result.status === "failed")
|
|
913
|
-
return { success: false, error: result.error || "Grok generation failed" };
|
|
914
|
-
if (!wait)
|
|
915
|
-
return { success: true, taskId: result.id, status: "processing", provider: "grok" };
|
|
916
|
-
const finalResult = await grok.waitForCompletion(result.id, () => { }, 300000);
|
|
917
|
-
if (finalResult.status !== "completed")
|
|
918
|
-
return { success: false, error: finalResult.error || "Grok generation failed" };
|
|
919
|
-
let outputPath;
|
|
920
|
-
if (output && finalResult.videoUrl) {
|
|
921
|
-
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
922
|
-
outputPath = resolve(process.cwd(), output);
|
|
923
|
-
await writeFile(outputPath, buffer);
|
|
924
|
-
}
|
|
925
|
-
return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath, provider: "grok" };
|
|
926
|
-
}
|
|
927
|
-
return { success: false, error: `Unsupported provider: ${provider}` };
|
|
928
|
-
}
|
|
929
|
-
catch (error) {
|
|
930
|
-
return { success: false, error: `Video generation failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
export async function executeVideoStatus(options) {
|
|
934
|
-
const { taskId, provider = "runway", taskType = "text2video", wait = false, output, apiKey } = options;
|
|
935
|
-
try {
|
|
936
|
-
const envKeyMap = { runway: "RUNWAY_API_SECRET", kling: "KLING_API_KEY" };
|
|
937
|
-
const key = apiKey || process.env[envKeyMap[provider] || ""];
|
|
938
|
-
if (!key)
|
|
939
|
-
return { success: false, error: `${envKeyMap[provider]} required` };
|
|
940
|
-
if (provider === "runway") {
|
|
941
|
-
const runway = new RunwayProvider();
|
|
942
|
-
await runway.initialize({ apiKey: key });
|
|
943
|
-
let result = await runway.getGenerationStatus(taskId);
|
|
944
|
-
if (wait && result.status !== "completed" && result.status !== "failed" && result.status !== "cancelled") {
|
|
945
|
-
result = await runway.waitForCompletion(taskId, () => { });
|
|
946
|
-
}
|
|
947
|
-
let outputPath;
|
|
948
|
-
if (output && result.videoUrl) {
|
|
949
|
-
const buffer = await downloadVideo(result.videoUrl, key);
|
|
950
|
-
outputPath = resolve(process.cwd(), output);
|
|
951
|
-
await writeFile(outputPath, buffer);
|
|
952
|
-
}
|
|
953
|
-
return { success: true, taskId, status: result.status, progress: result.progress, videoUrl: result.videoUrl, outputPath };
|
|
954
|
-
}
|
|
955
|
-
else if (provider === "kling") {
|
|
956
|
-
const kling = new KlingProvider();
|
|
957
|
-
await kling.initialize({ apiKey: key });
|
|
958
|
-
let result = await kling.getGenerationStatus(taskId, taskType);
|
|
959
|
-
if (wait && result.status !== "completed" && result.status !== "failed" && result.status !== "cancelled") {
|
|
960
|
-
result = await kling.waitForCompletion(taskId, taskType, () => { });
|
|
961
|
-
}
|
|
962
|
-
let outputPath;
|
|
963
|
-
if (output && result.videoUrl) {
|
|
964
|
-
const buffer = await downloadVideo(result.videoUrl, key);
|
|
965
|
-
outputPath = resolve(process.cwd(), output);
|
|
966
|
-
await writeFile(outputPath, buffer);
|
|
967
|
-
}
|
|
968
|
-
return { success: true, taskId, status: result.status, videoUrl: result.videoUrl, duration: result.duration, outputPath };
|
|
969
|
-
}
|
|
970
|
-
return { success: false, error: `Unsupported provider: ${provider}` };
|
|
971
|
-
}
|
|
972
|
-
catch (error) {
|
|
973
|
-
return { success: false, error: `Status check failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
export async function executeVideoCancel(options) {
|
|
977
|
-
const { taskId, apiKey } = options;
|
|
978
|
-
try {
|
|
979
|
-
const key = apiKey || process.env.RUNWAY_API_SECRET;
|
|
980
|
-
if (!key)
|
|
981
|
-
return { success: false, error: "RUNWAY_API_SECRET required" };
|
|
982
|
-
const runway = new RunwayProvider();
|
|
983
|
-
await runway.initialize({ apiKey: key });
|
|
984
|
-
const success = await runway.cancelGeneration(taskId);
|
|
985
|
-
return { success };
|
|
986
|
-
}
|
|
987
|
-
catch (error) {
|
|
988
|
-
return { success: false, error: `Cancel failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
export async function executeVideoExtend(options) {
|
|
992
|
-
const { videoId, provider = "kling", prompt, duration = 5, negative, veoModel = "3.1", output, wait = true, apiKey } = options;
|
|
993
|
-
try {
|
|
994
|
-
if (provider === "kling") {
|
|
995
|
-
const key = apiKey || process.env.KLING_API_KEY;
|
|
996
|
-
if (!key)
|
|
997
|
-
return { success: false, error: "KLING_API_KEY required" };
|
|
998
|
-
const kling = new KlingProvider();
|
|
999
|
-
await kling.initialize({ apiKey: key });
|
|
1000
|
-
if (!kling.isConfigured())
|
|
1001
|
-
return { success: false, error: "Invalid Kling API key format" };
|
|
1002
|
-
const result = await kling.extendVideo(videoId, {
|
|
1003
|
-
prompt,
|
|
1004
|
-
negativePrompt: negative,
|
|
1005
|
-
duration: String(duration),
|
|
1006
|
-
});
|
|
1007
|
-
if (result.status === "failed")
|
|
1008
|
-
return { success: false, error: result.error || "Kling extension failed" };
|
|
1009
|
-
if (!wait)
|
|
1010
|
-
return { success: true, taskId: result.id, status: "processing" };
|
|
1011
|
-
const finalResult = await kling.waitForExtendCompletion(result.id, () => { }, 600000);
|
|
1012
|
-
if (finalResult.status !== "completed")
|
|
1013
|
-
return { success: false, error: finalResult.error || "Kling extension failed" };
|
|
1014
|
-
let outputPath;
|
|
1015
|
-
if (output && finalResult.videoUrl) {
|
|
1016
|
-
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
1017
|
-
outputPath = resolve(process.cwd(), output);
|
|
1018
|
-
await writeFile(outputPath, buffer);
|
|
1019
|
-
}
|
|
1020
|
-
return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath };
|
|
1021
|
-
}
|
|
1022
|
-
else if (provider === "veo") {
|
|
1023
|
-
const key = apiKey || process.env.GOOGLE_API_KEY;
|
|
1024
|
-
if (!key)
|
|
1025
|
-
return { success: false, error: "GOOGLE_API_KEY required" };
|
|
1026
|
-
const gemini = new GeminiProvider();
|
|
1027
|
-
await gemini.initialize({ apiKey: key });
|
|
1028
|
-
const veoModelMap = { "3.0": "veo-3.0-generate-preview", "3.1": "veo-3.1-generate-preview", "3.1-fast": "veo-3.1-fast-generate-preview" };
|
|
1029
|
-
const model = veoModelMap[veoModel] || "veo-3.1-generate-preview";
|
|
1030
|
-
const result = await gemini.extendVideo(videoId, prompt, {
|
|
1031
|
-
duration: duration,
|
|
1032
|
-
model: model,
|
|
1033
|
-
});
|
|
1034
|
-
if (result.status === "failed")
|
|
1035
|
-
return { success: false, error: result.error || "Veo extension failed" };
|
|
1036
|
-
if (!wait)
|
|
1037
|
-
return { success: true, taskId: result.id, status: "processing" };
|
|
1038
|
-
const finalResult = await gemini.waitForVideoCompletion(result.id, () => { }, 300000);
|
|
1039
|
-
if (finalResult.status !== "completed")
|
|
1040
|
-
return { success: false, error: finalResult.error || "Veo extension failed" };
|
|
1041
|
-
let outputPath;
|
|
1042
|
-
if (output && finalResult.videoUrl) {
|
|
1043
|
-
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
1044
|
-
outputPath = resolve(process.cwd(), output);
|
|
1045
|
-
await writeFile(outputPath, buffer);
|
|
1046
|
-
}
|
|
1047
|
-
return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, outputPath };
|
|
1048
|
-
}
|
|
1049
|
-
return { success: false, error: `Unsupported provider: ${provider}` };
|
|
1050
|
-
}
|
|
1051
|
-
catch (error) {
|
|
1052
|
-
return { success: false, error: `Video extension failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
//# sourceMappingURL=ai-video.js.map
|