@vibeframe/mcp-server 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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +289 -205
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -18,7 +18,7 @@ results, dry-run/cost gates, `build-report.json`, `review-report.json`,
18
18
  | ------------------------------------------------------------------- | -------------------------------- | --------------------------------------------------------------------------------------- |
19
19
  | MCP host (Claude Desktop / Cursor / OpenCode / Claude Code) | `@vibeframe/mcp-server` _(this)_ | host calls tool by name, for example `mcp__vibeframe__build({...})` |
20
20
  | Shell / scripts (any agent host: Codex / Aider / Gemini CLI / etc.) | `@vibeframe/cli` | `vibe init my-video && vibe build my-video && vibe render my-video` |
21
- | Optional standalone agent REPL | `@vibeframe/cli` (`vibe agent`) | natural language -> CLI calls when you do not already use Claude Code/Codex/Cursor/etc. |
21
+ | Standalone agent REPL (deprecated, removed before 1.0) | `@vibeframe/cli` (`vibe agent`) | use an MCP host or a coding agent instead |
22
22
 
23
23
  Outer-loop stop rules should be explicit: final MP4 path exists, duration and
24
24
  aspect ratio match the brief, render inspection has no errors, any AI review score
package/dist/index.js CHANGED
@@ -439,6 +439,82 @@ var init_whisper = __esm({
439
439
  }
440
440
  });
441
441
 
442
+ // ../ai-providers/dist/catalog/catalog.js
443
+ function listModels(filter3 = {}) {
444
+ return MODEL_CATALOG.filter((m2) => (!filter3.provider || m2.provider === filter3.provider) && (!filter3.kind || m2.kind === filter3.kind));
445
+ }
446
+ function defaultModel(provider, kind3) {
447
+ const found = MODEL_CATALOG.find((m2) => m2.provider === provider && m2.kind === kind3 && m2.default);
448
+ if (!found)
449
+ throw new Error(`Model catalog has no default ${kind3} model for ${provider}`);
450
+ return found;
451
+ }
452
+ function findModel(provider, kind3, aliasOrId) {
453
+ const key2 = aliasOrId?.trim();
454
+ if (!key2)
455
+ return defaultModel(provider, kind3);
456
+ const lower = key2.toLowerCase();
457
+ return listModels({ provider, kind: kind3 }).find((m2) => m2.id === key2 || m2.aliases?.includes(lower));
458
+ }
459
+ function modelAliases(provider, kind3) {
460
+ return listModels({ provider, kind: kind3 }).flatMap((m2) => m2.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((m2) => (m2.aliases ?? []).map((a4) => [a4, m2.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((m2) => (m2.aliases ?? []).map((a4) => [a4, m2.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(config4) {
2109
2158
  this.apiKey = config4.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(config4) {
3825
3875
  this.apiKey = config4.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((m2) => (m2.aliases ?? []).map((a4) => [a4, m2.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: data2.id,
@@ -5649,8 +5707,9 @@ var init_RunwayProvider = __esm({
5649
5707
  if (data2.status === "SUCCEEDED" && data2.output && data2.output.length > 0) {
5650
5708
  result.videoUrl = data2.output[0];
5651
5709
  }
5652
- if (data2.status === "FAILED" || data2.status === "THROTTLED") {
5653
- result.error = data2.failure || data2.failureCode || "Generation failed";
5710
+ if (data2.status === "FAILED") {
5711
+ const reason = data2.failure || "Generation failed";
5712
+ result.error = data2.failureCode ? `${reason} (${data2.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 key2 = (alias ?? "v3").trim().toLowerCase();
5796
- const aliases2 = {
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(aliases2, key2))
5806
- return aliases2[key2];
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 key2 = (alias ?? "1.5").trim().toLowerCase();
6259
- const aliases2 = {
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(aliases2, key2))
6269
- return aliases2[key2];
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 key2 = (alias ?? "quality").trim().toLowerCase();
10726
- const aliases2 = {
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(aliases2, key2))
10736
- return aliases2[key2];
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_exports, {
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_exports, {
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_exports, {
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_dist = __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
  // ../cli/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
  (c2) => `%${c2.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(query2).sort(([a4], [b4]) => a4.localeCompare(b4)).map(([key2, value]) => `${awsEncode(key2)}=${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 key2 = `${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: key2, 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: key2, 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: key2,
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
  "../cli/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: key2 });
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,
@@ -275942,16 +276002,14 @@ import { tmpdir as tmpdir9 } from "node:os";
275942
276002
  import { createHash as createHash11 } from "node:crypto";
275943
276003
  async function ensureRemotionInstalled() {
275944
276004
  try {
275945
- await execSafe("npx", ["--yes", "remotion", "--help"], { timeout: 6e4 });
276005
+ await execSafe("npm", ["--version"], { timeout: 3e4 });
275946
276006
  return null;
275947
276007
  } catch (error) {
275948
276008
  const detail = error instanceof Error ? error.message : String(error);
275949
- console.error(`[Remotion] ensureRemotionInstalled failed: ${detail.slice(0, 300)}`);
275950
276009
  return [
275951
- "Remotion CLI not found or failed to initialize.",
276010
+ "Remotion renders need npm to install the Remotion CLI into a temporary project.",
275952
276011
  ` Debug: ${detail.slice(0, 200)}`,
275953
- " Fix: npm install -g @remotion/cli",
275954
- " Or ensure npx is available and can download @remotion/cli on demand."
276012
+ " Fix: install Node.js 20+ (which includes npm) and make sure `npm` is on PATH."
275955
276013
  ].join("\n");
275956
276014
  }
275957
276015
  }
@@ -277074,7 +277132,7 @@ ${textsToTranslate}`;
277074
277132
  Authorization: `Bearer ${openaiKey}`
277075
277133
  },
277076
277134
  body: JSON.stringify({
277077
- model: "gpt-5.4-mini",
277135
+ model: defaultModel("openai", "llm").id,
277078
277136
  messages: [{ role: "user", content: translatePrompt }]
277079
277137
  })
277080
277138
  });
@@ -277102,7 +277160,7 @@ ${textsToTranslate}`;
277102
277160
  "anthropic-version": "2023-06-01"
277103
277161
  },
277104
277162
  body: JSON.stringify({
277105
- model: "claude-sonnet-5-5",
277163
+ model: defaultModel("claude", "llm").id,
277106
277164
  max_tokens: 16e3,
277107
277165
  messages: [{ role: "user", content: translatePrompt }]
277108
277166
  })
@@ -277153,6 +277211,7 @@ var init_translate_srt = __esm({
277153
277211
  "../cli/src/commands/_shared/edit/translate-srt.ts"() {
277154
277212
  "use strict";
277155
277213
  init_subtitle();
277214
+ init_dist();
277156
277215
  }
277157
277216
  });
277158
277217
 
@@ -278353,22 +278412,13 @@ function analyzeGapFillability(gaps, videoClips, sources) {
278353
278412
  return { gap, canExtendBefore, canExtendAfter, remainingGap, gapStart };
278354
278413
  });
278355
278414
  }
278356
- async function uploadFrameToImgbb(framePath, imgbbApiKey) {
278415
+ async function uploadFrame(host, framePath) {
278357
278416
  try {
278358
- const frameBuffer = await readFile26(framePath);
278359
- const frameBase64 = frameBuffer.toString("base64");
278360
- const formData = new FormData();
278361
- formData.append("key", imgbbApiKey);
278362
- formData.append("image", frameBase64);
278363
- const response = await fetch("https://api.imgbb.com/1/upload", {
278364
- method: "POST",
278365
- body: formData
278417
+ const upload = await host.uploadImage(await readFile26(framePath), {
278418
+ filename: framePath,
278419
+ mimeType: "image/png"
278366
278420
  });
278367
- const data2 = await response.json();
278368
- if (!data2.success || !data2.data?.url) {
278369
- return { error: data2.error?.message || "Upload failed" };
278370
- }
278371
- return { url: data2.data.url };
278421
+ return { url: upload.url };
278372
278422
  } catch (err) {
278373
278423
  return { error: err instanceof Error ? err.message : String(err) };
278374
278424
  }
@@ -278519,11 +278569,13 @@ async function executeFillGaps(options) {
278519
278569
  await mkdir20(footageDir, { recursive: true });
278520
278570
  }
278521
278571
  humanLines.push("Generating AI Videos");
278522
- const imgbbApiKey = options.imgbbApiKey || await getApiKey("IMGBB_API_KEY", "imgbb", void 0);
278523
- if (!imgbbApiKey) {
278572
+ let uploadHost;
278573
+ try {
278574
+ uploadHost = await resolveUploadHost();
278575
+ } catch (err) {
278524
278576
  return {
278525
278577
  success: false,
278526
- error: "IMGBB_API_KEY required for image hosting. Get a free API key at https://api.imgbb.com/",
278578
+ error: err instanceof Error ? err.message : String(err),
278527
278579
  humanLines
278528
278580
  };
278529
278581
  }
@@ -278567,12 +278619,12 @@ async function executeFillGaps(options) {
278567
278619
  humanLines
278568
278620
  };
278569
278621
  }
278570
- onProgress("Uploading frame to imgbb...");
278571
- const upload = await uploadFrameToImgbb(framePath, imgbbApiKey);
278622
+ onProgress(`Uploading frame via ${uploadHost.provider}...`);
278623
+ const upload = await uploadFrame(uploadHost, framePath);
278572
278624
  if (!upload.url) {
278573
278625
  return {
278574
278626
  success: false,
278575
- error: `Failed to upload frame to imgbb: ${upload.error || "unknown"}`,
278627
+ error: `Failed to upload frame via ${uploadHost.provider}: ${upload.error || "unknown"}`,
278576
278628
  humanLines
278577
278629
  };
278578
278630
  }
@@ -278647,7 +278699,7 @@ async function executeFillGaps(options) {
278647
278699
  humanLines.push(" Failed to extract frame for continuation");
278648
278700
  break;
278649
278701
  }
278650
- const extUpload = await uploadFrameToImgbb(lastFramePath, imgbbApiKey);
278702
+ const extUpload = await uploadFrame(uploadHost, lastFramePath);
278651
278703
  if (!extUpload.url) {
278652
278704
  humanLines.push(" Failed to upload continuation frame");
278653
278705
  break;
@@ -278770,6 +278822,7 @@ var init_execute_fill_gaps = __esm({
278770
278822
  init_dist();
278771
278823
  init_engine();
278772
278824
  init_api_key();
278825
+ init_upload_host();
278773
278826
  init_exec_safe();
278774
278827
  init_project_resolver();
278775
278828
  init_ai_helpers();
@@ -278837,6 +278890,13 @@ __export(ai_motion_exports, {
278837
278890
  import { resolve as resolve48 } from "node:path";
278838
278891
  import { existsSync as existsSync69 } from "node:fs";
278839
278892
  import { readFile as readFile27, writeFile as writeFile29 } from "node:fs/promises";
278893
+ function resolveMotionModel(alias) {
278894
+ const claude = findModel("claude", "llm", alias);
278895
+ if (claude) return { provider: "claude", modelId: claude.id };
278896
+ const gemini = findModel("gemini", "llm", alias);
278897
+ if (gemini) return { provider: "gemini", modelId: gemini.id };
278898
+ return { provider: "claude", modelId: defaultModel("claude", "llm").id };
278899
+ }
278840
278900
  async function getOptionalGoogleApiKey() {
278841
278901
  const configKey = await getApiKeyFromConfig("google");
278842
278902
  if (configKey) return configKey;
@@ -278851,7 +278911,7 @@ function normalizeUnderstand(value) {
278851
278911
  }
278852
278912
  async function executeMotion(options) {
278853
278913
  const modelAlias = options.model || "sonnet";
278854
- const modelConfig = MODEL_MAP2[modelAlias] ?? MODEL_MAP2["sonnet"];
278914
+ const modelConfig = resolveMotionModel(modelAlias);
278855
278915
  const useGemini = modelConfig.provider === "gemini";
278856
278916
  const width = options.width || 1920;
278857
278917
  const height = options.height || 1080;
@@ -279230,7 +279290,6 @@ function registerMotionCommand(aiCommand) {
279230
279290
  }
279231
279291
  });
279232
279292
  }
279233
- var MODEL_MAP2;
279234
279293
  var init_ai_motion = __esm({
279235
279294
  "../cli/src/commands/ai-motion.ts"() {
279236
279295
  "use strict";
@@ -279241,14 +279300,6 @@ var init_ai_motion = __esm({
279241
279300
  init_config();
279242
279301
  init_output();
279243
279302
  init_validate();
279244
- MODEL_MAP2 = {
279245
- sonnet: { provider: "claude", modelId: "claude-sonnet-5-5" },
279246
- opus: { provider: "claude", modelId: "claude-opus-5-5" },
279247
- "opus-4-6": { provider: "claude", modelId: "claude-opus-4-6" },
279248
- gemini: { provider: "gemini", modelId: GEMINI_DEFAULT_TEXT_MODEL },
279249
- "gemini-2.5-pro": { provider: "gemini", modelId: "gemini-2.5-pro" },
279250
- "gemini-3.1-pro": { provider: "gemini", modelId: "gemini-3.1-pro-preview" }
279251
- };
279252
279303
  }
279253
279304
  });
279254
279305
 
@@ -282362,16 +282413,8 @@ var init_provider_resolver = __esm({
282362
282413
 
282363
282414
  // ../cli/src/commands/_shared/openai-image.ts
282364
282415
  function resolveOpenAIImageModel(modelAlias) {
282365
- const alias = modelAlias?.trim() ?? "";
282366
- for (const [id, model] of Object.entries(OPENAI_IMAGE_MODELS)) {
282367
- if (alias === id || model.aliases.includes(alias)) {
282368
- return { openaiModel: id, modelLabel: model.label };
282369
- }
282370
- }
282371
- return {
282372
- openaiModel: OPENAI_IMAGE_DEFAULT_MODEL,
282373
- modelLabel: OPENAI_IMAGE_MODELS[OPENAI_IMAGE_DEFAULT_MODEL].label
282374
- };
282416
+ const model = findModel("openai", "image", modelAlias) ?? defaultModel("openai", "image");
282417
+ return { openaiModel: model.id, modelLabel: model.label };
282375
282418
  }
282376
282419
  async function executeOpenAIImageGenerate(prompt3, options, ctx) {
282377
282420
  const provider = new OpenAIImageProvider();
@@ -282386,18 +282429,45 @@ async function executeOpenAIImageGenerate(prompt3, options, ctx) {
282386
282429
  });
282387
282430
  return { result, openaiModel, modelLabel };
282388
282431
  }
282389
- var OPENAI_IMAGE_MODELS;
282390
282432
  var init_openai_image2 = __esm({
282391
282433
  "../cli/src/commands/_shared/openai-image.ts"() {
282392
282434
  "use strict";
282393
282435
  init_dist();
282394
- OPENAI_IMAGE_MODELS = {
282395
- "gpt-image-2.5-sunburst": { label: "GPT Image 2.5 Sunburst", aliases: ["2.5", "sunburst"] },
282396
- "gpt-image-2.5-flare": { label: "GPT Image 2.5 Flare", aliases: ["flare", "2.5-flare"] },
282397
- "gpt-image-2": { label: "GPT Image 2", aliases: ["2"] },
282398
- "gpt-image-1.5": { label: "GPT Image 1.5", aliases: ["1.5"] }
282436
+ }
282437
+ });
282438
+
282439
+ // ../cli/src/commands/_shared/image-cost.ts
282440
+ function catalogPrice(provider, model) {
282441
+ if (provider === "openai") return findModel("openai", "image", resolveOpenAIImageModel(model).openaiModel)?.price?.usd;
282442
+ if (provider === "gemini") return findModel("gemini", "image", model ?? "flash")?.price?.usd ?? findModel("gemini", "image")?.price?.usd;
282443
+ if (provider === "grok") return findModel("grok", "image", resolveGrokImageModel(model).model)?.price?.usd;
282444
+ return void 0;
282445
+ }
282446
+ function estimateImageCostUsd(provider, model, count) {
282447
+ const images = Math.max(1, count);
282448
+ const perImage = catalogPrice(provider, model);
282449
+ if (perImage === void 0) {
282450
+ return {
282451
+ costUsd: lookupCostEstimateUpperBound("generate image") ?? 5,
282452
+ warnings: [
282453
+ `costUsd is the tier upper bound for ${provider} - actual provider billing is typically lower and is not metered here.`
282454
+ ]
282399
282455
  };
282400
282456
  }
282457
+ return {
282458
+ costUsd: Number((perImage * images).toFixed(3)),
282459
+ warnings: [
282460
+ `costUsd is an upper-bound estimate from ${provider} list prices for ${images} image(s) - not metered billing.`
282461
+ ]
282462
+ };
282463
+ }
282464
+ var init_image_cost = __esm({
282465
+ "../cli/src/commands/_shared/image-cost.ts"() {
282466
+ "use strict";
282467
+ init_dist();
282468
+ init_output();
282469
+ init_openai_image2();
282470
+ }
282401
282471
  });
282402
282472
 
282403
282473
  // ../cli/src/commands/generate/image.ts
@@ -282497,6 +282567,7 @@ Examples:
282497
282567
  command: "generate image",
282498
282568
  startedAt,
282499
282569
  dryRun: true,
282570
+ ...estimateImageCostUsd(provider, options.model, parseInt(options.count) || 1),
282500
282571
  data: {
282501
282572
  params: {
282502
282573
  prompt: prompt3,
@@ -282546,6 +282617,7 @@ Examples:
282546
282617
  outputSuccess({
282547
282618
  command: "generate image",
282548
282619
  startedAt,
282620
+ ...estimateImageCostUsd("openai", options.model, result.images.length),
282549
282621
  data: {
282550
282622
  provider: "openai",
282551
282623
  model: modelLabel,
@@ -282661,7 +282733,7 @@ Examples:
282661
282733
  outputSuccess({
282662
282734
  command: "generate image",
282663
282735
  startedAt,
282664
- warnings: [],
282736
+ ...estimateImageCostUsd("gemini", options.model, result.images.length),
282665
282737
  data: {
282666
282738
  provider: "gemini",
282667
282739
  model: usedLabel,
@@ -282756,6 +282828,7 @@ Examples:
282756
282828
  outputSuccess({
282757
282829
  command: "generate image",
282758
282830
  startedAt,
282831
+ ...estimateImageCostUsd("grok", options.model, result.images.length),
282759
282832
  data: {
282760
282833
  provider: "grok",
282761
282834
  modelId: resolveGrokImageModel(options.model).model,
@@ -282875,6 +282948,7 @@ var init_image2 = __esm({
282875
282948
  init_validate();
282876
282949
  init_provider_resolver();
282877
282950
  init_openai_image2();
282951
+ init_image_cost();
282878
282952
  init_image_file();
282879
282953
  }
282880
282954
  });
@@ -283974,6 +284048,14 @@ Examples:
283974
284048
  log(`${provider} does not support 1:1 \u2014 falling back to 16:9`);
283975
284049
  options.ratio = "16:9";
283976
284050
  }
284051
+ try {
284052
+ if (provider === "seedance" || provider === "fal") resolveSeedanceVariant(options.seedanceModel);
284053
+ if (provider === "grok") resolveGrokVideoModel(options.grokModel);
284054
+ if (provider === "kling") resolveKlingModel(options.klingModel);
284055
+ if (provider === "veo") resolveVeoModel(options.veoModel);
284056
+ } catch (err) {
284057
+ exitWithError(usageError(err instanceof Error ? err.message : String(err)));
284058
+ }
283977
284059
  if (options.dryRun) {
283978
284060
  const costUsd = provider === "seedance" || provider === "fal" ? realRunCost(provider, options).costUsd : void 0;
283979
284061
  outputSuccess({
@@ -298375,10 +298457,11 @@ var init_openai3 = __esm({
298375
298457
  "../cli/src/agent/adapters/openai.ts"() {
298376
298458
  "use strict";
298377
298459
  init_openai2();
298460
+ init_dist();
298378
298461
  OpenAIAdapter = class {
298379
298462
  provider = "openai";
298380
298463
  client = null;
298381
- model = "gpt-5.4-mini";
298464
+ model = defaultModel("openai", "llm").id;
298382
298465
  async initialize(apiKey) {
298383
298466
  this.client = new openai_default({ apiKey });
298384
298467
  }
@@ -301924,10 +302007,11 @@ var init_claude2 = __esm({
301924
302007
  "../cli/src/agent/adapters/claude.ts"() {
301925
302008
  "use strict";
301926
302009
  init_sdk();
302010
+ init_dist();
301927
302011
  ClaudeAdapter = class {
301928
302012
  provider = "claude";
301929
302013
  client = null;
301930
- model = "claude-sonnet-5-5";
302014
+ model = defaultModel("claude", "llm").id;
301931
302015
  async initialize(apiKey) {
301932
302016
  this.client = new sdk_default({ apiKey });
301933
302017
  }
@@ -303363,10 +303447,11 @@ var init_xai = __esm({
303363
303447
  "../cli/src/agent/adapters/xai.ts"() {
303364
303448
  "use strict";
303365
303449
  init_openai2();
303450
+ init_dist();
303366
303451
  XAIAdapter = class {
303367
303452
  provider = "xai";
303368
303453
  client = null;
303369
- model = "grok-4.3";
303454
+ model = defaultModel("grok", "llm").id;
303370
303455
  async initialize(apiKey) {
303371
303456
  this.client = new openai_default({
303372
303457
  apiKey,
@@ -304157,8 +304242,9 @@ var EXPLICIT_COMMAND_METADATA = {
304157
304242
  schema: { surface: "agent", note: "Machine-readable command discovery." },
304158
304243
  completion: { surface: "advanced", note: "Shell ergonomics helper." },
304159
304244
  agent: {
304160
- surface: "advanced",
304161
- note: "Optional fallback REPL; external coding agents are the primary workflow."
304245
+ surface: "legacy",
304246
+ replacement: "a host agent (Claude Code, Codex, Cursor) or the MCP server via `vibe host setup`",
304247
+ note: "Deprecated built-in REPL, removed before 1.0."
304162
304248
  },
304163
304249
  "design.validate": { surface: "public", note: "Validate the DESIGN.md visual contract." },
304164
304250
  "generate.image": { surface: "public" },
@@ -314191,8 +314277,9 @@ they want for a given task. This guide is the operator-facing summary.
314191
314277
 
314192
314278
  If you already use Claude Code, Codex, Cursor, Aider, Gemini CLI, OpenCode,
314193
314279
  or another coding agent, let that host drive \`vibe\` directly through shell
314194
- commands plus \`AGENTS.md\` / \`CLAUDE.md\`. \`vibe agent\` is the optional
314195
- built-in fallback when you do not already have an agent host.
314280
+ commands plus \`AGENTS.md\` / \`CLAUDE.md\`. Without a coding agent, connect
314281
+ the MCP server to Claude Desktop or ChatGPT (\`vibe host setup\`).
314282
+ \`vibe agent\` is deprecated and will be removed before 1.0.
314196
314283
 
314197
314284
  ## TL;DR
314198
314285
 
@@ -314203,12 +314290,12 @@ built-in fallback when you do not already have an agent host.
314203
314290
  | **Reproducibility** | none | high (idempotent) | highest (checkpointed) |
314204
314291
  | **Budget caps** | per-session max-turns | none | \`--budget-usd\`, \`--budget-tokens\`, \`--max-errors\` |
314205
314292
  | **Resume after crash** | no | re-invoke | \`--resume\` |
314206
- | **Best for** | optional built-in exploration | finished script | repeatable workflows |
314293
+ | **Best for** | deprecated; use a host agent | finished script | repeatable workflows |
314207
314294
 
314208
314295
  ## Decision tree
314209
314296
 
314210
314297
  - "I am already in Claude Code/Codex/Cursor/etc." \u2192 regular \`vibe\` shell commands + \`vibe guide\` / \`vibe schema\`
314211
- - "I want to play and do not have an external coding agent" \u2192 \`vibe agent\`
314298
+ - "I do not use a coding agent" \u2192 the MCP server in Claude Desktop or ChatGPT (\`vibe host setup\`)
314212
314299
  - "I have a finished script + visual identity" \u2192 \`vibe build\`
314213
314300
  - "I want this to run again next month" \u2192 \`vibe run\`
314214
314301
 
@@ -314234,9 +314321,6 @@ agent calls them through a tool manifest; \`build\` calls a curated subset
314234
314321
  - \`vibe build\` is conceptually a 4-step pipeline; \`vibe run\` could express
314235
314322
  the same flow but build's STORYBOARD.md input + opinionated defaults are
314236
314323
  the value-add.
314237
- - \`vibe agent\`'s tool registry currently exposes primitives, not
314238
- orchestrators. Adding \`vibe.build\` / \`vibe.run\` as agent tools is on the
314239
- table for a future major.
314240
314324
  - \`vibe run --resume\` has no analog in build/agent; build's idempotent
314241
314325
  re-invoke covers the common case.
314242
314326
  `;
@@ -314343,17 +314427,17 @@ var META = {
314343
314427
  },
314344
314428
  architecture: {
314345
314429
  title: "external agents / vibe agent / build / run",
314346
- summary: "Choose between host-agent shell use, optional built-in agent mode, storyboard builds, and YAML pipelines",
314430
+ summary: "Choose between host-agent shell use, MCP hosts, storyboard builds, and YAML pipelines",
314347
314431
  steps: [
314348
314432
  "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`.",
314349
- "Pick `vibe agent` only for optional built-in exploration when no external agent host is driving the CLI.",
314433
+ "Without a coding agent, connect the MCP server to Claude Desktop or ChatGPT with `vibe host setup`; `vibe agent` is deprecated.",
314350
314434
  "Pick build for STORYBOARD.md \u2192 MP4 with opinionated defaults.",
314351
314435
  "Pick run for repeatable, budget-capped, checkpointed YAML pipelines.",
314352
314436
  "Run `vibe doctor --test-keys` before any high-cost orchestrator to validate keys upfront.",
314353
314437
  "Use `vibe schema --list` (cost field, v0.84) to plan the budget per step before kicking off `vibe run --budget-usd`."
314354
314438
  ],
314355
314439
  relatedCommands: [
314356
- "vibe agent",
314440
+ "vibe host setup",
314357
314441
  "vibe build",
314358
314442
  "vibe run",
314359
314443
  "vibe doctor",
@@ -315349,7 +315433,7 @@ function handleCliFlags(argv, version2) {
315349
315433
  }
315350
315434
 
315351
315435
  // src/index.ts
315352
- if (handleCliFlags(process.argv.slice(2), "0.115.3")) {
315436
+ if (handleCliFlags(process.argv.slice(2), "0.115.4")) {
315353
315437
  process.exit(0);
315354
315438
  }
315355
315439
  console.log = (...args) => console.error(...args);
@@ -315362,7 +315446,7 @@ var server = new Server(
315362
315446
  {
315363
315447
  name: "vibeframe",
315364
315448
  // Stamped with the package version by build.js at bundle time.
315365
- version: "0.115.3"
315449
+ version: "0.115.4"
315366
315450
  },
315367
315451
  {
315368
315452
  capabilities: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeframe/mcp-server",
3
- "version": "0.115.3",
3
+ "version": "0.115.4",
4
4
  "description": "VibeFrame MCP Server - frontier AI video generation for agents (Seedance, Runway, Veo, Kling) on your own keys, behind a hard cost cap",
5
5
  "type": "module",
6
6
  "bin": {
@@ -66,8 +66,8 @@
66
66
  "tsx": "^4.21.0",
67
67
  "typescript": "^5.3.3",
68
68
  "vitest": "^1.2.2",
69
- "@vibeframe/cli": "0.115.3",
70
- "@vibeframe/core": "0.115.3"
69
+ "@vibeframe/cli": "0.115.4",
70
+ "@vibeframe/core": "0.115.4"
71
71
  },
72
72
  "engines": {
73
73
  "node": ">=20"