@vibeframe/cli 0.115.2 → 0.115.4
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/agent/adapters/gemini.d.ts +2 -0
- package/dist/agent/adapters/provider-content.test.d.ts +6 -0
- package/dist/agent/memory/index.d.ts +1 -1
- package/dist/agent/types.d.ts +8 -0
- package/dist/commands/_shared/build-video-providers.d.ts +12 -0
- package/dist/commands/_shared/build-video-providers.test.d.ts +1 -0
- package/dist/commands/_shared/edit/translate-srt.test.d.ts +1 -0
- package/dist/commands/_shared/execute-fill-gaps.d.ts +0 -2
- package/dist/commands/_shared/image-cost.d.ts +15 -0
- package/dist/commands/_shared/image-cost.test.d.ts +1 -0
- package/dist/commands/_shared/openai-image.d.ts +9 -8
- package/dist/commands/_shared/project-config.d.ts +2 -1
- package/dist/commands/_shared/scene-build.d.ts +3 -2
- package/dist/commands/_shared/scene-build.network.test.d.ts +1 -0
- package/dist/commands/_shared/video-utils.d.ts +3 -1
- package/dist/commands/agent.d.ts +6 -0
- package/dist/commands/ai-video.d.ts +2 -0
- package/dist/commands/generate/image.d.ts +1 -1
- package/dist/commands/generate/video.d.ts +1 -10
- package/dist/config/schema.d.ts +1 -1
- package/dist/index.js +1198 -817
- package/dist/testing/fake-provider-network.d.ts +45 -0
- package/dist/tools/define-tool.js +3 -2
- package/dist/tools/manifest/edit.d.ts +5 -5
- package/dist/tools/manifest/generate.d.ts +12 -6
- package/dist/tools/manifest/index.js +1132 -757
- package/dist/tools/manifest/scene.d.ts +3 -3
- package/dist/tools/manifest/storyboard.d.ts +3 -3
- package/dist/utils/image-file.d.ts +19 -0
- package/dist/utils/image-file.test.d.ts +1 -0
- package/dist/utils/remotion-precheck.test.d.ts +1 -0
- package/dist/utils/remotion.d.ts +7 -1
- package/package.json +4 -3
|
@@ -191,8 +191,8 @@ var init_api_keys = __esm({
|
|
|
191
191
|
envVar: "OPENAI_API_KEY",
|
|
192
192
|
label: "OpenAI",
|
|
193
193
|
showInSetup: true,
|
|
194
|
-
setupDescription: "gpt-image-2 image gen (
|
|
195
|
-
envExampleComment: "OpenAI API Key (Whisper transcription, gpt-4o-mini-tts narration, gpt-image-2
|
|
194
|
+
setupDescription: "gpt-image-2.5 image gen ($), gpt-4o-mini-tts narration, Whisper transcribe, Agent",
|
|
195
|
+
envExampleComment: "OpenAI API Key (Whisper transcription, gpt-4o-mini-tts narration, gpt-image-2.5 text-to-image)",
|
|
196
196
|
envExampleUrl: "https://platform.openai.com/api-keys",
|
|
197
197
|
keyFormat: { prefix: /^sk-/, example: "sk-..." }
|
|
198
198
|
});
|
|
@@ -267,8 +267,7 @@ var init_api_keys = __esm({
|
|
|
267
267
|
setupDescription: "v2.5/v3 video \u2014 std ($$) and pro ($$$) modes",
|
|
268
268
|
envExampleComment: "Kling API Key (Kling video generation)",
|
|
269
269
|
envExampleUrl: "https://platform.klingai.com/",
|
|
270
|
-
envExampleExtraLines: ["
|
|
271
|
-
keyFormat: { prefix: /:/, example: "ACCESS_KEY:SECRET_KEY" }
|
|
270
|
+
envExampleExtraLines: ["API key from the Kling console (legacy ACCESS_KEY:SECRET_KEY also works)"]
|
|
272
271
|
});
|
|
273
272
|
defineApiKey({
|
|
274
273
|
configKey: "replicate",
|
|
@@ -440,6 +439,82 @@ var init_whisper = __esm({
|
|
|
440
439
|
}
|
|
441
440
|
});
|
|
442
441
|
|
|
442
|
+
// ../ai-providers/dist/catalog/catalog.js
|
|
443
|
+
function listModels(filter = {}) {
|
|
444
|
+
return MODEL_CATALOG.filter((m) => (!filter.provider || m.provider === filter.provider) && (!filter.kind || m.kind === filter.kind));
|
|
445
|
+
}
|
|
446
|
+
function defaultModel(provider, kind) {
|
|
447
|
+
const found = MODEL_CATALOG.find((m) => m.provider === provider && m.kind === kind && m.default);
|
|
448
|
+
if (!found)
|
|
449
|
+
throw new Error(`Model catalog has no default ${kind} model for ${provider}`);
|
|
450
|
+
return found;
|
|
451
|
+
}
|
|
452
|
+
function findModel(provider, kind, aliasOrId) {
|
|
453
|
+
const key = aliasOrId?.trim();
|
|
454
|
+
if (!key)
|
|
455
|
+
return defaultModel(provider, kind);
|
|
456
|
+
const lower = key.toLowerCase();
|
|
457
|
+
return listModels({ provider, kind }).find((m) => m.id === key || m.aliases?.includes(lower));
|
|
458
|
+
}
|
|
459
|
+
function modelAliases(provider, kind) {
|
|
460
|
+
return listModels({ provider, kind }).flatMap((m) => m.aliases ?? []);
|
|
461
|
+
}
|
|
462
|
+
var MODEL_CATALOG;
|
|
463
|
+
var init_catalog = __esm({
|
|
464
|
+
"../ai-providers/dist/catalog/catalog.js"() {
|
|
465
|
+
"use strict";
|
|
466
|
+
MODEL_CATALOG = [
|
|
467
|
+
// ── LLMs ──────────────────────────────────────────────────────────────
|
|
468
|
+
{ id: "claude-sonnet-5-5", provider: "claude", kind: "llm", label: "Claude Sonnet 5.5", aliases: ["sonnet"], default: true, status: "ga", price: { usd: 2, per: "1M input tokens" }, note: "Agent, storyboard, translate-srt, motion default" },
|
|
469
|
+
{ id: "claude-opus-5-5", provider: "claude", kind: "llm", label: "Claude Opus 5.5", aliases: ["opus"], status: "ga", price: { usd: 4, per: "1M input tokens" } },
|
|
470
|
+
{ id: "claude-opus-4-6", provider: "claude", kind: "llm", label: "Claude Opus 4.6", aliases: ["opus-4-6"], status: "legacy", price: { usd: 5, per: "1M input tokens" } },
|
|
471
|
+
{ id: "gpt-5.4-mini", provider: "openai", kind: "llm", label: "GPT-5.4 mini", default: true, status: "ga", price: { usd: 0.75, per: "1M input tokens" }, note: "Agent and storyboard default (tools on Chat Completions)" },
|
|
472
|
+
{ id: "gemini-3.8-flash", provider: "gemini", kind: "llm", label: "Gemini 3.8 Flash", aliases: ["flash", "latest", "flash-3.8", "gemini"], default: true, status: "ga", price: { usd: 0.75, per: "1M input tokens", basis: "until 2026-12-31, then $1.50" } },
|
|
473
|
+
{ id: "gemini-3.5-flash", provider: "gemini", kind: "llm", label: "Gemini 3.5 Flash", aliases: ["flash-3.5"], status: "ga" },
|
|
474
|
+
{ id: "gemini-3-flash-preview", provider: "gemini", kind: "llm", label: "Gemini 3 Flash (preview)", aliases: ["flash-3"], status: "preview" },
|
|
475
|
+
{ id: "gemini-3.1-pro-preview", provider: "gemini", kind: "llm", label: "Gemini 3.1 Pro (preview)", aliases: ["pro", "pro-3.1", "3.1-pro", "gemini-3.1-pro"], status: "preview" },
|
|
476
|
+
{ id: "gemini-2.5-flash", provider: "gemini", kind: "llm", label: "Gemini 2.5 Flash", aliases: ["flash-2.5"], status: "legacy", note: "New projects cannot use 2.5 models since 2026-09-18" },
|
|
477
|
+
{ id: "gemini-2.5-pro", provider: "gemini", kind: "llm", label: "Gemini 2.5 Pro", aliases: ["pro-2.5", "2.5-pro"], status: "legacy" },
|
|
478
|
+
{ id: "grok-4.3", provider: "grok", kind: "llm", label: "Grok 4.3", default: true, status: "ga", price: { usd: 1.25, per: "1M input tokens" } },
|
|
479
|
+
{ id: "grok-4.7", provider: "grok", kind: "llm", label: "Grok 4.7", status: "ga", price: { usd: 2, per: "1M input tokens" } },
|
|
480
|
+
// ── Images ────────────────────────────────────────────────────────────
|
|
481
|
+
{ id: "gpt-image-2.5-sunburst", provider: "openai", kind: "image", label: "GPT Image 2.5 Sunburst", aliases: ["2.5", "sunburst"], default: true, status: "ga", price: { usd: 0.211, per: "image", basis: "high, 1024x1024" } },
|
|
482
|
+
{ id: "gpt-image-2.5-flare", provider: "openai", kind: "image", label: "GPT Image 2.5 Flare", aliases: ["flare", "2.5-flare"], status: "ga", price: { usd: 0.211, per: "image", basis: "high, 1024x1024" } },
|
|
483
|
+
{ id: "gpt-image-2", provider: "openai", kind: "image", label: "GPT Image 2", aliases: ["2"], status: "ga", price: { usd: 0.211, per: "image", basis: "high, 1024x1024" } },
|
|
484
|
+
{ id: "gpt-image-1.5", provider: "openai", kind: "image", label: "GPT Image 1.5", aliases: ["1.5"], status: "deprecated", shutdown: "2026-12-01", price: { usd: 0.133, per: "image", basis: "high, 1024x1024" } },
|
|
485
|
+
{ id: "gemini-3.1-flash-image", provider: "gemini", kind: "image", label: "Nano Banana 2", aliases: ["flash", "3.1-flash", "latest"], default: true, status: "ga", price: { usd: 0.067, per: "image", basis: "1K" } },
|
|
486
|
+
{ id: "gemini-3.1-flash-lite-image", provider: "gemini", kind: "image", label: "Nano Banana 2 Lite", aliases: ["lite"], status: "ga", price: { usd: 0.034, per: "image", basis: "1K" } },
|
|
487
|
+
{ id: "gemini-3-pro-image", provider: "gemini", kind: "image", label: "Nano Banana Pro", aliases: ["pro"], status: "ga", price: { usd: 0.134, per: "image", basis: "1K-2K" } },
|
|
488
|
+
{ id: "gemini-2.5-flash-image", provider: "gemini", kind: "image", label: "Nano Banana (2.5 Flash Image)", status: "deprecated", shutdown: "2026-10-02" },
|
|
489
|
+
{ id: "gemini-3.1-flash-image-preview", provider: "gemini", kind: "image", label: "Nano Banana 2 (preview)", status: "deprecated", shutdown: "2026-06-25" },
|
|
490
|
+
{ id: "gemini-3-pro-image-preview", provider: "gemini", kind: "image", label: "Nano Banana Pro (preview)", status: "deprecated", shutdown: "2026-06-25" },
|
|
491
|
+
{ id: "grok-imagine-image", provider: "grok", kind: "image", label: "Grok Imagine Image", default: true, status: "ga", price: { usd: 0.02, per: "image" } },
|
|
492
|
+
{ id: "grok-imagine-image-2.0", provider: "grok", kind: "image", label: "Grok Imagine Image 2.0", aliases: ["pro", "2.0", "quality"], status: "ga", price: { usd: 0.08, per: "image", basis: "medium, 2K" } },
|
|
493
|
+
// ── Video ─────────────────────────────────────────────────────────────
|
|
494
|
+
{ id: "seedance-2.0", provider: "seedance", kind: "video", label: "Seedance 2.0", aliases: ["quality", "2.0"], default: true, status: "ga", price: { usd: 0.3024, per: "second", basis: "720p 16:9" }, note: "4-15 s, native audio" },
|
|
495
|
+
{ id: "seedance-2.0-fast", provider: "seedance", kind: "video", label: "Seedance 2.0 Fast", aliases: ["fast"], status: "ga", price: { usd: 0.2419, per: "second", basis: "720p 16:9" }, note: "4-15 s, up to 720p, native audio" },
|
|
496
|
+
{ id: "seedance-2.5", provider: "seedance", kind: "video", label: "Seedance 2.5", aliases: ["2.5"], status: "ga", price: { usd: 0.473, per: "second", basis: "720p 16:9" }, note: "Opt-in; 4-30 s, native audio" },
|
|
497
|
+
{ id: "gemini-omni-1.1-flash", provider: "omni", kind: "video", label: "Gemini Omni 1.1 Flash", default: true, status: "ga", price: { usd: 0.1, per: "second", basis: "720p" }, note: "Google video default; the model picks 3-10 s; native audio" },
|
|
498
|
+
{ id: "veo-3.1-generate-preview", provider: "veo", kind: "video", label: "Veo 3.1", aliases: ["3.1"], status: "deprecated", shutdown: "2026-10-22", price: { usd: 0.4, per: "second", basis: "720p/1080p" }, note: "4-8 s, native audio; explicit `-p veo` only" },
|
|
499
|
+
{ id: "veo-3.1-fast-generate-preview", provider: "veo", kind: "video", label: "Veo 3.1 Fast", aliases: ["3.1-fast"], default: true, status: "deprecated", shutdown: "2026-10-22", price: { usd: 0.1, per: "second", basis: "720p" }, note: "4-8 s, native audio; explicit `-p veo` only" },
|
|
500
|
+
{ id: "grok-imagine-video-1.5", provider: "grok", kind: "video", label: "Grok Imagine Video 1.5", aliases: ["1.5"], default: true, status: "ga", price: { usd: 0.14, per: "second", basis: "720p" }, note: "1-15 s, native audio; 720p unless `--resolution` says otherwise" },
|
|
501
|
+
{ id: "grok-imagine-video-1.5-lite", provider: "grok", kind: "video", label: "Grok Imagine Video 1.5 Lite", aliases: ["lite", "1.5-lite"], status: "ga", price: { usd: 0.03, per: "second", basis: "720p" }, note: "1-15 s, native audio" },
|
|
502
|
+
{ id: "grok-imagine-video", provider: "grok", kind: "video", label: "Grok Imagine Video", aliases: ["classic"], status: "legacy", price: { usd: 0.05, per: "second", basis: "480p" }, note: "Previous generation" },
|
|
503
|
+
{ id: "kling-v3", provider: "kling", kind: "video", label: "Kling v3", aliases: ["v3"], default: true, status: "ga", price: { usd: 0.084, per: "second", basis: "std, silent" }, note: "3-15 s, multi-shot; `std` 720p, `pro` 1080p" },
|
|
504
|
+
{ id: "kling-v2-6", provider: "kling", kind: "video", label: "Kling v2.6", aliases: ["v2.6"], status: "ga", price: { usd: 0.042, per: "second", basis: "std 720p" }, note: "5 or 10 s" },
|
|
505
|
+
{ id: "kling-v2-5-turbo", provider: "kling", kind: "video", label: "Kling v2.5 Turbo", aliases: ["v2.5-turbo", "v2.5"], status: "ga", price: { usd: 0.042, per: "second", basis: "std" }, note: "5 or 10 s, no audio" },
|
|
506
|
+
{ id: "gen4.5", provider: "runway", kind: "video", label: "Runway Gen-4.5", default: true, status: "ga", price: { usd: 0.12, per: "second" }, note: "2-10 s, no audio" },
|
|
507
|
+
{ id: "gen4_turbo", provider: "runway", kind: "video", label: "Runway Gen-4 Turbo", status: "ga", price: { usd: 0.05, per: "second" }, note: "Image-to-video only, no audio" },
|
|
508
|
+
// ── Audio ─────────────────────────────────────────────────────────────
|
|
509
|
+
{ id: "eleven_v3", provider: "elevenlabs", kind: "speech", label: "ElevenLabs v3", default: true, status: "ga", price: { usd: 0.08, per: "1K characters" } },
|
|
510
|
+
{ id: "gpt-4o-mini-tts", provider: "openai", kind: "speech", label: "GPT-4o mini TTS", default: true, status: "deprecated", shutdown: "2027-01-06" },
|
|
511
|
+
{ id: "music_v2_5", provider: "elevenlabs", kind: "music", label: "ElevenLabs Music v2.5", default: true, status: "ga", price: { usd: 0.15, per: "minute" } },
|
|
512
|
+
{ id: "eleven_text_to_sound_v2", provider: "elevenlabs", kind: "sound-effect", label: "ElevenLabs Sound Effects v2", default: true, status: "ga", price: { usd: 0.12, per: "minute" }, note: "0.5-30 s" },
|
|
513
|
+
{ id: "whisper-1", provider: "openai", kind: "transcription", label: "Whisper", default: true, status: "deprecated", shutdown: "2027-02-26", note: "Only OpenAI model with word timestamps" }
|
|
514
|
+
];
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
|
|
443
518
|
// ../ai-providers/dist/gemini/gemini-models.js
|
|
444
519
|
function isGeminiTextModelAlias(model) {
|
|
445
520
|
return Object.prototype.hasOwnProperty.call(GEMINI_TEXT_MODEL_ALIASES, model);
|
|
@@ -458,18 +533,11 @@ var GEMINI_DEFAULT_TEXT_MODEL, GEMINI_AGENT_DEFAULT_TEXT_MODEL, GEMINI_TEXT_MODE
|
|
|
458
533
|
var init_gemini_models = __esm({
|
|
459
534
|
"../ai-providers/dist/gemini/gemini-models.js"() {
|
|
460
535
|
"use strict";
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
"flash-3.5": GEMINI_DEFAULT_TEXT_MODEL,
|
|
467
|
-
"flash-3": "gemini-3-flash-preview",
|
|
468
|
-
"flash-2.5": "gemini-2.5-flash",
|
|
469
|
-
pro: "gemini-2.5-pro",
|
|
470
|
-
"pro-3.1": "gemini-3.1-pro-preview"
|
|
471
|
-
};
|
|
472
|
-
GEMINI_TEXT_MODEL_HELP = "flash/latest (Gemini 3.5 Flash), flash-3.5, flash-3, flash-2.5, pro, pro-3.1, or a full gemini-* model ID";
|
|
536
|
+
init_catalog();
|
|
537
|
+
GEMINI_DEFAULT_TEXT_MODEL = defaultModel("gemini", "llm").id;
|
|
538
|
+
GEMINI_AGENT_DEFAULT_TEXT_MODEL = GEMINI_DEFAULT_TEXT_MODEL;
|
|
539
|
+
GEMINI_TEXT_MODEL_ALIASES = Object.fromEntries(listModels({ provider: "gemini", kind: "llm" }).flatMap((m) => (m.aliases ?? []).map((a) => [a, m.id])));
|
|
540
|
+
GEMINI_TEXT_MODEL_HELP = "flash/latest (Gemini 3.8 Flash), flash-3.8, flash-3.5, flash-3, flash-2.5, pro (Gemini 3.1 Pro), pro-3.1, pro-2.5, or a full gemini-* model ID";
|
|
473
541
|
}
|
|
474
542
|
});
|
|
475
543
|
|
|
@@ -656,7 +724,6 @@ UNIVERSAL RULES:
|
|
|
656
724
|
system_instruction: { parts: [{ text: systemPrompt }] },
|
|
657
725
|
contents: [{ role: "user", parts: [{ text: userPrompt }] }],
|
|
658
726
|
generationConfig: {
|
|
659
|
-
temperature: 0.8,
|
|
660
727
|
maxOutputTokens: 16384
|
|
661
728
|
}
|
|
662
729
|
})
|
|
@@ -757,7 +824,7 @@ Return the complete modified component as JSON.`
|
|
|
757
824
|
]
|
|
758
825
|
}
|
|
759
826
|
],
|
|
760
|
-
generationConfig: {
|
|
827
|
+
generationConfig: { maxOutputTokens: 16384 }
|
|
761
828
|
})
|
|
762
829
|
});
|
|
763
830
|
if (!response.ok) {
|
|
@@ -803,18 +870,7 @@ var init_gemini_motion = __esm({
|
|
|
803
870
|
"../ai-providers/dist/gemini/gemini-motion.js"() {
|
|
804
871
|
"use strict";
|
|
805
872
|
init_gemini_models();
|
|
806
|
-
GEMINI_MOTION_MODELS =
|
|
807
|
-
gemini: GEMINI_DEFAULT_TEXT_MODEL,
|
|
808
|
-
flash: GEMINI_DEFAULT_TEXT_MODEL,
|
|
809
|
-
latest: GEMINI_DEFAULT_TEXT_MODEL,
|
|
810
|
-
"flash-3.5": GEMINI_DEFAULT_TEXT_MODEL,
|
|
811
|
-
"flash-3": "gemini-3-flash-preview",
|
|
812
|
-
"flash-2.5": "gemini-2.5-flash",
|
|
813
|
-
pro: "gemini-2.5-pro",
|
|
814
|
-
"2.5-pro": "gemini-2.5-pro",
|
|
815
|
-
"3.1-pro": "gemini-3.1-pro-preview",
|
|
816
|
-
"pro-3.1": "gemini-3.1-pro-preview"
|
|
817
|
-
};
|
|
873
|
+
GEMINI_MOTION_MODELS = GEMINI_TEXT_MODEL_ALIASES;
|
|
818
874
|
STYLE_USER_INSTRUCTIONS = {
|
|
819
875
|
minimal: "CENTER-ALIGNED pure typography. Thin lines + large title + subtitle. NO glass panels, NO bokeh, NO dark bars. Breathing pulse during hold.",
|
|
820
876
|
corporate: "Data-rich info bar at bottom + top-right badge. Animated number counter. Brand color stripe. Progress bar.",
|
|
@@ -922,7 +978,6 @@ var init_storyboard_prompt = __esm({
|
|
|
922
978
|
async function analyzeContent(api, content, targetDuration, options) {
|
|
923
979
|
const creativity = options?.creativity || "low";
|
|
924
980
|
const systemPrompt = buildStoryboardSystemPrompt(targetDuration, creativity);
|
|
925
|
-
const temperature = creativity === "high" ? 1 : 0.7;
|
|
926
981
|
try {
|
|
927
982
|
const payload = {
|
|
928
983
|
system_instruction: {
|
|
@@ -932,7 +987,6 @@ async function analyzeContent(api, content, targetDuration, options) {
|
|
|
932
987
|
parts: [{ text: buildStoryboardUserMessage(content) }]
|
|
933
988
|
}],
|
|
934
989
|
generationConfig: {
|
|
935
|
-
temperature,
|
|
936
990
|
maxOutputTokens: 4096
|
|
937
991
|
}
|
|
938
992
|
};
|
|
@@ -1003,7 +1057,15 @@ var init_http = __esm({
|
|
|
1003
1057
|
});
|
|
1004
1058
|
|
|
1005
1059
|
// ../ai-providers/dist/gemini/GeminiProvider.js
|
|
1006
|
-
|
|
1060
|
+
function resolveVeoModel(alias) {
|
|
1061
|
+
if (Object.hasOwn(VEO_MODEL_ALIASES, alias)) {
|
|
1062
|
+
return VEO_MODEL_ALIASES[alias];
|
|
1063
|
+
}
|
|
1064
|
+
const valid = Object.keys(VEO_MODEL_ALIASES).join(", ");
|
|
1065
|
+
const hint = alias === "3.0" ? " Veo 3.0 was shut down by Google on 2025-11-12." : "";
|
|
1066
|
+
throw new Error(`Unknown Veo model "${alias}". Valid: ${valid}.${hint}`);
|
|
1067
|
+
}
|
|
1068
|
+
var VEO_MODEL_ALIASES, GeminiProvider, geminiProvider;
|
|
1007
1069
|
var init_GeminiProvider = __esm({
|
|
1008
1070
|
"../ai-providers/dist/gemini/GeminiProvider.js"() {
|
|
1009
1071
|
"use strict";
|
|
@@ -1011,15 +1073,8 @@ var init_GeminiProvider = __esm({
|
|
|
1011
1073
|
init_gemini_models();
|
|
1012
1074
|
init_gemini_storyboard();
|
|
1013
1075
|
init_http();
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
"3.1-flash": "gemini-3.1-flash-image-preview",
|
|
1017
|
-
"latest": "gemini-3.1-flash-image-preview",
|
|
1018
|
-
"pro": "gemini-3-pro-image-preview",
|
|
1019
|
-
"gemini-2.5-flash-image": "gemini-2.5-flash-image",
|
|
1020
|
-
"gemini-3.1-flash-image-preview": "gemini-3.1-flash-image-preview",
|
|
1021
|
-
"gemini-3-pro-image-preview": "gemini-3-pro-image-preview"
|
|
1022
|
-
};
|
|
1076
|
+
init_catalog();
|
|
1077
|
+
VEO_MODEL_ALIASES = Object.fromEntries(listModels({ provider: "veo", kind: "video" }).flatMap((m) => (m.aliases ?? []).map((a) => [a, m.id])));
|
|
1023
1078
|
GeminiProvider = class {
|
|
1024
1079
|
constructor() {
|
|
1025
1080
|
this.id = "gemini";
|
|
@@ -1278,9 +1333,7 @@ var init_GeminiProvider = __esm({
|
|
|
1278
1333
|
* Resolve model alias to full model ID
|
|
1279
1334
|
*/
|
|
1280
1335
|
resolveModel(model) {
|
|
1281
|
-
|
|
1282
|
-
return MODEL_MAP["flash"];
|
|
1283
|
-
return MODEL_MAP[model] || MODEL_MAP["flash"];
|
|
1336
|
+
return (findModel("gemini", "image", model) ?? defaultModel("gemini", "image")).id;
|
|
1284
1337
|
}
|
|
1285
1338
|
/**
|
|
1286
1339
|
* Check if model is Pro
|
|
@@ -1324,7 +1377,7 @@ var init_GeminiProvider = __esm({
|
|
|
1324
1377
|
contents: [{ parts: [{ text: prompt3 }] }],
|
|
1325
1378
|
generationConfig
|
|
1326
1379
|
};
|
|
1327
|
-
const is31Flash = modelId
|
|
1380
|
+
const is31Flash = modelId.startsWith("gemini-3.1-flash-image");
|
|
1328
1381
|
if (options.imageSearchGrounding && is31Flash) {
|
|
1329
1382
|
payload.tools = [{ googleSearch: { searchTypes: { webSearch: {}, imageSearch: {} } } }];
|
|
1330
1383
|
} else if (options.grounding && isPro) {
|
|
@@ -1552,7 +1605,6 @@ var init_GeminiProvider = __esm({
|
|
|
1552
1605
|
videoPart.video_metadata = videoMetadata;
|
|
1553
1606
|
}
|
|
1554
1607
|
const generationConfig = {
|
|
1555
|
-
temperature: 0.4,
|
|
1556
1608
|
maxOutputTokens: 8192
|
|
1557
1609
|
};
|
|
1558
1610
|
if (options.lowResolution) {
|
|
@@ -1634,7 +1686,6 @@ var init_GeminiProvider = __esm({
|
|
|
1634
1686
|
}
|
|
1635
1687
|
}));
|
|
1636
1688
|
const generationConfig = {
|
|
1637
|
-
temperature: 0.4,
|
|
1638
1689
|
maxOutputTokens: 8192
|
|
1639
1690
|
};
|
|
1640
1691
|
if (options.lowResolution) {
|
|
@@ -1734,7 +1785,6 @@ Respond with ONLY the JSON array, no other text.`;
|
|
|
1734
1785
|
body: JSON.stringify({
|
|
1735
1786
|
contents: [{ parts: [{ text: prompt3 }] }],
|
|
1736
1787
|
generationConfig: {
|
|
1737
|
-
temperature: 0.3,
|
|
1738
1788
|
maxOutputTokens: 1024
|
|
1739
1789
|
}
|
|
1740
1790
|
})
|
|
@@ -1828,7 +1878,7 @@ Respond with ONLY the JSON array, no other text.`;
|
|
|
1828
1878
|
return refineMotion({ apiKey: this.apiKey, baseUrl: this.baseUrl }, existingCode, instructions, options);
|
|
1829
1879
|
}
|
|
1830
1880
|
/**
|
|
1831
|
-
* Generate a storyboard from script content using Gemini
|
|
1881
|
+
* Generate a storyboard from script content using the default Gemini Flash model.
|
|
1832
1882
|
* Alternative to ClaudeProvider.analyzeContent for when Claude is unavailable.
|
|
1833
1883
|
*/
|
|
1834
1884
|
async analyzeContent(content, targetDuration, options) {
|
|
@@ -1843,43 +1893,48 @@ Respond with ONLY the JSON array, no other text.`;
|
|
|
1843
1893
|
});
|
|
1844
1894
|
|
|
1845
1895
|
// ../ai-providers/dist/gemini/gemini-omni.js
|
|
1846
|
-
function
|
|
1847
|
-
const
|
|
1848
|
-
|
|
1849
|
-
return refs[0];
|
|
1850
|
-
const ref = options.referenceImage;
|
|
1851
|
-
if (typeof ref === "string" && ref) {
|
|
1896
|
+
function frameImages(options) {
|
|
1897
|
+
const frames = [];
|
|
1898
|
+
const toInline = (ref) => {
|
|
1852
1899
|
const m = ref.match(/^data:(.+?);base64,(.*)$/);
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1900
|
+
return m ? { mimeType: m[1], base64: m[2] } : { mimeType: "image/png", base64: ref };
|
|
1901
|
+
};
|
|
1902
|
+
if (options.referenceImages?.[0]?.base64)
|
|
1903
|
+
frames.push(options.referenceImages[0]);
|
|
1904
|
+
else if (typeof options.referenceImage === "string" && options.referenceImage) {
|
|
1905
|
+
frames.push(toInline(options.referenceImage));
|
|
1906
|
+
}
|
|
1907
|
+
if (frames.length > 0 && options.lastFrame)
|
|
1908
|
+
frames.push(toInline(options.lastFrame));
|
|
1909
|
+
return frames;
|
|
1910
|
+
}
|
|
1911
|
+
function findOmniVideo(response) {
|
|
1912
|
+
for (const step of response.steps ?? []) {
|
|
1913
|
+
if (step.type !== "model_output")
|
|
1914
|
+
continue;
|
|
1915
|
+
const video = step.content?.find((c) => c.type === "video");
|
|
1916
|
+
if (video)
|
|
1917
|
+
return video;
|
|
1856
1918
|
}
|
|
1857
|
-
return
|
|
1919
|
+
return response.output_video;
|
|
1858
1920
|
}
|
|
1859
|
-
function
|
|
1860
|
-
|
|
1861
|
-
return void 0;
|
|
1862
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
1863
|
-
if (typeof v === "string" && /^https?:\/\//.test(v) && /(uri|url|video)/i.test(k))
|
|
1864
|
-
return v;
|
|
1865
|
-
if (typeof v === "object") {
|
|
1866
|
-
const nested = findVideoUrl(v);
|
|
1867
|
-
if (nested)
|
|
1868
|
-
return nested;
|
|
1869
|
-
}
|
|
1870
|
-
}
|
|
1871
|
-
return void 0;
|
|
1921
|
+
function fileIdFromUri(uri) {
|
|
1922
|
+
return uri.match(/files\/([^/?:]+)/)?.[1];
|
|
1872
1923
|
}
|
|
1873
|
-
var OMNI_MODEL,
|
|
1924
|
+
var OMNI_MODEL, API_ROOT, FILE_POLL_INTERVAL_MS, FILE_POLL_TIMEOUT_MS, OmniProvider, omniProvider;
|
|
1874
1925
|
var init_gemini_omni = __esm({
|
|
1875
1926
|
"../ai-providers/dist/gemini/gemini-omni.js"() {
|
|
1876
1927
|
"use strict";
|
|
1877
|
-
|
|
1878
|
-
|
|
1928
|
+
init_http();
|
|
1929
|
+
init_catalog();
|
|
1930
|
+
OMNI_MODEL = defaultModel("omni", "video").id;
|
|
1931
|
+
API_ROOT = "https://generativelanguage.googleapis.com";
|
|
1932
|
+
FILE_POLL_INTERVAL_MS = 3e3;
|
|
1933
|
+
FILE_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
1879
1934
|
OmniProvider = class {
|
|
1880
1935
|
constructor() {
|
|
1881
1936
|
this.id = "omni";
|
|
1882
|
-
this.label = "Gemini Omni
|
|
1937
|
+
this.label = "Gemini Omni 1.1 Flash";
|
|
1883
1938
|
}
|
|
1884
1939
|
async initialize(config2) {
|
|
1885
1940
|
this.apiKey = config2.apiKey;
|
|
@@ -1892,22 +1947,23 @@ var init_gemini_omni = __esm({
|
|
|
1892
1947
|
return { id: "", status: "failed", error: "GOOGLE_API_KEY not configured for Gemini Omni" };
|
|
1893
1948
|
}
|
|
1894
1949
|
const opts = options ?? { prompt: prompt3 };
|
|
1895
|
-
const
|
|
1896
|
-
const
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
inputs.push({ inline_data: { mime_type: image.mimeType, data: image.base64 } });
|
|
1901
|
-
}
|
|
1950
|
+
const frames = frameImages(opts);
|
|
1951
|
+
const input = frames.length === 0 ? prompt3 : [
|
|
1952
|
+
...frames.map((f) => ({ type: "image", data: f.base64, mime_type: f.mimeType })),
|
|
1953
|
+
{ type: "text", text: prompt3 }
|
|
1954
|
+
];
|
|
1902
1955
|
const body = {
|
|
1903
1956
|
model: OMNI_MODEL,
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1957
|
+
input,
|
|
1958
|
+
response_format: {
|
|
1959
|
+
type: "video",
|
|
1960
|
+
aspect_ratio: opts.aspectRatio === "9:16" ? "9:16" : "16:9",
|
|
1961
|
+
resolution: opts.resolution ?? "720p",
|
|
1962
|
+
delivery: "uri"
|
|
1907
1963
|
}
|
|
1908
1964
|
};
|
|
1909
1965
|
try {
|
|
1910
|
-
const res = await fetch(
|
|
1966
|
+
const res = await fetch(`${API_ROOT}/v1beta/interactions`, {
|
|
1911
1967
|
method: "POST",
|
|
1912
1968
|
headers: { "Content-Type": "application/json", "x-goog-api-key": this.apiKey },
|
|
1913
1969
|
body: JSON.stringify(body)
|
|
@@ -1917,33 +1973,52 @@ var init_gemini_omni = __esm({
|
|
|
1917
1973
|
return {
|
|
1918
1974
|
id: "",
|
|
1919
1975
|
status: "failed",
|
|
1920
|
-
error: `Gemini Omni
|
|
1976
|
+
error: `Gemini Omni request failed: HTTP ${res.status} - ${text.slice(0, 300)}`
|
|
1921
1977
|
};
|
|
1922
1978
|
}
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1979
|
+
const parsed = JSON.parse(text);
|
|
1980
|
+
const id = parsed.id ?? "";
|
|
1981
|
+
const video = findOmniVideo(parsed);
|
|
1982
|
+
if (!video?.uri) {
|
|
1983
|
+
const reason = parsed.error?.message ?? `status ${parsed.status ?? "unknown"}`;
|
|
1984
|
+
return { id, status: "failed", error: `Gemini Omni returned no video (${reason})` };
|
|
1928
1985
|
}
|
|
1929
|
-
const
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
};
|
|
1986
|
+
const fileId = fileIdFromUri(video.uri);
|
|
1987
|
+
if (!fileId) {
|
|
1988
|
+
return { id, status: "failed", error: `Gemini Omni returned an unexpected video URI: ${video.uri}` };
|
|
1989
|
+
}
|
|
1990
|
+
const ready = await this.waitForFile(fileId);
|
|
1991
|
+
if (ready !== "ACTIVE") {
|
|
1992
|
+
return { id, status: "failed", error: `Gemini Omni video file ended in state ${ready}` };
|
|
1937
1993
|
}
|
|
1938
|
-
return {
|
|
1994
|
+
return {
|
|
1995
|
+
id,
|
|
1996
|
+
status: "completed",
|
|
1997
|
+
videoUrl: `${API_ROOT}/download/v1beta/files/${fileId}:download?alt=media`
|
|
1998
|
+
};
|
|
1939
1999
|
} catch (err) {
|
|
1940
2000
|
return {
|
|
1941
2001
|
id: "",
|
|
1942
2002
|
status: "failed",
|
|
1943
|
-
error: `Gemini Omni
|
|
2003
|
+
error: `Gemini Omni error: ${err instanceof Error ? err.message : String(err)}`
|
|
1944
2004
|
};
|
|
1945
2005
|
}
|
|
1946
2006
|
}
|
|
2007
|
+
/** Poll the Files API until the generated video is downloadable. */
|
|
2008
|
+
async waitForFile(fileId) {
|
|
2009
|
+
const deadline = Date.now() + FILE_POLL_TIMEOUT_MS;
|
|
2010
|
+
for (; ; ) {
|
|
2011
|
+
const res = await fetch(`${API_ROOT}/v1beta/files/${fileId}`, {
|
|
2012
|
+
headers: { "x-goog-api-key": this.apiKey }
|
|
2013
|
+
});
|
|
2014
|
+
const state = res.ok ? (await res.json()).state : `HTTP ${res.status}`;
|
|
2015
|
+
if (state !== "PROCESSING")
|
|
2016
|
+
return state ?? "UNKNOWN";
|
|
2017
|
+
if (Date.now() > deadline)
|
|
2018
|
+
return "TIMEOUT";
|
|
2019
|
+
await sleep(FILE_POLL_INTERVAL_MS);
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
1947
2022
|
};
|
|
1948
2023
|
omniProvider = new OmniProvider();
|
|
1949
2024
|
}
|
|
@@ -1977,24 +2052,33 @@ var init_gemini = __esm({
|
|
|
1977
2052
|
label: "Veo",
|
|
1978
2053
|
apiKey: "google",
|
|
1979
2054
|
kinds: ["video"],
|
|
1980
|
-
resolverPriority:
|
|
2055
|
+
// No resolverPriority: the Veo 3.1 previews shut down on 2026-10-22, so
|
|
2056
|
+
// Veo is explicit-only (`-p veo`) and Omni is the Google default.
|
|
1981
2057
|
commandsUnlocked: ["generate video -p veo"]
|
|
1982
2058
|
});
|
|
1983
2059
|
defineProvider({
|
|
1984
2060
|
id: "omni",
|
|
1985
|
-
label: "Gemini Omni
|
|
2061
|
+
label: "Gemini Omni",
|
|
1986
2062
|
apiKey: "google",
|
|
1987
2063
|
kinds: ["video"],
|
|
2064
|
+
resolverPriority: { video: 3 },
|
|
1988
2065
|
commandsUnlocked: ["generate video -p omni"]
|
|
1989
2066
|
});
|
|
1990
2067
|
}
|
|
1991
2068
|
});
|
|
1992
2069
|
|
|
2070
|
+
// ../ai-providers/dist/catalog/index.js
|
|
2071
|
+
var init_catalog2 = __esm({
|
|
2072
|
+
"../ai-providers/dist/catalog/index.js"() {
|
|
2073
|
+
"use strict";
|
|
2074
|
+
init_catalog();
|
|
2075
|
+
}
|
|
2076
|
+
});
|
|
2077
|
+
|
|
1993
2078
|
// ../ai-providers/dist/openai/openai-storyboard.js
|
|
1994
2079
|
async function analyzeContent2(apiKey, content, targetDuration, options) {
|
|
1995
2080
|
const creativity = options?.creativity || "low";
|
|
1996
|
-
const systemPrompt = buildStoryboardSystemPrompt(targetDuration, creativity);
|
|
1997
|
-
const temperature = creativity === "high" ? 1 : 0.7;
|
|
2081
|
+
const systemPrompt = buildStoryboardSystemPrompt(targetDuration, creativity) + '\n\nWrap the array in a JSON object: {"segments": [ ...segment objects... ]}.';
|
|
1998
2082
|
try {
|
|
1999
2083
|
const response = await fetch("https://api.openai.com/v1/chat/completions", {
|
|
2000
2084
|
method: "POST",
|
|
@@ -2003,13 +2087,13 @@ async function analyzeContent2(apiKey, content, targetDuration, options) {
|
|
|
2003
2087
|
Authorization: `Bearer ${apiKey}`
|
|
2004
2088
|
},
|
|
2005
2089
|
body: JSON.stringify({
|
|
2006
|
-
model: "
|
|
2090
|
+
model: defaultModel("openai", "llm").id,
|
|
2007
2091
|
messages: [
|
|
2008
2092
|
{ role: "system", content: systemPrompt },
|
|
2009
2093
|
{ role: "user", content: buildStoryboardUserMessage(content) }
|
|
2010
2094
|
],
|
|
2011
|
-
|
|
2012
|
-
|
|
2095
|
+
// Reasoning tokens count against this cap.
|
|
2096
|
+
max_completion_tokens: 16384,
|
|
2013
2097
|
response_format: { type: "json_object" }
|
|
2014
2098
|
})
|
|
2015
2099
|
});
|
|
@@ -2048,6 +2132,7 @@ var init_openai_storyboard = __esm({
|
|
|
2048
2132
|
"../ai-providers/dist/openai/openai-storyboard.js"() {
|
|
2049
2133
|
"use strict";
|
|
2050
2134
|
init_storyboard_prompt();
|
|
2135
|
+
init_catalog();
|
|
2051
2136
|
}
|
|
2052
2137
|
});
|
|
2053
2138
|
|
|
@@ -2057,6 +2142,7 @@ var init_OpenAIProvider = __esm({
|
|
|
2057
2142
|
"../ai-providers/dist/openai/OpenAIProvider.js"() {
|
|
2058
2143
|
"use strict";
|
|
2059
2144
|
init_openai_storyboard();
|
|
2145
|
+
init_catalog();
|
|
2060
2146
|
OpenAIProvider = class {
|
|
2061
2147
|
constructor() {
|
|
2062
2148
|
this.id = "openai-gpt";
|
|
@@ -2066,7 +2152,7 @@ var init_OpenAIProvider = __esm({
|
|
|
2066
2152
|
this.iconUrl = "/icons/openai.svg";
|
|
2067
2153
|
this.isAvailable = true;
|
|
2068
2154
|
this.baseUrl = "https://api.openai.com/v1";
|
|
2069
|
-
this.model = "
|
|
2155
|
+
this.model = defaultModel("openai", "llm").id;
|
|
2070
2156
|
}
|
|
2071
2157
|
async initialize(config2) {
|
|
2072
2158
|
this.apiKey = config2.apiKey;
|
|
@@ -2162,7 +2248,6 @@ Or if clarification needed:
|
|
|
2162
2248
|
{ role: "system", content: systemPrompt },
|
|
2163
2249
|
{ role: "user", content: instruction }
|
|
2164
2250
|
],
|
|
2165
|
-
temperature: 0.2,
|
|
2166
2251
|
response_format: { type: "json_object" }
|
|
2167
2252
|
})
|
|
2168
2253
|
});
|
|
@@ -2373,8 +2458,9 @@ Each segment should be 3-10 seconds long.`;
|
|
|
2373
2458
|
Authorization: `Bearer ${this.apiKey}`
|
|
2374
2459
|
},
|
|
2375
2460
|
body: JSON.stringify({
|
|
2376
|
-
model: "
|
|
2377
|
-
|
|
2461
|
+
model: defaultModel("openai", "llm").id,
|
|
2462
|
+
// Reasoning tokens count against this cap.
|
|
2463
|
+
max_completion_tokens: 16384,
|
|
2378
2464
|
response_format: { type: "json_object" },
|
|
2379
2465
|
messages: [
|
|
2380
2466
|
{ role: "system", content: systemPrompt },
|
|
@@ -2407,7 +2493,7 @@ ${videoAnalysis}` }
|
|
|
2407
2493
|
}
|
|
2408
2494
|
}
|
|
2409
2495
|
/**
|
|
2410
|
-
* Generate a storyboard from script content using GPT-5
|
|
2496
|
+
* Generate a storyboard from script content using GPT-5.4 mini.
|
|
2411
2497
|
* Alternative to ClaudeProvider.analyzeContent for when Claude is unavailable.
|
|
2412
2498
|
*/
|
|
2413
2499
|
async analyzeContent(content, targetDuration, options) {
|
|
@@ -2455,10 +2541,12 @@ async function callClaude(params, opts) {
|
|
|
2455
2541
|
},
|
|
2456
2542
|
body: JSON.stringify({
|
|
2457
2543
|
model: params.model,
|
|
2458
|
-
|
|
2459
|
-
|
|
2544
|
+
// Claude 5.x thinks by default and thinking tokens count against
|
|
2545
|
+
// max_tokens, so a small cap can end before any text is written.
|
|
2546
|
+
max_tokens: Math.max(opts.maxTokens, CLAUDE_MIN_MAX_TOKENS),
|
|
2460
2547
|
messages: opts.messages,
|
|
2461
|
-
system: opts.system
|
|
2548
|
+
system: opts.system,
|
|
2549
|
+
...opts.jsonSchema ? { output_config: { format: { type: "json_schema", schema: opts.jsonSchema } } } : {}
|
|
2462
2550
|
})
|
|
2463
2551
|
});
|
|
2464
2552
|
if (!response.ok) {
|
|
@@ -2480,9 +2568,11 @@ function extractJsonArray(text) {
|
|
|
2480
2568
|
const match = text.match(/\[[\s\S]*\]/);
|
|
2481
2569
|
return match ? match[0] : null;
|
|
2482
2570
|
}
|
|
2571
|
+
var CLAUDE_MIN_MAX_TOKENS;
|
|
2483
2572
|
var init_claude_api = __esm({
|
|
2484
2573
|
"../ai-providers/dist/claude/claude-api.js"() {
|
|
2485
2574
|
"use strict";
|
|
2575
|
+
CLAUDE_MIN_MAX_TOKENS = 16e3;
|
|
2486
2576
|
}
|
|
2487
2577
|
});
|
|
2488
2578
|
|
|
@@ -2518,7 +2608,8 @@ MANDATORY ADAPTATION RULES:
|
|
|
2518
2608
|
const text = await callClaude(api, {
|
|
2519
2609
|
system: systemPrompt,
|
|
2520
2610
|
messages: [{ role: "user", content: userContent }],
|
|
2521
|
-
maxTokens: 16e3
|
|
2611
|
+
maxTokens: 16e3,
|
|
2612
|
+
jsonSchema: MOTION_COMPONENT_SCHEMA
|
|
2522
2613
|
});
|
|
2523
2614
|
const jsonStr = extractJsonObject(text);
|
|
2524
2615
|
if (!jsonStr) {
|
|
@@ -2593,7 +2684,8 @@ Modification instructions: ${instructions}
|
|
|
2593
2684
|
|
|
2594
2685
|
Return the complete modified component as JSON.`
|
|
2595
2686
|
}],
|
|
2596
|
-
maxTokens: 16e3
|
|
2687
|
+
maxTokens: 16e3,
|
|
2688
|
+
jsonSchema: MOTION_COMPONENT_SCHEMA
|
|
2597
2689
|
});
|
|
2598
2690
|
const jsonStr = extractJsonObject(text);
|
|
2599
2691
|
if (!jsonStr)
|
|
@@ -2622,15 +2714,13 @@ async function analyzeContent3(api, content, targetDuration, options) {
|
|
|
2622
2714
|
const creativity = options?.creativity || "low";
|
|
2623
2715
|
const systemPrompt = buildStoryboardSystemPrompt(targetDuration, creativity);
|
|
2624
2716
|
try {
|
|
2625
|
-
const temperature = creativity === "high" ? 1 : 0.7;
|
|
2626
2717
|
const text = await callClaude(api, {
|
|
2627
2718
|
system: systemPrompt,
|
|
2628
2719
|
messages: [{
|
|
2629
2720
|
role: "user",
|
|
2630
2721
|
content: buildStoryboardUserMessage(content)
|
|
2631
2722
|
}],
|
|
2632
|
-
maxTokens: 4096
|
|
2633
|
-
temperature
|
|
2723
|
+
maxTokens: 4096
|
|
2634
2724
|
});
|
|
2635
2725
|
const jsonStr = extractJsonArray(text);
|
|
2636
2726
|
if (!jsonStr) {
|
|
@@ -2987,11 +3077,22 @@ UNIVERSAL RULES:
|
|
|
2987
3077
|
- Both entrance AND exit animations
|
|
2988
3078
|
- whiteSpace: "nowrap" on all text`;
|
|
2989
3079
|
}
|
|
3080
|
+
var MOTION_COMPONENT_SCHEMA;
|
|
2990
3081
|
var init_claude_motion = __esm({
|
|
2991
3082
|
"../ai-providers/dist/claude/claude-motion.js"() {
|
|
2992
3083
|
"use strict";
|
|
2993
3084
|
init_claude_api();
|
|
2994
3085
|
init_storyboard_prompt();
|
|
3086
|
+
MOTION_COMPONENT_SCHEMA = {
|
|
3087
|
+
type: "object",
|
|
3088
|
+
properties: {
|
|
3089
|
+
name: { type: "string" },
|
|
3090
|
+
code: { type: "string" },
|
|
3091
|
+
description: { type: "string" }
|
|
3092
|
+
},
|
|
3093
|
+
required: ["name", "code", "description"],
|
|
3094
|
+
additionalProperties: false
|
|
3095
|
+
};
|
|
2995
3096
|
}
|
|
2996
3097
|
});
|
|
2997
3098
|
|
|
@@ -3753,10 +3854,12 @@ var ClaudeProvider, claudeProvider;
|
|
|
3753
3854
|
var init_ClaudeProvider = __esm({
|
|
3754
3855
|
"../ai-providers/dist/claude/ClaudeProvider.js"() {
|
|
3755
3856
|
"use strict";
|
|
3857
|
+
init_claude_api();
|
|
3756
3858
|
init_claude_motion();
|
|
3757
3859
|
init_claude_analysis();
|
|
3758
3860
|
init_claude_viral();
|
|
3759
3861
|
init_claude_visual_fx();
|
|
3862
|
+
init_catalog();
|
|
3760
3863
|
ClaudeProvider = class {
|
|
3761
3864
|
constructor() {
|
|
3762
3865
|
this.id = "claude";
|
|
@@ -3766,7 +3869,7 @@ var init_ClaudeProvider = __esm({
|
|
|
3766
3869
|
this.iconUrl = "/icons/claude.svg";
|
|
3767
3870
|
this.isAvailable = true;
|
|
3768
3871
|
this.baseUrl = "https://api.anthropic.com/v1";
|
|
3769
|
-
this.model = "claude
|
|
3872
|
+
this.model = defaultModel("claude", "llm").id;
|
|
3770
3873
|
}
|
|
3771
3874
|
async initialize(config2) {
|
|
3772
3875
|
this.apiKey = config2.apiKey;
|
|
@@ -3870,7 +3973,7 @@ Or if clarification needed:
|
|
|
3870
3973
|
},
|
|
3871
3974
|
body: JSON.stringify({
|
|
3872
3975
|
model: this.model,
|
|
3873
|
-
max_tokens:
|
|
3976
|
+
max_tokens: CLAUDE_MIN_MAX_TOKENS,
|
|
3874
3977
|
messages: [{ role: "user", content: instruction }],
|
|
3875
3978
|
system: systemPrompt
|
|
3876
3979
|
})
|
|
@@ -3940,7 +4043,7 @@ Respond with JSON array:
|
|
|
3940
4043
|
},
|
|
3941
4044
|
body: JSON.stringify({
|
|
3942
4045
|
model: this.model,
|
|
3943
|
-
max_tokens:
|
|
4046
|
+
max_tokens: CLAUDE_MIN_MAX_TOKENS,
|
|
3944
4047
|
messages: [{
|
|
3945
4048
|
role: "user",
|
|
3946
4049
|
content: `Clips: ${JSON.stringify(clipsInfo)}
|
|
@@ -4068,11 +4171,7 @@ Instruction: ${instruction}`
|
|
|
4068
4171
|
return generateNarrationScript(this.api, videoAnalysis, duration, style, language);
|
|
4069
4172
|
}
|
|
4070
4173
|
};
|
|
4071
|
-
ClaudeProvider.MOTION_MODELS = {
|
|
4072
|
-
sonnet: "claude-sonnet-4-6",
|
|
4073
|
-
opus: "claude-opus-4-7",
|
|
4074
|
-
"opus-4-6": "claude-opus-4-6"
|
|
4075
|
-
};
|
|
4174
|
+
ClaudeProvider.MOTION_MODELS = Object.fromEntries(listModels({ provider: "claude", kind: "llm" }).flatMap((m) => (m.aliases ?? []).map((a) => [a, m.id])));
|
|
4076
4175
|
claudeProvider = new ClaudeProvider();
|
|
4077
4176
|
}
|
|
4078
4177
|
});
|
|
@@ -4408,10 +4507,11 @@ function resolveVoiceId(input) {
|
|
|
4408
4507
|
const availableVoices = Object.keys(KNOWN_VOICES).join(", ");
|
|
4409
4508
|
throw new Error(`Unknown voice "${input}". Available voices: ${availableVoices}. You can also use a custom voice ID from your ElevenLabs account.`);
|
|
4410
4509
|
}
|
|
4411
|
-
var KNOWN_VOICES, TTS_429_MAX_RETRIES, TTS_429_RETRY_DELAY_MS, ElevenLabsProvider, elevenLabsProvider;
|
|
4510
|
+
var KNOWN_VOICES, TTS_429_MAX_RETRIES, TTS_429_RETRY_DELAY_MS, ELEVENLABS_MUSIC_MODEL, ElevenLabsProvider, elevenLabsProvider;
|
|
4412
4511
|
var init_ElevenLabsProvider = __esm({
|
|
4413
4512
|
"../ai-providers/dist/elevenlabs/ElevenLabsProvider.js"() {
|
|
4414
4513
|
"use strict";
|
|
4514
|
+
init_catalog();
|
|
4415
4515
|
KNOWN_VOICES = {
|
|
4416
4516
|
// Default/popular voices
|
|
4417
4517
|
rachel: "21m00Tcm4TlvDq8ikWAM",
|
|
@@ -4445,6 +4545,7 @@ var init_ElevenLabsProvider = __esm({
|
|
|
4445
4545
|
};
|
|
4446
4546
|
TTS_429_MAX_RETRIES = 1;
|
|
4447
4547
|
TTS_429_RETRY_DELAY_MS = 2e3;
|
|
4548
|
+
ELEVENLABS_MUSIC_MODEL = defaultModel("elevenlabs", "music").id;
|
|
4448
4549
|
ElevenLabsProvider = class {
|
|
4449
4550
|
constructor() {
|
|
4450
4551
|
this.id = "elevenlabs";
|
|
@@ -4525,9 +4626,10 @@ var init_ElevenLabsProvider = __esm({
|
|
|
4525
4626
|
stability: options.stability ?? 0.5,
|
|
4526
4627
|
similarity_boost: options.similarityBoost ?? 0.75,
|
|
4527
4628
|
style: options.style ?? 0,
|
|
4528
|
-
use_speaker_boost: true
|
|
4529
|
-
|
|
4530
|
-
|
|
4629
|
+
use_speaker_boost: true,
|
|
4630
|
+
// The API reads speed only inside voice_settings.
|
|
4631
|
+
...options.speed !== void 0 && { speed: options.speed }
|
|
4632
|
+
}
|
|
4531
4633
|
})
|
|
4532
4634
|
});
|
|
4533
4635
|
if (response.status === 429 && attempt < TTS_429_MAX_RETRIES) {
|
|
@@ -4597,7 +4699,7 @@ var init_ElevenLabsProvider = __esm({
|
|
|
4597
4699
|
prompt_influence: options.promptInfluence ?? 0.3
|
|
4598
4700
|
};
|
|
4599
4701
|
if (options.duration !== void 0) {
|
|
4600
|
-
const duration = Math.max(0.5, Math.min(
|
|
4702
|
+
const duration = Math.max(0.5, Math.min(30, options.duration));
|
|
4601
4703
|
body.duration_seconds = duration;
|
|
4602
4704
|
}
|
|
4603
4705
|
const response = await fetch(`${this.baseUrl}/sound-generation`, {
|
|
@@ -4642,7 +4744,7 @@ var init_ElevenLabsProvider = __esm({
|
|
|
4642
4744
|
try {
|
|
4643
4745
|
const body = {
|
|
4644
4746
|
prompt: prompt3,
|
|
4645
|
-
model_id:
|
|
4747
|
+
model_id: ELEVENLABS_MUSIC_MODEL
|
|
4646
4748
|
};
|
|
4647
4749
|
if (options.duration !== void 0) {
|
|
4648
4750
|
const duration = Math.max(3, Math.min(600, options.duration));
|
|
@@ -4853,6 +4955,55 @@ var init_elevenlabs = __esm({
|
|
|
4853
4955
|
});
|
|
4854
4956
|
|
|
4855
4957
|
// ../ai-providers/dist/kokoro/KokoroProvider.js
|
|
4958
|
+
function splitForKokoro(text, maxChars = KOKORO_MAX_CHUNK_CHARS) {
|
|
4959
|
+
const pieces = (part, pattern) => part.length <= maxChars ? [part] : part.split(pattern).filter((p) => p.trim().length > 0);
|
|
4960
|
+
const units2 = text.trim().split(/(?<=[.!?…])\s+/).flatMap((sentence) => pieces(sentence, /(?<=[,;:])\s+/)).flatMap((clause) => {
|
|
4961
|
+
if (clause.length <= maxChars)
|
|
4962
|
+
return [clause];
|
|
4963
|
+
const words = [];
|
|
4964
|
+
let line = "";
|
|
4965
|
+
for (const word of clause.split(/\s+/)) {
|
|
4966
|
+
if (line && line.length + word.length + 1 > maxChars) {
|
|
4967
|
+
words.push(line);
|
|
4968
|
+
line = word;
|
|
4969
|
+
} else {
|
|
4970
|
+
line = line ? `${line} ${word}` : word;
|
|
4971
|
+
}
|
|
4972
|
+
}
|
|
4973
|
+
if (line)
|
|
4974
|
+
words.push(line);
|
|
4975
|
+
return words;
|
|
4976
|
+
});
|
|
4977
|
+
const chunks = [];
|
|
4978
|
+
for (const unit of units2) {
|
|
4979
|
+
const last = chunks.at(-1);
|
|
4980
|
+
if (last !== void 0 && last.length + unit.length + 1 <= maxChars) {
|
|
4981
|
+
chunks[chunks.length - 1] = `${last} ${unit}`;
|
|
4982
|
+
} else {
|
|
4983
|
+
chunks.push(unit);
|
|
4984
|
+
}
|
|
4985
|
+
}
|
|
4986
|
+
return chunks;
|
|
4987
|
+
}
|
|
4988
|
+
function encodeFloatWav(samples, sampleRate) {
|
|
4989
|
+
const dataBytes = samples.length * 4;
|
|
4990
|
+
const buffer = Buffer.alloc(44 + dataBytes);
|
|
4991
|
+
buffer.write("RIFF", 0, "ascii");
|
|
4992
|
+
buffer.writeUInt32LE(36 + dataBytes, 4);
|
|
4993
|
+
buffer.write("WAVE", 8, "ascii");
|
|
4994
|
+
buffer.write("fmt ", 12, "ascii");
|
|
4995
|
+
buffer.writeUInt32LE(16, 16);
|
|
4996
|
+
buffer.writeUInt16LE(3, 20);
|
|
4997
|
+
buffer.writeUInt16LE(1, 22);
|
|
4998
|
+
buffer.writeUInt32LE(sampleRate, 24);
|
|
4999
|
+
buffer.writeUInt32LE(sampleRate * 4, 28);
|
|
5000
|
+
buffer.writeUInt16LE(4, 32);
|
|
5001
|
+
buffer.writeUInt16LE(32, 34);
|
|
5002
|
+
buffer.write("data", 36, "ascii");
|
|
5003
|
+
buffer.writeUInt32LE(dataBytes, 40);
|
|
5004
|
+
Buffer.from(samples.buffer, samples.byteOffset, dataBytes).copy(buffer, 44);
|
|
5005
|
+
return buffer;
|
|
5006
|
+
}
|
|
4856
5007
|
async function loadKokoroRuntime() {
|
|
4857
5008
|
if (factoryOverride)
|
|
4858
5009
|
return { factory: factoryOverride, device: "cpu" };
|
|
@@ -4890,7 +5041,7 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
|
|
|
4890
5041
|
if (!base)
|
|
4891
5042
|
return null;
|
|
4892
5043
|
try {
|
|
4893
|
-
const { readFile: readFile44, writeFile:
|
|
5044
|
+
const { readFile: readFile44, writeFile: writeFile47, mkdir: mkdir27 } = await import("node:fs/promises");
|
|
4894
5045
|
const { join: join29, resolve: resolve65 } = await import("node:path");
|
|
4895
5046
|
const { pathToFileURL } = await import("node:url");
|
|
4896
5047
|
const { homedir: homedir5 } = await import("node:os");
|
|
@@ -4911,8 +5062,8 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
|
|
|
4911
5062
|
async put(key, response) {
|
|
4912
5063
|
try {
|
|
4913
5064
|
const buf = Buffer.from(await response.arrayBuffer());
|
|
4914
|
-
await
|
|
4915
|
-
await
|
|
5065
|
+
await mkdir27(cacheRoot, { recursive: true });
|
|
5066
|
+
await writeFile47(join29(cacheRoot, encodeURIComponent(String(key))), buf);
|
|
4916
5067
|
} catch {
|
|
4917
5068
|
}
|
|
4918
5069
|
}
|
|
@@ -4961,12 +5112,13 @@ function normaliseEvent(raw) {
|
|
|
4961
5112
|
total: typeof r.total === "number" ? r.total : void 0
|
|
4962
5113
|
};
|
|
4963
5114
|
}
|
|
4964
|
-
var KOKORO_DEFAULT_VOICE, KOKORO_MODEL_ID, modelPromise, factoryOverride, KokoroProvider, kokoroProvider;
|
|
5115
|
+
var KOKORO_DEFAULT_VOICE, KOKORO_MODEL_ID, KOKORO_MAX_CHUNK_CHARS, modelPromise, factoryOverride, KokoroProvider, kokoroProvider;
|
|
4965
5116
|
var init_KokoroProvider = __esm({
|
|
4966
5117
|
"../ai-providers/dist/kokoro/KokoroProvider.js"() {
|
|
4967
5118
|
"use strict";
|
|
4968
5119
|
KOKORO_DEFAULT_VOICE = "af_heart";
|
|
4969
5120
|
KOKORO_MODEL_ID = "onnx-community/Kokoro-82M-v1.0-ONNX";
|
|
5121
|
+
KOKORO_MAX_CHUNK_CHARS = 300;
|
|
4970
5122
|
modelPromise = null;
|
|
4971
5123
|
factoryOverride = null;
|
|
4972
5124
|
KokoroProvider = class {
|
|
@@ -4993,11 +5145,32 @@ var init_KokoroProvider = __esm({
|
|
|
4993
5145
|
}
|
|
4994
5146
|
try {
|
|
4995
5147
|
const model = await loadModel(options.onProgress);
|
|
4996
|
-
const
|
|
5148
|
+
const voiceOptions = {
|
|
4997
5149
|
voice: options.voice ?? KOKORO_DEFAULT_VOICE,
|
|
4998
5150
|
speed: options.speed ?? 1
|
|
4999
|
-
}
|
|
5000
|
-
const
|
|
5151
|
+
};
|
|
5152
|
+
const chunks = splitForKokoro(text);
|
|
5153
|
+
let buffer;
|
|
5154
|
+
if (chunks.length === 1) {
|
|
5155
|
+
buffer = Buffer.from((await model.generate(chunks[0], voiceOptions)).toWav());
|
|
5156
|
+
} else {
|
|
5157
|
+
const parts = [];
|
|
5158
|
+
let sampleRate = 24e3;
|
|
5159
|
+
for (const chunk of chunks) {
|
|
5160
|
+
const audio = await model.generate(chunk, voiceOptions);
|
|
5161
|
+
if (!audio.audio)
|
|
5162
|
+
throw new Error("Kokoro returned no raw samples to join");
|
|
5163
|
+
parts.push(audio.audio);
|
|
5164
|
+
sampleRate = audio.sampling_rate ?? sampleRate;
|
|
5165
|
+
}
|
|
5166
|
+
const samples = new Float32Array(parts.reduce((n, part) => n + part.length, 0));
|
|
5167
|
+
let offset = 0;
|
|
5168
|
+
for (const part of parts) {
|
|
5169
|
+
samples.set(part, offset);
|
|
5170
|
+
offset += part.length;
|
|
5171
|
+
}
|
|
5172
|
+
buffer = encodeFloatWav(samples, sampleRate);
|
|
5173
|
+
}
|
|
5001
5174
|
return {
|
|
5002
5175
|
success: true,
|
|
5003
5176
|
audioBuffer: buffer,
|
|
@@ -5032,11 +5205,13 @@ var init_kokoro = __esm({
|
|
|
5032
5205
|
});
|
|
5033
5206
|
|
|
5034
5207
|
// ../ai-providers/dist/openai-image/OpenAIImageProvider.js
|
|
5035
|
-
var DEFAULT_MODEL, OpenAIImageProvider, openaiImageProvider;
|
|
5208
|
+
var OPENAI_IMAGE_DEFAULT_MODEL, DEFAULT_MODEL, OpenAIImageProvider, openaiImageProvider;
|
|
5036
5209
|
var init_OpenAIImageProvider = __esm({
|
|
5037
5210
|
"../ai-providers/dist/openai-image/OpenAIImageProvider.js"() {
|
|
5038
5211
|
"use strict";
|
|
5039
|
-
|
|
5212
|
+
init_catalog();
|
|
5213
|
+
OPENAI_IMAGE_DEFAULT_MODEL = defaultModel("openai", "image").id;
|
|
5214
|
+
DEFAULT_MODEL = OPENAI_IMAGE_DEFAULT_MODEL;
|
|
5040
5215
|
OpenAIImageProvider = class {
|
|
5041
5216
|
constructor() {
|
|
5042
5217
|
this.id = "openai-image";
|
|
@@ -5058,7 +5233,7 @@ var init_OpenAIImageProvider = __esm({
|
|
|
5058
5233
|
}
|
|
5059
5234
|
/**
|
|
5060
5235
|
* Generate images from text prompt
|
|
5061
|
-
* Uses GPT Image
|
|
5236
|
+
* Uses GPT Image 2.5 Sunburst by default
|
|
5062
5237
|
*/
|
|
5063
5238
|
async generateImage(prompt3, options = {}) {
|
|
5064
5239
|
if (!this.apiKey) {
|
|
@@ -5068,28 +5243,20 @@ var init_OpenAIImageProvider = __esm({
|
|
|
5068
5243
|
};
|
|
5069
5244
|
}
|
|
5070
5245
|
const model = options.model || DEFAULT_MODEL;
|
|
5071
|
-
const isGPTImage = model === "gpt-image-1.5" || model === "gpt-image-2";
|
|
5072
5246
|
try {
|
|
5073
5247
|
const body = {
|
|
5074
5248
|
model,
|
|
5075
5249
|
prompt: prompt3,
|
|
5076
5250
|
n: options.n || 1
|
|
5077
5251
|
};
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
body.size = options.size;
|
|
5087
|
-
}
|
|
5088
|
-
} else {
|
|
5089
|
-
body.response_format = "url";
|
|
5090
|
-
body.size = options.size || "1024x1024";
|
|
5091
|
-
body.quality = options.quality === "high" ? "hd" : options.quality || "standard";
|
|
5092
|
-
body.style = options.style || "vivid";
|
|
5252
|
+
const qualityMap = {
|
|
5253
|
+
standard: "medium",
|
|
5254
|
+
hd: "high"
|
|
5255
|
+
};
|
|
5256
|
+
const quality = options.quality || "medium";
|
|
5257
|
+
body.quality = qualityMap[quality] || quality;
|
|
5258
|
+
if (options.size && options.size !== "auto") {
|
|
5259
|
+
body.size = options.size;
|
|
5093
5260
|
}
|
|
5094
5261
|
const response = await fetch(`${this.baseUrl}/images/generations`, {
|
|
5095
5262
|
method: "POST",
|
|
@@ -5242,49 +5409,6 @@ var init_OpenAIImageProvider = __esm({
|
|
|
5242
5409
|
};
|
|
5243
5410
|
}
|
|
5244
5411
|
}
|
|
5245
|
-
/**
|
|
5246
|
-
* Create image variations (uses DALL-E 2)
|
|
5247
|
-
*/
|
|
5248
|
-
async createVariation(imageBuffer, options = {}) {
|
|
5249
|
-
if (!this.apiKey) {
|
|
5250
|
-
return {
|
|
5251
|
-
success: false,
|
|
5252
|
-
error: "OpenAI API key not configured"
|
|
5253
|
-
};
|
|
5254
|
-
}
|
|
5255
|
-
try {
|
|
5256
|
-
const formData = new FormData();
|
|
5257
|
-
const uint8Array = new Uint8Array(imageBuffer);
|
|
5258
|
-
formData.append("image", new Blob([uint8Array], { type: "image/png" }), "image.png");
|
|
5259
|
-
formData.append("model", "dall-e-2");
|
|
5260
|
-
formData.append("n", String(options.n || 1));
|
|
5261
|
-
formData.append("size", options.size || "1024x1024");
|
|
5262
|
-
const response = await fetch(`${this.baseUrl}/images/variations`, {
|
|
5263
|
-
method: "POST",
|
|
5264
|
-
headers: {
|
|
5265
|
-
Authorization: `Bearer ${this.apiKey}`
|
|
5266
|
-
},
|
|
5267
|
-
body: formData
|
|
5268
|
-
});
|
|
5269
|
-
if (!response.ok) {
|
|
5270
|
-
const error = await response.text();
|
|
5271
|
-
return {
|
|
5272
|
-
success: false,
|
|
5273
|
-
error: `API error: ${response.status} - ${error}`
|
|
5274
|
-
};
|
|
5275
|
-
}
|
|
5276
|
-
const data = await response.json();
|
|
5277
|
-
return {
|
|
5278
|
-
success: true,
|
|
5279
|
-
images: data.data.map((img) => ({ url: img.url }))
|
|
5280
|
-
};
|
|
5281
|
-
} catch (error) {
|
|
5282
|
-
return {
|
|
5283
|
-
success: false,
|
|
5284
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
5285
|
-
};
|
|
5286
|
-
}
|
|
5287
|
-
}
|
|
5288
5412
|
};
|
|
5289
5413
|
openaiImageProvider = new OpenAIImageProvider();
|
|
5290
5414
|
}
|
|
@@ -5410,7 +5534,8 @@ var DEFAULT_MODEL3, RunwayProvider, runwayProvider;
|
|
|
5410
5534
|
var init_RunwayProvider = __esm({
|
|
5411
5535
|
"../ai-providers/dist/runway/RunwayProvider.js"() {
|
|
5412
5536
|
"use strict";
|
|
5413
|
-
|
|
5537
|
+
init_catalog();
|
|
5538
|
+
DEFAULT_MODEL3 = defaultModel("runway", "video").id;
|
|
5414
5539
|
RunwayProvider = class _RunwayProvider {
|
|
5415
5540
|
constructor() {
|
|
5416
5541
|
this.id = "runway";
|
|
@@ -5463,6 +5588,13 @@ var init_RunwayProvider = __esm({
|
|
|
5463
5588
|
}
|
|
5464
5589
|
const hasImage = !!options?.referenceImage;
|
|
5465
5590
|
const endpoint = hasImage ? "image_to_video" : "text_to_video";
|
|
5591
|
+
if (!hasImage && apiRatio === "960:960") {
|
|
5592
|
+
return {
|
|
5593
|
+
id: "",
|
|
5594
|
+
status: "failed",
|
|
5595
|
+
error: "Runway text-to-video supports 16:9 and 9:16 only. Use 16:9 or 9:16, or pass an image (-i) for square output."
|
|
5596
|
+
};
|
|
5597
|
+
}
|
|
5466
5598
|
const body = {
|
|
5467
5599
|
model,
|
|
5468
5600
|
promptText: prompt3,
|
|
@@ -5563,7 +5695,9 @@ var init_RunwayProvider = __esm({
|
|
|
5563
5695
|
SUCCEEDED: "completed",
|
|
5564
5696
|
FAILED: "failed",
|
|
5565
5697
|
CANCELLED: "cancelled",
|
|
5566
|
-
THROTTLED
|
|
5698
|
+
// THROTTLED means queued behind the account's concurrency limit; the
|
|
5699
|
+
// task starts on its own, so keep polling.
|
|
5700
|
+
THROTTLED: "pending"
|
|
5567
5701
|
};
|
|
5568
5702
|
const result = {
|
|
5569
5703
|
id: data.id,
|
|
@@ -5573,8 +5707,9 @@ var init_RunwayProvider = __esm({
|
|
|
5573
5707
|
if (data.status === "SUCCEEDED" && data.output && data.output.length > 0) {
|
|
5574
5708
|
result.videoUrl = data.output[0];
|
|
5575
5709
|
}
|
|
5576
|
-
if (data.status === "FAILED"
|
|
5577
|
-
|
|
5710
|
+
if (data.status === "FAILED") {
|
|
5711
|
+
const reason = data.failure || "Generation failed";
|
|
5712
|
+
result.error = data.failureCode ? `${reason} (${data.failureCode})` : reason;
|
|
5578
5713
|
}
|
|
5579
5714
|
return result;
|
|
5580
5715
|
} catch (error) {
|
|
@@ -5586,27 +5721,14 @@ var init_RunwayProvider = __esm({
|
|
|
5586
5721
|
}
|
|
5587
5722
|
}
|
|
5588
5723
|
/**
|
|
5589
|
-
* Cancel
|
|
5724
|
+
* Cancel a pending or running task. Runway documents cancellation as
|
|
5725
|
+
* `DELETE /v1/tasks/{id}` (there is no `/cancel` route).
|
|
5590
5726
|
*/
|
|
5591
5727
|
async cancelGeneration(id) {
|
|
5592
|
-
|
|
5593
|
-
return false;
|
|
5594
|
-
}
|
|
5595
|
-
try {
|
|
5596
|
-
const response = await fetch(`${this.baseUrl}/tasks/${id}/cancel`, {
|
|
5597
|
-
method: "POST",
|
|
5598
|
-
headers: {
|
|
5599
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
5600
|
-
"X-Runway-Version": _RunwayProvider.API_VERSION
|
|
5601
|
-
}
|
|
5602
|
-
});
|
|
5603
|
-
return response.ok;
|
|
5604
|
-
} catch {
|
|
5605
|
-
return false;
|
|
5606
|
-
}
|
|
5728
|
+
return this.deleteTask(id);
|
|
5607
5729
|
}
|
|
5608
5730
|
/**
|
|
5609
|
-
*
|
|
5731
|
+
* Cancel a running task, or delete a finished one (`DELETE /v1/tasks/{id}`).
|
|
5610
5732
|
*/
|
|
5611
5733
|
async deleteTask(id) {
|
|
5612
5734
|
if (!this.apiKey) {
|
|
@@ -5715,12 +5837,25 @@ var init_runway = __esm({
|
|
|
5715
5837
|
|
|
5716
5838
|
// ../ai-providers/dist/kling/KlingProvider.js
|
|
5717
5839
|
import { createHmac } from "node:crypto";
|
|
5840
|
+
function resolveKlingModel(alias) {
|
|
5841
|
+
const model = findModel("kling", "video", alias);
|
|
5842
|
+
if (model)
|
|
5843
|
+
return model.id;
|
|
5844
|
+
throw new Error(`Unknown Kling model "${alias}". Valid: ${modelAliases("kling", "video").join(", ")}.`);
|
|
5845
|
+
}
|
|
5846
|
+
function klingDuration(model, seconds) {
|
|
5847
|
+
const requested = typeof seconds === "number" && Number.isFinite(seconds) ? Math.round(seconds) : 5;
|
|
5848
|
+
if (model === "kling-v3")
|
|
5849
|
+
return String(Math.max(3, Math.min(15, requested)));
|
|
5850
|
+
return requested >= 10 ? "10" : "5";
|
|
5851
|
+
}
|
|
5718
5852
|
var DEFAULT_MODEL4, STD_MODE_MODELS, KlingProvider, klingProvider;
|
|
5719
5853
|
var init_KlingProvider = __esm({
|
|
5720
5854
|
"../ai-providers/dist/kling/KlingProvider.js"() {
|
|
5721
5855
|
"use strict";
|
|
5722
|
-
|
|
5723
|
-
|
|
5856
|
+
init_catalog();
|
|
5857
|
+
DEFAULT_MODEL4 = defaultModel("kling", "video").id;
|
|
5858
|
+
STD_MODE_MODELS = ["kling-v2-5-turbo", "kling-v2-6", "kling-v3"];
|
|
5724
5859
|
KlingProvider = class {
|
|
5725
5860
|
constructor() {
|
|
5726
5861
|
this.id = "kling";
|
|
@@ -5735,11 +5870,11 @@ var init_KlingProvider = __esm({
|
|
|
5735
5870
|
async initialize(config2) {
|
|
5736
5871
|
if (config2.apiKey) {
|
|
5737
5872
|
const parts = config2.apiKey.split(":");
|
|
5738
|
-
if (parts.length === 2) {
|
|
5873
|
+
if (parts.length === 2 && parts[0] && parts[1]) {
|
|
5739
5874
|
this.accessKey = parts[0];
|
|
5740
5875
|
this.secretKey = parts[1];
|
|
5741
5876
|
} else {
|
|
5742
|
-
this.
|
|
5877
|
+
this.apiKey = config2.apiKey;
|
|
5743
5878
|
}
|
|
5744
5879
|
}
|
|
5745
5880
|
if (config2.baseUrl) {
|
|
@@ -5747,7 +5882,11 @@ var init_KlingProvider = __esm({
|
|
|
5747
5882
|
}
|
|
5748
5883
|
}
|
|
5749
5884
|
isConfigured() {
|
|
5750
|
-
return !!(this.accessKey && this.secretKey);
|
|
5885
|
+
return !!(this.apiKey || this.accessKey && this.secretKey);
|
|
5886
|
+
}
|
|
5887
|
+
/** Bearer value: the API key itself, or a JWT signed from the legacy pair. */
|
|
5888
|
+
bearerToken() {
|
|
5889
|
+
return this.apiKey ?? this.generateToken();
|
|
5751
5890
|
}
|
|
5752
5891
|
/**
|
|
5753
5892
|
* Generate JWT token for Kling API authentication
|
|
@@ -5777,11 +5916,11 @@ var init_KlingProvider = __esm({
|
|
|
5777
5916
|
return {
|
|
5778
5917
|
id: "",
|
|
5779
5918
|
status: "failed",
|
|
5780
|
-
error: "Kling API credentials not configured.
|
|
5919
|
+
error: "Kling API credentials not configured. Set KLING_API_KEY to your Kling API key (or the legacy ACCESS_KEY:SECRET_KEY pair)."
|
|
5781
5920
|
};
|
|
5782
5921
|
}
|
|
5783
5922
|
try {
|
|
5784
|
-
const token = this.
|
|
5923
|
+
const token = this.bearerToken();
|
|
5785
5924
|
const model = options?.model || DEFAULT_MODEL4;
|
|
5786
5925
|
let mode = options?.mode || "std";
|
|
5787
5926
|
if (!STD_MODE_MODELS.includes(model) && mode === "std") {
|
|
@@ -5799,7 +5938,7 @@ var init_KlingProvider = __esm({
|
|
|
5799
5938
|
model_name: model,
|
|
5800
5939
|
mode,
|
|
5801
5940
|
aspect_ratio: aspectRatioMap[options?.aspectRatio || "16:9"] || "16:9",
|
|
5802
|
-
duration: options?.duration
|
|
5941
|
+
duration: klingDuration(model, options?.duration)
|
|
5803
5942
|
};
|
|
5804
5943
|
if (options?.negativePrompt) {
|
|
5805
5944
|
body.negative_prompt = options.negativePrompt;
|
|
@@ -5911,7 +6050,7 @@ var init_KlingProvider = __esm({
|
|
|
5911
6050
|
};
|
|
5912
6051
|
}
|
|
5913
6052
|
try {
|
|
5914
|
-
const token = this.
|
|
6053
|
+
const token = this.bearerToken();
|
|
5915
6054
|
const response = await fetch(`${this.baseUrl}/videos/${type}/${id}`, {
|
|
5916
6055
|
headers: {
|
|
5917
6056
|
"Content-Type": "application/json",
|
|
@@ -5993,11 +6132,11 @@ var init_KlingProvider = __esm({
|
|
|
5993
6132
|
return {
|
|
5994
6133
|
id: "",
|
|
5995
6134
|
status: "failed",
|
|
5996
|
-
error: "Kling API credentials not configured.
|
|
6135
|
+
error: "Kling API credentials not configured. Set KLING_API_KEY to your Kling API key (or the legacy ACCESS_KEY:SECRET_KEY pair)."
|
|
5997
6136
|
};
|
|
5998
6137
|
}
|
|
5999
6138
|
try {
|
|
6000
|
-
const token = this.
|
|
6139
|
+
const token = this.bearerToken();
|
|
6001
6140
|
const body = {
|
|
6002
6141
|
video_id: videoId,
|
|
6003
6142
|
duration: options?.duration || "5"
|
|
@@ -6037,7 +6176,7 @@ var init_KlingProvider = __esm({
|
|
|
6037
6176
|
};
|
|
6038
6177
|
}
|
|
6039
6178
|
try {
|
|
6040
|
-
const token = this.
|
|
6179
|
+
const token = this.bearerToken();
|
|
6041
6180
|
const response = await fetch(`${this.baseUrl}/videos/video-extend/${id}`, {
|
|
6042
6181
|
headers: {
|
|
6043
6182
|
"Content-Type": "application/json",
|
|
@@ -6153,11 +6292,24 @@ var init_kling = __esm({
|
|
|
6153
6292
|
});
|
|
6154
6293
|
|
|
6155
6294
|
// ../ai-providers/dist/grok/GrokProvider.js
|
|
6156
|
-
|
|
6295
|
+
function resolveGrokVideoModel(alias) {
|
|
6296
|
+
const model = findModel("grok", "video", alias);
|
|
6297
|
+
if (model)
|
|
6298
|
+
return model.id;
|
|
6299
|
+
throw new Error(`Unknown Grok video model "${alias}". Valid: ${modelAliases("grok", "video").join(", ")}.`);
|
|
6300
|
+
}
|
|
6301
|
+
function resolveGrokImageModel(alias) {
|
|
6302
|
+
const model = (findModel("grok", "image", alias) ?? defaultModel("grok", "image")).id;
|
|
6303
|
+
return model === "grok-imagine-image-2.0" ? { model, quality: "medium" } : { model };
|
|
6304
|
+
}
|
|
6305
|
+
var DEFAULT_MODEL5, DEFAULT_VIDEO_RESOLUTION, GROK_VIDEO_RESOLUTIONS, GrokProvider, grokProvider;
|
|
6157
6306
|
var init_GrokProvider = __esm({
|
|
6158
6307
|
"../ai-providers/dist/grok/GrokProvider.js"() {
|
|
6159
6308
|
"use strict";
|
|
6160
|
-
|
|
6309
|
+
init_catalog();
|
|
6310
|
+
DEFAULT_MODEL5 = defaultModel("grok", "video").id;
|
|
6311
|
+
DEFAULT_VIDEO_RESOLUTION = "720p";
|
|
6312
|
+
GROK_VIDEO_RESOLUTIONS = ["480p", "720p", "1080p"];
|
|
6161
6313
|
GrokProvider = class {
|
|
6162
6314
|
constructor() {
|
|
6163
6315
|
this.id = "grok";
|
|
@@ -6191,6 +6343,7 @@ var init_GrokProvider = __esm({
|
|
|
6191
6343
|
try {
|
|
6192
6344
|
const body = {
|
|
6193
6345
|
model: options.model || "grok-imagine-image",
|
|
6346
|
+
...options.quality ? { quality: options.quality } : {},
|
|
6194
6347
|
prompt: prompt3,
|
|
6195
6348
|
n: options.n || 1,
|
|
6196
6349
|
response_format: options.responseFormat || "url"
|
|
@@ -6258,6 +6411,7 @@ var init_GrokProvider = __esm({
|
|
|
6258
6411
|
const dataUri = `data:image/png;base64,${base64}`;
|
|
6259
6412
|
const body = {
|
|
6260
6413
|
model: options.model || "grok-imagine-image",
|
|
6414
|
+
...options.quality ? { quality: options.quality } : {},
|
|
6261
6415
|
prompt: prompt3,
|
|
6262
6416
|
image: {
|
|
6263
6417
|
url: dataUri,
|
|
@@ -6324,11 +6478,15 @@ var init_GrokProvider = __esm({
|
|
|
6324
6478
|
try {
|
|
6325
6479
|
const duration = Math.round(Math.min(15, Math.max(1, options?.duration || 5)));
|
|
6326
6480
|
const body = {
|
|
6327
|
-
model: DEFAULT_MODEL5,
|
|
6481
|
+
model: options?.model || DEFAULT_MODEL5,
|
|
6328
6482
|
prompt: prompt3,
|
|
6329
6483
|
duration,
|
|
6330
|
-
aspect_ratio: options?.aspectRatio || "16:9"
|
|
6484
|
+
aspect_ratio: options?.aspectRatio || "16:9",
|
|
6485
|
+
resolution: GROK_VIDEO_RESOLUTIONS.includes(options?.resolution ?? "") ? options.resolution : DEFAULT_VIDEO_RESOLUTION
|
|
6331
6486
|
};
|
|
6487
|
+
if (typeof options?.generateAudio === "boolean") {
|
|
6488
|
+
body.generate_audio = options.generateAudio;
|
|
6489
|
+
}
|
|
6332
6490
|
if (options?.referenceImage) {
|
|
6333
6491
|
body.image = { url: options.referenceImage };
|
|
6334
6492
|
}
|
|
@@ -6390,13 +6548,14 @@ var init_GrokProvider = __esm({
|
|
|
6390
6548
|
const statusMap = {
|
|
6391
6549
|
pending: "pending",
|
|
6392
6550
|
done: "completed",
|
|
6393
|
-
expired: "failed"
|
|
6551
|
+
expired: "failed",
|
|
6552
|
+
failed: "failed"
|
|
6394
6553
|
};
|
|
6395
6554
|
return {
|
|
6396
6555
|
id,
|
|
6397
6556
|
status: statusMap[data.status] || "pending",
|
|
6398
6557
|
videoUrl: data.video?.url,
|
|
6399
|
-
error: data.status === "expired" ? "Generation expired" : void 0
|
|
6558
|
+
error: data.status === "expired" ? "Generation expired" : data.status === "failed" ? `Generation failed: ${data.error?.message ?? data.error?.code ?? "unknown error"}` : void 0
|
|
6400
6559
|
};
|
|
6401
6560
|
} catch (error) {
|
|
6402
6561
|
return {
|
|
@@ -10590,14 +10749,21 @@ var require_src = __commonJS({
|
|
|
10590
10749
|
});
|
|
10591
10750
|
|
|
10592
10751
|
// ../ai-providers/dist/fal/FalProvider.js
|
|
10752
|
+
function resolveSeedanceVariant(alias) {
|
|
10753
|
+
const model = findModel("seedance", "video", alias);
|
|
10754
|
+
if (model)
|
|
10755
|
+
return model.id;
|
|
10756
|
+
throw new Error(`Unknown Seedance model "${alias}". Valid: ${modelAliases("seedance", "video").join(", ")}.`);
|
|
10757
|
+
}
|
|
10593
10758
|
function estimateSeedanceVideoCostUsd(opts) {
|
|
10594
10759
|
const shortSide = SEEDANCE_SHORT_SIDE[opts.resolution ?? "720p"] ?? 720;
|
|
10595
10760
|
const [a, b] = (opts.aspectRatio ?? "16:9").split(":").map(Number);
|
|
10596
10761
|
const ratioFactor = a > 0 && b > 0 ? Math.max(a, b) / Math.min(a, b) : 16 / 9;
|
|
10597
10762
|
const longSide = Math.round(shortSide * ratioFactor);
|
|
10598
10763
|
const tokensPerSecond = shortSide * longSide * 24 / 1024;
|
|
10599
|
-
|
|
10600
|
-
|
|
10764
|
+
const rate = opts.v25 ? shortSide >= 1080 ? SEEDANCE_25_1080P_USD_PER_1K_TOKENS : SEEDANCE_25_USD_PER_1K_TOKENS : SEEDANCE_USD_PER_1K_TOKENS;
|
|
10765
|
+
let usdPerSecond = tokensPerSecond / 1e3 * rate;
|
|
10766
|
+
if (opts.fast && !opts.v25 && shortSide <= 720)
|
|
10601
10767
|
usdPerSecond *= SEEDANCE_FAST_FACTOR;
|
|
10602
10768
|
if (opts.hasVideoReference)
|
|
10603
10769
|
usdPerSecond *= SEEDANCE_VIDEO_REF_FACTOR;
|
|
@@ -10705,34 +10871,43 @@ function normaliseResolution(value) {
|
|
|
10705
10871
|
return "1080p";
|
|
10706
10872
|
return "720p";
|
|
10707
10873
|
}
|
|
10708
|
-
function normaliseDuration(value) {
|
|
10709
|
-
if (typeof value !== "number")
|
|
10874
|
+
function normaliseDuration(value, maxSec) {
|
|
10875
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
10710
10876
|
return "auto";
|
|
10711
|
-
|
|
10712
|
-
return "auto";
|
|
10713
|
-
return Math.max(4, Math.min(15, Math.round(value)));
|
|
10877
|
+
return String(Math.max(4, Math.min(maxSec, Math.round(value))));
|
|
10714
10878
|
}
|
|
10715
|
-
var import_client, ENDPOINT_TEXT_TO_VIDEO, ENDPOINT_IMAGE_TO_VIDEO, ENDPOINT_REFERENCE_TO_VIDEO, DEFAULT_VARIANT, VALID_RESOLUTIONS, VALID_ASPECTS, SEEDANCE_USD_PER_1K_TOKENS, SEEDANCE_FAST_FACTOR, SEEDANCE_VIDEO_REF_FACTOR, SEEDANCE_SHORT_SIDE, FalProvider, falProvider;
|
|
10879
|
+
var import_client, ENDPOINT_TEXT_TO_VIDEO, ENDPOINT_IMAGE_TO_VIDEO, ENDPOINT_REFERENCE_TO_VIDEO, DEFAULT_VARIANT, MAX_DURATION_SEC, VALID_RESOLUTIONS, VALID_ASPECTS, SEEDANCE_USD_PER_1K_TOKENS, SEEDANCE_25_USD_PER_1K_TOKENS, SEEDANCE_25_1080P_USD_PER_1K_TOKENS, SEEDANCE_FAST_FACTOR, SEEDANCE_VIDEO_REF_FACTOR, SEEDANCE_SHORT_SIDE, FalProvider, falProvider;
|
|
10716
10880
|
var init_FalProvider = __esm({
|
|
10717
10881
|
"../ai-providers/dist/fal/FalProvider.js"() {
|
|
10718
10882
|
"use strict";
|
|
10719
10883
|
import_client = __toESM(require_src(), 1);
|
|
10884
|
+
init_catalog();
|
|
10720
10885
|
ENDPOINT_TEXT_TO_VIDEO = {
|
|
10721
10886
|
"seedance-2.0": "bytedance/seedance-2.0/text-to-video",
|
|
10722
|
-
"seedance-2.0-fast": "bytedance/seedance-2.0/fast/text-to-video"
|
|
10887
|
+
"seedance-2.0-fast": "bytedance/seedance-2.0/fast/text-to-video",
|
|
10888
|
+
"seedance-2.5": "bytedance/seedance-2.5/text-to-video"
|
|
10723
10889
|
};
|
|
10724
10890
|
ENDPOINT_IMAGE_TO_VIDEO = {
|
|
10725
10891
|
"seedance-2.0": "bytedance/seedance-2.0/image-to-video",
|
|
10726
|
-
"seedance-2.0-fast": "bytedance/seedance-2.0/fast/image-to-video"
|
|
10892
|
+
"seedance-2.0-fast": "bytedance/seedance-2.0/fast/image-to-video",
|
|
10893
|
+
"seedance-2.5": "bytedance/seedance-2.5/image-to-video"
|
|
10727
10894
|
};
|
|
10728
10895
|
ENDPOINT_REFERENCE_TO_VIDEO = {
|
|
10729
10896
|
"seedance-2.0": "bytedance/seedance-2.0/reference-to-video",
|
|
10730
|
-
"seedance-2.0-fast": "bytedance/seedance-2.0/fast/reference-to-video"
|
|
10897
|
+
"seedance-2.0-fast": "bytedance/seedance-2.0/fast/reference-to-video",
|
|
10898
|
+
"seedance-2.5": "bytedance/seedance-2.5/reference-to-video"
|
|
10731
10899
|
};
|
|
10732
10900
|
DEFAULT_VARIANT = "seedance-2.0";
|
|
10901
|
+
MAX_DURATION_SEC = {
|
|
10902
|
+
"seedance-2.0": 15,
|
|
10903
|
+
"seedance-2.0-fast": 15,
|
|
10904
|
+
"seedance-2.5": 30
|
|
10905
|
+
};
|
|
10733
10906
|
VALID_RESOLUTIONS = ["480p", "720p", "1080p"];
|
|
10734
10907
|
VALID_ASPECTS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "auto"];
|
|
10735
10908
|
SEEDANCE_USD_PER_1K_TOKENS = 0.014;
|
|
10909
|
+
SEEDANCE_25_USD_PER_1K_TOKENS = 0.0214;
|
|
10910
|
+
SEEDANCE_25_1080P_USD_PER_1K_TOKENS = 0.0234;
|
|
10736
10911
|
SEEDANCE_FAST_FACTOR = 0.8;
|
|
10737
10912
|
SEEDANCE_VIDEO_REF_FACTOR = 0.6;
|
|
10738
10913
|
SEEDANCE_SHORT_SIDE = { "480p": 480, "720p": 720, "1080p": 1080 };
|
|
@@ -10787,7 +10962,7 @@ var init_FalProvider = __esm({
|
|
|
10787
10962
|
const endpointId = hasReferences ? ENDPOINT_REFERENCE_TO_VIDEO[variant] : isImageToVideo ? ENDPOINT_IMAGE_TO_VIDEO[variant] : ENDPOINT_TEXT_TO_VIDEO[variant];
|
|
10788
10963
|
const aspect = normaliseAspect(options?.aspectRatio);
|
|
10789
10964
|
const resolution = normaliseResolution(options?.resolution);
|
|
10790
|
-
const duration = normaliseDuration(options?.duration);
|
|
10965
|
+
const duration = normaliseDuration(options?.duration, MAX_DURATION_SEC[variant]);
|
|
10791
10966
|
const input = {
|
|
10792
10967
|
prompt: prompt3,
|
|
10793
10968
|
aspect_ratio: aspect,
|
|
@@ -10805,10 +10980,12 @@ var init_FalProvider = __esm({
|
|
|
10805
10980
|
} else if (referenceImage) {
|
|
10806
10981
|
input.image_url = referenceImage;
|
|
10807
10982
|
}
|
|
10808
|
-
if (
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
10983
|
+
if (variant !== "seedance-2.5") {
|
|
10984
|
+
if (options?.negativePrompt)
|
|
10985
|
+
input.negative_prompt = options.negativePrompt;
|
|
10986
|
+
if (typeof options?.seed === "number")
|
|
10987
|
+
input.seed = options.seed;
|
|
10988
|
+
}
|
|
10812
10989
|
if (typeof options?.generateAudio === "boolean")
|
|
10813
10990
|
input.generate_audio = options.generateAudio;
|
|
10814
10991
|
if (options?.endUserId)
|
|
@@ -11535,6 +11712,7 @@ var init_replicate = __esm({
|
|
|
11535
11712
|
var dist_exports2 = {};
|
|
11536
11713
|
__export(dist_exports2, {
|
|
11537
11714
|
ClaudeProvider: () => ClaudeProvider,
|
|
11715
|
+
ELEVENLABS_MUSIC_MODEL: () => ELEVENLABS_MUSIC_MODEL,
|
|
11538
11716
|
ElevenLabsProvider: () => ElevenLabsProvider,
|
|
11539
11717
|
FalProvider: () => FalProvider,
|
|
11540
11718
|
GEMINI_AGENT_DEFAULT_TEXT_MODEL: () => GEMINI_AGENT_DEFAULT_TEXT_MODEL,
|
|
@@ -11548,6 +11726,8 @@ __export(dist_exports2, {
|
|
|
11548
11726
|
KOKORO_MODEL_ID: () => KOKORO_MODEL_ID,
|
|
11549
11727
|
KlingProvider: () => KlingProvider,
|
|
11550
11728
|
KokoroProvider: () => KokoroProvider,
|
|
11729
|
+
MODEL_CATALOG: () => MODEL_CATALOG,
|
|
11730
|
+
OPENAI_IMAGE_DEFAULT_MODEL: () => OPENAI_IMAGE_DEFAULT_MODEL,
|
|
11551
11731
|
OPENAI_TTS_VOICES: () => OPENAI_TTS_VOICES,
|
|
11552
11732
|
OllamaProvider: () => OllamaProvider,
|
|
11553
11733
|
OmniProvider: () => OmniProvider,
|
|
@@ -11556,13 +11736,16 @@ __export(dist_exports2, {
|
|
|
11556
11736
|
OpenAiTtsProvider: () => OpenAiTtsProvider,
|
|
11557
11737
|
ReplicateProvider: () => ReplicateProvider,
|
|
11558
11738
|
RunwayProvider: () => RunwayProvider,
|
|
11739
|
+
VEO_MODEL_ALIASES: () => VEO_MODEL_ALIASES,
|
|
11559
11740
|
WhisperProvider: () => WhisperProvider,
|
|
11560
11741
|
claudeProvider: () => claudeProvider,
|
|
11742
|
+
defaultModel: () => defaultModel,
|
|
11561
11743
|
defineApiKey: () => defineApiKey,
|
|
11562
11744
|
defineProvider: () => defineProvider,
|
|
11563
11745
|
elevenLabsProvider: () => elevenLabsProvider,
|
|
11564
11746
|
estimateSeedanceVideoCostUsd: () => estimateSeedanceVideoCostUsd,
|
|
11565
11747
|
falProvider: () => falProvider,
|
|
11748
|
+
findModel: () => findModel,
|
|
11566
11749
|
geminiProvider: () => geminiProvider,
|
|
11567
11750
|
getAllApiKeys: () => getAllApiKeys,
|
|
11568
11751
|
getAllProviders: () => getAllProviders,
|
|
@@ -11576,10 +11759,13 @@ __export(dist_exports2, {
|
|
|
11576
11759
|
getSetupProviders: () => getSetupProviders,
|
|
11577
11760
|
grokProvider: () => grokProvider,
|
|
11578
11761
|
isGeminiTextModelAlias: () => isGeminiTextModelAlias,
|
|
11762
|
+
klingDuration: () => klingDuration,
|
|
11579
11763
|
klingProvider: () => klingProvider,
|
|
11580
11764
|
kokoroProvider: () => kokoroProvider,
|
|
11765
|
+
listModels: () => listModels,
|
|
11581
11766
|
loadBundledKokoroRuntime: () => loadBundledKokoroRuntime,
|
|
11582
11767
|
loadKokoroFromWorkspace: () => loadKokoroFromWorkspace,
|
|
11768
|
+
modelAliases: () => modelAliases,
|
|
11583
11769
|
ollamaProvider: () => ollamaProvider,
|
|
11584
11770
|
omniProvider: () => omniProvider,
|
|
11585
11771
|
openaiImageProvider: () => openaiImageProvider,
|
|
@@ -11588,6 +11774,11 @@ __export(dist_exports2, {
|
|
|
11588
11774
|
providerRegistry: () => providerRegistry,
|
|
11589
11775
|
replicateProvider: () => replicateProvider,
|
|
11590
11776
|
resolveGeminiTextModel: () => resolveGeminiTextModel,
|
|
11777
|
+
resolveGrokImageModel: () => resolveGrokImageModel,
|
|
11778
|
+
resolveGrokVideoModel: () => resolveGrokVideoModel,
|
|
11779
|
+
resolveKlingModel: () => resolveKlingModel,
|
|
11780
|
+
resolveSeedanceVariant: () => resolveSeedanceVariant,
|
|
11781
|
+
resolveVeoModel: () => resolveVeoModel,
|
|
11591
11782
|
resolveVoiceId: () => resolveVoiceId,
|
|
11592
11783
|
runwayProvider: () => runwayProvider,
|
|
11593
11784
|
whisperProvider: () => whisperProvider
|
|
@@ -11601,6 +11792,7 @@ var init_dist2 = __esm({
|
|
|
11601
11792
|
init_define_provider();
|
|
11602
11793
|
init_whisper();
|
|
11603
11794
|
init_gemini();
|
|
11795
|
+
init_catalog2();
|
|
11604
11796
|
init_openai();
|
|
11605
11797
|
init_claude();
|
|
11606
11798
|
init_ollama();
|
|
@@ -19843,12 +20035,15 @@ var init_ai_helpers = __esm({
|
|
|
19843
20035
|
});
|
|
19844
20036
|
|
|
19845
20037
|
// src/commands/_shared/video-utils.ts
|
|
19846
|
-
async function uploadToImgbb(imageBuffer, apiKey) {
|
|
20038
|
+
async function uploadToImgbb(imageBuffer, apiKey, expirationSeconds) {
|
|
19847
20039
|
try {
|
|
19848
20040
|
const base64Image = imageBuffer.toString("base64");
|
|
19849
20041
|
const formData = new URLSearchParams();
|
|
19850
20042
|
formData.append("key", apiKey);
|
|
19851
20043
|
formData.append("image", base64Image);
|
|
20044
|
+
if (expirationSeconds !== void 0) {
|
|
20045
|
+
formData.append("expiration", String(expirationSeconds));
|
|
20046
|
+
}
|
|
19852
20047
|
const response = await fetch("https://api.imgbb.com/1/upload", {
|
|
19853
20048
|
method: "POST",
|
|
19854
20049
|
body: formData
|
|
@@ -19911,7 +20106,10 @@ function awsEncode(value) {
|
|
|
19911
20106
|
(c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
|
|
19912
20107
|
);
|
|
19913
20108
|
}
|
|
19914
|
-
function
|
|
20109
|
+
function clamp(value, min, max) {
|
|
20110
|
+
return Math.min(max, Math.max(min, Math.round(value)));
|
|
20111
|
+
}
|
|
20112
|
+
function presignS3Url(params) {
|
|
19915
20113
|
const now = /* @__PURE__ */ new Date();
|
|
19916
20114
|
const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, "");
|
|
19917
20115
|
const dateStamp = amzDate.slice(0, 8);
|
|
@@ -19922,7 +20120,7 @@ function presignS3PutUrl(params) {
|
|
|
19922
20120
|
"X-Amz-Algorithm": "AWS4-HMAC-SHA256",
|
|
19923
20121
|
"X-Amz-Credential": `${params.accessKeyId}/${credentialScope}`,
|
|
19924
20122
|
"X-Amz-Date": amzDate,
|
|
19925
|
-
"X-Amz-Expires": String(params.ttlSeconds),
|
|
20123
|
+
"X-Amz-Expires": String(clamp(params.ttlSeconds, 1, S3_MAX_PRESIGN_SECONDS)),
|
|
19926
20124
|
"X-Amz-SignedHeaders": "host"
|
|
19927
20125
|
};
|
|
19928
20126
|
if (params.sessionToken) {
|
|
@@ -19930,7 +20128,7 @@ function presignS3PutUrl(params) {
|
|
|
19930
20128
|
}
|
|
19931
20129
|
const canonicalQuery = Object.entries(query).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => `${awsEncode(key)}=${awsEncode(value)}`).join("&");
|
|
19932
20130
|
const canonicalRequest = [
|
|
19933
|
-
|
|
20131
|
+
params.method,
|
|
19934
20132
|
canonicalUri,
|
|
19935
20133
|
canonicalQuery,
|
|
19936
20134
|
`host:${host}`,
|
|
@@ -19989,7 +20187,8 @@ async function resolveUploadHost() {
|
|
|
19989
20187
|
const ext = extensionFor(opts);
|
|
19990
20188
|
const prefix = safePrefix(settings.s3.prefix);
|
|
19991
20189
|
const key = `${prefix}/${Date.now()}-${randomUUID()}.${ext}`;
|
|
19992
|
-
const presignedUrl =
|
|
20190
|
+
const presignedUrl = presignS3Url({
|
|
20191
|
+
method: "PUT",
|
|
19993
20192
|
accessKeyId,
|
|
19994
20193
|
secretAccessKey,
|
|
19995
20194
|
sessionToken,
|
|
@@ -20008,10 +20207,26 @@ async function resolveUploadHost() {
|
|
|
20008
20207
|
if (!response.ok) {
|
|
20009
20208
|
throw new Error(`S3 upload failed (${response.status}): ${response.statusText}`);
|
|
20010
20209
|
}
|
|
20210
|
+
if (settings.s3.publicBaseUrl) {
|
|
20211
|
+
return {
|
|
20212
|
+
provider: "s3",
|
|
20213
|
+
url: publicS3Url({ region, bucket, key, publicBaseUrl: settings.s3.publicBaseUrl })
|
|
20214
|
+
};
|
|
20215
|
+
}
|
|
20216
|
+
const ttlSeconds = clamp(settings.ttlSeconds, 1, S3_MAX_PRESIGN_SECONDS);
|
|
20011
20217
|
return {
|
|
20012
20218
|
provider: "s3",
|
|
20013
|
-
url:
|
|
20014
|
-
|
|
20219
|
+
url: presignS3Url({
|
|
20220
|
+
method: "GET",
|
|
20221
|
+
accessKeyId,
|
|
20222
|
+
secretAccessKey,
|
|
20223
|
+
sessionToken,
|
|
20224
|
+
region,
|
|
20225
|
+
bucket,
|
|
20226
|
+
key,
|
|
20227
|
+
ttlSeconds
|
|
20228
|
+
}),
|
|
20229
|
+
expiresAt: new Date(Date.now() + ttlSeconds * 1e3).toISOString()
|
|
20015
20230
|
};
|
|
20016
20231
|
}
|
|
20017
20232
|
};
|
|
@@ -20023,19 +20238,28 @@ async function resolveUploadHost() {
|
|
|
20023
20238
|
if (!imgbbKey) {
|
|
20024
20239
|
throw new Error("IMGBB_API_KEY required for image-to-video uploads.");
|
|
20025
20240
|
}
|
|
20026
|
-
const
|
|
20241
|
+
const expiration = clamp(settings.ttlSeconds, IMGBB_MIN_EXPIRATION_SECONDS, IMGBB_MAX_EXPIRATION_SECONDS);
|
|
20242
|
+
const result = await uploadToImgbb(imageBuffer, imgbbKey, expiration);
|
|
20027
20243
|
if (!result.success || !result.url) {
|
|
20028
20244
|
throw new Error(`ImgBB upload failed: ${result.error ?? "unknown error"}`);
|
|
20029
20245
|
}
|
|
20030
|
-
return {
|
|
20246
|
+
return {
|
|
20247
|
+
provider: "imgbb",
|
|
20248
|
+
url: result.url,
|
|
20249
|
+
expiresAt: new Date(Date.now() + expiration * 1e3).toISOString()
|
|
20250
|
+
};
|
|
20031
20251
|
}
|
|
20032
20252
|
};
|
|
20033
20253
|
}
|
|
20254
|
+
var S3_MAX_PRESIGN_SECONDS, IMGBB_MIN_EXPIRATION_SECONDS, IMGBB_MAX_EXPIRATION_SECONDS;
|
|
20034
20255
|
var init_upload_host = __esm({
|
|
20035
20256
|
"src/utils/upload-host.ts"() {
|
|
20036
20257
|
"use strict";
|
|
20037
20258
|
init_config();
|
|
20038
20259
|
init_video_utils();
|
|
20260
|
+
S3_MAX_PRESIGN_SECONDS = 7 * 24 * 60 * 60;
|
|
20261
|
+
IMGBB_MIN_EXPIRATION_SECONDS = 60;
|
|
20262
|
+
IMGBB_MAX_EXPIRATION_SECONDS = 15552e3;
|
|
20039
20263
|
}
|
|
20040
20264
|
});
|
|
20041
20265
|
|
|
@@ -20653,8 +20877,14 @@ __export(ai_video_exports, {
|
|
|
20653
20877
|
executeVideoGenerate: () => executeVideoGenerate,
|
|
20654
20878
|
executeVideoStatus: () => executeVideoStatus
|
|
20655
20879
|
});
|
|
20656
|
-
import { readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
20657
|
-
import { resolve as resolve3 } from "node:path";
|
|
20880
|
+
import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
20881
|
+
import { dirname as dirname2, resolve as resolve3 } from "node:path";
|
|
20882
|
+
async function saveOutput(output, buffer) {
|
|
20883
|
+
const outputPath = resolve3(process.cwd(), output);
|
|
20884
|
+
await mkdir2(dirname2(outputPath), { recursive: true });
|
|
20885
|
+
await writeFile3(outputPath, buffer);
|
|
20886
|
+
return outputPath;
|
|
20887
|
+
}
|
|
20658
20888
|
async function executeVideoGenerate(options) {
|
|
20659
20889
|
const {
|
|
20660
20890
|
prompt: prompt3,
|
|
@@ -20670,7 +20900,10 @@ async function executeVideoGenerate(options) {
|
|
|
20670
20900
|
negative,
|
|
20671
20901
|
resolution,
|
|
20672
20902
|
veoModel = "3.1-fast",
|
|
20903
|
+
runwayModel,
|
|
20673
20904
|
seedanceModel = "quality",
|
|
20905
|
+
grokModel,
|
|
20906
|
+
klingModel,
|
|
20674
20907
|
generateAudio,
|
|
20675
20908
|
output,
|
|
20676
20909
|
wait = true,
|
|
@@ -20725,7 +20958,7 @@ async function executeVideoGenerate(options) {
|
|
|
20725
20958
|
});
|
|
20726
20959
|
falImage = upload.url;
|
|
20727
20960
|
}
|
|
20728
|
-
const model = seedanceModel
|
|
20961
|
+
const model = resolveSeedanceVariant(seedanceModel);
|
|
20729
20962
|
const result = await fal.generateVideo(prompt3, {
|
|
20730
20963
|
prompt: prompt3,
|
|
20731
20964
|
referenceImage: references.length > 0 ? void 0 : falImage,
|
|
@@ -20742,8 +20975,7 @@ async function executeVideoGenerate(options) {
|
|
|
20742
20975
|
let outputPath;
|
|
20743
20976
|
if (output && result.videoUrl) {
|
|
20744
20977
|
const buffer = await downloadVideo(result.videoUrl, key);
|
|
20745
|
-
outputPath =
|
|
20746
|
-
await writeFile3(outputPath, buffer);
|
|
20978
|
+
outputPath = await saveOutput(output, buffer);
|
|
20747
20979
|
}
|
|
20748
20980
|
return {
|
|
20749
20981
|
success: true,
|
|
@@ -20758,6 +20990,7 @@ async function executeVideoGenerate(options) {
|
|
|
20758
20990
|
await runway.initialize({ apiKey: key });
|
|
20759
20991
|
const result = await runway.generateVideo(prompt3, {
|
|
20760
20992
|
prompt: prompt3,
|
|
20993
|
+
model: runwayModel,
|
|
20761
20994
|
referenceImage,
|
|
20762
20995
|
duration,
|
|
20763
20996
|
aspectRatio: ratio,
|
|
@@ -20774,8 +21007,7 @@ async function executeVideoGenerate(options) {
|
|
|
20774
21007
|
let outputPath;
|
|
20775
21008
|
if (output && finalResult.videoUrl) {
|
|
20776
21009
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
20777
|
-
outputPath =
|
|
20778
|
-
await writeFile3(outputPath, buffer);
|
|
21010
|
+
outputPath = await saveOutput(output, buffer);
|
|
20779
21011
|
}
|
|
20780
21012
|
return {
|
|
20781
21013
|
success: true,
|
|
@@ -20801,6 +21033,7 @@ async function executeVideoGenerate(options) {
|
|
|
20801
21033
|
}
|
|
20802
21034
|
const result = await kling.generateVideo(prompt3, {
|
|
20803
21035
|
prompt: prompt3,
|
|
21036
|
+
model: resolveKlingModel(klingModel),
|
|
20804
21037
|
referenceImage: klingImage,
|
|
20805
21038
|
duration,
|
|
20806
21039
|
aspectRatio: ratio,
|
|
@@ -20819,8 +21052,7 @@ async function executeVideoGenerate(options) {
|
|
|
20819
21052
|
let outputPath;
|
|
20820
21053
|
if (output && finalResult.videoUrl) {
|
|
20821
21054
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
20822
|
-
outputPath =
|
|
20823
|
-
await writeFile3(outputPath, buffer);
|
|
21055
|
+
outputPath = await saveOutput(output, buffer);
|
|
20824
21056
|
}
|
|
20825
21057
|
return {
|
|
20826
21058
|
success: true,
|
|
@@ -20834,12 +21066,7 @@ async function executeVideoGenerate(options) {
|
|
|
20834
21066
|
} else if (provider === "veo") {
|
|
20835
21067
|
const gemini = new GeminiProvider();
|
|
20836
21068
|
await gemini.initialize({ apiKey: key });
|
|
20837
|
-
const
|
|
20838
|
-
"3.0": "veo-3.0-generate-preview",
|
|
20839
|
-
"3.1": "veo-3.1-generate-preview",
|
|
20840
|
-
"3.1-fast": "veo-3.1-fast-generate-preview"
|
|
20841
|
-
};
|
|
20842
|
-
const model = veoModelMap[veoModel] || "veo-3.1-fast-generate-preview";
|
|
21069
|
+
const model = resolveVeoModel(veoModel);
|
|
20843
21070
|
const veoDuration = duration <= 6 ? 6 : 8;
|
|
20844
21071
|
const result = await gemini.generateVideo(prompt3, {
|
|
20845
21072
|
prompt: prompt3,
|
|
@@ -20860,8 +21087,7 @@ async function executeVideoGenerate(options) {
|
|
|
20860
21087
|
let outputPath;
|
|
20861
21088
|
if (output && finalResult.videoUrl) {
|
|
20862
21089
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
20863
|
-
outputPath =
|
|
20864
|
-
await writeFile3(outputPath, buffer);
|
|
21090
|
+
outputPath = await saveOutput(output, buffer);
|
|
20865
21091
|
}
|
|
20866
21092
|
return {
|
|
20867
21093
|
success: true,
|
|
@@ -20876,9 +21102,12 @@ async function executeVideoGenerate(options) {
|
|
|
20876
21102
|
await grok.initialize({ apiKey: key });
|
|
20877
21103
|
const result = await grok.generateVideo(prompt3, {
|
|
20878
21104
|
prompt: prompt3,
|
|
21105
|
+
model: resolveGrokVideoModel(grokModel),
|
|
20879
21106
|
referenceImage,
|
|
20880
21107
|
duration,
|
|
20881
|
-
aspectRatio: ratio
|
|
21108
|
+
aspectRatio: ratio,
|
|
21109
|
+
resolution,
|
|
21110
|
+
generateAudio
|
|
20882
21111
|
});
|
|
20883
21112
|
if (result.status === "failed")
|
|
20884
21113
|
return { success: false, error: result.error || "Grok generation failed" };
|
|
@@ -20891,8 +21120,7 @@ async function executeVideoGenerate(options) {
|
|
|
20891
21120
|
let outputPath;
|
|
20892
21121
|
if (output && finalResult.videoUrl) {
|
|
20893
21122
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
20894
|
-
outputPath =
|
|
20895
|
-
await writeFile3(outputPath, buffer);
|
|
21123
|
+
outputPath = await saveOutput(output, buffer);
|
|
20896
21124
|
}
|
|
20897
21125
|
return {
|
|
20898
21126
|
success: true,
|
|
@@ -20909,7 +21137,8 @@ async function executeVideoGenerate(options) {
|
|
|
20909
21137
|
const result = await omni.generateVideo(prompt3, {
|
|
20910
21138
|
prompt: prompt3,
|
|
20911
21139
|
referenceImage,
|
|
20912
|
-
aspectRatio: ratio
|
|
21140
|
+
aspectRatio: ratio,
|
|
21141
|
+
resolution
|
|
20913
21142
|
});
|
|
20914
21143
|
if (result.status !== "completed" || !result.videoUrl) {
|
|
20915
21144
|
return { success: false, error: result.error || "Gemini Omni generation failed" };
|
|
@@ -20917,8 +21146,7 @@ async function executeVideoGenerate(options) {
|
|
|
20917
21146
|
let outputPath;
|
|
20918
21147
|
if (output) {
|
|
20919
21148
|
const buffer = await downloadVideo(result.videoUrl, key);
|
|
20920
|
-
outputPath =
|
|
20921
|
-
await writeFile3(outputPath, buffer);
|
|
21149
|
+
outputPath = await saveOutput(output, buffer);
|
|
20922
21150
|
}
|
|
20923
21151
|
return {
|
|
20924
21152
|
success: true,
|
|
@@ -21014,8 +21242,7 @@ async function executeVideoStatus(options) {
|
|
|
21014
21242
|
let outputPath;
|
|
21015
21243
|
if (output && result.videoUrl) {
|
|
21016
21244
|
const buffer = await downloadVideo(result.videoUrl);
|
|
21017
|
-
outputPath =
|
|
21018
|
-
await writeFile3(outputPath, buffer);
|
|
21245
|
+
outputPath = await saveOutput(output, buffer);
|
|
21019
21246
|
}
|
|
21020
21247
|
return {
|
|
21021
21248
|
success: true,
|
|
@@ -21037,8 +21264,7 @@ async function executeVideoStatus(options) {
|
|
|
21037
21264
|
let outputPath;
|
|
21038
21265
|
if (output && result.videoUrl) {
|
|
21039
21266
|
const buffer = await downloadVideo(result.videoUrl, key);
|
|
21040
|
-
outputPath =
|
|
21041
|
-
await writeFile3(outputPath, buffer);
|
|
21267
|
+
outputPath = await saveOutput(output, buffer);
|
|
21042
21268
|
}
|
|
21043
21269
|
return {
|
|
21044
21270
|
success: true,
|
|
@@ -21059,8 +21285,7 @@ async function executeVideoStatus(options) {
|
|
|
21059
21285
|
let outputPath;
|
|
21060
21286
|
if (output && result.videoUrl) {
|
|
21061
21287
|
const buffer = await downloadVideo(result.videoUrl, key);
|
|
21062
|
-
outputPath =
|
|
21063
|
-
await writeFile3(outputPath, buffer);
|
|
21288
|
+
outputPath = await saveOutput(output, buffer);
|
|
21064
21289
|
}
|
|
21065
21290
|
return {
|
|
21066
21291
|
success: true,
|
|
@@ -21082,8 +21307,7 @@ async function executeVideoStatus(options) {
|
|
|
21082
21307
|
let outputPath;
|
|
21083
21308
|
if (output && result.videoUrl) {
|
|
21084
21309
|
const buffer = await downloadVideo(result.videoUrl, key);
|
|
21085
|
-
outputPath =
|
|
21086
|
-
await writeFile3(outputPath, buffer);
|
|
21310
|
+
outputPath = await saveOutput(output, buffer);
|
|
21087
21311
|
}
|
|
21088
21312
|
return {
|
|
21089
21313
|
success: true,
|
|
@@ -21153,8 +21377,7 @@ async function executeVideoExtend(options) {
|
|
|
21153
21377
|
let outputPath;
|
|
21154
21378
|
if (output && finalResult.videoUrl) {
|
|
21155
21379
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
21156
|
-
outputPath =
|
|
21157
|
-
await writeFile3(outputPath, buffer);
|
|
21380
|
+
outputPath = await saveOutput(output, buffer);
|
|
21158
21381
|
}
|
|
21159
21382
|
return {
|
|
21160
21383
|
success: true,
|
|
@@ -21169,12 +21392,7 @@ async function executeVideoExtend(options) {
|
|
|
21169
21392
|
if (!key) return { success: false, error: "GOOGLE_API_KEY required" };
|
|
21170
21393
|
const gemini = new GeminiProvider();
|
|
21171
21394
|
await gemini.initialize({ apiKey: key });
|
|
21172
|
-
const
|
|
21173
|
-
"3.0": "veo-3.0-generate-preview",
|
|
21174
|
-
"3.1": "veo-3.1-generate-preview",
|
|
21175
|
-
"3.1-fast": "veo-3.1-fast-generate-preview"
|
|
21176
|
-
};
|
|
21177
|
-
const model = veoModelMap[veoModel] || "veo-3.1-generate-preview";
|
|
21395
|
+
const model = resolveVeoModel(veoModel);
|
|
21178
21396
|
const result = await gemini.extendVideo(videoId, prompt3, {
|
|
21179
21397
|
duration,
|
|
21180
21398
|
model
|
|
@@ -21189,8 +21407,7 @@ async function executeVideoExtend(options) {
|
|
|
21189
21407
|
let outputPath;
|
|
21190
21408
|
if (output && finalResult.videoUrl) {
|
|
21191
21409
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
21192
|
-
outputPath =
|
|
21193
|
-
await writeFile3(outputPath, buffer);
|
|
21410
|
+
outputPath = await saveOutput(output, buffer);
|
|
21194
21411
|
}
|
|
21195
21412
|
return {
|
|
21196
21413
|
success: true,
|
|
@@ -21252,8 +21469,8 @@ var init_music_status = __esm({
|
|
|
21252
21469
|
|
|
21253
21470
|
// src/commands/_shared/build-asset-metadata.ts
|
|
21254
21471
|
import { existsSync, readFileSync } from "node:fs";
|
|
21255
|
-
import { mkdir as
|
|
21256
|
-
import { dirname as
|
|
21472
|
+
import { mkdir as mkdir3, writeFile as writeFile4 } from "node:fs/promises";
|
|
21473
|
+
import { dirname as dirname3, join } from "node:path";
|
|
21257
21474
|
function assetMetadataPath(kind, beatId) {
|
|
21258
21475
|
return `.vibeframe/assets/${kind}-${beatId}.json`;
|
|
21259
21476
|
}
|
|
@@ -21301,7 +21518,7 @@ async function writeAssetMetadata(opts) {
|
|
|
21301
21518
|
cachePath: opts.cachePath,
|
|
21302
21519
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
21303
21520
|
};
|
|
21304
|
-
await
|
|
21521
|
+
await mkdir3(dirname3(abs), { recursive: true });
|
|
21305
21522
|
await writeFile4(abs, JSON.stringify(metadata, null, 2) + "\n", "utf-8");
|
|
21306
21523
|
}
|
|
21307
21524
|
var init_build_asset_metadata = __esm({
|
|
@@ -22260,7 +22477,7 @@ var init_storyboard_edit = __esm({
|
|
|
22260
22477
|
|
|
22261
22478
|
// src/commands/_shared/storyboard-source.ts
|
|
22262
22479
|
import { existsSync as existsSync2 } from "node:fs";
|
|
22263
|
-
import { mkdir as
|
|
22480
|
+
import { mkdir as mkdir4, readdir, readFile as readFile4, rename, rm, writeFile as writeFile6 } from "node:fs/promises";
|
|
22264
22481
|
import { basename, join as join3 } from "node:path";
|
|
22265
22482
|
function sceneFileFrom(dir, filename) {
|
|
22266
22483
|
const stem = filename.replace(/\.mdx?$/i, "");
|
|
@@ -22373,7 +22590,7 @@ ${(0, import_yaml5.stringify)(data, { lineWidth: 0 }).trimEnd()}
|
|
|
22373
22590
|
};
|
|
22374
22591
|
}
|
|
22375
22592
|
async function writeMigration(projectDir, plan) {
|
|
22376
|
-
await
|
|
22593
|
+
await mkdir4(join3(projectDir, SCENES_DIRNAME), { recursive: true });
|
|
22377
22594
|
for (const file of plan.scenes) {
|
|
22378
22595
|
await writeFile6(join3(projectDir, file.path), file.contents, "utf-8");
|
|
22379
22596
|
}
|
|
@@ -22395,7 +22612,7 @@ function strayBeatIssues(strayBeatIds) {
|
|
|
22395
22612
|
async function upsertScene(projectDir, opts) {
|
|
22396
22613
|
const beatId = deriveBeatId(opts.beatId);
|
|
22397
22614
|
const dir = join3(projectDir, SCENES_DIRNAME);
|
|
22398
|
-
await
|
|
22615
|
+
await mkdir4(dir, { recursive: true });
|
|
22399
22616
|
const cues = {};
|
|
22400
22617
|
if (opts.duration !== void 0) cues.duration = opts.duration;
|
|
22401
22618
|
if (opts.narration?.trim()) cues.narration = opts.narration.trim();
|
|
@@ -22467,22 +22684,22 @@ var init_storyboard_source = __esm({
|
|
|
22467
22684
|
// src/commands/_shared/status-jobs.ts
|
|
22468
22685
|
import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
|
|
22469
22686
|
import { existsSync as existsSync3, statSync } from "node:fs";
|
|
22470
|
-
import { copyFile, mkdir as
|
|
22471
|
-
import { dirname as
|
|
22687
|
+
import { copyFile, mkdir as mkdir5, readFile as readFile5, readdir as readdir2, rename as rename2, stat, writeFile as writeFile7 } from "node:fs/promises";
|
|
22688
|
+
import { dirname as dirname4, join as join4, parse as parse2, relative, resolve as resolve5 } from "node:path";
|
|
22472
22689
|
function isLocalJob(record) {
|
|
22473
22690
|
return record.jobType === "build" || record.jobType === "render";
|
|
22474
22691
|
}
|
|
22475
22692
|
function findProjectRoot(start = process.cwd()) {
|
|
22476
22693
|
let dir = resolve5(start);
|
|
22477
22694
|
try {
|
|
22478
|
-
if (existsSync3(dir) && statSync(dir).isFile()) dir =
|
|
22695
|
+
if (existsSync3(dir) && statSync(dir).isFile()) dir = dirname4(dir);
|
|
22479
22696
|
} catch {
|
|
22480
22697
|
}
|
|
22481
22698
|
for (; ; ) {
|
|
22482
22699
|
if (existsSync3(join4(dir, "vibe.config.json")) || existsSync3(join4(dir, "STORYBOARD.md"))) {
|
|
22483
22700
|
return dir;
|
|
22484
22701
|
}
|
|
22485
|
-
const parent =
|
|
22702
|
+
const parent = dirname4(dir);
|
|
22486
22703
|
if (parent === dir) return resolve5(start);
|
|
22487
22704
|
dir = parent;
|
|
22488
22705
|
}
|
|
@@ -22549,7 +22766,7 @@ async function createAndWriteJobRecord(opts) {
|
|
|
22549
22766
|
}
|
|
22550
22767
|
async function writeJobRecord(record) {
|
|
22551
22768
|
const dir = jobsDir(record.projectDir);
|
|
22552
|
-
await
|
|
22769
|
+
await mkdir5(dir, { recursive: true });
|
|
22553
22770
|
const path2 = jobRecordPath(record.id, record.projectDir);
|
|
22554
22771
|
const tmp = `${path2}.${randomUUID2()}.tmp`;
|
|
22555
22772
|
await writeFile7(tmp, JSON.stringify(stripUndefined2(record), null, 2) + "\n", "utf-8");
|
|
@@ -22597,7 +22814,7 @@ async function refreshJobRecord(record, opts = {}) {
|
|
|
22597
22814
|
try {
|
|
22598
22815
|
if (record.jobType === "generate-video") {
|
|
22599
22816
|
const output = resolveRefreshOutput(record, opts);
|
|
22600
|
-
if (output) await
|
|
22817
|
+
if (output) await mkdir5(dirname4(output), { recursive: true });
|
|
22601
22818
|
const result = await executeVideoStatus({
|
|
22602
22819
|
taskId: record.providerTaskId,
|
|
22603
22820
|
provider: record.provider,
|
|
@@ -22880,14 +23097,14 @@ async function downloadUrl(url, outputPath) {
|
|
|
22880
23097
|
const response = await fetch(url);
|
|
22881
23098
|
if (!response.ok) throw new Error(`Download failed: HTTP ${response.status}`);
|
|
22882
23099
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
22883
|
-
await
|
|
23100
|
+
await mkdir5(dirname4(outputPath), { recursive: true });
|
|
22884
23101
|
await writeFile7(outputPath, buffer);
|
|
22885
23102
|
return outputPath;
|
|
22886
23103
|
}
|
|
22887
23104
|
async function maybeCacheOutput(record) {
|
|
22888
23105
|
if (record.status !== "completed" || !record.outputPath || !record.cachePath) return;
|
|
22889
23106
|
try {
|
|
22890
|
-
await
|
|
23107
|
+
await mkdir5(dirname4(record.cachePath), { recursive: true });
|
|
22891
23108
|
await copyFile(record.outputPath, record.cachePath);
|
|
22892
23109
|
} catch {
|
|
22893
23110
|
}
|
|
@@ -23471,7 +23688,7 @@ var init_project_config = __esm({
|
|
|
23471
23688
|
});
|
|
23472
23689
|
|
|
23473
23690
|
// src/commands/_shared/scene-project.ts
|
|
23474
|
-
import { mkdir as
|
|
23691
|
+
import { mkdir as mkdir6, readFile as readFile7, writeFile as writeFile8, access as access3 } from "node:fs/promises";
|
|
23475
23692
|
import { resolve as resolve7, basename as basename2 } from "node:path";
|
|
23476
23693
|
function isSceneKind(value) {
|
|
23477
23694
|
return VALID_SCENE_KINDS.includes(value);
|
|
@@ -24083,11 +24300,11 @@ async function scaffoldSceneProject(opts) {
|
|
|
24083
24300
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
24084
24301
|
const profile = opts.profile ?? "full";
|
|
24085
24302
|
const kind = opts.kind ?? DEFAULT_SCENE_KIND;
|
|
24086
|
-
await
|
|
24303
|
+
await mkdir6(dir, { recursive: true });
|
|
24087
24304
|
if (profile === "full") {
|
|
24088
|
-
await
|
|
24089
|
-
await
|
|
24090
|
-
await
|
|
24305
|
+
await mkdir6(resolve7(dir, "compositions"), { recursive: true });
|
|
24306
|
+
await mkdir6(resolve7(dir, "assets"), { recursive: true });
|
|
24307
|
+
await mkdir6(resolve7(dir, "renders"), { recursive: true });
|
|
24091
24308
|
}
|
|
24092
24309
|
const created = [];
|
|
24093
24310
|
const skipped2 = [];
|
|
@@ -31642,7 +31859,7 @@ var init_scene_audio_scan = __esm({
|
|
|
31642
31859
|
|
|
31643
31860
|
// src/commands/_shared/scene-audio-mux.ts
|
|
31644
31861
|
import { rename as rename3, unlink } from "node:fs/promises";
|
|
31645
|
-
import { resolve as resolve17, dirname as
|
|
31862
|
+
import { resolve as resolve17, dirname as dirname6, extname as extname2, basename as basename3 } from "node:path";
|
|
31646
31863
|
function buildAudioMuxFilter(audios) {
|
|
31647
31864
|
if (audios.length === 0) return null;
|
|
31648
31865
|
const labels = [];
|
|
@@ -31703,7 +31920,7 @@ async function muxAudioIntoVideo(opts) {
|
|
|
31703
31920
|
}
|
|
31704
31921
|
const ext = extname2(opts.videoPath) || `.${opts.format}`;
|
|
31705
31922
|
const tmpPath = resolve17(
|
|
31706
|
-
|
|
31923
|
+
dirname6(opts.videoPath),
|
|
31707
31924
|
`.${basename3(opts.videoPath, ext)}.muxing${ext}`
|
|
31708
31925
|
);
|
|
31709
31926
|
const args = ["-y", "-loglevel", "error", "-i", opts.videoPath];
|
|
@@ -31851,8 +32068,8 @@ __export(scene_render_exports, {
|
|
|
31851
32068
|
});
|
|
31852
32069
|
import { execFile as execFile2 } from "node:child_process";
|
|
31853
32070
|
import { existsSync as existsSync15 } from "node:fs";
|
|
31854
|
-
import { mkdir as
|
|
31855
|
-
import { resolve as resolve19, relative as relative6, dirname as
|
|
32071
|
+
import { mkdir as mkdir9, readFile as readFile16, stat as stat3, writeFile as writeFile14 } from "node:fs/promises";
|
|
32072
|
+
import { resolve as resolve19, relative as relative6, dirname as dirname7, basename as basename4, join as join13, isAbsolute as isAbsolute2 } from "node:path";
|
|
31856
32073
|
import { promisify as promisify2 } from "node:util";
|
|
31857
32074
|
import {
|
|
31858
32075
|
createRenderJob,
|
|
@@ -31905,7 +32122,7 @@ function buildMediaOpenCommand(action, filePath, platform = process.platform) {
|
|
|
31905
32122
|
display: ["cmd", ...args].map(quoteCliArg).join(" ")
|
|
31906
32123
|
};
|
|
31907
32124
|
}
|
|
31908
|
-
const target = action === "reveal" ?
|
|
32125
|
+
const target = action === "reveal" ? dirname7(filePath) : filePath;
|
|
31909
32126
|
return {
|
|
31910
32127
|
command: "xdg-open",
|
|
31911
32128
|
args: [target],
|
|
@@ -32001,7 +32218,7 @@ async function executeSceneRender(opts = {}) {
|
|
|
32001
32218
|
}
|
|
32002
32219
|
const projectName = projectConfig.config.name;
|
|
32003
32220
|
const outputPath = opts.output ? resolve19(projectDir, opts.output) : defaultOutputPath({ projectDir, projectName, format: opts.format, beatId: opts.beatId });
|
|
32004
|
-
await
|
|
32221
|
+
await mkdir9(dirname7(outputPath), { recursive: true });
|
|
32005
32222
|
const config2 = buildRenderConfig({
|
|
32006
32223
|
fps: opts.fps,
|
|
32007
32224
|
quality: opts.quality,
|
|
@@ -32197,7 +32414,7 @@ async function prepareBeatRenderRoot(opts) {
|
|
|
32197
32414
|
durationSec,
|
|
32198
32415
|
narrationPath
|
|
32199
32416
|
});
|
|
32200
|
-
await
|
|
32417
|
+
await mkdir9(dirname7(join13(opts.projectDir, root)), { recursive: true });
|
|
32201
32418
|
await writeFile14(join13(opts.projectDir, root), html, "utf-8");
|
|
32202
32419
|
return {
|
|
32203
32420
|
success: true,
|
|
@@ -32481,7 +32698,7 @@ var init_design_parse = __esm({
|
|
|
32481
32698
|
|
|
32482
32699
|
// src/commands/_shared/compose-aivideo.ts
|
|
32483
32700
|
import { existsSync as existsSync16 } from "node:fs";
|
|
32484
|
-
import { mkdir as
|
|
32701
|
+
import { mkdir as mkdir10, readFile as readFile17, writeFile as writeFile15 } from "node:fs/promises";
|
|
32485
32702
|
import { join as join14, resolve as resolve20 } from "node:path";
|
|
32486
32703
|
function headingDescriptor(heading) {
|
|
32487
32704
|
const stripped = heading.replace(/^\s*beat\s+/i, "");
|
|
@@ -32644,7 +32861,7 @@ async function composeAiVideo(opts) {
|
|
|
32644
32861
|
}
|
|
32645
32862
|
clipRels.push(rel);
|
|
32646
32863
|
}
|
|
32647
|
-
await
|
|
32864
|
+
await mkdir10(join14(projectDir, "assets"), { recursive: true });
|
|
32648
32865
|
const bgRel = "assets/bg-full.mp4";
|
|
32649
32866
|
const concatArgs = buildBgConcatArgs(
|
|
32650
32867
|
clipRels.map((r) => join14(projectDir, r)),
|
|
@@ -32652,7 +32869,7 @@ async function composeAiVideo(opts) {
|
|
|
32652
32869
|
);
|
|
32653
32870
|
await execSafe("ffmpeg", concatArgs, { timeout: 6e5 });
|
|
32654
32871
|
const totalDurationSec = await probeDurationSec(join14(projectDir, bgRel));
|
|
32655
|
-
await
|
|
32872
|
+
await mkdir10(join14(projectDir, "compositions"), { recursive: true });
|
|
32656
32873
|
const sceneFiles = [];
|
|
32657
32874
|
for (let i = 0; i < beats.length; i++) {
|
|
32658
32875
|
const beat = beats[i];
|
|
@@ -32801,8 +33018,8 @@ var init_compose_aivideo = __esm({
|
|
|
32801
33018
|
|
|
32802
33019
|
// src/commands/_shared/footage-assemble.ts
|
|
32803
33020
|
import { existsSync as existsSync17 } from "node:fs";
|
|
32804
|
-
import { mkdir as
|
|
32805
|
-
import { dirname as
|
|
33021
|
+
import { mkdir as mkdir11, writeFile as writeFile16 } from "node:fs/promises";
|
|
33022
|
+
import { dirname as dirname8, isAbsolute as isAbsolute3, join as join15, resolve as resolve21 } from "node:path";
|
|
32806
33023
|
function planFootageTimeline(inputs, opts = {}) {
|
|
32807
33024
|
if (inputs.length === 0) {
|
|
32808
33025
|
throw new Error("No clips to assemble.");
|
|
@@ -33131,7 +33348,7 @@ async function executeFootageAssemble(opts) {
|
|
|
33131
33348
|
if (opts.dryRun) {
|
|
33132
33349
|
return { success: true, dryRun: true, outputPath, report };
|
|
33133
33350
|
}
|
|
33134
|
-
await
|
|
33351
|
+
await mkdir11(dirname8(outputPath), { recursive: true });
|
|
33135
33352
|
const args = buildFootageAssembleArgs({
|
|
33136
33353
|
sources: sourceRels.map((s) => ({ path: join15(projectDir, s.rel), kind: s.kind })),
|
|
33137
33354
|
plan,
|
|
@@ -33492,9 +33709,40 @@ var init_composer_resolve = __esm({
|
|
|
33492
33709
|
}
|
|
33493
33710
|
});
|
|
33494
33711
|
|
|
33712
|
+
// src/commands/_shared/build-video-providers.ts
|
|
33713
|
+
function isBuildVideoProvider(value) {
|
|
33714
|
+
return BUILD_VIDEO_PROVIDERS.includes(value);
|
|
33715
|
+
}
|
|
33716
|
+
function resolveBuildVideoProvider(value) {
|
|
33717
|
+
const provider = String(value ?? "seedance").toLowerCase();
|
|
33718
|
+
if (provider === "fal") return "seedance";
|
|
33719
|
+
return isBuildVideoProvider(provider) ? provider : "seedance";
|
|
33720
|
+
}
|
|
33721
|
+
function videoProviderConfigKey(provider) {
|
|
33722
|
+
switch (provider) {
|
|
33723
|
+
case "seedance":
|
|
33724
|
+
case "fal":
|
|
33725
|
+
return "fal";
|
|
33726
|
+
case "grok":
|
|
33727
|
+
return "xai";
|
|
33728
|
+
case "veo":
|
|
33729
|
+
case "omni":
|
|
33730
|
+
return "google";
|
|
33731
|
+
default:
|
|
33732
|
+
return provider;
|
|
33733
|
+
}
|
|
33734
|
+
}
|
|
33735
|
+
var BUILD_VIDEO_PROVIDERS;
|
|
33736
|
+
var init_build_video_providers = __esm({
|
|
33737
|
+
"src/commands/_shared/build-video-providers.ts"() {
|
|
33738
|
+
"use strict";
|
|
33739
|
+
BUILD_VIDEO_PROVIDERS = ["seedance", "grok", "kling", "runway", "omni", "veo"];
|
|
33740
|
+
}
|
|
33741
|
+
});
|
|
33742
|
+
|
|
33495
33743
|
// src/commands/_shared/build-plan.ts
|
|
33496
33744
|
import { existsSync as existsSync19 } from "node:fs";
|
|
33497
|
-
import { dirname as
|
|
33745
|
+
import { dirname as dirname9, join as join16, resolve as resolve23 } from "node:path";
|
|
33498
33746
|
function backdropCostUsd(quality) {
|
|
33499
33747
|
return quality === "hd" ? 0.2 : 0.05;
|
|
33500
33748
|
}
|
|
@@ -34166,12 +34414,7 @@ function normalizeImageProvider(value) {
|
|
|
34166
34414
|
return provider || "openai";
|
|
34167
34415
|
}
|
|
34168
34416
|
function normalizeVideoProvider(value) {
|
|
34169
|
-
|
|
34170
|
-
if (provider === "fal") return "seedance";
|
|
34171
|
-
if (provider === "seedance" || provider === "grok" || provider === "kling" || provider === "runway" || provider === "veo") {
|
|
34172
|
-
return provider;
|
|
34173
|
-
}
|
|
34174
|
-
return "seedance";
|
|
34417
|
+
return resolveBuildVideoProvider(value);
|
|
34175
34418
|
}
|
|
34176
34419
|
function normalizeMusicProvider(value) {
|
|
34177
34420
|
const provider = String(value ?? "elevenlabs").toLowerCase();
|
|
@@ -34183,7 +34426,7 @@ function imageConfigKey(provider) {
|
|
|
34183
34426
|
return "openai";
|
|
34184
34427
|
}
|
|
34185
34428
|
function videoConfigKey(provider) {
|
|
34186
|
-
return provider
|
|
34429
|
+
return videoProviderConfigKey(provider);
|
|
34187
34430
|
}
|
|
34188
34431
|
function composerConfigKey(provider) {
|
|
34189
34432
|
return provider === "claude" ? "anthropic" : provider === "gemini" ? "google" : "openai";
|
|
@@ -34201,12 +34444,12 @@ function loadPlanEnv(projectDir) {
|
|
|
34201
34444
|
(0, import_dotenv2.config)({ path: join16(projectDir, ".env"), quiet: true });
|
|
34202
34445
|
(0, import_dotenv2.config)({ path: resolve23(process.cwd(), ".env"), quiet: true });
|
|
34203
34446
|
let dir = process.cwd();
|
|
34204
|
-
while (dir !==
|
|
34447
|
+
while (dir !== dirname9(dir)) {
|
|
34205
34448
|
if (existsSync19(join16(dir, "pnpm-workspace.yaml"))) {
|
|
34206
34449
|
(0, import_dotenv2.config)({ path: join16(dir, ".env"), quiet: true });
|
|
34207
34450
|
return;
|
|
34208
34451
|
}
|
|
34209
|
-
dir =
|
|
34452
|
+
dir = dirname9(dir);
|
|
34210
34453
|
}
|
|
34211
34454
|
}
|
|
34212
34455
|
var import_dotenv2, VIDEO_COST_USD, MUSIC_COST_USD, ELEVENLABS_NARRATION_COST_USD, OPENAI_NARRATION_COST_USD, TRANSCRIPT_COST_USD, COMPOSE_COST_USD, SUPPORTED_BUILD_IMAGE_PROVIDERS;
|
|
@@ -34227,6 +34470,7 @@ var init_build_plan = __esm({
|
|
|
34227
34470
|
init_project_config();
|
|
34228
34471
|
init_scene_project();
|
|
34229
34472
|
init_storyboard_edit();
|
|
34473
|
+
init_build_video_providers();
|
|
34230
34474
|
VIDEO_COST_USD = 5;
|
|
34231
34475
|
MUSIC_COST_USD = 0.5;
|
|
34232
34476
|
ELEVENLABS_NARRATION_COST_USD = 0.05;
|
|
@@ -34405,7 +34649,7 @@ function registerMusicCommand(parent) {
|
|
|
34405
34649
|
console.log();
|
|
34406
34650
|
console.log(`Saved to: ${source_default.bold(outputPath)}`);
|
|
34407
34651
|
console.log(`Duration: ${duration}s`);
|
|
34408
|
-
console.log(`Provider: ElevenLabs (
|
|
34652
|
+
console.log(`Provider: ElevenLabs (${ELEVENLABS_MUSIC_MODEL})`);
|
|
34409
34653
|
if (options.instrumental) console.log(`Mode: Instrumental`);
|
|
34410
34654
|
console.log();
|
|
34411
34655
|
} else {
|
|
@@ -34544,6 +34788,48 @@ var init_scene_build_mode = __esm({
|
|
|
34544
34788
|
}
|
|
34545
34789
|
});
|
|
34546
34790
|
|
|
34791
|
+
// src/utils/image-file.ts
|
|
34792
|
+
import { rm as rm2, writeFile as writeFile18 } from "node:fs/promises";
|
|
34793
|
+
import { extname as extname4 } from "node:path";
|
|
34794
|
+
function detectImageFormat(buffer) {
|
|
34795
|
+
if (buffer.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
|
|
34796
|
+
return "png";
|
|
34797
|
+
}
|
|
34798
|
+
if (buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) return "jpeg";
|
|
34799
|
+
if (buffer.toString("ascii", 0, 4) === "RIFF" && buffer.toString("ascii", 8, 12) === "WEBP") {
|
|
34800
|
+
return "webp";
|
|
34801
|
+
}
|
|
34802
|
+
return void 0;
|
|
34803
|
+
}
|
|
34804
|
+
async function writeImageFile(path2, buffer) {
|
|
34805
|
+
const wanted = EXTENSION_FORMATS[extname4(path2).toLowerCase()];
|
|
34806
|
+
const actual = detectImageFormat(buffer);
|
|
34807
|
+
if (!wanted || !actual || wanted === actual) {
|
|
34808
|
+
await writeFile18(path2, buffer);
|
|
34809
|
+
return;
|
|
34810
|
+
}
|
|
34811
|
+
const source = `${path2}.source.${actual === "jpeg" ? "jpg" : actual}`;
|
|
34812
|
+
await writeFile18(source, buffer);
|
|
34813
|
+
try {
|
|
34814
|
+
await execSafe("ffmpeg", ["-y", "-loglevel", "error", "-i", source, "-frames:v", "1", path2]);
|
|
34815
|
+
} finally {
|
|
34816
|
+
await rm2(source, { force: true });
|
|
34817
|
+
}
|
|
34818
|
+
}
|
|
34819
|
+
var EXTENSION_FORMATS;
|
|
34820
|
+
var init_image_file = __esm({
|
|
34821
|
+
"src/utils/image-file.ts"() {
|
|
34822
|
+
"use strict";
|
|
34823
|
+
init_exec_safe();
|
|
34824
|
+
EXTENSION_FORMATS = {
|
|
34825
|
+
".png": "png",
|
|
34826
|
+
".jpg": "jpeg",
|
|
34827
|
+
".jpeg": "jpeg",
|
|
34828
|
+
".webp": "webp"
|
|
34829
|
+
};
|
|
34830
|
+
}
|
|
34831
|
+
});
|
|
34832
|
+
|
|
34547
34833
|
// src/commands/_shared/scene-build.ts
|
|
34548
34834
|
var scene_build_exports = {};
|
|
34549
34835
|
__export(scene_build_exports, {
|
|
@@ -34552,8 +34838,8 @@ __export(scene_build_exports, {
|
|
|
34552
34838
|
resolveSceneBuildMode: () => resolveSceneBuildMode
|
|
34553
34839
|
});
|
|
34554
34840
|
import { existsSync as existsSync21, readFileSync as readFileSync2 } from "node:fs";
|
|
34555
|
-
import { copyFile as copyFile3, mkdir as
|
|
34556
|
-
import { dirname as
|
|
34841
|
+
import { copyFile as copyFile3, mkdir as mkdir12, readFile as readFile18, rm as rm3, writeFile as writeFile19 } from "node:fs/promises";
|
|
34842
|
+
import { dirname as dirname10, join as join17, resolve as resolve26 } from "node:path";
|
|
34557
34843
|
function readProjectKindSync(projectDir) {
|
|
34558
34844
|
try {
|
|
34559
34845
|
const raw = readFileSync2(join17(projectDir, "vibe.config.json"), "utf-8");
|
|
@@ -35406,7 +35692,7 @@ async function dispatchNarration(beat, ctx) {
|
|
|
35406
35692
|
};
|
|
35407
35693
|
}
|
|
35408
35694
|
if (existsSync21(cacheAbs) && !ctx.force) {
|
|
35409
|
-
await
|
|
35695
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35410
35696
|
await copyFile3(cacheAbs, abs);
|
|
35411
35697
|
await writeAssetMetadata({
|
|
35412
35698
|
projectDir: ctx.projectDir,
|
|
@@ -35437,14 +35723,14 @@ async function dispatchNarration(beat, ctx) {
|
|
|
35437
35723
|
ctx.onProgress({ type: "narration-failed", beatId: beat.id, error });
|
|
35438
35724
|
return { status: "failed", error };
|
|
35439
35725
|
}
|
|
35440
|
-
await
|
|
35441
|
-
await
|
|
35726
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35727
|
+
await writeFile19(abs, result.audioBuffer);
|
|
35442
35728
|
for (const otherExt of ["mp3", "wav"]) {
|
|
35443
35729
|
const sibling = join17(ctx.projectDir, `assets/narration-${beat.id}.${otherExt}`);
|
|
35444
|
-
if (sibling !== abs && existsSync21(sibling)) await
|
|
35730
|
+
if (sibling !== abs && existsSync21(sibling)) await rm3(sibling, { force: true });
|
|
35445
35731
|
}
|
|
35446
|
-
await
|
|
35447
|
-
await
|
|
35732
|
+
await mkdir12(dirname10(cacheAbs), { recursive: true });
|
|
35733
|
+
await writeFile19(cacheAbs, result.audioBuffer);
|
|
35448
35734
|
await writeAssetMetadata({
|
|
35449
35735
|
projectDir: ctx.projectDir,
|
|
35450
35736
|
kind: "narration",
|
|
@@ -35500,8 +35786,8 @@ async function dispatchTranscript(beat, narrationPath, narrationFresh, ctx) {
|
|
|
35500
35786
|
return "skipped";
|
|
35501
35787
|
}
|
|
35502
35788
|
try {
|
|
35503
|
-
await
|
|
35504
|
-
await
|
|
35789
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35790
|
+
await writeFile19(abs, JSON.stringify(words, null, 2), "utf-8");
|
|
35505
35791
|
} catch (err) {
|
|
35506
35792
|
ctx.onProgress({
|
|
35507
35793
|
type: "transcript-skipped",
|
|
@@ -35589,7 +35875,7 @@ async function buildCharacters(characters, ctx) {
|
|
|
35589
35875
|
}
|
|
35590
35876
|
const cacheAbs = join17(ctx.projectDir, cache.path);
|
|
35591
35877
|
if (existsSync21(cacheAbs) && !ctx.force) {
|
|
35592
|
-
await
|
|
35878
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35593
35879
|
await copyFile3(cacheAbs, abs);
|
|
35594
35880
|
await writeAssetMetadata({
|
|
35595
35881
|
projectDir: ctx.projectDir,
|
|
@@ -35622,10 +35908,10 @@ async function buildCharacters(characters, ctx) {
|
|
|
35622
35908
|
ctx.onProgress({ type: "character-failed", name: character.name, error: generated.error });
|
|
35623
35909
|
continue;
|
|
35624
35910
|
}
|
|
35625
|
-
await
|
|
35626
|
-
await
|
|
35627
|
-
await
|
|
35628
|
-
await
|
|
35911
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35912
|
+
await writeImageFile(abs, generated.buffer);
|
|
35913
|
+
await mkdir12(dirname10(cacheAbs), { recursive: true });
|
|
35914
|
+
await writeImageFile(cacheAbs, generated.buffer);
|
|
35629
35915
|
await writeAssetMetadata({
|
|
35630
35916
|
projectDir: ctx.projectDir,
|
|
35631
35917
|
kind: "character",
|
|
@@ -35694,7 +35980,7 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
35694
35980
|
}
|
|
35695
35981
|
const cacheAbs = join17(ctx.projectDir, cache.path);
|
|
35696
35982
|
if (existsSync21(cacheAbs) && !ctx.force) {
|
|
35697
|
-
await
|
|
35983
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35698
35984
|
await copyFile3(cacheAbs, abs);
|
|
35699
35985
|
await writeAssetMetadata({
|
|
35700
35986
|
projectDir: ctx.projectDir,
|
|
@@ -35724,11 +36010,11 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
35724
36010
|
ctx.onProgress({ type: "backdrop-failed", beatId: beat.id, error });
|
|
35725
36011
|
return { status: "failed", error };
|
|
35726
36012
|
}
|
|
35727
|
-
await
|
|
36013
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35728
36014
|
const buffer = generated.buffer;
|
|
35729
|
-
await
|
|
35730
|
-
await
|
|
35731
|
-
await
|
|
36015
|
+
await writeImageFile(abs, buffer);
|
|
36016
|
+
await mkdir12(dirname10(cacheAbs), { recursive: true });
|
|
36017
|
+
await writeImageFile(cacheAbs, buffer);
|
|
35732
36018
|
await writeAssetMetadata({
|
|
35733
36019
|
projectDir: ctx.projectDir,
|
|
35734
36020
|
kind: "backdrop",
|
|
@@ -35772,7 +36058,7 @@ async function generateBackdropImage(prompt3, ctx, ratio) {
|
|
|
35772
36058
|
const result2 = await provider2.generateImage(prompt3, {
|
|
35773
36059
|
// CLI input is free-form; an alias the provider doesn't know fails the
|
|
35774
36060
|
// API call and surfaces as a beat-scoped backdrop/keyframe error.
|
|
35775
|
-
model: ctx.imageModel ??
|
|
36061
|
+
model: ctx.imageModel ?? OPENAI_IMAGE_DEFAULT_MODEL,
|
|
35776
36062
|
size: ctx.imageSize,
|
|
35777
36063
|
quality: ctx.imageQuality
|
|
35778
36064
|
});
|
|
@@ -35857,7 +36143,7 @@ async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
|
35857
36143
|
}
|
|
35858
36144
|
const cacheAbs = join17(ctx.projectDir, cache.path);
|
|
35859
36145
|
if (existsSync21(cacheAbs) && !ctx.force) {
|
|
35860
|
-
await
|
|
36146
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35861
36147
|
await copyFile3(cacheAbs, abs);
|
|
35862
36148
|
await writeAssetMetadata({
|
|
35863
36149
|
projectDir: ctx.projectDir,
|
|
@@ -35887,10 +36173,10 @@ async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
|
35887
36173
|
const identityLock = "Keep the EXACT same person and face as the reference image(s): identical facial features (eyes, nose shape, jawline), skin tone and complexion, hairstyle, hair color, and wardrobe. Do not restyle or change the face. Change only the scene, pose, framing, and lighting. ";
|
|
35888
36174
|
const generated = sheetBuffers.length > 0 ? await editKeyframeImage(`${identityLock}${keyframeCue}`, sheetBuffers, imgCtx, ratio) : await generateBackdropImage(keyframeCue, imgCtx, ratio);
|
|
35889
36175
|
if (!generated.success) return { status: "failed", error: generated.error };
|
|
35890
|
-
await
|
|
35891
|
-
await
|
|
35892
|
-
await
|
|
35893
|
-
await
|
|
36176
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
36177
|
+
await writeImageFile(abs, generated.buffer);
|
|
36178
|
+
await mkdir12(dirname10(cacheAbs), { recursive: true });
|
|
36179
|
+
await writeImageFile(cacheAbs, generated.buffer);
|
|
35894
36180
|
await writeAssetMetadata({
|
|
35895
36181
|
projectDir: ctx.projectDir,
|
|
35896
36182
|
kind: "keyframe",
|
|
@@ -35986,7 +36272,7 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
35986
36272
|
}
|
|
35987
36273
|
const cacheAbs = join17(ctx.projectDir, cache.path);
|
|
35988
36274
|
if (existsSync21(cacheAbs) && !ctx.force) {
|
|
35989
|
-
await
|
|
36275
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35990
36276
|
await copyFile3(cacheAbs, abs);
|
|
35991
36277
|
await writeAssetMetadata({
|
|
35992
36278
|
projectDir: ctx.projectDir,
|
|
@@ -36063,7 +36349,7 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
36063
36349
|
}
|
|
36064
36350
|
}
|
|
36065
36351
|
if (result.status === "completed" && existsSync21(abs)) {
|
|
36066
|
-
await
|
|
36352
|
+
await mkdir12(dirname10(cacheAbs), { recursive: true });
|
|
36067
36353
|
await copyFile3(abs, cacheAbs);
|
|
36068
36354
|
await writeAssetMetadata({
|
|
36069
36355
|
projectDir: ctx.projectDir,
|
|
@@ -36165,7 +36451,7 @@ async function dispatchMusic(beat, ctx) {
|
|
|
36165
36451
|
}
|
|
36166
36452
|
const cacheAbs = join17(ctx.projectDir, cache.path);
|
|
36167
36453
|
if (existsSync21(cacheAbs) && !ctx.force) {
|
|
36168
|
-
await
|
|
36454
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
36169
36455
|
await copyFile3(cacheAbs, abs);
|
|
36170
36456
|
await writeAssetMetadata({
|
|
36171
36457
|
projectDir: ctx.projectDir,
|
|
@@ -36243,7 +36529,7 @@ async function dispatchMusic(beat, ctx) {
|
|
|
36243
36529
|
ctx.onProgress({ type: "music-failed", beatId: beat.id, error });
|
|
36244
36530
|
return { status: "failed", error };
|
|
36245
36531
|
}
|
|
36246
|
-
await
|
|
36532
|
+
await mkdir12(dirname10(cacheAbs), { recursive: true });
|
|
36247
36533
|
await copyFile3(abs, cacheAbs);
|
|
36248
36534
|
await writeAssetMetadata({
|
|
36249
36535
|
projectDir: ctx.projectDir,
|
|
@@ -36277,12 +36563,12 @@ function loadSceneBuildEnv(projectDir) {
|
|
|
36277
36563
|
(0, import_dotenv3.config)({ path: join17(projectDir, ".env"), quiet: true });
|
|
36278
36564
|
(0, import_dotenv3.config)({ path: resolve26(process.cwd(), ".env"), quiet: true });
|
|
36279
36565
|
let dir = process.cwd();
|
|
36280
|
-
while (dir !==
|
|
36566
|
+
while (dir !== dirname10(dir)) {
|
|
36281
36567
|
if (existsSync21(join17(dir, "pnpm-workspace.yaml"))) {
|
|
36282
36568
|
(0, import_dotenv3.config)({ path: join17(dir, ".env"), quiet: true });
|
|
36283
36569
|
return;
|
|
36284
36570
|
}
|
|
36285
|
-
dir =
|
|
36571
|
+
dir = dirname10(dir);
|
|
36286
36572
|
}
|
|
36287
36573
|
}
|
|
36288
36574
|
async function skipped(kind, beatId, reason, ctx) {
|
|
@@ -36507,14 +36793,6 @@ async function safeAudioDuration(absPath) {
|
|
|
36507
36793
|
return void 0;
|
|
36508
36794
|
}
|
|
36509
36795
|
}
|
|
36510
|
-
function resolveBuildVideoProvider(value) {
|
|
36511
|
-
const provider = String(value ?? "seedance").toLowerCase();
|
|
36512
|
-
if (provider === "fal") return "seedance";
|
|
36513
|
-
if (provider === "seedance" || provider === "grok" || provider === "kling" || provider === "runway" || provider === "veo") {
|
|
36514
|
-
return provider;
|
|
36515
|
-
}
|
|
36516
|
-
return "seedance";
|
|
36517
|
-
}
|
|
36518
36796
|
function resolveBuildMusicProvider(value) {
|
|
36519
36797
|
const provider = String(value ?? "elevenlabs").toLowerCase();
|
|
36520
36798
|
return provider === "replicate" ? "replicate" : "elevenlabs";
|
|
@@ -36526,8 +36804,7 @@ function stringOrUndefined4(value) {
|
|
|
36526
36804
|
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
36527
36805
|
}
|
|
36528
36806
|
async function apiKeyForVideoProvider(provider, projectDir) {
|
|
36529
|
-
|
|
36530
|
-
return getApiKeyFromConfig(providerKey, { cwd: projectDir });
|
|
36807
|
+
return getApiKeyFromConfig(videoProviderConfigKey(provider), { cwd: projectDir });
|
|
36531
36808
|
}
|
|
36532
36809
|
async function finalizeBuildResult(projectDir, startedAt, result, reportResult = result) {
|
|
36533
36810
|
const reportPath = join17(projectDir, "build-report.json");
|
|
@@ -36550,7 +36827,7 @@ async function finalizeBuildResult(projectDir, startedAt, result, reportResult =
|
|
|
36550
36827
|
const withMeta = decorate(result);
|
|
36551
36828
|
const reportMeta = reportResult === result ? withMeta : decorate(reportResult);
|
|
36552
36829
|
try {
|
|
36553
|
-
await
|
|
36830
|
+
await writeFile19(
|
|
36554
36831
|
reportPath,
|
|
36555
36832
|
JSON.stringify(toBuildReport(projectDir, reportMeta), null, 2) + "\n",
|
|
36556
36833
|
"utf-8"
|
|
@@ -36803,6 +37080,8 @@ var init_scene_build = __esm({
|
|
|
36803
37080
|
init_scene_repair();
|
|
36804
37081
|
init_tts_resolve();
|
|
36805
37082
|
init_scene_build_mode();
|
|
37083
|
+
init_image_file();
|
|
37084
|
+
init_build_video_providers();
|
|
36806
37085
|
init_scene_build_mode();
|
|
36807
37086
|
BEAT_PRIMITIVES_CONCURRENCY = 4;
|
|
36808
37087
|
}
|
|
@@ -36915,8 +37194,8 @@ __export(ai_audio_exports, {
|
|
|
36915
37194
|
executeTranscribe: () => executeTranscribe,
|
|
36916
37195
|
executeVoiceClone: () => executeVoiceClone
|
|
36917
37196
|
});
|
|
36918
|
-
import { resolve as resolve28, dirname as
|
|
36919
|
-
import { readFile as readFile19, writeFile as
|
|
37197
|
+
import { resolve as resolve28, dirname as dirname11, basename as basename5, extname as extname5 } from "node:path";
|
|
37198
|
+
import { readFile as readFile19, writeFile as writeFile20 } from "node:fs/promises";
|
|
36920
37199
|
import { existsSync as existsSync22 } from "node:fs";
|
|
36921
37200
|
async function executeTranscribe(options) {
|
|
36922
37201
|
const { audioPath, language, output, format, apiKey } = options;
|
|
@@ -36938,7 +37217,7 @@ async function executeTranscribe(options) {
|
|
|
36938
37217
|
outputPath = resolve28(process.cwd(), output);
|
|
36939
37218
|
const fmt = detectFormat(output, format);
|
|
36940
37219
|
const content = formatTranscript(result, fmt);
|
|
36941
|
-
await
|
|
37220
|
+
await writeFile20(outputPath, content, "utf-8");
|
|
36942
37221
|
}
|
|
36943
37222
|
return {
|
|
36944
37223
|
success: true,
|
|
@@ -36966,7 +37245,7 @@ async function executeIsolate(options) {
|
|
|
36966
37245
|
return { success: false, error: result.error || "Audio isolation failed" };
|
|
36967
37246
|
}
|
|
36968
37247
|
const outputPath = resolve28(process.cwd(), output);
|
|
36969
|
-
await
|
|
37248
|
+
await writeFile20(outputPath, result.audioBuffer);
|
|
36970
37249
|
return { success: true, outputPath };
|
|
36971
37250
|
} catch (error) {
|
|
36972
37251
|
return { success: false, error: `Audio isolation failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
@@ -37012,11 +37291,11 @@ async function executeDub(options) {
|
|
|
37012
37291
|
if (!openaiKey) return { success: false, error: "OPENAI_API_KEY required for Whisper transcription" };
|
|
37013
37292
|
if (!anthropicKey) return { success: false, error: "ANTHROPIC_API_KEY required for Claude translation" };
|
|
37014
37293
|
if (!analyzeOnly && !elevenlabsKey) return { success: false, error: "ELEVENLABS_API_KEY required for TTS" };
|
|
37015
|
-
const ext =
|
|
37294
|
+
const ext = extname5(absPath).toLowerCase();
|
|
37016
37295
|
const isVideo = [".mp4", ".mov", ".avi", ".mkv", ".webm"].includes(ext);
|
|
37017
37296
|
let audioPath = absPath;
|
|
37018
37297
|
if (isVideo) {
|
|
37019
|
-
const tempAudioPath = resolve28(
|
|
37298
|
+
const tempAudioPath = resolve28(dirname11(absPath), `temp-audio-${Date.now()}.mp3`);
|
|
37020
37299
|
execSafeSync("ffmpeg", ["-i", absPath, "-vn", "-acodec", "mp3", "-y", tempAudioPath]);
|
|
37021
37300
|
audioPath = tempAudioPath;
|
|
37022
37301
|
}
|
|
@@ -37077,7 +37356,7 @@ ${segmentTexts}`,
|
|
|
37077
37356
|
translated: translatedSegments[i]?.text || s.text
|
|
37078
37357
|
}))
|
|
37079
37358
|
};
|
|
37080
|
-
await
|
|
37359
|
+
await writeFile20(timingPath, JSON.stringify(timingData, null, 2));
|
|
37081
37360
|
}
|
|
37082
37361
|
return {
|
|
37083
37362
|
success: true,
|
|
@@ -37097,10 +37376,10 @@ ${segmentTexts}`,
|
|
|
37097
37376
|
}
|
|
37098
37377
|
}
|
|
37099
37378
|
const combinedBuffer = Buffer.concat(dubbedBuffers);
|
|
37100
|
-
const outputExt = isVideo ? ".mp3" :
|
|
37101
|
-
const defaultOutputPath2 = resolve28(
|
|
37379
|
+
const outputExt = isVideo ? ".mp3" : extname5(absPath);
|
|
37380
|
+
const defaultOutputPath2 = resolve28(dirname11(absPath), `${basename5(absPath, extname5(absPath))}-${language}${outputExt}`);
|
|
37102
37381
|
const finalOutputPath = resolve28(process.cwd(), output || defaultOutputPath2);
|
|
37103
|
-
await
|
|
37382
|
+
await writeFile20(finalOutputPath, combinedBuffer);
|
|
37104
37383
|
if (isVideo && audioPath !== absPath) {
|
|
37105
37384
|
try {
|
|
37106
37385
|
const { unlink: unlink3 } = await import("node:fs/promises");
|
|
@@ -37135,7 +37414,7 @@ async function executeDuck(options) {
|
|
|
37135
37414
|
const absVoicePath = resolve28(process.cwd(), voicePath);
|
|
37136
37415
|
if (!existsSync22(absMusicPath)) return { success: false, error: `Music file not found: ${absMusicPath}` };
|
|
37137
37416
|
if (!existsSync22(absVoicePath)) return { success: false, error: `Voice file not found: ${absVoicePath}` };
|
|
37138
|
-
const defaultOutput = resolve28(
|
|
37417
|
+
const defaultOutput = resolve28(dirname11(absMusicPath), `${basename5(absMusicPath, extname5(absMusicPath))}-ducked${extname5(absMusicPath)}`);
|
|
37139
37418
|
const outputPath = resolve28(process.cwd(), output || defaultOutput);
|
|
37140
37419
|
const filter = `[1:a]asplit=2[sc][mix];[0:a][sc]sidechaincompress=threshold=${threshold}dB:ratio=${ratio}:attack=${attack}:release=${release}[ducked];[ducked][mix]amix=inputs=2:duration=longest`;
|
|
37141
37420
|
await execSafe("ffmpeg", [
|
|
@@ -37400,7 +37679,7 @@ var init_silence_cut = __esm({
|
|
|
37400
37679
|
|
|
37401
37680
|
// src/commands/_shared/edit/jump-cut.ts
|
|
37402
37681
|
import { existsSync as existsSync24 } from "node:fs";
|
|
37403
|
-
import { readFile as readFile21, writeFile as
|
|
37682
|
+
import { readFile as readFile21, writeFile as writeFile21, mkdir as mkdir13 } from "node:fs/promises";
|
|
37404
37683
|
import { join as join18 } from "node:path";
|
|
37405
37684
|
async function transcribeWithWords(audioPath, apiKey, language) {
|
|
37406
37685
|
const audioBuffer = await readFile21(audioPath);
|
|
@@ -37480,7 +37759,7 @@ async function executeJumpCut(options) {
|
|
|
37480
37759
|
}
|
|
37481
37760
|
try {
|
|
37482
37761
|
const tmpDir = `/tmp/vibe_jumpcut_${Date.now()}`;
|
|
37483
|
-
await
|
|
37762
|
+
await mkdir13(tmpDir, { recursive: true });
|
|
37484
37763
|
const audioPath = join18(tmpDir, "audio.wav");
|
|
37485
37764
|
try {
|
|
37486
37765
|
await execSafe(
|
|
@@ -37559,7 +37838,7 @@ async function executeJumpCut(options) {
|
|
|
37559
37838
|
}
|
|
37560
37839
|
const concatList = segmentPaths.map((p) => `file '${p}'`).join("\n");
|
|
37561
37840
|
const listPath = join18(tmpDir, "concat.txt");
|
|
37562
|
-
await
|
|
37841
|
+
await writeFile21(listPath, concatList);
|
|
37563
37842
|
await execSafe(
|
|
37564
37843
|
"ffmpeg",
|
|
37565
37844
|
[
|
|
@@ -37586,8 +37865,8 @@ async function executeJumpCut(options) {
|
|
|
37586
37865
|
};
|
|
37587
37866
|
} finally {
|
|
37588
37867
|
try {
|
|
37589
|
-
const { rm:
|
|
37590
|
-
await
|
|
37868
|
+
const { rm: rm7 } = await import("node:fs/promises");
|
|
37869
|
+
await rm7(tmpDir, { recursive: true, force: true });
|
|
37591
37870
|
} catch {
|
|
37592
37871
|
}
|
|
37593
37872
|
}
|
|
@@ -37664,29 +37943,27 @@ __export(remotion_exports, {
|
|
|
37664
37943
|
wrapComponentWithImage: () => wrapComponentWithImage,
|
|
37665
37944
|
wrapComponentWithVideo: () => wrapComponentWithVideo
|
|
37666
37945
|
});
|
|
37667
|
-
import { writeFile as
|
|
37946
|
+
import { writeFile as writeFile22, mkdir as mkdir14, rm as rm4, copyFile as copyFile4 } from "node:fs/promises";
|
|
37668
37947
|
import { existsSync as existsSync25 } from "node:fs";
|
|
37669
37948
|
import { join as join19 } from "node:path";
|
|
37670
37949
|
import { tmpdir } from "node:os";
|
|
37671
37950
|
import { createHash as createHash4 } from "node:crypto";
|
|
37672
37951
|
async function ensureRemotionInstalled() {
|
|
37673
37952
|
try {
|
|
37674
|
-
await execSafe("
|
|
37953
|
+
await execSafe("npm", ["--version"], { timeout: 3e4 });
|
|
37675
37954
|
return null;
|
|
37676
37955
|
} catch (error) {
|
|
37677
37956
|
const detail = error instanceof Error ? error.message : String(error);
|
|
37678
|
-
console.error(`[Remotion] ensureRemotionInstalled failed: ${detail.slice(0, 300)}`);
|
|
37679
37957
|
return [
|
|
37680
|
-
"Remotion
|
|
37958
|
+
"Remotion renders need npm to install the Remotion CLI into a temporary project.",
|
|
37681
37959
|
` Debug: ${detail.slice(0, 200)}`,
|
|
37682
|
-
" Fix: npm
|
|
37683
|
-
" Or ensure npx is available and can download @remotion/cli on demand."
|
|
37960
|
+
" Fix: install Node.js 20+ (which includes npm) and make sure `npm` is on PATH."
|
|
37684
37961
|
].join("\n");
|
|
37685
37962
|
}
|
|
37686
37963
|
}
|
|
37687
37964
|
async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
37688
37965
|
const dir = join19(tmpdir(), `vibe_motion_${Date.now()}`);
|
|
37689
|
-
await
|
|
37966
|
+
await mkdir14(dir, { recursive: true });
|
|
37690
37967
|
const deps = {
|
|
37691
37968
|
remotion: REMOTION_VERSION,
|
|
37692
37969
|
"@remotion/cli": REMOTION_VERSION,
|
|
@@ -37704,7 +37981,7 @@ async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
|
37704
37981
|
dependencies: deps
|
|
37705
37982
|
};
|
|
37706
37983
|
const packageJsonStr = JSON.stringify(packageJson, null, 2);
|
|
37707
|
-
await
|
|
37984
|
+
await writeFile22(join19(dir, "package.json"), packageJsonStr);
|
|
37708
37985
|
const tsconfig = {
|
|
37709
37986
|
compilerOptions: {
|
|
37710
37987
|
target: "ES2020",
|
|
@@ -37716,8 +37993,8 @@ async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
|
37716
37993
|
skipLibCheck: true
|
|
37717
37994
|
}
|
|
37718
37995
|
};
|
|
37719
|
-
await
|
|
37720
|
-
await
|
|
37996
|
+
await writeFile22(join19(dir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2));
|
|
37997
|
+
await writeFile22(join19(dir, "Component.tsx"), componentCode);
|
|
37721
37998
|
const rootCode = `import { registerRoot, Composition } from "remotion";
|
|
37722
37999
|
import { ${componentName} } from "./Component";
|
|
37723
38000
|
|
|
@@ -37736,7 +38013,7 @@ const Root = () => {
|
|
|
37736
38013
|
|
|
37737
38014
|
registerRoot(Root);
|
|
37738
38015
|
`;
|
|
37739
|
-
await
|
|
38016
|
+
await writeFile22(join19(dir, "Root.tsx"), rootCode);
|
|
37740
38017
|
const depsHash = createHash4("md5").update(packageJsonStr).digest("hex").slice(0, 12);
|
|
37741
38018
|
const cacheMarker = join19(REMOTION_CACHE_DIR, `.deps-${depsHash}`);
|
|
37742
38019
|
const cachedModules = join19(REMOTION_CACHE_DIR, "node_modules");
|
|
@@ -37750,15 +38027,15 @@ registerRoot(Root);
|
|
|
37750
38027
|
} else {
|
|
37751
38028
|
await this_npmInstall(dir);
|
|
37752
38029
|
try {
|
|
37753
|
-
await
|
|
37754
|
-
await
|
|
38030
|
+
await mkdir14(REMOTION_CACHE_DIR, { recursive: true });
|
|
38031
|
+
await writeFile22(join19(REMOTION_CACHE_DIR, "package.json"), packageJsonStr);
|
|
37755
38032
|
if (existsSync25(join19(dir, "node_modules"))) {
|
|
37756
38033
|
const { rename: rename5, symlink } = await import("node:fs/promises");
|
|
37757
38034
|
await rename5(join19(dir, "node_modules"), cachedModules).catch(() => {
|
|
37758
38035
|
});
|
|
37759
38036
|
await symlink(cachedModules, join19(dir, "node_modules"), "dir").catch(() => {
|
|
37760
38037
|
});
|
|
37761
|
-
await
|
|
38038
|
+
await writeFile22(cacheMarker, depsHash);
|
|
37762
38039
|
}
|
|
37763
38040
|
} catch {
|
|
37764
38041
|
}
|
|
@@ -37858,7 +38135,7 @@ async function renderMotion(options) {
|
|
|
37858
38135
|
stderr: ${stderr}` : ""}`);
|
|
37859
38136
|
return { success: false, error: `Remotion render failed: ${msg}` };
|
|
37860
38137
|
} finally {
|
|
37861
|
-
await
|
|
38138
|
+
await rm4(dir, { recursive: true, force: true }).catch(() => {
|
|
37862
38139
|
});
|
|
37863
38140
|
}
|
|
37864
38141
|
}
|
|
@@ -37927,7 +38204,7 @@ async function renderWithEmbeddedImage(options) {
|
|
|
37927
38204
|
);
|
|
37928
38205
|
try {
|
|
37929
38206
|
const publicDir = join19(dir, "public");
|
|
37930
|
-
await
|
|
38207
|
+
await mkdir14(publicDir, { recursive: true });
|
|
37931
38208
|
await copyFile4(options.imagePath, join19(publicDir, options.imageFileName));
|
|
37932
38209
|
const entryPoint = join19(dir, "Root.tsx");
|
|
37933
38210
|
const mp4Out = options.outputPath.replace(/\.\w+$/, ".mp4");
|
|
@@ -37950,7 +38227,7 @@ async function renderWithEmbeddedImage(options) {
|
|
|
37950
38227
|
const msg = error instanceof Error ? error.message : String(error);
|
|
37951
38228
|
return { success: false, error: `Remotion image embed render failed: ${msg}` };
|
|
37952
38229
|
} finally {
|
|
37953
|
-
await
|
|
38230
|
+
await rm4(dir, { recursive: true, force: true }).catch(() => {
|
|
37954
38231
|
});
|
|
37955
38232
|
}
|
|
37956
38233
|
}
|
|
@@ -37991,7 +38268,7 @@ async function renderWithEmbeddedVideo(options) {
|
|
|
37991
38268
|
);
|
|
37992
38269
|
try {
|
|
37993
38270
|
const publicDir = join19(dir, "public");
|
|
37994
|
-
await
|
|
38271
|
+
await mkdir14(publicDir, { recursive: true });
|
|
37995
38272
|
await copyFile4(options.videoPath, join19(publicDir, options.videoFileName));
|
|
37996
38273
|
const entryPoint = join19(dir, "Root.tsx");
|
|
37997
38274
|
const mp4VideoOnly = options.outputPath.replace(/\.\w+$/, "_video_only.mp4");
|
|
@@ -38027,14 +38304,14 @@ async function renderWithEmbeddedVideo(options) {
|
|
|
38027
38304
|
"-shortest",
|
|
38028
38305
|
mp4Out
|
|
38029
38306
|
], { timeout: 12e4 });
|
|
38030
|
-
await
|
|
38307
|
+
await rm4(mp4VideoOnly, { force: true }).catch(() => {
|
|
38031
38308
|
});
|
|
38032
38309
|
return { success: true, outputPath: mp4Out };
|
|
38033
38310
|
} catch (error) {
|
|
38034
38311
|
const msg = error instanceof Error ? error.message : String(error);
|
|
38035
38312
|
return { success: false, error: `Remotion video embed render failed: ${msg}` };
|
|
38036
38313
|
} finally {
|
|
38037
|
-
await
|
|
38314
|
+
await rm4(dir, { recursive: true, force: true }).catch(() => {
|
|
38038
38315
|
});
|
|
38039
38316
|
}
|
|
38040
38317
|
}
|
|
@@ -38415,8 +38692,8 @@ var init_remotion = __esm({
|
|
|
38415
38692
|
|
|
38416
38693
|
// src/commands/_shared/edit/caption.ts
|
|
38417
38694
|
import { existsSync as existsSync26 } from "node:fs";
|
|
38418
|
-
import { readFile as readFile22, writeFile as
|
|
38419
|
-
import { dirname as
|
|
38695
|
+
import { readFile as readFile22, writeFile as writeFile23, mkdir as mkdir15 } from "node:fs/promises";
|
|
38696
|
+
import { dirname as dirname12, basename as basename6, extname as extname6, join as join20 } from "node:path";
|
|
38420
38697
|
function getCaptionForceStyle(style, fontSize, fontColor, position) {
|
|
38421
38698
|
const alignment = position === "top" ? 8 : position === "center" ? 5 : 2;
|
|
38422
38699
|
const marginV = position === "center" ? 0 : 30;
|
|
@@ -38462,7 +38739,7 @@ async function executeCaption(options) {
|
|
|
38462
38739
|
}
|
|
38463
38740
|
try {
|
|
38464
38741
|
const tmpDir = `/tmp/vibe_caption_${Date.now()}`;
|
|
38465
|
-
await
|
|
38742
|
+
await mkdir15(tmpDir, { recursive: true });
|
|
38466
38743
|
const audioPath = join20(tmpDir, "audio.wav");
|
|
38467
38744
|
const srtPath = join20(tmpDir, "captions.srt");
|
|
38468
38745
|
try {
|
|
@@ -38495,7 +38772,7 @@ async function executeCaption(options) {
|
|
|
38495
38772
|
};
|
|
38496
38773
|
}
|
|
38497
38774
|
const srtContent = formatSRT(transcriptResult.segments);
|
|
38498
|
-
await
|
|
38775
|
+
await writeFile23(srtPath, srtContent);
|
|
38499
38776
|
const { width, height } = await getVideoResolution(videoPath);
|
|
38500
38777
|
const fontSize = customFontSize || Math.round(height / 18);
|
|
38501
38778
|
let hasSubtitles = false;
|
|
@@ -38532,12 +38809,12 @@ async function executeCaption(options) {
|
|
|
38532
38809
|
} = await Promise.resolve().then(() => (init_remotion(), remotion_exports));
|
|
38533
38810
|
const remotionErr = await ensureRemotionInstalled2();
|
|
38534
38811
|
if (remotionErr) {
|
|
38535
|
-
const outputDir2 =
|
|
38812
|
+
const outputDir2 = dirname12(outputPath);
|
|
38536
38813
|
const outputSrtPath2 = join20(
|
|
38537
38814
|
outputDir2,
|
|
38538
|
-
basename6(outputPath,
|
|
38815
|
+
basename6(outputPath, extname6(outputPath)) + ".srt"
|
|
38539
38816
|
);
|
|
38540
|
-
await
|
|
38817
|
+
await writeFile23(outputSrtPath2, srtContent);
|
|
38541
38818
|
return { success: false, error: `${remotionErr}
|
|
38542
38819
|
SRT saved to: ${outputSrtPath2}` };
|
|
38543
38820
|
}
|
|
@@ -38571,12 +38848,12 @@ SRT saved to: ${outputSrtPath2}` };
|
|
|
38571
38848
|
outputPath
|
|
38572
38849
|
});
|
|
38573
38850
|
if (!renderResult.success) {
|
|
38574
|
-
const outputDir2 =
|
|
38851
|
+
const outputDir2 = dirname12(outputPath);
|
|
38575
38852
|
const outputSrtPath2 = join20(
|
|
38576
38853
|
outputDir2,
|
|
38577
|
-
basename6(outputPath,
|
|
38854
|
+
basename6(outputPath, extname6(outputPath)) + ".srt"
|
|
38578
38855
|
);
|
|
38579
|
-
await
|
|
38856
|
+
await writeFile23(outputSrtPath2, srtContent);
|
|
38580
38857
|
return {
|
|
38581
38858
|
success: false,
|
|
38582
38859
|
error: `${renderResult.error}
|
|
@@ -38584,12 +38861,12 @@ SRT saved to: ${outputSrtPath2}`
|
|
|
38584
38861
|
};
|
|
38585
38862
|
}
|
|
38586
38863
|
}
|
|
38587
|
-
const outputDir =
|
|
38864
|
+
const outputDir = dirname12(outputPath);
|
|
38588
38865
|
const outputSrtPath = join20(
|
|
38589
38866
|
outputDir,
|
|
38590
|
-
basename6(outputPath,
|
|
38867
|
+
basename6(outputPath, extname6(outputPath)) + ".srt"
|
|
38591
38868
|
);
|
|
38592
|
-
await
|
|
38869
|
+
await writeFile23(outputSrtPath, srtContent);
|
|
38593
38870
|
return {
|
|
38594
38871
|
success: true,
|
|
38595
38872
|
outputPath,
|
|
@@ -38598,8 +38875,8 @@ SRT saved to: ${outputSrtPath2}`
|
|
|
38598
38875
|
};
|
|
38599
38876
|
} finally {
|
|
38600
38877
|
try {
|
|
38601
|
-
const { rm:
|
|
38602
|
-
await
|
|
38878
|
+
const { rm: rm7 } = await import("node:fs/promises");
|
|
38879
|
+
await rm7(tmpDir, { recursive: true, force: true });
|
|
38603
38880
|
} catch {
|
|
38604
38881
|
}
|
|
38605
38882
|
}
|
|
@@ -38760,7 +39037,7 @@ var init_fade = __esm({
|
|
|
38760
39037
|
|
|
38761
39038
|
// src/commands/_shared/edit/translate-srt.ts
|
|
38762
39039
|
import { existsSync as existsSync29 } from "node:fs";
|
|
38763
|
-
import { readFile as readFile23, writeFile as
|
|
39040
|
+
import { readFile as readFile23, writeFile as writeFile24 } from "node:fs/promises";
|
|
38764
39041
|
async function executeTranslateSrt(options) {
|
|
38765
39042
|
const {
|
|
38766
39043
|
srtPath,
|
|
@@ -38803,15 +39080,14 @@ ${textsToTranslate}`;
|
|
|
38803
39080
|
Authorization: `Bearer ${openaiKey}`
|
|
38804
39081
|
},
|
|
38805
39082
|
body: JSON.stringify({
|
|
38806
|
-
model: "
|
|
38807
|
-
messages: [{ role: "user", content: translatePrompt }]
|
|
38808
|
-
temperature: 0.3
|
|
39083
|
+
model: defaultModel("openai", "llm").id,
|
|
39084
|
+
messages: [{ role: "user", content: translatePrompt }]
|
|
38809
39085
|
})
|
|
38810
39086
|
});
|
|
38811
39087
|
if (!response.ok) {
|
|
38812
39088
|
return {
|
|
38813
39089
|
success: false,
|
|
38814
|
-
error: `OpenAI API error: ${response.status} ${response.statusText}`
|
|
39090
|
+
error: `OpenAI API error: ${response.status} ${response.statusText}: ${await response.text()}`
|
|
38815
39091
|
};
|
|
38816
39092
|
}
|
|
38817
39093
|
const data = await response.json();
|
|
@@ -38832,15 +39108,15 @@ ${textsToTranslate}`;
|
|
|
38832
39108
|
"anthropic-version": "2023-06-01"
|
|
38833
39109
|
},
|
|
38834
39110
|
body: JSON.stringify({
|
|
38835
|
-
model: "claude
|
|
38836
|
-
max_tokens:
|
|
39111
|
+
model: defaultModel("claude", "llm").id,
|
|
39112
|
+
max_tokens: 16e3,
|
|
38837
39113
|
messages: [{ role: "user", content: translatePrompt }]
|
|
38838
39114
|
})
|
|
38839
39115
|
});
|
|
38840
39116
|
if (!response.ok) {
|
|
38841
39117
|
return {
|
|
38842
39118
|
success: false,
|
|
38843
|
-
error: `Claude API error: ${response.status} ${response.statusText}`
|
|
39119
|
+
error: `Claude API error: ${response.status} ${response.statusText}: ${await response.text()}`
|
|
38844
39120
|
};
|
|
38845
39121
|
}
|
|
38846
39122
|
const data = await response.json();
|
|
@@ -38864,7 +39140,7 @@ ${textsToTranslate}`;
|
|
|
38864
39140
|
}
|
|
38865
39141
|
}
|
|
38866
39142
|
const translatedSrt = formatSRT(translatedSegments);
|
|
38867
|
-
await
|
|
39143
|
+
await writeFile24(outputPath, translatedSrt);
|
|
38868
39144
|
return {
|
|
38869
39145
|
success: true,
|
|
38870
39146
|
outputPath,
|
|
@@ -38883,6 +39159,7 @@ var init_translate_srt = __esm({
|
|
|
38883
39159
|
"src/commands/_shared/edit/translate-srt.ts"() {
|
|
38884
39160
|
"use strict";
|
|
38885
39161
|
init_subtitle();
|
|
39162
|
+
init_dist2();
|
|
38886
39163
|
}
|
|
38887
39164
|
});
|
|
38888
39165
|
|
|
@@ -39116,7 +39393,7 @@ var init_ai_edit = __esm({
|
|
|
39116
39393
|
});
|
|
39117
39394
|
|
|
39118
39395
|
// src/commands/ai-edit-cli.ts
|
|
39119
|
-
import { resolve as resolve30, extname as
|
|
39396
|
+
import { resolve as resolve30, extname as extname7, basename as basename7 } from "node:path";
|
|
39120
39397
|
import { existsSync as existsSync31 } from "node:fs";
|
|
39121
39398
|
function registerEditCommands(aiCommand) {
|
|
39122
39399
|
aiCommand.command("silence-cut").alias("sc").description("Remove silent segments from video (FFmpeg default, or Gemini for smart detection)").argument("<video>", "Video file path").option("-o, --output <path>", "Output file path (default: <name>-cut.<ext>)").option("--noise <dB>", "Silence threshold in dB (default: -30)", "-30").option("-d, --min-duration <seconds>", "Minimum silence duration to cut (default: 0.5)", "0.5").option("--padding <seconds>", "Padding around non-silent segments (default: 0.1)", "0.1").option("--analyze-only", "(deprecated - use `vibe detect silence`) Only detect silence, don't cut").option("--use-gemini", "Use Gemini Video Understanding for context-aware silence detection").option("-m, --model <model>", "Gemini model (default: flash)").option("--low-res", "Low resolution mode for longer videos (Gemini only)").option("-k, --api-key <key>", "Google API key override (or set GOOGLE_API_KEY env)").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
|
|
@@ -39140,7 +39417,7 @@ No API key needed (FFmpeg only). Use --use-gemini for smart detection (requires
|
|
|
39140
39417
|
if (!commandExists("ffmpeg")) {
|
|
39141
39418
|
exitWithError(generalError("FFmpeg not found. Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux). Run `vibe doctor` for details."));
|
|
39142
39419
|
}
|
|
39143
|
-
const ext =
|
|
39420
|
+
const ext = extname7(videoPath);
|
|
39144
39421
|
const name = basename7(videoPath, ext);
|
|
39145
39422
|
const outputPath = options.output || `${name}-cut${ext}`;
|
|
39146
39423
|
const useGemini = options.useGemini || false;
|
|
@@ -39270,7 +39547,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
39270
39547
|
if (!apiKey) {
|
|
39271
39548
|
exitWithError(authError("OPENAI_API_KEY", "OpenAI"));
|
|
39272
39549
|
}
|
|
39273
|
-
const ext =
|
|
39550
|
+
const ext = extname7(videoPath);
|
|
39274
39551
|
const name = basename7(videoPath, ext);
|
|
39275
39552
|
const outputPath = options.output || `${name}-captioned${ext}`;
|
|
39276
39553
|
const spinner2 = ora("Starting caption process...").start();
|
|
@@ -39344,7 +39621,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
39344
39621
|
});
|
|
39345
39622
|
return;
|
|
39346
39623
|
}
|
|
39347
|
-
const ext =
|
|
39624
|
+
const ext = extname7(inputPath);
|
|
39348
39625
|
const name = basename7(inputPath, ext);
|
|
39349
39626
|
const outputPath = options.output || `${name}-denoised${ext}`;
|
|
39350
39627
|
const spinner2 = ora("Applying noise reduction...").start();
|
|
@@ -39412,7 +39689,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
39412
39689
|
});
|
|
39413
39690
|
return;
|
|
39414
39691
|
}
|
|
39415
|
-
const ext =
|
|
39692
|
+
const ext = extname7(videoPath);
|
|
39416
39693
|
const name = basename7(videoPath, ext);
|
|
39417
39694
|
const outputPath = options.output || `${name}-faded${ext}`;
|
|
39418
39695
|
const spinner2 = ora("Applying fade effects...").start();
|
|
@@ -39490,7 +39767,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
39490
39767
|
if (!apiKey) {
|
|
39491
39768
|
exitWithError(authError(envKey, providerName));
|
|
39492
39769
|
}
|
|
39493
|
-
const ext =
|
|
39770
|
+
const ext = extname7(srtPath);
|
|
39494
39771
|
const name = basename7(srtPath, ext);
|
|
39495
39772
|
const outputPath = options.output || `${name}-${options.target}${ext}`;
|
|
39496
39773
|
const spinner2 = ora(`Translating to ${options.target}...`).start();
|
|
@@ -39568,7 +39845,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
39568
39845
|
if (!apiKey) {
|
|
39569
39846
|
exitWithError(authError("OPENAI_API_KEY", "OpenAI"));
|
|
39570
39847
|
}
|
|
39571
|
-
const ext =
|
|
39848
|
+
const ext = extname7(videoPath);
|
|
39572
39849
|
const name = basename7(videoPath, ext);
|
|
39573
39850
|
const outputPath = options.output || `${name}-jumpcut${ext}`;
|
|
39574
39851
|
const fillers = options.fillers ? options.fillers.split(",").map((f) => f.trim()) : void 0;
|
|
@@ -40029,8 +40306,8 @@ var init_project_resolver = __esm({
|
|
|
40029
40306
|
|
|
40030
40307
|
// src/commands/_shared/execute-fill-gaps.ts
|
|
40031
40308
|
import { existsSync as existsSync32 } from "node:fs";
|
|
40032
|
-
import { readFile as readFile24, writeFile as
|
|
40033
|
-
import { resolve as resolve32, dirname as
|
|
40309
|
+
import { readFile as readFile24, writeFile as writeFile25, mkdir as mkdir16, rename as renameFs } from "node:fs/promises";
|
|
40310
|
+
import { resolve as resolve32, dirname as dirname13 } from "node:path";
|
|
40034
40311
|
function detectVideoGaps(videoClips, totalDuration) {
|
|
40035
40312
|
const gaps = [];
|
|
40036
40313
|
const sortedClips = [...videoClips].sort((a, b) => a.startTime - b.startTime);
|
|
@@ -40084,22 +40361,13 @@ function analyzeGapFillability(gaps, videoClips, sources) {
|
|
|
40084
40361
|
return { gap, canExtendBefore, canExtendAfter, remainingGap, gapStart };
|
|
40085
40362
|
});
|
|
40086
40363
|
}
|
|
40087
|
-
async function
|
|
40364
|
+
async function uploadFrame(host, framePath) {
|
|
40088
40365
|
try {
|
|
40089
|
-
const
|
|
40090
|
-
|
|
40091
|
-
|
|
40092
|
-
formData.append("key", imgbbApiKey);
|
|
40093
|
-
formData.append("image", frameBase64);
|
|
40094
|
-
const response = await fetch("https://api.imgbb.com/1/upload", {
|
|
40095
|
-
method: "POST",
|
|
40096
|
-
body: formData
|
|
40366
|
+
const upload = await host.uploadImage(await readFile24(framePath), {
|
|
40367
|
+
filename: framePath,
|
|
40368
|
+
mimeType: "image/png"
|
|
40097
40369
|
});
|
|
40098
|
-
|
|
40099
|
-
if (!data.success || !data.data?.url) {
|
|
40100
|
-
return { error: data.error?.message || "Upload failed" };
|
|
40101
|
-
}
|
|
40102
|
-
return { url: data.data.url };
|
|
40370
|
+
return { url: upload.url };
|
|
40103
40371
|
} catch (err) {
|
|
40104
40372
|
return { error: err instanceof Error ? err.message : String(err) };
|
|
40105
40373
|
}
|
|
@@ -40240,21 +40508,23 @@ async function executeFillGaps(options) {
|
|
|
40240
40508
|
if (!kling.isConfigured()) {
|
|
40241
40509
|
return {
|
|
40242
40510
|
success: false,
|
|
40243
|
-
error: "Invalid KLING_API_KEY (
|
|
40511
|
+
error: "Invalid KLING_API_KEY (set your Kling API key, or the legacy ACCESS_KEY:SECRET_KEY pair)",
|
|
40244
40512
|
humanLines
|
|
40245
40513
|
};
|
|
40246
40514
|
}
|
|
40247
|
-
const projectDir =
|
|
40515
|
+
const projectDir = dirname13(filePath);
|
|
40248
40516
|
const footageDir = options.dir ? resolve32(process.cwd(), options.dir) : resolve32(projectDir, "footage");
|
|
40249
40517
|
if (!existsSync32(footageDir)) {
|
|
40250
|
-
await
|
|
40518
|
+
await mkdir16(footageDir, { recursive: true });
|
|
40251
40519
|
}
|
|
40252
40520
|
humanLines.push("Generating AI Videos");
|
|
40253
|
-
|
|
40254
|
-
|
|
40521
|
+
let uploadHost;
|
|
40522
|
+
try {
|
|
40523
|
+
uploadHost = await resolveUploadHost();
|
|
40524
|
+
} catch (err) {
|
|
40255
40525
|
return {
|
|
40256
40526
|
success: false,
|
|
40257
|
-
error:
|
|
40527
|
+
error: err instanceof Error ? err.message : String(err),
|
|
40258
40528
|
humanLines
|
|
40259
40529
|
};
|
|
40260
40530
|
}
|
|
@@ -40298,12 +40568,12 @@ async function executeFillGaps(options) {
|
|
|
40298
40568
|
humanLines
|
|
40299
40569
|
};
|
|
40300
40570
|
}
|
|
40301
|
-
onProgress(
|
|
40302
|
-
const upload = await
|
|
40571
|
+
onProgress(`Uploading frame via ${uploadHost.provider}...`);
|
|
40572
|
+
const upload = await uploadFrame(uploadHost, framePath);
|
|
40303
40573
|
if (!upload.url) {
|
|
40304
40574
|
return {
|
|
40305
40575
|
success: false,
|
|
40306
|
-
error: `Failed to upload frame
|
|
40576
|
+
error: `Failed to upload frame via ${uploadHost.provider}: ${upload.error || "unknown"}`,
|
|
40307
40577
|
humanLines
|
|
40308
40578
|
};
|
|
40309
40579
|
}
|
|
@@ -40312,13 +40582,13 @@ async function executeFillGaps(options) {
|
|
|
40312
40582
|
let generatedDuration = 0;
|
|
40313
40583
|
const generatedVideos = [];
|
|
40314
40584
|
const initialDuration = Math.min(10, targetDuration);
|
|
40315
|
-
const
|
|
40316
|
-
onProgress(`Generating ${
|
|
40585
|
+
const klingDuration2 = initialDuration > 5 ? "10" : "5";
|
|
40586
|
+
onProgress(`Generating ${klingDuration2}s video with Kling...`);
|
|
40317
40587
|
const prompt3 = options.prompt || "Continue the scene naturally with subtle motion";
|
|
40318
40588
|
const result = await kling.generateVideo(prompt3, {
|
|
40319
40589
|
prompt: prompt3,
|
|
40320
40590
|
referenceImage: frameUrl,
|
|
40321
|
-
duration: parseInt(
|
|
40591
|
+
duration: parseInt(klingDuration2),
|
|
40322
40592
|
aspectRatio: options.ratio || "16:9",
|
|
40323
40593
|
mode: options.mode || "std"
|
|
40324
40594
|
});
|
|
@@ -40341,8 +40611,8 @@ async function executeFillGaps(options) {
|
|
|
40341
40611
|
const videoPath = resolve32(footageDir, videoFileName);
|
|
40342
40612
|
onProgress("Downloading generated video...");
|
|
40343
40613
|
const videoBuffer = await downloadVideo(finalResult.videoUrl);
|
|
40344
|
-
await
|
|
40345
|
-
generatedDuration = finalResult.duration || parseInt(
|
|
40614
|
+
await writeFile25(videoPath, videoBuffer);
|
|
40615
|
+
generatedDuration = finalResult.duration || parseInt(klingDuration2);
|
|
40346
40616
|
generatedVideos.push(videoPath);
|
|
40347
40617
|
humanLines.push(` Generated: ${videoFileName} (${generatedDuration}s)`);
|
|
40348
40618
|
let segmentIndex = 1;
|
|
@@ -40378,7 +40648,7 @@ async function executeFillGaps(options) {
|
|
|
40378
40648
|
humanLines.push(" Failed to extract frame for continuation");
|
|
40379
40649
|
break;
|
|
40380
40650
|
}
|
|
40381
|
-
const extUpload = await
|
|
40651
|
+
const extUpload = await uploadFrame(uploadHost, lastFramePath);
|
|
40382
40652
|
if (!extUpload.url) {
|
|
40383
40653
|
humanLines.push(" Failed to upload continuation frame");
|
|
40384
40654
|
break;
|
|
@@ -40411,11 +40681,11 @@ async function executeFillGaps(options) {
|
|
|
40411
40681
|
`gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}-seg${segmentIndex}.mp4`
|
|
40412
40682
|
);
|
|
40413
40683
|
const segVideoBuffer = await downloadVideo(segFinalResult.videoUrl);
|
|
40414
|
-
await
|
|
40684
|
+
await writeFile25(segVideoPath, segVideoBuffer);
|
|
40415
40685
|
const concatListPath = resolve32(footageDir, `concat-${gap.start.toFixed(2)}.txt`);
|
|
40416
40686
|
const concatList = generatedVideos.map((v) => `file '${v}'`).join("\n") + `
|
|
40417
40687
|
file '${segVideoPath}'`;
|
|
40418
|
-
await
|
|
40688
|
+
await writeFile25(concatListPath, concatList);
|
|
40419
40689
|
const concatOutputPath = resolve32(
|
|
40420
40690
|
footageDir,
|
|
40421
40691
|
`gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}-merged.mp4`
|
|
@@ -40473,7 +40743,7 @@ file '${segVideoPath}'`;
|
|
|
40473
40743
|
let outputPath = filePath;
|
|
40474
40744
|
if (generatedCount > 0) {
|
|
40475
40745
|
outputPath = options.output ? resolve32(process.cwd(), options.output) : filePath;
|
|
40476
|
-
await
|
|
40746
|
+
await writeFile25(outputPath, JSON.stringify(project.toJSON(), null, 2));
|
|
40477
40747
|
humanLines.push(`\u2714 Filled ${generatedCount} gap(s) with AI-generated video`);
|
|
40478
40748
|
humanLines.push(`Project saved: ${outputPath}`);
|
|
40479
40749
|
} else {
|
|
@@ -40501,6 +40771,7 @@ var init_execute_fill_gaps = __esm({
|
|
|
40501
40771
|
init_dist2();
|
|
40502
40772
|
init_engine();
|
|
40503
40773
|
init_api_key();
|
|
40774
|
+
init_upload_host();
|
|
40504
40775
|
init_exec_safe();
|
|
40505
40776
|
init_project_resolver();
|
|
40506
40777
|
init_ai_helpers();
|
|
@@ -40567,7 +40838,14 @@ __export(ai_motion_exports, {
|
|
|
40567
40838
|
});
|
|
40568
40839
|
import { resolve as resolve33 } from "node:path";
|
|
40569
40840
|
import { existsSync as existsSync33 } from "node:fs";
|
|
40570
|
-
import { readFile as readFile25, writeFile as
|
|
40841
|
+
import { readFile as readFile25, writeFile as writeFile26 } from "node:fs/promises";
|
|
40842
|
+
function resolveMotionModel(alias) {
|
|
40843
|
+
const claude = findModel("claude", "llm", alias);
|
|
40844
|
+
if (claude) return { provider: "claude", modelId: claude.id };
|
|
40845
|
+
const gemini = findModel("gemini", "llm", alias);
|
|
40846
|
+
if (gemini) return { provider: "gemini", modelId: gemini.id };
|
|
40847
|
+
return { provider: "claude", modelId: defaultModel("claude", "llm").id };
|
|
40848
|
+
}
|
|
40571
40849
|
async function getOptionalGoogleApiKey() {
|
|
40572
40850
|
const configKey = await getApiKeyFromConfig("google");
|
|
40573
40851
|
if (configKey) return configKey;
|
|
@@ -40582,7 +40860,7 @@ function normalizeUnderstand(value) {
|
|
|
40582
40860
|
}
|
|
40583
40861
|
async function executeMotion(options) {
|
|
40584
40862
|
const modelAlias = options.model || "sonnet";
|
|
40585
|
-
const modelConfig =
|
|
40863
|
+
const modelConfig = resolveMotionModel(modelAlias);
|
|
40586
40864
|
const useGemini = modelConfig.provider === "gemini";
|
|
40587
40865
|
const width = options.width || 1920;
|
|
40588
40866
|
const height = options.height || 1080;
|
|
@@ -40737,7 +41015,7 @@ Use this video understanding to place motion graphics in safe zones, match the c
|
|
|
40737
41015
|
const defaultOutput = options.video || options.image ? "motion-output.mp4" : options.render ? "motion.webm" : "motion.tsx";
|
|
40738
41016
|
const outputPath = resolve33(process.cwd(), options.output || defaultOutput);
|
|
40739
41017
|
const codePath = outputPath.replace(/\.\w+$/, ".tsx");
|
|
40740
|
-
await
|
|
41018
|
+
await writeFile26(codePath, component.code, "utf-8");
|
|
40741
41019
|
const shouldRender = options.render || !!options.video || !!options.image;
|
|
40742
41020
|
if (!shouldRender) {
|
|
40743
41021
|
return { success: true, codePath, componentName: component.name };
|
|
@@ -40961,7 +41239,6 @@ function registerMotionCommand(aiCommand) {
|
|
|
40961
41239
|
}
|
|
40962
41240
|
});
|
|
40963
41241
|
}
|
|
40964
|
-
var MODEL_MAP2;
|
|
40965
41242
|
var init_ai_motion = __esm({
|
|
40966
41243
|
"src/commands/ai-motion.ts"() {
|
|
40967
41244
|
"use strict";
|
|
@@ -40972,14 +41249,6 @@ var init_ai_motion = __esm({
|
|
|
40972
41249
|
init_config();
|
|
40973
41250
|
init_output();
|
|
40974
41251
|
init_validate();
|
|
40975
|
-
MODEL_MAP2 = {
|
|
40976
|
-
sonnet: { provider: "claude", modelId: "claude-sonnet-4-6" },
|
|
40977
|
-
opus: { provider: "claude", modelId: "claude-opus-4-7" },
|
|
40978
|
-
"opus-4-6": { provider: "claude", modelId: "claude-opus-4-6" },
|
|
40979
|
-
gemini: { provider: "gemini", modelId: GEMINI_DEFAULT_TEXT_MODEL },
|
|
40980
|
-
"gemini-2.5-pro": { provider: "gemini", modelId: "gemini-2.5-pro" },
|
|
40981
|
-
"gemini-3.1-pro": { provider: "gemini", modelId: "gemini-3.1-pro-preview" }
|
|
40982
|
-
};
|
|
40983
41252
|
}
|
|
40984
41253
|
});
|
|
40985
41254
|
|
|
@@ -41216,7 +41485,7 @@ __export(project_builder_exports, {
|
|
|
41216
41485
|
buildTempProject: () => buildTempProject,
|
|
41217
41486
|
resolveSourceUrl: () => resolveSourceUrl
|
|
41218
41487
|
});
|
|
41219
|
-
import { mkdtemp, mkdir as
|
|
41488
|
+
import { mkdtemp, mkdir as mkdir17, copyFile as copyFile5, writeFile as writeFile27, rm as rm5, readdir as readdir4 } from "node:fs/promises";
|
|
41220
41489
|
import { existsSync as existsSync34 } from "node:fs";
|
|
41221
41490
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
41222
41491
|
import { createRequire } from "node:module";
|
|
@@ -41224,7 +41493,7 @@ import * as path from "node:path";
|
|
|
41224
41493
|
async function buildTempProject(state, projectFileDir) {
|
|
41225
41494
|
const dir = await mkdtemp(path.join(tmpdir2(), "vibeframe-hf-"));
|
|
41226
41495
|
const assetsDir = path.join(dir, "assets");
|
|
41227
|
-
await
|
|
41496
|
+
await mkdir17(assetsDir, { recursive: true });
|
|
41228
41497
|
const copied = /* @__PURE__ */ new Map();
|
|
41229
41498
|
for (const source of state.sources) {
|
|
41230
41499
|
if (copied.has(source.id)) continue;
|
|
@@ -41240,10 +41509,10 @@ async function buildTempProject(state, projectFileDir) {
|
|
|
41240
41509
|
await copyLottieRuntime(dir);
|
|
41241
41510
|
}
|
|
41242
41511
|
const html = generateCompositionHtml(state);
|
|
41243
|
-
await
|
|
41512
|
+
await writeFile27(path.join(dir, "index.html"), html, "utf-8");
|
|
41244
41513
|
return {
|
|
41245
41514
|
dir,
|
|
41246
|
-
cleanup: () =>
|
|
41515
|
+
cleanup: () => rm5(dir, { recursive: true, force: true })
|
|
41247
41516
|
};
|
|
41248
41517
|
}
|
|
41249
41518
|
async function copyLottieRuntime(tempDir) {
|
|
@@ -41254,7 +41523,7 @@ async function copyLottieRuntime(tempDir) {
|
|
|
41254
41523
|
const wasmSrc = path.join(path.dirname(webEntry), "dotlottie-player.wasm");
|
|
41255
41524
|
const vendorDir = path.join(tempDir, "vendor");
|
|
41256
41525
|
const wcDest = path.join(vendorDir, "dotlottie-wc");
|
|
41257
|
-
await
|
|
41526
|
+
await mkdir17(wcDest, { recursive: true });
|
|
41258
41527
|
for (const file of await readdir4(wcDistDir)) {
|
|
41259
41528
|
if (file.endsWith(".map") || file.endsWith(".d.ts")) continue;
|
|
41260
41529
|
await copyFile5(path.join(wcDistDir, file), path.join(wcDest, file));
|
|
@@ -41362,9 +41631,9 @@ __export(motion_overlay_exports, {
|
|
|
41362
41631
|
executeMotionOverlay: () => executeMotionOverlay,
|
|
41363
41632
|
registerMotionOverlayCommand: () => registerMotionOverlayCommand
|
|
41364
41633
|
});
|
|
41365
|
-
import { mkdir as
|
|
41634
|
+
import { mkdir as mkdir18 } from "node:fs/promises";
|
|
41366
41635
|
import { existsSync as existsSync35 } from "node:fs";
|
|
41367
|
-
import { basename as basename9, dirname as
|
|
41636
|
+
import { basename as basename9, dirname as dirname15, extname as extname8, resolve as resolve35 } from "node:path";
|
|
41368
41637
|
function normalizeUnderstand2(value) {
|
|
41369
41638
|
return value === "off" || value === "required" || value === "auto" ? value : "auto";
|
|
41370
41639
|
}
|
|
@@ -41387,7 +41656,7 @@ function assertValidRequest(options) {
|
|
|
41387
41656
|
return "Provide a motion description, or pass --asset <logo.json|logo.lottie>.";
|
|
41388
41657
|
}
|
|
41389
41658
|
if (hasAsset) {
|
|
41390
|
-
const ext =
|
|
41659
|
+
const ext = extname8(options.asset).toLowerCase();
|
|
41391
41660
|
if (ext !== ".json" && ext !== ".lottie") {
|
|
41392
41661
|
return "Lottie overlay asset must be a .json or .lottie file.";
|
|
41393
41662
|
}
|
|
@@ -41510,7 +41779,7 @@ async function executeMotionOverlay(options) {
|
|
|
41510
41779
|
const scale = Math.max(0.01, Math.min(2, numberOption(options.scale, position === "full" ? 1 : 0.25)));
|
|
41511
41780
|
const opacity = Math.max(0, Math.min(1, numberOption(options.opacity, 1)));
|
|
41512
41781
|
const loop = options.loop ?? true;
|
|
41513
|
-
await
|
|
41782
|
+
await mkdir18(dirname15(outputPath), { recursive: true });
|
|
41514
41783
|
const backend = createHyperframesBackend();
|
|
41515
41784
|
const result2 = await backend.render({
|
|
41516
41785
|
projectState: buildLottieTimelineState({
|
|
@@ -41536,7 +41805,7 @@ async function executeMotionOverlay(options) {
|
|
|
41536
41805
|
return { success: true, outputPath, provider: "lottie" };
|
|
41537
41806
|
}
|
|
41538
41807
|
const duration = options.duration ?? await ffprobeDuration(absVideo).catch(() => void 0);
|
|
41539
|
-
await
|
|
41808
|
+
await mkdir18(dirname15(outputPath), { recursive: true });
|
|
41540
41809
|
const result = await executeMotion({
|
|
41541
41810
|
description: options.description.trim(),
|
|
41542
41811
|
video: absVideo,
|
|
@@ -41664,8 +41933,8 @@ __export(edit_cmd_exports, {
|
|
|
41664
41933
|
executeSpeedRamp: () => executeSpeedRamp,
|
|
41665
41934
|
executeUpscale: () => executeUpscale
|
|
41666
41935
|
});
|
|
41667
|
-
import { resolve as resolve36, dirname as
|
|
41668
|
-
import { readFile as readFile26, writeFile as
|
|
41936
|
+
import { resolve as resolve36, dirname as dirname16 } from "node:path";
|
|
41937
|
+
import { readFile as readFile26, writeFile as writeFile28, mkdir as mkdir19 } from "node:fs/promises";
|
|
41669
41938
|
async function executeGrade(options) {
|
|
41670
41939
|
const { videoPath, style, preset, output, analyzeOnly, apiKey } = options;
|
|
41671
41940
|
try {
|
|
@@ -41858,6 +42127,7 @@ var init_edit_cmd = __esm({
|
|
|
41858
42127
|
init_output();
|
|
41859
42128
|
init_validate();
|
|
41860
42129
|
init_cost_tier();
|
|
42130
|
+
init_image_file();
|
|
41861
42131
|
editCommand = new Command("edit").alias("ed").description(
|
|
41862
42132
|
"Edit and post-process media (silence-cut, caption, grade, reframe, upscale...)"
|
|
41863
42133
|
).addHelpText(
|
|
@@ -42293,7 +42563,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42293
42563
|
console.log();
|
|
42294
42564
|
if (options.keyframes) {
|
|
42295
42565
|
const keyframesPath = resolve36(process.cwd(), options.keyframes);
|
|
42296
|
-
await
|
|
42566
|
+
await writeFile28(keyframesPath, JSON.stringify(cropKeyframes, null, 2));
|
|
42297
42567
|
console.log(source_default.green(`Keyframes saved to: ${keyframesPath}`));
|
|
42298
42568
|
}
|
|
42299
42569
|
if (options.analyzeOnly) {
|
|
@@ -42317,7 +42587,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42317
42587
|
exitWithError(generalError(`Reframe failed: ${msg}`));
|
|
42318
42588
|
}
|
|
42319
42589
|
});
|
|
42320
|
-
editCommand.command("image").description("Edit image(s) using AI (Gemini, OpenAI, or Grok)").argument("<images...>", "Input image file(s) followed by edit prompt").option("-p, --provider <provider>", "Provider: gemini (default), openai, grok", "gemini").option("-k, --api-key <key>", "API key (or set env variable)").option("-o, --output <path>", "Output file path", "edited.png").option("-m, --model <model>", "Model: flash
|
|
42590
|
+
editCommand.command("image").description("Edit image(s) using AI (Gemini, OpenAI, or Grok)").argument("<images...>", "Input image file(s) followed by edit prompt").option("-p, --provider <provider>", "Provider: gemini (default), openai, grok", "gemini").option("-k, --api-key <key>", "API key (or set env variable)").option("-o, --output <path>", "Output file path", "edited.png").option("-m, --model <model>", "Model: flash, lite, pro (Gemini); pro (Grok)", "flash").option("-r, --ratio <ratio>", "Output aspect ratio").option("--size <resolution>", "Resolution: 1K, 2K, 4K (Gemini Pro only)").option("--dry-run", "Preview parameters without executing").action(async (args, options) => {
|
|
42321
42591
|
const startedAt = Date.now();
|
|
42322
42592
|
try {
|
|
42323
42593
|
if (args.length < 2) {
|
|
@@ -42376,14 +42646,16 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42376
42646
|
const grok = new GrokProvider();
|
|
42377
42647
|
await grok.initialize({ apiKey });
|
|
42378
42648
|
result = await grok.editImage(imageBuffers[0], prompt3, {
|
|
42649
|
+
...resolveGrokImageModel(options.model),
|
|
42379
42650
|
aspectRatio: options.ratio
|
|
42380
42651
|
});
|
|
42381
42652
|
} else {
|
|
42382
42653
|
const editModelNames = {
|
|
42383
|
-
flash: "gemini-
|
|
42384
|
-
"3.1-flash": "gemini-3.1-flash-image
|
|
42385
|
-
latest: "gemini-3.1-flash-image
|
|
42386
|
-
|
|
42654
|
+
flash: "gemini-3.1-flash-image",
|
|
42655
|
+
"3.1-flash": "gemini-3.1-flash-image",
|
|
42656
|
+
latest: "gemini-3.1-flash-image",
|
|
42657
|
+
lite: "gemini-3.1-flash-lite-image",
|
|
42658
|
+
pro: "gemini-3-pro-image"
|
|
42387
42659
|
};
|
|
42388
42660
|
const editModelName = editModelNames[options.model] || editModelNames.flash;
|
|
42389
42661
|
spinner2.text = `Editing with ${editModelName}...`;
|
|
@@ -42394,15 +42666,6 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42394
42666
|
aspectRatio: options.ratio,
|
|
42395
42667
|
resolution: options.size
|
|
42396
42668
|
});
|
|
42397
|
-
const fallbackModels = ["latest", "3.1-flash"];
|
|
42398
|
-
if (!result.success && fallbackModels.includes(options.model)) {
|
|
42399
|
-
spinner2.text = `${source_default.dim(result.error || `${editModelName} failed`)} \u2014 retrying with flash...`;
|
|
42400
|
-
result = await gemini.editImage(imageBuffers, prompt3, {
|
|
42401
|
-
model: "flash",
|
|
42402
|
-
aspectRatio: options.ratio,
|
|
42403
|
-
resolution: options.size
|
|
42404
|
-
});
|
|
42405
|
-
}
|
|
42406
42669
|
}
|
|
42407
42670
|
if (!result.success || !result.images || result.images.length === 0) {
|
|
42408
42671
|
spinner2.fail(result.error || "Image editing failed");
|
|
@@ -42412,14 +42675,14 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42412
42675
|
const img = result.images[0];
|
|
42413
42676
|
const outputPath = resolve36(process.cwd(), options.output);
|
|
42414
42677
|
const saveImage = async () => {
|
|
42415
|
-
await
|
|
42678
|
+
await mkdir19(dirname16(outputPath), { recursive: true });
|
|
42416
42679
|
if (img.base64) {
|
|
42417
42680
|
const buffer = Buffer.from(img.base64, "base64");
|
|
42418
|
-
await
|
|
42681
|
+
await writeImageFile(outputPath, buffer);
|
|
42419
42682
|
} else if (img.url) {
|
|
42420
42683
|
const resp = await fetch(img.url);
|
|
42421
42684
|
const arrayBuf = await resp.arrayBuffer();
|
|
42422
|
-
await
|
|
42685
|
+
await writeImageFile(outputPath, Buffer.from(arrayBuf));
|
|
42423
42686
|
}
|
|
42424
42687
|
};
|
|
42425
42688
|
const resultModel = result.model;
|
|
@@ -42638,8 +42901,8 @@ __export(ai_image_exports, {
|
|
|
42638
42901
|
executeImageGenerate: () => executeImageGenerate,
|
|
42639
42902
|
executeThumbnailBestFrame: () => executeThumbnailBestFrame
|
|
42640
42903
|
});
|
|
42641
|
-
import { resolve as resolve38, dirname as
|
|
42642
|
-
import { readFile as readFile27,
|
|
42904
|
+
import { resolve as resolve38, dirname as dirname18 } from "node:path";
|
|
42905
|
+
import { readFile as readFile27, mkdir as mkdir21 } from "node:fs/promises";
|
|
42643
42906
|
import { existsSync as existsSync37 } from "node:fs";
|
|
42644
42907
|
async function executeImageGenerate(options) {
|
|
42645
42908
|
const {
|
|
@@ -42682,8 +42945,8 @@ async function executeImageGenerate(options) {
|
|
|
42682
42945
|
return { success: false, error: "No image data available" };
|
|
42683
42946
|
}
|
|
42684
42947
|
outputPath = resolve38(process.cwd(), output);
|
|
42685
|
-
await
|
|
42686
|
-
await
|
|
42948
|
+
await mkdir21(dirname18(outputPath), { recursive: true });
|
|
42949
|
+
await writeImageFile(outputPath, buffer);
|
|
42687
42950
|
}
|
|
42688
42951
|
return {
|
|
42689
42952
|
success: true,
|
|
@@ -42717,8 +42980,8 @@ async function executeImageGenerate(options) {
|
|
|
42717
42980
|
const img = result.images[0];
|
|
42718
42981
|
if (img.base64) {
|
|
42719
42982
|
outputPath = resolve38(process.cwd(), output);
|
|
42720
|
-
await
|
|
42721
|
-
await
|
|
42983
|
+
await mkdir21(dirname18(outputPath), { recursive: true });
|
|
42984
|
+
await writeImageFile(outputPath, Buffer.from(img.base64, "base64"));
|
|
42722
42985
|
}
|
|
42723
42986
|
}
|
|
42724
42987
|
return {
|
|
@@ -42731,10 +42994,11 @@ async function executeImageGenerate(options) {
|
|
|
42731
42994
|
} else if (provider === "grok") {
|
|
42732
42995
|
const key = apiKey || process.env.XAI_API_KEY;
|
|
42733
42996
|
if (!key) return { success: false, error: "XAI_API_KEY required" };
|
|
42734
|
-
const
|
|
42735
|
-
await
|
|
42736
|
-
const result = await
|
|
42737
|
-
|
|
42997
|
+
const grok = new GrokProvider();
|
|
42998
|
+
await grok.initialize({ apiKey: key });
|
|
42999
|
+
const result = await grok.generateImage(prompt3, {
|
|
43000
|
+
...resolveGrokImageModel(model),
|
|
43001
|
+
aspectRatio: ratio,
|
|
42738
43002
|
n: count
|
|
42739
43003
|
});
|
|
42740
43004
|
if (!result.success || !result.images) {
|
|
@@ -42753,8 +43017,8 @@ async function executeImageGenerate(options) {
|
|
|
42753
43017
|
return { success: false, error: "No image data available" };
|
|
42754
43018
|
}
|
|
42755
43019
|
outputPath = resolve38(process.cwd(), output);
|
|
42756
|
-
await
|
|
42757
|
-
await
|
|
43020
|
+
await mkdir21(dirname18(outputPath), { recursive: true });
|
|
43021
|
+
await writeImageFile(outputPath, buffer);
|
|
42758
43022
|
}
|
|
42759
43023
|
return {
|
|
42760
43024
|
success: true,
|
|
@@ -42812,8 +43076,8 @@ async function executeGeminiEdit(options) {
|
|
|
42812
43076
|
let outputPath;
|
|
42813
43077
|
if (img.base64) {
|
|
42814
43078
|
outputPath = resolve38(process.cwd(), output);
|
|
42815
|
-
await
|
|
42816
|
-
await
|
|
43079
|
+
await mkdir21(dirname18(outputPath), { recursive: true });
|
|
43080
|
+
await writeImageFile(outputPath, Buffer.from(img.base64, "base64"));
|
|
42817
43081
|
}
|
|
42818
43082
|
return {
|
|
42819
43083
|
success: true,
|
|
@@ -42887,6 +43151,7 @@ var init_ai_image = __esm({
|
|
|
42887
43151
|
"use strict";
|
|
42888
43152
|
init_dist2();
|
|
42889
43153
|
init_exec_safe();
|
|
43154
|
+
init_image_file();
|
|
42890
43155
|
}
|
|
42891
43156
|
});
|
|
42892
43157
|
|
|
@@ -42898,7 +43163,7 @@ __export(ai_analyze_exports, {
|
|
|
42898
43163
|
registerAnalyzeCommands: () => registerAnalyzeCommands
|
|
42899
43164
|
});
|
|
42900
43165
|
import { readFile as readFile28 } from "node:fs/promises";
|
|
42901
|
-
import { extname as
|
|
43166
|
+
import { extname as extname9, resolve as resolve39 } from "node:path";
|
|
42902
43167
|
import { existsSync as existsSync38 } from "node:fs";
|
|
42903
43168
|
async function executeGeminiVideo(options) {
|
|
42904
43169
|
try {
|
|
@@ -42955,7 +43220,7 @@ async function executeAnalyze(options) {
|
|
|
42955
43220
|
const isYouTube = source.includes("youtube.com") || source.includes("youtu.be");
|
|
42956
43221
|
const isImageUrl = /^https?:\/\/.+\.(png|jpg|jpeg|webp|gif)(\?.*)?$/i.test(source);
|
|
42957
43222
|
const isVideoUrl = /^https?:\/\/.+\.(mp4|mov|webm)(\?.*)?$/i.test(source);
|
|
42958
|
-
const ext =
|
|
43223
|
+
const ext = extname9(source).toLowerCase();
|
|
42959
43224
|
const imageExts = [".png", ".jpg", ".jpeg", ".webp", ".gif"];
|
|
42960
43225
|
const videoExts = [".mp4", ".mov", ".webm", ".avi", ".mkv"];
|
|
42961
43226
|
const isLocalImage = imageExts.includes(ext);
|
|
@@ -43363,7 +43628,7 @@ async function executeSoundEffect(options) {
|
|
|
43363
43628
|
}
|
|
43364
43629
|
}
|
|
43365
43630
|
function registerSoundEffectCommand(parent) {
|
|
43366
|
-
parent.command("sound-effect").description("Generate sound effect using ElevenLabs").argument("<prompt>", "Description of the sound effect").option("-k, --api-key <key>", "ElevenLabs API key (or set ELEVENLABS_API_KEY env)").option("-o, --output <path>", "Output audio file path", "sound-effect.mp3").option("-d, --duration <seconds>", "Duration in seconds (0.5-
|
|
43631
|
+
parent.command("sound-effect").description("Generate sound effect using ElevenLabs").argument("<prompt>", "Description of the sound effect").option("-k, --api-key <key>", "ElevenLabs API key (or set ELEVENLABS_API_KEY env)").option("-o, --output <path>", "Output audio file path", "sound-effect.mp3").option("-d, --duration <seconds>", "Duration in seconds (0.5-30, default: auto)").option("--prompt-influence <value>", "Prompt influence (0-1, default: 0.3)").option("--dry-run", "Preview parameters without executing").action(async (prompt3, options) => {
|
|
43367
43632
|
const startedAt = Date.now();
|
|
43368
43633
|
try {
|
|
43369
43634
|
rejectControlChars(prompt3);
|
|
@@ -43663,9 +43928,9 @@ var init_speech = __esm({
|
|
|
43663
43928
|
});
|
|
43664
43929
|
|
|
43665
43930
|
// src/commands/generate/thumbnail.ts
|
|
43666
|
-
import { resolve as resolve47, dirname as
|
|
43931
|
+
import { resolve as resolve47, dirname as dirname19, basename as basename13, extname as extname10 } from "node:path";
|
|
43667
43932
|
import { existsSync as existsSync42 } from "node:fs";
|
|
43668
|
-
import { writeFile as writeFile33, mkdir as
|
|
43933
|
+
import { writeFile as writeFile33, mkdir as mkdir22 } from "node:fs/promises";
|
|
43669
43934
|
function registerThumbnailCommand(parent) {
|
|
43670
43935
|
parent.command("thumbnail").description("Generate video thumbnail (DALL-E) or extract best frame from video (Gemini)").argument("[description]", "Thumbnail description (for DALL-E generation)").option("-k, --api-key <key>", "API key (OpenAI for generation, Google for best-frame)").option("-o, --output <path>", "Output file path").option("--style <style>", "Platform style: youtube, instagram, tiktok, twitter").option("--best-frame <video>", "Extract best thumbnail frame from video using Gemini AI").option("--prompt <prompt>", "Custom prompt for best-frame analysis").option("--model <model>", `Gemini model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").action(async (description, options) => {
|
|
43671
43936
|
const startedAt = Date.now();
|
|
@@ -43688,7 +43953,7 @@ function registerThumbnailCommand(parent) {
|
|
|
43688
43953
|
);
|
|
43689
43954
|
}
|
|
43690
43955
|
const apiKey2 = await requireApiKey("GOOGLE_API_KEY", "Google", options.apiKey);
|
|
43691
|
-
const name = basename13(options.bestFrame,
|
|
43956
|
+
const name = basename13(options.bestFrame, extname10(options.bestFrame));
|
|
43692
43957
|
const outputPath = options.output || `${name}-thumbnail.png`;
|
|
43693
43958
|
const spinner3 = ora("Analyzing video for best frame...").start();
|
|
43694
43959
|
const result2 = await executeThumbnailBestFrame({
|
|
@@ -43756,7 +44021,7 @@ function registerThumbnailCommand(parent) {
|
|
|
43756
44021
|
throw new Error("No image data available");
|
|
43757
44022
|
}
|
|
43758
44023
|
outputPath = resolve47(process.cwd(), options.output);
|
|
43759
|
-
await
|
|
44024
|
+
await mkdir22(dirname19(outputPath), { recursive: true });
|
|
43760
44025
|
await writeFile33(outputPath, buffer);
|
|
43761
44026
|
}
|
|
43762
44027
|
outputSuccess({
|
|
@@ -43787,7 +44052,7 @@ function registerThumbnailCommand(parent) {
|
|
|
43787
44052
|
throw new Error("No image data available");
|
|
43788
44053
|
}
|
|
43789
44054
|
const outputPath = resolve47(process.cwd(), options.output);
|
|
43790
|
-
await
|
|
44055
|
+
await mkdir22(dirname19(outputPath), { recursive: true });
|
|
43791
44056
|
await writeFile33(outputPath, buffer);
|
|
43792
44057
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
43793
44058
|
} catch {
|
|
@@ -43818,7 +44083,7 @@ var init_thumbnail = __esm({
|
|
|
43818
44083
|
import { resolve as resolve48 } from "node:path";
|
|
43819
44084
|
import { writeFile as writeFile34 } from "node:fs/promises";
|
|
43820
44085
|
function registerVideoExtendCommand(parent) {
|
|
43821
|
-
parent.command("video-extend", { hidden: true }).description("Extend video duration (Kling by video ID, Veo by operation name)").argument("<id>", "Kling video ID or Veo operation name").option("-p, --provider <provider>", "Provider: kling, veo", "kling").option("-k, --api-key <key>", "API key (KLING_API_KEY or GOOGLE_API_KEY)").option("-o, --output <path>", "Output file path").option("--prompt <text>", "Continuation prompt").option("-d, --duration <sec>", "Duration: 5 or 10 (Kling), 4/6/8 (Veo)", "5").option("--negative <prompt>", "Negative prompt (what to avoid, Kling only)").option("--veo-model <model>", "Veo model: 3.
|
|
44086
|
+
parent.command("video-extend", { hidden: true }).description("Extend video duration (Kling by video ID, Veo by operation name)").argument("<id>", "Kling video ID or Veo operation name").option("-p, --provider <provider>", "Provider: kling, veo", "kling").option("-k, --api-key <key>", "API key (KLING_API_KEY or GOOGLE_API_KEY)").option("-o, --output <path>", "Output file path").option("--prompt <text>", "Continuation prompt").option("-d, --duration <sec>", "Duration: 5 or 10 (Kling), 4/6/8 (Veo)", "5").option("--negative <prompt>", "Negative prompt (what to avoid, Kling only)").option("--veo-model <model>", "Veo model: 3.1, 3.1-fast", "3.1").option("--no-wait", "Start extension and return task ID without waiting").option("--dry-run", "Preview parameters without executing").action(async (id, options) => {
|
|
43822
44087
|
const startedAt = Date.now();
|
|
43823
44088
|
try {
|
|
43824
44089
|
const provider = (options.provider || "kling").toLowerCase();
|
|
@@ -43936,12 +44201,7 @@ function registerVideoExtendCommand(parent) {
|
|
|
43936
44201
|
const spinner2 = ora("Initializing Veo...").start();
|
|
43937
44202
|
const gemini = new GeminiProvider();
|
|
43938
44203
|
await gemini.initialize({ apiKey });
|
|
43939
|
-
const
|
|
43940
|
-
"3.0": "veo-3.0-generate-preview",
|
|
43941
|
-
"3.1": "veo-3.1-generate-preview",
|
|
43942
|
-
"3.1-fast": "veo-3.1-fast-generate-preview"
|
|
43943
|
-
};
|
|
43944
|
-
const veoModel = veoModelMap[options.veoModel] || "veo-3.1-generate-preview";
|
|
44204
|
+
const veoModel = resolveVeoModel(options.veoModel);
|
|
43945
44205
|
spinner2.text = "Starting video extension...";
|
|
43946
44206
|
const result = await gemini.extendVideo(id, options.prompt, {
|
|
43947
44207
|
duration: parseInt(options.duration),
|
|
@@ -44102,11 +44362,8 @@ var init_provider_resolver = __esm({
|
|
|
44102
44362
|
|
|
44103
44363
|
// src/commands/_shared/openai-image.ts
|
|
44104
44364
|
function resolveOpenAIImageModel(modelAlias) {
|
|
44105
|
-
const
|
|
44106
|
-
return {
|
|
44107
|
-
openaiModel: isGptImage15 ? "gpt-image-1.5" : "gpt-image-2",
|
|
44108
|
-
modelLabel: isGptImage15 ? "GPT Image 1.5" : "GPT Image 2"
|
|
44109
|
-
};
|
|
44365
|
+
const model = findModel("openai", "image", modelAlias) ?? defaultModel("openai", "image");
|
|
44366
|
+
return { openaiModel: model.id, modelLabel: model.label };
|
|
44110
44367
|
}
|
|
44111
44368
|
async function executeOpenAIImageGenerate(prompt3, options, ctx) {
|
|
44112
44369
|
const provider = new OpenAIImageProvider();
|
|
@@ -44128,10 +44385,44 @@ var init_openai_image2 = __esm({
|
|
|
44128
44385
|
}
|
|
44129
44386
|
});
|
|
44130
44387
|
|
|
44388
|
+
// src/commands/_shared/image-cost.ts
|
|
44389
|
+
function catalogPrice(provider, model) {
|
|
44390
|
+
if (provider === "openai") return findModel("openai", "image", resolveOpenAIImageModel(model).openaiModel)?.price?.usd;
|
|
44391
|
+
if (provider === "gemini") return findModel("gemini", "image", model ?? "flash")?.price?.usd ?? findModel("gemini", "image")?.price?.usd;
|
|
44392
|
+
if (provider === "grok") return findModel("grok", "image", resolveGrokImageModel(model).model)?.price?.usd;
|
|
44393
|
+
return void 0;
|
|
44394
|
+
}
|
|
44395
|
+
function estimateImageCostUsd(provider, model, count) {
|
|
44396
|
+
const images = Math.max(1, count);
|
|
44397
|
+
const perImage = catalogPrice(provider, model);
|
|
44398
|
+
if (perImage === void 0) {
|
|
44399
|
+
return {
|
|
44400
|
+
costUsd: lookupCostEstimateUpperBound("generate image") ?? 5,
|
|
44401
|
+
warnings: [
|
|
44402
|
+
`costUsd is the tier upper bound for ${provider} - actual provider billing is typically lower and is not metered here.`
|
|
44403
|
+
]
|
|
44404
|
+
};
|
|
44405
|
+
}
|
|
44406
|
+
return {
|
|
44407
|
+
costUsd: Number((perImage * images).toFixed(3)),
|
|
44408
|
+
warnings: [
|
|
44409
|
+
`costUsd is an upper-bound estimate from ${provider} list prices for ${images} image(s) - not metered billing.`
|
|
44410
|
+
]
|
|
44411
|
+
};
|
|
44412
|
+
}
|
|
44413
|
+
var init_image_cost = __esm({
|
|
44414
|
+
"src/commands/_shared/image-cost.ts"() {
|
|
44415
|
+
"use strict";
|
|
44416
|
+
init_dist2();
|
|
44417
|
+
init_output();
|
|
44418
|
+
init_openai_image2();
|
|
44419
|
+
}
|
|
44420
|
+
});
|
|
44421
|
+
|
|
44131
44422
|
// src/commands/generate/image.ts
|
|
44132
|
-
import { resolve as resolve49, dirname as
|
|
44423
|
+
import { resolve as resolve49, dirname as dirname20 } from "node:path";
|
|
44133
44424
|
import { fileURLToPath } from "node:url";
|
|
44134
|
-
import {
|
|
44425
|
+
import { mkdir as mkdir23 } from "node:fs/promises";
|
|
44135
44426
|
function registerImageCommand(parent) {
|
|
44136
44427
|
parent.command("image").alias("img").description("Generate image using AI (Gemini, OpenAI gpt-image, Grok, or Runway)").argument("[prompt]", "Image description prompt (interactive if omitted)").option(
|
|
44137
44428
|
"-p, --provider <provider>",
|
|
@@ -44142,7 +44433,7 @@ function registerImageCommand(parent) {
|
|
|
44142
44433
|
"1:1"
|
|
44143
44434
|
).option("--quality <quality>", "Quality: standard, hd (openai only)", "standard").option("--style <style>", "Style: vivid, natural (openai only)", "vivid").option("--count <n>", "Number of images to generate", "1").option(
|
|
44144
44435
|
"-m, --model <model>",
|
|
44145
|
-
"Model. Gemini: flash
|
|
44436
|
+
"Model. Gemini: flash (default), lite, pro. OpenAI: 2.5 (default), flare, 2, 1.5. Grok: pro"
|
|
44146
44437
|
).option("--dry-run", "Preview parameters without executing").addHelpText(
|
|
44147
44438
|
"after",
|
|
44148
44439
|
`
|
|
@@ -44225,6 +44516,7 @@ Examples:
|
|
|
44225
44516
|
command: "generate image",
|
|
44226
44517
|
startedAt,
|
|
44227
44518
|
dryRun: true,
|
|
44519
|
+
...estimateImageCostUsd(provider, options.model, parseInt(options.count) || 1),
|
|
44228
44520
|
data: {
|
|
44229
44521
|
params: {
|
|
44230
44522
|
prompt: prompt3,
|
|
@@ -44245,7 +44537,7 @@ Examples:
|
|
|
44245
44537
|
const apiKey = await requireApiKey(envKey, providerName, options.apiKey);
|
|
44246
44538
|
const spinner2 = ora(`Generating image with ${providerName}...`).start();
|
|
44247
44539
|
if (provider === "openai") {
|
|
44248
|
-
const { result, modelLabel } = await executeOpenAIImageGenerate(prompt3, options, {
|
|
44540
|
+
const { result, modelLabel, openaiModel } = await executeOpenAIImageGenerate(prompt3, options, {
|
|
44249
44541
|
apiKey
|
|
44250
44542
|
});
|
|
44251
44543
|
if (!result.success || !result.images) {
|
|
@@ -44268,14 +44560,17 @@ Examples:
|
|
|
44268
44560
|
} else {
|
|
44269
44561
|
throw new Error("No image data available");
|
|
44270
44562
|
}
|
|
44271
|
-
await
|
|
44272
|
-
await
|
|
44563
|
+
await mkdir23(dirname20(outputPath), { recursive: true });
|
|
44564
|
+
await writeImageFile(outputPath, buffer);
|
|
44273
44565
|
}
|
|
44274
44566
|
outputSuccess({
|
|
44275
44567
|
command: "generate image",
|
|
44276
44568
|
startedAt,
|
|
44569
|
+
...estimateImageCostUsd("openai", options.model, result.images.length),
|
|
44277
44570
|
data: {
|
|
44278
44571
|
provider: "openai",
|
|
44572
|
+
model: modelLabel,
|
|
44573
|
+
modelId: openaiModel,
|
|
44279
44574
|
images: result.images.map((img) => ({
|
|
44280
44575
|
url: img.url,
|
|
44281
44576
|
revisedPrompt: img.revisedPrompt
|
|
@@ -44315,8 +44610,8 @@ Examples:
|
|
|
44315
44610
|
throw new Error("No image data available");
|
|
44316
44611
|
}
|
|
44317
44612
|
const outputPath = resolve49(process.cwd(), options.output);
|
|
44318
|
-
await
|
|
44319
|
-
await
|
|
44613
|
+
await mkdir23(dirname20(outputPath), { recursive: true });
|
|
44614
|
+
await writeImageFile(outputPath, buffer);
|
|
44320
44615
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
44321
44616
|
} catch (err) {
|
|
44322
44617
|
saveSpinner.fail(
|
|
@@ -44325,7 +44620,7 @@ Examples:
|
|
|
44325
44620
|
}
|
|
44326
44621
|
}
|
|
44327
44622
|
} else if (provider === "gemini") {
|
|
44328
|
-
const validGeminiModels = ["flash", "3.1-flash", "latest", "pro"];
|
|
44623
|
+
const validGeminiModels = ["flash", "3.1-flash", "latest", "lite", "pro"];
|
|
44329
44624
|
if (options.model && !validGeminiModels.includes(options.model)) {
|
|
44330
44625
|
console.warn(
|
|
44331
44626
|
source_default.yellow(
|
|
@@ -44358,26 +44653,17 @@ Examples:
|
|
|
44358
44653
|
const gemini = new GeminiProvider();
|
|
44359
44654
|
await gemini.initialize({ apiKey });
|
|
44360
44655
|
const geminiModelNames = {
|
|
44361
|
-
flash: "Nano Banana",
|
|
44656
|
+
flash: "Nano Banana 2",
|
|
44362
44657
|
"3.1-flash": "Nano Banana 2",
|
|
44363
44658
|
latest: "Nano Banana 2",
|
|
44659
|
+
lite: "Nano Banana 2 Lite",
|
|
44364
44660
|
pro: "Nano Banana Pro"
|
|
44365
44661
|
};
|
|
44366
|
-
const
|
|
44367
|
-
|
|
44662
|
+
const usedLabel = geminiModelNames[options.model] || "Nano Banana 2";
|
|
44663
|
+
const result = await gemini.generateImage(prompt3, {
|
|
44368
44664
|
model: options.model,
|
|
44369
44665
|
aspectRatio: options.ratio
|
|
44370
44666
|
});
|
|
44371
|
-
let usedLabel = modelLabel;
|
|
44372
|
-
const fallbackModels = ["latest", "3.1-flash"];
|
|
44373
|
-
if (!result.success && options.model && fallbackModels.includes(options.model)) {
|
|
44374
|
-
spinner2.text = `${source_default.dim(result.error || "Failed")} \u2014 retrying with Nano Banana (flash)...`;
|
|
44375
|
-
result = await gemini.generateImage(prompt3, {
|
|
44376
|
-
model: "flash",
|
|
44377
|
-
aspectRatio: options.ratio
|
|
44378
|
-
});
|
|
44379
|
-
usedLabel = "Nano Banana (fallback)";
|
|
44380
|
-
}
|
|
44381
44667
|
if (!result.success || !result.images) {
|
|
44382
44668
|
spinner2.fail(result.error || "Image generation failed");
|
|
44383
44669
|
exitWithError(apiError(result.error || "Image generation failed", true));
|
|
@@ -44390,16 +44676,17 @@ Examples:
|
|
|
44390
44676
|
if (outputPath && result.images.length > 0) {
|
|
44391
44677
|
const img = result.images[0];
|
|
44392
44678
|
const buffer = Buffer.from(img.base64, "base64");
|
|
44393
|
-
await
|
|
44394
|
-
await
|
|
44679
|
+
await mkdir23(dirname20(outputPath), { recursive: true });
|
|
44680
|
+
await writeImageFile(outputPath, buffer);
|
|
44395
44681
|
}
|
|
44396
44682
|
outputSuccess({
|
|
44397
44683
|
command: "generate image",
|
|
44398
44684
|
startedAt,
|
|
44399
|
-
|
|
44685
|
+
...estimateImageCostUsd("gemini", options.model, result.images.length),
|
|
44400
44686
|
data: {
|
|
44401
44687
|
provider: "gemini",
|
|
44402
44688
|
model: usedLabel,
|
|
44689
|
+
modelId: result.model,
|
|
44403
44690
|
images: result.images.map((img) => ({
|
|
44404
44691
|
mimeType: img.mimeType
|
|
44405
44692
|
})),
|
|
@@ -44423,8 +44710,8 @@ Examples:
|
|
|
44423
44710
|
const img = result.images[0];
|
|
44424
44711
|
const buffer = Buffer.from(img.base64, "base64");
|
|
44425
44712
|
const outputPath = resolve49(process.cwd(), options.output);
|
|
44426
|
-
await
|
|
44427
|
-
await
|
|
44713
|
+
await mkdir23(dirname20(outputPath), { recursive: true });
|
|
44714
|
+
await writeImageFile(outputPath, buffer);
|
|
44428
44715
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
44429
44716
|
} catch (err) {
|
|
44430
44717
|
saveSpinner.fail(
|
|
@@ -44462,6 +44749,7 @@ Examples:
|
|
|
44462
44749
|
options.ratio = "1:1";
|
|
44463
44750
|
}
|
|
44464
44751
|
const result = await grok.generateImage(prompt3, {
|
|
44752
|
+
...resolveGrokImageModel(options.model),
|
|
44465
44753
|
aspectRatio: options.ratio || "1:1",
|
|
44466
44754
|
n: parseInt(options.count)
|
|
44467
44755
|
});
|
|
@@ -44483,14 +44771,16 @@ Examples:
|
|
|
44483
44771
|
} else {
|
|
44484
44772
|
throw new Error("No image data available");
|
|
44485
44773
|
}
|
|
44486
|
-
await
|
|
44487
|
-
await
|
|
44774
|
+
await mkdir23(dirname20(outputPath), { recursive: true });
|
|
44775
|
+
await writeImageFile(outputPath, buffer);
|
|
44488
44776
|
}
|
|
44489
44777
|
outputSuccess({
|
|
44490
44778
|
command: "generate image",
|
|
44491
44779
|
startedAt,
|
|
44780
|
+
...estimateImageCostUsd("grok", options.model, result.images.length),
|
|
44492
44781
|
data: {
|
|
44493
44782
|
provider: "grok",
|
|
44783
|
+
modelId: resolveGrokImageModel(options.model).model,
|
|
44494
44784
|
images: result.images.map((img) => ({ url: img.url })),
|
|
44495
44785
|
outputPath
|
|
44496
44786
|
}
|
|
@@ -44524,8 +44814,8 @@ Examples:
|
|
|
44524
44814
|
throw new Error("No image data available");
|
|
44525
44815
|
}
|
|
44526
44816
|
const outputPath = resolve49(process.cwd(), options.output);
|
|
44527
|
-
await
|
|
44528
|
-
await
|
|
44817
|
+
await mkdir23(dirname20(outputPath), { recursive: true });
|
|
44818
|
+
await writeImageFile(outputPath, buffer);
|
|
44529
44819
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
44530
44820
|
} catch (err) {
|
|
44531
44821
|
saveSpinner.fail(
|
|
@@ -44536,7 +44826,7 @@ Examples:
|
|
|
44536
44826
|
} else if (provider === "runway") {
|
|
44537
44827
|
const { spawn: spawn2 } = await import("child_process");
|
|
44538
44828
|
const __filename = fileURLToPath(import.meta.url);
|
|
44539
|
-
const __dirname =
|
|
44829
|
+
const __dirname = dirname20(__filename);
|
|
44540
44830
|
const scriptPath = resolve49(
|
|
44541
44831
|
__dirname,
|
|
44542
44832
|
"../../../../.claude/skills/runway-video/scripts/image.py"
|
|
@@ -44607,6 +44897,8 @@ var init_image = __esm({
|
|
|
44607
44897
|
init_validate();
|
|
44608
44898
|
init_provider_resolver();
|
|
44609
44899
|
init_openai_image2();
|
|
44900
|
+
init_image_cost();
|
|
44901
|
+
init_image_file();
|
|
44610
44902
|
}
|
|
44611
44903
|
});
|
|
44612
44904
|
|
|
@@ -45555,11 +45847,11 @@ var init_dist3 = __esm({
|
|
|
45555
45847
|
|
|
45556
45848
|
// src/commands/generate/video.ts
|
|
45557
45849
|
import { resolve as resolve50 } from "node:path";
|
|
45558
|
-
import { readFile as readFile33, writeFile as
|
|
45850
|
+
import { readFile as readFile33, writeFile as writeFile35 } from "node:fs/promises";
|
|
45559
45851
|
function registerVideoCommand(parent) {
|
|
45560
45852
|
parent.command("video").alias("vid").description("Generate video using AI (Seedance, Grok, Kling, Runway, Veo, or Gemini Omni)").argument("[prompt]", "Text prompt describing the video (interactive if omitted)").option(
|
|
45561
45853
|
"-p, --provider <provider>",
|
|
45562
|
-
"Provider: seedance (ByteDance Seedance 2.0 via fal.ai), grok, kling, runway,
|
|
45854
|
+
"Provider: seedance (ByteDance Seedance 2.0 via fal.ai), grok, kling, runway, omni (Gemini Omni 1.1 Flash; Google default), veo (Veo 3.1 preview, shuts down 2026-10-22). `fal` is a deprecated v0.x alias for seedance and will be removed in 1.0."
|
|
45563
45855
|
).option(
|
|
45564
45856
|
"-k, --api-key <key>",
|
|
45565
45857
|
"API key (or set FAL_API_KEY / XAI_API_KEY / RUNWAY_API_SECRET / KLING_API_KEY / GOOGLE_API_KEY env)"
|
|
@@ -45572,12 +45864,12 @@ function registerVideoCommand(parent) {
|
|
|
45572
45864
|
"Aspect ratio: 16:9, 9:16, or 1:1 (auto-detected from image if omitted)"
|
|
45573
45865
|
).option("--seed <number>", "Random seed for reproducibility (Runway only)").option("--mode <mode>", "Generation mode: std or pro (Kling only)", "std").option(
|
|
45574
45866
|
"--seedance-model <model>",
|
|
45575
|
-
"Seedance variant: quality
|
|
45867
|
+
"Seedance variant: quality (2.0), fast, or 2.5 (fal.ai only)",
|
|
45576
45868
|
"quality"
|
|
45577
|
-
).option("--negative <prompt>", "Negative prompt - what to avoid (Kling/Veo)").option("--resolution <res>", "Video resolution: 480p, 720p, 1080p, or 4k depending on provider").option("--last-frame <path>", "Last frame image for frame interpolation (Veo) or Seedance end frame").option("--end-image <path>", "Ending frame image for Seedance image-to-video").option(
|
|
45869
|
+
).option("--grok-model <model>", "Grok video model: 1.5 (default), lite, classic", "1.5").option("--kling-model <model>", "Kling model: v3 (default), v2.6, v2.5-turbo", "v3").option("--negative <prompt>", "Negative prompt - what to avoid (Kling/Veo)").option("--resolution <res>", "Video resolution: 480p, 720p, 1080p, or 4k depending on provider").option("--last-frame <path>", "Last frame image for frame interpolation (Veo) or Seedance end frame").option("--end-image <path>", "Ending frame image for Seedance image-to-video").option(
|
|
45578
45870
|
"--ref-images <paths...>",
|
|
45579
45871
|
"Reference images for Seedance reference-to-video or Veo character consistency"
|
|
45580
|
-
).option("--ref-videos <paths...>", "Reference videos for Seedance reference-to-video").option("--ref-audio <paths...>", "Reference audio for Seedance reference-to-video").option("--no-generate-audio", "Disable native audio when the provider supports it").option("--person <mode>", "Person generation: allow_all, allow_adult (Veo only)").option("--veo-model <model>", "Veo model: 3.
|
|
45872
|
+
).option("--ref-videos <paths...>", "Reference videos for Seedance reference-to-video").option("--ref-audio <paths...>", "Reference audio for Seedance reference-to-video").option("--no-generate-audio", "Disable native audio when the provider supports it").option("--person <mode>", "Person generation: allow_all, allow_adult (Veo only)").option("--veo-model <model>", "Veo model: 3.1, 3.1-fast (default: 3.1-fast)", "3.1-fast").option(
|
|
45581
45873
|
"--runway-model <model>",
|
|
45582
45874
|
"Runway model: gen4.5 (default, text+image-to-video), gen4_turbo (image-to-video only)",
|
|
45583
45875
|
"gen4.5"
|
|
@@ -45638,7 +45930,7 @@ Examples:
|
|
|
45638
45930
|
exitWithError(
|
|
45639
45931
|
usageError(
|
|
45640
45932
|
`Invalid provider: ${provider}`,
|
|
45641
|
-
"Available providers: seedance, grok, kling, runway,
|
|
45933
|
+
"Available providers: seedance, grok, kling, runway, omni, veo. `fal` is a deprecated alias for seedance."
|
|
45642
45934
|
)
|
|
45643
45935
|
);
|
|
45644
45936
|
}
|
|
@@ -45705,14 +45997,16 @@ Examples:
|
|
|
45705
45997
|
log(`${provider} does not support 1:1 \u2014 falling back to 16:9`);
|
|
45706
45998
|
options.ratio = "16:9";
|
|
45707
45999
|
}
|
|
46000
|
+
try {
|
|
46001
|
+
if (provider === "seedance" || provider === "fal") resolveSeedanceVariant(options.seedanceModel);
|
|
46002
|
+
if (provider === "grok") resolveGrokVideoModel(options.grokModel);
|
|
46003
|
+
if (provider === "kling") resolveKlingModel(options.klingModel);
|
|
46004
|
+
if (provider === "veo") resolveVeoModel(options.veoModel);
|
|
46005
|
+
} catch (err) {
|
|
46006
|
+
exitWithError(usageError(err instanceof Error ? err.message : String(err)));
|
|
46007
|
+
}
|
|
45708
46008
|
if (options.dryRun) {
|
|
45709
|
-
const costUsd = provider === "seedance" || provider === "fal" ?
|
|
45710
|
-
durationSec: Number(options.duration) || 5,
|
|
45711
|
-
resolution: options.resolution,
|
|
45712
|
-
aspectRatio: options.ratio,
|
|
45713
|
-
fast: options.seedanceModel === "fast",
|
|
45714
|
-
hasVideoReference: Boolean(options.refVideos)
|
|
45715
|
-
}) : void 0;
|
|
46009
|
+
const costUsd = provider === "seedance" || provider === "fal" ? realRunCost(provider, options).costUsd : void 0;
|
|
45716
46010
|
outputSuccess({
|
|
45717
46011
|
command: "generate video",
|
|
45718
46012
|
startedAt,
|
|
@@ -45730,6 +46024,8 @@ Examples:
|
|
|
45730
46024
|
resolution: options.resolution,
|
|
45731
46025
|
veoModel: options.veoModel,
|
|
45732
46026
|
seedanceModel: options.seedanceModel,
|
|
46027
|
+
grokModel: options.grokModel,
|
|
46028
|
+
klingModel: options.klingModel,
|
|
45733
46029
|
refImages: options.refImages,
|
|
45734
46030
|
refVideos: options.refVideos,
|
|
45735
46031
|
refAudio: options.refAudio,
|
|
@@ -45751,7 +46047,7 @@ Examples:
|
|
|
45751
46047
|
runway: "Runway",
|
|
45752
46048
|
kling: "Kling",
|
|
45753
46049
|
veo: "Veo",
|
|
45754
|
-
omni: "Gemini Omni
|
|
46050
|
+
omni: "Gemini Omni 1.1 Flash",
|
|
45755
46051
|
grok: "Grok",
|
|
45756
46052
|
seedance: "Seedance 2.0 via fal.ai"
|
|
45757
46053
|
};
|
|
@@ -45850,6 +46146,7 @@ Examples:
|
|
|
45850
46146
|
}
|
|
45851
46147
|
result = await kling.generateVideo(prompt3, {
|
|
45852
46148
|
prompt: prompt3,
|
|
46149
|
+
model: resolveKlingModel(options.klingModel),
|
|
45853
46150
|
referenceImage: klingImage,
|
|
45854
46151
|
duration: parseInt(options.duration),
|
|
45855
46152
|
aspectRatio: options.ratio,
|
|
@@ -45899,12 +46196,7 @@ Examples:
|
|
|
45899
46196
|
} else if (provider === "veo") {
|
|
45900
46197
|
const gemini = new GeminiProvider();
|
|
45901
46198
|
await gemini.initialize({ apiKey });
|
|
45902
|
-
const
|
|
45903
|
-
"3.0": "veo-3.0-generate-preview",
|
|
45904
|
-
"3.1": "veo-3.1-generate-preview",
|
|
45905
|
-
"3.1-fast": "veo-3.1-fast-generate-preview"
|
|
45906
|
-
};
|
|
45907
|
-
const veoModel = veoModelMap[options.veoModel] || "veo-3.1-fast-generate-preview";
|
|
46199
|
+
const veoModel = resolveVeoModel(options.veoModel);
|
|
45908
46200
|
const veoDuration = parseInt(options.duration) <= 6 ? 6 : 8;
|
|
45909
46201
|
let lastFrame;
|
|
45910
46202
|
if (options.lastFrame) {
|
|
@@ -45978,9 +46270,12 @@ Examples:
|
|
|
45978
46270
|
await grok.initialize({ apiKey });
|
|
45979
46271
|
result = await grok.generateVideo(prompt3, {
|
|
45980
46272
|
prompt: prompt3,
|
|
46273
|
+
model: resolveGrokVideoModel(options.grokModel),
|
|
45981
46274
|
referenceImage,
|
|
45982
46275
|
duration: parseInt(options.duration),
|
|
45983
|
-
aspectRatio: options.ratio
|
|
46276
|
+
aspectRatio: options.ratio,
|
|
46277
|
+
resolution: options.resolution,
|
|
46278
|
+
generateAudio: options.generateAudio
|
|
45984
46279
|
});
|
|
45985
46280
|
if (result.status === "failed") {
|
|
45986
46281
|
spinner2.fail(result.error || "Failed to start generation");
|
|
@@ -46070,9 +46365,8 @@ Examples:
|
|
|
46070
46365
|
exitWithError(apiError(message, true));
|
|
46071
46366
|
}
|
|
46072
46367
|
}
|
|
46073
|
-
|
|
46074
|
-
|
|
46075
|
-
const falModel = seedanceModel === "fast" || seedanceModel === "seedance-2.0-fast" ? "seedance-2.0-fast" : "seedance-2.0";
|
|
46368
|
+
const falModel = resolveSeedanceVariant(options.seedanceModel);
|
|
46369
|
+
spinner2.text = `Generating video with fal.ai ${falModel} (this may take 1-3 minutes)...`;
|
|
46076
46370
|
result = await fal.generateVideo(prompt3, {
|
|
46077
46371
|
prompt: prompt3,
|
|
46078
46372
|
referenceImage: seedanceReferences.length > 0 ? void 0 : falImage,
|
|
@@ -46089,11 +46383,20 @@ Examples:
|
|
|
46089
46383
|
} else if (provider === "omni") {
|
|
46090
46384
|
const omni = new OmniProvider();
|
|
46091
46385
|
await omni.initialize({ apiKey });
|
|
46092
|
-
spinner2.text = "Generating video with Gemini Omni
|
|
46386
|
+
spinner2.text = "Generating video with Gemini Omni 1.1 Flash...";
|
|
46387
|
+
let lastFrame;
|
|
46388
|
+
if (options.lastFrame) {
|
|
46389
|
+
const lastFramePath = resolve50(process.cwd(), options.lastFrame);
|
|
46390
|
+
const ext = options.lastFrame.toLowerCase().split(".").pop();
|
|
46391
|
+
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
|
|
46392
|
+
lastFrame = `data:${mimeType};base64,${(await readFile33(lastFramePath)).toString("base64")}`;
|
|
46393
|
+
}
|
|
46093
46394
|
result = await omni.generateVideo(prompt3, {
|
|
46094
46395
|
prompt: prompt3,
|
|
46095
46396
|
referenceImage,
|
|
46096
|
-
|
|
46397
|
+
lastFrame,
|
|
46398
|
+
aspectRatio: options.ratio,
|
|
46399
|
+
resolution: options.resolution
|
|
46097
46400
|
});
|
|
46098
46401
|
finalResult = result;
|
|
46099
46402
|
}
|
|
@@ -46107,14 +46410,14 @@ Examples:
|
|
|
46107
46410
|
if (options.output && finalResult.videoUrl) {
|
|
46108
46411
|
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
46109
46412
|
outputPath = resolve50(process.cwd(), options.output);
|
|
46110
|
-
await
|
|
46413
|
+
await writeFile35(outputPath, buffer);
|
|
46111
46414
|
}
|
|
46112
46415
|
const cost = realRunCost(provider, options);
|
|
46113
46416
|
outputSuccess({
|
|
46114
46417
|
command: "generate video",
|
|
46115
46418
|
startedAt,
|
|
46116
46419
|
costUsd: cost.costUsd,
|
|
46117
|
-
warnings: cost.warnings,
|
|
46420
|
+
warnings: provider === "veo" ? [VEO_SHUTDOWN_WARNING, ...cost.warnings] : cost.warnings,
|
|
46118
46421
|
data: {
|
|
46119
46422
|
provider,
|
|
46120
46423
|
taskId: result?.id,
|
|
@@ -46126,6 +46429,9 @@ Examples:
|
|
|
46126
46429
|
return;
|
|
46127
46430
|
}
|
|
46128
46431
|
console.log();
|
|
46432
|
+
if (provider === "veo") {
|
|
46433
|
+
console.log(source_default.yellow(VEO_SHUTDOWN_WARNING));
|
|
46434
|
+
}
|
|
46129
46435
|
if (finalResult.videoUrl) {
|
|
46130
46436
|
console.log(`Video URL: ${finalResult.videoUrl}`);
|
|
46131
46437
|
}
|
|
@@ -46138,7 +46444,7 @@ Examples:
|
|
|
46138
46444
|
try {
|
|
46139
46445
|
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
46140
46446
|
const outputPath = resolve50(process.cwd(), options.output);
|
|
46141
|
-
await
|
|
46447
|
+
await writeFile35(outputPath, buffer);
|
|
46142
46448
|
downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
46143
46449
|
} catch (err) {
|
|
46144
46450
|
downloadSpinner.fail(
|
|
@@ -46153,12 +46459,14 @@ Examples:
|
|
|
46153
46459
|
}
|
|
46154
46460
|
function realRunCost(provider, options) {
|
|
46155
46461
|
if (provider === "seedance" || provider === "fal") {
|
|
46462
|
+
const variant = resolveSeedanceVariant(options.seedanceModel);
|
|
46156
46463
|
return {
|
|
46157
46464
|
costUsd: estimateSeedanceVideoCostUsd({
|
|
46158
46465
|
durationSec: Number(options.duration) || 5,
|
|
46159
46466
|
resolution: options.resolution,
|
|
46160
46467
|
aspectRatio: options.ratio,
|
|
46161
|
-
fast:
|
|
46468
|
+
fast: variant === "seedance-2.0-fast",
|
|
46469
|
+
v25: variant === "seedance-2.5",
|
|
46162
46470
|
hasVideoReference: Boolean(options.refVideos)
|
|
46163
46471
|
}),
|
|
46164
46472
|
warnings: []
|
|
@@ -46248,6 +46556,7 @@ function printVideoStarted(providerLabel, taskId, taskType) {
|
|
|
46248
46556
|
console.log(`Task ID: ${source_default.bold(taskId)}`);
|
|
46249
46557
|
if (taskType) console.log(`Type: ${taskType}`);
|
|
46250
46558
|
}
|
|
46559
|
+
var VEO_SHUTDOWN_WARNING;
|
|
46251
46560
|
var init_video = __esm({
|
|
46252
46561
|
"src/commands/generate/video.ts"() {
|
|
46253
46562
|
"use strict";
|
|
@@ -46263,6 +46572,7 @@ var init_video = __esm({
|
|
|
46263
46572
|
init_upload_host();
|
|
46264
46573
|
init_ai_helpers();
|
|
46265
46574
|
init_status_jobs();
|
|
46575
|
+
VEO_SHUTDOWN_WARNING = "Veo 3.1 preview models shut down on 2026-10-22. Use `-p omni` (Gemini Omni 1.1 Flash) instead.";
|
|
46266
46576
|
}
|
|
46267
46577
|
});
|
|
46268
46578
|
|
|
@@ -46282,7 +46592,7 @@ var init_sanitize = __esm({
|
|
|
46282
46592
|
|
|
46283
46593
|
// src/commands/generate/storyboard.ts
|
|
46284
46594
|
import { resolve as resolve51 } from "node:path";
|
|
46285
|
-
import { writeFile as
|
|
46595
|
+
import { writeFile as writeFile36 } from "node:fs/promises";
|
|
46286
46596
|
async function executeStoryboard(options) {
|
|
46287
46597
|
const { content, duration, creativity = "low", output, apiKey } = options;
|
|
46288
46598
|
try {
|
|
@@ -46301,7 +46611,7 @@ async function executeStoryboard(options) {
|
|
|
46301
46611
|
let outputPath;
|
|
46302
46612
|
if (output) {
|
|
46303
46613
|
outputPath = resolve51(process.cwd(), output);
|
|
46304
|
-
await
|
|
46614
|
+
await writeFile36(outputPath, JSON.stringify(segments, null, 2), "utf-8");
|
|
46305
46615
|
}
|
|
46306
46616
|
return { success: true, segments, segmentCount: segments.length, outputPath };
|
|
46307
46617
|
} catch (error) {
|
|
@@ -46417,10 +46727,11 @@ var OpenAIAdapter;
|
|
|
46417
46727
|
var init_openai2 = __esm({
|
|
46418
46728
|
"src/agent/adapters/openai.ts"() {
|
|
46419
46729
|
"use strict";
|
|
46730
|
+
init_dist2();
|
|
46420
46731
|
OpenAIAdapter = class {
|
|
46421
46732
|
provider = "openai";
|
|
46422
46733
|
client = null;
|
|
46423
|
-
model = "
|
|
46734
|
+
model = defaultModel("openai", "llm").id;
|
|
46424
46735
|
async initialize(apiKey) {
|
|
46425
46736
|
this.client = new OpenAI({ apiKey });
|
|
46426
46737
|
}
|
|
@@ -46513,10 +46824,11 @@ var ClaudeAdapter;
|
|
|
46513
46824
|
var init_claude2 = __esm({
|
|
46514
46825
|
"src/agent/adapters/claude.ts"() {
|
|
46515
46826
|
"use strict";
|
|
46827
|
+
init_dist2();
|
|
46516
46828
|
ClaudeAdapter = class {
|
|
46517
46829
|
provider = "claude";
|
|
46518
46830
|
client = null;
|
|
46519
|
-
model = "claude
|
|
46831
|
+
model = defaultModel("claude", "llm").id;
|
|
46520
46832
|
async initialize(apiKey) {
|
|
46521
46833
|
this.client = new Anthropic({ apiKey });
|
|
46522
46834
|
}
|
|
@@ -46541,6 +46853,13 @@ var init_claude2 = __esm({
|
|
|
46541
46853
|
content: msg.content
|
|
46542
46854
|
});
|
|
46543
46855
|
} else if (msg.role === "assistant") {
|
|
46856
|
+
if (msg.providerContent) {
|
|
46857
|
+
claudeMessages.push({
|
|
46858
|
+
role: "assistant",
|
|
46859
|
+
content: msg.providerContent
|
|
46860
|
+
});
|
|
46861
|
+
continue;
|
|
46862
|
+
}
|
|
46544
46863
|
const content = [];
|
|
46545
46864
|
if (msg.content) {
|
|
46546
46865
|
content.push({ type: "text", text: msg.content });
|
|
@@ -46562,16 +46881,17 @@ var init_claude2 = __esm({
|
|
|
46562
46881
|
});
|
|
46563
46882
|
}
|
|
46564
46883
|
} else if (msg.role === "tool") {
|
|
46565
|
-
|
|
46566
|
-
|
|
46567
|
-
|
|
46568
|
-
|
|
46569
|
-
|
|
46570
|
-
|
|
46571
|
-
|
|
46572
|
-
|
|
46573
|
-
|
|
46574
|
-
|
|
46884
|
+
const result = {
|
|
46885
|
+
type: "tool_result",
|
|
46886
|
+
tool_use_id: msg.toolCallId,
|
|
46887
|
+
content: msg.content
|
|
46888
|
+
};
|
|
46889
|
+
const last = claudeMessages.at(-1);
|
|
46890
|
+
if (last?.role === "user" && Array.isArray(last.content)) {
|
|
46891
|
+
last.content.push(result);
|
|
46892
|
+
} else {
|
|
46893
|
+
claudeMessages.push({ role: "user", content: [result] });
|
|
46894
|
+
}
|
|
46575
46895
|
}
|
|
46576
46896
|
}
|
|
46577
46897
|
const claudeTools = tools.map((tool) => ({
|
|
@@ -46585,7 +46905,8 @@ var init_claude2 = __esm({
|
|
|
46585
46905
|
}));
|
|
46586
46906
|
const response = await this.client.messages.create({
|
|
46587
46907
|
model: this.model,
|
|
46588
|
-
|
|
46908
|
+
// Thinking tokens count against this cap on Claude 5.x.
|
|
46909
|
+
max_tokens: 16e3,
|
|
46589
46910
|
system: systemPrompt,
|
|
46590
46911
|
messages: claudeMessages,
|
|
46591
46912
|
tools: claudeTools.length > 0 ? claudeTools : void 0
|
|
@@ -46612,7 +46933,8 @@ var init_claude2 = __esm({
|
|
|
46612
46933
|
return {
|
|
46613
46934
|
content: textContent,
|
|
46614
46935
|
toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
46615
|
-
finishReason
|
|
46936
|
+
finishReason,
|
|
46937
|
+
providerContent: response.content
|
|
46616
46938
|
};
|
|
46617
46939
|
}
|
|
46618
46940
|
};
|
|
@@ -46622,17 +46944,51 @@ var init_claude2 = __esm({
|
|
|
46622
46944
|
// src/agent/adapters/gemini.ts
|
|
46623
46945
|
var gemini_exports = {};
|
|
46624
46946
|
__export(gemini_exports, {
|
|
46625
|
-
GeminiAdapter: () => GeminiAdapter
|
|
46947
|
+
GeminiAdapter: () => GeminiAdapter,
|
|
46948
|
+
toGeminiSchema: () => toGeminiSchema
|
|
46626
46949
|
});
|
|
46627
46950
|
import { GoogleGenerativeAI, SchemaType } from "@google/generative-ai";
|
|
46628
|
-
|
|
46951
|
+
function toGeminiSchema(schema) {
|
|
46952
|
+
if (Array.isArray(schema)) return schema.map(toGeminiSchema);
|
|
46953
|
+
if (!schema || typeof schema !== "object") return schema;
|
|
46954
|
+
const out = {};
|
|
46955
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
46956
|
+
if (!GEMINI_SCHEMA_KEYS.has(key)) continue;
|
|
46957
|
+
if (key === "properties" && value && typeof value === "object") {
|
|
46958
|
+
out.properties = Object.fromEntries(
|
|
46959
|
+
Object.entries(value).map(([name, prop]) => [name, toGeminiSchema(prop)])
|
|
46960
|
+
);
|
|
46961
|
+
} else if (key === "items") {
|
|
46962
|
+
out.items = toGeminiSchema(value);
|
|
46963
|
+
} else {
|
|
46964
|
+
out[key] = value;
|
|
46965
|
+
}
|
|
46966
|
+
}
|
|
46967
|
+
return out;
|
|
46968
|
+
}
|
|
46969
|
+
var GEMINI_SCHEMA_KEYS, GeminiAdapter;
|
|
46629
46970
|
var init_gemini2 = __esm({
|
|
46630
46971
|
"src/agent/adapters/gemini.ts"() {
|
|
46631
46972
|
"use strict";
|
|
46973
|
+
init_dist2();
|
|
46974
|
+
GEMINI_SCHEMA_KEYS = /* @__PURE__ */ new Set([
|
|
46975
|
+
"type",
|
|
46976
|
+
"format",
|
|
46977
|
+
"description",
|
|
46978
|
+
"nullable",
|
|
46979
|
+
"enum",
|
|
46980
|
+
"items",
|
|
46981
|
+
"properties",
|
|
46982
|
+
"required",
|
|
46983
|
+
"minItems",
|
|
46984
|
+
"maxItems",
|
|
46985
|
+
"minimum",
|
|
46986
|
+
"maximum"
|
|
46987
|
+
]);
|
|
46632
46988
|
GeminiAdapter = class {
|
|
46633
46989
|
provider = "gemini";
|
|
46634
46990
|
client = null;
|
|
46635
|
-
model =
|
|
46991
|
+
model = GEMINI_AGENT_DEFAULT_TEXT_MODEL;
|
|
46636
46992
|
async initialize(apiKey) {
|
|
46637
46993
|
this.client = new GoogleGenerativeAI(apiKey);
|
|
46638
46994
|
}
|
|
@@ -46654,7 +47010,12 @@ var init_gemini2 = __esm({
|
|
|
46654
47010
|
description: tool.description,
|
|
46655
47011
|
parameters: {
|
|
46656
47012
|
type: SchemaType.OBJECT,
|
|
46657
|
-
properties:
|
|
47013
|
+
properties: Object.fromEntries(
|
|
47014
|
+
Object.entries(tool.parameters.properties).map(([name, prop]) => [
|
|
47015
|
+
name,
|
|
47016
|
+
toGeminiSchema(prop)
|
|
47017
|
+
])
|
|
47018
|
+
),
|
|
46658
47019
|
required: tool.parameters.required
|
|
46659
47020
|
}
|
|
46660
47021
|
}))
|
|
@@ -46673,6 +47034,10 @@ var init_gemini2 = __esm({
|
|
|
46673
47034
|
parts: [{ text: msg.content }]
|
|
46674
47035
|
});
|
|
46675
47036
|
} else if (msg.role === "assistant") {
|
|
47037
|
+
if (msg.providerContent) {
|
|
47038
|
+
geminiContents.push({ role: "model", parts: msg.providerContent });
|
|
47039
|
+
continue;
|
|
47040
|
+
}
|
|
46676
47041
|
const parts = [];
|
|
46677
47042
|
if (msg.content) {
|
|
46678
47043
|
parts.push({ text: msg.content });
|
|
@@ -46694,16 +47059,19 @@ var init_gemini2 = __esm({
|
|
|
46694
47059
|
});
|
|
46695
47060
|
}
|
|
46696
47061
|
} else if (msg.role === "tool") {
|
|
46697
|
-
|
|
46698
|
-
|
|
46699
|
-
|
|
46700
|
-
|
|
46701
|
-
|
|
46702
|
-
|
|
46703
|
-
|
|
46704
|
-
|
|
46705
|
-
|
|
46706
|
-
|
|
47062
|
+
const part = {
|
|
47063
|
+
functionResponse: {
|
|
47064
|
+
name: msg.toolCallId.split(":::")[0] || "unknown",
|
|
47065
|
+
// Extract function name from id
|
|
47066
|
+
response: { result: msg.content }
|
|
47067
|
+
}
|
|
47068
|
+
};
|
|
47069
|
+
const last = geminiContents.at(-1);
|
|
47070
|
+
if (last?.role === "user" && last.parts.every((p) => "functionResponse" in p)) {
|
|
47071
|
+
last.parts.push(part);
|
|
47072
|
+
} else {
|
|
47073
|
+
geminiContents.push({ role: "user", parts: [part] });
|
|
47074
|
+
}
|
|
46707
47075
|
}
|
|
46708
47076
|
}
|
|
46709
47077
|
const result = await model.generateContent({
|
|
@@ -46740,7 +47108,8 @@ var init_gemini2 = __esm({
|
|
|
46740
47108
|
return {
|
|
46741
47109
|
content: textContent,
|
|
46742
47110
|
toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
46743
|
-
finishReason
|
|
47111
|
+
finishReason,
|
|
47112
|
+
providerContent: candidate.content.parts
|
|
46744
47113
|
};
|
|
46745
47114
|
}
|
|
46746
47115
|
};
|
|
@@ -46940,10 +47309,11 @@ var XAIAdapter;
|
|
|
46940
47309
|
var init_xai = __esm({
|
|
46941
47310
|
"src/agent/adapters/xai.ts"() {
|
|
46942
47311
|
"use strict";
|
|
47312
|
+
init_dist2();
|
|
46943
47313
|
XAIAdapter = class {
|
|
46944
47314
|
provider = "xai";
|
|
46945
47315
|
client = null;
|
|
46946
|
-
model = "grok
|
|
47316
|
+
model = defaultModel("grok", "llm").id;
|
|
46947
47317
|
async initialize(apiKey) {
|
|
46948
47318
|
this.client = new OpenAI2({
|
|
46949
47319
|
apiKey,
|
|
@@ -47243,7 +47613,7 @@ __export(detect_exports, {
|
|
|
47243
47613
|
executeDetectScenes: () => executeDetectScenes,
|
|
47244
47614
|
executeDetectSilence: () => executeDetectSilence
|
|
47245
47615
|
});
|
|
47246
|
-
import { readFile as readFile38, writeFile as
|
|
47616
|
+
import { readFile as readFile38, writeFile as writeFile40 } from "node:fs/promises";
|
|
47247
47617
|
import { resolve as resolve56, basename as basename15 } from "node:path";
|
|
47248
47618
|
async function executeDetectScenes(options) {
|
|
47249
47619
|
try {
|
|
@@ -47282,7 +47652,7 @@ async function executeDetectScenes(options) {
|
|
|
47282
47652
|
}));
|
|
47283
47653
|
if (options.outputPath) {
|
|
47284
47654
|
const outputPath = resolve56(process.cwd(), options.outputPath);
|
|
47285
|
-
await
|
|
47655
|
+
await writeFile40(outputPath, JSON.stringify({ source: absPath, totalDuration, threshold, scenes: result }, null, 2), "utf-8");
|
|
47286
47656
|
}
|
|
47287
47657
|
return { success: true, scenes: result, totalDuration };
|
|
47288
47658
|
} catch (error) {
|
|
@@ -47329,7 +47699,7 @@ async function executeDetectSilence(options) {
|
|
|
47329
47699
|
}
|
|
47330
47700
|
if (options.outputPath) {
|
|
47331
47701
|
const outputPath = resolve56(process.cwd(), options.outputPath);
|
|
47332
|
-
await
|
|
47702
|
+
await writeFile40(outputPath, JSON.stringify({ source: absPath, silences }, null, 2), "utf-8");
|
|
47333
47703
|
}
|
|
47334
47704
|
return { success: true, silences };
|
|
47335
47705
|
} catch (error) {
|
|
@@ -47378,7 +47748,7 @@ async function executeDetectBeats(options) {
|
|
|
47378
47748
|
}
|
|
47379
47749
|
if (options.outputPath) {
|
|
47380
47750
|
const outputPath = resolve56(process.cwd(), options.outputPath);
|
|
47381
|
-
await
|
|
47751
|
+
await writeFile40(outputPath, JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2), "utf-8");
|
|
47382
47752
|
}
|
|
47383
47753
|
return { success: true, beats, beatCount: beats.length };
|
|
47384
47754
|
} catch (error) {
|
|
@@ -47482,7 +47852,7 @@ var init_detect = __esm({
|
|
|
47482
47852
|
duration: (i < scenes.length - 1 ? scenes[i + 1].timestamp : totalDuration) - s.timestamp
|
|
47483
47853
|
}))
|
|
47484
47854
|
};
|
|
47485
|
-
await
|
|
47855
|
+
await writeFile40(outputPath, JSON.stringify(result, null, 2), "utf-8");
|
|
47486
47856
|
console.log(source_default.green(`Saved to: ${outputPath}`));
|
|
47487
47857
|
}
|
|
47488
47858
|
if (options.project) {
|
|
@@ -47512,7 +47882,7 @@ var init_detect = __esm({
|
|
|
47512
47882
|
sourceEndOffset: end
|
|
47513
47883
|
});
|
|
47514
47884
|
}
|
|
47515
|
-
await
|
|
47885
|
+
await writeFile40(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
47516
47886
|
console.log(source_default.green(`Added ${scenes.length} clips to project`));
|
|
47517
47887
|
}
|
|
47518
47888
|
} catch (error) {
|
|
@@ -47594,7 +47964,7 @@ var init_detect = __esm({
|
|
|
47594
47964
|
console.log();
|
|
47595
47965
|
if (options.output) {
|
|
47596
47966
|
const outputPath = resolve56(process.cwd(), options.output);
|
|
47597
|
-
await
|
|
47967
|
+
await writeFile40(
|
|
47598
47968
|
outputPath,
|
|
47599
47969
|
JSON.stringify({ source: absPath, silences }, null, 2),
|
|
47600
47970
|
"utf-8"
|
|
@@ -47679,7 +48049,7 @@ var init_detect = __esm({
|
|
|
47679
48049
|
console.log();
|
|
47680
48050
|
if (options.output) {
|
|
47681
48051
|
const outputPath = resolve56(process.cwd(), options.output);
|
|
47682
|
-
await
|
|
48052
|
+
await writeFile40(
|
|
47683
48053
|
outputPath,
|
|
47684
48054
|
JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2),
|
|
47685
48055
|
"utf-8"
|
|
@@ -51762,8 +52132,9 @@ var EXPLICIT_COMMAND_METADATA = {
|
|
|
51762
52132
|
schema: { surface: "agent", note: "Machine-readable command discovery." },
|
|
51763
52133
|
completion: { surface: "advanced", note: "Shell ergonomics helper." },
|
|
51764
52134
|
agent: {
|
|
51765
|
-
surface: "
|
|
51766
|
-
|
|
52135
|
+
surface: "legacy",
|
|
52136
|
+
replacement: "a host agent (Claude Code, Codex, Cursor) or the MCP server via `vibe host setup`",
|
|
52137
|
+
note: "Deprecated built-in REPL, removed before 1.0."
|
|
51767
52138
|
},
|
|
51768
52139
|
"design.validate": { surface: "public", note: "Validate the DESIGN.md visual contract." },
|
|
51769
52140
|
"generate.image": { surface: "public" },
|
|
@@ -52300,8 +52671,8 @@ init_tts_resolve();
|
|
|
52300
52671
|
init_scene_project();
|
|
52301
52672
|
init_project_config();
|
|
52302
52673
|
init_cost_tier();
|
|
52303
|
-
import { resolve as resolve15, relative as relative5, dirname as
|
|
52304
|
-
import { mkdir as
|
|
52674
|
+
import { resolve as resolve15, relative as relative5, dirname as dirname5 } from "node:path";
|
|
52675
|
+
import { mkdir as mkdir8, readFile as readFile13, writeFile as writeFile13, access as access4, copyFile as copyFile2 } from "node:fs/promises";
|
|
52305
52676
|
import { existsSync as existsSync12 } from "node:fs";
|
|
52306
52677
|
|
|
52307
52678
|
// src/commands/_shared/scene-html-emit.ts
|
|
@@ -52781,7 +53152,7 @@ init_storyboard_parse();
|
|
|
52781
53152
|
init_storyboard_source();
|
|
52782
53153
|
init_root_sync();
|
|
52783
53154
|
import { existsSync as existsSync10 } from "node:fs";
|
|
52784
|
-
import { mkdir as
|
|
53155
|
+
import { mkdir as mkdir7, writeFile as writeFile11 } from "node:fs/promises";
|
|
52785
53156
|
import { join as join10, resolve as resolve12 } from "node:path";
|
|
52786
53157
|
async function executeSceneSubmit(opts) {
|
|
52787
53158
|
const projectDir = resolve12(opts.projectDir);
|
|
@@ -52875,7 +53246,7 @@ async function executeSceneSubmit(opts) {
|
|
|
52875
53246
|
return { ...base, success: true };
|
|
52876
53247
|
}
|
|
52877
53248
|
const absPath = join10(projectDir, scenePath);
|
|
52878
|
-
await
|
|
53249
|
+
await mkdir7(join10(projectDir, "compositions"), { recursive: true });
|
|
52879
53250
|
await writeFile11(absPath, html.endsWith("\n") ? html : `${html}
|
|
52880
53251
|
`, "utf-8");
|
|
52881
53252
|
return {
|
|
@@ -53466,7 +53837,7 @@ async function executeSceneAdd(opts) {
|
|
|
53466
53837
|
}
|
|
53467
53838
|
audioRelPath = `assets/narration-${id}.${ext}`;
|
|
53468
53839
|
audioAbsPath = resolve15(projectDir, audioRelPath);
|
|
53469
|
-
await
|
|
53840
|
+
await mkdir8(dirname5(audioAbsPath), { recursive: true });
|
|
53470
53841
|
await copyFile2(sourceAbs, audioAbsPath);
|
|
53471
53842
|
try {
|
|
53472
53843
|
narrationDuration = await getAudioDuration(audioAbsPath);
|
|
@@ -53499,7 +53870,7 @@ async function executeSceneAdd(opts) {
|
|
|
53499
53870
|
}
|
|
53500
53871
|
audioRelPath = `assets/narration-${id}.${resolution.audioExtension}`;
|
|
53501
53872
|
audioAbsPath = resolve15(projectDir, audioRelPath);
|
|
53502
|
-
await
|
|
53873
|
+
await mkdir8(dirname5(audioAbsPath), { recursive: true });
|
|
53503
53874
|
await writeFile13(audioAbsPath, tts.audioBuffer);
|
|
53504
53875
|
try {
|
|
53505
53876
|
narrationDuration = await getAudioDuration(audioAbsPath);
|
|
@@ -53562,7 +53933,7 @@ async function executeSceneAdd(opts) {
|
|
|
53562
53933
|
const img = imageResult.images[0];
|
|
53563
53934
|
imageRelPath = `assets/scene-${id}.png`;
|
|
53564
53935
|
imageAbsPath = resolve15(projectDir, imageRelPath);
|
|
53565
|
-
await
|
|
53936
|
+
await mkdir8(dirname5(imageAbsPath), { recursive: true });
|
|
53566
53937
|
let buffer;
|
|
53567
53938
|
if (img.base64) {
|
|
53568
53939
|
buffer = Buffer.from(img.base64, "base64");
|
|
@@ -53589,7 +53960,7 @@ async function executeSceneAdd(opts) {
|
|
|
53589
53960
|
}
|
|
53590
53961
|
imageRelPath = `assets/scene-${id}.png`;
|
|
53591
53962
|
imageAbsPath = resolve15(projectDir, imageRelPath);
|
|
53592
|
-
await
|
|
53963
|
+
await mkdir8(dirname5(imageAbsPath), { recursive: true });
|
|
53593
53964
|
const buffer = Buffer.from(imageResult.images[0].base64, "base64");
|
|
53594
53965
|
await writeFile13(imageAbsPath, buffer);
|
|
53595
53966
|
}
|
|
@@ -53608,7 +53979,7 @@ async function executeSceneAdd(opts) {
|
|
|
53608
53979
|
}
|
|
53609
53980
|
lottieRelPath = `assets/lottie-${id}.${ext}`;
|
|
53610
53981
|
lottieAbsPath = resolve15(projectDir, lottieRelPath);
|
|
53611
|
-
await
|
|
53982
|
+
await mkdir8(dirname5(lottieAbsPath), { recursive: true });
|
|
53612
53983
|
await copyFile2(sourceAbs, lottieAbsPath);
|
|
53613
53984
|
lottieInput = {
|
|
53614
53985
|
src: lottieRelPath,
|
|
@@ -53678,7 +54049,7 @@ async function executeSceneAdd(opts) {
|
|
|
53678
54049
|
transcript: transcriptWords,
|
|
53679
54050
|
lottie: lottieInput
|
|
53680
54051
|
});
|
|
53681
|
-
await
|
|
54052
|
+
await mkdir8(dirname5(scenePath), { recursive: true });
|
|
53682
54053
|
await writeFile13(scenePath, sceneHtml, "utf-8");
|
|
53683
54054
|
opts.onProgress?.("Updating root composition...");
|
|
53684
54055
|
let start = 0;
|
|
@@ -53895,6 +54266,7 @@ init_scene_build();
|
|
|
53895
54266
|
init_install_skill();
|
|
53896
54267
|
init_compose_prompts();
|
|
53897
54268
|
init_scene_repair();
|
|
54269
|
+
init_build_video_providers();
|
|
53898
54270
|
var SCENE_PRESETS2 = [
|
|
53899
54271
|
"simple",
|
|
53900
54272
|
"announcement",
|
|
@@ -54294,12 +54666,12 @@ var sceneBuildSchema = external_exports.object({
|
|
|
54294
54666
|
"TTS provider override. Default 'auto' (elevenlabs key > openai key > local kokoro)."
|
|
54295
54667
|
),
|
|
54296
54668
|
voice: external_exports.string().optional().describe("TTS voice id (provider-specific)."),
|
|
54297
|
-
imageProvider: external_exports.enum(["openai"]).optional().describe("Image provider for backdrops. Default 'openai' (gpt-image-2)."),
|
|
54298
|
-
videoProvider: external_exports.enum(
|
|
54669
|
+
imageProvider: external_exports.enum(["openai"]).optional().describe("Image provider for backdrops. Default 'openai' (gpt-image-2.5-sunburst)."),
|
|
54670
|
+
videoProvider: external_exports.enum(BUILD_VIDEO_PROVIDERS).optional().describe("Video provider for per-beat video cues. Default seedance."),
|
|
54299
54671
|
musicProvider: external_exports.enum(["elevenlabs", "replicate"]).optional().describe("Music provider for per-beat music cues. Default elevenlabs."),
|
|
54300
54672
|
imageQuality: external_exports.enum(["standard", "hd"]).optional().describe("OpenAI image quality. Default 'standard'."),
|
|
54301
54673
|
imageModel: external_exports.string().optional().describe(
|
|
54302
|
-
"Image model for keyframes/backdrops/character sheets (gemini: flash|pro, openai: gpt-image-2). Provider default when omitted."
|
|
54674
|
+
"Image model for keyframes/backdrops/character sheets (gemini: flash|lite|pro, openai: gpt-image-2.5-sunburst|gpt-image-2.5-flare|gpt-image-2). Provider default when omitted."
|
|
54303
54675
|
),
|
|
54304
54676
|
imageSize: external_exports.enum(["1024x1024", "1536x1024", "1024x1536"]).optional().describe("OpenAI image size. Default '1536x1024' (cinematic 16:9-ish)."),
|
|
54305
54677
|
maxCostUsd: external_exports.number().optional().describe("Fail before provider spend when estimated cost exceeds this USD cap."),
|
|
@@ -54729,8 +55101,8 @@ init_ai_edit();
|
|
|
54729
55101
|
init_api_key();
|
|
54730
55102
|
init_exec_safe();
|
|
54731
55103
|
init_remotion();
|
|
54732
|
-
import { resolve as resolve37, dirname as
|
|
54733
|
-
import { writeFile as
|
|
55104
|
+
import { resolve as resolve37, dirname as dirname17, basename as basename10 } from "node:path";
|
|
55105
|
+
import { writeFile as writeFile29, mkdir as mkdir20, rm as rm6 } from "node:fs/promises";
|
|
54734
55106
|
import { existsSync as existsSync36 } from "node:fs";
|
|
54735
55107
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
54736
55108
|
var ASS_STYLES = ["karaoke-sweep", "typewriter"];
|
|
@@ -54882,7 +55254,7 @@ async function executeAnimatedCaption(options) {
|
|
|
54882
55254
|
}
|
|
54883
55255
|
const effectiveFontSize = fontSize ?? Math.round(height * 0.04);
|
|
54884
55256
|
const tmpAudioDir = resolve37(tmpdir3(), `vf-ac-${Date.now()}`);
|
|
54885
|
-
await
|
|
55257
|
+
await mkdir20(tmpAudioDir, { recursive: true });
|
|
54886
55258
|
const audioPath = resolve37(tmpAudioDir, "audio.wav");
|
|
54887
55259
|
await execSafe("ffmpeg", [
|
|
54888
55260
|
"-y",
|
|
@@ -54899,21 +55271,21 @@ async function executeAnimatedCaption(options) {
|
|
|
54899
55271
|
], { timeout: 12e4 });
|
|
54900
55272
|
const apiKey = await getApiKey("OPENAI_API_KEY", "OpenAI");
|
|
54901
55273
|
if (!apiKey) {
|
|
54902
|
-
await
|
|
55274
|
+
await rm6(tmpAudioDir, { recursive: true, force: true }).catch(() => {
|
|
54903
55275
|
});
|
|
54904
55276
|
return { success: false, error: "OPENAI_API_KEY required for Whisper transcription. Run 'vibe setup' or set OPENAI_API_KEY in .env" };
|
|
54905
55277
|
}
|
|
54906
55278
|
const transcript = await transcribeWithWords(audioPath, apiKey, language);
|
|
54907
55279
|
if (!transcript.words || transcript.words.length === 0) {
|
|
54908
|
-
await
|
|
55280
|
+
await rm6(tmpAudioDir, { recursive: true, force: true }).catch(() => {
|
|
54909
55281
|
});
|
|
54910
55282
|
return { success: false, error: "No words detected in transcription" };
|
|
54911
55283
|
}
|
|
54912
55284
|
const groups = groupWords(transcript.words, { wordsPerGroup, maxChars });
|
|
54913
55285
|
const absOutputPath = resolve37(process.cwd(), outputPath);
|
|
54914
|
-
const outDir =
|
|
55286
|
+
const outDir = dirname17(absOutputPath);
|
|
54915
55287
|
if (!existsSync36(outDir)) {
|
|
54916
|
-
await
|
|
55288
|
+
await mkdir20(outDir, { recursive: true });
|
|
54917
55289
|
}
|
|
54918
55290
|
if (tier === "ass") {
|
|
54919
55291
|
const assContent = generateASS(
|
|
@@ -54922,7 +55294,7 @@ async function executeAnimatedCaption(options) {
|
|
|
54922
55294
|
{ highlightColor, fontSize: effectiveFontSize, position, width, height }
|
|
54923
55295
|
);
|
|
54924
55296
|
const assPath = resolve37(tmpAudioDir, "captions.ass");
|
|
54925
|
-
await
|
|
55297
|
+
await writeFile29(assPath, assContent, "utf-8");
|
|
54926
55298
|
const escapedAssPath = assPath.replace(/\\/g, "\\\\").replace(/:/g, "\\:");
|
|
54927
55299
|
await execSafe("ffmpeg", [
|
|
54928
55300
|
"-y",
|
|
@@ -54959,12 +55331,12 @@ async function executeAnimatedCaption(options) {
|
|
|
54959
55331
|
outputPath: absOutputPath
|
|
54960
55332
|
});
|
|
54961
55333
|
if (!renderResult.success) {
|
|
54962
|
-
await
|
|
55334
|
+
await rm6(tmpAudioDir, { recursive: true, force: true }).catch(() => {
|
|
54963
55335
|
});
|
|
54964
55336
|
return { success: false, error: renderResult.error };
|
|
54965
55337
|
}
|
|
54966
55338
|
}
|
|
54967
|
-
await
|
|
55339
|
+
await rm6(tmpAudioDir, { recursive: true, force: true }).catch(() => {
|
|
54968
55340
|
});
|
|
54969
55341
|
return {
|
|
54970
55342
|
success: true,
|
|
@@ -55373,7 +55745,7 @@ var editImageTool = defineTool({
|
|
|
55373
55745
|
imagePaths: external_exports.array(external_exports.string()).describe("Input image file path(s)"),
|
|
55374
55746
|
prompt: external_exports.string().describe("Edit instruction"),
|
|
55375
55747
|
output: external_exports.string().optional().describe("Output file path (default: edited.png)"),
|
|
55376
|
-
model: external_exports.enum(["flash", "3.1-flash", "latest", "pro"]).optional().describe("Gemini model (default: flash)"),
|
|
55748
|
+
model: external_exports.enum(["flash", "3.1-flash", "latest", "lite", "pro"]).optional().describe("Gemini model (default: flash = Nano Banana 2)"),
|
|
55377
55749
|
ratio: external_exports.string().optional().describe("Output aspect ratio"),
|
|
55378
55750
|
resolution: external_exports.string().optional().describe("Resolution: 1K, 2K, 4K (Pro only)")
|
|
55379
55751
|
}),
|
|
@@ -57224,7 +57596,7 @@ var generateSoundEffectTool = defineTool({
|
|
|
57224
57596
|
schema: external_exports.object({
|
|
57225
57597
|
prompt: external_exports.string().describe("Description of the sound effect"),
|
|
57226
57598
|
output: external_exports.string().optional().describe("Output audio file path (default: sound-effect.mp3)"),
|
|
57227
|
-
duration: external_exports.number().optional().describe("Duration in seconds (0.5-
|
|
57599
|
+
duration: external_exports.number().optional().describe("Duration in seconds (0.5-30, default: auto)"),
|
|
57228
57600
|
promptInfluence: external_exports.number().optional().describe("Prompt influence 0-1 (default: 0.3)")
|
|
57229
57601
|
}),
|
|
57230
57602
|
async execute(args) {
|
|
@@ -57301,7 +57673,7 @@ var generateImageTool = defineTool({
|
|
|
57301
57673
|
ratio: external_exports.string().optional().describe("Aspect ratio for Gemini (1:1, 16:9, 9:16, 4:3, 3:4, etc.)"),
|
|
57302
57674
|
quality: external_exports.string().optional().describe("Quality for OpenAI: standard, hd"),
|
|
57303
57675
|
count: external_exports.number().optional().describe("Number of images (default: 1)"),
|
|
57304
|
-
model: external_exports.string().optional().describe("
|
|
57676
|
+
model: external_exports.string().optional().describe("Image model. Gemini: flash (default), lite, pro. OpenAI: 2.5 (default), flare, 2, 1.5. Grok: pro")
|
|
57305
57677
|
}),
|
|
57306
57678
|
async execute(args) {
|
|
57307
57679
|
const result = await executeImageGenerate(args);
|
|
@@ -57364,9 +57736,11 @@ var generateVideoTool = defineTool({
|
|
|
57364
57736
|
mode: external_exports.string().optional().describe("Kling mode: std or pro"),
|
|
57365
57737
|
negative: external_exports.string().optional().describe("Negative prompt (Seedance/Kling/Veo)"),
|
|
57366
57738
|
resolution: external_exports.string().optional().describe("Resolution: 480p, 720p, 1080p, or 4k depending on provider"),
|
|
57367
|
-
veoModel: external_exports.string().optional().describe("Veo model: 3.
|
|
57739
|
+
veoModel: external_exports.string().optional().describe("Veo model: 3.1, 3.1-fast"),
|
|
57368
57740
|
runwayModel: external_exports.string().optional().describe("Runway model: gen4.5, gen4_turbo"),
|
|
57369
|
-
seedanceModel: external_exports.string().optional().describe("Seedance variant: quality
|
|
57741
|
+
seedanceModel: external_exports.string().optional().describe("Seedance variant: quality (2.0), fast, or 2.5 (fal.ai only)"),
|
|
57742
|
+
grokModel: external_exports.string().optional().describe("Grok video model: 1.5 (default), lite, classic"),
|
|
57743
|
+
klingModel: external_exports.string().optional().describe("Kling model: v3 (default), v2.6, v2.5-turbo"),
|
|
57370
57744
|
generateAudio: external_exports.boolean().optional().describe("Generate native synchronized audio when supported"),
|
|
57371
57745
|
output: external_exports.string().optional().describe("Output file path (downloads video)"),
|
|
57372
57746
|
wait: external_exports.boolean().optional().describe("Wait for completion (default: true)")
|
|
@@ -57438,7 +57812,7 @@ var generateVideoExtendTool = defineTool({
|
|
|
57438
57812
|
prompt: external_exports.string().optional().describe("Continuation prompt"),
|
|
57439
57813
|
duration: external_exports.number().optional().describe("Duration in seconds"),
|
|
57440
57814
|
negative: external_exports.string().optional().describe("Negative prompt (Kling)"),
|
|
57441
|
-
veoModel: external_exports.string().optional().describe("Veo model: 3.
|
|
57815
|
+
veoModel: external_exports.string().optional().describe("Veo model: 3.1, 3.1-fast"),
|
|
57442
57816
|
output: external_exports.string().optional().describe("Output file path"),
|
|
57443
57817
|
wait: external_exports.boolean().optional().describe("Wait for completion (default: true)")
|
|
57444
57818
|
}),
|
|
@@ -57474,14 +57848,14 @@ var generateTools = [
|
|
|
57474
57848
|
|
|
57475
57849
|
// src/tools/manifest/storyboard.ts
|
|
57476
57850
|
import { existsSync as existsSync44 } from "node:fs";
|
|
57477
|
-
import { readFile as readFile35, writeFile as
|
|
57851
|
+
import { readFile as readFile35, writeFile as writeFile38 } from "node:fs/promises";
|
|
57478
57852
|
import { resolve as resolve53 } from "node:path";
|
|
57479
57853
|
init_storyboard_parse();
|
|
57480
57854
|
init_storyboard_edit();
|
|
57481
57855
|
|
|
57482
57856
|
// src/commands/_shared/storyboard-revise.ts
|
|
57483
57857
|
import { existsSync as existsSync43 } from "node:fs";
|
|
57484
|
-
import { readFile as readFile34, writeFile as
|
|
57858
|
+
import { readFile as readFile34, writeFile as writeFile37 } from "node:fs/promises";
|
|
57485
57859
|
import { join as join24, resolve as resolve52 } from "node:path";
|
|
57486
57860
|
|
|
57487
57861
|
// src/agent/adapters/index.ts
|
|
@@ -57650,7 +58024,7 @@ async function executeStoryboardRevision(opts) {
|
|
|
57650
58024
|
if (loaded.layout === "bundle") {
|
|
57651
58025
|
await rewriteBundleFromMarkdown(projectDir, storyboardMd);
|
|
57652
58026
|
} else {
|
|
57653
|
-
await
|
|
58027
|
+
await writeFile37(storyboardPath, storyboardMd, "utf-8");
|
|
57654
58028
|
}
|
|
57655
58029
|
}
|
|
57656
58030
|
const changedBeats = unique5([...diffChangedBeats(currentStoryboard, storyboardMd), ...payload.changedBeats]);
|
|
@@ -57828,6 +58202,7 @@ function stripUndefined3(value) {
|
|
|
57828
58202
|
|
|
57829
58203
|
// src/tools/manifest/storyboard.ts
|
|
57830
58204
|
init_build_plan();
|
|
58205
|
+
init_build_video_providers();
|
|
57831
58206
|
var PROJECT_DIR_DESCRIPTION3 = "Project directory. Defaults to the surface's cwd; in MCP hosts, relative paths resolve under the configured server workspace.";
|
|
57832
58207
|
var projectDirSchema = external_exports.object({
|
|
57833
58208
|
projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION3)
|
|
@@ -57948,7 +58323,7 @@ var storyboardSetTool = defineTool({
|
|
|
57948
58323
|
value,
|
|
57949
58324
|
unset: args.unset
|
|
57950
58325
|
});
|
|
57951
|
-
await
|
|
58326
|
+
await writeFile38(file.path, next, "utf-8");
|
|
57952
58327
|
return {
|
|
57953
58328
|
success: true,
|
|
57954
58329
|
data: { beat: args.beat, key: args.key },
|
|
@@ -57980,7 +58355,7 @@ var storyboardMoveTool = defineTool({
|
|
|
57980
58355
|
beatId: args.beat,
|
|
57981
58356
|
afterBeatId: args.after
|
|
57982
58357
|
});
|
|
57983
|
-
await
|
|
58358
|
+
await writeFile38(file.path, next, "utf-8");
|
|
57984
58359
|
return {
|
|
57985
58360
|
success: true,
|
|
57986
58361
|
data: { beat: args.beat, after: args.after },
|
|
@@ -58045,7 +58420,7 @@ var planTool = defineTool({
|
|
|
58045
58420
|
imageProvider: external_exports.string().optional().describe("Image provider override."),
|
|
58046
58421
|
imageQuality: external_exports.enum(["standard", "hd"]).optional().describe("Image quality override."),
|
|
58047
58422
|
imageSize: external_exports.string().optional().describe("Image size override."),
|
|
58048
|
-
videoProvider: external_exports.enum(
|
|
58423
|
+
videoProvider: external_exports.enum(BUILD_VIDEO_PROVIDERS).optional().describe("Video provider override."),
|
|
58049
58424
|
musicProvider: external_exports.enum(["elevenlabs", "replicate"]).optional().describe("Music provider override."),
|
|
58050
58425
|
composer: external_exports.enum(["claude", "openai", "gemini"]).optional().describe("Composer provider override."),
|
|
58051
58426
|
force: external_exports.boolean().optional().describe("Plan regeneration even when outputs exist.")
|
|
@@ -58133,13 +58508,13 @@ var designValidateTool = defineTool({
|
|
|
58133
58508
|
var designTools = [designValidateTool];
|
|
58134
58509
|
|
|
58135
58510
|
// src/tools/manifest/remix.ts
|
|
58136
|
-
import { writeFile as
|
|
58511
|
+
import { writeFile as writeFile42 } from "node:fs/promises";
|
|
58137
58512
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
58138
58513
|
import { join as join26 } from "node:path";
|
|
58139
58514
|
|
|
58140
58515
|
// src/commands/ai-highlights.ts
|
|
58141
|
-
import { readFile as readFile37, writeFile as
|
|
58142
|
-
import { resolve as resolve55, dirname as
|
|
58516
|
+
import { readFile as readFile37, writeFile as writeFile39, mkdir as mkdir24 } from "node:fs/promises";
|
|
58517
|
+
import { resolve as resolve55, dirname as dirname21, basename as basename14, extname as extname11 } from "node:path";
|
|
58143
58518
|
import { existsSync as existsSync46 } from "node:fs";
|
|
58144
58519
|
init_dist2();
|
|
58145
58520
|
init_engine();
|
|
@@ -58174,7 +58549,7 @@ async function executeHighlights(options) {
|
|
|
58174
58549
|
if (!existsSync46(absPath)) {
|
|
58175
58550
|
return { success: false, highlights: [], totalDuration: 0, totalHighlightDuration: 0, error: `File not found: ${absPath}` };
|
|
58176
58551
|
}
|
|
58177
|
-
const ext =
|
|
58552
|
+
const ext = extname11(absPath).toLowerCase();
|
|
58178
58553
|
const videoExtensions = [".mp4", ".mov", ".avi", ".mkv", ".webm", ".m4v"];
|
|
58179
58554
|
const isVideo = videoExtensions.includes(ext);
|
|
58180
58555
|
const targetDuration = options.duration;
|
|
@@ -58319,7 +58694,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
|
|
|
58319
58694
|
};
|
|
58320
58695
|
if (options.output) {
|
|
58321
58696
|
const outputPath = resolve55(process.cwd(), options.output);
|
|
58322
|
-
await
|
|
58697
|
+
await writeFile39(outputPath, JSON.stringify({
|
|
58323
58698
|
sourceFile: absPath,
|
|
58324
58699
|
totalDuration: sourceDuration,
|
|
58325
58700
|
criteria: options.criteria || "all",
|
|
@@ -58354,7 +58729,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
|
|
|
58354
58729
|
}
|
|
58355
58730
|
}
|
|
58356
58731
|
const projectPath = resolve55(process.cwd(), options.project);
|
|
58357
|
-
await
|
|
58732
|
+
await writeFile39(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
58358
58733
|
extractResult.projectPath = projectPath;
|
|
58359
58734
|
}
|
|
58360
58735
|
return extractResult;
|
|
@@ -58501,9 +58876,9 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
58501
58876
|
}))
|
|
58502
58877
|
};
|
|
58503
58878
|
}
|
|
58504
|
-
const outputDir = options.outputDir ? resolve55(process.cwd(), options.outputDir) :
|
|
58879
|
+
const outputDir = options.outputDir ? resolve55(process.cwd(), options.outputDir) : dirname21(absPath);
|
|
58505
58880
|
if (options.outputDir && !existsSync46(outputDir)) {
|
|
58506
|
-
await
|
|
58881
|
+
await mkdir24(outputDir, { recursive: true });
|
|
58507
58882
|
}
|
|
58508
58883
|
const result = {
|
|
58509
58884
|
success: true,
|
|
@@ -58511,7 +58886,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
58511
58886
|
};
|
|
58512
58887
|
for (let i = 0; i < selectedHighlights.length; i++) {
|
|
58513
58888
|
const h = selectedHighlights[i];
|
|
58514
|
-
const baseName = basename14(absPath,
|
|
58889
|
+
const baseName = basename14(absPath, extname11(absPath));
|
|
58515
58890
|
const outputPath = resolve55(outputDir, `${baseName}-short-${i + 1}.mp4`);
|
|
58516
58891
|
const { stdout: probeOut } = await execSafe("ffprobe", [
|
|
58517
58892
|
"-v",
|
|
@@ -58581,7 +58956,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
58581
58956
|
// src/pipeline/executor.ts
|
|
58582
58957
|
var import_yaml8 = __toESM(require_dist2(), 1);
|
|
58583
58958
|
import { resolve as resolve57 } from "node:path";
|
|
58584
|
-
import { readFile as readFile39, writeFile as
|
|
58959
|
+
import { readFile as readFile39, writeFile as writeFile41, mkdir as mkdir25 } from "node:fs/promises";
|
|
58585
58960
|
import { existsSync as existsSync47 } from "node:fs";
|
|
58586
58961
|
|
|
58587
58962
|
// src/pipeline/resolver.ts
|
|
@@ -58643,6 +59018,7 @@ function findUnresolvedRefs(params, availableStepIds) {
|
|
|
58643
59018
|
init_output();
|
|
58644
59019
|
init_config();
|
|
58645
59020
|
init_provider_resolver();
|
|
59021
|
+
init_build_video_providers();
|
|
58646
59022
|
var ACTION_METADATA = {
|
|
58647
59023
|
"generate-image": { id: "generate-image", title: "Generate image", category: "generate", command: "generate image", outputs: ["image"] },
|
|
58648
59024
|
"generate-video": { id: "generate-video", title: "Generate video", category: "generate", command: "generate video", outputs: ["video"], requiredKeys: ["provider-dependent"] },
|
|
@@ -58716,7 +59092,7 @@ async function resolvePipelineVideoProvider(provider) {
|
|
|
58716
59092
|
if (explicit === "fal") return "seedance";
|
|
58717
59093
|
if (explicit) return explicit;
|
|
58718
59094
|
await loadProviderDefaults();
|
|
58719
|
-
return resolveProvider("video")?.name ?? "grok";
|
|
59095
|
+
return resolveBuildVideoProvider(resolveProvider("video")?.name ?? "grok");
|
|
58720
59096
|
}
|
|
58721
59097
|
function providerKeyForImage(provider) {
|
|
58722
59098
|
switch (provider) {
|
|
@@ -58742,6 +59118,7 @@ function providerKeyForVideo(provider) {
|
|
|
58742
59118
|
case "runway":
|
|
58743
59119
|
return "runway";
|
|
58744
59120
|
case "veo":
|
|
59121
|
+
case "omni":
|
|
58745
59122
|
return "google";
|
|
58746
59123
|
default:
|
|
58747
59124
|
return void 0;
|
|
@@ -58993,7 +59370,7 @@ var CHECKPOINT_FILE = ".pipeline-state.yaml";
|
|
|
58993
59370
|
async function executePipeline(manifest2, options = {}) {
|
|
58994
59371
|
await ensureActionsRegistered();
|
|
58995
59372
|
const outputDir = resolve57(process.cwd(), options.outputDir || `${manifest2.name}-output`);
|
|
58996
|
-
await
|
|
59373
|
+
await mkdir25(outputDir, { recursive: true });
|
|
58997
59374
|
const completedSteps = /* @__PURE__ */ new Map();
|
|
58998
59375
|
const results = [];
|
|
58999
59376
|
const startTime = Date.now();
|
|
@@ -59118,7 +59495,7 @@ async function executePipeline(manifest2, options = {}) {
|
|
|
59118
59495
|
data: s.data
|
|
59119
59496
|
}))
|
|
59120
59497
|
};
|
|
59121
|
-
await
|
|
59498
|
+
await writeFile41(
|
|
59122
59499
|
resolve57(outputDir, CHECKPOINT_FILE),
|
|
59123
59500
|
(0, import_yaml8.stringify)(checkpoint, { indent: 2 }),
|
|
59124
59501
|
"utf-8"
|
|
@@ -59273,7 +59650,7 @@ var pipelineRunTool = defineTool({
|
|
|
59273
59650
|
let tempPath;
|
|
59274
59651
|
if (args.pipelineYaml) {
|
|
59275
59652
|
tempPath = join26(tmpdir4(), `vibe-mcp-pipeline-${Date.now()}.yaml`);
|
|
59276
|
-
await
|
|
59653
|
+
await writeFile42(tempPath, args.pipelineYaml, "utf-8");
|
|
59277
59654
|
resolvedPath = tempPath;
|
|
59278
59655
|
}
|
|
59279
59656
|
try {
|
|
@@ -59408,7 +59785,7 @@ var detectTools = [
|
|
|
59408
59785
|
];
|
|
59409
59786
|
|
|
59410
59787
|
// src/tools/manifest/timeline.ts
|
|
59411
|
-
import { mkdir as
|
|
59788
|
+
import { mkdir as mkdir26, writeFile as writeFile44 } from "node:fs/promises";
|
|
59412
59789
|
import { basename as basename16, resolve as resolve58 } from "node:path";
|
|
59413
59790
|
init_engine();
|
|
59414
59791
|
init_project_resolver();
|
|
@@ -59416,7 +59793,7 @@ init_project_resolver();
|
|
|
59416
59793
|
// src/tools/manifest/_project-io.ts
|
|
59417
59794
|
init_engine();
|
|
59418
59795
|
init_project_resolver();
|
|
59419
|
-
import { readFile as readFile40, writeFile as
|
|
59796
|
+
import { readFile as readFile40, writeFile as writeFile43 } from "node:fs/promises";
|
|
59420
59797
|
async function loadProject(projectPath, cwd) {
|
|
59421
59798
|
const absPath = await resolveTimelineFile(projectPath, cwd);
|
|
59422
59799
|
const content = await readFile40(absPath, "utf-8");
|
|
@@ -59424,7 +59801,7 @@ async function loadProject(projectPath, cwd) {
|
|
|
59424
59801
|
return { project: Project.fromJSON(data), absPath };
|
|
59425
59802
|
}
|
|
59426
59803
|
async function saveProject(absPath, project) {
|
|
59427
|
-
await
|
|
59804
|
+
await writeFile43(absPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
59428
59805
|
}
|
|
59429
59806
|
|
|
59430
59807
|
// src/tools/manifest/timeline.ts
|
|
@@ -59464,10 +59841,10 @@ var timelineCreateTool = defineTool({
|
|
|
59464
59841
|
outputPath = resolve58(ctx.workingDirectory, args.outputPath);
|
|
59465
59842
|
} else {
|
|
59466
59843
|
const dirPath = resolve58(ctx.workingDirectory, args.name);
|
|
59467
|
-
await
|
|
59844
|
+
await mkdir26(dirPath, { recursive: true });
|
|
59468
59845
|
outputPath = resolve58(dirPath, TIMELINE_FILENAME);
|
|
59469
59846
|
}
|
|
59470
|
-
await
|
|
59847
|
+
await writeFile44(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
59471
59848
|
return {
|
|
59472
59849
|
success: true,
|
|
59473
59850
|
data: { name: projectName, outputPath },
|
|
@@ -59764,7 +60141,7 @@ var timelineTools = [
|
|
|
59764
60141
|
|
|
59765
60142
|
// src/tools/manifest/project.ts
|
|
59766
60143
|
import { resolve as resolve60 } from "node:path";
|
|
59767
|
-
import { writeFile as
|
|
60144
|
+
import { writeFile as writeFile45 } from "node:fs/promises";
|
|
59768
60145
|
init_engine();
|
|
59769
60146
|
|
|
59770
60147
|
// src/commands/_shared/project-list.ts
|
|
@@ -59922,7 +60299,7 @@ var projectCreateTool = defineTool({
|
|
|
59922
60299
|
const outputPath = resolve60(ctx.workingDirectory, args.outputPath ?? `${args.name}.vibe.json`);
|
|
59923
60300
|
const project = new Project(args.name);
|
|
59924
60301
|
if (args.fps) project.setFrameRate(args.fps);
|
|
59925
|
-
await
|
|
60302
|
+
await writeFile45(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
59926
60303
|
return {
|
|
59927
60304
|
success: true,
|
|
59928
60305
|
data: { name: args.name, outputPath },
|
|
@@ -60642,8 +61019,8 @@ var exportVideoTool = defineTool({
|
|
|
60642
61019
|
var exportTools = [exportVideoTool];
|
|
60643
61020
|
|
|
60644
61021
|
// src/tools/manifest/agent-only.ts
|
|
60645
|
-
import { readFile as readFile43, writeFile as
|
|
60646
|
-
import { resolve as resolve63, join as join28, basename as basename17, extname as
|
|
61022
|
+
import { readFile as readFile43, writeFile as writeFile46, readdir as readdir8, stat as stat8, access as access7, unlink as unlink2 } from "node:fs/promises";
|
|
61023
|
+
import { resolve as resolve63, join as join28, basename as basename17, extname as extname12 } from "node:path";
|
|
60647
61024
|
init_engine();
|
|
60648
61025
|
init_exec_safe();
|
|
60649
61026
|
init_project_resolver();
|
|
@@ -60665,7 +61042,7 @@ function formatSize(bytes) {
|
|
|
60665
61042
|
return `${size.toFixed(1)}${units2[unit]}`;
|
|
60666
61043
|
}
|
|
60667
61044
|
function detectMediaType(filePath) {
|
|
60668
|
-
const ext =
|
|
61045
|
+
const ext = extname12(filePath).toLowerCase();
|
|
60669
61046
|
if ([".mp4", ".mov", ".avi", ".mkv", ".webm", ".m4v"].includes(ext)) return "video";
|
|
60670
61047
|
if ([".mp3", ".wav", ".aac", ".flac", ".ogg", ".m4a"].includes(ext)) return "audio";
|
|
60671
61048
|
if ([".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"].includes(ext)) return "image";
|
|
@@ -60692,7 +61069,7 @@ function isMediaFile(filePath) {
|
|
|
60692
61069
|
".webp",
|
|
60693
61070
|
".bmp"
|
|
60694
61071
|
];
|
|
60695
|
-
return mediaExts.includes(
|
|
61072
|
+
return mediaExts.includes(extname12(filePath).toLowerCase());
|
|
60696
61073
|
}
|
|
60697
61074
|
async function getMediaDuration2(filePath) {
|
|
60698
61075
|
try {
|
|
@@ -60775,7 +61152,7 @@ var fsWriteTool = defineTool({
|
|
|
60775
61152
|
async execute(args, ctx) {
|
|
60776
61153
|
try {
|
|
60777
61154
|
const absPath = resolve63(ctx.workingDirectory, args.path);
|
|
60778
|
-
await
|
|
61155
|
+
await writeFile46(absPath, args.content, "utf-8");
|
|
60779
61156
|
return { success: true, data: { bytes: args.content.length }, humanLines: [`File written: ${args.path} (${formatSize(args.content.length)})`] };
|
|
60780
61157
|
} catch (error) {
|
|
60781
61158
|
return { success: false, error: `Failed to write file: ${error instanceof Error ? error.message : String(error)}` };
|
|
@@ -60838,7 +61215,7 @@ var batchImportTool = defineTool({
|
|
|
60838
61215
|
if (entry.isDirectory() && recursive) {
|
|
60839
61216
|
await scanDir(entryPath);
|
|
60840
61217
|
} else if (entry.isFile()) {
|
|
60841
|
-
const ext =
|
|
61218
|
+
const ext = extname12(entry.name).toLowerCase();
|
|
60842
61219
|
const matchesFilter = !filterExts || filterExts.includes(ext);
|
|
60843
61220
|
if (matchesFilter && isMediaFile(entryPath)) mediaFiles.push(entryPath);
|
|
60844
61221
|
}
|
|
@@ -60861,7 +61238,7 @@ var batchImportTool = defineTool({
|
|
|
60861
61238
|
const source = project.addSource({ name: mediaName, type: mediaType, url: mediaFile, duration });
|
|
60862
61239
|
addedSources.push({ id: source.id, name: mediaName, type: mediaType });
|
|
60863
61240
|
}
|
|
60864
|
-
await
|
|
61241
|
+
await writeFile46(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
60865
61242
|
return {
|
|
60866
61243
|
success: true,
|
|
60867
61244
|
data: { count: addedSources.length, sources: addedSources },
|
|
@@ -60931,7 +61308,7 @@ var batchConcatTool = defineTool({
|
|
|
60931
61308
|
createdClips.push({ id: clip.id, sourceName: source.name, startTime: currentTime, duration: source.duration });
|
|
60932
61309
|
currentTime += source.duration + gap;
|
|
60933
61310
|
}
|
|
60934
|
-
await
|
|
61311
|
+
await writeFile46(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
60935
61312
|
const totalDuration = currentTime - gap - startTime;
|
|
60936
61313
|
return {
|
|
60937
61314
|
success: true,
|
|
@@ -60994,7 +61371,7 @@ var batchApplyEffectTool = defineTool({
|
|
|
60994
61371
|
});
|
|
60995
61372
|
if (effect) appliedEffects.push({ clipId: clip.id, effectId: effect.id });
|
|
60996
61373
|
}
|
|
60997
|
-
await
|
|
61374
|
+
await writeFile46(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
60998
61375
|
return {
|
|
60999
61376
|
success: true,
|
|
61000
61377
|
data: { applied: appliedEffects.length, effectType: args.effectType },
|
|
@@ -61063,7 +61440,7 @@ var timelineClearTool = defineTool({
|
|
|
61063
61440
|
removed.sources++;
|
|
61064
61441
|
}
|
|
61065
61442
|
}
|
|
61066
|
-
await
|
|
61443
|
+
await writeFile46(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
61067
61444
|
const parts = [];
|
|
61068
61445
|
if (removed.clips > 0) parts.push(`${removed.clips} clips`);
|
|
61069
61446
|
if (removed.tracks > 0) parts.push(`${removed.tracks} tracks`);
|
|
@@ -61114,7 +61491,7 @@ var projectSetTool = defineTool({
|
|
|
61114
61491
|
project.setFrameRate(args.fps);
|
|
61115
61492
|
updates.push(`Frame Rate: ${args.fps} fps`);
|
|
61116
61493
|
}
|
|
61117
|
-
await
|
|
61494
|
+
await writeFile46(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
61118
61495
|
return {
|
|
61119
61496
|
success: true,
|
|
61120
61497
|
data: { updates },
|
|
@@ -61484,7 +61861,7 @@ var mediaConcatTool = defineTool({
|
|
|
61484
61861
|
} else {
|
|
61485
61862
|
const tempList = resolve63(ctx.workingDirectory, `concat-list-${Date.now()}.txt`);
|
|
61486
61863
|
const listContent = args.inputs.map((i) => `file '${resolve63(ctx.workingDirectory, i)}'`).join("\n");
|
|
61487
|
-
await
|
|
61864
|
+
await writeFile46(tempList, listContent, "utf-8");
|
|
61488
61865
|
try {
|
|
61489
61866
|
await execSafe(
|
|
61490
61867
|
"ffmpeg",
|
|
@@ -61775,8 +62152,9 @@ they want for a given task. This guide is the operator-facing summary.
|
|
|
61775
62152
|
|
|
61776
62153
|
If you already use Claude Code, Codex, Cursor, Aider, Gemini CLI, OpenCode,
|
|
61777
62154
|
or another coding agent, let that host drive \`vibe\` directly through shell
|
|
61778
|
-
commands plus \`AGENTS.md\` / \`CLAUDE.md\`.
|
|
61779
|
-
|
|
62155
|
+
commands plus \`AGENTS.md\` / \`CLAUDE.md\`. Without a coding agent, connect
|
|
62156
|
+
the MCP server to Claude Desktop or ChatGPT (\`vibe host setup\`).
|
|
62157
|
+
\`vibe agent\` is deprecated and will be removed before 1.0.
|
|
61780
62158
|
|
|
61781
62159
|
## TL;DR
|
|
61782
62160
|
|
|
@@ -61787,12 +62165,12 @@ built-in fallback when you do not already have an agent host.
|
|
|
61787
62165
|
| **Reproducibility** | none | high (idempotent) | highest (checkpointed) |
|
|
61788
62166
|
| **Budget caps** | per-session max-turns | none | \`--budget-usd\`, \`--budget-tokens\`, \`--max-errors\` |
|
|
61789
62167
|
| **Resume after crash** | no | re-invoke | \`--resume\` |
|
|
61790
|
-
| **Best for** |
|
|
62168
|
+
| **Best for** | deprecated; use a host agent | finished script | repeatable workflows |
|
|
61791
62169
|
|
|
61792
62170
|
## Decision tree
|
|
61793
62171
|
|
|
61794
62172
|
- "I am already in Claude Code/Codex/Cursor/etc." \u2192 regular \`vibe\` shell commands + \`vibe guide\` / \`vibe schema\`
|
|
61795
|
-
- "I
|
|
62173
|
+
- "I do not use a coding agent" \u2192 the MCP server in Claude Desktop or ChatGPT (\`vibe host setup\`)
|
|
61796
62174
|
- "I have a finished script + visual identity" \u2192 \`vibe build\`
|
|
61797
62175
|
- "I want this to run again next month" \u2192 \`vibe run\`
|
|
61798
62176
|
|
|
@@ -61818,9 +62196,6 @@ agent calls them through a tool manifest; \`build\` calls a curated subset
|
|
|
61818
62196
|
- \`vibe build\` is conceptually a 4-step pipeline; \`vibe run\` could express
|
|
61819
62197
|
the same flow but build's STORYBOARD.md input + opinionated defaults are
|
|
61820
62198
|
the value-add.
|
|
61821
|
-
- \`vibe agent\`'s tool registry currently exposes primitives, not
|
|
61822
|
-
orchestrators. Adding \`vibe.build\` / \`vibe.run\` as agent tools is on the
|
|
61823
|
-
table for a future major.
|
|
61824
62199
|
- \`vibe run --resume\` has no analog in build/agent; build's idempotent
|
|
61825
62200
|
re-invoke covers the common case.
|
|
61826
62201
|
`;
|
|
@@ -61927,17 +62302,17 @@ var META = {
|
|
|
61927
62302
|
},
|
|
61928
62303
|
architecture: {
|
|
61929
62304
|
title: "external agents / vibe agent / build / run",
|
|
61930
|
-
summary: "Choose between host-agent shell use,
|
|
62305
|
+
summary: "Choose between host-agent shell use, MCP hosts, storyboard builds, and YAML pipelines",
|
|
61931
62306
|
steps: [
|
|
61932
62307
|
"If you are already in Claude Code/Codex/Cursor/etc., let that host drive normal `vibe` shell commands using `AGENTS.md`, `vibe guide`, and `vibe schema`.",
|
|
61933
|
-
"
|
|
62308
|
+
"Without a coding agent, connect the MCP server to Claude Desktop or ChatGPT with `vibe host setup`; `vibe agent` is deprecated.",
|
|
61934
62309
|
"Pick build for STORYBOARD.md \u2192 MP4 with opinionated defaults.",
|
|
61935
62310
|
"Pick run for repeatable, budget-capped, checkpointed YAML pipelines.",
|
|
61936
62311
|
"Run `vibe doctor --test-keys` before any high-cost orchestrator to validate keys upfront.",
|
|
61937
62312
|
"Use `vibe schema --list` (cost field, v0.84) to plan the budget per step before kicking off `vibe run --budget-usd`."
|
|
61938
62313
|
],
|
|
61939
62314
|
relatedCommands: [
|
|
61940
|
-
"vibe
|
|
62315
|
+
"vibe host setup",
|
|
61941
62316
|
"vibe build",
|
|
61942
62317
|
"vibe run",
|
|
61943
62318
|
"vibe doctor",
|