@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.
package/dist/index.js CHANGED
@@ -7222,6 +7222,82 @@ var init_whisper = __esm({
7222
7222
  }
7223
7223
  });
7224
7224
 
7225
+ // ../ai-providers/dist/catalog/catalog.js
7226
+ function listModels(filter = {}) {
7227
+ return MODEL_CATALOG.filter((m) => (!filter.provider || m.provider === filter.provider) && (!filter.kind || m.kind === filter.kind));
7228
+ }
7229
+ function defaultModel(provider, kind) {
7230
+ const found = MODEL_CATALOG.find((m) => m.provider === provider && m.kind === kind && m.default);
7231
+ if (!found)
7232
+ throw new Error(`Model catalog has no default ${kind} model for ${provider}`);
7233
+ return found;
7234
+ }
7235
+ function findModel(provider, kind, aliasOrId) {
7236
+ const key = aliasOrId?.trim();
7237
+ if (!key)
7238
+ return defaultModel(provider, kind);
7239
+ const lower = key.toLowerCase();
7240
+ return listModels({ provider, kind }).find((m) => m.id === key || m.aliases?.includes(lower));
7241
+ }
7242
+ function modelAliases(provider, kind) {
7243
+ return listModels({ provider, kind }).flatMap((m) => m.aliases ?? []);
7244
+ }
7245
+ var MODEL_CATALOG;
7246
+ var init_catalog = __esm({
7247
+ "../ai-providers/dist/catalog/catalog.js"() {
7248
+ "use strict";
7249
+ MODEL_CATALOG = [
7250
+ // ── LLMs ──────────────────────────────────────────────────────────────
7251
+ { 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" },
7252
+ { 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" } },
7253
+ { 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" } },
7254
+ { 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)" },
7255
+ { 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" } },
7256
+ { id: "gemini-3.5-flash", provider: "gemini", kind: "llm", label: "Gemini 3.5 Flash", aliases: ["flash-3.5"], status: "ga" },
7257
+ { id: "gemini-3-flash-preview", provider: "gemini", kind: "llm", label: "Gemini 3 Flash (preview)", aliases: ["flash-3"], status: "preview" },
7258
+ { 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" },
7259
+ { 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" },
7260
+ { id: "gemini-2.5-pro", provider: "gemini", kind: "llm", label: "Gemini 2.5 Pro", aliases: ["pro-2.5", "2.5-pro"], status: "legacy" },
7261
+ { id: "grok-4.3", provider: "grok", kind: "llm", label: "Grok 4.3", default: true, status: "ga", price: { usd: 1.25, per: "1M input tokens" } },
7262
+ { id: "grok-4.7", provider: "grok", kind: "llm", label: "Grok 4.7", status: "ga", price: { usd: 2, per: "1M input tokens" } },
7263
+ // ── Images ────────────────────────────────────────────────────────────
7264
+ { 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" } },
7265
+ { 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" } },
7266
+ { 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" } },
7267
+ { 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" } },
7268
+ { 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" } },
7269
+ { 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" } },
7270
+ { 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" } },
7271
+ { id: "gemini-2.5-flash-image", provider: "gemini", kind: "image", label: "Nano Banana (2.5 Flash Image)", status: "deprecated", shutdown: "2026-10-02" },
7272
+ { id: "gemini-3.1-flash-image-preview", provider: "gemini", kind: "image", label: "Nano Banana 2 (preview)", status: "deprecated", shutdown: "2026-06-25" },
7273
+ { id: "gemini-3-pro-image-preview", provider: "gemini", kind: "image", label: "Nano Banana Pro (preview)", status: "deprecated", shutdown: "2026-06-25" },
7274
+ { id: "grok-imagine-image", provider: "grok", kind: "image", label: "Grok Imagine Image", default: true, status: "ga", price: { usd: 0.02, per: "image" } },
7275
+ { 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" } },
7276
+ // ── Video ─────────────────────────────────────────────────────────────
7277
+ { 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" },
7278
+ { 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" },
7279
+ { 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" },
7280
+ { 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" },
7281
+ { 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" },
7282
+ { 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" },
7283
+ { 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" },
7284
+ { 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" },
7285
+ { 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" },
7286
+ { 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" },
7287
+ { 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" },
7288
+ { 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" },
7289
+ { 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" },
7290
+ { 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" },
7291
+ // ── Audio ─────────────────────────────────────────────────────────────
7292
+ { id: "eleven_v3", provider: "elevenlabs", kind: "speech", label: "ElevenLabs v3", default: true, status: "ga", price: { usd: 0.08, per: "1K characters" } },
7293
+ { id: "gpt-4o-mini-tts", provider: "openai", kind: "speech", label: "GPT-4o mini TTS", default: true, status: "deprecated", shutdown: "2027-01-06" },
7294
+ { id: "music_v2_5", provider: "elevenlabs", kind: "music", label: "ElevenLabs Music v2.5", default: true, status: "ga", price: { usd: 0.15, per: "minute" } },
7295
+ { 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" },
7296
+ { id: "whisper-1", provider: "openai", kind: "transcription", label: "Whisper", default: true, status: "deprecated", shutdown: "2027-02-26", note: "Only OpenAI model with word timestamps" }
7297
+ ];
7298
+ }
7299
+ });
7300
+
7225
7301
  // ../ai-providers/dist/gemini/gemini-models.js
7226
7302
  function isGeminiTextModelAlias(model) {
7227
7303
  return Object.prototype.hasOwnProperty.call(GEMINI_TEXT_MODEL_ALIASES, model);
@@ -7240,19 +7316,10 @@ var GEMINI_DEFAULT_TEXT_MODEL, GEMINI_AGENT_DEFAULT_TEXT_MODEL, GEMINI_TEXT_MODE
7240
7316
  var init_gemini_models = __esm({
7241
7317
  "../ai-providers/dist/gemini/gemini-models.js"() {
7242
7318
  "use strict";
7243
- GEMINI_DEFAULT_TEXT_MODEL = "gemini-3.8-flash";
7319
+ init_catalog();
7320
+ GEMINI_DEFAULT_TEXT_MODEL = defaultModel("gemini", "llm").id;
7244
7321
  GEMINI_AGENT_DEFAULT_TEXT_MODEL = GEMINI_DEFAULT_TEXT_MODEL;
7245
- GEMINI_TEXT_MODEL_ALIASES = {
7246
- flash: GEMINI_DEFAULT_TEXT_MODEL,
7247
- latest: GEMINI_DEFAULT_TEXT_MODEL,
7248
- "flash-3.8": GEMINI_DEFAULT_TEXT_MODEL,
7249
- "flash-3.5": "gemini-3.5-flash",
7250
- "flash-3": "gemini-3-flash-preview",
7251
- "flash-2.5": "gemini-2.5-flash",
7252
- pro: "gemini-3.1-pro-preview",
7253
- "pro-3.1": "gemini-3.1-pro-preview",
7254
- "pro-2.5": "gemini-2.5-pro"
7255
- };
7322
+ GEMINI_TEXT_MODEL_ALIASES = Object.fromEntries(listModels({ provider: "gemini", kind: "llm" }).flatMap((m) => (m.aliases ?? []).map((a) => [a, m.id])));
7256
7323
  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";
7257
7324
  }
7258
7325
  });
@@ -7586,19 +7653,7 @@ var init_gemini_motion = __esm({
7586
7653
  "../ai-providers/dist/gemini/gemini-motion.js"() {
7587
7654
  "use strict";
7588
7655
  init_gemini_models();
7589
- GEMINI_MOTION_MODELS = {
7590
- gemini: GEMINI_DEFAULT_TEXT_MODEL,
7591
- flash: GEMINI_DEFAULT_TEXT_MODEL,
7592
- latest: GEMINI_DEFAULT_TEXT_MODEL,
7593
- "flash-3.8": GEMINI_DEFAULT_TEXT_MODEL,
7594
- "flash-3.5": "gemini-3.5-flash",
7595
- "flash-3": "gemini-3-flash-preview",
7596
- "flash-2.5": "gemini-2.5-flash",
7597
- pro: "gemini-3.1-pro-preview",
7598
- "2.5-pro": "gemini-2.5-pro",
7599
- "3.1-pro": "gemini-3.1-pro-preview",
7600
- "pro-3.1": "gemini-3.1-pro-preview"
7601
- };
7656
+ GEMINI_MOTION_MODELS = GEMINI_TEXT_MODEL_ALIASES;
7602
7657
  STYLE_USER_INSTRUCTIONS = {
7603
7658
  minimal: "CENTER-ALIGNED pure typography. Thin lines + large title + subtitle. NO glass panels, NO bokeh, NO dark bars. Breathing pulse during hold.",
7604
7659
  corporate: "Data-rich info bar at bottom + top-right badge. Animated number counter. Brand color stripe. Progress bar.",
@@ -7793,7 +7848,7 @@ function resolveVeoModel(alias) {
7793
7848
  const hint = alias === "3.0" ? " Veo 3.0 was shut down by Google on 2025-11-12." : "";
7794
7849
  throw new Error(`Unknown Veo model "${alias}". Valid: ${valid}.${hint}`);
7795
7850
  }
7796
- var VEO_MODEL_ALIASES, MODEL_MAP, GeminiProvider, geminiProvider;
7851
+ var VEO_MODEL_ALIASES, GeminiProvider, geminiProvider;
7797
7852
  var init_GeminiProvider = __esm({
7798
7853
  "../ai-providers/dist/gemini/GeminiProvider.js"() {
7799
7854
  "use strict";
@@ -7801,23 +7856,8 @@ var init_GeminiProvider = __esm({
7801
7856
  init_gemini_models();
7802
7857
  init_gemini_storyboard();
7803
7858
  init_http();
7804
- VEO_MODEL_ALIASES = {
7805
- "3.1": "veo-3.1-generate-preview",
7806
- "3.1-fast": "veo-3.1-fast-generate-preview"
7807
- };
7808
- MODEL_MAP = {
7809
- "flash": "gemini-3.1-flash-image",
7810
- "3.1-flash": "gemini-3.1-flash-image",
7811
- "latest": "gemini-3.1-flash-image",
7812
- "lite": "gemini-3.1-flash-lite-image",
7813
- "pro": "gemini-3-pro-image",
7814
- "gemini-3.1-flash-image": "gemini-3.1-flash-image",
7815
- "gemini-3.1-flash-lite-image": "gemini-3.1-flash-lite-image",
7816
- "gemini-3-pro-image": "gemini-3-pro-image",
7817
- "gemini-2.5-flash-image": "gemini-2.5-flash-image",
7818
- "gemini-3.1-flash-image-preview": "gemini-3.1-flash-image-preview",
7819
- "gemini-3-pro-image-preview": "gemini-3-pro-image-preview"
7820
- };
7859
+ init_catalog();
7860
+ VEO_MODEL_ALIASES = Object.fromEntries(listModels({ provider: "veo", kind: "video" }).flatMap((m) => (m.aliases ?? []).map((a) => [a, m.id])));
7821
7861
  GeminiProvider = class {
7822
7862
  constructor() {
7823
7863
  this.id = "gemini";
@@ -8076,9 +8116,7 @@ var init_GeminiProvider = __esm({
8076
8116
  * Resolve model alias to full model ID
8077
8117
  */
8078
8118
  resolveModel(model) {
8079
- if (!model)
8080
- return MODEL_MAP["flash"];
8081
- return MODEL_MAP[model] || MODEL_MAP["flash"];
8119
+ return (findModel("gemini", "image", model) ?? defaultModel("gemini", "image")).id;
8082
8120
  }
8083
8121
  /**
8084
8122
  * Check if model is Pro
@@ -8671,7 +8709,8 @@ var init_gemini_omni = __esm({
8671
8709
  "../ai-providers/dist/gemini/gemini-omni.js"() {
8672
8710
  "use strict";
8673
8711
  init_http();
8674
- OMNI_MODEL = "gemini-omni-1.1-flash";
8712
+ init_catalog();
8713
+ OMNI_MODEL = defaultModel("omni", "video").id;
8675
8714
  API_ROOT = "https://generativelanguage.googleapis.com";
8676
8715
  FILE_POLL_INTERVAL_MS = 3e3;
8677
8716
  FILE_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -8811,6 +8850,14 @@ var init_gemini = __esm({
8811
8850
  }
8812
8851
  });
8813
8852
 
8853
+ // ../ai-providers/dist/catalog/index.js
8854
+ var init_catalog2 = __esm({
8855
+ "../ai-providers/dist/catalog/index.js"() {
8856
+ "use strict";
8857
+ init_catalog();
8858
+ }
8859
+ });
8860
+
8814
8861
  // ../ai-providers/dist/openai/openai-storyboard.js
8815
8862
  async function analyzeContent2(apiKey, content, targetDuration, options) {
8816
8863
  const creativity = options?.creativity || "low";
@@ -8823,7 +8870,7 @@ async function analyzeContent2(apiKey, content, targetDuration, options) {
8823
8870
  Authorization: `Bearer ${apiKey}`
8824
8871
  },
8825
8872
  body: JSON.stringify({
8826
- model: "gpt-5.4-mini",
8873
+ model: defaultModel("openai", "llm").id,
8827
8874
  messages: [
8828
8875
  { role: "system", content: systemPrompt },
8829
8876
  { role: "user", content: buildStoryboardUserMessage(content) }
@@ -8868,6 +8915,7 @@ var init_openai_storyboard = __esm({
8868
8915
  "../ai-providers/dist/openai/openai-storyboard.js"() {
8869
8916
  "use strict";
8870
8917
  init_storyboard_prompt();
8918
+ init_catalog();
8871
8919
  }
8872
8920
  });
8873
8921
 
@@ -8877,6 +8925,7 @@ var init_OpenAIProvider = __esm({
8877
8925
  "../ai-providers/dist/openai/OpenAIProvider.js"() {
8878
8926
  "use strict";
8879
8927
  init_openai_storyboard();
8928
+ init_catalog();
8880
8929
  OpenAIProvider = class {
8881
8930
  constructor() {
8882
8931
  this.id = "openai-gpt";
@@ -8886,7 +8935,7 @@ var init_OpenAIProvider = __esm({
8886
8935
  this.iconUrl = "/icons/openai.svg";
8887
8936
  this.isAvailable = true;
8888
8937
  this.baseUrl = "https://api.openai.com/v1";
8889
- this.model = "gpt-5.4-mini";
8938
+ this.model = defaultModel("openai", "llm").id;
8890
8939
  }
8891
8940
  async initialize(config2) {
8892
8941
  this.apiKey = config2.apiKey;
@@ -9192,7 +9241,7 @@ Each segment should be 3-10 seconds long.`;
9192
9241
  Authorization: `Bearer ${this.apiKey}`
9193
9242
  },
9194
9243
  body: JSON.stringify({
9195
- model: "gpt-5.4-mini",
9244
+ model: defaultModel("openai", "llm").id,
9196
9245
  // Reasoning tokens count against this cap.
9197
9246
  max_completion_tokens: 16384,
9198
9247
  response_format: { type: "json_object" },
@@ -10593,6 +10642,7 @@ var init_ClaudeProvider = __esm({
10593
10642
  init_claude_analysis();
10594
10643
  init_claude_viral();
10595
10644
  init_claude_visual_fx();
10645
+ init_catalog();
10596
10646
  ClaudeProvider = class {
10597
10647
  constructor() {
10598
10648
  this.id = "claude";
@@ -10602,7 +10652,7 @@ var init_ClaudeProvider = __esm({
10602
10652
  this.iconUrl = "/icons/claude.svg";
10603
10653
  this.isAvailable = true;
10604
10654
  this.baseUrl = "https://api.anthropic.com/v1";
10605
- this.model = "claude-sonnet-5-5";
10655
+ this.model = defaultModel("claude", "llm").id;
10606
10656
  }
10607
10657
  async initialize(config2) {
10608
10658
  this.apiKey = config2.apiKey;
@@ -10904,11 +10954,7 @@ Instruction: ${instruction}`
10904
10954
  return generateNarrationScript(this.api, videoAnalysis, duration, style, language);
10905
10955
  }
10906
10956
  };
10907
- ClaudeProvider.MOTION_MODELS = {
10908
- sonnet: "claude-sonnet-5-5",
10909
- opus: "claude-opus-5-5",
10910
- "opus-4-6": "claude-opus-4-6"
10911
- };
10957
+ ClaudeProvider.MOTION_MODELS = Object.fromEntries(listModels({ provider: "claude", kind: "llm" }).flatMap((m) => (m.aliases ?? []).map((a) => [a, m.id])));
10912
10958
  claudeProvider = new ClaudeProvider();
10913
10959
  }
10914
10960
  });
@@ -11248,6 +11294,7 @@ var KNOWN_VOICES, TTS_429_MAX_RETRIES, TTS_429_RETRY_DELAY_MS, ELEVENLABS_MUSIC_
11248
11294
  var init_ElevenLabsProvider = __esm({
11249
11295
  "../ai-providers/dist/elevenlabs/ElevenLabsProvider.js"() {
11250
11296
  "use strict";
11297
+ init_catalog();
11251
11298
  KNOWN_VOICES = {
11252
11299
  // Default/popular voices
11253
11300
  rachel: "21m00Tcm4TlvDq8ikWAM",
@@ -11281,7 +11328,7 @@ var init_ElevenLabsProvider = __esm({
11281
11328
  };
11282
11329
  TTS_429_MAX_RETRIES = 1;
11283
11330
  TTS_429_RETRY_DELAY_MS = 2e3;
11284
- ELEVENLABS_MUSIC_MODEL = "music_v2_5";
11331
+ ELEVENLABS_MUSIC_MODEL = defaultModel("elevenlabs", "music").id;
11285
11332
  ElevenLabsProvider = class {
11286
11333
  constructor() {
11287
11334
  this.id = "elevenlabs";
@@ -11945,7 +11992,8 @@ var OPENAI_IMAGE_DEFAULT_MODEL, DEFAULT_MODEL, OpenAIImageProvider, openaiImageP
11945
11992
  var init_OpenAIImageProvider = __esm({
11946
11993
  "../ai-providers/dist/openai-image/OpenAIImageProvider.js"() {
11947
11994
  "use strict";
11948
- OPENAI_IMAGE_DEFAULT_MODEL = "gpt-image-2.5-sunburst";
11995
+ init_catalog();
11996
+ OPENAI_IMAGE_DEFAULT_MODEL = defaultModel("openai", "image").id;
11949
11997
  DEFAULT_MODEL = OPENAI_IMAGE_DEFAULT_MODEL;
11950
11998
  OpenAIImageProvider = class {
11951
11999
  constructor() {
@@ -12269,7 +12317,8 @@ var DEFAULT_MODEL3, RunwayProvider, runwayProvider;
12269
12317
  var init_RunwayProvider = __esm({
12270
12318
  "../ai-providers/dist/runway/RunwayProvider.js"() {
12271
12319
  "use strict";
12272
- DEFAULT_MODEL3 = "gen4.5";
12320
+ init_catalog();
12321
+ DEFAULT_MODEL3 = defaultModel("runway", "video").id;
12273
12322
  RunwayProvider = class _RunwayProvider {
12274
12323
  constructor() {
12275
12324
  this.id = "runway";
@@ -12322,6 +12371,13 @@ var init_RunwayProvider = __esm({
12322
12371
  }
12323
12372
  const hasImage = !!options?.referenceImage;
12324
12373
  const endpoint = hasImage ? "image_to_video" : "text_to_video";
12374
+ if (!hasImage && apiRatio === "960:960") {
12375
+ return {
12376
+ id: "",
12377
+ status: "failed",
12378
+ 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."
12379
+ };
12380
+ }
12325
12381
  const body = {
12326
12382
  model,
12327
12383
  promptText: prompt3,
@@ -12422,7 +12478,9 @@ var init_RunwayProvider = __esm({
12422
12478
  SUCCEEDED: "completed",
12423
12479
  FAILED: "failed",
12424
12480
  CANCELLED: "cancelled",
12425
- THROTTLED: "failed"
12481
+ // THROTTLED means queued behind the account's concurrency limit; the
12482
+ // task starts on its own, so keep polling.
12483
+ THROTTLED: "pending"
12426
12484
  };
12427
12485
  const result = {
12428
12486
  id: data.id,
@@ -12432,8 +12490,9 @@ var init_RunwayProvider = __esm({
12432
12490
  if (data.status === "SUCCEEDED" && data.output && data.output.length > 0) {
12433
12491
  result.videoUrl = data.output[0];
12434
12492
  }
12435
- if (data.status === "FAILED" || data.status === "THROTTLED") {
12436
- result.error = data.failure || data.failureCode || "Generation failed";
12493
+ if (data.status === "FAILED") {
12494
+ const reason = data.failure || "Generation failed";
12495
+ result.error = data.failureCode ? `${reason} (${data.failureCode})` : reason;
12437
12496
  }
12438
12497
  return result;
12439
12498
  } catch (error) {
@@ -12445,27 +12504,14 @@ var init_RunwayProvider = __esm({
12445
12504
  }
12446
12505
  }
12447
12506
  /**
12448
- * Cancel ongoing generation
12507
+ * Cancel a pending or running task. Runway documents cancellation as
12508
+ * `DELETE /v1/tasks/{id}` (there is no `/cancel` route).
12449
12509
  */
12450
12510
  async cancelGeneration(id) {
12451
- if (!this.apiKey) {
12452
- return false;
12453
- }
12454
- try {
12455
- const response = await fetch(`${this.baseUrl}/tasks/${id}/cancel`, {
12456
- method: "POST",
12457
- headers: {
12458
- Authorization: `Bearer ${this.apiKey}`,
12459
- "X-Runway-Version": _RunwayProvider.API_VERSION
12460
- }
12461
- });
12462
- return response.ok;
12463
- } catch {
12464
- return false;
12465
- }
12511
+ return this.deleteTask(id);
12466
12512
  }
12467
12513
  /**
12468
- * Delete a completed task
12514
+ * Cancel a running task, or delete a finished one (`DELETE /v1/tasks/{id}`).
12469
12515
  */
12470
12516
  async deleteTask(id) {
12471
12517
  if (!this.apiKey) {
@@ -12575,19 +12621,10 @@ var init_runway = __esm({
12575
12621
  // ../ai-providers/dist/kling/KlingProvider.js
12576
12622
  import { createHmac } from "node:crypto";
12577
12623
  function resolveKlingModel(alias) {
12578
- const key = (alias ?? "v3").trim().toLowerCase();
12579
- const aliases = {
12580
- v3: "kling-v3",
12581
- "kling-v3": "kling-v3",
12582
- "v2.6": "kling-v2-6",
12583
- "kling-v2-6": "kling-v2-6",
12584
- "v2.5-turbo": "kling-v2-5-turbo",
12585
- "v2.5": "kling-v2-5-turbo",
12586
- "kling-v2-5-turbo": "kling-v2-5-turbo"
12587
- };
12588
- if (Object.hasOwn(aliases, key))
12589
- return aliases[key];
12590
- throw new Error(`Unknown Kling model "${alias}". Valid: v3, v2.6, v2.5-turbo.`);
12624
+ const model = findModel("kling", "video", alias);
12625
+ if (model)
12626
+ return model.id;
12627
+ throw new Error(`Unknown Kling model "${alias}". Valid: ${modelAliases("kling", "video").join(", ")}.`);
12591
12628
  }
12592
12629
  function klingDuration(model, seconds) {
12593
12630
  const requested = typeof seconds === "number" && Number.isFinite(seconds) ? Math.round(seconds) : 5;
@@ -12599,7 +12636,8 @@ var DEFAULT_MODEL4, STD_MODE_MODELS, KlingProvider, klingProvider;
12599
12636
  var init_KlingProvider = __esm({
12600
12637
  "../ai-providers/dist/kling/KlingProvider.js"() {
12601
12638
  "use strict";
12602
- DEFAULT_MODEL4 = "kling-v3";
12639
+ init_catalog();
12640
+ DEFAULT_MODEL4 = defaultModel("kling", "video").id;
12603
12641
  STD_MODE_MODELS = ["kling-v2-5-turbo", "kling-v2-6", "kling-v3"];
12604
12642
  KlingProvider = class {
12605
12643
  constructor() {
@@ -13038,31 +13076,21 @@ var init_kling = __esm({
13038
13076
 
13039
13077
  // ../ai-providers/dist/grok/GrokProvider.js
13040
13078
  function resolveGrokVideoModel(alias) {
13041
- const key = (alias ?? "1.5").trim().toLowerCase();
13042
- const aliases = {
13043
- "1.5": "grok-imagine-video-1.5",
13044
- "grok-imagine-video-1.5": "grok-imagine-video-1.5",
13045
- lite: "grok-imagine-video-1.5-lite",
13046
- "1.5-lite": "grok-imagine-video-1.5-lite",
13047
- "grok-imagine-video-1.5-lite": "grok-imagine-video-1.5-lite",
13048
- classic: "grok-imagine-video",
13049
- "grok-imagine-video": "grok-imagine-video"
13050
- };
13051
- if (Object.hasOwn(aliases, key))
13052
- return aliases[key];
13053
- throw new Error(`Unknown Grok video model "${alias}". Valid: 1.5, lite, classic.`);
13079
+ const model = findModel("grok", "video", alias);
13080
+ if (model)
13081
+ return model.id;
13082
+ throw new Error(`Unknown Grok video model "${alias}". Valid: ${modelAliases("grok", "video").join(", ")}.`);
13054
13083
  }
13055
13084
  function resolveGrokImageModel(alias) {
13056
- if (alias === "pro" || alias === "2.0" || alias === "quality" || alias === "grok-imagine-image-2.0") {
13057
- return { model: "grok-imagine-image-2.0", quality: "medium" };
13058
- }
13059
- return { model: "grok-imagine-image" };
13085
+ const model = (findModel("grok", "image", alias) ?? defaultModel("grok", "image")).id;
13086
+ return model === "grok-imagine-image-2.0" ? { model, quality: "medium" } : { model };
13060
13087
  }
13061
13088
  var DEFAULT_MODEL5, DEFAULT_VIDEO_RESOLUTION, GROK_VIDEO_RESOLUTIONS, GrokProvider, grokProvider;
13062
13089
  var init_GrokProvider = __esm({
13063
13090
  "../ai-providers/dist/grok/GrokProvider.js"() {
13064
13091
  "use strict";
13065
- DEFAULT_MODEL5 = "grok-imagine-video-1.5";
13092
+ init_catalog();
13093
+ DEFAULT_MODEL5 = defaultModel("grok", "video").id;
13066
13094
  DEFAULT_VIDEO_RESOLUTION = "720p";
13067
13095
  GROK_VIDEO_RESOLUTIONS = ["480p", "720p", "1080p"];
13068
13096
  GrokProvider = class {
@@ -17505,19 +17533,10 @@ var require_src = __commonJS({
17505
17533
 
17506
17534
  // ../ai-providers/dist/fal/FalProvider.js
17507
17535
  function resolveSeedanceVariant(alias) {
17508
- const key = (alias ?? "quality").trim().toLowerCase();
17509
- const aliases = {
17510
- quality: "seedance-2.0",
17511
- "2.0": "seedance-2.0",
17512
- "seedance-2.0": "seedance-2.0",
17513
- fast: "seedance-2.0-fast",
17514
- "seedance-2.0-fast": "seedance-2.0-fast",
17515
- "2.5": "seedance-2.5",
17516
- "seedance-2.5": "seedance-2.5"
17517
- };
17518
- if (Object.hasOwn(aliases, key))
17519
- return aliases[key];
17520
- throw new Error(`Unknown Seedance model "${alias}". Valid: quality, fast, 2.5.`);
17536
+ const model = findModel("seedance", "video", alias);
17537
+ if (model)
17538
+ return model.id;
17539
+ throw new Error(`Unknown Seedance model "${alias}". Valid: ${modelAliases("seedance", "video").join(", ")}.`);
17521
17540
  }
17522
17541
  function estimateSeedanceVideoCostUsd(opts) {
17523
17542
  const shortSide = SEEDANCE_SHORT_SIDE[opts.resolution ?? "720p"] ?? 720;
@@ -17645,6 +17664,7 @@ var init_FalProvider = __esm({
17645
17664
  "../ai-providers/dist/fal/FalProvider.js"() {
17646
17665
  "use strict";
17647
17666
  import_client = __toESM(require_src(), 1);
17667
+ init_catalog();
17648
17668
  ENDPOINT_TEXT_TO_VIDEO = {
17649
17669
  "seedance-2.0": "bytedance/seedance-2.0/text-to-video",
17650
17670
  "seedance-2.0-fast": "bytedance/seedance-2.0/fast/text-to-video",
@@ -18489,6 +18509,7 @@ __export(dist_exports2, {
18489
18509
  KOKORO_MODEL_ID: () => KOKORO_MODEL_ID,
18490
18510
  KlingProvider: () => KlingProvider,
18491
18511
  KokoroProvider: () => KokoroProvider,
18512
+ MODEL_CATALOG: () => MODEL_CATALOG,
18492
18513
  OPENAI_IMAGE_DEFAULT_MODEL: () => OPENAI_IMAGE_DEFAULT_MODEL,
18493
18514
  OPENAI_TTS_VOICES: () => OPENAI_TTS_VOICES,
18494
18515
  OllamaProvider: () => OllamaProvider,
@@ -18501,11 +18522,13 @@ __export(dist_exports2, {
18501
18522
  VEO_MODEL_ALIASES: () => VEO_MODEL_ALIASES,
18502
18523
  WhisperProvider: () => WhisperProvider,
18503
18524
  claudeProvider: () => claudeProvider,
18525
+ defaultModel: () => defaultModel,
18504
18526
  defineApiKey: () => defineApiKey,
18505
18527
  defineProvider: () => defineProvider,
18506
18528
  elevenLabsProvider: () => elevenLabsProvider,
18507
18529
  estimateSeedanceVideoCostUsd: () => estimateSeedanceVideoCostUsd,
18508
18530
  falProvider: () => falProvider,
18531
+ findModel: () => findModel,
18509
18532
  geminiProvider: () => geminiProvider,
18510
18533
  getAllApiKeys: () => getAllApiKeys,
18511
18534
  getAllProviders: () => getAllProviders,
@@ -18522,8 +18545,10 @@ __export(dist_exports2, {
18522
18545
  klingDuration: () => klingDuration,
18523
18546
  klingProvider: () => klingProvider,
18524
18547
  kokoroProvider: () => kokoroProvider,
18548
+ listModels: () => listModels,
18525
18549
  loadBundledKokoroRuntime: () => loadBundledKokoroRuntime,
18526
18550
  loadKokoroFromWorkspace: () => loadKokoroFromWorkspace,
18551
+ modelAliases: () => modelAliases,
18527
18552
  ollamaProvider: () => ollamaProvider,
18528
18553
  omniProvider: () => omniProvider,
18529
18554
  openaiImageProvider: () => openaiImageProvider,
@@ -18550,6 +18575,7 @@ var init_dist2 = __esm({
18550
18575
  init_define_provider();
18551
18576
  init_whisper();
18552
18577
  init_gemini();
18578
+ init_catalog2();
18553
18579
  init_openai();
18554
18580
  init_claude();
18555
18581
  init_ollama();
@@ -32160,16 +32186,14 @@ import { tmpdir } from "node:os";
32160
32186
  import { createHash } from "node:crypto";
32161
32187
  async function ensureRemotionInstalled() {
32162
32188
  try {
32163
- await execSafe("npx", ["--yes", "remotion", "--help"], { timeout: 6e4 });
32189
+ await execSafe("npm", ["--version"], { timeout: 3e4 });
32164
32190
  return null;
32165
32191
  } catch (error) {
32166
32192
  const detail = error instanceof Error ? error.message : String(error);
32167
- console.error(`[Remotion] ensureRemotionInstalled failed: ${detail.slice(0, 300)}`);
32168
32193
  return [
32169
- "Remotion CLI not found or failed to initialize.",
32194
+ "Remotion renders need npm to install the Remotion CLI into a temporary project.",
32170
32195
  ` Debug: ${detail.slice(0, 200)}`,
32171
- " Fix: npm install -g @remotion/cli",
32172
- " Or ensure npx is available and can download @remotion/cli on demand."
32196
+ " Fix: install Node.js 20+ (which includes npm) and make sure `npm` is on PATH."
32173
32197
  ].join("\n");
32174
32198
  }
32175
32199
  }
@@ -32911,6 +32935,13 @@ __export(ai_motion_exports, {
32911
32935
  import { resolve as resolve18 } from "node:path";
32912
32936
  import { existsSync as existsSync13 } from "node:fs";
32913
32937
  import { readFile as readFile14, writeFile as writeFile14 } from "node:fs/promises";
32938
+ function resolveMotionModel(alias) {
32939
+ const claude = findModel("claude", "llm", alias);
32940
+ if (claude) return { provider: "claude", modelId: claude.id };
32941
+ const gemini = findModel("gemini", "llm", alias);
32942
+ if (gemini) return { provider: "gemini", modelId: gemini.id };
32943
+ return { provider: "claude", modelId: defaultModel("claude", "llm").id };
32944
+ }
32914
32945
  async function getOptionalGoogleApiKey() {
32915
32946
  const configKey = await getApiKeyFromConfig("google");
32916
32947
  if (configKey) return configKey;
@@ -32925,7 +32956,7 @@ function normalizeUnderstand(value) {
32925
32956
  }
32926
32957
  async function executeMotion(options) {
32927
32958
  const modelAlias = options.model || "sonnet";
32928
- const modelConfig = MODEL_MAP2[modelAlias] ?? MODEL_MAP2["sonnet"];
32959
+ const modelConfig = resolveMotionModel(modelAlias);
32929
32960
  const useGemini = modelConfig.provider === "gemini";
32930
32961
  const width = options.width || 1920;
32931
32962
  const height = options.height || 1080;
@@ -33304,7 +33335,6 @@ function registerMotionCommand(aiCommand) {
33304
33335
  }
33305
33336
  });
33306
33337
  }
33307
- var MODEL_MAP2;
33308
33338
  var init_ai_motion = __esm({
33309
33339
  "src/commands/ai-motion.ts"() {
33310
33340
  "use strict";
@@ -33315,14 +33345,6 @@ var init_ai_motion = __esm({
33315
33345
  init_config();
33316
33346
  init_output();
33317
33347
  init_validate();
33318
- MODEL_MAP2 = {
33319
- sonnet: { provider: "claude", modelId: "claude-sonnet-5-5" },
33320
- opus: { provider: "claude", modelId: "claude-opus-5-5" },
33321
- "opus-4-6": { provider: "claude", modelId: "claude-opus-4-6" },
33322
- gemini: { provider: "gemini", modelId: GEMINI_DEFAULT_TEXT_MODEL },
33323
- "gemini-2.5-pro": { provider: "gemini", modelId: "gemini-2.5-pro" },
33324
- "gemini-3.1-pro": { provider: "gemini", modelId: "gemini-3.1-pro-preview" }
33325
- };
33326
33348
  }
33327
33349
  });
33328
33350
 
@@ -34088,12 +34110,15 @@ var init_ai_helpers = __esm({
34088
34110
  });
34089
34111
 
34090
34112
  // src/commands/_shared/video-utils.ts
34091
- async function uploadToImgbb(imageBuffer, apiKey) {
34113
+ async function uploadToImgbb(imageBuffer, apiKey, expirationSeconds) {
34092
34114
  try {
34093
34115
  const base64Image = imageBuffer.toString("base64");
34094
34116
  const formData = new URLSearchParams();
34095
34117
  formData.append("key", apiKey);
34096
34118
  formData.append("image", base64Image);
34119
+ if (expirationSeconds !== void 0) {
34120
+ formData.append("expiration", String(expirationSeconds));
34121
+ }
34097
34122
  const response = await fetch("https://api.imgbb.com/1/upload", {
34098
34123
  method: "POST",
34099
34124
  body: formData
@@ -34156,7 +34181,10 @@ function awsEncode(value) {
34156
34181
  (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
34157
34182
  );
34158
34183
  }
34159
- function presignS3PutUrl(params) {
34184
+ function clamp(value, min, max) {
34185
+ return Math.min(max, Math.max(min, Math.round(value)));
34186
+ }
34187
+ function presignS3Url(params) {
34160
34188
  const now = /* @__PURE__ */ new Date();
34161
34189
  const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, "");
34162
34190
  const dateStamp = amzDate.slice(0, 8);
@@ -34167,7 +34195,7 @@ function presignS3PutUrl(params) {
34167
34195
  "X-Amz-Algorithm": "AWS4-HMAC-SHA256",
34168
34196
  "X-Amz-Credential": `${params.accessKeyId}/${credentialScope}`,
34169
34197
  "X-Amz-Date": amzDate,
34170
- "X-Amz-Expires": String(params.ttlSeconds),
34198
+ "X-Amz-Expires": String(clamp(params.ttlSeconds, 1, S3_MAX_PRESIGN_SECONDS)),
34171
34199
  "X-Amz-SignedHeaders": "host"
34172
34200
  };
34173
34201
  if (params.sessionToken) {
@@ -34175,7 +34203,7 @@ function presignS3PutUrl(params) {
34175
34203
  }
34176
34204
  const canonicalQuery = Object.entries(query).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => `${awsEncode(key)}=${awsEncode(value)}`).join("&");
34177
34205
  const canonicalRequest = [
34178
- "PUT",
34206
+ params.method,
34179
34207
  canonicalUri,
34180
34208
  canonicalQuery,
34181
34209
  `host:${host}`,
@@ -34234,7 +34262,8 @@ async function resolveUploadHost() {
34234
34262
  const ext = extensionFor(opts);
34235
34263
  const prefix = safePrefix(settings.s3.prefix);
34236
34264
  const key = `${prefix}/${Date.now()}-${randomUUID()}.${ext}`;
34237
- const presignedUrl = presignS3PutUrl({
34265
+ const presignedUrl = presignS3Url({
34266
+ method: "PUT",
34238
34267
  accessKeyId,
34239
34268
  secretAccessKey,
34240
34269
  sessionToken,
@@ -34253,10 +34282,26 @@ async function resolveUploadHost() {
34253
34282
  if (!response.ok) {
34254
34283
  throw new Error(`S3 upload failed (${response.status}): ${response.statusText}`);
34255
34284
  }
34285
+ if (settings.s3.publicBaseUrl) {
34286
+ return {
34287
+ provider: "s3",
34288
+ url: publicS3Url({ region, bucket, key, publicBaseUrl: settings.s3.publicBaseUrl })
34289
+ };
34290
+ }
34291
+ const ttlSeconds = clamp(settings.ttlSeconds, 1, S3_MAX_PRESIGN_SECONDS);
34256
34292
  return {
34257
34293
  provider: "s3",
34258
- url: publicS3Url({ region, bucket, key, publicBaseUrl: settings.s3.publicBaseUrl }),
34259
- expiresAt: new Date(Date.now() + settings.ttlSeconds * 1e3).toISOString()
34294
+ url: presignS3Url({
34295
+ method: "GET",
34296
+ accessKeyId,
34297
+ secretAccessKey,
34298
+ sessionToken,
34299
+ region,
34300
+ bucket,
34301
+ key,
34302
+ ttlSeconds
34303
+ }),
34304
+ expiresAt: new Date(Date.now() + ttlSeconds * 1e3).toISOString()
34260
34305
  };
34261
34306
  }
34262
34307
  };
@@ -34268,19 +34313,28 @@ async function resolveUploadHost() {
34268
34313
  if (!imgbbKey) {
34269
34314
  throw new Error("IMGBB_API_KEY required for image-to-video uploads.");
34270
34315
  }
34271
- const result = await uploadToImgbb(imageBuffer, imgbbKey);
34316
+ const expiration = clamp(settings.ttlSeconds, IMGBB_MIN_EXPIRATION_SECONDS, IMGBB_MAX_EXPIRATION_SECONDS);
34317
+ const result = await uploadToImgbb(imageBuffer, imgbbKey, expiration);
34272
34318
  if (!result.success || !result.url) {
34273
34319
  throw new Error(`ImgBB upload failed: ${result.error ?? "unknown error"}`);
34274
34320
  }
34275
- return { provider: "imgbb", url: result.url };
34321
+ return {
34322
+ provider: "imgbb",
34323
+ url: result.url,
34324
+ expiresAt: new Date(Date.now() + expiration * 1e3).toISOString()
34325
+ };
34276
34326
  }
34277
34327
  };
34278
34328
  }
34329
+ var S3_MAX_PRESIGN_SECONDS, IMGBB_MIN_EXPIRATION_SECONDS, IMGBB_MAX_EXPIRATION_SECONDS;
34279
34330
  var init_upload_host = __esm({
34280
34331
  "src/utils/upload-host.ts"() {
34281
34332
  "use strict";
34282
34333
  init_config();
34283
34334
  init_video_utils();
34335
+ S3_MAX_PRESIGN_SECONDS = 7 * 24 * 60 * 60;
34336
+ IMGBB_MIN_EXPIRATION_SECONDS = 60;
34337
+ IMGBB_MAX_EXPIRATION_SECONDS = 15552e3;
34284
34338
  }
34285
34339
  });
34286
34340
 
@@ -34315,6 +34369,7 @@ async function executeVideoGenerate(options) {
34315
34369
  negative,
34316
34370
  resolution,
34317
34371
  veoModel = "3.1-fast",
34372
+ runwayModel,
34318
34373
  seedanceModel = "quality",
34319
34374
  grokModel,
34320
34375
  klingModel,
@@ -34404,6 +34459,7 @@ async function executeVideoGenerate(options) {
34404
34459
  await runway.initialize({ apiKey: key });
34405
34460
  const result = await runway.generateVideo(prompt3, {
34406
34461
  prompt: prompt3,
34462
+ model: runwayModel,
34407
34463
  referenceImage,
34408
34464
  duration,
34409
34465
  aspectRatio: ratio,
@@ -36829,16 +36885,8 @@ var init_provider_resolver = __esm({
36829
36885
 
36830
36886
  // src/commands/_shared/openai-image.ts
36831
36887
  function resolveOpenAIImageModel(modelAlias) {
36832
- const alias = modelAlias?.trim() ?? "";
36833
- for (const [id, model] of Object.entries(OPENAI_IMAGE_MODELS)) {
36834
- if (alias === id || model.aliases.includes(alias)) {
36835
- return { openaiModel: id, modelLabel: model.label };
36836
- }
36837
- }
36838
- return {
36839
- openaiModel: OPENAI_IMAGE_DEFAULT_MODEL,
36840
- modelLabel: OPENAI_IMAGE_MODELS[OPENAI_IMAGE_DEFAULT_MODEL].label
36841
- };
36888
+ const model = findModel("openai", "image", modelAlias) ?? defaultModel("openai", "image");
36889
+ return { openaiModel: model.id, modelLabel: model.label };
36842
36890
  }
36843
36891
  async function executeOpenAIImageGenerate(prompt3, options, ctx) {
36844
36892
  const provider = new OpenAIImageProvider();
@@ -36853,18 +36901,45 @@ async function executeOpenAIImageGenerate(prompt3, options, ctx) {
36853
36901
  });
36854
36902
  return { result, openaiModel, modelLabel };
36855
36903
  }
36856
- var OPENAI_IMAGE_MODELS;
36857
36904
  var init_openai_image2 = __esm({
36858
36905
  "src/commands/_shared/openai-image.ts"() {
36859
36906
  "use strict";
36860
36907
  init_dist2();
36861
- OPENAI_IMAGE_MODELS = {
36862
- "gpt-image-2.5-sunburst": { label: "GPT Image 2.5 Sunburst", aliases: ["2.5", "sunburst"] },
36863
- "gpt-image-2.5-flare": { label: "GPT Image 2.5 Flare", aliases: ["flare", "2.5-flare"] },
36864
- "gpt-image-2": { label: "GPT Image 2", aliases: ["2"] },
36865
- "gpt-image-1.5": { label: "GPT Image 1.5", aliases: ["1.5"] }
36908
+ }
36909
+ });
36910
+
36911
+ // src/commands/_shared/image-cost.ts
36912
+ function catalogPrice(provider, model) {
36913
+ if (provider === "openai") return findModel("openai", "image", resolveOpenAIImageModel(model).openaiModel)?.price?.usd;
36914
+ if (provider === "gemini") return findModel("gemini", "image", model ?? "flash")?.price?.usd ?? findModel("gemini", "image")?.price?.usd;
36915
+ if (provider === "grok") return findModel("grok", "image", resolveGrokImageModel(model).model)?.price?.usd;
36916
+ return void 0;
36917
+ }
36918
+ function estimateImageCostUsd(provider, model, count) {
36919
+ const images = Math.max(1, count);
36920
+ const perImage = catalogPrice(provider, model);
36921
+ if (perImage === void 0) {
36922
+ return {
36923
+ costUsd: lookupCostEstimateUpperBound("generate image") ?? 5,
36924
+ warnings: [
36925
+ `costUsd is the tier upper bound for ${provider} - actual provider billing is typically lower and is not metered here.`
36926
+ ]
36866
36927
  };
36867
36928
  }
36929
+ return {
36930
+ costUsd: Number((perImage * images).toFixed(3)),
36931
+ warnings: [
36932
+ `costUsd is an upper-bound estimate from ${provider} list prices for ${images} image(s) - not metered billing.`
36933
+ ]
36934
+ };
36935
+ }
36936
+ var init_image_cost = __esm({
36937
+ "src/commands/_shared/image-cost.ts"() {
36938
+ "use strict";
36939
+ init_dist2();
36940
+ init_output();
36941
+ init_openai_image2();
36942
+ }
36868
36943
  });
36869
36944
 
36870
36945
  // src/commands/generate/image.ts
@@ -36964,6 +37039,7 @@ Examples:
36964
37039
  command: "generate image",
36965
37040
  startedAt,
36966
37041
  dryRun: true,
37042
+ ...estimateImageCostUsd(provider, options.model, parseInt(options.count) || 1),
36967
37043
  data: {
36968
37044
  params: {
36969
37045
  prompt: prompt3,
@@ -37013,6 +37089,7 @@ Examples:
37013
37089
  outputSuccess({
37014
37090
  command: "generate image",
37015
37091
  startedAt,
37092
+ ...estimateImageCostUsd("openai", options.model, result.images.length),
37016
37093
  data: {
37017
37094
  provider: "openai",
37018
37095
  model: modelLabel,
@@ -37128,7 +37205,7 @@ Examples:
37128
37205
  outputSuccess({
37129
37206
  command: "generate image",
37130
37207
  startedAt,
37131
- warnings: [],
37208
+ ...estimateImageCostUsd("gemini", options.model, result.images.length),
37132
37209
  data: {
37133
37210
  provider: "gemini",
37134
37211
  model: usedLabel,
@@ -37223,6 +37300,7 @@ Examples:
37223
37300
  outputSuccess({
37224
37301
  command: "generate image",
37225
37302
  startedAt,
37303
+ ...estimateImageCostUsd("grok", options.model, result.images.length),
37226
37304
  data: {
37227
37305
  provider: "grok",
37228
37306
  modelId: resolveGrokImageModel(options.model).model,
@@ -37342,6 +37420,7 @@ var init_image = __esm({
37342
37420
  init_validate();
37343
37421
  init_provider_resolver();
37344
37422
  init_openai_image2();
37423
+ init_image_cost();
37345
37424
  init_image_file();
37346
37425
  }
37347
37426
  });
@@ -38441,6 +38520,14 @@ Examples:
38441
38520
  log(`${provider} does not support 1:1 \u2014 falling back to 16:9`);
38442
38521
  options.ratio = "16:9";
38443
38522
  }
38523
+ try {
38524
+ if (provider === "seedance" || provider === "fal") resolveSeedanceVariant(options.seedanceModel);
38525
+ if (provider === "grok") resolveGrokVideoModel(options.grokModel);
38526
+ if (provider === "kling") resolveKlingModel(options.klingModel);
38527
+ if (provider === "veo") resolveVeoModel(options.veoModel);
38528
+ } catch (err) {
38529
+ exitWithError(usageError(err instanceof Error ? err.message : String(err)));
38530
+ }
38444
38531
  if (options.dryRun) {
38445
38532
  const costUsd = provider === "seedance" || provider === "fal" ? realRunCost(provider, options).costUsd : void 0;
38446
38533
  outputSuccess({
@@ -40127,7 +40214,7 @@ ${textsToTranslate}`;
40127
40214
  Authorization: `Bearer ${openaiKey}`
40128
40215
  },
40129
40216
  body: JSON.stringify({
40130
- model: "gpt-5.4-mini",
40217
+ model: defaultModel("openai", "llm").id,
40131
40218
  messages: [{ role: "user", content: translatePrompt }]
40132
40219
  })
40133
40220
  });
@@ -40155,7 +40242,7 @@ ${textsToTranslate}`;
40155
40242
  "anthropic-version": "2023-06-01"
40156
40243
  },
40157
40244
  body: JSON.stringify({
40158
- model: "claude-sonnet-5-5",
40245
+ model: defaultModel("claude", "llm").id,
40159
40246
  max_tokens: 16e3,
40160
40247
  messages: [{ role: "user", content: translatePrompt }]
40161
40248
  })
@@ -40206,6 +40293,7 @@ var init_translate_srt = __esm({
40206
40293
  "src/commands/_shared/edit/translate-srt.ts"() {
40207
40294
  "use strict";
40208
40295
  init_subtitle();
40296
+ init_dist2();
40209
40297
  }
40210
40298
  });
40211
40299
 
@@ -41019,22 +41107,13 @@ function analyzeGapFillability(gaps, videoClips, sources) {
41019
41107
  return { gap, canExtendBefore, canExtendAfter, remainingGap, gapStart };
41020
41108
  });
41021
41109
  }
41022
- async function uploadFrameToImgbb(framePath, imgbbApiKey) {
41110
+ async function uploadFrame(host, framePath) {
41023
41111
  try {
41024
- const frameBuffer = await readFile23(framePath);
41025
- const frameBase64 = frameBuffer.toString("base64");
41026
- const formData = new FormData();
41027
- formData.append("key", imgbbApiKey);
41028
- formData.append("image", frameBase64);
41029
- const response = await fetch("https://api.imgbb.com/1/upload", {
41030
- method: "POST",
41031
- body: formData
41112
+ const upload = await host.uploadImage(await readFile23(framePath), {
41113
+ filename: framePath,
41114
+ mimeType: "image/png"
41032
41115
  });
41033
- const data = await response.json();
41034
- if (!data.success || !data.data?.url) {
41035
- return { error: data.error?.message || "Upload failed" };
41036
- }
41037
- return { url: data.data.url };
41116
+ return { url: upload.url };
41038
41117
  } catch (err) {
41039
41118
  return { error: err instanceof Error ? err.message : String(err) };
41040
41119
  }
@@ -41185,11 +41264,13 @@ async function executeFillGaps(options) {
41185
41264
  await mkdir16(footageDir, { recursive: true });
41186
41265
  }
41187
41266
  humanLines.push("Generating AI Videos");
41188
- const imgbbApiKey = options.imgbbApiKey || await getApiKey("IMGBB_API_KEY", "imgbb", void 0);
41189
- if (!imgbbApiKey) {
41267
+ let uploadHost;
41268
+ try {
41269
+ uploadHost = await resolveUploadHost();
41270
+ } catch (err) {
41190
41271
  return {
41191
41272
  success: false,
41192
- error: "IMGBB_API_KEY required for image hosting. Get a free API key at https://api.imgbb.com/",
41273
+ error: err instanceof Error ? err.message : String(err),
41193
41274
  humanLines
41194
41275
  };
41195
41276
  }
@@ -41233,12 +41314,12 @@ async function executeFillGaps(options) {
41233
41314
  humanLines
41234
41315
  };
41235
41316
  }
41236
- onProgress("Uploading frame to imgbb...");
41237
- const upload = await uploadFrameToImgbb(framePath, imgbbApiKey);
41317
+ onProgress(`Uploading frame via ${uploadHost.provider}...`);
41318
+ const upload = await uploadFrame(uploadHost, framePath);
41238
41319
  if (!upload.url) {
41239
41320
  return {
41240
41321
  success: false,
41241
- error: `Failed to upload frame to imgbb: ${upload.error || "unknown"}`,
41322
+ error: `Failed to upload frame via ${uploadHost.provider}: ${upload.error || "unknown"}`,
41242
41323
  humanLines
41243
41324
  };
41244
41325
  }
@@ -41313,7 +41394,7 @@ async function executeFillGaps(options) {
41313
41394
  humanLines.push(" Failed to extract frame for continuation");
41314
41395
  break;
41315
41396
  }
41316
- const extUpload = await uploadFrameToImgbb(lastFramePath, imgbbApiKey);
41397
+ const extUpload = await uploadFrame(uploadHost, lastFramePath);
41317
41398
  if (!extUpload.url) {
41318
41399
  humanLines.push(" Failed to upload continuation frame");
41319
41400
  break;
@@ -41436,6 +41517,7 @@ var init_execute_fill_gaps = __esm({
41436
41517
  init_dist2();
41437
41518
  init_engine();
41438
41519
  init_api_key();
41520
+ init_upload_host();
41439
41521
  init_exec_safe();
41440
41522
  init_project_resolver();
41441
41523
  init_ai_helpers();
@@ -46474,8 +46556,9 @@ var init_product_surface = __esm({
46474
46556
  schema: { surface: "agent", note: "Machine-readable command discovery." },
46475
46557
  completion: { surface: "advanced", note: "Shell ergonomics helper." },
46476
46558
  agent: {
46477
- surface: "advanced",
46478
- note: "Optional fallback REPL; external coding agents are the primary workflow."
46559
+ surface: "legacy",
46560
+ replacement: "a host agent (Claude Code, Codex, Cursor) or the MCP server via `vibe host setup`",
46561
+ note: "Deprecated built-in REPL, removed before 1.0."
46479
46562
  },
46480
46563
  "design.validate": { surface: "public", note: "Validate the DESIGN.md visual contract." },
46481
46564
  "generate.image": { surface: "public" },
@@ -56709,8 +56792,9 @@ they want for a given task. This guide is the operator-facing summary.
56709
56792
 
56710
56793
  If you already use Claude Code, Codex, Cursor, Aider, Gemini CLI, OpenCode,
56711
56794
  or another coding agent, let that host drive \`vibe\` directly through shell
56712
- commands plus \`AGENTS.md\` / \`CLAUDE.md\`. \`vibe agent\` is the optional
56713
- built-in fallback when you do not already have an agent host.
56795
+ commands plus \`AGENTS.md\` / \`CLAUDE.md\`. Without a coding agent, connect
56796
+ the MCP server to Claude Desktop or ChatGPT (\`vibe host setup\`).
56797
+ \`vibe agent\` is deprecated and will be removed before 1.0.
56714
56798
 
56715
56799
  ## TL;DR
56716
56800
 
@@ -56721,12 +56805,12 @@ built-in fallback when you do not already have an agent host.
56721
56805
  | **Reproducibility** | none | high (idempotent) | highest (checkpointed) |
56722
56806
  | **Budget caps** | per-session max-turns | none | \`--budget-usd\`, \`--budget-tokens\`, \`--max-errors\` |
56723
56807
  | **Resume after crash** | no | re-invoke | \`--resume\` |
56724
- | **Best for** | optional built-in exploration | finished script | repeatable workflows |
56808
+ | **Best for** | deprecated; use a host agent | finished script | repeatable workflows |
56725
56809
 
56726
56810
  ## Decision tree
56727
56811
 
56728
56812
  - "I am already in Claude Code/Codex/Cursor/etc." \u2192 regular \`vibe\` shell commands + \`vibe guide\` / \`vibe schema\`
56729
- - "I want to play and do not have an external coding agent" \u2192 \`vibe agent\`
56813
+ - "I do not use a coding agent" \u2192 the MCP server in Claude Desktop or ChatGPT (\`vibe host setup\`)
56730
56814
  - "I have a finished script + visual identity" \u2192 \`vibe build\`
56731
56815
  - "I want this to run again next month" \u2192 \`vibe run\`
56732
56816
 
@@ -56752,9 +56836,6 @@ agent calls them through a tool manifest; \`build\` calls a curated subset
56752
56836
  - \`vibe build\` is conceptually a 4-step pipeline; \`vibe run\` could express
56753
56837
  the same flow but build's STORYBOARD.md input + opinionated defaults are
56754
56838
  the value-add.
56755
- - \`vibe agent\`'s tool registry currently exposes primitives, not
56756
- orchestrators. Adding \`vibe.build\` / \`vibe.run\` as agent tools is on the
56757
- table for a future major.
56758
56839
  - \`vibe run --resume\` has no analog in build/agent; build's idempotent
56759
56840
  re-invoke covers the common case.
56760
56841
  `;
@@ -56861,17 +56942,17 @@ vibe generate motion "animated product logo reveal" --render -o logo-reveal.mp4
56861
56942
  },
56862
56943
  architecture: {
56863
56944
  title: "external agents / vibe agent / build / run",
56864
- summary: "Choose between host-agent shell use, optional built-in agent mode, storyboard builds, and YAML pipelines",
56945
+ summary: "Choose between host-agent shell use, MCP hosts, storyboard builds, and YAML pipelines",
56865
56946
  steps: [
56866
56947
  "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`.",
56867
- "Pick `vibe agent` only for optional built-in exploration when no external agent host is driving the CLI.",
56948
+ "Without a coding agent, connect the MCP server to Claude Desktop or ChatGPT with `vibe host setup`; `vibe agent` is deprecated.",
56868
56949
  "Pick build for STORYBOARD.md \u2192 MP4 with opinionated defaults.",
56869
56950
  "Pick run for repeatable, budget-capped, checkpointed YAML pipelines.",
56870
56951
  "Run `vibe doctor --test-keys` before any high-cost orchestrator to validate keys upfront.",
56871
56952
  "Use `vibe schema --list` (cost field, v0.84) to plan the budget per step before kicking off `vibe run --budget-usd`."
56872
56953
  ],
56873
56954
  relatedCommands: [
56874
- "vibe agent",
56955
+ "vibe host setup",
56875
56956
  "vibe build",
56876
56957
  "vibe run",
56877
56958
  "vibe doctor",
@@ -57046,10 +57127,11 @@ var OpenAIAdapter;
57046
57127
  var init_openai2 = __esm({
57047
57128
  "src/agent/adapters/openai.ts"() {
57048
57129
  "use strict";
57130
+ init_dist2();
57049
57131
  OpenAIAdapter = class {
57050
57132
  provider = "openai";
57051
57133
  client = null;
57052
- model = "gpt-5.4-mini";
57134
+ model = defaultModel("openai", "llm").id;
57053
57135
  async initialize(apiKey) {
57054
57136
  this.client = new OpenAI({ apiKey });
57055
57137
  }
@@ -57142,10 +57224,11 @@ var ClaudeAdapter;
57142
57224
  var init_claude2 = __esm({
57143
57225
  "src/agent/adapters/claude.ts"() {
57144
57226
  "use strict";
57227
+ init_dist2();
57145
57228
  ClaudeAdapter = class {
57146
57229
  provider = "claude";
57147
57230
  client = null;
57148
- model = "claude-sonnet-5-5";
57231
+ model = defaultModel("claude", "llm").id;
57149
57232
  async initialize(apiKey) {
57150
57233
  this.client = new Anthropic({ apiKey });
57151
57234
  }
@@ -57626,10 +57709,11 @@ var XAIAdapter;
57626
57709
  var init_xai = __esm({
57627
57710
  "src/agent/adapters/xai.ts"() {
57628
57711
  "use strict";
57712
+ init_dist2();
57629
57713
  XAIAdapter = class {
57630
57714
  provider = "xai";
57631
57715
  client = null;
57632
- model = "grok-4.3";
57716
+ model = defaultModel("grok", "llm").id;
57633
57717
  async initialize(apiKey) {
57634
57718
  this.client = new OpenAI2({
57635
57719
  apiKey,
@@ -73588,7 +73672,7 @@ init_source();
73588
73672
  // package.json
73589
73673
  var package_default = {
73590
73674
  name: "@vibeframe/cli",
73591
- version: "0.115.3",
73675
+ version: "0.115.4",
73592
73676
  description: "Frontier AI video generation for coding agents - Seedance, Runway, Veo, and Kling on your own keys, behind a hard cost cap",
73593
73677
  private: false,
73594
73678
  license: "MIT",
@@ -73660,6 +73744,7 @@ var package_default = {
73660
73744
  start: "tsx src/index.ts",
73661
73745
  lint: "eslint --ext .ts,.tsx src/",
73662
73746
  test: "vitest run",
73747
+ "test:integration": "VIBE_TEST_INTEGRATION=1 vitest run",
73663
73748
  "test:watch": "vitest",
73664
73749
  pretest: "pnpm --dir ../core build && pnpm --dir ../ai-providers build && node build.js",
73665
73750
  prepublishOnly: "node build.js"
@@ -81537,7 +81622,7 @@ async function collectKeys(config2, keys) {
81537
81622
  }
81538
81623
  async function runCustomSetup(config2, scope = "user", opts = {}) {
81539
81624
  console.log(
81540
- source_default.bold("1. LLM Provider") + source_default.dim(" (optional built-in vibe agent / fallback)")
81625
+ source_default.bold("1. LLM Provider") + source_default.dim(" (only for the deprecated vibe agent)")
81541
81626
  );
81542
81627
  console.log(
81543
81628
  source_default.dim(
@@ -86857,7 +86942,9 @@ async function promptConfirm2(toolName, args, cost) {
86857
86942
  const defaultYes = cost !== "very-high";
86858
86943
  return promptConfirm("", defaultYes);
86859
86944
  }
86945
+ var AGENT_DEPRECATION_NOTICE = "`vibe agent` is deprecated and will be removed before 1.0. Drive vibe from Claude Code, Codex, or Cursor, or connect the MCP server to Claude Desktop or ChatGPT (`vibe host setup`).";
86860
86946
  async function startAgent(options = {}) {
86947
+ console.error(source_default.yellow(`Deprecated: ${AGENT_DEPRECATION_NOTICE}`));
86861
86948
  const isNonInteractive = !!options.input;
86862
86949
  const confirmAlways = options.confirm || false;
86863
86950
  const noConfirm = options.noConfirm || false;
@@ -87068,7 +87155,7 @@ async function startAgent(options = {}) {
87068
87155
  rl.prompt();
87069
87156
  });
87070
87157
  }
87071
- var agentCommand = new Command("agent").description("Optional built-in natural-language agent (fallback when no external coding agent is driving vibe)").option("-p, --provider <provider>", "LLM provider (openai, claude, gemini, ollama, xai, openrouter, evolink)", "openai").option("-m, --model <model>", "Model to use (provider-specific)").option("--project <path>", "Timeline file or directory to load").option("-v, --verbose", "Show verbose output including tool calls").option("--max-turns <n>", "Maximum turns per request", "10").option("-i, --input <query>", "Run a single query and exit (non-interactive)").option("-c, --confirm", "Confirm before every tool - broadens the default cost gate (paid only) to all calls").option("--no-confirm", "Disable all confirm prompts including the high/very-high cost gate (CI / automation)").option("--budget-usd <usd>", "Reject tool calls past this cumulative USD ceiling using conservative tier estimates", parseFloat).action(async (options) => {
87158
+ var agentCommand = new Command("agent").description("[Deprecated, removed before 1.0] Built-in natural-language agent. Use a host agent or the MCP server instead").option("-p, --provider <provider>", "LLM provider (openai, claude, gemini, ollama, xai, openrouter, evolink)", "openai").option("-m, --model <model>", "Model to use (provider-specific)").option("--project <path>", "Timeline file or directory to load").option("-v, --verbose", "Show verbose output including tool calls").option("--max-turns <n>", "Maximum turns per request", "10").option("-i, --input <query>", "Run a single query and exit (non-interactive)").option("-c, --confirm", "Confirm before every tool - broadens the default cost gate (paid only) to all calls").option("--no-confirm", "Disable all confirm prompts including the high/very-high cost gate (CI / automation)").option("--budget-usd <usd>", "Reject tool calls past this cumulative USD ceiling using conservative tier estimates", parseFloat).action(async (options) => {
87072
87159
  await startAgent(options);
87073
87160
  });
87074
87161
  function getEnvVar(provider) {
@@ -87689,7 +87776,7 @@ program2.addCommand(doctorCommand);
87689
87776
  program2.addCommand(hostCommand);
87690
87777
  program2.addCommand(demoCommand, { hidden: true });
87691
87778
  program2.addCommand(runCommand);
87692
- program2.addCommand(agentCommand);
87779
+ program2.addCommand(agentCommand, { hidden: true });
87693
87780
  program2.addCommand(projectCommand, { hidden: true });
87694
87781
  program2.addCommand(sceneCommand, { hidden: true });
87695
87782
  program2.addCommand(timelineCommand, { hidden: true });