@vibeframe/cli 0.115.3 → 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.
@@ -439,6 +439,82 @@ var init_whisper = __esm({
439
439
  }
440
440
  });
441
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
+
442
518
  // ../ai-providers/dist/gemini/gemini-models.js
443
519
  function isGeminiTextModelAlias(model) {
444
520
  return Object.prototype.hasOwnProperty.call(GEMINI_TEXT_MODEL_ALIASES, model);
@@ -457,19 +533,10 @@ var GEMINI_DEFAULT_TEXT_MODEL, GEMINI_AGENT_DEFAULT_TEXT_MODEL, GEMINI_TEXT_MODE
457
533
  var init_gemini_models = __esm({
458
534
  "../ai-providers/dist/gemini/gemini-models.js"() {
459
535
  "use strict";
460
- GEMINI_DEFAULT_TEXT_MODEL = "gemini-3.8-flash";
536
+ init_catalog();
537
+ GEMINI_DEFAULT_TEXT_MODEL = defaultModel("gemini", "llm").id;
461
538
  GEMINI_AGENT_DEFAULT_TEXT_MODEL = GEMINI_DEFAULT_TEXT_MODEL;
462
- GEMINI_TEXT_MODEL_ALIASES = {
463
- flash: GEMINI_DEFAULT_TEXT_MODEL,
464
- latest: GEMINI_DEFAULT_TEXT_MODEL,
465
- "flash-3.8": GEMINI_DEFAULT_TEXT_MODEL,
466
- "flash-3.5": "gemini-3.5-flash",
467
- "flash-3": "gemini-3-flash-preview",
468
- "flash-2.5": "gemini-2.5-flash",
469
- pro: "gemini-3.1-pro-preview",
470
- "pro-3.1": "gemini-3.1-pro-preview",
471
- "pro-2.5": "gemini-2.5-pro"
472
- };
539
+ GEMINI_TEXT_MODEL_ALIASES = Object.fromEntries(listModels({ provider: "gemini", kind: "llm" }).flatMap((m) => (m.aliases ?? []).map((a) => [a, m.id])));
473
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";
474
541
  }
475
542
  });
@@ -803,19 +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.8": GEMINI_DEFAULT_TEXT_MODEL,
811
- "flash-3.5": "gemini-3.5-flash",
812
- "flash-3": "gemini-3-flash-preview",
813
- "flash-2.5": "gemini-2.5-flash",
814
- pro: "gemini-3.1-pro-preview",
815
- "2.5-pro": "gemini-2.5-pro",
816
- "3.1-pro": "gemini-3.1-pro-preview",
817
- "pro-3.1": "gemini-3.1-pro-preview"
818
- };
873
+ GEMINI_MOTION_MODELS = GEMINI_TEXT_MODEL_ALIASES;
819
874
  STYLE_USER_INSTRUCTIONS = {
820
875
  minimal: "CENTER-ALIGNED pure typography. Thin lines + large title + subtitle. NO glass panels, NO bokeh, NO dark bars. Breathing pulse during hold.",
821
876
  corporate: "Data-rich info bar at bottom + top-right badge. Animated number counter. Brand color stripe. Progress bar.",
@@ -1010,7 +1065,7 @@ function resolveVeoModel(alias) {
1010
1065
  const hint = alias === "3.0" ? " Veo 3.0 was shut down by Google on 2025-11-12." : "";
1011
1066
  throw new Error(`Unknown Veo model "${alias}". Valid: ${valid}.${hint}`);
1012
1067
  }
1013
- var VEO_MODEL_ALIASES, MODEL_MAP, GeminiProvider, geminiProvider;
1068
+ var VEO_MODEL_ALIASES, GeminiProvider, geminiProvider;
1014
1069
  var init_GeminiProvider = __esm({
1015
1070
  "../ai-providers/dist/gemini/GeminiProvider.js"() {
1016
1071
  "use strict";
@@ -1018,23 +1073,8 @@ var init_GeminiProvider = __esm({
1018
1073
  init_gemini_models();
1019
1074
  init_gemini_storyboard();
1020
1075
  init_http();
1021
- VEO_MODEL_ALIASES = {
1022
- "3.1": "veo-3.1-generate-preview",
1023
- "3.1-fast": "veo-3.1-fast-generate-preview"
1024
- };
1025
- MODEL_MAP = {
1026
- "flash": "gemini-3.1-flash-image",
1027
- "3.1-flash": "gemini-3.1-flash-image",
1028
- "latest": "gemini-3.1-flash-image",
1029
- "lite": "gemini-3.1-flash-lite-image",
1030
- "pro": "gemini-3-pro-image",
1031
- "gemini-3.1-flash-image": "gemini-3.1-flash-image",
1032
- "gemini-3.1-flash-lite-image": "gemini-3.1-flash-lite-image",
1033
- "gemini-3-pro-image": "gemini-3-pro-image",
1034
- "gemini-2.5-flash-image": "gemini-2.5-flash-image",
1035
- "gemini-3.1-flash-image-preview": "gemini-3.1-flash-image-preview",
1036
- "gemini-3-pro-image-preview": "gemini-3-pro-image-preview"
1037
- };
1076
+ init_catalog();
1077
+ VEO_MODEL_ALIASES = Object.fromEntries(listModels({ provider: "veo", kind: "video" }).flatMap((m) => (m.aliases ?? []).map((a) => [a, m.id])));
1038
1078
  GeminiProvider = class {
1039
1079
  constructor() {
1040
1080
  this.id = "gemini";
@@ -1293,9 +1333,7 @@ var init_GeminiProvider = __esm({
1293
1333
  * Resolve model alias to full model ID
1294
1334
  */
1295
1335
  resolveModel(model) {
1296
- if (!model)
1297
- return MODEL_MAP["flash"];
1298
- return MODEL_MAP[model] || MODEL_MAP["flash"];
1336
+ return (findModel("gemini", "image", model) ?? defaultModel("gemini", "image")).id;
1299
1337
  }
1300
1338
  /**
1301
1339
  * Check if model is Pro
@@ -1888,7 +1926,8 @@ var init_gemini_omni = __esm({
1888
1926
  "../ai-providers/dist/gemini/gemini-omni.js"() {
1889
1927
  "use strict";
1890
1928
  init_http();
1891
- OMNI_MODEL = "gemini-omni-1.1-flash";
1929
+ init_catalog();
1930
+ OMNI_MODEL = defaultModel("omni", "video").id;
1892
1931
  API_ROOT = "https://generativelanguage.googleapis.com";
1893
1932
  FILE_POLL_INTERVAL_MS = 3e3;
1894
1933
  FILE_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -2028,6 +2067,14 @@ var init_gemini = __esm({
2028
2067
  }
2029
2068
  });
2030
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
+
2031
2078
  // ../ai-providers/dist/openai/openai-storyboard.js
2032
2079
  async function analyzeContent2(apiKey, content, targetDuration, options) {
2033
2080
  const creativity = options?.creativity || "low";
@@ -2040,7 +2087,7 @@ async function analyzeContent2(apiKey, content, targetDuration, options) {
2040
2087
  Authorization: `Bearer ${apiKey}`
2041
2088
  },
2042
2089
  body: JSON.stringify({
2043
- model: "gpt-5.4-mini",
2090
+ model: defaultModel("openai", "llm").id,
2044
2091
  messages: [
2045
2092
  { role: "system", content: systemPrompt },
2046
2093
  { role: "user", content: buildStoryboardUserMessage(content) }
@@ -2085,6 +2132,7 @@ var init_openai_storyboard = __esm({
2085
2132
  "../ai-providers/dist/openai/openai-storyboard.js"() {
2086
2133
  "use strict";
2087
2134
  init_storyboard_prompt();
2135
+ init_catalog();
2088
2136
  }
2089
2137
  });
2090
2138
 
@@ -2094,6 +2142,7 @@ var init_OpenAIProvider = __esm({
2094
2142
  "../ai-providers/dist/openai/OpenAIProvider.js"() {
2095
2143
  "use strict";
2096
2144
  init_openai_storyboard();
2145
+ init_catalog();
2097
2146
  OpenAIProvider = class {
2098
2147
  constructor() {
2099
2148
  this.id = "openai-gpt";
@@ -2103,7 +2152,7 @@ var init_OpenAIProvider = __esm({
2103
2152
  this.iconUrl = "/icons/openai.svg";
2104
2153
  this.isAvailable = true;
2105
2154
  this.baseUrl = "https://api.openai.com/v1";
2106
- this.model = "gpt-5.4-mini";
2155
+ this.model = defaultModel("openai", "llm").id;
2107
2156
  }
2108
2157
  async initialize(config2) {
2109
2158
  this.apiKey = config2.apiKey;
@@ -2409,7 +2458,7 @@ Each segment should be 3-10 seconds long.`;
2409
2458
  Authorization: `Bearer ${this.apiKey}`
2410
2459
  },
2411
2460
  body: JSON.stringify({
2412
- model: "gpt-5.4-mini",
2461
+ model: defaultModel("openai", "llm").id,
2413
2462
  // Reasoning tokens count against this cap.
2414
2463
  max_completion_tokens: 16384,
2415
2464
  response_format: { type: "json_object" },
@@ -3810,6 +3859,7 @@ var init_ClaudeProvider = __esm({
3810
3859
  init_claude_analysis();
3811
3860
  init_claude_viral();
3812
3861
  init_claude_visual_fx();
3862
+ init_catalog();
3813
3863
  ClaudeProvider = class {
3814
3864
  constructor() {
3815
3865
  this.id = "claude";
@@ -3819,7 +3869,7 @@ var init_ClaudeProvider = __esm({
3819
3869
  this.iconUrl = "/icons/claude.svg";
3820
3870
  this.isAvailable = true;
3821
3871
  this.baseUrl = "https://api.anthropic.com/v1";
3822
- this.model = "claude-sonnet-5-5";
3872
+ this.model = defaultModel("claude", "llm").id;
3823
3873
  }
3824
3874
  async initialize(config2) {
3825
3875
  this.apiKey = config2.apiKey;
@@ -4121,11 +4171,7 @@ Instruction: ${instruction}`
4121
4171
  return generateNarrationScript(this.api, videoAnalysis, duration, style, language);
4122
4172
  }
4123
4173
  };
4124
- ClaudeProvider.MOTION_MODELS = {
4125
- sonnet: "claude-sonnet-5-5",
4126
- opus: "claude-opus-5-5",
4127
- "opus-4-6": "claude-opus-4-6"
4128
- };
4174
+ ClaudeProvider.MOTION_MODELS = Object.fromEntries(listModels({ provider: "claude", kind: "llm" }).flatMap((m) => (m.aliases ?? []).map((a) => [a, m.id])));
4129
4175
  claudeProvider = new ClaudeProvider();
4130
4176
  }
4131
4177
  });
@@ -4465,6 +4511,7 @@ var KNOWN_VOICES, TTS_429_MAX_RETRIES, TTS_429_RETRY_DELAY_MS, ELEVENLABS_MUSIC_
4465
4511
  var init_ElevenLabsProvider = __esm({
4466
4512
  "../ai-providers/dist/elevenlabs/ElevenLabsProvider.js"() {
4467
4513
  "use strict";
4514
+ init_catalog();
4468
4515
  KNOWN_VOICES = {
4469
4516
  // Default/popular voices
4470
4517
  rachel: "21m00Tcm4TlvDq8ikWAM",
@@ -4498,7 +4545,7 @@ var init_ElevenLabsProvider = __esm({
4498
4545
  };
4499
4546
  TTS_429_MAX_RETRIES = 1;
4500
4547
  TTS_429_RETRY_DELAY_MS = 2e3;
4501
- ELEVENLABS_MUSIC_MODEL = "music_v2_5";
4548
+ ELEVENLABS_MUSIC_MODEL = defaultModel("elevenlabs", "music").id;
4502
4549
  ElevenLabsProvider = class {
4503
4550
  constructor() {
4504
4551
  this.id = "elevenlabs";
@@ -5162,7 +5209,8 @@ var OPENAI_IMAGE_DEFAULT_MODEL, DEFAULT_MODEL, OpenAIImageProvider, openaiImageP
5162
5209
  var init_OpenAIImageProvider = __esm({
5163
5210
  "../ai-providers/dist/openai-image/OpenAIImageProvider.js"() {
5164
5211
  "use strict";
5165
- OPENAI_IMAGE_DEFAULT_MODEL = "gpt-image-2.5-sunburst";
5212
+ init_catalog();
5213
+ OPENAI_IMAGE_DEFAULT_MODEL = defaultModel("openai", "image").id;
5166
5214
  DEFAULT_MODEL = OPENAI_IMAGE_DEFAULT_MODEL;
5167
5215
  OpenAIImageProvider = class {
5168
5216
  constructor() {
@@ -5486,7 +5534,8 @@ var DEFAULT_MODEL3, RunwayProvider, runwayProvider;
5486
5534
  var init_RunwayProvider = __esm({
5487
5535
  "../ai-providers/dist/runway/RunwayProvider.js"() {
5488
5536
  "use strict";
5489
- DEFAULT_MODEL3 = "gen4.5";
5537
+ init_catalog();
5538
+ DEFAULT_MODEL3 = defaultModel("runway", "video").id;
5490
5539
  RunwayProvider = class _RunwayProvider {
5491
5540
  constructor() {
5492
5541
  this.id = "runway";
@@ -5539,6 +5588,13 @@ var init_RunwayProvider = __esm({
5539
5588
  }
5540
5589
  const hasImage = !!options?.referenceImage;
5541
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
+ }
5542
5598
  const body = {
5543
5599
  model,
5544
5600
  promptText: prompt3,
@@ -5639,7 +5695,9 @@ var init_RunwayProvider = __esm({
5639
5695
  SUCCEEDED: "completed",
5640
5696
  FAILED: "failed",
5641
5697
  CANCELLED: "cancelled",
5642
- THROTTLED: "failed"
5698
+ // THROTTLED means queued behind the account's concurrency limit; the
5699
+ // task starts on its own, so keep polling.
5700
+ THROTTLED: "pending"
5643
5701
  };
5644
5702
  const result = {
5645
5703
  id: data.id,
@@ -5649,8 +5707,9 @@ var init_RunwayProvider = __esm({
5649
5707
  if (data.status === "SUCCEEDED" && data.output && data.output.length > 0) {
5650
5708
  result.videoUrl = data.output[0];
5651
5709
  }
5652
- if (data.status === "FAILED" || data.status === "THROTTLED") {
5653
- result.error = data.failure || data.failureCode || "Generation failed";
5710
+ if (data.status === "FAILED") {
5711
+ const reason = data.failure || "Generation failed";
5712
+ result.error = data.failureCode ? `${reason} (${data.failureCode})` : reason;
5654
5713
  }
5655
5714
  return result;
5656
5715
  } catch (error) {
@@ -5662,27 +5721,14 @@ var init_RunwayProvider = __esm({
5662
5721
  }
5663
5722
  }
5664
5723
  /**
5665
- * Cancel ongoing generation
5724
+ * Cancel a pending or running task. Runway documents cancellation as
5725
+ * `DELETE /v1/tasks/{id}` (there is no `/cancel` route).
5666
5726
  */
5667
5727
  async cancelGeneration(id) {
5668
- if (!this.apiKey) {
5669
- return false;
5670
- }
5671
- try {
5672
- const response = await fetch(`${this.baseUrl}/tasks/${id}/cancel`, {
5673
- method: "POST",
5674
- headers: {
5675
- Authorization: `Bearer ${this.apiKey}`,
5676
- "X-Runway-Version": _RunwayProvider.API_VERSION
5677
- }
5678
- });
5679
- return response.ok;
5680
- } catch {
5681
- return false;
5682
- }
5728
+ return this.deleteTask(id);
5683
5729
  }
5684
5730
  /**
5685
- * Delete a completed task
5731
+ * Cancel a running task, or delete a finished one (`DELETE /v1/tasks/{id}`).
5686
5732
  */
5687
5733
  async deleteTask(id) {
5688
5734
  if (!this.apiKey) {
@@ -5792,19 +5838,10 @@ var init_runway = __esm({
5792
5838
  // ../ai-providers/dist/kling/KlingProvider.js
5793
5839
  import { createHmac } from "node:crypto";
5794
5840
  function resolveKlingModel(alias) {
5795
- const key = (alias ?? "v3").trim().toLowerCase();
5796
- const aliases = {
5797
- v3: "kling-v3",
5798
- "kling-v3": "kling-v3",
5799
- "v2.6": "kling-v2-6",
5800
- "kling-v2-6": "kling-v2-6",
5801
- "v2.5-turbo": "kling-v2-5-turbo",
5802
- "v2.5": "kling-v2-5-turbo",
5803
- "kling-v2-5-turbo": "kling-v2-5-turbo"
5804
- };
5805
- if (Object.hasOwn(aliases, key))
5806
- return aliases[key];
5807
- throw new Error(`Unknown Kling model "${alias}". Valid: v3, v2.6, v2.5-turbo.`);
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(", ")}.`);
5808
5845
  }
5809
5846
  function klingDuration(model, seconds) {
5810
5847
  const requested = typeof seconds === "number" && Number.isFinite(seconds) ? Math.round(seconds) : 5;
@@ -5816,7 +5853,8 @@ var DEFAULT_MODEL4, STD_MODE_MODELS, KlingProvider, klingProvider;
5816
5853
  var init_KlingProvider = __esm({
5817
5854
  "../ai-providers/dist/kling/KlingProvider.js"() {
5818
5855
  "use strict";
5819
- DEFAULT_MODEL4 = "kling-v3";
5856
+ init_catalog();
5857
+ DEFAULT_MODEL4 = defaultModel("kling", "video").id;
5820
5858
  STD_MODE_MODELS = ["kling-v2-5-turbo", "kling-v2-6", "kling-v3"];
5821
5859
  KlingProvider = class {
5822
5860
  constructor() {
@@ -6255,31 +6293,21 @@ var init_kling = __esm({
6255
6293
 
6256
6294
  // ../ai-providers/dist/grok/GrokProvider.js
6257
6295
  function resolveGrokVideoModel(alias) {
6258
- const key = (alias ?? "1.5").trim().toLowerCase();
6259
- const aliases = {
6260
- "1.5": "grok-imagine-video-1.5",
6261
- "grok-imagine-video-1.5": "grok-imagine-video-1.5",
6262
- lite: "grok-imagine-video-1.5-lite",
6263
- "1.5-lite": "grok-imagine-video-1.5-lite",
6264
- "grok-imagine-video-1.5-lite": "grok-imagine-video-1.5-lite",
6265
- classic: "grok-imagine-video",
6266
- "grok-imagine-video": "grok-imagine-video"
6267
- };
6268
- if (Object.hasOwn(aliases, key))
6269
- return aliases[key];
6270
- throw new Error(`Unknown Grok video model "${alias}". Valid: 1.5, lite, classic.`);
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(", ")}.`);
6271
6300
  }
6272
6301
  function resolveGrokImageModel(alias) {
6273
- if (alias === "pro" || alias === "2.0" || alias === "quality" || alias === "grok-imagine-image-2.0") {
6274
- return { model: "grok-imagine-image-2.0", quality: "medium" };
6275
- }
6276
- return { model: "grok-imagine-image" };
6302
+ const model = (findModel("grok", "image", alias) ?? defaultModel("grok", "image")).id;
6303
+ return model === "grok-imagine-image-2.0" ? { model, quality: "medium" } : { model };
6277
6304
  }
6278
6305
  var DEFAULT_MODEL5, DEFAULT_VIDEO_RESOLUTION, GROK_VIDEO_RESOLUTIONS, GrokProvider, grokProvider;
6279
6306
  var init_GrokProvider = __esm({
6280
6307
  "../ai-providers/dist/grok/GrokProvider.js"() {
6281
6308
  "use strict";
6282
- DEFAULT_MODEL5 = "grok-imagine-video-1.5";
6309
+ init_catalog();
6310
+ DEFAULT_MODEL5 = defaultModel("grok", "video").id;
6283
6311
  DEFAULT_VIDEO_RESOLUTION = "720p";
6284
6312
  GROK_VIDEO_RESOLUTIONS = ["480p", "720p", "1080p"];
6285
6313
  GrokProvider = class {
@@ -10722,19 +10750,10 @@ var require_src = __commonJS({
10722
10750
 
10723
10751
  // ../ai-providers/dist/fal/FalProvider.js
10724
10752
  function resolveSeedanceVariant(alias) {
10725
- const key = (alias ?? "quality").trim().toLowerCase();
10726
- const aliases = {
10727
- quality: "seedance-2.0",
10728
- "2.0": "seedance-2.0",
10729
- "seedance-2.0": "seedance-2.0",
10730
- fast: "seedance-2.0-fast",
10731
- "seedance-2.0-fast": "seedance-2.0-fast",
10732
- "2.5": "seedance-2.5",
10733
- "seedance-2.5": "seedance-2.5"
10734
- };
10735
- if (Object.hasOwn(aliases, key))
10736
- return aliases[key];
10737
- throw new Error(`Unknown Seedance model "${alias}". Valid: quality, fast, 2.5.`);
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(", ")}.`);
10738
10757
  }
10739
10758
  function estimateSeedanceVideoCostUsd(opts) {
10740
10759
  const shortSide = SEEDANCE_SHORT_SIDE[opts.resolution ?? "720p"] ?? 720;
@@ -10862,6 +10881,7 @@ var init_FalProvider = __esm({
10862
10881
  "../ai-providers/dist/fal/FalProvider.js"() {
10863
10882
  "use strict";
10864
10883
  import_client = __toESM(require_src(), 1);
10884
+ init_catalog();
10865
10885
  ENDPOINT_TEXT_TO_VIDEO = {
10866
10886
  "seedance-2.0": "bytedance/seedance-2.0/text-to-video",
10867
10887
  "seedance-2.0-fast": "bytedance/seedance-2.0/fast/text-to-video",
@@ -11706,6 +11726,7 @@ __export(dist_exports2, {
11706
11726
  KOKORO_MODEL_ID: () => KOKORO_MODEL_ID,
11707
11727
  KlingProvider: () => KlingProvider,
11708
11728
  KokoroProvider: () => KokoroProvider,
11729
+ MODEL_CATALOG: () => MODEL_CATALOG,
11709
11730
  OPENAI_IMAGE_DEFAULT_MODEL: () => OPENAI_IMAGE_DEFAULT_MODEL,
11710
11731
  OPENAI_TTS_VOICES: () => OPENAI_TTS_VOICES,
11711
11732
  OllamaProvider: () => OllamaProvider,
@@ -11718,11 +11739,13 @@ __export(dist_exports2, {
11718
11739
  VEO_MODEL_ALIASES: () => VEO_MODEL_ALIASES,
11719
11740
  WhisperProvider: () => WhisperProvider,
11720
11741
  claudeProvider: () => claudeProvider,
11742
+ defaultModel: () => defaultModel,
11721
11743
  defineApiKey: () => defineApiKey,
11722
11744
  defineProvider: () => defineProvider,
11723
11745
  elevenLabsProvider: () => elevenLabsProvider,
11724
11746
  estimateSeedanceVideoCostUsd: () => estimateSeedanceVideoCostUsd,
11725
11747
  falProvider: () => falProvider,
11748
+ findModel: () => findModel,
11726
11749
  geminiProvider: () => geminiProvider,
11727
11750
  getAllApiKeys: () => getAllApiKeys,
11728
11751
  getAllProviders: () => getAllProviders,
@@ -11739,8 +11762,10 @@ __export(dist_exports2, {
11739
11762
  klingDuration: () => klingDuration,
11740
11763
  klingProvider: () => klingProvider,
11741
11764
  kokoroProvider: () => kokoroProvider,
11765
+ listModels: () => listModels,
11742
11766
  loadBundledKokoroRuntime: () => loadBundledKokoroRuntime,
11743
11767
  loadKokoroFromWorkspace: () => loadKokoroFromWorkspace,
11768
+ modelAliases: () => modelAliases,
11744
11769
  ollamaProvider: () => ollamaProvider,
11745
11770
  omniProvider: () => omniProvider,
11746
11771
  openaiImageProvider: () => openaiImageProvider,
@@ -11767,6 +11792,7 @@ var init_dist2 = __esm({
11767
11792
  init_define_provider();
11768
11793
  init_whisper();
11769
11794
  init_gemini();
11795
+ init_catalog2();
11770
11796
  init_openai();
11771
11797
  init_claude();
11772
11798
  init_ollama();
@@ -20009,12 +20035,15 @@ var init_ai_helpers = __esm({
20009
20035
  });
20010
20036
 
20011
20037
  // src/commands/_shared/video-utils.ts
20012
- async function uploadToImgbb(imageBuffer, apiKey) {
20038
+ async function uploadToImgbb(imageBuffer, apiKey, expirationSeconds) {
20013
20039
  try {
20014
20040
  const base64Image = imageBuffer.toString("base64");
20015
20041
  const formData = new URLSearchParams();
20016
20042
  formData.append("key", apiKey);
20017
20043
  formData.append("image", base64Image);
20044
+ if (expirationSeconds !== void 0) {
20045
+ formData.append("expiration", String(expirationSeconds));
20046
+ }
20018
20047
  const response = await fetch("https://api.imgbb.com/1/upload", {
20019
20048
  method: "POST",
20020
20049
  body: formData
@@ -20077,7 +20106,10 @@ function awsEncode(value) {
20077
20106
  (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
20078
20107
  );
20079
20108
  }
20080
- function presignS3PutUrl(params) {
20109
+ function clamp(value, min, max) {
20110
+ return Math.min(max, Math.max(min, Math.round(value)));
20111
+ }
20112
+ function presignS3Url(params) {
20081
20113
  const now = /* @__PURE__ */ new Date();
20082
20114
  const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, "");
20083
20115
  const dateStamp = amzDate.slice(0, 8);
@@ -20088,7 +20120,7 @@ function presignS3PutUrl(params) {
20088
20120
  "X-Amz-Algorithm": "AWS4-HMAC-SHA256",
20089
20121
  "X-Amz-Credential": `${params.accessKeyId}/${credentialScope}`,
20090
20122
  "X-Amz-Date": amzDate,
20091
- "X-Amz-Expires": String(params.ttlSeconds),
20123
+ "X-Amz-Expires": String(clamp(params.ttlSeconds, 1, S3_MAX_PRESIGN_SECONDS)),
20092
20124
  "X-Amz-SignedHeaders": "host"
20093
20125
  };
20094
20126
  if (params.sessionToken) {
@@ -20096,7 +20128,7 @@ function presignS3PutUrl(params) {
20096
20128
  }
20097
20129
  const canonicalQuery = Object.entries(query).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => `${awsEncode(key)}=${awsEncode(value)}`).join("&");
20098
20130
  const canonicalRequest = [
20099
- "PUT",
20131
+ params.method,
20100
20132
  canonicalUri,
20101
20133
  canonicalQuery,
20102
20134
  `host:${host}`,
@@ -20155,7 +20187,8 @@ async function resolveUploadHost() {
20155
20187
  const ext = extensionFor(opts);
20156
20188
  const prefix = safePrefix(settings.s3.prefix);
20157
20189
  const key = `${prefix}/${Date.now()}-${randomUUID()}.${ext}`;
20158
- const presignedUrl = presignS3PutUrl({
20190
+ const presignedUrl = presignS3Url({
20191
+ method: "PUT",
20159
20192
  accessKeyId,
20160
20193
  secretAccessKey,
20161
20194
  sessionToken,
@@ -20174,10 +20207,26 @@ async function resolveUploadHost() {
20174
20207
  if (!response.ok) {
20175
20208
  throw new Error(`S3 upload failed (${response.status}): ${response.statusText}`);
20176
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);
20177
20217
  return {
20178
20218
  provider: "s3",
20179
- url: publicS3Url({ region, bucket, key, publicBaseUrl: settings.s3.publicBaseUrl }),
20180
- expiresAt: new Date(Date.now() + settings.ttlSeconds * 1e3).toISOString()
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()
20181
20230
  };
20182
20231
  }
20183
20232
  };
@@ -20189,19 +20238,28 @@ async function resolveUploadHost() {
20189
20238
  if (!imgbbKey) {
20190
20239
  throw new Error("IMGBB_API_KEY required for image-to-video uploads.");
20191
20240
  }
20192
- const result = await uploadToImgbb(imageBuffer, imgbbKey);
20241
+ const expiration = clamp(settings.ttlSeconds, IMGBB_MIN_EXPIRATION_SECONDS, IMGBB_MAX_EXPIRATION_SECONDS);
20242
+ const result = await uploadToImgbb(imageBuffer, imgbbKey, expiration);
20193
20243
  if (!result.success || !result.url) {
20194
20244
  throw new Error(`ImgBB upload failed: ${result.error ?? "unknown error"}`);
20195
20245
  }
20196
- return { provider: "imgbb", url: result.url };
20246
+ return {
20247
+ provider: "imgbb",
20248
+ url: result.url,
20249
+ expiresAt: new Date(Date.now() + expiration * 1e3).toISOString()
20250
+ };
20197
20251
  }
20198
20252
  };
20199
20253
  }
20254
+ var S3_MAX_PRESIGN_SECONDS, IMGBB_MIN_EXPIRATION_SECONDS, IMGBB_MAX_EXPIRATION_SECONDS;
20200
20255
  var init_upload_host = __esm({
20201
20256
  "src/utils/upload-host.ts"() {
20202
20257
  "use strict";
20203
20258
  init_config();
20204
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;
20205
20263
  }
20206
20264
  });
20207
20265
 
@@ -20842,6 +20900,7 @@ async function executeVideoGenerate(options) {
20842
20900
  negative,
20843
20901
  resolution,
20844
20902
  veoModel = "3.1-fast",
20903
+ runwayModel,
20845
20904
  seedanceModel = "quality",
20846
20905
  grokModel,
20847
20906
  klingModel,
@@ -20931,6 +20990,7 @@ async function executeVideoGenerate(options) {
20931
20990
  await runway.initialize({ apiKey: key });
20932
20991
  const result = await runway.generateVideo(prompt3, {
20933
20992
  prompt: prompt3,
20993
+ model: runwayModel,
20934
20994
  referenceImage,
20935
20995
  duration,
20936
20996
  aspectRatio: ratio,
@@ -37890,16 +37950,14 @@ import { tmpdir } from "node:os";
37890
37950
  import { createHash as createHash4 } from "node:crypto";
37891
37951
  async function ensureRemotionInstalled() {
37892
37952
  try {
37893
- await execSafe("npx", ["--yes", "remotion", "--help"], { timeout: 6e4 });
37953
+ await execSafe("npm", ["--version"], { timeout: 3e4 });
37894
37954
  return null;
37895
37955
  } catch (error) {
37896
37956
  const detail = error instanceof Error ? error.message : String(error);
37897
- console.error(`[Remotion] ensureRemotionInstalled failed: ${detail.slice(0, 300)}`);
37898
37957
  return [
37899
- "Remotion CLI not found or failed to initialize.",
37958
+ "Remotion renders need npm to install the Remotion CLI into a temporary project.",
37900
37959
  ` Debug: ${detail.slice(0, 200)}`,
37901
- " Fix: npm install -g @remotion/cli",
37902
- " 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."
37903
37961
  ].join("\n");
37904
37962
  }
37905
37963
  }
@@ -39022,7 +39080,7 @@ ${textsToTranslate}`;
39022
39080
  Authorization: `Bearer ${openaiKey}`
39023
39081
  },
39024
39082
  body: JSON.stringify({
39025
- model: "gpt-5.4-mini",
39083
+ model: defaultModel("openai", "llm").id,
39026
39084
  messages: [{ role: "user", content: translatePrompt }]
39027
39085
  })
39028
39086
  });
@@ -39050,7 +39108,7 @@ ${textsToTranslate}`;
39050
39108
  "anthropic-version": "2023-06-01"
39051
39109
  },
39052
39110
  body: JSON.stringify({
39053
- model: "claude-sonnet-5-5",
39111
+ model: defaultModel("claude", "llm").id,
39054
39112
  max_tokens: 16e3,
39055
39113
  messages: [{ role: "user", content: translatePrompt }]
39056
39114
  })
@@ -39101,6 +39159,7 @@ var init_translate_srt = __esm({
39101
39159
  "src/commands/_shared/edit/translate-srt.ts"() {
39102
39160
  "use strict";
39103
39161
  init_subtitle();
39162
+ init_dist2();
39104
39163
  }
39105
39164
  });
39106
39165
 
@@ -40302,22 +40361,13 @@ function analyzeGapFillability(gaps, videoClips, sources) {
40302
40361
  return { gap, canExtendBefore, canExtendAfter, remainingGap, gapStart };
40303
40362
  });
40304
40363
  }
40305
- async function uploadFrameToImgbb(framePath, imgbbApiKey) {
40364
+ async function uploadFrame(host, framePath) {
40306
40365
  try {
40307
- const frameBuffer = await readFile24(framePath);
40308
- const frameBase64 = frameBuffer.toString("base64");
40309
- const formData = new FormData();
40310
- formData.append("key", imgbbApiKey);
40311
- formData.append("image", frameBase64);
40312
- const response = await fetch("https://api.imgbb.com/1/upload", {
40313
- method: "POST",
40314
- body: formData
40366
+ const upload = await host.uploadImage(await readFile24(framePath), {
40367
+ filename: framePath,
40368
+ mimeType: "image/png"
40315
40369
  });
40316
- const data = await response.json();
40317
- if (!data.success || !data.data?.url) {
40318
- return { error: data.error?.message || "Upload failed" };
40319
- }
40320
- return { url: data.data.url };
40370
+ return { url: upload.url };
40321
40371
  } catch (err) {
40322
40372
  return { error: err instanceof Error ? err.message : String(err) };
40323
40373
  }
@@ -40468,11 +40518,13 @@ async function executeFillGaps(options) {
40468
40518
  await mkdir16(footageDir, { recursive: true });
40469
40519
  }
40470
40520
  humanLines.push("Generating AI Videos");
40471
- const imgbbApiKey = options.imgbbApiKey || await getApiKey("IMGBB_API_KEY", "imgbb", void 0);
40472
- if (!imgbbApiKey) {
40521
+ let uploadHost;
40522
+ try {
40523
+ uploadHost = await resolveUploadHost();
40524
+ } catch (err) {
40473
40525
  return {
40474
40526
  success: false,
40475
- error: "IMGBB_API_KEY required for image hosting. Get a free API key at https://api.imgbb.com/",
40527
+ error: err instanceof Error ? err.message : String(err),
40476
40528
  humanLines
40477
40529
  };
40478
40530
  }
@@ -40516,12 +40568,12 @@ async function executeFillGaps(options) {
40516
40568
  humanLines
40517
40569
  };
40518
40570
  }
40519
- onProgress("Uploading frame to imgbb...");
40520
- const upload = await uploadFrameToImgbb(framePath, imgbbApiKey);
40571
+ onProgress(`Uploading frame via ${uploadHost.provider}...`);
40572
+ const upload = await uploadFrame(uploadHost, framePath);
40521
40573
  if (!upload.url) {
40522
40574
  return {
40523
40575
  success: false,
40524
- error: `Failed to upload frame to imgbb: ${upload.error || "unknown"}`,
40576
+ error: `Failed to upload frame via ${uploadHost.provider}: ${upload.error || "unknown"}`,
40525
40577
  humanLines
40526
40578
  };
40527
40579
  }
@@ -40596,7 +40648,7 @@ async function executeFillGaps(options) {
40596
40648
  humanLines.push(" Failed to extract frame for continuation");
40597
40649
  break;
40598
40650
  }
40599
- const extUpload = await uploadFrameToImgbb(lastFramePath, imgbbApiKey);
40651
+ const extUpload = await uploadFrame(uploadHost, lastFramePath);
40600
40652
  if (!extUpload.url) {
40601
40653
  humanLines.push(" Failed to upload continuation frame");
40602
40654
  break;
@@ -40719,6 +40771,7 @@ var init_execute_fill_gaps = __esm({
40719
40771
  init_dist2();
40720
40772
  init_engine();
40721
40773
  init_api_key();
40774
+ init_upload_host();
40722
40775
  init_exec_safe();
40723
40776
  init_project_resolver();
40724
40777
  init_ai_helpers();
@@ -40786,6 +40839,13 @@ __export(ai_motion_exports, {
40786
40839
  import { resolve as resolve33 } from "node:path";
40787
40840
  import { existsSync as existsSync33 } from "node:fs";
40788
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
+ }
40789
40849
  async function getOptionalGoogleApiKey() {
40790
40850
  const configKey = await getApiKeyFromConfig("google");
40791
40851
  if (configKey) return configKey;
@@ -40800,7 +40860,7 @@ function normalizeUnderstand(value) {
40800
40860
  }
40801
40861
  async function executeMotion(options) {
40802
40862
  const modelAlias = options.model || "sonnet";
40803
- const modelConfig = MODEL_MAP2[modelAlias] ?? MODEL_MAP2["sonnet"];
40863
+ const modelConfig = resolveMotionModel(modelAlias);
40804
40864
  const useGemini = modelConfig.provider === "gemini";
40805
40865
  const width = options.width || 1920;
40806
40866
  const height = options.height || 1080;
@@ -41179,7 +41239,6 @@ function registerMotionCommand(aiCommand) {
41179
41239
  }
41180
41240
  });
41181
41241
  }
41182
- var MODEL_MAP2;
41183
41242
  var init_ai_motion = __esm({
41184
41243
  "src/commands/ai-motion.ts"() {
41185
41244
  "use strict";
@@ -41190,14 +41249,6 @@ var init_ai_motion = __esm({
41190
41249
  init_config();
41191
41250
  init_output();
41192
41251
  init_validate();
41193
- MODEL_MAP2 = {
41194
- sonnet: { provider: "claude", modelId: "claude-sonnet-5-5" },
41195
- opus: { provider: "claude", modelId: "claude-opus-5-5" },
41196
- "opus-4-6": { provider: "claude", modelId: "claude-opus-4-6" },
41197
- gemini: { provider: "gemini", modelId: GEMINI_DEFAULT_TEXT_MODEL },
41198
- "gemini-2.5-pro": { provider: "gemini", modelId: "gemini-2.5-pro" },
41199
- "gemini-3.1-pro": { provider: "gemini", modelId: "gemini-3.1-pro-preview" }
41200
- };
41201
41252
  }
41202
41253
  });
41203
41254
 
@@ -44311,16 +44362,8 @@ var init_provider_resolver = __esm({
44311
44362
 
44312
44363
  // src/commands/_shared/openai-image.ts
44313
44364
  function resolveOpenAIImageModel(modelAlias) {
44314
- const alias = modelAlias?.trim() ?? "";
44315
- for (const [id, model] of Object.entries(OPENAI_IMAGE_MODELS)) {
44316
- if (alias === id || model.aliases.includes(alias)) {
44317
- return { openaiModel: id, modelLabel: model.label };
44318
- }
44319
- }
44320
- return {
44321
- openaiModel: OPENAI_IMAGE_DEFAULT_MODEL,
44322
- modelLabel: OPENAI_IMAGE_MODELS[OPENAI_IMAGE_DEFAULT_MODEL].label
44323
- };
44365
+ const model = findModel("openai", "image", modelAlias) ?? defaultModel("openai", "image");
44366
+ return { openaiModel: model.id, modelLabel: model.label };
44324
44367
  }
44325
44368
  async function executeOpenAIImageGenerate(prompt3, options, ctx) {
44326
44369
  const provider = new OpenAIImageProvider();
@@ -44335,18 +44378,45 @@ async function executeOpenAIImageGenerate(prompt3, options, ctx) {
44335
44378
  });
44336
44379
  return { result, openaiModel, modelLabel };
44337
44380
  }
44338
- var OPENAI_IMAGE_MODELS;
44339
44381
  var init_openai_image2 = __esm({
44340
44382
  "src/commands/_shared/openai-image.ts"() {
44341
44383
  "use strict";
44342
44384
  init_dist2();
44343
- OPENAI_IMAGE_MODELS = {
44344
- "gpt-image-2.5-sunburst": { label: "GPT Image 2.5 Sunburst", aliases: ["2.5", "sunburst"] },
44345
- "gpt-image-2.5-flare": { label: "GPT Image 2.5 Flare", aliases: ["flare", "2.5-flare"] },
44346
- "gpt-image-2": { label: "GPT Image 2", aliases: ["2"] },
44347
- "gpt-image-1.5": { label: "GPT Image 1.5", aliases: ["1.5"] }
44385
+ }
44386
+ });
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
+ ]
44348
44404
  };
44349
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
+ }
44350
44420
  });
44351
44421
 
44352
44422
  // src/commands/generate/image.ts
@@ -44446,6 +44516,7 @@ Examples:
44446
44516
  command: "generate image",
44447
44517
  startedAt,
44448
44518
  dryRun: true,
44519
+ ...estimateImageCostUsd(provider, options.model, parseInt(options.count) || 1),
44449
44520
  data: {
44450
44521
  params: {
44451
44522
  prompt: prompt3,
@@ -44495,6 +44566,7 @@ Examples:
44495
44566
  outputSuccess({
44496
44567
  command: "generate image",
44497
44568
  startedAt,
44569
+ ...estimateImageCostUsd("openai", options.model, result.images.length),
44498
44570
  data: {
44499
44571
  provider: "openai",
44500
44572
  model: modelLabel,
@@ -44610,7 +44682,7 @@ Examples:
44610
44682
  outputSuccess({
44611
44683
  command: "generate image",
44612
44684
  startedAt,
44613
- warnings: [],
44685
+ ...estimateImageCostUsd("gemini", options.model, result.images.length),
44614
44686
  data: {
44615
44687
  provider: "gemini",
44616
44688
  model: usedLabel,
@@ -44705,6 +44777,7 @@ Examples:
44705
44777
  outputSuccess({
44706
44778
  command: "generate image",
44707
44779
  startedAt,
44780
+ ...estimateImageCostUsd("grok", options.model, result.images.length),
44708
44781
  data: {
44709
44782
  provider: "grok",
44710
44783
  modelId: resolveGrokImageModel(options.model).model,
@@ -44824,6 +44897,7 @@ var init_image = __esm({
44824
44897
  init_validate();
44825
44898
  init_provider_resolver();
44826
44899
  init_openai_image2();
44900
+ init_image_cost();
44827
44901
  init_image_file();
44828
44902
  }
44829
44903
  });
@@ -45923,6 +45997,14 @@ Examples:
45923
45997
  log(`${provider} does not support 1:1 \u2014 falling back to 16:9`);
45924
45998
  options.ratio = "16:9";
45925
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
+ }
45926
46008
  if (options.dryRun) {
45927
46009
  const costUsd = provider === "seedance" || provider === "fal" ? realRunCost(provider, options).costUsd : void 0;
45928
46010
  outputSuccess({
@@ -46645,10 +46727,11 @@ var OpenAIAdapter;
46645
46727
  var init_openai2 = __esm({
46646
46728
  "src/agent/adapters/openai.ts"() {
46647
46729
  "use strict";
46730
+ init_dist2();
46648
46731
  OpenAIAdapter = class {
46649
46732
  provider = "openai";
46650
46733
  client = null;
46651
- model = "gpt-5.4-mini";
46734
+ model = defaultModel("openai", "llm").id;
46652
46735
  async initialize(apiKey) {
46653
46736
  this.client = new OpenAI({ apiKey });
46654
46737
  }
@@ -46741,10 +46824,11 @@ var ClaudeAdapter;
46741
46824
  var init_claude2 = __esm({
46742
46825
  "src/agent/adapters/claude.ts"() {
46743
46826
  "use strict";
46827
+ init_dist2();
46744
46828
  ClaudeAdapter = class {
46745
46829
  provider = "claude";
46746
46830
  client = null;
46747
- model = "claude-sonnet-5-5";
46831
+ model = defaultModel("claude", "llm").id;
46748
46832
  async initialize(apiKey) {
46749
46833
  this.client = new Anthropic({ apiKey });
46750
46834
  }
@@ -47225,10 +47309,11 @@ var XAIAdapter;
47225
47309
  var init_xai = __esm({
47226
47310
  "src/agent/adapters/xai.ts"() {
47227
47311
  "use strict";
47312
+ init_dist2();
47228
47313
  XAIAdapter = class {
47229
47314
  provider = "xai";
47230
47315
  client = null;
47231
- model = "grok-4.3";
47316
+ model = defaultModel("grok", "llm").id;
47232
47317
  async initialize(apiKey) {
47233
47318
  this.client = new OpenAI2({
47234
47319
  apiKey,
@@ -52047,8 +52132,9 @@ var EXPLICIT_COMMAND_METADATA = {
52047
52132
  schema: { surface: "agent", note: "Machine-readable command discovery." },
52048
52133
  completion: { surface: "advanced", note: "Shell ergonomics helper." },
52049
52134
  agent: {
52050
- surface: "advanced",
52051
- note: "Optional fallback REPL; external coding agents are the primary workflow."
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."
52052
52138
  },
52053
52139
  "design.validate": { surface: "public", note: "Validate the DESIGN.md visual contract." },
52054
52140
  "generate.image": { surface: "public" },
@@ -62066,8 +62152,9 @@ they want for a given task. This guide is the operator-facing summary.
62066
62152
 
62067
62153
  If you already use Claude Code, Codex, Cursor, Aider, Gemini CLI, OpenCode,
62068
62154
  or another coding agent, let that host drive \`vibe\` directly through shell
62069
- commands plus \`AGENTS.md\` / \`CLAUDE.md\`. \`vibe agent\` is the optional
62070
- built-in fallback when you do not already have an agent host.
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.
62071
62158
 
62072
62159
  ## TL;DR
62073
62160
 
@@ -62078,12 +62165,12 @@ built-in fallback when you do not already have an agent host.
62078
62165
  | **Reproducibility** | none | high (idempotent) | highest (checkpointed) |
62079
62166
  | **Budget caps** | per-session max-turns | none | \`--budget-usd\`, \`--budget-tokens\`, \`--max-errors\` |
62080
62167
  | **Resume after crash** | no | re-invoke | \`--resume\` |
62081
- | **Best for** | optional built-in exploration | finished script | repeatable workflows |
62168
+ | **Best for** | deprecated; use a host agent | finished script | repeatable workflows |
62082
62169
 
62083
62170
  ## Decision tree
62084
62171
 
62085
62172
  - "I am already in Claude Code/Codex/Cursor/etc." \u2192 regular \`vibe\` shell commands + \`vibe guide\` / \`vibe schema\`
62086
- - "I want to play and do not have an external coding agent" \u2192 \`vibe agent\`
62173
+ - "I do not use a coding agent" \u2192 the MCP server in Claude Desktop or ChatGPT (\`vibe host setup\`)
62087
62174
  - "I have a finished script + visual identity" \u2192 \`vibe build\`
62088
62175
  - "I want this to run again next month" \u2192 \`vibe run\`
62089
62176
 
@@ -62109,9 +62196,6 @@ agent calls them through a tool manifest; \`build\` calls a curated subset
62109
62196
  - \`vibe build\` is conceptually a 4-step pipeline; \`vibe run\` could express
62110
62197
  the same flow but build's STORYBOARD.md input + opinionated defaults are
62111
62198
  the value-add.
62112
- - \`vibe agent\`'s tool registry currently exposes primitives, not
62113
- orchestrators. Adding \`vibe.build\` / \`vibe.run\` as agent tools is on the
62114
- table for a future major.
62115
62199
  - \`vibe run --resume\` has no analog in build/agent; build's idempotent
62116
62200
  re-invoke covers the common case.
62117
62201
  `;
@@ -62218,17 +62302,17 @@ var META = {
62218
62302
  },
62219
62303
  architecture: {
62220
62304
  title: "external agents / vibe agent / build / run",
62221
- summary: "Choose between host-agent shell use, optional built-in agent mode, storyboard builds, and YAML pipelines",
62305
+ summary: "Choose between host-agent shell use, MCP hosts, storyboard builds, and YAML pipelines",
62222
62306
  steps: [
62223
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`.",
62224
- "Pick `vibe agent` only for optional built-in exploration when no external agent host is driving the CLI.",
62308
+ "Without a coding agent, connect the MCP server to Claude Desktop or ChatGPT with `vibe host setup`; `vibe agent` is deprecated.",
62225
62309
  "Pick build for STORYBOARD.md \u2192 MP4 with opinionated defaults.",
62226
62310
  "Pick run for repeatable, budget-capped, checkpointed YAML pipelines.",
62227
62311
  "Run `vibe doctor --test-keys` before any high-cost orchestrator to validate keys upfront.",
62228
62312
  "Use `vibe schema --list` (cost field, v0.84) to plan the budget per step before kicking off `vibe run --budget-usd`."
62229
62313
  ],
62230
62314
  relatedCommands: [
62231
- "vibe agent",
62315
+ "vibe host setup",
62232
62316
  "vibe build",
62233
62317
  "vibe run",
62234
62318
  "vibe doctor",