@vibeframe/cli 0.80.1 → 0.82.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/dist/index.js +439 -162
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -14372,7 +14372,11 @@ var init_api_keys = __esm({
|
|
|
14372
14372
|
showInSetup: true,
|
|
14373
14373
|
setupDescription: "Seedance 2.0 video gen ($$, default since v0.57)",
|
|
14374
14374
|
envExampleComment: "fal.ai API Key (Seedance 2.0 video \u2014 default text/image-to-video since v0.57, Artificial Analysis ELO #2)",
|
|
14375
|
-
envExampleUrl: "https://fal.ai/dashboard/keys"
|
|
14375
|
+
envExampleUrl: "https://fal.ai/dashboard/keys",
|
|
14376
|
+
// fal keys are `<key-id>:<key-secret>` (both UUIDs). The colon is the
|
|
14377
|
+
// structural marker — same approach as Kling. Don't pin the UUID shape
|
|
14378
|
+
// since fal could rotate to a different secret format.
|
|
14379
|
+
keyFormat: { prefix: /:/, example: "<key-id>:<key-secret>" }
|
|
14376
14380
|
});
|
|
14377
14381
|
defineApiKey({
|
|
14378
14382
|
configKey: "xai",
|
|
@@ -14433,6 +14437,10 @@ var init_api_keys = __esm({
|
|
|
14433
14437
|
// not prompted in setup wizard — internal upload host
|
|
14434
14438
|
envExampleComment: "ImgBB API Key (image hosting \u2014 used by Kling and Seedance for image-to-video uploads)",
|
|
14435
14439
|
envExampleUrl: "https://api.imgbb.com/",
|
|
14440
|
+
// ImgBB issues 32-character lowercase hex keys. Soft-warn if a pasted
|
|
14441
|
+
// key doesn't match — covers the common "I copied my Kling key by
|
|
14442
|
+
// mistake" failure mode.
|
|
14443
|
+
keyFormat: { prefix: /^[a-f0-9]{32}$/, example: "32-char hex" },
|
|
14436
14444
|
// ImgBB has no provider class (envvar-only); doctor still shows what it
|
|
14437
14445
|
// unlocks at the apiKey level.
|
|
14438
14446
|
commandsUnlocked: [
|
|
@@ -17264,18 +17272,18 @@ ${transcriptWithTimestamps}`
|
|
|
17264
17272
|
return emptyViralAnalysis("Analysis failed");
|
|
17265
17273
|
}
|
|
17266
17274
|
}
|
|
17267
|
-
async function suggestPlatformCuts(api, transcriptSegments, viralAnalysis,
|
|
17268
|
-
const emptyResult = { platform:
|
|
17275
|
+
async function suggestPlatformCuts(api, transcriptSegments, viralAnalysis, platform3, clips) {
|
|
17276
|
+
const emptyResult = { platform: platform3.id, segments: [], totalDuration: 0 };
|
|
17269
17277
|
const transcriptWithTimestamps = transcriptSegments.map((seg) => `[${seg.startTime.toFixed(1)}s - ${seg.endTime.toFixed(1)}s] ${seg.text}`).join("\n");
|
|
17270
17278
|
const clipsInfo = clips.map((c) => `[${c.id}] ${c.startTime.toFixed(1)}s - ${(c.startTime + c.duration).toFixed(1)}s (${c.duration.toFixed(1)}s)`).join("\n");
|
|
17271
|
-
const systemPrompt = `You are an expert video editor optimizing content for ${
|
|
17279
|
+
const systemPrompt = `You are an expert video editor optimizing content for ${platform3.name}.
|
|
17272
17280
|
|
|
17273
17281
|
Platform requirements:
|
|
17274
|
-
- Aspect ratio: ${
|
|
17275
|
-
- Maximum duration: ${
|
|
17276
|
-
- Ideal duration: ${
|
|
17277
|
-
- Needs strong hook: ${
|
|
17278
|
-
- Needs captions: ${
|
|
17282
|
+
- Aspect ratio: ${platform3.aspectRatio}
|
|
17283
|
+
- Maximum duration: ${platform3.maxDuration}s
|
|
17284
|
+
- Ideal duration: ${platform3.idealDuration.min}-${platform3.idealDuration.max}s
|
|
17285
|
+
- Needs strong hook: ${platform3.features.hook ? "Yes" : "No"}
|
|
17286
|
+
- Needs captions: ${platform3.features.captions ? "Yes" : "No"}
|
|
17279
17287
|
|
|
17280
17288
|
Previous analysis found:
|
|
17281
17289
|
- Hook strength: ${viralAnalysis.hookStrength}%
|
|
@@ -17291,7 +17299,7 @@ Your task:
|
|
|
17291
17299
|
|
|
17292
17300
|
Respond with JSON only:
|
|
17293
17301
|
{
|
|
17294
|
-
"platform": "${
|
|
17302
|
+
"platform": "${platform3.id}",
|
|
17295
17303
|
"segments": [
|
|
17296
17304
|
{"sourceClipId": "clip-id", "startTime": 0, "endTime": 45.5, "priority": 1.0}
|
|
17297
17305
|
],
|
|
@@ -17302,7 +17310,7 @@ Respond with JSON only:
|
|
|
17302
17310
|
system: systemPrompt,
|
|
17303
17311
|
messages: [{
|
|
17304
17312
|
role: "user",
|
|
17305
|
-
content: `Optimize this video for ${
|
|
17313
|
+
content: `Optimize this video for ${platform3.name}:
|
|
17306
17314
|
|
|
17307
17315
|
## Transcript:
|
|
17308
17316
|
${transcriptWithTimestamps}
|
|
@@ -17998,10 +18006,10 @@ Instruction: ${instruction}`
|
|
|
17998
18006
|
}
|
|
17999
18007
|
return analyzeViralPotential(this.api, transcriptSegments, projectMeta, targetPlatforms);
|
|
18000
18008
|
}
|
|
18001
|
-
async suggestPlatformCuts(transcriptSegments, viralAnalysis,
|
|
18009
|
+
async suggestPlatformCuts(transcriptSegments, viralAnalysis, platform3, clips) {
|
|
18002
18010
|
if (!this.api)
|
|
18003
|
-
return { platform:
|
|
18004
|
-
return suggestPlatformCuts(this.api, transcriptSegments, viralAnalysis,
|
|
18011
|
+
return { platform: platform3.id, segments: [], totalDuration: 0 };
|
|
18012
|
+
return suggestPlatformCuts(this.api, transcriptSegments, viralAnalysis, platform3, clips);
|
|
18005
18013
|
}
|
|
18006
18014
|
async generateViralCaptions(transcriptSegments, style) {
|
|
18007
18015
|
if (!this.api)
|
|
@@ -33626,7 +33634,7 @@ Examples:
|
|
|
33626
33634
|
}
|
|
33627
33635
|
}
|
|
33628
33636
|
} else if (provider === "runway") {
|
|
33629
|
-
const { spawn:
|
|
33637
|
+
const { spawn: spawn4 } = await import("child_process");
|
|
33630
33638
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
33631
33639
|
const __dirname2 = dirname7(__filename2);
|
|
33632
33640
|
const scriptPath = resolve23(
|
|
@@ -33641,7 +33649,7 @@ Examples:
|
|
|
33641
33649
|
const args = [scriptPath, prompt3, "-o", outputPath, "-r", options.ratio || "16:9"];
|
|
33642
33650
|
spinner2.text = "Generating image with Runway (gemini_2.5_flash)...";
|
|
33643
33651
|
await new Promise((resolvePromise, reject) => {
|
|
33644
|
-
const proc =
|
|
33652
|
+
const proc = spawn4("python3", args, {
|
|
33645
33653
|
env: { ...process.env, RUNWAY_API_SECRET: apiKey },
|
|
33646
33654
|
stdio: ["ignore", "pipe", "pipe"]
|
|
33647
33655
|
});
|
|
@@ -37001,8 +37009,8 @@ var init_translate_srt = __esm({
|
|
|
37001
37009
|
import { existsSync as existsSync21 } from "node:fs";
|
|
37002
37010
|
import { resolve as resolve27 } from "node:path";
|
|
37003
37011
|
function detectSystemFont() {
|
|
37004
|
-
const
|
|
37005
|
-
if (
|
|
37012
|
+
const platform3 = process.platform;
|
|
37013
|
+
if (platform3 === "darwin") {
|
|
37006
37014
|
const candidates = [
|
|
37007
37015
|
"/System/Library/Fonts/Helvetica.ttc",
|
|
37008
37016
|
"/System/Library/Fonts/HelveticaNeue.ttc",
|
|
@@ -37011,7 +37019,7 @@ function detectSystemFont() {
|
|
|
37011
37019
|
for (const f of candidates) {
|
|
37012
37020
|
if (existsSync21(f)) return f;
|
|
37013
37021
|
}
|
|
37014
|
-
} else if (
|
|
37022
|
+
} else if (platform3 === "linux") {
|
|
37015
37023
|
const candidates = [
|
|
37016
37024
|
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
|
|
37017
37025
|
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
|
|
@@ -37020,7 +37028,7 @@ function detectSystemFont() {
|
|
|
37020
37028
|
for (const f of candidates) {
|
|
37021
37029
|
if (existsSync21(f)) return f;
|
|
37022
37030
|
}
|
|
37023
|
-
} else if (
|
|
37031
|
+
} else if (platform3 === "win32") {
|
|
37024
37032
|
const candidates = [
|
|
37025
37033
|
"C:\\Windows\\Fonts\\arial.ttf",
|
|
37026
37034
|
"C:\\Windows\\Fonts\\segoeui.ttf"
|
|
@@ -37071,11 +37079,11 @@ async function applyTextOverlays(options) {
|
|
|
37071
37079
|
} = await Promise.resolve().then(() => (init_remotion(), remotion_exports));
|
|
37072
37080
|
const remotionErr = await ensureRemotionInstalled2();
|
|
37073
37081
|
if (remotionErr) {
|
|
37074
|
-
const
|
|
37082
|
+
const platform3 = process.platform;
|
|
37075
37083
|
let hint = "";
|
|
37076
|
-
if (
|
|
37084
|
+
if (platform3 === "darwin") {
|
|
37077
37085
|
hint = "\n\nFix: brew uninstall ffmpeg && brew install ffmpeg\n(The default homebrew formula includes libfreetype)";
|
|
37078
|
-
} else if (
|
|
37086
|
+
} else if (platform3 === "linux") {
|
|
37079
37087
|
hint = "\n\nFix: sudo apt install ffmpeg (Ubuntu/Debian)\n or rebuild FFmpeg with --enable-libfreetype";
|
|
37080
37088
|
}
|
|
37081
37089
|
return {
|
|
@@ -51222,6 +51230,126 @@ overlay, etc.) \u2014 useful at the tail of a pipeline.
|
|
|
51222
51230
|
}
|
|
51223
51231
|
});
|
|
51224
51232
|
|
|
51233
|
+
// src/utils/key-live-test.ts
|
|
51234
|
+
var key_live_test_exports = {};
|
|
51235
|
+
__export(key_live_test_exports, {
|
|
51236
|
+
isTestableProvider: () => isTestableProvider,
|
|
51237
|
+
testKey: () => testKey
|
|
51238
|
+
});
|
|
51239
|
+
async function getOk(url, headers, signal) {
|
|
51240
|
+
try {
|
|
51241
|
+
const res = await fetch(url, { method: "GET", headers, signal });
|
|
51242
|
+
if (res.ok) return { ok: true, status: res.status };
|
|
51243
|
+
return {
|
|
51244
|
+
ok: false,
|
|
51245
|
+
status: res.status,
|
|
51246
|
+
message: `${res.status} ${res.statusText || ""}`.trim()
|
|
51247
|
+
};
|
|
51248
|
+
} catch (err) {
|
|
51249
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
51250
|
+
return { ok: false, message: msg };
|
|
51251
|
+
}
|
|
51252
|
+
}
|
|
51253
|
+
async function testKey(configKey, key, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
51254
|
+
const tester = TESTERS[configKey];
|
|
51255
|
+
if (!tester) {
|
|
51256
|
+
return { ok: false, skipped: true, message: "no tester registered" };
|
|
51257
|
+
}
|
|
51258
|
+
const ctrl = new AbortController();
|
|
51259
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
51260
|
+
try {
|
|
51261
|
+
return await tester.test(key, ctrl.signal);
|
|
51262
|
+
} finally {
|
|
51263
|
+
clearTimeout(timer);
|
|
51264
|
+
}
|
|
51265
|
+
}
|
|
51266
|
+
function isTestableProvider(configKey) {
|
|
51267
|
+
const t = TESTERS[configKey];
|
|
51268
|
+
if (!t) return false;
|
|
51269
|
+
return true;
|
|
51270
|
+
}
|
|
51271
|
+
var DEFAULT_TIMEOUT_MS, TESTERS;
|
|
51272
|
+
var init_key_live_test = __esm({
|
|
51273
|
+
"src/utils/key-live-test.ts"() {
|
|
51274
|
+
"use strict";
|
|
51275
|
+
DEFAULT_TIMEOUT_MS = 5e3;
|
|
51276
|
+
TESTERS = {
|
|
51277
|
+
anthropic: {
|
|
51278
|
+
name: "Anthropic",
|
|
51279
|
+
test: (key, signal) => getOk(
|
|
51280
|
+
"https://api.anthropic.com/v1/models",
|
|
51281
|
+
{ "x-api-key": key, "anthropic-version": "2023-06-01" },
|
|
51282
|
+
signal
|
|
51283
|
+
)
|
|
51284
|
+
},
|
|
51285
|
+
openai: {
|
|
51286
|
+
name: "OpenAI",
|
|
51287
|
+
test: (key, signal) => getOk(
|
|
51288
|
+
"https://api.openai.com/v1/models",
|
|
51289
|
+
{ Authorization: `Bearer ${key}` },
|
|
51290
|
+
signal
|
|
51291
|
+
)
|
|
51292
|
+
},
|
|
51293
|
+
google: {
|
|
51294
|
+
name: "Google",
|
|
51295
|
+
test: (key, signal) => getOk(
|
|
51296
|
+
`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(key)}`,
|
|
51297
|
+
{},
|
|
51298
|
+
signal
|
|
51299
|
+
)
|
|
51300
|
+
},
|
|
51301
|
+
xai: {
|
|
51302
|
+
name: "xAI",
|
|
51303
|
+
test: (key, signal) => getOk(
|
|
51304
|
+
"https://api.x.ai/v1/models",
|
|
51305
|
+
{ Authorization: `Bearer ${key}` },
|
|
51306
|
+
signal
|
|
51307
|
+
)
|
|
51308
|
+
},
|
|
51309
|
+
elevenlabs: {
|
|
51310
|
+
name: "ElevenLabs",
|
|
51311
|
+
test: (key, signal) => getOk("https://api.elevenlabs.io/v1/user", { "xi-api-key": key }, signal)
|
|
51312
|
+
},
|
|
51313
|
+
replicate: {
|
|
51314
|
+
name: "Replicate",
|
|
51315
|
+
test: (key, signal) => getOk(
|
|
51316
|
+
"https://api.replicate.com/v1/account",
|
|
51317
|
+
{ Authorization: `Bearer ${key}` },
|
|
51318
|
+
signal
|
|
51319
|
+
)
|
|
51320
|
+
},
|
|
51321
|
+
openrouter: {
|
|
51322
|
+
name: "OpenRouter",
|
|
51323
|
+
test: (key, signal) => getOk(
|
|
51324
|
+
"https://openrouter.ai/api/v1/models",
|
|
51325
|
+
{ Authorization: `Bearer ${key}` },
|
|
51326
|
+
signal
|
|
51327
|
+
)
|
|
51328
|
+
},
|
|
51329
|
+
// The four below have no cheap authenticated GET — providing a tester
|
|
51330
|
+
// would either consume a paid API call (fal, Runway), require HMAC
|
|
51331
|
+
// signing per request (Kling), or burn an image upload (ImgBB). We
|
|
51332
|
+
// surface them as `skipped` so the user knows we didn't blank-check.
|
|
51333
|
+
fal: {
|
|
51334
|
+
name: "fal.ai",
|
|
51335
|
+
test: async () => ({ ok: false, skipped: true, message: "no list endpoint" })
|
|
51336
|
+
},
|
|
51337
|
+
kling: {
|
|
51338
|
+
name: "Kling",
|
|
51339
|
+
test: async () => ({ ok: false, skipped: true, message: "HMAC-signed; can't test cheaply" })
|
|
51340
|
+
},
|
|
51341
|
+
runway: {
|
|
51342
|
+
name: "Runway",
|
|
51343
|
+
test: async () => ({ ok: false, skipped: true, message: "POST-only API" })
|
|
51344
|
+
},
|
|
51345
|
+
imgbb: {
|
|
51346
|
+
name: "ImgBB",
|
|
51347
|
+
test: async () => ({ ok: false, skipped: true, message: "would consume an upload" })
|
|
51348
|
+
}
|
|
51349
|
+
};
|
|
51350
|
+
}
|
|
51351
|
+
});
|
|
51352
|
+
|
|
51225
51353
|
// src/pipeline/renderers/chrome.ts
|
|
51226
51354
|
import { existsSync as existsSync32 } from "node:fs";
|
|
51227
51355
|
import { homedir as homedir5 } from "node:os";
|
|
@@ -58996,10 +59124,10 @@ var init_ai_suggest_edit = __esm({
|
|
|
58996
59124
|
}
|
|
58997
59125
|
});
|
|
58998
59126
|
|
|
58999
|
-
// src/tools/manifest/
|
|
59000
|
-
var analyzeMediaTool, analyzeVideoTool, analyzeReviewTool, analyzeSuggestTool,
|
|
59001
|
-
var
|
|
59002
|
-
"src/tools/manifest/
|
|
59127
|
+
// src/tools/manifest/inspect.ts
|
|
59128
|
+
var analyzeMediaTool, analyzeVideoTool, analyzeReviewTool, analyzeSuggestTool, inspectTools;
|
|
59129
|
+
var init_inspect = __esm({
|
|
59130
|
+
"src/tools/manifest/inspect.ts"() {
|
|
59003
59131
|
"use strict";
|
|
59004
59132
|
init_zod();
|
|
59005
59133
|
init_define_tool();
|
|
@@ -59122,7 +59250,7 @@ var init_analyze = __esm({
|
|
|
59122
59250
|
};
|
|
59123
59251
|
}
|
|
59124
59252
|
});
|
|
59125
|
-
|
|
59253
|
+
inspectTools = [
|
|
59126
59254
|
analyzeMediaTool,
|
|
59127
59255
|
analyzeVideoTool,
|
|
59128
59256
|
analyzeReviewTool,
|
|
@@ -59458,13 +59586,13 @@ var init_generate2 = __esm({
|
|
|
59458
59586
|
}
|
|
59459
59587
|
});
|
|
59460
59588
|
|
|
59461
|
-
// src/tools/manifest/
|
|
59589
|
+
// src/tools/manifest/remix.ts
|
|
59462
59590
|
import { writeFile as writeFile43 } from "node:fs/promises";
|
|
59463
59591
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
59464
59592
|
import { join as join13 } from "node:path";
|
|
59465
|
-
var pipelineHighlightsTool, pipelineAutoShortsTool, pipelineRunTool, pipelineRegenerateSceneTool,
|
|
59466
|
-
var
|
|
59467
|
-
"src/tools/manifest/
|
|
59593
|
+
var pipelineHighlightsTool, pipelineAutoShortsTool, pipelineRunTool, pipelineRegenerateSceneTool, remixTools;
|
|
59594
|
+
var init_remix = __esm({
|
|
59595
|
+
"src/tools/manifest/remix.ts"() {
|
|
59468
59596
|
"use strict";
|
|
59469
59597
|
init_zod();
|
|
59470
59598
|
init_define_tool();
|
|
@@ -59647,7 +59775,7 @@ var init_pipeline2 = __esm({
|
|
|
59647
59775
|
};
|
|
59648
59776
|
}
|
|
59649
59777
|
});
|
|
59650
|
-
|
|
59778
|
+
remixTools = [
|
|
59651
59779
|
pipelineHighlightsTool,
|
|
59652
59780
|
pipelineAutoShortsTool,
|
|
59653
59781
|
pipelineRunTool,
|
|
@@ -60471,7 +60599,7 @@ var init_hyperframes = __esm({
|
|
|
60471
60599
|
// src/commands/export.ts
|
|
60472
60600
|
import { readFile as readFile40, access as access8 } from "node:fs/promises";
|
|
60473
60601
|
import { resolve as resolve61, basename as basename21 } from "node:path";
|
|
60474
|
-
import { spawn as
|
|
60602
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
60475
60603
|
function timelineBaseName(path2) {
|
|
60476
60604
|
const name = basename21(path2);
|
|
60477
60605
|
if (name.endsWith(".vibe.json")) return name.slice(0, -".vibe.json".length);
|
|
@@ -60945,7 +61073,7 @@ function buildFFmpegArgs(clips, sources, presetSettings, outputPath, options, so
|
|
|
60945
61073
|
}
|
|
60946
61074
|
function runFFmpegProcess(ffmpegPath, args, onProgress) {
|
|
60947
61075
|
return new Promise((resolve64, reject) => {
|
|
60948
|
-
const ffmpeg =
|
|
61076
|
+
const ffmpeg = spawn3(ffmpegPath, args, {
|
|
60949
61077
|
stdio: ["pipe", "pipe", "pipe"]
|
|
60950
61078
|
});
|
|
60951
61079
|
let duration = 0;
|
|
@@ -62278,15 +62406,15 @@ var init_walkthrough = __esm({
|
|
|
62278
62406
|
var manifest_exports = {};
|
|
62279
62407
|
__export(manifest_exports, {
|
|
62280
62408
|
agentOnlyTools: () => agentOnlyTools,
|
|
62281
|
-
analyzeTools: () => analyzeTools,
|
|
62282
62409
|
audioTools: () => audioTools,
|
|
62283
62410
|
detectTools: () => detectTools,
|
|
62284
62411
|
editTools: () => editTools,
|
|
62285
62412
|
exportTools: () => exportTools,
|
|
62286
62413
|
generateTools: () => generateTools,
|
|
62414
|
+
inspectTools: () => inspectTools,
|
|
62287
62415
|
manifest: () => manifest,
|
|
62288
|
-
pipelineTools: () => pipelineTools,
|
|
62289
62416
|
projectTools: () => projectTools,
|
|
62417
|
+
remixTools: () => remixTools,
|
|
62290
62418
|
sceneTools: () => sceneTools,
|
|
62291
62419
|
timelineTools: () => timelineTools,
|
|
62292
62420
|
walkthroughTools: () => walkthroughTools
|
|
@@ -62298,9 +62426,9 @@ var init_manifest = __esm({
|
|
|
62298
62426
|
init_scene2();
|
|
62299
62427
|
init_audio2();
|
|
62300
62428
|
init_edit();
|
|
62301
|
-
|
|
62429
|
+
init_inspect();
|
|
62302
62430
|
init_generate2();
|
|
62303
|
-
|
|
62431
|
+
init_remix();
|
|
62304
62432
|
init_detect2();
|
|
62305
62433
|
init_timeline();
|
|
62306
62434
|
init_project2();
|
|
@@ -62311,9 +62439,9 @@ var init_manifest = __esm({
|
|
|
62311
62439
|
...sceneTools,
|
|
62312
62440
|
...audioTools,
|
|
62313
62441
|
...editTools,
|
|
62314
|
-
...
|
|
62442
|
+
...inspectTools,
|
|
62315
62443
|
...generateTools,
|
|
62316
|
-
...
|
|
62444
|
+
...remixTools,
|
|
62317
62445
|
...detectTools,
|
|
62318
62446
|
...timelineTools,
|
|
62319
62447
|
...projectTools,
|
|
@@ -62523,7 +62651,7 @@ init_source();
|
|
|
62523
62651
|
// package.json
|
|
62524
62652
|
var package_default = {
|
|
62525
62653
|
name: "@vibeframe/cli",
|
|
62526
|
-
version: "0.
|
|
62654
|
+
version: "0.82.0",
|
|
62527
62655
|
description: "VibeFrame CLI - natural language video editing from the terminal",
|
|
62528
62656
|
private: false,
|
|
62529
62657
|
license: "MIT",
|
|
@@ -63678,7 +63806,7 @@ function detectMediaType(path2) {
|
|
|
63678
63806
|
init_generate();
|
|
63679
63807
|
init_edit_cmd();
|
|
63680
63808
|
|
|
63681
|
-
// src/commands/
|
|
63809
|
+
// src/commands/inspect.ts
|
|
63682
63810
|
init_esm();
|
|
63683
63811
|
init_source();
|
|
63684
63812
|
init_ora();
|
|
@@ -63693,7 +63821,7 @@ init_sanitize();
|
|
|
63693
63821
|
init_validate();
|
|
63694
63822
|
import { readFile as readFile23, writeFile as writeFile30 } from "node:fs/promises";
|
|
63695
63823
|
import { resolve as resolve33 } from "node:path";
|
|
63696
|
-
var
|
|
63824
|
+
var inspectCommand = new Command("inspect").description("Inspect media using AI (images, videos, YouTube URLs)").addHelpText(
|
|
63697
63825
|
"after",
|
|
63698
63826
|
`
|
|
63699
63827
|
Examples:
|
|
@@ -63711,7 +63839,7 @@ Use '--fields response,model' to limit output size.
|
|
|
63711
63839
|
Run 'vibe schema inspect.<command>' for structured parameter info.
|
|
63712
63840
|
`
|
|
63713
63841
|
);
|
|
63714
|
-
|
|
63842
|
+
inspectCommand.command("media").description("Analyze any media: images, videos, or YouTube URLs using Gemini").argument("<source>", "Image/video file path, image URL, or YouTube URL").argument("<prompt>", "Analysis prompt (e.g., 'Describe this image', 'Summarize this video')").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("-m, --model <model>", "Model: flash (default), flash-2.5, pro", "flash").option("--fps <number>", "Frames per second for video (default: 1)").option("--start <seconds>", "Start offset in seconds (video only)").option("--end <seconds>", "End offset in seconds (video only)").option("--low-res", "Use low resolution mode (fewer tokens)").option("--verbose", "Show token usage").option("--fields <fields>", "Comma-separated fields to include in output (e.g., response,model)").option("--dry-run", "Preview parameters without executing").action(async (source, prompt3, options) => {
|
|
63715
63843
|
const startedAt = Date.now();
|
|
63716
63844
|
try {
|
|
63717
63845
|
rejectControlChars(prompt3);
|
|
@@ -63788,7 +63916,7 @@ analyzeCommand.command("media").description("Analyze any media: images, videos,
|
|
|
63788
63916
|
exitWithError(apiError(`Analysis failed: ${error.message}`));
|
|
63789
63917
|
}
|
|
63790
63918
|
});
|
|
63791
|
-
|
|
63919
|
+
inspectCommand.command("video").description("Analyze video using Gemini (summarize, Q&A, extract info)").argument("<source>", "Video file path or YouTube URL").argument("<prompt>", "Analysis prompt (e.g., 'Summarize this video')").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("-m, --model <model>", "Model: flash (default), flash-2.5, pro", "flash").option("--fps <number>", "Frames per second (default: 1, higher for action)").option("--start <seconds>", "Start offset in seconds (for clipping)").option("--end <seconds>", "End offset in seconds (for clipping)").option("--low-res", "Use low resolution mode (fewer tokens, longer videos)").option("--verbose", "Show token usage").option("--fields <fields>", "Comma-separated fields to include in output (e.g., response,model)").option("--dry-run", "Preview parameters without executing").action(async (source, prompt3, options) => {
|
|
63792
63920
|
const startedAt = Date.now();
|
|
63793
63921
|
try {
|
|
63794
63922
|
rejectControlChars(prompt3);
|
|
@@ -63864,8 +63992,8 @@ analyzeCommand.command("video").description("Analyze video using Gemini (summari
|
|
|
63864
63992
|
exitWithError(apiError(`Video analysis failed: ${error.message}`));
|
|
63865
63993
|
}
|
|
63866
63994
|
});
|
|
63867
|
-
registerReviewCommand(
|
|
63868
|
-
|
|
63995
|
+
registerReviewCommand(inspectCommand);
|
|
63996
|
+
inspectCommand.command("suggest").description("Get AI edit suggestions using Gemini").argument("<project>", "Timeline file or directory").argument("<instruction>", "Natural language instruction").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("--apply", "Apply the first suggestion automatically").option("--dry-run", "Preview parameters without executing").action(async (projectPath, instruction, options) => {
|
|
63869
63997
|
const startedAt = Date.now();
|
|
63870
63998
|
try {
|
|
63871
63999
|
rejectControlChars(instruction);
|
|
@@ -64452,7 +64580,7 @@ audioCommand.command("duck").description("Auto-duck background music when voice
|
|
|
64452
64580
|
}
|
|
64453
64581
|
});
|
|
64454
64582
|
|
|
64455
|
-
// src/commands/
|
|
64583
|
+
// src/commands/remix.ts
|
|
64456
64584
|
init_esm();
|
|
64457
64585
|
init_source();
|
|
64458
64586
|
init_ora();
|
|
@@ -64637,11 +64765,11 @@ function registerScriptPipelineCommands(aiCommand) {
|
|
|
64637
64765
|
});
|
|
64638
64766
|
}
|
|
64639
64767
|
|
|
64640
|
-
// src/commands/
|
|
64768
|
+
// src/commands/remix.ts
|
|
64641
64769
|
init_ai_highlights();
|
|
64642
64770
|
init_ai_animated_caption();
|
|
64643
64771
|
init_output();
|
|
64644
|
-
var
|
|
64772
|
+
var remixCommand = new Command("remix").description(
|
|
64645
64773
|
"Transform existing media (highlights, auto-shorts, animated captions, regenerate-scene)"
|
|
64646
64774
|
).addHelpText(
|
|
64647
64775
|
"after",
|
|
@@ -64675,10 +64803,10 @@ Use '--dry-run' to preview parameters before execution.
|
|
|
64675
64803
|
Run 'vibe schema remix.<command>' for structured parameter info.
|
|
64676
64804
|
`
|
|
64677
64805
|
);
|
|
64678
|
-
registerScriptPipelineCommands(
|
|
64679
|
-
registerHighlightsCommands(
|
|
64806
|
+
registerScriptPipelineCommands(remixCommand);
|
|
64807
|
+
registerHighlightsCommands(remixCommand);
|
|
64680
64808
|
var ANIMATED_CAPTION_STYLES = ["highlight", "bounce", "pop-in", "neon", "karaoke-sweep", "typewriter"];
|
|
64681
|
-
|
|
64809
|
+
remixCommand.command("animated-caption").description("Add animated captions with word-by-word effects (Whisper + Remotion/ASS)").argument("<video>", "Video file path").option("--style <preset>", "Style preset (default: highlight)", "highlight").option("--highlight-color <color>", "Active word highlight color", "#FFFF00").option("--font-size <px>", "Font size (default: auto based on resolution)").option("--position <pos>", "Caption position: top, center, bottom", "bottom").option("--words-per-group <n>", "Words shown at once (default: auto 3-5)").option("--max-chars <n>", "Max characters per group").option("-l, --language <lang>", "Whisper language hint").option("--fast", "Use ASS/FFmpeg only (no Remotion, forces ASS tier styles)").option("-o, --output <path>", "Output file path").option("--dry-run", "Preview parameters without executing").addHelpText(
|
|
64682
64810
|
"after",
|
|
64683
64811
|
`
|
|
64684
64812
|
Examples:
|
|
@@ -69397,6 +69525,50 @@ function validateKeyFormat(configKey, value) {
|
|
|
69397
69525
|
return { ok: false, expected: fmt.example };
|
|
69398
69526
|
}
|
|
69399
69527
|
|
|
69528
|
+
// src/utils/clipboard.ts
|
|
69529
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
69530
|
+
import { platform as platform2 } from "node:os";
|
|
69531
|
+
function resolveCopier() {
|
|
69532
|
+
switch (platform2()) {
|
|
69533
|
+
case "darwin":
|
|
69534
|
+
return { command: "pbcopy", args: [] };
|
|
69535
|
+
case "win32":
|
|
69536
|
+
return { command: "clip", args: [] };
|
|
69537
|
+
case "linux":
|
|
69538
|
+
case "freebsd":
|
|
69539
|
+
case "openbsd":
|
|
69540
|
+
if (process.env.WAYLAND_DISPLAY) {
|
|
69541
|
+
return { command: "wl-copy", args: [] };
|
|
69542
|
+
}
|
|
69543
|
+
return { command: "xclip", args: ["-selection", "clipboard"] };
|
|
69544
|
+
default:
|
|
69545
|
+
return null;
|
|
69546
|
+
}
|
|
69547
|
+
}
|
|
69548
|
+
async function copyToClipboard(text) {
|
|
69549
|
+
const opener = resolveCopier();
|
|
69550
|
+
if (!opener) return false;
|
|
69551
|
+
return new Promise((resolve64) => {
|
|
69552
|
+
let settled = false;
|
|
69553
|
+
const finish = (ok) => {
|
|
69554
|
+
if (settled) return;
|
|
69555
|
+
settled = true;
|
|
69556
|
+
resolve64(ok);
|
|
69557
|
+
};
|
|
69558
|
+
try {
|
|
69559
|
+
const child = spawn2(opener.command, opener.args, {
|
|
69560
|
+
stdio: ["pipe", "ignore", "ignore"],
|
|
69561
|
+
shell: false
|
|
69562
|
+
});
|
|
69563
|
+
child.on("error", () => finish(false));
|
|
69564
|
+
child.on("close", (code) => finish(code === 0));
|
|
69565
|
+
child.stdin.end(text, "utf8");
|
|
69566
|
+
} catch {
|
|
69567
|
+
finish(false);
|
|
69568
|
+
}
|
|
69569
|
+
});
|
|
69570
|
+
}
|
|
69571
|
+
|
|
69400
69572
|
// src/commands/setup.ts
|
|
69401
69573
|
init_agent_host_detect();
|
|
69402
69574
|
init_dist2();
|
|
@@ -69409,13 +69581,17 @@ var VALID_LLM_PROVIDERS = [
|
|
|
69409
69581
|
"xai",
|
|
69410
69582
|
"openrouter"
|
|
69411
69583
|
];
|
|
69412
|
-
var setupCommand = new Command("setup").description("Configure VibeFrame (LLM provider, API keys)").option("--reset", "Reset configuration to defaults").option("--full", "Run full setup with all optional providers").option("--show", "Show current configuration (for debugging)").option("--claude-code", "Show Claude Code integration guide").option("-y, --yes", "Non-interactive: write config without prompting (CI / devcontainer)").option("--provider <id>", "Set the Agent LLM provider (claude | openai | gemini | xai | openrouter | ollama)").option("--import-env", "Promote API keys from .env / shell env into config.yaml").addHelpText(
|
|
69584
|
+
var setupCommand = new Command("setup").description("Configure VibeFrame (LLM provider, API keys)").option("--reset", "Reset configuration to defaults").option("--full", "Run full setup with all optional providers").option("--show", "Show current configuration (for debugging)").option("-v, --verbose", "With --show: include unset providers + Resolution order + Defaults block").option("--claude-code", "Show Claude Code integration guide").option("-y, --yes", "Non-interactive: write config without prompting (CI / devcontainer)").option("--provider <id>", "Set the Agent LLM provider (claude | openai | gemini | xai | openrouter | ollama)").option("--import-env", "Promote API keys from .env / shell env into config.yaml").option("--test", "After save, live-test each configured key (exits 7 if any FAIL)").addHelpText(
|
|
69413
69585
|
"after",
|
|
69414
69586
|
`
|
|
69415
69587
|
Non-interactive examples (no TTY required):
|
|
69416
|
-
vibe setup --yes --provider claude --import-env
|
|
69417
|
-
vibe setup --yes --import-env
|
|
69418
|
-
vibe setup --yes --provider openai
|
|
69588
|
+
vibe setup --yes --provider claude --import-env Bootstrap CI / devcontainer
|
|
69589
|
+
vibe setup --yes --import-env --test Persist .env keys + verify each one
|
|
69590
|
+
vibe setup --yes --provider openai Just switch the agent provider
|
|
69591
|
+
|
|
69592
|
+
Exit codes (non-interactive):
|
|
69593
|
+
0 success 7 --test verification failed (one or more keys returned non-2xx)
|
|
69594
|
+
2 usage error (other codes match the rest of the CLI: 4/5/6 = auth/api/network)
|
|
69419
69595
|
`
|
|
69420
69596
|
).action(async (options) => {
|
|
69421
69597
|
if (options.claudeCode) {
|
|
@@ -69423,7 +69599,7 @@ Non-interactive examples (no TTY required):
|
|
|
69423
69599
|
return;
|
|
69424
69600
|
}
|
|
69425
69601
|
if (options.show) {
|
|
69426
|
-
await showConfig();
|
|
69602
|
+
await showConfig({ verbose: Boolean(options.verbose) });
|
|
69427
69603
|
return;
|
|
69428
69604
|
}
|
|
69429
69605
|
if (options.reset) {
|
|
@@ -69437,7 +69613,8 @@ Non-interactive examples (no TTY required):
|
|
|
69437
69613
|
if (wantsNonInteractive) {
|
|
69438
69614
|
await runNonInteractiveSetup({
|
|
69439
69615
|
provider: options.provider,
|
|
69440
|
-
importEnv: Boolean(options.importEnv)
|
|
69616
|
+
importEnv: Boolean(options.importEnv),
|
|
69617
|
+
test: Boolean(options.test)
|
|
69441
69618
|
});
|
|
69442
69619
|
return;
|
|
69443
69620
|
}
|
|
@@ -69544,6 +69721,37 @@ async function runNonInteractiveSetup(opts) {
|
|
|
69544
69721
|
for (const w of warnings) {
|
|
69545
69722
|
console.error(source_default.yellow(`\u26A0 ${w}`));
|
|
69546
69723
|
}
|
|
69724
|
+
if (opts.test) {
|
|
69725
|
+
const { testKey: testKey2 } = await Promise.resolve().then(() => (init_key_live_test(), key_live_test_exports));
|
|
69726
|
+
console.log();
|
|
69727
|
+
console.log(source_default.bold("Live key tests"));
|
|
69728
|
+
let failures = 0;
|
|
69729
|
+
let tested = 0;
|
|
69730
|
+
for (const meta of getAllApiKeys()) {
|
|
69731
|
+
const value = config2.providers[meta.configKey];
|
|
69732
|
+
if (!value) continue;
|
|
69733
|
+
tested++;
|
|
69734
|
+
const result = await testKey2(meta.configKey, value);
|
|
69735
|
+
const label = meta.label.padEnd(12);
|
|
69736
|
+
if (result.skipped) {
|
|
69737
|
+
console.log(source_default.dim(` SKIP ${label} ${result.message ?? "no test available"}`));
|
|
69738
|
+
} else if (result.ok) {
|
|
69739
|
+
console.log(source_default.green(` \u2713 ${label}`) + source_default.dim(` ${result.status}`));
|
|
69740
|
+
} else {
|
|
69741
|
+
failures++;
|
|
69742
|
+
const detail = result.message ?? `status ${result.status ?? "?"}`;
|
|
69743
|
+
console.log(source_default.red(` \u2717 ${label}`) + source_default.dim(` ${detail}`));
|
|
69744
|
+
}
|
|
69745
|
+
}
|
|
69746
|
+
if (tested === 0) {
|
|
69747
|
+
console.log(source_default.dim(" (no keys configured to test)"));
|
|
69748
|
+
}
|
|
69749
|
+
if (failures > 0) {
|
|
69750
|
+
console.error();
|
|
69751
|
+
console.error(source_default.red(`Verification failed: ${failures} key${failures === 1 ? "" : "s"} returned non-2xx.`));
|
|
69752
|
+
process.exit(7);
|
|
69753
|
+
}
|
|
69754
|
+
}
|
|
69547
69755
|
}
|
|
69548
69756
|
async function runSetupWizard(fullSetup = false) {
|
|
69549
69757
|
console.log();
|
|
@@ -69574,7 +69782,7 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
69574
69782
|
console.log();
|
|
69575
69783
|
if (topIndex === 0) {
|
|
69576
69784
|
await saveConfig(config2);
|
|
69577
|
-
showComplete(config2, "vibe edit silence-cut video.mp4 -o clean.mp4");
|
|
69785
|
+
await showComplete(config2, "vibe edit silence-cut video.mp4 -o clean.mp4");
|
|
69578
69786
|
return;
|
|
69579
69787
|
}
|
|
69580
69788
|
if (topIndex === 3) {
|
|
@@ -69595,7 +69803,7 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
69595
69803
|
console.log();
|
|
69596
69804
|
await collectKeys(config2, pipelineKeys);
|
|
69597
69805
|
await saveConfig(config2);
|
|
69598
|
-
showComplete(config2, "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format");
|
|
69806
|
+
await showComplete(config2, "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format");
|
|
69599
69807
|
return;
|
|
69600
69808
|
}
|
|
69601
69809
|
console.log(source_default.dim("2. Features"));
|
|
@@ -69617,7 +69825,7 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
69617
69825
|
console.log(source_default.dim(" No features selected. You can re-run setup anytime."));
|
|
69618
69826
|
console.log();
|
|
69619
69827
|
await saveConfig(config2);
|
|
69620
|
-
showComplete(config2, "vibe --help", []);
|
|
69828
|
+
await showComplete(config2, "vibe --help", []);
|
|
69621
69829
|
return;
|
|
69622
69830
|
}
|
|
69623
69831
|
console.log(source_default.dim("3. API keys"));
|
|
@@ -69670,7 +69878,7 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
69670
69878
|
console.log();
|
|
69671
69879
|
}
|
|
69672
69880
|
await saveConfig(config2);
|
|
69673
|
-
showComplete(config2, selectedFeatures[0].tryCommand, selectedFeatures);
|
|
69881
|
+
await showComplete(config2, selectedFeatures[0].tryCommand, selectedFeatures);
|
|
69674
69882
|
}
|
|
69675
69883
|
async function collectKeys(config2, keys) {
|
|
69676
69884
|
loadEnv();
|
|
@@ -69777,14 +69985,15 @@ async function runCustomSetup(config2) {
|
|
|
69777
69985
|
}
|
|
69778
69986
|
console.log();
|
|
69779
69987
|
await saveConfig(config2);
|
|
69780
|
-
showComplete(config2, "vibe doctor");
|
|
69988
|
+
await showComplete(config2, "vibe doctor");
|
|
69781
69989
|
}
|
|
69782
|
-
function showComplete(config2, defaultTryCommand, features = []) {
|
|
69990
|
+
async function showComplete(config2, defaultTryCommand, features = []) {
|
|
69783
69991
|
console.log(source_default.dim("\u2500".repeat(40)));
|
|
69784
69992
|
console.log(source_default.green.bold("\u2713 Setup complete!"));
|
|
69785
69993
|
console.log();
|
|
69786
69994
|
console.log(source_default.dim(` Config: ${CONFIG_PATH}`));
|
|
69787
69995
|
console.log();
|
|
69996
|
+
const primaryTry = features.length > 1 ? features[0].tryCommand : defaultTryCommand;
|
|
69788
69997
|
if (features.length > 1) {
|
|
69789
69998
|
console.log(source_default.bold(" Try these:"));
|
|
69790
69999
|
for (const f of features) {
|
|
@@ -69793,6 +70002,12 @@ function showComplete(config2, defaultTryCommand, features = []) {
|
|
|
69793
70002
|
} else {
|
|
69794
70003
|
console.log(` Try: ${source_default.cyan(defaultTryCommand)}`);
|
|
69795
70004
|
}
|
|
70005
|
+
if (process.stdout.isTTY) {
|
|
70006
|
+
const copied = await copyToClipboard(primaryTry);
|
|
70007
|
+
if (copied) {
|
|
70008
|
+
console.log(source_default.dim(" \u2713 Copied to clipboard"));
|
|
70009
|
+
}
|
|
70010
|
+
}
|
|
69796
70011
|
console.log();
|
|
69797
70012
|
console.log(source_default.bold(" Next steps:"));
|
|
69798
70013
|
console.log(source_default.dim(" cd <project>; vibe init Scaffold AGENTS.md / CLAUDE.md / .env.example (project scope)"));
|
|
@@ -69802,6 +70017,7 @@ function showComplete(config2, defaultTryCommand, features = []) {
|
|
|
69802
70017
|
const tag = hostDetected && w.topic === "scene" ? source_default.cyan(" (recommended)") : "";
|
|
69803
70018
|
console.log(source_default.dim(` ${cmd}${w.summary}${tag}`));
|
|
69804
70019
|
}
|
|
70020
|
+
console.log(source_default.dim(" vibe doctor --test-keys Live-check each provider key against its API"));
|
|
69805
70021
|
console.log(source_default.dim(" vibe doctor Check system health + available commands"));
|
|
69806
70022
|
console.log(source_default.dim(" vibe schema --list Discover every command"));
|
|
69807
70023
|
console.log(source_default.dim(" vibe setup Re-run user-scope setup anytime"));
|
|
@@ -69849,7 +70065,8 @@ function maskApiKey(key) {
|
|
|
69849
70065
|
if (key.length <= 8) return "****";
|
|
69850
70066
|
return `${key.slice(0, 4)}${"*".repeat(8)}${key.slice(-4)}`;
|
|
69851
70067
|
}
|
|
69852
|
-
async function showConfig() {
|
|
70068
|
+
async function showConfig(opts = { verbose: false }) {
|
|
70069
|
+
const { verbose } = opts;
|
|
69853
70070
|
loadEnv();
|
|
69854
70071
|
const cwdEnvPath = resolve42(process.cwd(), ".env");
|
|
69855
70072
|
let hasCwdEnv = false;
|
|
@@ -69900,6 +70117,7 @@ async function showConfig() {
|
|
|
69900
70117
|
{ key: "replicate", name: "Replicate", env: "REPLICATE_API_TOKEN" },
|
|
69901
70118
|
{ key: "openrouter", name: "OpenRouter", env: "OPENROUTER_API_KEY" }
|
|
69902
70119
|
];
|
|
70120
|
+
let unsetCount = 0;
|
|
69903
70121
|
for (const p of providerKeys) {
|
|
69904
70122
|
const configValue = config2?.providers[p.key];
|
|
69905
70123
|
const dotenvValue = dotenvKeys[p.env];
|
|
@@ -69911,23 +70129,31 @@ async function showConfig() {
|
|
|
69911
70129
|
const status = source_default.green("\u2713");
|
|
69912
70130
|
console.log(` ${status} ${p.name.padEnd(12)} ${maskApiKey(value)} (${sources.join(" + ")})`);
|
|
69913
70131
|
} else {
|
|
69914
|
-
|
|
69915
|
-
|
|
70132
|
+
unsetCount++;
|
|
70133
|
+
if (verbose) {
|
|
70134
|
+
const status = source_default.dim("\u25CB");
|
|
70135
|
+
console.log(` ${status} ${p.name.padEnd(12)} ${source_default.dim("not set")}`);
|
|
70136
|
+
}
|
|
69916
70137
|
}
|
|
69917
70138
|
}
|
|
70139
|
+
if (!verbose && unsetCount > 0) {
|
|
70140
|
+
console.log(source_default.dim(` (${unsetCount} provider${unsetCount === 1 ? "" : "s"} unset \u2014 run with --verbose to list)`));
|
|
70141
|
+
}
|
|
69918
70142
|
console.log();
|
|
69919
|
-
if (
|
|
69920
|
-
|
|
69921
|
-
|
|
69922
|
-
|
|
70143
|
+
if (verbose) {
|
|
70144
|
+
if (config2) {
|
|
70145
|
+
console.log(source_default.bold("Defaults:"));
|
|
70146
|
+
console.log(` Aspect Ratio: ${config2.defaults.aspectRatio}`);
|
|
70147
|
+
console.log(` Export Quality: ${config2.defaults.exportQuality}`);
|
|
70148
|
+
console.log();
|
|
70149
|
+
}
|
|
70150
|
+
console.log(source_default.bold("Resolution order:"));
|
|
70151
|
+
console.log(source_default.dim(" 1. --api-key CLI option"));
|
|
70152
|
+
console.log(source_default.dim(` 2. ${CONFIG_PATH}`));
|
|
70153
|
+
console.log(source_default.dim(" 3. .env in current directory"));
|
|
70154
|
+
console.log(source_default.dim(" 4. Shell environment variables"));
|
|
69923
70155
|
console.log();
|
|
69924
70156
|
}
|
|
69925
|
-
console.log(source_default.bold("Resolution order:"));
|
|
69926
|
-
console.log(source_default.dim(" 1. --api-key CLI option"));
|
|
69927
|
-
console.log(source_default.dim(` 2. ${CONFIG_PATH}`));
|
|
69928
|
-
console.log(source_default.dim(" 3. .env in current directory"));
|
|
69929
|
-
console.log(source_default.dim(" 4. Shell environment variables"));
|
|
69930
|
-
console.log();
|
|
69931
70157
|
}
|
|
69932
70158
|
|
|
69933
70159
|
// src/commands/init.ts
|
|
@@ -70846,11 +71072,13 @@ var FREE_COMMANDS = [
|
|
|
70846
71072
|
"timeline (all)",
|
|
70847
71073
|
"batch import/concat"
|
|
70848
71074
|
];
|
|
70849
|
-
var doctorCommand = new Command("doctor").description("Check system health and available commands").option("--json", "Output in JSON format").addHelpText(
|
|
71075
|
+
var doctorCommand = new Command("doctor").description("Check system health and available commands").option("--json", "Output in JSON format").option("-v, --verbose", "Show full report (every provider row, scene composer block, free-command list)").option("--test-keys", "Make a lightweight authenticated request to each provider (validates configured keys; skips providers without a cheap test endpoint)").addHelpText(
|
|
70850
71076
|
"after",
|
|
70851
71077
|
`
|
|
70852
71078
|
Examples:
|
|
70853
|
-
$ vibe doctor
|
|
71079
|
+
$ vibe doctor Compact health summary (issues + Ready %)
|
|
71080
|
+
$ vibe doctor --verbose Full report \u2014 all providers, composer, free commands
|
|
71081
|
+
$ vibe doctor --test-keys Validate each configured key against its provider
|
|
70854
71082
|
$ vibe doctor --json Machine-readable output
|
|
70855
71083
|
`
|
|
70856
71084
|
).action(async (options) => {
|
|
@@ -70866,7 +71094,10 @@ Examples:
|
|
|
70866
71094
|
});
|
|
70867
71095
|
return;
|
|
70868
71096
|
}
|
|
70869
|
-
printReport(results);
|
|
71097
|
+
printReport(results, { verbose: Boolean(options.verbose) });
|
|
71098
|
+
if (options.testKeys) {
|
|
71099
|
+
await runLiveKeyTests(results);
|
|
71100
|
+
}
|
|
70870
71101
|
});
|
|
70871
71102
|
var REQUIRED_FFMPEG_FILTERS = {
|
|
70872
71103
|
drawtext: {
|
|
@@ -70920,14 +71151,14 @@ async function runDiagnostics() {
|
|
|
70920
71151
|
try {
|
|
70921
71152
|
const filtersResult = await execSafe("ffmpeg", ["-filters"]);
|
|
70922
71153
|
const filtersOutput = filtersResult.stdout;
|
|
70923
|
-
const
|
|
71154
|
+
const platform3 = process.platform;
|
|
70924
71155
|
ffmpegFilters = {};
|
|
70925
71156
|
for (const [filterName, info] of Object.entries(REQUIRED_FFMPEG_FILTERS)) {
|
|
70926
71157
|
const available = filtersOutput.includes(filterName);
|
|
70927
71158
|
ffmpegFilters[filterName] = {
|
|
70928
71159
|
available,
|
|
70929
71160
|
commands: info.commands,
|
|
70930
|
-
...!available && info.fix[
|
|
71161
|
+
...!available && info.fix[platform3] ? { fix: info.fix[platform3] } : {}
|
|
70931
71162
|
};
|
|
70932
71163
|
}
|
|
70933
71164
|
} catch {
|
|
@@ -71029,7 +71260,8 @@ async function runDiagnostics() {
|
|
|
71029
71260
|
totalCount
|
|
71030
71261
|
};
|
|
71031
71262
|
}
|
|
71032
|
-
function printReport(results) {
|
|
71263
|
+
function printReport(results, opts = { verbose: false }) {
|
|
71264
|
+
const { verbose } = opts;
|
|
71033
71265
|
console.log();
|
|
71034
71266
|
console.log(source_default.bold(" System"));
|
|
71035
71267
|
const nodeIcon = results.system.node.ok ? source_default.green("OK") : source_default.red("MISSING");
|
|
@@ -71058,10 +71290,25 @@ function printReport(results) {
|
|
|
71058
71290
|
}
|
|
71059
71291
|
}
|
|
71060
71292
|
if (results.system.optionalTools) {
|
|
71061
|
-
|
|
71062
|
-
|
|
71063
|
-
|
|
71064
|
-
|
|
71293
|
+
const tools = Object.entries(results.system.optionalTools);
|
|
71294
|
+
if (verbose) {
|
|
71295
|
+
for (const [name, info] of tools) {
|
|
71296
|
+
if (info.installed) {
|
|
71297
|
+
console.log(` ${name.padEnd(11)}${source_default.green("OK")} ${source_default.dim(info.commands.join(", "))}`);
|
|
71298
|
+
} else {
|
|
71299
|
+
console.log(
|
|
71300
|
+
` ${name.padEnd(11)}${source_default.yellow("MISSING")} ${source_default.dim(`needed by: ${info.commands.join(", ")}`)}`
|
|
71301
|
+
);
|
|
71302
|
+
console.log(` ${source_default.dim(`Install: ${info.install}`)}`);
|
|
71303
|
+
}
|
|
71304
|
+
}
|
|
71305
|
+
} else {
|
|
71306
|
+
const okNames = tools.filter(([, t]) => t.installed).map(([n]) => n);
|
|
71307
|
+
const missing2 = tools.filter(([, t]) => !t.installed);
|
|
71308
|
+
if (okNames.length > 0) {
|
|
71309
|
+
console.log(` Tools ${source_default.green("OK")} ${source_default.dim(okNames.join(", "))}`);
|
|
71310
|
+
}
|
|
71311
|
+
for (const [name, info] of missing2) {
|
|
71065
71312
|
console.log(
|
|
71066
71313
|
` ${name.padEnd(11)}${source_default.yellow("MISSING")} ${source_default.dim(`needed by: ${info.commands.join(", ")}`)}`
|
|
71067
71314
|
);
|
|
@@ -71083,29 +71330,31 @@ function printReport(results) {
|
|
|
71083
71330
|
console.log(` Project ${source_default.yellow("NOT INIT")} ${source_default.dim(`Run: vibe init (cwd: ${results.scope.project.cwd})`)}`);
|
|
71084
71331
|
}
|
|
71085
71332
|
console.log(` Agents ${source_default.dim(results.scope.agentHosts.summary)}`);
|
|
71086
|
-
|
|
71087
|
-
|
|
71088
|
-
|
|
71089
|
-
|
|
71090
|
-
|
|
71091
|
-
|
|
71092
|
-
|
|
71093
|
-
|
|
71094
|
-
|
|
71095
|
-
)
|
|
71096
|
-
|
|
71097
|
-
console.log(
|
|
71098
|
-
` Batch LLM ${source_default.yellow("--")} ${source_default.dim("no ANTHROPIC_API_KEY / GOOGLE_API_KEY / OPENAI_API_KEY \u2014 agent-mode only")}`
|
|
71099
|
-
);
|
|
71100
|
-
}
|
|
71101
|
-
if (sc.sceneProjectInCwd) {
|
|
71102
|
-
if (sc.skillInstalled) {
|
|
71103
|
-
console.log(` SKILL.md ${source_default.green("OK")} ${source_default.dim("installed in this scene project")}`);
|
|
71333
|
+
if (verbose) {
|
|
71334
|
+
console.log();
|
|
71335
|
+
console.log(source_default.bold(" Scene composer (vibe build)"));
|
|
71336
|
+
const sc = results.scope.sceneComposer;
|
|
71337
|
+
const modeBadge = sc.recommendedMode === "agent" ? source_default.cyan("agent") : source_default.dim("batch");
|
|
71338
|
+
const modeNote = sc.recommendedMode === "agent" ? source_default.dim("host agent authors HTML; no internal LLM call") : source_default.dim("CLI's internal LLM authors HTML");
|
|
71339
|
+
console.log(` Mode (auto) ${modeBadge} ${modeNote}`);
|
|
71340
|
+
if (sc.composer) {
|
|
71341
|
+
console.log(
|
|
71342
|
+
` Batch LLM ${source_default.green("OK")} ${source_default.dim(`${composerLabel(sc.composer)} (${sc.composerEnvVar})`)}`
|
|
71343
|
+
);
|
|
71104
71344
|
} else {
|
|
71105
|
-
console.log(
|
|
71345
|
+
console.log(
|
|
71346
|
+
` Batch LLM ${source_default.yellow("--")} ${source_default.dim("no ANTHROPIC_API_KEY / GOOGLE_API_KEY / OPENAI_API_KEY \u2014 agent-mode only")}`
|
|
71347
|
+
);
|
|
71348
|
+
}
|
|
71349
|
+
if (sc.sceneProjectInCwd) {
|
|
71350
|
+
if (sc.skillInstalled) {
|
|
71351
|
+
console.log(` SKILL.md ${source_default.green("OK")} ${source_default.dim("installed in this scene project")}`);
|
|
71352
|
+
} else {
|
|
71353
|
+
console.log(` SKILL.md ${source_default.yellow("MISSING")} ${source_default.dim("Run: vibe scene install-skill")}`);
|
|
71354
|
+
}
|
|
71355
|
+
} else {
|
|
71356
|
+
console.log(` SKILL.md ${source_default.dim("(no STORYBOARD.md in cwd \u2014 skill is per-scene-project)")}`);
|
|
71106
71357
|
}
|
|
71107
|
-
} else {
|
|
71108
|
-
console.log(` SKILL.md ${source_default.dim("(no STORYBOARD.md in cwd \u2014 skill is per-scene-project)")}`);
|
|
71109
71358
|
}
|
|
71110
71359
|
console.log();
|
|
71111
71360
|
console.log(source_default.bold(" API Keys"));
|
|
@@ -71122,16 +71371,24 @@ function printReport(results) {
|
|
|
71122
71371
|
}
|
|
71123
71372
|
}
|
|
71124
71373
|
if (missing.length > 0) {
|
|
71125
|
-
|
|
71126
|
-
const
|
|
71374
|
+
if (verbose) {
|
|
71375
|
+
for (const name of missing) {
|
|
71376
|
+
const info = results.providers[name];
|
|
71377
|
+
console.log(
|
|
71378
|
+
` ${source_default.red("--")} ${info.envVar.padEnd(24)} ${source_default.dim(info.commands.join(", "))}`
|
|
71379
|
+
);
|
|
71380
|
+
}
|
|
71381
|
+
} else {
|
|
71127
71382
|
console.log(
|
|
71128
|
-
` ${
|
|
71383
|
+
source_default.dim(` ${missing.length} provider${missing.length === 1 ? "" : "s"} unconfigured (${missing.slice(0, 4).join(", ")}${missing.length > 4 ? ", \u2026" : ""}). Run with --verbose to list.`)
|
|
71129
71384
|
);
|
|
71130
71385
|
}
|
|
71131
71386
|
}
|
|
71132
|
-
|
|
71133
|
-
|
|
71134
|
-
|
|
71387
|
+
if (verbose) {
|
|
71388
|
+
console.log();
|
|
71389
|
+
console.log(source_default.bold(" No API key needed"));
|
|
71390
|
+
console.log(` ${source_default.dim(FREE_COMMANDS.join(", "))}`);
|
|
71391
|
+
}
|
|
71135
71392
|
console.log();
|
|
71136
71393
|
const pct = Math.round(results.readyCount / results.totalCount * 100);
|
|
71137
71394
|
const readyColor = pct >= 80 ? source_default.green : pct >= 40 ? source_default.yellow : source_default.red;
|
|
@@ -71147,6 +71404,32 @@ function printReport(results) {
|
|
|
71147
71404
|
}
|
|
71148
71405
|
console.log();
|
|
71149
71406
|
}
|
|
71407
|
+
async function runLiveKeyTests(results) {
|
|
71408
|
+
console.log();
|
|
71409
|
+
console.log(source_default.bold(" Live key tests"));
|
|
71410
|
+
console.log(source_default.dim(" Hits each provider's cheapest authenticated endpoint with a 5s timeout."));
|
|
71411
|
+
const configured = Object.entries(results.providers).filter(([, info]) => info.configured);
|
|
71412
|
+
if (configured.length === 0) {
|
|
71413
|
+
console.log(source_default.dim(" No keys configured \u2014 nothing to test."));
|
|
71414
|
+
return;
|
|
71415
|
+
}
|
|
71416
|
+
const { testKey: testKey2 } = await Promise.resolve().then(() => (init_key_live_test(), key_live_test_exports));
|
|
71417
|
+
for (const [name, info] of configured) {
|
|
71418
|
+
const value = process.env[info.envVar];
|
|
71419
|
+
if (!value) continue;
|
|
71420
|
+
process.stdout.write(` ${name.padEnd(12)} `);
|
|
71421
|
+
const result = await testKey2(name, value);
|
|
71422
|
+
if (result.skipped) {
|
|
71423
|
+
console.log(source_default.dim(`SKIP ${result.message ?? "no test available"}`));
|
|
71424
|
+
} else if (result.ok) {
|
|
71425
|
+
console.log(`${source_default.green("OK")} ${source_default.dim(`${result.status}`)}`);
|
|
71426
|
+
} else {
|
|
71427
|
+
const detail = result.message ?? `status ${result.status ?? "?"}`;
|
|
71428
|
+
console.log(`${source_default.red("FAIL")} ${source_default.dim(detail)}`);
|
|
71429
|
+
}
|
|
71430
|
+
}
|
|
71431
|
+
console.log();
|
|
71432
|
+
}
|
|
71150
71433
|
function pickNextStep(results, hasMissingProviders) {
|
|
71151
71434
|
if (!results.scope.user.configured) {
|
|
71152
71435
|
return "Next: run 'vibe setup' to configure your user scope (API keys + LLM provider).";
|
|
@@ -72463,10 +72746,10 @@ function showFirstRunBanner() {
|
|
|
72463
72746
|
console.log(` ${source_default.white("2.")} ${source_default.green("vibe doctor")} Check system health`);
|
|
72464
72747
|
console.log(` ${source_default.white("3.")} ${source_default.green("vibe --help")} See all commands`);
|
|
72465
72748
|
console.log();
|
|
72466
|
-
console.log(source_default.dim("
|
|
72749
|
+
console.log(source_default.dim(" Try without keys:"));
|
|
72750
|
+
console.log(` ${source_default.green("vibe demo")} Run sample edits on a test video`);
|
|
72467
72751
|
console.log(source_default.dim(" vibe edit silence-cut video.mp4 -o clean.mp4"));
|
|
72468
72752
|
console.log(source_default.dim(" vibe detect scenes video.mp4"));
|
|
72469
|
-
console.log(source_default.dim(" vibe edit fade video.mp4 -o faded.mp4 --fade-in 1 --fade-out 1"));
|
|
72470
72753
|
console.log();
|
|
72471
72754
|
}
|
|
72472
72755
|
|
|
@@ -72518,48 +72801,42 @@ program2.name("vibe").showSuggestionAfterError(true).description("VibeFrame CLI
|
|
|
72518
72801
|
}).addHelpText(
|
|
72519
72802
|
"after",
|
|
72520
72803
|
`
|
|
72521
|
-
|
|
72522
|
-
|
|
72523
|
-
|
|
72524
|
-
|
|
72525
|
-
|
|
72526
|
-
|
|
72527
|
-
|
|
72528
|
-
|
|
72529
|
-
|
|
72530
|
-
|
|
72531
|
-
|
|
72532
|
-
|
|
72533
|
-
|
|
72534
|
-
|
|
72535
|
-
|
|
72536
|
-
|
|
72537
|
-
|
|
72538
|
-
|
|
72539
|
-
|
|
72540
|
-
|
|
72541
|
-
|
|
72542
|
-
|
|
72543
|
-
|
|
72544
|
-
|
|
72545
|
-
|
|
72546
|
-
|
|
72547
|
-
|
|
72548
|
-
|
|
72549
|
-
|
|
72550
|
-
|
|
72551
|
-
|
|
72552
|
-
|
|
72553
|
-
|
|
72554
|
-
|
|
72555
|
-
|
|
72556
|
-
|
|
72557
|
-
Cost tiers (per call):
|
|
72558
|
-
Free detect, edit (silence-cut/fade/noise-reduce), timeline
|
|
72559
|
-
Low inspect, audio transcribe, generate image ~$0.01-$0.10
|
|
72560
|
-
High generate video, edit image ~$1-$5
|
|
72561
|
-
V.High remix (regenerate-scene, highlights, auto-shorts) ~$5-$50+
|
|
72562
|
-
Tip Add --dry-run before paid generation to preview the work.
|
|
72804
|
+
Common workflows (the alphabetical list above is the full command set;
|
|
72805
|
+
this section shows the typical entry points by use case):
|
|
72806
|
+
|
|
72807
|
+
Get started:
|
|
72808
|
+
vibe doctor System health + key status
|
|
72809
|
+
vibe setup Configure API keys interactively
|
|
72810
|
+
vibe init my-video Scaffold a video project
|
|
72811
|
+
vibe build my-video Build STORYBOARD.md \u2192 scene assets
|
|
72812
|
+
vibe render my-video Render the project to MP4
|
|
72813
|
+
vibe demo Try VibeFrame without API keys
|
|
72814
|
+
|
|
72815
|
+
One-shot media:
|
|
72816
|
+
vibe generate image "..." Generate a still image
|
|
72817
|
+
vibe generate video "..." Generate a standalone AI video
|
|
72818
|
+
vibe edit caption clip.mp4 -o out.mp4
|
|
72819
|
+
vibe inspect media clip.mp4 "Summarize this"
|
|
72820
|
+
vibe remix highlights long.mp4 -d 60
|
|
72821
|
+
|
|
72822
|
+
Authoring:
|
|
72823
|
+
vibe timeline create my-video Low-level timeline JSON
|
|
72824
|
+
vibe scene add intro --headline "Welcome"
|
|
72825
|
+
|
|
72826
|
+
Automation & agents:
|
|
72827
|
+
vibe run workflow.yaml Video-as-YAML pipeline
|
|
72828
|
+
vibe agent Natural-language interface
|
|
72829
|
+
vibe schema generate.video JSON schema for any command
|
|
72830
|
+
vibe walkthrough scene Step-by-step authoring guide
|
|
72831
|
+
|
|
72832
|
+
Common-flag note: most commands accept --dry-run to preview cost/output
|
|
72833
|
+
before invoking paid providers.
|
|
72834
|
+
|
|
72835
|
+
Cost tiers:
|
|
72836
|
+
Free detect, edit (silence-cut/fade/noise-reduce), timeline
|
|
72837
|
+
Low inspect, audio transcribe, generate image ~$0.01\u2013$0.10
|
|
72838
|
+
High generate video, edit image ~$1\u2013$5
|
|
72839
|
+
V.High remix (regenerate-scene, highlights, auto-shorts) ~$5\u2013$50+
|
|
72563
72840
|
`
|
|
72564
72841
|
);
|
|
72565
72842
|
program2.hook("preAction", async (thisCommand, actionCommand) => {
|
|
@@ -72621,9 +72898,9 @@ program2.hook("preAction", async (thisCommand, actionCommand) => {
|
|
|
72621
72898
|
});
|
|
72622
72899
|
program2.addCommand(generateCommand);
|
|
72623
72900
|
program2.addCommand(editCommand);
|
|
72624
|
-
program2.addCommand(
|
|
72901
|
+
program2.addCommand(inspectCommand);
|
|
72625
72902
|
program2.addCommand(audioCommand);
|
|
72626
|
-
program2.addCommand(
|
|
72903
|
+
program2.addCommand(remixCommand);
|
|
72627
72904
|
program2.addCommand(setupCommand);
|
|
72628
72905
|
program2.addCommand(initCommand);
|
|
72629
72906
|
program2.addCommand(buildCommand);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeframe/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.82.0",
|
|
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.
|
|
187
|
-
"@vibeframe/core": "0.
|
|
186
|
+
"@vibeframe/ai-providers": "0.82.0",
|
|
187
|
+
"@vibeframe/core": "0.82.0"
|
|
188
188
|
},
|
|
189
189
|
"engines": {
|
|
190
190
|
"node": ">=20"
|