@vibeframe/mcp-server 0.112.1 → 0.113.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.
- package/README.md +8 -6
- package/dist/index.js +238 -47
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -45,16 +45,17 @@ enabled = true
|
|
|
45
45
|
|
|
46
46
|
Install the prebuilt Desktop Extension — no Node, npx, or JSON editing needed:
|
|
47
47
|
|
|
48
|
-
1. Download
|
|
49
|
-
[
|
|
48
|
+
1. Download the extension: [vibeframe.mcpb (always latest)](https://github.com/vericontext/vibeframe/releases/latest/download/vibeframe.mcpb)
|
|
49
|
+
— or pick a specific version from the [releases page](https://github.com/vericontext/vibeframe/releases).
|
|
50
50
|
2. In Claude Desktop open **Settings → Extensions** and drag the `.mcpb` file in
|
|
51
51
|
(or double-click the file).
|
|
52
52
|
3. In the extension's settings pick your **Workspace folder** (projects are
|
|
53
53
|
created there; a `.env` file in that folder is loaded for API keys) and
|
|
54
54
|
optionally paste provider keys.
|
|
55
55
|
|
|
56
|
-
Rendering still needs Google Chrome and `ffmpeg` on the machine.
|
|
57
|
-
Kokoro
|
|
56
|
+
Rendering still needs Google Chrome and `ffmpeg` on the machine. Free local
|
|
57
|
+
Kokoro narration is bundled inside the extension — no install step; the first
|
|
58
|
+
use downloads a ~90 MB voice model to `~/.cache/vibeframe/models`. To update,
|
|
58
59
|
download the new release's `.mcpb` and install it over the old one.
|
|
59
60
|
|
|
60
61
|
To build the bundle from source: `pnpm -F @vibeframe/mcp-server build:mcpb`
|
|
@@ -131,8 +132,9 @@ The server prefers asking over silently picking defaults:
|
|
|
131
132
|
|
|
132
133
|
- On hosts that support **MCP elicitation** (Claude Code 2.1.76+), the `build`
|
|
133
134
|
tool opens a native form before the build starts for any choice the call
|
|
134
|
-
left unspecified: narration provider (Kokoro free/local
|
|
135
|
-
backdrop image generation (skip vs paid
|
|
135
|
+
left unspecified: narration provider (Kokoro free/local, OpenAI's
|
|
136
|
+
gpt-4o-mini-tts, or ElevenLabs), backdrop image generation (skip vs paid
|
|
137
|
+
OpenAI), and a max cost cap.
|
|
136
138
|
Declining cancels the build before any provider spend. Set
|
|
137
139
|
`VIBE_MCP_ELICIT=off` in the server env to disable the form (headless and
|
|
138
140
|
automation setups).
|
package/dist/index.js
CHANGED
|
@@ -192,8 +192,8 @@ var init_api_keys = __esm({
|
|
|
192
192
|
envVar: "OPENAI_API_KEY",
|
|
193
193
|
label: "OpenAI",
|
|
194
194
|
showInSetup: true,
|
|
195
|
-
setupDescription: "gpt-image-2 image gen ($, default since v0.56), Whisper transcribe, Agent",
|
|
196
|
-
envExampleComment: "OpenAI API Key (Whisper transcription, gpt-image-2 \u2014 default text-to-image since v0.56)",
|
|
195
|
+
setupDescription: "gpt-image-2 image gen ($, default since v0.56), gpt-4o-mini-tts narration, Whisper transcribe, Agent",
|
|
196
|
+
envExampleComment: "OpenAI API Key (Whisper transcription, gpt-4o-mini-tts narration, gpt-image-2 \u2014 default text-to-image since v0.56)",
|
|
197
197
|
envExampleUrl: "https://platform.openai.com/api-keys",
|
|
198
198
|
keyFormat: { prefix: /^sk-/, example: "sk-..." }
|
|
199
199
|
});
|
|
@@ -2300,8 +2300,8 @@ var init_openai = __esm({
|
|
|
2300
2300
|
id: "openai",
|
|
2301
2301
|
label: "OpenAI",
|
|
2302
2302
|
apiKey: "openai",
|
|
2303
|
-
kinds: ["llm", "image", "transcription"],
|
|
2304
|
-
resolverPriority: { image: 1 },
|
|
2303
|
+
kinds: ["llm", "image", "transcription", "speech"],
|
|
2304
|
+
resolverPriority: { image: 1, speech: 2 },
|
|
2305
2305
|
commandsUnlocked: [
|
|
2306
2306
|
"agent -p openai",
|
|
2307
2307
|
"generate image -p openai",
|
|
@@ -4723,16 +4723,19 @@ var init_elevenlabs = __esm({
|
|
|
4723
4723
|
});
|
|
4724
4724
|
|
|
4725
4725
|
// ../ai-providers/dist/kokoro/KokoroProvider.js
|
|
4726
|
-
async function
|
|
4726
|
+
async function loadKokoroRuntime() {
|
|
4727
4727
|
if (factoryOverride)
|
|
4728
|
-
return factoryOverride;
|
|
4728
|
+
return { factory: factoryOverride, device: "cpu" };
|
|
4729
4729
|
try {
|
|
4730
4730
|
const mod = await import("kokoro-js");
|
|
4731
|
-
return mod.KokoroTTS;
|
|
4731
|
+
return { factory: mod.KokoroTTS, device: "cpu" };
|
|
4732
4732
|
} catch (err) {
|
|
4733
|
-
const
|
|
4734
|
-
if (
|
|
4735
|
-
return
|
|
4733
|
+
const workspace = await loadKokoroFromWorkspace();
|
|
4734
|
+
if (workspace)
|
|
4735
|
+
return { factory: workspace, device: "cpu" };
|
|
4736
|
+
const bundled = await loadBundledKokoroRuntime();
|
|
4737
|
+
if (bundled)
|
|
4738
|
+
return bundled;
|
|
4736
4739
|
throw mapKokoroImportError(err);
|
|
4737
4740
|
}
|
|
4738
4741
|
}
|
|
@@ -4752,10 +4755,51 @@ async function loadKokoroFromWorkspace(baseDir = process.cwd()) {
|
|
|
4752
4755
|
return null;
|
|
4753
4756
|
}
|
|
4754
4757
|
}
|
|
4758
|
+
async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUNTIME) {
|
|
4759
|
+
const base = runtimeDir?.trim();
|
|
4760
|
+
if (!base)
|
|
4761
|
+
return null;
|
|
4762
|
+
try {
|
|
4763
|
+
const { readFile: readFile46, writeFile: writeFile53, mkdir: mkdir30 } = await import("node:fs/promises");
|
|
4764
|
+
const { join: join45, resolve: resolve80 } = await import("node:path");
|
|
4765
|
+
const { pathToFileURL } = await import("node:url");
|
|
4766
|
+
const { homedir: homedir8 } = await import("node:os");
|
|
4767
|
+
const transformersDir = resolve80(base, "node_modules", "@huggingface", "transformers");
|
|
4768
|
+
const ortDistDir = resolve80(base, "node_modules", "onnxruntime-web", "dist");
|
|
4769
|
+
const transformers = await import(pathToFileURL(join45(transformersDir, "dist", "transformers.web.js")).href);
|
|
4770
|
+
const cacheRoot = join45(homedir8(), ".cache", "vibeframe", "models");
|
|
4771
|
+
transformers.env.allowLocalModels = false;
|
|
4772
|
+
transformers.env.useCustomCache = true;
|
|
4773
|
+
transformers.env.customCache = {
|
|
4774
|
+
async match(key2) {
|
|
4775
|
+
try {
|
|
4776
|
+
return new Response(await readFile46(join45(cacheRoot, encodeURIComponent(String(key2)))));
|
|
4777
|
+
} catch {
|
|
4778
|
+
return void 0;
|
|
4779
|
+
}
|
|
4780
|
+
},
|
|
4781
|
+
async put(key2, response) {
|
|
4782
|
+
try {
|
|
4783
|
+
const buf = Buffer.from(await response.arrayBuffer());
|
|
4784
|
+
await mkdir30(cacheRoot, { recursive: true });
|
|
4785
|
+
await writeFile53(join45(cacheRoot, encodeURIComponent(String(key2))), buf);
|
|
4786
|
+
} catch {
|
|
4787
|
+
}
|
|
4788
|
+
}
|
|
4789
|
+
};
|
|
4790
|
+
transformers.env.backends.onnx.wasm.wasmPaths = pathToFileURL(ortDistDir + "/").href;
|
|
4791
|
+
const factory = await loadKokoroFromWorkspace(base);
|
|
4792
|
+
if (!factory)
|
|
4793
|
+
return null;
|
|
4794
|
+
return { factory, device: "cpu" };
|
|
4795
|
+
} catch {
|
|
4796
|
+
return null;
|
|
4797
|
+
}
|
|
4798
|
+
}
|
|
4755
4799
|
function mapKokoroImportError(err) {
|
|
4756
4800
|
const code = err instanceof Error && "code" in err ? err.code : void 0;
|
|
4757
4801
|
if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") {
|
|
4758
|
-
return new Error("Local Kokoro TTS is unavailable:
|
|
4802
|
+
return new Error("Local Kokoro TTS is unavailable: kokoro-js could not be loaded from the npm install, the workspace node_modules, or the bundled extension runtime. Set OPENAI_API_KEY or ELEVENLABS_API_KEY to use a cloud voice instead (ttsProvider: openai / elevenlabs), or install the engine locally with `npm i kokoro-js` in your workspace folder.");
|
|
4759
4803
|
}
|
|
4760
4804
|
return err instanceof Error ? err : new Error(String(err));
|
|
4761
4805
|
}
|
|
@@ -4763,10 +4807,12 @@ function loadModel(progress) {
|
|
|
4763
4807
|
if (modelPromise)
|
|
4764
4808
|
return modelPromise;
|
|
4765
4809
|
modelPromise = (async () => {
|
|
4766
|
-
const
|
|
4767
|
-
|
|
4810
|
+
const runtime = await loadKokoroRuntime();
|
|
4811
|
+
const override = process.env.VIBE_ONNX_DEVICE;
|
|
4812
|
+
const device = override === "cpu" || override === "wasm" ? override : runtime.device;
|
|
4813
|
+
return runtime.factory.from_pretrained(KOKORO_MODEL_ID, {
|
|
4768
4814
|
dtype: "q8",
|
|
4769
|
-
device
|
|
4815
|
+
device,
|
|
4770
4816
|
progress_callback: progress ? (raw2) => progress(normaliseEvent(raw2)) : void 0
|
|
4771
4817
|
});
|
|
4772
4818
|
})().catch((err) => {
|
|
@@ -4850,7 +4896,7 @@ var init_kokoro = __esm({
|
|
|
4850
4896
|
label: "Kokoro (local)",
|
|
4851
4897
|
apiKey: null,
|
|
4852
4898
|
kinds: ["speech"],
|
|
4853
|
-
resolverPriority: { speech:
|
|
4899
|
+
resolverPriority: { speech: 3 }
|
|
4854
4900
|
});
|
|
4855
4901
|
}
|
|
4856
4902
|
});
|
|
@@ -5122,12 +5168,119 @@ var init_openai_image = __esm({
|
|
|
5122
5168
|
}
|
|
5123
5169
|
});
|
|
5124
5170
|
|
|
5171
|
+
// ../ai-providers/dist/openai-tts/OpenAiTtsProvider.js
|
|
5172
|
+
var OPENAI_TTS_VOICES, DEFAULT_VOICE, DEFAULT_MODEL2, TTS_429_MAX_RETRIES2, TTS_429_RETRY_DELAY_MS2, OpenAiTtsProvider, openaiTtsProvider;
|
|
5173
|
+
var init_OpenAiTtsProvider = __esm({
|
|
5174
|
+
"../ai-providers/dist/openai-tts/OpenAiTtsProvider.js"() {
|
|
5175
|
+
"use strict";
|
|
5176
|
+
OPENAI_TTS_VOICES = [
|
|
5177
|
+
"alloy",
|
|
5178
|
+
"ash",
|
|
5179
|
+
"ballad",
|
|
5180
|
+
"cedar",
|
|
5181
|
+
"coral",
|
|
5182
|
+
"echo",
|
|
5183
|
+
"fable",
|
|
5184
|
+
"marin",
|
|
5185
|
+
"nova",
|
|
5186
|
+
"onyx",
|
|
5187
|
+
"sage",
|
|
5188
|
+
"shimmer",
|
|
5189
|
+
"verse"
|
|
5190
|
+
];
|
|
5191
|
+
DEFAULT_VOICE = "marin";
|
|
5192
|
+
DEFAULT_MODEL2 = "gpt-4o-mini-tts";
|
|
5193
|
+
TTS_429_MAX_RETRIES2 = 1;
|
|
5194
|
+
TTS_429_RETRY_DELAY_MS2 = 2e3;
|
|
5195
|
+
OpenAiTtsProvider = class {
|
|
5196
|
+
constructor() {
|
|
5197
|
+
this.id = "openai";
|
|
5198
|
+
this.name = "OpenAI TTS";
|
|
5199
|
+
this.description = "OpenAI cloud text-to-speech (gpt-4o-mini-tts)";
|
|
5200
|
+
this.capabilities = ["text-to-speech"];
|
|
5201
|
+
this.isAvailable = true;
|
|
5202
|
+
this.baseUrl = "https://api.openai.com/v1";
|
|
5203
|
+
}
|
|
5204
|
+
async initialize(config4) {
|
|
5205
|
+
this.apiKey = config4.apiKey;
|
|
5206
|
+
if (config4.baseUrl) {
|
|
5207
|
+
this.baseUrl = config4.baseUrl;
|
|
5208
|
+
}
|
|
5209
|
+
}
|
|
5210
|
+
isConfigured() {
|
|
5211
|
+
return !!this.apiKey;
|
|
5212
|
+
}
|
|
5213
|
+
async textToSpeech(text, options = {}) {
|
|
5214
|
+
if (!this.apiKey) {
|
|
5215
|
+
return { success: false, error: "OpenAI API key not configured" };
|
|
5216
|
+
}
|
|
5217
|
+
const voice = (options.voice ?? DEFAULT_VOICE).toLowerCase();
|
|
5218
|
+
if (!OPENAI_TTS_VOICES.includes(voice)) {
|
|
5219
|
+
return {
|
|
5220
|
+
success: false,
|
|
5221
|
+
error: `Unknown OpenAI voice "${options.voice}". Available voices: ${OPENAI_TTS_VOICES.join(", ")}.`
|
|
5222
|
+
};
|
|
5223
|
+
}
|
|
5224
|
+
try {
|
|
5225
|
+
let response;
|
|
5226
|
+
for (let attempt = 0; ; attempt++) {
|
|
5227
|
+
response = await fetch(`${this.baseUrl}/audio/speech`, {
|
|
5228
|
+
method: "POST",
|
|
5229
|
+
headers: {
|
|
5230
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
5231
|
+
"Content-Type": "application/json"
|
|
5232
|
+
},
|
|
5233
|
+
body: JSON.stringify({
|
|
5234
|
+
model: options.model ?? DEFAULT_MODEL2,
|
|
5235
|
+
input: text,
|
|
5236
|
+
voice,
|
|
5237
|
+
response_format: "mp3",
|
|
5238
|
+
...options.speed !== void 0 && { speed: options.speed },
|
|
5239
|
+
...options.instructions !== void 0 && { instructions: options.instructions }
|
|
5240
|
+
})
|
|
5241
|
+
});
|
|
5242
|
+
if (response.status === 429 && attempt < TTS_429_MAX_RETRIES2) {
|
|
5243
|
+
await new Promise((resolveDelay) => setTimeout(resolveDelay, TTS_429_RETRY_DELAY_MS2 * (attempt + 1)));
|
|
5244
|
+
continue;
|
|
5245
|
+
}
|
|
5246
|
+
break;
|
|
5247
|
+
}
|
|
5248
|
+
if (!response.ok) {
|
|
5249
|
+
const error = await response.text();
|
|
5250
|
+
return { success: false, error: `OpenAI TTS failed: ${error}` };
|
|
5251
|
+
}
|
|
5252
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
5253
|
+
return {
|
|
5254
|
+
success: true,
|
|
5255
|
+
audioBuffer: Buffer.from(arrayBuffer),
|
|
5256
|
+
characterCount: text.length
|
|
5257
|
+
};
|
|
5258
|
+
} catch (error) {
|
|
5259
|
+
return {
|
|
5260
|
+
success: false,
|
|
5261
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
5262
|
+
};
|
|
5263
|
+
}
|
|
5264
|
+
}
|
|
5265
|
+
};
|
|
5266
|
+
openaiTtsProvider = new OpenAiTtsProvider();
|
|
5267
|
+
}
|
|
5268
|
+
});
|
|
5269
|
+
|
|
5270
|
+
// ../ai-providers/dist/openai-tts/index.js
|
|
5271
|
+
var init_openai_tts = __esm({
|
|
5272
|
+
"../ai-providers/dist/openai-tts/index.js"() {
|
|
5273
|
+
"use strict";
|
|
5274
|
+
init_OpenAiTtsProvider();
|
|
5275
|
+
}
|
|
5276
|
+
});
|
|
5277
|
+
|
|
5125
5278
|
// ../ai-providers/dist/runway/RunwayProvider.js
|
|
5126
|
-
var
|
|
5279
|
+
var DEFAULT_MODEL3, RunwayProvider, runwayProvider;
|
|
5127
5280
|
var init_RunwayProvider = __esm({
|
|
5128
5281
|
"../ai-providers/dist/runway/RunwayProvider.js"() {
|
|
5129
5282
|
"use strict";
|
|
5130
|
-
|
|
5283
|
+
DEFAULT_MODEL3 = "gen4.5";
|
|
5131
5284
|
RunwayProvider = class _RunwayProvider {
|
|
5132
5285
|
constructor() {
|
|
5133
5286
|
this.id = "runway";
|
|
@@ -5170,7 +5323,7 @@ var init_RunwayProvider = __esm({
|
|
|
5170
5323
|
"1:1": "960:960"
|
|
5171
5324
|
};
|
|
5172
5325
|
const apiRatio = ratioMap[options?.aspectRatio || "16:9"] || "1280:720";
|
|
5173
|
-
const model = options?.model ||
|
|
5326
|
+
const model = options?.model || DEFAULT_MODEL3;
|
|
5174
5327
|
if (!options?.referenceImage && model !== "gen4.5") {
|
|
5175
5328
|
return {
|
|
5176
5329
|
id: "",
|
|
@@ -5432,11 +5585,11 @@ var init_runway = __esm({
|
|
|
5432
5585
|
|
|
5433
5586
|
// ../ai-providers/dist/kling/KlingProvider.js
|
|
5434
5587
|
import { createHmac } from "node:crypto";
|
|
5435
|
-
var
|
|
5588
|
+
var DEFAULT_MODEL4, STD_MODE_MODELS, KlingProvider, klingProvider;
|
|
5436
5589
|
var init_KlingProvider = __esm({
|
|
5437
5590
|
"../ai-providers/dist/kling/KlingProvider.js"() {
|
|
5438
5591
|
"use strict";
|
|
5439
|
-
|
|
5592
|
+
DEFAULT_MODEL4 = "kling-v2-5-turbo";
|
|
5440
5593
|
STD_MODE_MODELS = ["kling-v2-5-turbo", "kling-v2-6", "kling-v3", "kling-v3-omni"];
|
|
5441
5594
|
KlingProvider = class {
|
|
5442
5595
|
constructor() {
|
|
@@ -5499,7 +5652,7 @@ var init_KlingProvider = __esm({
|
|
|
5499
5652
|
}
|
|
5500
5653
|
try {
|
|
5501
5654
|
const token = this.generateToken();
|
|
5502
|
-
const model = options?.model ||
|
|
5655
|
+
const model = options?.model || DEFAULT_MODEL4;
|
|
5503
5656
|
let mode = options?.mode || "std";
|
|
5504
5657
|
if (!STD_MODE_MODELS.includes(model) && mode === "std") {
|
|
5505
5658
|
mode = "pro";
|
|
@@ -5870,11 +6023,11 @@ var init_kling = __esm({
|
|
|
5870
6023
|
});
|
|
5871
6024
|
|
|
5872
6025
|
// ../ai-providers/dist/grok/GrokProvider.js
|
|
5873
|
-
var
|
|
6026
|
+
var DEFAULT_MODEL5, GrokProvider, grokProvider;
|
|
5874
6027
|
var init_GrokProvider = __esm({
|
|
5875
6028
|
"../ai-providers/dist/grok/GrokProvider.js"() {
|
|
5876
6029
|
"use strict";
|
|
5877
|
-
|
|
6030
|
+
DEFAULT_MODEL5 = "grok-imagine-video";
|
|
5878
6031
|
GrokProvider = class {
|
|
5879
6032
|
constructor() {
|
|
5880
6033
|
this.id = "grok";
|
|
@@ -6041,7 +6194,7 @@ var init_GrokProvider = __esm({
|
|
|
6041
6194
|
try {
|
|
6042
6195
|
const duration = Math.round(Math.min(15, Math.max(1, options?.duration || 5)));
|
|
6043
6196
|
const body = {
|
|
6044
|
-
model:
|
|
6197
|
+
model: DEFAULT_MODEL5,
|
|
6045
6198
|
prompt: prompt3,
|
|
6046
6199
|
duration,
|
|
6047
6200
|
aspect_ratio: options?.aspectRatio || "16:9"
|
|
@@ -11248,9 +11401,11 @@ __export(dist_exports, {
|
|
|
11248
11401
|
KOKORO_MODEL_ID: () => KOKORO_MODEL_ID,
|
|
11249
11402
|
KlingProvider: () => KlingProvider,
|
|
11250
11403
|
KokoroProvider: () => KokoroProvider,
|
|
11404
|
+
OPENAI_TTS_VOICES: () => OPENAI_TTS_VOICES,
|
|
11251
11405
|
OllamaProvider: () => OllamaProvider,
|
|
11252
11406
|
OpenAIImageProvider: () => OpenAIImageProvider,
|
|
11253
11407
|
OpenAIProvider: () => OpenAIProvider,
|
|
11408
|
+
OpenAiTtsProvider: () => OpenAiTtsProvider,
|
|
11254
11409
|
ReplicateProvider: () => ReplicateProvider,
|
|
11255
11410
|
RunwayProvider: () => RunwayProvider,
|
|
11256
11411
|
WhisperProvider: () => WhisperProvider,
|
|
@@ -11274,9 +11429,12 @@ __export(dist_exports, {
|
|
|
11274
11429
|
isGeminiTextModelAlias: () => isGeminiTextModelAlias,
|
|
11275
11430
|
klingProvider: () => klingProvider,
|
|
11276
11431
|
kokoroProvider: () => kokoroProvider,
|
|
11432
|
+
loadBundledKokoroRuntime: () => loadBundledKokoroRuntime,
|
|
11433
|
+
loadKokoroFromWorkspace: () => loadKokoroFromWorkspace,
|
|
11277
11434
|
ollamaProvider: () => ollamaProvider,
|
|
11278
11435
|
openaiImageProvider: () => openaiImageProvider,
|
|
11279
11436
|
openaiProvider: () => openaiProvider,
|
|
11437
|
+
openaiTtsProvider: () => openaiTtsProvider,
|
|
11280
11438
|
providerRegistry: () => providerRegistry,
|
|
11281
11439
|
replicateProvider: () => replicateProvider,
|
|
11282
11440
|
resolveGeminiTextModel: () => resolveGeminiTextModel,
|
|
@@ -11299,6 +11457,7 @@ var init_dist = __esm({
|
|
|
11299
11457
|
init_elevenlabs();
|
|
11300
11458
|
init_kokoro();
|
|
11301
11459
|
init_openai_image();
|
|
11460
|
+
init_openai_tts();
|
|
11302
11461
|
init_runway();
|
|
11303
11462
|
init_kling();
|
|
11304
11463
|
init_grok();
|
|
@@ -28714,10 +28873,22 @@ var init_esm = __esm({
|
|
|
28714
28873
|
|
|
28715
28874
|
// ../cli/src/commands/_shared/tts-resolve.ts
|
|
28716
28875
|
async function resolveTtsProvider(preferred = "auto") {
|
|
28717
|
-
|
|
28876
|
+
let choice = preferred;
|
|
28877
|
+
if (choice === "auto") {
|
|
28878
|
+
if (await getConfiguredApiKey("ELEVENLABS_API_KEY")) {
|
|
28879
|
+
choice = "elevenlabs";
|
|
28880
|
+
} else if (await getConfiguredApiKey("OPENAI_API_KEY")) {
|
|
28881
|
+
choice = "openai";
|
|
28882
|
+
} else {
|
|
28883
|
+
choice = "kokoro";
|
|
28884
|
+
}
|
|
28885
|
+
}
|
|
28718
28886
|
if (choice === "elevenlabs") {
|
|
28719
28887
|
return buildElevenLabs();
|
|
28720
28888
|
}
|
|
28889
|
+
if (choice === "openai") {
|
|
28890
|
+
return buildOpenAi();
|
|
28891
|
+
}
|
|
28721
28892
|
return buildKokoro();
|
|
28722
28893
|
}
|
|
28723
28894
|
async function buildElevenLabs() {
|
|
@@ -28733,6 +28904,19 @@ async function buildElevenLabs() {
|
|
|
28733
28904
|
});
|
|
28734
28905
|
return { provider: "elevenlabs", audioExtension: "mp3", call };
|
|
28735
28906
|
}
|
|
28907
|
+
async function buildOpenAi() {
|
|
28908
|
+
const key2 = await getApiKey("OPENAI_API_KEY", "OpenAI");
|
|
28909
|
+
if (!key2) {
|
|
28910
|
+
throw new TtsKeyMissingError("openai");
|
|
28911
|
+
}
|
|
28912
|
+
const provider = new OpenAiTtsProvider();
|
|
28913
|
+
await provider.initialize({ apiKey: key2 });
|
|
28914
|
+
const call = async (text, opts) => provider.textToSpeech(text, {
|
|
28915
|
+
voice: opts?.voice,
|
|
28916
|
+
speed: opts?.speed
|
|
28917
|
+
});
|
|
28918
|
+
return { provider: "openai", audioExtension: "mp3", call };
|
|
28919
|
+
}
|
|
28736
28920
|
async function buildKokoro() {
|
|
28737
28921
|
const provider = new KokoroProvider();
|
|
28738
28922
|
await provider.initialize({});
|
|
@@ -28745,11 +28929,11 @@ async function buildKokoro() {
|
|
|
28745
28929
|
}
|
|
28746
28930
|
function parseTtsProviderName(value) {
|
|
28747
28931
|
if (!value) return "auto";
|
|
28748
|
-
if (value === "auto" || value === "elevenlabs" || value === "kokoro") {
|
|
28932
|
+
if (value === "auto" || value === "elevenlabs" || value === "openai" || value === "kokoro") {
|
|
28749
28933
|
return value;
|
|
28750
28934
|
}
|
|
28751
28935
|
throw new Error(
|
|
28752
|
-
`Invalid --tts: ${value}. Valid: auto, elevenlabs, kokoro.`
|
|
28936
|
+
`Invalid --tts: ${value}. Valid: auto, elevenlabs, openai, kokoro.`
|
|
28753
28937
|
);
|
|
28754
28938
|
}
|
|
28755
28939
|
var TtsKeyMissingError;
|
|
@@ -28761,7 +28945,7 @@ var init_tts_resolve = __esm({
|
|
|
28761
28945
|
TtsKeyMissingError = class extends Error {
|
|
28762
28946
|
constructor(provider) {
|
|
28763
28947
|
super(
|
|
28764
|
-
provider === "elevenlabs" ? "ElevenLabs API key required (ELEVENLABS_API_KEY). Run 'vibe setup', set ELEVENLABS_API_KEY in .env, or pass --tts kokoro for local synthesis." : `Provider ${provider} is unavailable.`
|
|
28948
|
+
provider === "elevenlabs" ? "ElevenLabs API key required (ELEVENLABS_API_KEY). Run 'vibe setup', set ELEVENLABS_API_KEY in .env, or pass --tts kokoro for local synthesis." : provider === "openai" ? "OpenAI API key required (OPENAI_API_KEY). Run 'vibe setup', set OPENAI_API_KEY in .env, or pass --tts kokoro for local synthesis." : `Provider ${provider} is unavailable.`
|
|
28765
28949
|
);
|
|
28766
28950
|
this.provider = provider;
|
|
28767
28951
|
this.name = "TtsKeyMissingError";
|
|
@@ -472016,13 +472200,13 @@ async function createBuildPlan(opts) {
|
|
|
472016
472200
|
const backdropCue = backdropPrompt ?? backdropReference?.raw;
|
|
472017
472201
|
const videoCue = videoPrompt ?? videoReference?.raw;
|
|
472018
472202
|
const musicCue = musicPrompt ?? musicReference?.raw;
|
|
472019
|
-
const narrationCost = resolved.narration.resolved === "elevenlabs" ? ELEVENLABS_NARRATION_COST_USD : 0;
|
|
472203
|
+
const narrationCost = resolved.narration.resolved === "elevenlabs" ? ELEVENLABS_NARRATION_COST_USD : resolved.narration.resolved === "openai" ? OPENAI_NARRATION_COST_USD : 0;
|
|
472020
472204
|
const narrationCache = narrationText && !narrationReference ? narrationCacheDescriptor({
|
|
472021
472205
|
beatId: beat.id,
|
|
472022
472206
|
cue: narrationText,
|
|
472023
472207
|
provider: resolved.narration.resolved,
|
|
472024
472208
|
voice,
|
|
472025
|
-
ext: resolved.narration.resolved === "
|
|
472209
|
+
ext: resolved.narration.resolved === "kokoro" ? "wav" : "mp3"
|
|
472026
472210
|
}) : null;
|
|
472027
472211
|
const backdropCache = augmentedBackdropPrompt && !backdropReference ? backdropCacheDescriptor({
|
|
472028
472212
|
beatId: beat.id,
|
|
@@ -472440,17 +472624,20 @@ function providerInput(opts) {
|
|
|
472440
472624
|
async function resolveNarrationProvider(input3, projectDir) {
|
|
472441
472625
|
const requested = input3.value.toLowerCase();
|
|
472442
472626
|
const hasElevenLabs = Boolean(await getApiKeyFromConfig("elevenlabs", { cwd: projectDir }));
|
|
472443
|
-
const
|
|
472627
|
+
const hasOpenAi = Boolean(await getApiKeyFromConfig("openai", { cwd: projectDir }));
|
|
472628
|
+
const resolved = requested === "elevenlabs" ? "elevenlabs" : requested === "openai" ? "openai" : requested === "kokoro" ? "kokoro" : hasElevenLabs ? "elevenlabs" : hasOpenAi ? "openai" : "kokoro";
|
|
472629
|
+
const requiresKey = resolved !== "kokoro";
|
|
472630
|
+
const hasKey = resolved === "elevenlabs" ? hasElevenLabs : resolved === "openai" ? hasOpenAi : true;
|
|
472444
472631
|
return {
|
|
472445
472632
|
kind: "narration",
|
|
472446
472633
|
requested: input3.requested,
|
|
472447
472634
|
resolved,
|
|
472448
472635
|
source: input3.source,
|
|
472449
|
-
requiresKey
|
|
472450
|
-
configured:
|
|
472451
|
-
...
|
|
472452
|
-
...
|
|
472453
|
-
retryWith:
|
|
472636
|
+
requiresKey,
|
|
472637
|
+
configured: hasKey,
|
|
472638
|
+
...requiresKey ? { configKey: resolved } : {},
|
|
472639
|
+
...requiresKey && !hasKey ? { missingKey: providerEnvVar(resolved) } : {},
|
|
472640
|
+
retryWith: requiresKey && !hasKey ? ["vibe setup --full"] : []
|
|
472454
472641
|
};
|
|
472455
472642
|
}
|
|
472456
472643
|
async function keyedProviderResolution(opts, projectDir) {
|
|
@@ -472546,7 +472733,7 @@ function loadPlanEnv(projectDir) {
|
|
|
472546
472733
|
dir = dirname17(dir);
|
|
472547
472734
|
}
|
|
472548
472735
|
}
|
|
472549
|
-
var import_dotenv2, VIDEO_COST_USD, MUSIC_COST_USD, ELEVENLABS_NARRATION_COST_USD, COMPOSE_COST_USD, SUPPORTED_BUILD_IMAGE_PROVIDERS;
|
|
472736
|
+
var import_dotenv2, VIDEO_COST_USD, MUSIC_COST_USD, ELEVENLABS_NARRATION_COST_USD, OPENAI_NARRATION_COST_USD, COMPOSE_COST_USD, SUPPORTED_BUILD_IMAGE_PROVIDERS;
|
|
472550
472737
|
var init_build_plan = __esm({
|
|
472551
472738
|
"../cli/src/commands/_shared/build-plan.ts"() {
|
|
472552
472739
|
"use strict";
|
|
@@ -472564,6 +472751,7 @@ var init_build_plan = __esm({
|
|
|
472564
472751
|
VIDEO_COST_USD = 5;
|
|
472565
472752
|
MUSIC_COST_USD = 0.5;
|
|
472566
472753
|
ELEVENLABS_NARRATION_COST_USD = 0.05;
|
|
472754
|
+
OPENAI_NARRATION_COST_USD = 0.01;
|
|
472567
472755
|
COMPOSE_COST_USD = 0.06;
|
|
472568
472756
|
SUPPORTED_BUILD_IMAGE_PROVIDERS = ["openai", "gemini", "grok"];
|
|
472569
472757
|
}
|
|
@@ -486565,7 +486753,7 @@ function pickOutputPath(data) {
|
|
|
486565
486753
|
}
|
|
486566
486754
|
|
|
486567
486755
|
// ../cli/src/tools/_shared/elicit.ts
|
|
486568
|
-
var NARRATION_CHOICES = ["kokoro", "elevenlabs"];
|
|
486756
|
+
var NARRATION_CHOICES = ["kokoro", "openai", "elevenlabs"];
|
|
486569
486757
|
var BACKDROP_CHOICES = ["skip", "openai"];
|
|
486570
486758
|
function planBuildElicitation(args) {
|
|
486571
486759
|
const assetsWillRun = args.stage === void 0 || args.stage === "all" || args.stage === "assets";
|
|
@@ -486580,8 +486768,9 @@ function planBuildElicitation(args) {
|
|
|
486580
486768
|
description: "Which TTS engine narrates the video?",
|
|
486581
486769
|
enum: [...NARRATION_CHOICES],
|
|
486582
486770
|
enumNames: [
|
|
486583
|
-
"Kokoro \u2014 free, runs
|
|
486584
|
-
"
|
|
486771
|
+
"Kokoro \u2014 free, runs on this machine (first use downloads a ~90 MB voice model; slower)",
|
|
486772
|
+
"OpenAI \u2014 fast cloud voice, uses your OpenAI API key (~$0.02 per video)",
|
|
486773
|
+
"ElevenLabs \u2014 premium cloud voices, uses your ElevenLabs credits"
|
|
486585
486774
|
]
|
|
486586
486775
|
};
|
|
486587
486776
|
required.push("narration");
|
|
@@ -487786,9 +487975,9 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
487786
487975
|
"Image prompt \u2014 generates assets/scene-<id>.png via the configured image provider"
|
|
487787
487976
|
).option("--headline <text>", "Visible headline (defaults to the humanised scene name)").option("--kicker <text>", "Small label above the headline (explainer / product-shot)").option("--insert-into <path>", "Root composition file to update", "index.html").option("--project <dir>", "Project directory", ".").option("--image-provider <name>", "Image provider: gemini, openai", "gemini").option(
|
|
487788
487977
|
"--tts <provider>",
|
|
487789
|
-
"TTS provider: auto, elevenlabs, kokoro (default auto \u2014
|
|
487978
|
+
"TTS provider: auto, elevenlabs, openai, kokoro (default auto \u2014 ElevenLabs key > OpenAI key > Kokoro local)",
|
|
487790
487979
|
"auto"
|
|
487791
|
-
).option("--voice <id>", "Voice id (ElevenLabs name/id, or Kokoro id like af_heart
|
|
487980
|
+
).option("--voice <id>", "Voice id (ElevenLabs name/id, OpenAI voice like marin, or Kokoro id like af_heart)").option(
|
|
487792
487981
|
"--no-audio",
|
|
487793
487982
|
"Skip TTS even when --narration is provided (useful for tests/agent dry runs)"
|
|
487794
487983
|
).option("--no-image", "Skip image generation even when --visuals is provided").option(
|
|
@@ -488049,7 +488238,7 @@ async function executeSceneAdd(opts) {
|
|
|
488049
488238
|
throw error;
|
|
488050
488239
|
}
|
|
488051
488240
|
opts.onProgress?.(
|
|
488052
|
-
resolution.provider === "kokoro" ? "Generating narration with Kokoro (local \u2014 first run downloads ~
|
|
488241
|
+
resolution.provider === "kokoro" ? "Generating narration with Kokoro (local \u2014 first run downloads a ~90MB model)..." : resolution.provider === "openai" ? "Generating narration with OpenAI (gpt-4o-mini-tts)..." : "Generating narration with ElevenLabs..."
|
|
488053
488242
|
);
|
|
488054
488243
|
const tts = await resolution.call(narrationText, {
|
|
488055
488244
|
voice: opts.voice,
|
|
@@ -488809,7 +488998,9 @@ var sceneBuildSchema = z2.object({
|
|
|
488809
488998
|
skipVideo: z2.boolean().optional().describe("Skip video generation for every beat (use existing MP4 assets if present)."),
|
|
488810
488999
|
skipMusic: z2.boolean().optional().describe("Skip music generation for every beat (use existing audio assets if present)."),
|
|
488811
489000
|
skipRender: z2.boolean().optional().describe("Stop after compose \u2014 produces compositions/*.html but no final MP4."),
|
|
488812
|
-
ttsProvider: z2.enum(["auto", "elevenlabs", "kokoro"]).optional().describe(
|
|
489001
|
+
ttsProvider: z2.enum(["auto", "elevenlabs", "openai", "kokoro"]).optional().describe(
|
|
489002
|
+
"TTS provider override. Default 'auto' (elevenlabs key > openai key > local kokoro)."
|
|
489003
|
+
),
|
|
488813
489004
|
voice: z2.string().optional().describe("TTS voice id (provider-specific)."),
|
|
488814
489005
|
imageProvider: z2.enum(["openai"]).optional().describe("Image provider for backdrops. Default 'openai' (gpt-image-2)."),
|
|
488815
489006
|
videoProvider: z2.enum(["seedance", "grok", "kling", "runway", "veo"]).optional().describe("Video provider for per-beat video cues. Default seedance."),
|
|
@@ -492652,7 +492843,7 @@ var planTool = defineTool({
|
|
|
492652
492843
|
skipBackdrop: z7.boolean().optional().describe("Don't include backdrop image generation in the plan."),
|
|
492653
492844
|
skipVideo: z7.boolean().optional().describe("Don't include video generation in the plan."),
|
|
492654
492845
|
skipMusic: z7.boolean().optional().describe("Don't include music generation in the plan."),
|
|
492655
|
-
ttsProvider: z7.enum(["auto", "elevenlabs", "kokoro"]).optional().describe("TTS provider override."),
|
|
492846
|
+
ttsProvider: z7.enum(["auto", "elevenlabs", "openai", "kokoro"]).optional().describe("TTS provider override."),
|
|
492656
492847
|
voice: z7.string().optional().describe("Voice id."),
|
|
492657
492848
|
imageProvider: z7.string().optional().describe("Image provider override."),
|
|
492658
492849
|
imageQuality: z7.enum(["standard", "hd"]).optional().describe("Image quality override."),
|
|
@@ -498289,7 +498480,7 @@ function buildServerInstructions(cwd = resolveServerWorkspaceRoot()) {
|
|
|
498289
498480
|
"When creating projects with init, use a project name or workspace-relative path under the workspace root.",
|
|
498290
498481
|
"Do not create projects in /tmp, /home/claude, /workspace, or other synthetic roots unless the user explicitly asks.",
|
|
498291
498482
|
"Before high or very-high cost provider work, run a dry-run or plan when available and ask the user to confirm provider spend.",
|
|
498292
|
-
"When the user's request leaves them unspecified, ask the user before building instead of silently picking defaults: narration provider (kokoro = free
|
|
498483
|
+
"When the user's request leaves them unspecified, ask the user before building instead of silently picking defaults: narration provider (kokoro = free, runs locally, first use downloads a ~90 MB voice model and synthesis is slower; openai = fast cloud voice using the OpenAI API key, roughly $0.02 per video; elevenlabs = premium cloud voices using ElevenLabs credits), backdrop image generation (paid; skipping is free), and visual style (list options via scene_list_styles). Present the choices and wait for the answer.",
|
|
498293
498484
|
"Narration and backdrop choices are independent \u2014 kokoro narration with OpenAI backdrops is a common combination. Pass each answer explicitly to build (ttsProvider plus skipBackdrop/imageProvider); never let one choice imply the other."
|
|
498294
498485
|
].join("\n");
|
|
498295
498486
|
}
|
|
@@ -498316,7 +498507,7 @@ var server2 = new Server(
|
|
|
498316
498507
|
{
|
|
498317
498508
|
name: "vibeframe",
|
|
498318
498509
|
// Stamped with the package version by build.js at bundle time.
|
|
498319
|
-
version: "0.
|
|
498510
|
+
version: "0.113.0"
|
|
498320
498511
|
},
|
|
498321
498512
|
{
|
|
498322
498513
|
capabilities: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeframe/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.113.0",
|
|
4
4
|
"description": "VibeFrame MCP Server - AI-native video editing via Model Context Protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"tsx": "^4.21.0",
|
|
61
61
|
"typescript": "^5.3.3",
|
|
62
62
|
"vitest": "^1.2.2",
|
|
63
|
-
"@vibeframe/cli": "0.
|
|
64
|
-
"@vibeframe/core": "0.
|
|
63
|
+
"@vibeframe/cli": "0.113.0",
|
|
64
|
+
"@vibeframe/core": "0.113.0"
|
|
65
65
|
},
|
|
66
66
|
"engines": {
|
|
67
67
|
"node": ">=20"
|