@vibeframe/cli 0.91.0 → 0.91.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +181 -39
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -31895,7 +31895,7 @@ async function promptConfirm(question, defaultYes = true) {
|
|
|
31895
31895
|
if (answer === "") return defaultYes;
|
|
31896
31896
|
return answer.toLowerCase().startsWith("y");
|
|
31897
31897
|
}
|
|
31898
|
-
async function promptMultiSelect(_question, options, defaultSelected = []) {
|
|
31898
|
+
async function promptMultiSelect(_question, options, defaultSelected = [], opts = {}) {
|
|
31899
31899
|
const input = getTTYInputStream();
|
|
31900
31900
|
const selected = options.map((_, i) => Boolean(defaultSelected[i]));
|
|
31901
31901
|
if (typeof input.setRawMode === "function") {
|
|
@@ -31931,6 +31931,9 @@ async function promptMultiSelect(_question, options, defaultSelected = []) {
|
|
|
31931
31931
|
};
|
|
31932
31932
|
const onData = (char) => {
|
|
31933
31933
|
if (char === "\r" || char === "\n") {
|
|
31934
|
+
if (opts.enterSelectsFocusedWhenEmpty && selected.every((v) => !v)) {
|
|
31935
|
+
selected[cursor] = true;
|
|
31936
|
+
}
|
|
31934
31937
|
finish();
|
|
31935
31938
|
} else if (char === "") {
|
|
31936
31939
|
input.setRawMode(false);
|
|
@@ -62910,7 +62913,7 @@ init_source();
|
|
|
62910
62913
|
// package.json
|
|
62911
62914
|
var package_default = {
|
|
62912
62915
|
name: "@vibeframe/cli",
|
|
62913
|
-
version: "0.91.
|
|
62916
|
+
version: "0.91.1",
|
|
62914
62917
|
description: "VibeFrame CLI - natural language video editing from the terminal",
|
|
62915
62918
|
private: false,
|
|
62916
62919
|
license: "MIT",
|
|
@@ -69987,6 +69990,26 @@ var AI_FEATURES = [
|
|
|
69987
69990
|
defaultProvider: "OpenAI gpt-image-2 (Artificial Analysis #1, since v0.56)",
|
|
69988
69991
|
alsoAvailable: "Gemini Nano Banana, Grok Imagine",
|
|
69989
69992
|
keys: [{ configKey: "openai", envVar: "OPENAI_API_KEY", name: "OpenAI", url: "https://platform.openai.com/api-keys", what: "gpt-image-2 image generation + editing (also Whisper, Agent)" }],
|
|
69993
|
+
providerChoices: [
|
|
69994
|
+
{
|
|
69995
|
+
label: "OpenAI gpt-image-2",
|
|
69996
|
+
desc: "recommended default, image generation + editing",
|
|
69997
|
+
key: { configKey: "openai", envVar: "OPENAI_API_KEY", name: "OpenAI", url: "https://platform.openai.com/api-keys", what: "gpt-image-2 image generation + editing (also Whisper, Agent)" },
|
|
69998
|
+
defaultFor: { kind: "image", value: "openai" }
|
|
69999
|
+
},
|
|
70000
|
+
{
|
|
70001
|
+
label: "Gemini",
|
|
70002
|
+
desc: "Google image generation + multimodal analysis",
|
|
70003
|
+
key: { configKey: "google", envVar: "GOOGLE_API_KEY", name: "Google", url: "https://aistudio.google.com/apikey", what: "Gemini image generation and multimodal analysis" },
|
|
70004
|
+
defaultFor: { kind: "image", value: "gemini" }
|
|
70005
|
+
},
|
|
70006
|
+
{
|
|
70007
|
+
label: "Grok",
|
|
70008
|
+
desc: "xAI image generation",
|
|
70009
|
+
key: { configKey: "xai", envVar: "XAI_API_KEY", name: "xAI", url: "https://console.x.ai/", what: "Grok image generation and Agent" },
|
|
70010
|
+
defaultFor: { kind: "image", value: "grok" }
|
|
70011
|
+
}
|
|
70012
|
+
],
|
|
69990
70013
|
tryCommand: 'vibe generate image "a sunset over mountains" -o test.png'
|
|
69991
70014
|
},
|
|
69992
70015
|
{
|
|
@@ -69995,6 +70018,38 @@ var AI_FEATURES = [
|
|
|
69995
70018
|
defaultProvider: "Seedance 2.0 via fal.ai (Artificial Analysis #2 t2v + i2v, since v0.57)",
|
|
69996
70019
|
alsoAvailable: "Grok Imagine, Kling, Runway Gen-4.5, Google Veo",
|
|
69997
70020
|
keys: [{ configKey: "fal", envVar: "FAL_KEY", name: "Seedance 2.0 (via fal.ai)", url: "https://fal.ai/dashboard/keys", what: "ByteDance Seedance 2.0 text-to-video and image-to-video" }],
|
|
70021
|
+
providerChoices: [
|
|
70022
|
+
{
|
|
70023
|
+
label: "Seedance 2.0 via fal.ai",
|
|
70024
|
+
desc: "recommended default, text-to-video + image-to-video",
|
|
70025
|
+
key: { configKey: "fal", envVar: "FAL_KEY", name: "Seedance 2.0 (via fal.ai)", url: "https://fal.ai/dashboard/keys", what: "ByteDance Seedance 2.0 text-to-video and image-to-video" },
|
|
70026
|
+
defaultFor: { kind: "video", value: "seedance" }
|
|
70027
|
+
},
|
|
70028
|
+
{
|
|
70029
|
+
label: "Grok",
|
|
70030
|
+
desc: "xAI video generation with audio",
|
|
70031
|
+
key: { configKey: "xai", envVar: "XAI_API_KEY", name: "xAI", url: "https://console.x.ai/", what: "Grok video generation and Agent" },
|
|
70032
|
+
defaultFor: { kind: "video", value: "grok" }
|
|
70033
|
+
},
|
|
70034
|
+
{
|
|
70035
|
+
label: "Kling",
|
|
70036
|
+
desc: "Kling v2.5/v3 video generation",
|
|
70037
|
+
key: { configKey: "kling", envVar: "KLING_API_KEY", name: "Kling", url: "https://platform.klingai.com/", what: "Kling video generation" },
|
|
70038
|
+
defaultFor: { kind: "video", value: "kling" }
|
|
70039
|
+
},
|
|
70040
|
+
{
|
|
70041
|
+
label: "Runway",
|
|
70042
|
+
desc: "Runway Gen-4.5 video generation",
|
|
70043
|
+
key: { configKey: "runway", envVar: "RUNWAY_API_SECRET", name: "Runway", url: "https://app.runwayml.com/settings/api-keys", what: "Runway Gen-4.5 video generation" },
|
|
70044
|
+
defaultFor: { kind: "video", value: "runway" }
|
|
70045
|
+
},
|
|
70046
|
+
{
|
|
70047
|
+
label: "Veo",
|
|
70048
|
+
desc: "Google Veo video generation",
|
|
70049
|
+
key: { configKey: "google", envVar: "GOOGLE_API_KEY", name: "Google", url: "https://aistudio.google.com/apikey", what: "Google Veo video generation" },
|
|
70050
|
+
defaultFor: { kind: "video", value: "veo" }
|
|
70051
|
+
}
|
|
70052
|
+
],
|
|
69998
70053
|
tryCommand: 'vibe generate video "ocean waves" -o waves.mp4'
|
|
69999
70054
|
},
|
|
70000
70055
|
{
|
|
@@ -70003,6 +70058,23 @@ var AI_FEATURES = [
|
|
|
70003
70058
|
defaultProvider: "ElevenLabs (paid, premium quality) \u2014 falls back to local Kokoro when no key (free, since v0.54)",
|
|
70004
70059
|
alsoAvailable: "Replicate MusicGen (music only)",
|
|
70005
70060
|
keys: [{ configKey: "elevenlabs", envVar: "ELEVENLABS_API_KEY", name: "ElevenLabs", url: "https://elevenlabs.io/app/settings/api-keys", what: "Text-to-speech, sound effects, music, voice cloning (skip to use local Kokoro)" }],
|
|
70061
|
+
providerChoices: [
|
|
70062
|
+
{
|
|
70063
|
+
label: "ElevenLabs",
|
|
70064
|
+
desc: "premium TTS, SFX, music, voice clone",
|
|
70065
|
+
key: { configKey: "elevenlabs", envVar: "ELEVENLABS_API_KEY", name: "ElevenLabs", url: "https://elevenlabs.io/app/settings/api-keys", what: "Text-to-speech, sound effects, music, voice cloning" }
|
|
70066
|
+
},
|
|
70067
|
+
{
|
|
70068
|
+
label: "Kokoro local",
|
|
70069
|
+
desc: "free local TTS fallback, no API key",
|
|
70070
|
+
keyless: true
|
|
70071
|
+
},
|
|
70072
|
+
{
|
|
70073
|
+
label: "Replicate MusicGen",
|
|
70074
|
+
desc: "background music generation",
|
|
70075
|
+
key: { configKey: "replicate", envVar: "REPLICATE_API_TOKEN", name: "Replicate", url: "https://replicate.com/account/api-tokens", what: "MusicGen background music" }
|
|
70076
|
+
}
|
|
70077
|
+
],
|
|
70006
70078
|
tryCommand: 'vibe generate speech "Hello world" -o hello.mp3'
|
|
70007
70079
|
},
|
|
70008
70080
|
{
|
|
@@ -70017,6 +70089,19 @@ var AI_FEATURES = [
|
|
|
70017
70089
|
tryCommand: "vibe edit caption video.mp4 -o captioned.mp4"
|
|
70018
70090
|
}
|
|
70019
70091
|
];
|
|
70092
|
+
function addUniqueKey(keys, keyDef) {
|
|
70093
|
+
if (!keys.some((k) => k.configKey === keyDef.configKey)) {
|
|
70094
|
+
keys.push(keyDef);
|
|
70095
|
+
}
|
|
70096
|
+
}
|
|
70097
|
+
function applyProviderDefault(config2, choice) {
|
|
70098
|
+
if (!choice.defaultFor) return;
|
|
70099
|
+
if (choice.defaultFor.kind === "image") {
|
|
70100
|
+
config2.defaults.imageProvider = choice.defaultFor.value;
|
|
70101
|
+
} else {
|
|
70102
|
+
config2.defaults.videoProvider = choice.defaultFor.value;
|
|
70103
|
+
}
|
|
70104
|
+
}
|
|
70020
70105
|
async function runNonInteractiveSetup(opts) {
|
|
70021
70106
|
const scope = opts.scope ?? "user";
|
|
70022
70107
|
let config2 = await loadConfig({ scope });
|
|
@@ -70158,6 +70243,7 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
|
|
|
70158
70243
|
console.log(source_default.dim("2. Features"));
|
|
70159
70244
|
console.log(source_default.bold("Which AI features do you need?"));
|
|
70160
70245
|
console.log(source_default.dim(" \u2191\u2193 navigate \xB7 space to toggle \xB7 enter to confirm"));
|
|
70246
|
+
console.log(source_default.dim(" Tip: pressing enter on the highlighted item selects it if nothing is checked yet."));
|
|
70161
70247
|
console.log();
|
|
70162
70248
|
const featureLabels = AI_FEATURES.map((f) => {
|
|
70163
70249
|
const keyCount = f.keys.length;
|
|
@@ -70166,7 +70252,9 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
|
|
|
70166
70252
|
});
|
|
70167
70253
|
const picked = await promptMultiSelect(
|
|
70168
70254
|
source_default.cyan(" Pick (e.g. 1,3 or 'all'): "),
|
|
70169
|
-
featureLabels
|
|
70255
|
+
featureLabels,
|
|
70256
|
+
[],
|
|
70257
|
+
{ enterSelectsFocusedWhenEmpty: true }
|
|
70170
70258
|
);
|
|
70171
70259
|
const selectedFeatures = picked.map((i) => AI_FEATURES[i]);
|
|
70172
70260
|
console.log();
|
|
@@ -70177,53 +70265,107 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
|
|
|
70177
70265
|
await showComplete(config2, "vibe --help", [], scope);
|
|
70178
70266
|
return;
|
|
70179
70267
|
}
|
|
70180
|
-
|
|
70181
|
-
console.log(source_default.
|
|
70182
|
-
console.log(source_default.
|
|
70268
|
+
const plannedKeys = /* @__PURE__ */ new Map();
|
|
70269
|
+
console.log(source_default.dim("3. Providers"));
|
|
70270
|
+
console.log(source_default.bold("Choose providers for each selected feature"));
|
|
70271
|
+
console.log(source_default.dim(" Recommended defaults are pre-selected. You can toggle more than one."));
|
|
70183
70272
|
console.log();
|
|
70184
|
-
const collectedKeys = /* @__PURE__ */ new Set();
|
|
70185
70273
|
for (const feature of selectedFeatures) {
|
|
70186
|
-
|
|
70187
|
-
|
|
70188
|
-
|
|
70189
|
-
console.log(source_default.dim(`
|
|
70274
|
+
const keysForFeature = [];
|
|
70275
|
+
if (feature.providerChoices && feature.providerChoices.length > 0) {
|
|
70276
|
+
console.log(source_default.bold.cyan(` ${feature.label}`));
|
|
70277
|
+
console.log(source_default.dim(` Default path: ${feature.defaultProvider}`));
|
|
70278
|
+
if (feature.alsoAvailable) {
|
|
70279
|
+
console.log(source_default.dim(` Alternatives: ${feature.alsoAvailable}`));
|
|
70280
|
+
}
|
|
70281
|
+
console.log();
|
|
70282
|
+
const defaultSelected = feature.providerChoices.map((_, i) => i === 0);
|
|
70283
|
+
const providerLabels = feature.providerChoices.map((choice) => {
|
|
70284
|
+
const keyHint = choice.keyless ? source_default.dim("no key") : choice.key ? source_default.dim(choice.key.envVar) : source_default.dim("no key");
|
|
70285
|
+
return `${choice.label} ${source_default.dim(`- ${choice.desc}`)} ${keyHint}`;
|
|
70286
|
+
});
|
|
70287
|
+
const pickedProviders = await promptMultiSelect(
|
|
70288
|
+
source_default.cyan(" Providers (space toggles, enter confirms): "),
|
|
70289
|
+
providerLabels,
|
|
70290
|
+
defaultSelected
|
|
70291
|
+
);
|
|
70292
|
+
const selectedChoices = pickedProviders.map((i) => feature.providerChoices[i]);
|
|
70293
|
+
const defaultChoice = selectedChoices.find((choice) => choice.defaultFor);
|
|
70294
|
+
if (defaultChoice) {
|
|
70295
|
+
applyProviderDefault(config2, defaultChoice);
|
|
70296
|
+
}
|
|
70297
|
+
for (const choice of selectedChoices) {
|
|
70298
|
+
if (choice.key) addUniqueKey(keysForFeature, choice.key);
|
|
70299
|
+
}
|
|
70300
|
+
if (selectedChoices.some((choice) => choice.keyless)) {
|
|
70301
|
+
console.log(source_default.dim(" No API key needed for selected local provider(s)."));
|
|
70302
|
+
}
|
|
70303
|
+
console.log();
|
|
70304
|
+
} else {
|
|
70305
|
+
for (const keyDef of feature.keys) {
|
|
70306
|
+
addUniqueKey(keysForFeature, keyDef);
|
|
70307
|
+
}
|
|
70190
70308
|
}
|
|
70309
|
+
plannedKeys.set(feature.label, keysForFeature);
|
|
70310
|
+
}
|
|
70311
|
+
const needsKeys = [...plannedKeys.values()].some((keys) => keys.length > 0);
|
|
70312
|
+
if (needsKeys) {
|
|
70313
|
+
console.log(source_default.dim("4. API keys"));
|
|
70314
|
+
console.log(source_default.bold("API Keys"));
|
|
70315
|
+
console.log(source_default.dim(" Saved locally, never shared. Press Enter to skip."));
|
|
70191
70316
|
console.log();
|
|
70192
|
-
|
|
70193
|
-
|
|
70194
|
-
|
|
70317
|
+
const collectedKeys = /* @__PURE__ */ new Set();
|
|
70318
|
+
for (const feature of selectedFeatures) {
|
|
70319
|
+
const keysForFeature = plannedKeys.get(feature.label) ?? [];
|
|
70320
|
+
if (keysForFeature.length === 0) {
|
|
70195
70321
|
continue;
|
|
70196
70322
|
}
|
|
70197
|
-
|
|
70198
|
-
|
|
70199
|
-
|
|
70200
|
-
|
|
70201
|
-
const value = configValue || envValue;
|
|
70202
|
-
const source = configValue ? "config" : ".env";
|
|
70203
|
-
console.log(` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(value)} ${source_default.dim(`(${source})`)}`);
|
|
70204
|
-
collectedKeys.add(keyDef.configKey);
|
|
70205
|
-
continue;
|
|
70323
|
+
console.log(source_default.bold.cyan(` ${feature.label}`));
|
|
70324
|
+
console.log(source_default.dim(` Default: ${feature.defaultProvider}`));
|
|
70325
|
+
if (feature.alsoAvailable) {
|
|
70326
|
+
console.log(source_default.dim(` Also available: ${feature.alsoAvailable}`));
|
|
70206
70327
|
}
|
|
70207
|
-
console.log(
|
|
70208
|
-
|
|
70209
|
-
|
|
70210
|
-
|
|
70211
|
-
|
|
70212
|
-
|
|
70213
|
-
|
|
70214
|
-
const
|
|
70215
|
-
|
|
70216
|
-
|
|
70217
|
-
|
|
70218
|
-
|
|
70328
|
+
console.log();
|
|
70329
|
+
for (const keyDef of keysForFeature) {
|
|
70330
|
+
if (collectedKeys.has(keyDef.configKey)) {
|
|
70331
|
+
console.log(` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} (already set above)`);
|
|
70332
|
+
continue;
|
|
70333
|
+
}
|
|
70334
|
+
loadEnv();
|
|
70335
|
+
const configValue = config2.providers[keyDef.configKey];
|
|
70336
|
+
const envValue = process.env[keyDef.envVar];
|
|
70337
|
+
if (configValue || envValue) {
|
|
70338
|
+
const value = configValue || envValue;
|
|
70339
|
+
const source = configValue ? "config" : ".env";
|
|
70340
|
+
console.log(` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(value)} ${source_default.dim(`(${source})`)}`);
|
|
70341
|
+
collectedKeys.add(keyDef.configKey);
|
|
70342
|
+
continue;
|
|
70343
|
+
}
|
|
70344
|
+
console.log(source_default.dim(` ${keyDef.what}`));
|
|
70345
|
+
console.log(source_default.dim(` Get key: ${keyDef.url} [o] open in browser`));
|
|
70346
|
+
const newKey = await promptHidden(
|
|
70347
|
+
source_default.cyan(` ${keyDef.name.padEnd(14)} ${source_default.dim(keyDef.envVar)}: `),
|
|
70348
|
+
{ openHotkeyUrl: keyDef.url }
|
|
70349
|
+
);
|
|
70350
|
+
if (newKey.trim()) {
|
|
70351
|
+
const trimmed = newKey.trim();
|
|
70352
|
+
config2.providers[keyDef.configKey] = trimmed;
|
|
70353
|
+
const fmt = validateKeyFormat(keyDef.configKey, trimmed);
|
|
70354
|
+
if (!fmt.ok && fmt.expected) {
|
|
70355
|
+
console.log(` ${source_default.yellow("\u26A0")} Saved, but format looks unusual ${source_default.dim(`(expected ${fmt.expected})`)}`);
|
|
70356
|
+
} else {
|
|
70357
|
+
console.log(` ${source_default.green("\u2713")} Saved`);
|
|
70358
|
+
}
|
|
70359
|
+
collectedKeys.add(keyDef.configKey);
|
|
70219
70360
|
} else {
|
|
70220
|
-
console.log(` ${source_default.
|
|
70361
|
+
console.log(` ${source_default.yellow("\u26A0")} Skipped ${source_default.dim(`(set ${keyDef.envVar} in .env later)`)}`);
|
|
70221
70362
|
}
|
|
70222
|
-
collectedKeys.add(keyDef.configKey);
|
|
70223
|
-
} else {
|
|
70224
|
-
console.log(` ${source_default.yellow("\u26A0")} Skipped ${source_default.dim(`(set ${keyDef.envVar} in .env later)`)}`);
|
|
70225
70363
|
}
|
|
70364
|
+
console.log();
|
|
70226
70365
|
}
|
|
70366
|
+
} else {
|
|
70367
|
+
console.log(source_default.dim("4. API keys"));
|
|
70368
|
+
console.log(source_default.dim(" No API keys needed for the selected provider(s)."));
|
|
70227
70369
|
console.log();
|
|
70228
70370
|
}
|
|
70229
70371
|
await saveConfig(config2, { scope });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeframe/cli",
|
|
3
|
-
"version": "0.91.
|
|
3
|
+
"version": "0.91.1",
|
|
4
4
|
"description": "VibeFrame CLI - natural language video editing from the terminal",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
@@ -183,8 +183,8 @@
|
|
|
183
183
|
"tsx": "^4.21.0",
|
|
184
184
|
"typescript": "^5.3.3",
|
|
185
185
|
"vitest": "^1.2.2",
|
|
186
|
-
"@vibeframe/ai-providers": "0.91.
|
|
187
|
-
"@vibeframe/core": "0.91.
|
|
186
|
+
"@vibeframe/ai-providers": "0.91.1",
|
|
187
|
+
"@vibeframe/core": "0.91.1"
|
|
188
188
|
},
|
|
189
189
|
"engines": {
|
|
190
190
|
"node": ">=20"
|