@vibeframe/mcp-server 0.41.0 → 0.43.0

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 (2) hide show
  1. package/dist/index.js +191 -82
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -6397,6 +6397,87 @@ var init_dist = __esm({
6397
6397
  }
6398
6398
  });
6399
6399
 
6400
+ // ../cli/src/config/schema.ts
6401
+ function createDefaultConfig() {
6402
+ return {
6403
+ version: "1.0.0",
6404
+ llm: {
6405
+ provider: "claude"
6406
+ },
6407
+ providers: {},
6408
+ defaults: {
6409
+ aspectRatio: "16:9",
6410
+ exportQuality: "standard"
6411
+ },
6412
+ repl: {
6413
+ autoSave: true
6414
+ }
6415
+ };
6416
+ }
6417
+ var PROVIDER_ENV_VARS;
6418
+ var init_schema = __esm({
6419
+ "../cli/src/config/schema.ts"() {
6420
+ "use strict";
6421
+ PROVIDER_ENV_VARS = {
6422
+ anthropic: "ANTHROPIC_API_KEY",
6423
+ openai: "OPENAI_API_KEY",
6424
+ google: "GOOGLE_API_KEY",
6425
+ elevenlabs: "ELEVENLABS_API_KEY",
6426
+ runway: "RUNWAY_API_SECRET",
6427
+ kling: "KLING_API_KEY",
6428
+ imgbb: "IMGBB_API_KEY",
6429
+ replicate: "REPLICATE_API_TOKEN",
6430
+ xai: "XAI_API_KEY",
6431
+ openrouter: "OPENROUTER_API_KEY"
6432
+ };
6433
+ }
6434
+ });
6435
+
6436
+ // ../cli/src/config/index.ts
6437
+ import { resolve as resolve5 } from "node:path";
6438
+ import { homedir } from "node:os";
6439
+ import { readFile as readFile3, writeFile as writeFile2, mkdir, access as access2 } from "node:fs/promises";
6440
+ import { parse, stringify } from "yaml";
6441
+ async function loadConfig() {
6442
+ try {
6443
+ await access2(CONFIG_PATH);
6444
+ const content = await readFile3(CONFIG_PATH, "utf-8");
6445
+ const config2 = parse(content);
6446
+ const defaults = createDefaultConfig();
6447
+ return {
6448
+ ...defaults,
6449
+ ...config2,
6450
+ llm: { ...defaults.llm, ...config2.llm },
6451
+ providers: { ...defaults.providers, ...config2.providers },
6452
+ defaults: { ...defaults.defaults, ...config2.defaults },
6453
+ repl: { ...defaults.repl, ...config2.repl }
6454
+ };
6455
+ } catch {
6456
+ return null;
6457
+ }
6458
+ }
6459
+ async function getApiKeyFromConfig(providerKey) {
6460
+ const config2 = await loadConfig();
6461
+ if (config2?.providers[providerKey]) {
6462
+ return config2.providers[providerKey];
6463
+ }
6464
+ const envVar = PROVIDER_ENV_VARS[providerKey];
6465
+ if (envVar) {
6466
+ return process.env[envVar];
6467
+ }
6468
+ return void 0;
6469
+ }
6470
+ var CONFIG_DIR, CONFIG_PATH;
6471
+ var init_config = __esm({
6472
+ "../cli/src/config/index.ts"() {
6473
+ "use strict";
6474
+ init_schema();
6475
+ init_schema();
6476
+ CONFIG_DIR = resolve5(homedir(), ".vibeframe");
6477
+ CONFIG_PATH = resolve5(CONFIG_DIR, "config.yaml");
6478
+ }
6479
+ });
6480
+
6400
6481
  // ../cli/src/utils/remotion.ts
6401
6482
  var remotion_exports = {};
6402
6483
  __export(remotion_exports, {
@@ -7967,7 +8048,23 @@ function authError(envVar, provider) {
7967
8048
  retryable: false
7968
8049
  };
7969
8050
  }
8051
+ var PROVIDER_ERROR_HINTS = [
8052
+ { pattern: /429|rate.?limit|too many requests/i, suggestion: "Rate limited. Wait 30-60 seconds and retry, or check your plan's rate limits.", retryable: true },
8053
+ { pattern: /401|unauthorized|invalid.*key|authentication/i, suggestion: "API key is invalid or expired. Run 'vibe setup' to update, or check the key at the provider's dashboard.", retryable: false },
8054
+ { pattern: /403|forbidden|permission/i, suggestion: "Access denied. Your API key may lack required permissions, or the feature requires a paid plan.", retryable: false },
8055
+ { pattern: /402|payment|billing|quota|exceeded|insufficient/i, suggestion: "Account quota exceeded or billing issue. Check your provider dashboard for usage limits.", retryable: false },
8056
+ { pattern: /500|internal.*error|server.*error/i, suggestion: "Provider server error. Retry in a few minutes.", retryable: true },
8057
+ { pattern: /503|service.*unavailable|overloaded/i, suggestion: "Provider is temporarily overloaded. Retry in 1-2 minutes.", retryable: true },
8058
+ { pattern: /timeout|timed?\s*out|ETIMEDOUT/i, suggestion: "Request timed out. The provider may be slow. Retry, or try a different provider with -p flag.", retryable: true },
8059
+ { pattern: /content.*policy|safety|moderation|blocked/i, suggestion: "Content was blocked by the provider's safety filter. Rephrase your prompt.", retryable: false },
8060
+ { pattern: /model.*not.*found|invalid.*model/i, suggestion: "The specified model is unavailable. Check 'vibe schema <command>' for valid model options.", retryable: false }
8061
+ ];
7970
8062
  function apiError(msg, retryable = false) {
8063
+ for (const hint of PROVIDER_ERROR_HINTS) {
8064
+ if (hint.pattern.test(msg)) {
8065
+ return { success: false, error: msg, code: "API_ERROR", exitCode: 5 /* API_ERROR */, suggestion: hint.suggestion, retryable: hint.retryable };
8066
+ }
8067
+ }
7971
8068
  return { success: false, error: msg, code: "API_ERROR", exitCode: 5 /* API_ERROR */, suggestion: retryable ? "Retry the command." : void 0, retryable };
7972
8069
  }
7973
8070
  function notFoundError(path) {
@@ -7995,7 +8092,60 @@ function isJsonMode() {
7995
8092
  function isQuietMode() {
7996
8093
  return process.env.VIBE_QUIET_OUTPUT === "1";
7997
8094
  }
8095
+ var COST_ESTIMATES = {
8096
+ // Free
8097
+ "detect scenes": { min: 0, max: 0, unit: "free" },
8098
+ "detect silence": { min: 0, max: 0, unit: "free" },
8099
+ "detect beats": { min: 0, max: 0, unit: "free" },
8100
+ "edit silence-cut": { min: 0, max: 0, unit: "free" },
8101
+ "edit fade": { min: 0, max: 0, unit: "free" },
8102
+ "edit noise-reduce": { min: 0, max: 0, unit: "free" },
8103
+ "edit reframe": { min: 0, max: 0, unit: "free" },
8104
+ "edit interpolate": { min: 0, max: 0, unit: "free" },
8105
+ "edit upscale-video": { min: 0, max: 0, unit: "free" },
8106
+ // Low
8107
+ "analyze media": { min: 0.01, max: 0.05, unit: "per call" },
8108
+ "analyze video": { min: 0.01, max: 0.1, unit: "per video" },
8109
+ "analyze review": { min: 0.01, max: 0.1, unit: "per video" },
8110
+ "generate image": { min: 0.01, max: 0.07, unit: "per image" },
8111
+ "generate thumbnail": { min: 0.01, max: 0.05, unit: "per image" },
8112
+ "generate storyboard": { min: 0.01, max: 0.05, unit: "per call" },
8113
+ "ai transcribe": { min: 0.01, max: 0.1, unit: "per minute" },
8114
+ "audio transcribe": { min: 0.01, max: 0.1, unit: "per minute" },
8115
+ "edit caption": { min: 0.01, max: 0.1, unit: "per video" },
8116
+ "edit jump-cut": { min: 0.01, max: 0.1, unit: "per video" },
8117
+ "edit translate-srt": { min: 0.01, max: 0.05, unit: "per file" },
8118
+ "edit animated-caption": { min: 0.01, max: 0.1, unit: "per video" },
8119
+ // Medium
8120
+ "generate speech": { min: 0.05, max: 0.3, unit: "per request" },
8121
+ "generate sound-effect": { min: 0.05, max: 0.2, unit: "per request" },
8122
+ "generate music": { min: 0.05, max: 0.5, unit: "per request" },
8123
+ "generate motion": { min: 0.01, max: 0.1, unit: "per generation" },
8124
+ "edit grade": { min: 0.01, max: 0.05, unit: "per video" },
8125
+ "edit speed-ramp": { min: 0.05, max: 0.15, unit: "per video" },
8126
+ "edit text-overlay": { min: 0, max: 0.05, unit: "per video" },
8127
+ // High
8128
+ "generate video": { min: 0.5, max: 5, unit: "per video" },
8129
+ "edit image": { min: 0.05, max: 0.5, unit: "per edit" },
8130
+ // Very High
8131
+ "pipeline script-to-video": { min: 5, max: 50, unit: "per project" },
8132
+ "pipeline highlights": { min: 0.05, max: 1, unit: "per analysis" },
8133
+ "pipeline auto-shorts": { min: 0.1, max: 2, unit: "per batch" },
8134
+ "pipeline animated-caption": { min: 0.01, max: 0.1, unit: "per video" },
8135
+ "pipeline regenerate-scene": { min: 0.5, max: 5, unit: "per scene" }
8136
+ };
8137
+ function formatCost(min, max, unit) {
8138
+ if (min === 0 && max === 0) return "Free";
8139
+ if (min === max) return `~$${min.toFixed(2)} ${unit}`;
8140
+ return `~$${min.toFixed(2)}-$${max.toFixed(2)} ${unit}`;
8141
+ }
7998
8142
  function outputResult(result) {
8143
+ if (result.dryRun && result.command && typeof result.command === "string") {
8144
+ const cost = COST_ESTIMATES[result.command];
8145
+ if (cost) {
8146
+ result.estimatedCost = formatCost(cost.min, cost.max, cost.unit);
8147
+ }
8148
+ }
7999
8149
  if (isJsonMode()) {
8000
8150
  const fields = process.env.VIBE_OUTPUT_FIELDS;
8001
8151
  if (fields) {
@@ -8149,7 +8299,7 @@ async function runExport(projectPath, outputPath, options = {}) {
8149
8299
  };
8150
8300
  }
8151
8301
  }
8152
- var exportCommand = new Command("export").description("Export project to video file").argument("<project>", "Project file path").option("-o, --output <path>", "Output file path").option("-f, --format <format>", "Output format (mp4, webm, mov)", "mp4").option(
8302
+ var exportCommand = new Command("export").description("Export project to video file").argument("<project>", "Project file path").option("-o, --output <path>", "Output file path").option("-f, --format <format>", "Output format (mp4, webm, mov, gif)", "mp4").option(
8153
8303
  "-p, --preset <preset>",
8154
8304
  "Quality preset (draft, standard, high, ultra)",
8155
8305
  "standard"
@@ -8158,8 +8308,10 @@ Examples:
8158
8308
  $ vibe export project.vibe.json -o output.mp4
8159
8309
  $ vibe export project.vibe.json -o output.mp4 -p high -y
8160
8310
  $ vibe export project.vibe.json -o output.webm -f webm
8311
+ $ vibe export project.vibe.json -o output.gif -f gif
8161
8312
 
8162
8313
  Cost: Free (no API keys needed). Requires FFmpeg.
8314
+ GIF format: 15fps, no audio, looping. Good for previews and sharing.
8163
8315
  Run 'vibe schema export' for structured parameter info.`).action(async (projectPath, options) => {
8164
8316
  const spinner = ora2("Checking FFmpeg...").start();
8165
8317
  try {
@@ -8588,7 +8740,17 @@ function buildFFmpegArgs(clips, sources, presetSettings, outputPath, options, so
8588
8740
  if (trackOutputLabels.length > 0) {
8589
8741
  args.push("-map", "[outa]");
8590
8742
  }
8591
- args.push(...presetSettings.ffmpegArgs);
8743
+ if (options.format === "gif") {
8744
+ const audioIdx = args.indexOf("[outa]");
8745
+ if (audioIdx !== -1) {
8746
+ const mapIdx = args.lastIndexOf("-map", audioIdx);
8747
+ if (mapIdx !== -1) args.splice(mapIdx, 2);
8748
+ }
8749
+ args.push("-r", "15");
8750
+ args.push("-loop", "0");
8751
+ } else {
8752
+ args.push(...presetSettings.ffmpegArgs);
8753
+ }
8592
8754
  args.push(outputPath);
8593
8755
  return args;
8594
8756
  }
@@ -8763,82 +8925,12 @@ import { readFile as readFile5, writeFile as writeFile5, mkdir as mkdir3 } from
8763
8925
  import { existsSync as existsSync2 } from "node:fs";
8764
8926
 
8765
8927
  // ../cli/src/utils/api-key.ts
8928
+ init_config();
8766
8929
  import { createInterface } from "node:readline";
8767
8930
  import { readFile as readFile4, writeFile as writeFile3, access as access3 } from "node:fs/promises";
8768
8931
  import { resolve as resolve6 } from "node:path";
8769
8932
  import { config } from "dotenv";
8770
8933
  import chalk3 from "chalk";
8771
-
8772
- // ../cli/src/config/index.ts
8773
- import { resolve as resolve5 } from "node:path";
8774
- import { homedir } from "node:os";
8775
- import { readFile as readFile3, writeFile as writeFile2, mkdir, access as access2 } from "node:fs/promises";
8776
- import { parse, stringify } from "yaml";
8777
-
8778
- // ../cli/src/config/schema.ts
8779
- var PROVIDER_ENV_VARS = {
8780
- anthropic: "ANTHROPIC_API_KEY",
8781
- openai: "OPENAI_API_KEY",
8782
- google: "GOOGLE_API_KEY",
8783
- elevenlabs: "ELEVENLABS_API_KEY",
8784
- runway: "RUNWAY_API_SECRET",
8785
- kling: "KLING_API_KEY",
8786
- imgbb: "IMGBB_API_KEY",
8787
- replicate: "REPLICATE_API_TOKEN",
8788
- xai: "XAI_API_KEY",
8789
- openrouter: "OPENROUTER_API_KEY"
8790
- };
8791
- function createDefaultConfig() {
8792
- return {
8793
- version: "1.0.0",
8794
- llm: {
8795
- provider: "claude"
8796
- },
8797
- providers: {},
8798
- defaults: {
8799
- aspectRatio: "16:9",
8800
- exportQuality: "standard"
8801
- },
8802
- repl: {
8803
- autoSave: true
8804
- }
8805
- };
8806
- }
8807
-
8808
- // ../cli/src/config/index.ts
8809
- var CONFIG_DIR = resolve5(homedir(), ".vibeframe");
8810
- var CONFIG_PATH = resolve5(CONFIG_DIR, "config.yaml");
8811
- async function loadConfig() {
8812
- try {
8813
- await access2(CONFIG_PATH);
8814
- const content = await readFile3(CONFIG_PATH, "utf-8");
8815
- const config2 = parse(content);
8816
- const defaults = createDefaultConfig();
8817
- return {
8818
- ...defaults,
8819
- ...config2,
8820
- llm: { ...defaults.llm, ...config2.llm },
8821
- providers: { ...defaults.providers, ...config2.providers },
8822
- defaults: { ...defaults.defaults, ...config2.defaults },
8823
- repl: { ...defaults.repl, ...config2.repl }
8824
- };
8825
- } catch {
8826
- return null;
8827
- }
8828
- }
8829
- async function getApiKeyFromConfig(providerKey) {
8830
- const config2 = await loadConfig();
8831
- if (config2?.providers[providerKey]) {
8832
- return config2.providers[providerKey];
8833
- }
8834
- const envVar = PROVIDER_ENV_VARS[providerKey];
8835
- if (envVar) {
8836
- return process.env[envVar];
8837
- }
8838
- return void 0;
8839
- }
8840
-
8841
- // ../cli/src/utils/api-key.ts
8842
8934
  function loadEnv() {
8843
8935
  config({ path: resolve6(process.cwd(), ".env"), debug: false, quiet: true });
8844
8936
  const monorepoRoot = findMonorepoRoot();
@@ -11136,7 +11228,9 @@ init_dist();
11136
11228
  import { readFile as readFile9, writeFile as writeFile7, mkdir as mkdir5, unlink, rename as rename2 } from "node:fs/promises";
11137
11229
  import { resolve as resolve11, basename as basename4, extname as extname4 } from "node:path";
11138
11230
  import { existsSync as existsSync6 } from "node:fs";
11231
+ import { stringify as yamlStringify, parse as yamlParse } from "yaml";
11139
11232
  import chalk7 from "chalk";
11233
+ init_config();
11140
11234
  init_exec_safe();
11141
11235
 
11142
11236
  // ../cli/src/commands/ai-helpers.ts
@@ -11398,8 +11492,8 @@ async function executeScriptToVideo(options) {
11398
11492
  if (segments.length === 0) {
11399
11493
  return { success: false, outputDir, scenes: 0, error: "Failed to generate storyboard" };
11400
11494
  }
11401
- const storyboardPath = resolve11(absOutputDir, "storyboard.json");
11402
- await writeFile7(storyboardPath, JSON.stringify(segments, null, 2), "utf-8");
11495
+ const storyboardPath = resolve11(absOutputDir, "storyboard.yaml");
11496
+ await writeFile7(storyboardPath, yamlStringify({ scenes: segments }, { indent: 2 }), "utf-8");
11403
11497
  const result = {
11404
11498
  success: true,
11405
11499
  outputDir: absOutputDir,
@@ -11460,7 +11554,7 @@ async function executeScriptToVideo(options) {
11460
11554
  segment.startTime = currentTime2;
11461
11555
  currentTime2 += segment.duration;
11462
11556
  }
11463
- await writeFile7(storyboardPath, JSON.stringify(segments, null, 2), "utf-8");
11557
+ await writeFile7(storyboardPath, yamlStringify({ scenes: segments }, { indent: 2 }), "utf-8");
11464
11558
  }
11465
11559
  const dalleImageSizes = {
11466
11560
  "16:9": "1536x1024",
@@ -11840,12 +11934,14 @@ async function executeScriptToVideo(options) {
11840
11934
  result.totalDuration = currentTime;
11841
11935
  if (options.review) {
11842
11936
  try {
11843
- const storyboardFile = resolve11(absOutputDir, "storyboard.json");
11937
+ const storyboardYaml = resolve11(absOutputDir, "storyboard.yaml");
11938
+ const storyboardJson = resolve11(absOutputDir, "storyboard.json");
11939
+ const storyboardFile = existsSync6(storyboardYaml) ? storyboardYaml : existsSync6(storyboardJson) ? storyboardJson : void 0;
11844
11940
  const reviewTarget = videoPaths.find((p) => p && p !== "") || imagePaths.find((p) => p && p !== "");
11845
11941
  if (reviewTarget) {
11846
11942
  const reviewResult = await executeReview({
11847
11943
  videoPath: reviewTarget,
11848
- storyboardPath: existsSync6(storyboardFile) ? storyboardFile : void 0,
11944
+ storyboardPath: storyboardFile,
11849
11945
  autoApply: options.reviewAutoApply,
11850
11946
  model: "flash"
11851
11947
  });
@@ -11876,15 +11972,17 @@ async function executeRegenerateScene(options) {
11876
11972
  };
11877
11973
  try {
11878
11974
  const outputDir = resolve11(process.cwd(), options.projectDir);
11879
- const storyboardPath = resolve11(outputDir, "storyboard.json");
11880
11975
  if (!existsSync6(outputDir)) {
11881
11976
  return { ...result, error: `Project directory not found: ${outputDir}` };
11882
11977
  }
11883
- if (!existsSync6(storyboardPath)) {
11884
- return { ...result, error: `Storyboard not found: ${storyboardPath}` };
11978
+ const yamlPath = resolve11(outputDir, "storyboard.yaml");
11979
+ const jsonPath = resolve11(outputDir, "storyboard.json");
11980
+ const storyboardPath = existsSync6(yamlPath) ? yamlPath : existsSync6(jsonPath) ? jsonPath : null;
11981
+ if (!storyboardPath) {
11982
+ return { ...result, error: `Storyboard not found in: ${outputDir} (expected storyboard.yaml or storyboard.json)` };
11885
11983
  }
11886
11984
  const storyboardContent = await readFile9(storyboardPath, "utf-8");
11887
- const segments = JSON.parse(storyboardContent);
11985
+ const segments = storyboardPath.endsWith(".yaml") ? yamlParse(storyboardContent).scenes : JSON.parse(storyboardContent);
11888
11986
  for (const sceneNum of options.scenes) {
11889
11987
  if (sceneNum < 1 || sceneNum > segments.length) {
11890
11988
  return { ...result, error: `Scene ${sceneNum} does not exist. Storyboard has ${segments.length} scenes.` };
@@ -14170,6 +14268,9 @@ async function prompt2(question) {
14170
14268
  });
14171
14269
  }
14172
14270
 
14271
+ // ../cli/src/commands/generate.ts
14272
+ init_config();
14273
+
14173
14274
  // ../cli/src/commands/sanitize.ts
14174
14275
  function sanitizeLLMResponse(text) {
14175
14276
  if (!text || typeof text !== "string") return text;
@@ -14202,9 +14303,16 @@ var PROVIDER_MAP = {
14202
14303
  video: VIDEO_PROVIDERS,
14203
14304
  speech: SPEECH_PROVIDERS
14204
14305
  };
14306
+ var configDefaults = null;
14205
14307
  function resolveProvider(category) {
14206
14308
  const candidates = PROVIDER_MAP[category];
14207
14309
  if (!candidates) return null;
14310
+ if (configDefaults?.[category]) {
14311
+ const preferred = candidates.find((c) => c.name === configDefaults[category]);
14312
+ if (preferred && hasApiKey(preferred.envVar)) {
14313
+ return { name: preferred.name, label: preferred.label };
14314
+ }
14315
+ }
14208
14316
  for (const candidate of candidates) {
14209
14317
  if (hasApiKey(candidate.envVar)) {
14210
14318
  return { name: candidate.name, label: candidate.label };
@@ -16799,6 +16907,7 @@ import { readFile as readFile14, writeFile as writeFile13 } from "node:fs/promis
16799
16907
  import { resolve as resolve17 } from "node:path";
16800
16908
  import chalk12 from "chalk";
16801
16909
  import ora10 from "ora";
16910
+ init_config();
16802
16911
  async function executeVideoGenerate(options) {
16803
16912
  const {
16804
16913
  prompt: prompt3,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeframe/mcp-server",
3
- "version": "0.41.0",
3
+ "version": "0.43.0",
4
4
  "description": "VibeFrame MCP Server - AI-native video editing via Model Context Protocol",
5
5
  "type": "module",
6
6
  "bin": {
@@ -57,8 +57,8 @@
57
57
  "tsx": "^4.21.0",
58
58
  "typescript": "^5.3.3",
59
59
  "vitest": "^1.2.2",
60
- "@vibeframe/cli": "0.41.0",
61
- "@vibeframe/core": "0.41.0"
60
+ "@vibeframe/cli": "0.43.0",
61
+ "@vibeframe/core": "0.43.0"
62
62
  },
63
63
  "engines": {
64
64
  "node": ">=20"