@vibeframe/cli 0.80.1 → 0.81.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 +396 -156
- 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 {
|
|
@@ -51991,6 +51999,126 @@ var init_scene_build = __esm({
|
|
|
51991
51999
|
}
|
|
51992
52000
|
});
|
|
51993
52001
|
|
|
52002
|
+
// src/utils/key-live-test.ts
|
|
52003
|
+
var key_live_test_exports = {};
|
|
52004
|
+
__export(key_live_test_exports, {
|
|
52005
|
+
isTestableProvider: () => isTestableProvider,
|
|
52006
|
+
testKey: () => testKey
|
|
52007
|
+
});
|
|
52008
|
+
async function getOk(url, headers, signal) {
|
|
52009
|
+
try {
|
|
52010
|
+
const res = await fetch(url, { method: "GET", headers, signal });
|
|
52011
|
+
if (res.ok) return { ok: true, status: res.status };
|
|
52012
|
+
return {
|
|
52013
|
+
ok: false,
|
|
52014
|
+
status: res.status,
|
|
52015
|
+
message: `${res.status} ${res.statusText || ""}`.trim()
|
|
52016
|
+
};
|
|
52017
|
+
} catch (err) {
|
|
52018
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
52019
|
+
return { ok: false, message: msg };
|
|
52020
|
+
}
|
|
52021
|
+
}
|
|
52022
|
+
async function testKey(configKey, key, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
52023
|
+
const tester = TESTERS[configKey];
|
|
52024
|
+
if (!tester) {
|
|
52025
|
+
return { ok: false, skipped: true, message: "no tester registered" };
|
|
52026
|
+
}
|
|
52027
|
+
const ctrl = new AbortController();
|
|
52028
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
52029
|
+
try {
|
|
52030
|
+
return await tester.test(key, ctrl.signal);
|
|
52031
|
+
} finally {
|
|
52032
|
+
clearTimeout(timer);
|
|
52033
|
+
}
|
|
52034
|
+
}
|
|
52035
|
+
function isTestableProvider(configKey) {
|
|
52036
|
+
const t = TESTERS[configKey];
|
|
52037
|
+
if (!t) return false;
|
|
52038
|
+
return true;
|
|
52039
|
+
}
|
|
52040
|
+
var DEFAULT_TIMEOUT_MS, TESTERS;
|
|
52041
|
+
var init_key_live_test = __esm({
|
|
52042
|
+
"src/utils/key-live-test.ts"() {
|
|
52043
|
+
"use strict";
|
|
52044
|
+
DEFAULT_TIMEOUT_MS = 5e3;
|
|
52045
|
+
TESTERS = {
|
|
52046
|
+
anthropic: {
|
|
52047
|
+
name: "Anthropic",
|
|
52048
|
+
test: (key, signal) => getOk(
|
|
52049
|
+
"https://api.anthropic.com/v1/models",
|
|
52050
|
+
{ "x-api-key": key, "anthropic-version": "2023-06-01" },
|
|
52051
|
+
signal
|
|
52052
|
+
)
|
|
52053
|
+
},
|
|
52054
|
+
openai: {
|
|
52055
|
+
name: "OpenAI",
|
|
52056
|
+
test: (key, signal) => getOk(
|
|
52057
|
+
"https://api.openai.com/v1/models",
|
|
52058
|
+
{ Authorization: `Bearer ${key}` },
|
|
52059
|
+
signal
|
|
52060
|
+
)
|
|
52061
|
+
},
|
|
52062
|
+
google: {
|
|
52063
|
+
name: "Google",
|
|
52064
|
+
test: (key, signal) => getOk(
|
|
52065
|
+
`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(key)}`,
|
|
52066
|
+
{},
|
|
52067
|
+
signal
|
|
52068
|
+
)
|
|
52069
|
+
},
|
|
52070
|
+
xai: {
|
|
52071
|
+
name: "xAI",
|
|
52072
|
+
test: (key, signal) => getOk(
|
|
52073
|
+
"https://api.x.ai/v1/models",
|
|
52074
|
+
{ Authorization: `Bearer ${key}` },
|
|
52075
|
+
signal
|
|
52076
|
+
)
|
|
52077
|
+
},
|
|
52078
|
+
elevenlabs: {
|
|
52079
|
+
name: "ElevenLabs",
|
|
52080
|
+
test: (key, signal) => getOk("https://api.elevenlabs.io/v1/user", { "xi-api-key": key }, signal)
|
|
52081
|
+
},
|
|
52082
|
+
replicate: {
|
|
52083
|
+
name: "Replicate",
|
|
52084
|
+
test: (key, signal) => getOk(
|
|
52085
|
+
"https://api.replicate.com/v1/account",
|
|
52086
|
+
{ Authorization: `Bearer ${key}` },
|
|
52087
|
+
signal
|
|
52088
|
+
)
|
|
52089
|
+
},
|
|
52090
|
+
openrouter: {
|
|
52091
|
+
name: "OpenRouter",
|
|
52092
|
+
test: (key, signal) => getOk(
|
|
52093
|
+
"https://openrouter.ai/api/v1/models",
|
|
52094
|
+
{ Authorization: `Bearer ${key}` },
|
|
52095
|
+
signal
|
|
52096
|
+
)
|
|
52097
|
+
},
|
|
52098
|
+
// The four below have no cheap authenticated GET — providing a tester
|
|
52099
|
+
// would either consume a paid API call (fal, Runway), require HMAC
|
|
52100
|
+
// signing per request (Kling), or burn an image upload (ImgBB). We
|
|
52101
|
+
// surface them as `skipped` so the user knows we didn't blank-check.
|
|
52102
|
+
fal: {
|
|
52103
|
+
name: "fal.ai",
|
|
52104
|
+
test: async () => ({ ok: false, skipped: true, message: "no list endpoint" })
|
|
52105
|
+
},
|
|
52106
|
+
kling: {
|
|
52107
|
+
name: "Kling",
|
|
52108
|
+
test: async () => ({ ok: false, skipped: true, message: "HMAC-signed; can't test cheaply" })
|
|
52109
|
+
},
|
|
52110
|
+
runway: {
|
|
52111
|
+
name: "Runway",
|
|
52112
|
+
test: async () => ({ ok: false, skipped: true, message: "POST-only API" })
|
|
52113
|
+
},
|
|
52114
|
+
imgbb: {
|
|
52115
|
+
name: "ImgBB",
|
|
52116
|
+
test: async () => ({ ok: false, skipped: true, message: "would consume an upload" })
|
|
52117
|
+
}
|
|
52118
|
+
};
|
|
52119
|
+
}
|
|
52120
|
+
});
|
|
52121
|
+
|
|
51994
52122
|
// src/pipeline/resolver.ts
|
|
51995
52123
|
function resolveStepParams(params, completedSteps) {
|
|
51996
52124
|
const resolved = {};
|
|
@@ -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.81.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,7 +69581,7 @@ 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").addHelpText(
|
|
69413
69585
|
"after",
|
|
69414
69586
|
`
|
|
69415
69587
|
Non-interactive examples (no TTY required):
|
|
@@ -69423,7 +69595,7 @@ Non-interactive examples (no TTY required):
|
|
|
69423
69595
|
return;
|
|
69424
69596
|
}
|
|
69425
69597
|
if (options.show) {
|
|
69426
|
-
await showConfig();
|
|
69598
|
+
await showConfig({ verbose: Boolean(options.verbose) });
|
|
69427
69599
|
return;
|
|
69428
69600
|
}
|
|
69429
69601
|
if (options.reset) {
|
|
@@ -69574,7 +69746,7 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
69574
69746
|
console.log();
|
|
69575
69747
|
if (topIndex === 0) {
|
|
69576
69748
|
await saveConfig(config2);
|
|
69577
|
-
showComplete(config2, "vibe edit silence-cut video.mp4 -o clean.mp4");
|
|
69749
|
+
await showComplete(config2, "vibe edit silence-cut video.mp4 -o clean.mp4");
|
|
69578
69750
|
return;
|
|
69579
69751
|
}
|
|
69580
69752
|
if (topIndex === 3) {
|
|
@@ -69595,7 +69767,7 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
69595
69767
|
console.log();
|
|
69596
69768
|
await collectKeys(config2, pipelineKeys);
|
|
69597
69769
|
await saveConfig(config2);
|
|
69598
|
-
showComplete(config2, "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format");
|
|
69770
|
+
await showComplete(config2, "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format");
|
|
69599
69771
|
return;
|
|
69600
69772
|
}
|
|
69601
69773
|
console.log(source_default.dim("2. Features"));
|
|
@@ -69617,7 +69789,7 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
69617
69789
|
console.log(source_default.dim(" No features selected. You can re-run setup anytime."));
|
|
69618
69790
|
console.log();
|
|
69619
69791
|
await saveConfig(config2);
|
|
69620
|
-
showComplete(config2, "vibe --help", []);
|
|
69792
|
+
await showComplete(config2, "vibe --help", []);
|
|
69621
69793
|
return;
|
|
69622
69794
|
}
|
|
69623
69795
|
console.log(source_default.dim("3. API keys"));
|
|
@@ -69670,7 +69842,7 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
69670
69842
|
console.log();
|
|
69671
69843
|
}
|
|
69672
69844
|
await saveConfig(config2);
|
|
69673
|
-
showComplete(config2, selectedFeatures[0].tryCommand, selectedFeatures);
|
|
69845
|
+
await showComplete(config2, selectedFeatures[0].tryCommand, selectedFeatures);
|
|
69674
69846
|
}
|
|
69675
69847
|
async function collectKeys(config2, keys) {
|
|
69676
69848
|
loadEnv();
|
|
@@ -69777,14 +69949,15 @@ async function runCustomSetup(config2) {
|
|
|
69777
69949
|
}
|
|
69778
69950
|
console.log();
|
|
69779
69951
|
await saveConfig(config2);
|
|
69780
|
-
showComplete(config2, "vibe doctor");
|
|
69952
|
+
await showComplete(config2, "vibe doctor");
|
|
69781
69953
|
}
|
|
69782
|
-
function showComplete(config2, defaultTryCommand, features = []) {
|
|
69954
|
+
async function showComplete(config2, defaultTryCommand, features = []) {
|
|
69783
69955
|
console.log(source_default.dim("\u2500".repeat(40)));
|
|
69784
69956
|
console.log(source_default.green.bold("\u2713 Setup complete!"));
|
|
69785
69957
|
console.log();
|
|
69786
69958
|
console.log(source_default.dim(` Config: ${CONFIG_PATH}`));
|
|
69787
69959
|
console.log();
|
|
69960
|
+
const primaryTry = features.length > 1 ? features[0].tryCommand : defaultTryCommand;
|
|
69788
69961
|
if (features.length > 1) {
|
|
69789
69962
|
console.log(source_default.bold(" Try these:"));
|
|
69790
69963
|
for (const f of features) {
|
|
@@ -69793,6 +69966,12 @@ function showComplete(config2, defaultTryCommand, features = []) {
|
|
|
69793
69966
|
} else {
|
|
69794
69967
|
console.log(` Try: ${source_default.cyan(defaultTryCommand)}`);
|
|
69795
69968
|
}
|
|
69969
|
+
if (process.stdout.isTTY) {
|
|
69970
|
+
const copied = await copyToClipboard(primaryTry);
|
|
69971
|
+
if (copied) {
|
|
69972
|
+
console.log(source_default.dim(" \u2713 Copied to clipboard"));
|
|
69973
|
+
}
|
|
69974
|
+
}
|
|
69796
69975
|
console.log();
|
|
69797
69976
|
console.log(source_default.bold(" Next steps:"));
|
|
69798
69977
|
console.log(source_default.dim(" cd <project>; vibe init Scaffold AGENTS.md / CLAUDE.md / .env.example (project scope)"));
|
|
@@ -69849,7 +70028,8 @@ function maskApiKey(key) {
|
|
|
69849
70028
|
if (key.length <= 8) return "****";
|
|
69850
70029
|
return `${key.slice(0, 4)}${"*".repeat(8)}${key.slice(-4)}`;
|
|
69851
70030
|
}
|
|
69852
|
-
async function showConfig() {
|
|
70031
|
+
async function showConfig(opts = { verbose: false }) {
|
|
70032
|
+
const { verbose } = opts;
|
|
69853
70033
|
loadEnv();
|
|
69854
70034
|
const cwdEnvPath = resolve42(process.cwd(), ".env");
|
|
69855
70035
|
let hasCwdEnv = false;
|
|
@@ -69900,6 +70080,7 @@ async function showConfig() {
|
|
|
69900
70080
|
{ key: "replicate", name: "Replicate", env: "REPLICATE_API_TOKEN" },
|
|
69901
70081
|
{ key: "openrouter", name: "OpenRouter", env: "OPENROUTER_API_KEY" }
|
|
69902
70082
|
];
|
|
70083
|
+
let unsetCount = 0;
|
|
69903
70084
|
for (const p of providerKeys) {
|
|
69904
70085
|
const configValue = config2?.providers[p.key];
|
|
69905
70086
|
const dotenvValue = dotenvKeys[p.env];
|
|
@@ -69911,23 +70092,31 @@ async function showConfig() {
|
|
|
69911
70092
|
const status = source_default.green("\u2713");
|
|
69912
70093
|
console.log(` ${status} ${p.name.padEnd(12)} ${maskApiKey(value)} (${sources.join(" + ")})`);
|
|
69913
70094
|
} else {
|
|
69914
|
-
|
|
69915
|
-
|
|
70095
|
+
unsetCount++;
|
|
70096
|
+
if (verbose) {
|
|
70097
|
+
const status = source_default.dim("\u25CB");
|
|
70098
|
+
console.log(` ${status} ${p.name.padEnd(12)} ${source_default.dim("not set")}`);
|
|
70099
|
+
}
|
|
69916
70100
|
}
|
|
69917
70101
|
}
|
|
70102
|
+
if (!verbose && unsetCount > 0) {
|
|
70103
|
+
console.log(source_default.dim(` (${unsetCount} provider${unsetCount === 1 ? "" : "s"} unset \u2014 run with --verbose to list)`));
|
|
70104
|
+
}
|
|
69918
70105
|
console.log();
|
|
69919
|
-
if (
|
|
69920
|
-
|
|
69921
|
-
|
|
69922
|
-
|
|
70106
|
+
if (verbose) {
|
|
70107
|
+
if (config2) {
|
|
70108
|
+
console.log(source_default.bold("Defaults:"));
|
|
70109
|
+
console.log(` Aspect Ratio: ${config2.defaults.aspectRatio}`);
|
|
70110
|
+
console.log(` Export Quality: ${config2.defaults.exportQuality}`);
|
|
70111
|
+
console.log();
|
|
70112
|
+
}
|
|
70113
|
+
console.log(source_default.bold("Resolution order:"));
|
|
70114
|
+
console.log(source_default.dim(" 1. --api-key CLI option"));
|
|
70115
|
+
console.log(source_default.dim(` 2. ${CONFIG_PATH}`));
|
|
70116
|
+
console.log(source_default.dim(" 3. .env in current directory"));
|
|
70117
|
+
console.log(source_default.dim(" 4. Shell environment variables"));
|
|
69923
70118
|
console.log();
|
|
69924
70119
|
}
|
|
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
70120
|
}
|
|
69932
70121
|
|
|
69933
70122
|
// src/commands/init.ts
|
|
@@ -70846,11 +71035,13 @@ var FREE_COMMANDS = [
|
|
|
70846
71035
|
"timeline (all)",
|
|
70847
71036
|
"batch import/concat"
|
|
70848
71037
|
];
|
|
70849
|
-
var doctorCommand = new Command("doctor").description("Check system health and available commands").option("--json", "Output in JSON format").addHelpText(
|
|
71038
|
+
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
71039
|
"after",
|
|
70851
71040
|
`
|
|
70852
71041
|
Examples:
|
|
70853
|
-
$ vibe doctor
|
|
71042
|
+
$ vibe doctor Compact health summary (issues + Ready %)
|
|
71043
|
+
$ vibe doctor --verbose Full report \u2014 all providers, composer, free commands
|
|
71044
|
+
$ vibe doctor --test-keys Validate each configured key against its provider
|
|
70854
71045
|
$ vibe doctor --json Machine-readable output
|
|
70855
71046
|
`
|
|
70856
71047
|
).action(async (options) => {
|
|
@@ -70866,7 +71057,10 @@ Examples:
|
|
|
70866
71057
|
});
|
|
70867
71058
|
return;
|
|
70868
71059
|
}
|
|
70869
|
-
printReport(results);
|
|
71060
|
+
printReport(results, { verbose: Boolean(options.verbose) });
|
|
71061
|
+
if (options.testKeys) {
|
|
71062
|
+
await runLiveKeyTests(results);
|
|
71063
|
+
}
|
|
70870
71064
|
});
|
|
70871
71065
|
var REQUIRED_FFMPEG_FILTERS = {
|
|
70872
71066
|
drawtext: {
|
|
@@ -70920,14 +71114,14 @@ async function runDiagnostics() {
|
|
|
70920
71114
|
try {
|
|
70921
71115
|
const filtersResult = await execSafe("ffmpeg", ["-filters"]);
|
|
70922
71116
|
const filtersOutput = filtersResult.stdout;
|
|
70923
|
-
const
|
|
71117
|
+
const platform3 = process.platform;
|
|
70924
71118
|
ffmpegFilters = {};
|
|
70925
71119
|
for (const [filterName, info] of Object.entries(REQUIRED_FFMPEG_FILTERS)) {
|
|
70926
71120
|
const available = filtersOutput.includes(filterName);
|
|
70927
71121
|
ffmpegFilters[filterName] = {
|
|
70928
71122
|
available,
|
|
70929
71123
|
commands: info.commands,
|
|
70930
|
-
...!available && info.fix[
|
|
71124
|
+
...!available && info.fix[platform3] ? { fix: info.fix[platform3] } : {}
|
|
70931
71125
|
};
|
|
70932
71126
|
}
|
|
70933
71127
|
} catch {
|
|
@@ -71029,7 +71223,8 @@ async function runDiagnostics() {
|
|
|
71029
71223
|
totalCount
|
|
71030
71224
|
};
|
|
71031
71225
|
}
|
|
71032
|
-
function printReport(results) {
|
|
71226
|
+
function printReport(results, opts = { verbose: false }) {
|
|
71227
|
+
const { verbose } = opts;
|
|
71033
71228
|
console.log();
|
|
71034
71229
|
console.log(source_default.bold(" System"));
|
|
71035
71230
|
const nodeIcon = results.system.node.ok ? source_default.green("OK") : source_default.red("MISSING");
|
|
@@ -71058,10 +71253,25 @@ function printReport(results) {
|
|
|
71058
71253
|
}
|
|
71059
71254
|
}
|
|
71060
71255
|
if (results.system.optionalTools) {
|
|
71061
|
-
|
|
71062
|
-
|
|
71063
|
-
|
|
71064
|
-
|
|
71256
|
+
const tools = Object.entries(results.system.optionalTools);
|
|
71257
|
+
if (verbose) {
|
|
71258
|
+
for (const [name, info] of tools) {
|
|
71259
|
+
if (info.installed) {
|
|
71260
|
+
console.log(` ${name.padEnd(11)}${source_default.green("OK")} ${source_default.dim(info.commands.join(", "))}`);
|
|
71261
|
+
} else {
|
|
71262
|
+
console.log(
|
|
71263
|
+
` ${name.padEnd(11)}${source_default.yellow("MISSING")} ${source_default.dim(`needed by: ${info.commands.join(", ")}`)}`
|
|
71264
|
+
);
|
|
71265
|
+
console.log(` ${source_default.dim(`Install: ${info.install}`)}`);
|
|
71266
|
+
}
|
|
71267
|
+
}
|
|
71268
|
+
} else {
|
|
71269
|
+
const okNames = tools.filter(([, t]) => t.installed).map(([n]) => n);
|
|
71270
|
+
const missing2 = tools.filter(([, t]) => !t.installed);
|
|
71271
|
+
if (okNames.length > 0) {
|
|
71272
|
+
console.log(` Tools ${source_default.green("OK")} ${source_default.dim(okNames.join(", "))}`);
|
|
71273
|
+
}
|
|
71274
|
+
for (const [name, info] of missing2) {
|
|
71065
71275
|
console.log(
|
|
71066
71276
|
` ${name.padEnd(11)}${source_default.yellow("MISSING")} ${source_default.dim(`needed by: ${info.commands.join(", ")}`)}`
|
|
71067
71277
|
);
|
|
@@ -71083,29 +71293,31 @@ function printReport(results) {
|
|
|
71083
71293
|
console.log(` Project ${source_default.yellow("NOT INIT")} ${source_default.dim(`Run: vibe init (cwd: ${results.scope.project.cwd})`)}`);
|
|
71084
71294
|
}
|
|
71085
71295
|
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")}`);
|
|
71296
|
+
if (verbose) {
|
|
71297
|
+
console.log();
|
|
71298
|
+
console.log(source_default.bold(" Scene composer (vibe build)"));
|
|
71299
|
+
const sc = results.scope.sceneComposer;
|
|
71300
|
+
const modeBadge = sc.recommendedMode === "agent" ? source_default.cyan("agent") : source_default.dim("batch");
|
|
71301
|
+
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");
|
|
71302
|
+
console.log(` Mode (auto) ${modeBadge} ${modeNote}`);
|
|
71303
|
+
if (sc.composer) {
|
|
71304
|
+
console.log(
|
|
71305
|
+
` Batch LLM ${source_default.green("OK")} ${source_default.dim(`${composerLabel(sc.composer)} (${sc.composerEnvVar})`)}`
|
|
71306
|
+
);
|
|
71104
71307
|
} else {
|
|
71105
|
-
console.log(
|
|
71308
|
+
console.log(
|
|
71309
|
+
` Batch LLM ${source_default.yellow("--")} ${source_default.dim("no ANTHROPIC_API_KEY / GOOGLE_API_KEY / OPENAI_API_KEY \u2014 agent-mode only")}`
|
|
71310
|
+
);
|
|
71311
|
+
}
|
|
71312
|
+
if (sc.sceneProjectInCwd) {
|
|
71313
|
+
if (sc.skillInstalled) {
|
|
71314
|
+
console.log(` SKILL.md ${source_default.green("OK")} ${source_default.dim("installed in this scene project")}`);
|
|
71315
|
+
} else {
|
|
71316
|
+
console.log(` SKILL.md ${source_default.yellow("MISSING")} ${source_default.dim("Run: vibe scene install-skill")}`);
|
|
71317
|
+
}
|
|
71318
|
+
} else {
|
|
71319
|
+
console.log(` SKILL.md ${source_default.dim("(no STORYBOARD.md in cwd \u2014 skill is per-scene-project)")}`);
|
|
71106
71320
|
}
|
|
71107
|
-
} else {
|
|
71108
|
-
console.log(` SKILL.md ${source_default.dim("(no STORYBOARD.md in cwd \u2014 skill is per-scene-project)")}`);
|
|
71109
71321
|
}
|
|
71110
71322
|
console.log();
|
|
71111
71323
|
console.log(source_default.bold(" API Keys"));
|
|
@@ -71122,16 +71334,24 @@ function printReport(results) {
|
|
|
71122
71334
|
}
|
|
71123
71335
|
}
|
|
71124
71336
|
if (missing.length > 0) {
|
|
71125
|
-
|
|
71126
|
-
const
|
|
71337
|
+
if (verbose) {
|
|
71338
|
+
for (const name of missing) {
|
|
71339
|
+
const info = results.providers[name];
|
|
71340
|
+
console.log(
|
|
71341
|
+
` ${source_default.red("--")} ${info.envVar.padEnd(24)} ${source_default.dim(info.commands.join(", "))}`
|
|
71342
|
+
);
|
|
71343
|
+
}
|
|
71344
|
+
} else {
|
|
71127
71345
|
console.log(
|
|
71128
|
-
` ${
|
|
71346
|
+
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
71347
|
);
|
|
71130
71348
|
}
|
|
71131
71349
|
}
|
|
71132
|
-
|
|
71133
|
-
|
|
71134
|
-
|
|
71350
|
+
if (verbose) {
|
|
71351
|
+
console.log();
|
|
71352
|
+
console.log(source_default.bold(" No API key needed"));
|
|
71353
|
+
console.log(` ${source_default.dim(FREE_COMMANDS.join(", "))}`);
|
|
71354
|
+
}
|
|
71135
71355
|
console.log();
|
|
71136
71356
|
const pct = Math.round(results.readyCount / results.totalCount * 100);
|
|
71137
71357
|
const readyColor = pct >= 80 ? source_default.green : pct >= 40 ? source_default.yellow : source_default.red;
|
|
@@ -71147,6 +71367,32 @@ function printReport(results) {
|
|
|
71147
71367
|
}
|
|
71148
71368
|
console.log();
|
|
71149
71369
|
}
|
|
71370
|
+
async function runLiveKeyTests(results) {
|
|
71371
|
+
console.log();
|
|
71372
|
+
console.log(source_default.bold(" Live key tests"));
|
|
71373
|
+
console.log(source_default.dim(" Hits each provider's cheapest authenticated endpoint with a 5s timeout."));
|
|
71374
|
+
const configured = Object.entries(results.providers).filter(([, info]) => info.configured);
|
|
71375
|
+
if (configured.length === 0) {
|
|
71376
|
+
console.log(source_default.dim(" No keys configured \u2014 nothing to test."));
|
|
71377
|
+
return;
|
|
71378
|
+
}
|
|
71379
|
+
const { testKey: testKey2 } = await Promise.resolve().then(() => (init_key_live_test(), key_live_test_exports));
|
|
71380
|
+
for (const [name, info] of configured) {
|
|
71381
|
+
const value = process.env[info.envVar];
|
|
71382
|
+
if (!value) continue;
|
|
71383
|
+
process.stdout.write(` ${name.padEnd(12)} `);
|
|
71384
|
+
const result = await testKey2(name, value);
|
|
71385
|
+
if (result.skipped) {
|
|
71386
|
+
console.log(source_default.dim(`SKIP ${result.message ?? "no test available"}`));
|
|
71387
|
+
} else if (result.ok) {
|
|
71388
|
+
console.log(`${source_default.green("OK")} ${source_default.dim(`${result.status}`)}`);
|
|
71389
|
+
} else {
|
|
71390
|
+
const detail = result.message ?? `status ${result.status ?? "?"}`;
|
|
71391
|
+
console.log(`${source_default.red("FAIL")} ${source_default.dim(detail)}`);
|
|
71392
|
+
}
|
|
71393
|
+
}
|
|
71394
|
+
console.log();
|
|
71395
|
+
}
|
|
71150
71396
|
function pickNextStep(results, hasMissingProviders) {
|
|
71151
71397
|
if (!results.scope.user.configured) {
|
|
71152
71398
|
return "Next: run 'vibe setup' to configure your user scope (API keys + LLM provider).";
|
|
@@ -72518,48 +72764,42 @@ program2.name("vibe").showSuggestionAfterError(true).description("VibeFrame CLI
|
|
|
72518
72764
|
}).addHelpText(
|
|
72519
72765
|
"after",
|
|
72520
72766
|
`
|
|
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.
|
|
72767
|
+
Common workflows (the alphabetical list above is the full command set;
|
|
72768
|
+
this section shows the typical entry points by use case):
|
|
72769
|
+
|
|
72770
|
+
Get started:
|
|
72771
|
+
vibe doctor System health + key status
|
|
72772
|
+
vibe setup Configure API keys interactively
|
|
72773
|
+
vibe init my-video Scaffold a video project
|
|
72774
|
+
vibe build my-video Build STORYBOARD.md \u2192 scene assets
|
|
72775
|
+
vibe render my-video Render the project to MP4
|
|
72776
|
+
vibe demo Try VibeFrame without API keys
|
|
72777
|
+
|
|
72778
|
+
One-shot media:
|
|
72779
|
+
vibe generate image "..." Generate a still image
|
|
72780
|
+
vibe generate video "..." Generate a standalone AI video
|
|
72781
|
+
vibe edit caption clip.mp4 -o out.mp4
|
|
72782
|
+
vibe inspect media clip.mp4 "Summarize this"
|
|
72783
|
+
vibe remix highlights long.mp4 -d 60
|
|
72784
|
+
|
|
72785
|
+
Authoring:
|
|
72786
|
+
vibe timeline create my-video Low-level timeline JSON
|
|
72787
|
+
vibe scene add intro --headline "Welcome"
|
|
72788
|
+
|
|
72789
|
+
Automation & agents:
|
|
72790
|
+
vibe run workflow.yaml Video-as-YAML pipeline
|
|
72791
|
+
vibe agent Natural-language interface
|
|
72792
|
+
vibe schema generate.video JSON schema for any command
|
|
72793
|
+
vibe walkthrough scene Step-by-step authoring guide
|
|
72794
|
+
|
|
72795
|
+
Common-flag note: most commands accept --dry-run to preview cost/output
|
|
72796
|
+
before invoking paid providers.
|
|
72797
|
+
|
|
72798
|
+
Cost tiers:
|
|
72799
|
+
Free detect, edit (silence-cut/fade/noise-reduce), timeline
|
|
72800
|
+
Low inspect, audio transcribe, generate image ~$0.01\u2013$0.10
|
|
72801
|
+
High generate video, edit image ~$1\u2013$5
|
|
72802
|
+
V.High remix (regenerate-scene, highlights, auto-shorts) ~$5\u2013$50+
|
|
72563
72803
|
`
|
|
72564
72804
|
);
|
|
72565
72805
|
program2.hook("preAction", async (thisCommand, actionCommand) => {
|
|
@@ -72621,9 +72861,9 @@ program2.hook("preAction", async (thisCommand, actionCommand) => {
|
|
|
72621
72861
|
});
|
|
72622
72862
|
program2.addCommand(generateCommand);
|
|
72623
72863
|
program2.addCommand(editCommand);
|
|
72624
|
-
program2.addCommand(
|
|
72864
|
+
program2.addCommand(inspectCommand);
|
|
72625
72865
|
program2.addCommand(audioCommand);
|
|
72626
|
-
program2.addCommand(
|
|
72866
|
+
program2.addCommand(remixCommand);
|
|
72627
72867
|
program2.addCommand(setupCommand);
|
|
72628
72868
|
program2.addCommand(initCommand);
|
|
72629
72869
|
program2.addCommand(buildCommand);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeframe/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.81.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.81.0",
|
|
187
|
+
"@vibeframe/core": "0.81.0"
|
|
188
188
|
},
|
|
189
189
|
"engines": {
|
|
190
190
|
"node": ">=20"
|