@vibeframe/cli 0.80.0 → 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 +834 -479
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -14298,7 +14298,8 @@ function getSetupProviders() {
|
|
|
14298
14298
|
key: k.configKey,
|
|
14299
14299
|
name: k.label,
|
|
14300
14300
|
env: k.envVar,
|
|
14301
|
-
desc: k.setupDescription ?? ""
|
|
14301
|
+
desc: k.setupDescription ?? "",
|
|
14302
|
+
url: k.envExampleUrl
|
|
14302
14303
|
}));
|
|
14303
14304
|
}
|
|
14304
14305
|
function getAllApiKeys() {
|
|
@@ -14371,7 +14372,11 @@ var init_api_keys = __esm({
|
|
|
14371
14372
|
showInSetup: true,
|
|
14372
14373
|
setupDescription: "Seedance 2.0 video gen ($$, default since v0.57)",
|
|
14373
14374
|
envExampleComment: "fal.ai API Key (Seedance 2.0 video \u2014 default text/image-to-video since v0.57, Artificial Analysis ELO #2)",
|
|
14374
|
-
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>" }
|
|
14375
14380
|
});
|
|
14376
14381
|
defineApiKey({
|
|
14377
14382
|
configKey: "xai",
|
|
@@ -14432,6 +14437,10 @@ var init_api_keys = __esm({
|
|
|
14432
14437
|
// not prompted in setup wizard — internal upload host
|
|
14433
14438
|
envExampleComment: "ImgBB API Key (image hosting \u2014 used by Kling and Seedance for image-to-video uploads)",
|
|
14434
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" },
|
|
14435
14444
|
// ImgBB has no provider class (envvar-only); doctor still shows what it
|
|
14436
14445
|
// unlocks at the apiKey level.
|
|
14437
14446
|
commandsUnlocked: [
|
|
@@ -17263,18 +17272,18 @@ ${transcriptWithTimestamps}`
|
|
|
17263
17272
|
return emptyViralAnalysis("Analysis failed");
|
|
17264
17273
|
}
|
|
17265
17274
|
}
|
|
17266
|
-
async function suggestPlatformCuts(api, transcriptSegments, viralAnalysis,
|
|
17267
|
-
const emptyResult = { platform:
|
|
17275
|
+
async function suggestPlatformCuts(api, transcriptSegments, viralAnalysis, platform3, clips) {
|
|
17276
|
+
const emptyResult = { platform: platform3.id, segments: [], totalDuration: 0 };
|
|
17268
17277
|
const transcriptWithTimestamps = transcriptSegments.map((seg) => `[${seg.startTime.toFixed(1)}s - ${seg.endTime.toFixed(1)}s] ${seg.text}`).join("\n");
|
|
17269
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");
|
|
17270
|
-
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}.
|
|
17271
17280
|
|
|
17272
17281
|
Platform requirements:
|
|
17273
|
-
- Aspect ratio: ${
|
|
17274
|
-
- Maximum duration: ${
|
|
17275
|
-
- Ideal duration: ${
|
|
17276
|
-
- Needs strong hook: ${
|
|
17277
|
-
- 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"}
|
|
17278
17287
|
|
|
17279
17288
|
Previous analysis found:
|
|
17280
17289
|
- Hook strength: ${viralAnalysis.hookStrength}%
|
|
@@ -17290,7 +17299,7 @@ Your task:
|
|
|
17290
17299
|
|
|
17291
17300
|
Respond with JSON only:
|
|
17292
17301
|
{
|
|
17293
|
-
"platform": "${
|
|
17302
|
+
"platform": "${platform3.id}",
|
|
17294
17303
|
"segments": [
|
|
17295
17304
|
{"sourceClipId": "clip-id", "startTime": 0, "endTime": 45.5, "priority": 1.0}
|
|
17296
17305
|
],
|
|
@@ -17301,7 +17310,7 @@ Respond with JSON only:
|
|
|
17301
17310
|
system: systemPrompt,
|
|
17302
17311
|
messages: [{
|
|
17303
17312
|
role: "user",
|
|
17304
|
-
content: `Optimize this video for ${
|
|
17313
|
+
content: `Optimize this video for ${platform3.name}:
|
|
17305
17314
|
|
|
17306
17315
|
## Transcript:
|
|
17307
17316
|
${transcriptWithTimestamps}
|
|
@@ -17997,10 +18006,10 @@ Instruction: ${instruction}`
|
|
|
17997
18006
|
}
|
|
17998
18007
|
return analyzeViralPotential(this.api, transcriptSegments, projectMeta, targetPlatforms);
|
|
17999
18008
|
}
|
|
18000
|
-
async suggestPlatformCuts(transcriptSegments, viralAnalysis,
|
|
18009
|
+
async suggestPlatformCuts(transcriptSegments, viralAnalysis, platform3, clips) {
|
|
18001
18010
|
if (!this.api)
|
|
18002
|
-
return { platform:
|
|
18003
|
-
return suggestPlatformCuts(this.api, transcriptSegments, viralAnalysis,
|
|
18011
|
+
return { platform: platform3.id, segments: [], totalDuration: 0 };
|
|
18012
|
+
return suggestPlatformCuts(this.api, transcriptSegments, viralAnalysis, platform3, clips);
|
|
18004
18013
|
}
|
|
18005
18014
|
async generateViralCaptions(transcriptSegments, style) {
|
|
18006
18015
|
if (!this.api)
|
|
@@ -31526,6 +31535,44 @@ var init_storyboard = __esm({
|
|
|
31526
31535
|
}
|
|
31527
31536
|
});
|
|
31528
31537
|
|
|
31538
|
+
// src/utils/open-url.ts
|
|
31539
|
+
import { spawn } from "node:child_process";
|
|
31540
|
+
import { platform } from "node:os";
|
|
31541
|
+
async function openUrl(url) {
|
|
31542
|
+
const { command, args } = resolveOpener(url);
|
|
31543
|
+
if (!command) return;
|
|
31544
|
+
try {
|
|
31545
|
+
const child = spawn(command, args, {
|
|
31546
|
+
detached: true,
|
|
31547
|
+
stdio: "ignore",
|
|
31548
|
+
shell: false
|
|
31549
|
+
});
|
|
31550
|
+
child.on("error", () => {
|
|
31551
|
+
});
|
|
31552
|
+
child.unref();
|
|
31553
|
+
} catch {
|
|
31554
|
+
}
|
|
31555
|
+
}
|
|
31556
|
+
function resolveOpener(url) {
|
|
31557
|
+
switch (platform()) {
|
|
31558
|
+
case "darwin":
|
|
31559
|
+
return { command: "open", args: [url] };
|
|
31560
|
+
case "win32":
|
|
31561
|
+
return { command: "cmd", args: ["/c", "start", "", url] };
|
|
31562
|
+
case "linux":
|
|
31563
|
+
case "freebsd":
|
|
31564
|
+
case "openbsd":
|
|
31565
|
+
return { command: "xdg-open", args: [url] };
|
|
31566
|
+
default:
|
|
31567
|
+
return { command: null, args: [] };
|
|
31568
|
+
}
|
|
31569
|
+
}
|
|
31570
|
+
var init_open_url = __esm({
|
|
31571
|
+
"src/utils/open-url.ts"() {
|
|
31572
|
+
"use strict";
|
|
31573
|
+
}
|
|
31574
|
+
});
|
|
31575
|
+
|
|
31529
31576
|
// src/utils/tty.ts
|
|
31530
31577
|
import { createInterface as createInterface2 } from "node:readline";
|
|
31531
31578
|
import { ReadStream } from "node:tty";
|
|
@@ -31579,7 +31626,7 @@ async function prompt2(question) {
|
|
|
31579
31626
|
});
|
|
31580
31627
|
});
|
|
31581
31628
|
}
|
|
31582
|
-
async function promptHidden(question) {
|
|
31629
|
+
async function promptHidden(question, opts = {}) {
|
|
31583
31630
|
const input = getTTYInputStream();
|
|
31584
31631
|
return new Promise((resolve64) => {
|
|
31585
31632
|
process.stdout.write(question);
|
|
@@ -31598,6 +31645,8 @@ async function promptHidden(question) {
|
|
|
31598
31645
|
input.setRawMode(false);
|
|
31599
31646
|
process.stdout.write("\n");
|
|
31600
31647
|
process.exit(1);
|
|
31648
|
+
} else if (opts.openHotkeyUrl && value.length === 0 && (char === "o" || char === "O")) {
|
|
31649
|
+
void openUrl(opts.openHotkeyUrl);
|
|
31601
31650
|
} else if (char === "\x7F" || char === "\b") {
|
|
31602
31651
|
if (value.length > 0) {
|
|
31603
31652
|
value = value.slice(0, -1);
|
|
@@ -31681,6 +31730,59 @@ async function promptSelect(_question, options, defaultIndex = 0) {
|
|
|
31681
31730
|
return index;
|
|
31682
31731
|
}
|
|
31683
31732
|
async function promptConfirm(question, defaultYes = true) {
|
|
31733
|
+
const input = getTTYInputStream();
|
|
31734
|
+
if (typeof input.setRawMode === "function") {
|
|
31735
|
+
return new Promise((resolve64) => {
|
|
31736
|
+
const options = ["Yes", "No"];
|
|
31737
|
+
let selected = defaultYes ? 0 : 1;
|
|
31738
|
+
let renderCount = 0;
|
|
31739
|
+
process.stdout.write(`${question}
|
|
31740
|
+
`);
|
|
31741
|
+
const render = () => {
|
|
31742
|
+
if (renderCount > 0) {
|
|
31743
|
+
process.stdout.write(`\x1B[${options.length}A`);
|
|
31744
|
+
}
|
|
31745
|
+
for (let i = 0; i < options.length; i++) {
|
|
31746
|
+
const marker = i === selected ? "\x1B[36m\u276F\x1B[0m" : " ";
|
|
31747
|
+
const text = i === selected ? `\x1B[1m${options[i]}\x1B[0m` : options[i];
|
|
31748
|
+
process.stdout.write(`\x1B[2K ${marker} ${text}
|
|
31749
|
+
`);
|
|
31750
|
+
}
|
|
31751
|
+
renderCount++;
|
|
31752
|
+
};
|
|
31753
|
+
render();
|
|
31754
|
+
input.setRawMode(true);
|
|
31755
|
+
input.resume();
|
|
31756
|
+
input.setEncoding("utf8");
|
|
31757
|
+
const onData = (char) => {
|
|
31758
|
+
if (char === "\r" || char === "\n") {
|
|
31759
|
+
input.setRawMode(false);
|
|
31760
|
+
input.removeListener("data", onData);
|
|
31761
|
+
resolve64(selected === 0);
|
|
31762
|
+
} else if (char === "") {
|
|
31763
|
+
input.setRawMode(false);
|
|
31764
|
+
process.stdout.write("\n");
|
|
31765
|
+
process.exit(1);
|
|
31766
|
+
} else if (char === "\x1B[A" || char === "\x1B[B" || char === "k" || char === "j") {
|
|
31767
|
+
selected = selected === 0 ? 1 : 0;
|
|
31768
|
+
render();
|
|
31769
|
+
} else if (char === "y" || char === "Y") {
|
|
31770
|
+
selected = 0;
|
|
31771
|
+
input.setRawMode(false);
|
|
31772
|
+
input.removeListener("data", onData);
|
|
31773
|
+
render();
|
|
31774
|
+
resolve64(true);
|
|
31775
|
+
} else if (char === "n" || char === "N") {
|
|
31776
|
+
selected = 1;
|
|
31777
|
+
input.setRawMode(false);
|
|
31778
|
+
input.removeListener("data", onData);
|
|
31779
|
+
render();
|
|
31780
|
+
resolve64(false);
|
|
31781
|
+
}
|
|
31782
|
+
};
|
|
31783
|
+
input.on("data", onData);
|
|
31784
|
+
});
|
|
31785
|
+
}
|
|
31684
31786
|
const hint = defaultYes ? "(Y/n)" : "(y/N)";
|
|
31685
31787
|
const answer = await prompt2(`${question} ${hint}: `);
|
|
31686
31788
|
if (answer === "") return defaultYes;
|
|
@@ -31774,6 +31876,7 @@ var ttyStream;
|
|
|
31774
31876
|
var init_tty = __esm({
|
|
31775
31877
|
"src/utils/tty.ts"() {
|
|
31776
31878
|
"use strict";
|
|
31879
|
+
init_open_url();
|
|
31777
31880
|
ttyStream = null;
|
|
31778
31881
|
}
|
|
31779
31882
|
});
|
|
@@ -33531,7 +33634,7 @@ Examples:
|
|
|
33531
33634
|
}
|
|
33532
33635
|
}
|
|
33533
33636
|
} else if (provider === "runway") {
|
|
33534
|
-
const { spawn:
|
|
33637
|
+
const { spawn: spawn4 } = await import("child_process");
|
|
33535
33638
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
33536
33639
|
const __dirname2 = dirname7(__filename2);
|
|
33537
33640
|
const scriptPath = resolve23(
|
|
@@ -33546,7 +33649,7 @@ Examples:
|
|
|
33546
33649
|
const args = [scriptPath, prompt3, "-o", outputPath, "-r", options.ratio || "16:9"];
|
|
33547
33650
|
spinner2.text = "Generating image with Runway (gemini_2.5_flash)...";
|
|
33548
33651
|
await new Promise((resolvePromise, reject) => {
|
|
33549
|
-
const proc =
|
|
33652
|
+
const proc = spawn4("python3", args, {
|
|
33550
33653
|
env: { ...process.env, RUNWAY_API_SECRET: apiKey },
|
|
33551
33654
|
stdio: ["ignore", "pipe", "pipe"]
|
|
33552
33655
|
});
|
|
@@ -36906,8 +37009,8 @@ var init_translate_srt = __esm({
|
|
|
36906
37009
|
import { existsSync as existsSync21 } from "node:fs";
|
|
36907
37010
|
import { resolve as resolve27 } from "node:path";
|
|
36908
37011
|
function detectSystemFont() {
|
|
36909
|
-
const
|
|
36910
|
-
if (
|
|
37012
|
+
const platform3 = process.platform;
|
|
37013
|
+
if (platform3 === "darwin") {
|
|
36911
37014
|
const candidates = [
|
|
36912
37015
|
"/System/Library/Fonts/Helvetica.ttc",
|
|
36913
37016
|
"/System/Library/Fonts/HelveticaNeue.ttc",
|
|
@@ -36916,7 +37019,7 @@ function detectSystemFont() {
|
|
|
36916
37019
|
for (const f of candidates) {
|
|
36917
37020
|
if (existsSync21(f)) return f;
|
|
36918
37021
|
}
|
|
36919
|
-
} else if (
|
|
37022
|
+
} else if (platform3 === "linux") {
|
|
36920
37023
|
const candidates = [
|
|
36921
37024
|
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
|
|
36922
37025
|
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
|
|
@@ -36925,7 +37028,7 @@ function detectSystemFont() {
|
|
|
36925
37028
|
for (const f of candidates) {
|
|
36926
37029
|
if (existsSync21(f)) return f;
|
|
36927
37030
|
}
|
|
36928
|
-
} else if (
|
|
37031
|
+
} else if (platform3 === "win32") {
|
|
36929
37032
|
const candidates = [
|
|
36930
37033
|
"C:\\Windows\\Fonts\\arial.ttf",
|
|
36931
37034
|
"C:\\Windows\\Fonts\\segoeui.ttf"
|
|
@@ -36976,11 +37079,11 @@ async function applyTextOverlays(options) {
|
|
|
36976
37079
|
} = await Promise.resolve().then(() => (init_remotion(), remotion_exports));
|
|
36977
37080
|
const remotionErr = await ensureRemotionInstalled2();
|
|
36978
37081
|
if (remotionErr) {
|
|
36979
|
-
const
|
|
37082
|
+
const platform3 = process.platform;
|
|
36980
37083
|
let hint = "";
|
|
36981
|
-
if (
|
|
37084
|
+
if (platform3 === "darwin") {
|
|
36982
37085
|
hint = "\n\nFix: brew uninstall ffmpeg && brew install ffmpeg\n(The default homebrew formula includes libfreetype)";
|
|
36983
|
-
} else if (
|
|
37086
|
+
} else if (platform3 === "linux") {
|
|
36984
37087
|
hint = "\n\nFix: sudo apt install ffmpeg (Ubuntu/Debian)\n or rebuild FFmpeg with --enable-libfreetype";
|
|
36985
37088
|
}
|
|
36986
37089
|
return {
|
|
@@ -50813,6 +50916,320 @@ var init_detect = __esm({
|
|
|
50813
50916
|
}
|
|
50814
50917
|
});
|
|
50815
50918
|
|
|
50919
|
+
// src/commands/_shared/walkthroughs/walkthroughs.ts
|
|
50920
|
+
function loadWalkthrough(topic) {
|
|
50921
|
+
const meta = META[topic];
|
|
50922
|
+
const content = CONTENT[topic];
|
|
50923
|
+
if (!meta || !content) {
|
|
50924
|
+
throw new Error(`Unknown walkthrough topic: ${topic}`);
|
|
50925
|
+
}
|
|
50926
|
+
return {
|
|
50927
|
+
topic,
|
|
50928
|
+
title: meta.title,
|
|
50929
|
+
summary: meta.summary,
|
|
50930
|
+
steps: meta.steps,
|
|
50931
|
+
relatedCommands: meta.relatedCommands,
|
|
50932
|
+
content
|
|
50933
|
+
};
|
|
50934
|
+
}
|
|
50935
|
+
function listWalkthroughs() {
|
|
50936
|
+
return WALKTHROUGH_TOPICS.map((topic) => ({
|
|
50937
|
+
topic,
|
|
50938
|
+
title: META[topic].title,
|
|
50939
|
+
summary: META[topic].summary
|
|
50940
|
+
}));
|
|
50941
|
+
}
|
|
50942
|
+
function isWalkthroughTopic(value) {
|
|
50943
|
+
return typeof value === "string" && WALKTHROUGH_TOPICS.includes(value);
|
|
50944
|
+
}
|
|
50945
|
+
var SCENE_WALKTHROUGH, PIPELINE_WALKTHROUGH, META, CONTENT, WALKTHROUGH_TOPICS;
|
|
50946
|
+
var init_walkthroughs = __esm({
|
|
50947
|
+
"src/commands/_shared/walkthroughs/walkthroughs.ts"() {
|
|
50948
|
+
"use strict";
|
|
50949
|
+
SCENE_WALKTHROUGH = `# Scene authoring with vibe
|
|
50950
|
+
|
|
50951
|
+
A scene project is a directory that is **bilingual**: it works with both
|
|
50952
|
+
\`vibe\` and \`npx hyperframes\`. Each scene is one HTML file with scoped CSS
|
|
50953
|
+
and a paused GSAP timeline. Cheap to edit, cheap to lint, expensive only
|
|
50954
|
+
at render.
|
|
50955
|
+
|
|
50956
|
+
\`vibe build\` (v0.60+) is the supported one-shot driver from a
|
|
50957
|
+
written storyboard to an MP4. Plan H (v0.70) added \`--mode agent\` so the
|
|
50958
|
+
host agent itself authors the per-beat HTML \u2014 no internal LLM call.
|
|
50959
|
+
|
|
50960
|
+
## Three authoring paths
|
|
50961
|
+
|
|
50962
|
+
| Path | Command | When to use |
|
|
50963
|
+
|---|---|---|
|
|
50964
|
+
| **One-shot (default, v0.60+)** | \`vibe build [project-dir]\` | STORYBOARD.md has YAML frontmatter + per-beat cues |
|
|
50965
|
+
| **High-craft (manual)** | \`DESIGN.md\` + local composition rules in your agent | Maximum control: hand-author each scene |
|
|
50966
|
+
| **Quick draft** | \`vibe scene add --style <preset>\` | No agent or no API keys; fast iteration |
|
|
50967
|
+
|
|
50968
|
+
Recommend \`vibe build\` whenever the user has a STORYBOARD with
|
|
50969
|
+
narration / backdrop intent.
|
|
50970
|
+
|
|
50971
|
+
## High-craft path
|
|
50972
|
+
|
|
50973
|
+
1. \`vibe init my-promo --visual-style "Swiss Pulse"\` \u2014 seeds
|
|
50974
|
+
\`DESIGN.md\` (palette, typography, motion, transitions) plus the
|
|
50975
|
+
\`vibe.project.yaml\` / \`hyperframes.json\` / \`index.html\` scaffold.
|
|
50976
|
+
In Plan H this **also installs local composition rules** at the
|
|
50977
|
+
right place for your host (\`.claude/skills/hyperframes/\` for Claude
|
|
50978
|
+
Code, \`.cursor/rules/hyperframes.mdc\` for Cursor, universal
|
|
50979
|
+
\`SKILL.md\` for everyone else).
|
|
50980
|
+
2. Read \`SKILL.md\` (or the host-specific copy) \u2014 Hyperframes
|
|
50981
|
+
framework rules, motion principles, type system, transition recipes.
|
|
50982
|
+
3. Read \`DESIGN.md\` \u2014 project-specific palette / typography / motion
|
|
50983
|
+
signature (visual identity hard-gate).
|
|
50984
|
+
4. Author each scene HTML directly under \`compositions/scene-<id>.html\`
|
|
50985
|
+
using the rules from steps 2 and 3. The skill enforces the visual
|
|
50986
|
+
identity contract \u2014 scenes that contradict DESIGN.md fail lint.
|
|
50987
|
+
5. \`vibe scene lint --fix\` for mechanical issues, \`vibe render my-promo\`
|
|
50988
|
+
to MP4.
|
|
50989
|
+
|
|
50990
|
+
## Quick-draft path
|
|
50991
|
+
|
|
50992
|
+
\`\`\`bash
|
|
50993
|
+
vibe init my-promo -r 16:9 -d 30
|
|
50994
|
+
vibe scene add intro --style announcement \\
|
|
50995
|
+
--headline "Ship videos, not clicks"
|
|
50996
|
+
vibe scene lint
|
|
50997
|
+
vibe render my-promo
|
|
50998
|
+
\`\`\`
|
|
50999
|
+
|
|
51000
|
+
\`vibe init\` is **idempotent** \u2014 running it on an existing Hyperframes
|
|
51001
|
+
directory merges \`hyperframes.json\` instead of clobbering it. Safe to
|
|
51002
|
+
invoke on user-provided projects.
|
|
51003
|
+
|
|
51004
|
+
## Subcommands
|
|
51005
|
+
|
|
51006
|
+
\`\`\`bash
|
|
51007
|
+
# Project flow (top-level \u2014 preferred entry points)
|
|
51008
|
+
vibe init <dir> [-r 16:9|9:16|1:1|4:5] [-d <sec>] [--visual-style "<name>"]
|
|
51009
|
+
vibe build [<dir>] [--mode agent|batch|auto] # H3 dispatch
|
|
51010
|
+
vibe render [<dir>] [--fps 30] [--quality standard] [--format mp4]
|
|
51011
|
+
|
|
51012
|
+
# Lower-level scene authoring
|
|
51013
|
+
vibe scene list-styles [<name>] # list / show vendored visual identities
|
|
51014
|
+
vibe scene install-skill [<dir>] [--host all] # retroactive composition-rules install
|
|
51015
|
+
vibe scene add <name> --style <preset> [...]
|
|
51016
|
+
vibe scene compose-prompts [<dir>] [--beat <id>] # H2: emit plan, no LLM call
|
|
51017
|
+
vibe scene lint [<root>] [--json] [--fix]
|
|
51018
|
+
\`\`\`
|
|
51019
|
+
|
|
51020
|
+
## Style presets (for \`vibe scene add --style\`)
|
|
51021
|
+
|
|
51022
|
+
- **simple** \u2014 backdrop + bottom caption (default)
|
|
51023
|
+
- **announcement** \u2014 single huge headline, gradient text
|
|
51024
|
+
- **explainer** \u2014 kicker + title + subtitle stack
|
|
51025
|
+
- **kinetic-type** \u2014 words animate in word-by-word
|
|
51026
|
+
- **product-shot** \u2014 corner label + bottom headline + slow zoom
|
|
51027
|
+
|
|
51028
|
+
All presets accept \`--narration <text|file>\`, \`--visuals <prompt>\`,
|
|
51029
|
+
\`--headline\`, \`--kicker\`. With \`--narration\`, scene duration auto-derives
|
|
51030
|
+
from the generated TTS audio.
|
|
51031
|
+
|
|
51032
|
+
## STORYBOARD-to-MP4 (one command, v0.60+)
|
|
51033
|
+
|
|
51034
|
+
\`\`\`bash
|
|
51035
|
+
vibe init my-promo --visual-style "Swiss Pulse" -d 12
|
|
51036
|
+
# (edit STORYBOARD.md with per-beat YAML cues \u2014 narration, backdrop, duration)
|
|
51037
|
+
vibe build my-promo
|
|
51038
|
+
\`\`\`
|
|
51039
|
+
|
|
51040
|
+
\`vibe build\` reads the STORYBOARD frontmatter + per-beat cues,
|
|
51041
|
+
dispatches TTS + image-gen per beat, then either:
|
|
51042
|
+
|
|
51043
|
+
- **\`--mode agent\`** (default when an agent host is detected) \u2014 emits a
|
|
51044
|
+
\`needs-author\` plan via \`vibe scene compose-prompts\`. The host agent
|
|
51045
|
+
authors each \`compositions/scene-<id>.html\` itself, then re-invoking
|
|
51046
|
+
\`vibe build\` proceeds to lint + render.
|
|
51047
|
+
- **\`--mode batch\`** \u2014 VibeFrame runs an internal LLM (Claude / OpenAI /
|
|
51048
|
+
Gemini) to compose the HTML, then renders.
|
|
51049
|
+
|
|
51050
|
+
\`VIBE_BUILD_MODE\` env var overrides the auto-resolve.
|
|
51051
|
+
|
|
51052
|
+
## Lint feedback loop
|
|
51053
|
+
|
|
51054
|
+
\`\`\`bash
|
|
51055
|
+
vibe scene lint --json --fix
|
|
51056
|
+
\`\`\`
|
|
51057
|
+
|
|
51058
|
+
Returns structured findings. The recommended loop: 1) run lint with
|
|
51059
|
+
\`--fix\` (mechanical fixes applied), 2) if \`errorCount > 0\`, edit the
|
|
51060
|
+
scene HTML, 3) re-lint. Cap retries at 3 \u2014 if errors persist, fall back
|
|
51061
|
+
to a template preset (\`vibe scene add <id> --style simple --force\`)
|
|
51062
|
+
and surface the error to the user.
|
|
51063
|
+
|
|
51064
|
+
## When to use VibeFrame vs raw Hyperframes
|
|
51065
|
+
|
|
51066
|
+
| Task | Tool |
|
|
51067
|
+
|------|------|
|
|
51068
|
+
| Generate narration + image, then author scene | \`vibe scene add\` |
|
|
51069
|
+
| Generate a full scenes project from a STORYBOARD | \`vibe build\` |
|
|
51070
|
+
| Hand-tweak a single scene's animation | edit \`compositions/<file>.html\` directly |
|
|
51071
|
+
| Render the project | \`vibe render\` (one canonical entry point) |
|
|
51072
|
+
| Lint | \`vibe scene lint\` *or* \`npx hyperframes lint\` (equivalent) |
|
|
51073
|
+
|
|
51074
|
+
The \`vibe\` CLI adds asset generation, AI orchestration, and pipeline
|
|
51075
|
+
integration on top of Hyperframes' rendering primitives.
|
|
51076
|
+
|
|
51077
|
+
## Quality checklist before render
|
|
51078
|
+
|
|
51079
|
+
- [ ] \`vibe scene lint\` exits 0 (or only warnings)
|
|
51080
|
+
- [ ] \`vibe doctor\` confirms a usable Chrome (required for render)
|
|
51081
|
+
- [ ] Root \`data-duration\` matches the sum of clip durations
|
|
51082
|
+
- [ ] Aspect ratio in \`vibe.project.yaml\` matches the destination platform
|
|
51083
|
+
`;
|
|
51084
|
+
PIPELINE_WALKTHROUGH = `# YAML pipelines (Video as Code)
|
|
51085
|
+
|
|
51086
|
+
A pipeline is a YAML manifest with steps that reference each other's
|
|
51087
|
+
outputs. \`vibe run pipeline.yaml\` executes them with checkpointing and
|
|
51088
|
+
cost estimation.
|
|
51089
|
+
|
|
51090
|
+
## Minimal skeleton
|
|
51091
|
+
|
|
51092
|
+
\`\`\`yaml
|
|
51093
|
+
name: promo-video
|
|
51094
|
+
description: 15s product teaser
|
|
51095
|
+
steps:
|
|
51096
|
+
- id: backdrop
|
|
51097
|
+
action: generate-image
|
|
51098
|
+
prompt: "sleek product shot on white background"
|
|
51099
|
+
output: backdrop.png
|
|
51100
|
+
- id: scene
|
|
51101
|
+
action: generate-video
|
|
51102
|
+
image: $backdrop.output # reference previous step output
|
|
51103
|
+
prompt: "slow camera pan"
|
|
51104
|
+
duration: 5
|
|
51105
|
+
output: scene.mp4
|
|
51106
|
+
- id: voice
|
|
51107
|
+
action: generate-tts
|
|
51108
|
+
text: "Meet the new standard."
|
|
51109
|
+
output: voice.mp3
|
|
51110
|
+
- id: final
|
|
51111
|
+
action: compose
|
|
51112
|
+
video: $scene.output
|
|
51113
|
+
audio: $voice.output
|
|
51114
|
+
output: final.mp4
|
|
51115
|
+
\`\`\`
|
|
51116
|
+
|
|
51117
|
+
## Supported actions
|
|
51118
|
+
|
|
51119
|
+
- \`generate-image\`, \`generate-video\`, \`generate-tts\`, \`generate-music\`,
|
|
51120
|
+
\`generate-sound-effect\`, \`generate-storyboard\`, \`generate-motion\`
|
|
51121
|
+
- \`edit-silence-cut\`, \`edit-jump-cut\`, \`edit-caption\`, \`edit-grade\`,
|
|
51122
|
+
\`edit-reframe\`, \`edit-speed-ramp\`, \`edit-fade\`, \`edit-noise-reduce\`,
|
|
51123
|
+
\`edit-text-overlay\`, \`edit-fill-gaps\`
|
|
51124
|
+
- \`analyze-media\`, \`analyze-video\`, \`analyze-review\`, \`analyze-suggest\`
|
|
51125
|
+
- \`audio-transcribe\`, \`audio-isolate\`, \`audio-voice-clone\`, \`audio-dub\`,
|
|
51126
|
+
\`audio-duck\`
|
|
51127
|
+
- \`detect-scenes\`, \`detect-silence\`, \`detect-beats\`
|
|
51128
|
+
- \`compose\`, \`export\`
|
|
51129
|
+
- \`scene-build\` (Plan H one-shot driver) and \`scene-render\`
|
|
51130
|
+
- \`compose-scenes-with-skills\` (internal-LLM compose pass)
|
|
51131
|
+
|
|
51132
|
+
The full set lives in \`packages/cli/src/pipeline/executor.ts\`.
|
|
51133
|
+
|
|
51134
|
+
## Variable references
|
|
51135
|
+
|
|
51136
|
+
- \`$<step-id>.output\` \u2014 previous step's output path
|
|
51137
|
+
- \`$<step-id>.result.<field>\` \u2014 structured field from JSON result
|
|
51138
|
+
- \`\${ENV_VAR}\` \u2014 environment variable
|
|
51139
|
+
- Values can be templated: \`"\${SCRIPT_TITLE} - Episode \${EPISODE}"\`
|
|
51140
|
+
|
|
51141
|
+
## Running
|
|
51142
|
+
|
|
51143
|
+
\`\`\`bash
|
|
51144
|
+
vibe run pipeline.yaml --dry-run # plan + cost estimate, no execution
|
|
51145
|
+
vibe run pipeline.yaml # execute
|
|
51146
|
+
vibe run pipeline.yaml --resume # retry from last successful step
|
|
51147
|
+
vibe run pipeline.yaml --from scene # start at specific step
|
|
51148
|
+
vibe run pipeline.yaml --provider-video kling # override provider
|
|
51149
|
+
\`\`\`
|
|
51150
|
+
|
|
51151
|
+
Checkpoints land next to the YAML: \`pipeline.yaml.checkpoint.json\`.
|
|
51152
|
+
|
|
51153
|
+
## Authoring tips
|
|
51154
|
+
|
|
51155
|
+
1. **Start from a tiny YAML** \u2014 keep it in your project directory and run
|
|
51156
|
+
\`vibe run pipeline.yaml --dry-run\` before spending provider budget.
|
|
51157
|
+
2. **Dry-run first** \u2014 you see estimated cost and resolved variable
|
|
51158
|
+
graph before spending API credits.
|
|
51159
|
+
3. **Keep step ids short and descriptive** (\`intro\`, \`scene1\`, \`voice\`,
|
|
51160
|
+
\`bgm\`) \u2014 they appear in logs and variable refs.
|
|
51161
|
+
4. **Name outputs** with extensions matching the action (\`.mp4\`, \`.mp3\`,
|
|
51162
|
+
\`.png\`, \`.json\`).
|
|
51163
|
+
5. **Declare \`budget:\`** on expensive pipelines:
|
|
51164
|
+
\`\`\`yaml
|
|
51165
|
+
budget:
|
|
51166
|
+
tokens: 500_000
|
|
51167
|
+
max_tool_errors: 3
|
|
51168
|
+
cost_usd: 5.00
|
|
51169
|
+
\`\`\`
|
|
51170
|
+
6. **Split large pipelines** into smaller YAML files and compose via
|
|
51171
|
+
\`action: run-pipeline\` (nested).
|
|
51172
|
+
|
|
51173
|
+
## Converting ad-hoc shell sessions to pipelines
|
|
51174
|
+
|
|
51175
|
+
When the user has a working shell sequence, extract steps:
|
|
51176
|
+
|
|
51177
|
+
- Each \`vibe ...\` command becomes one step
|
|
51178
|
+
- File outputs become step outputs; downstream \`-i <file>\` references
|
|
51179
|
+
become \`$<id>.output\`
|
|
51180
|
+
- Shared parameters move to a top-level \`defaults:\` section
|
|
51181
|
+
- Wrap the entire chain in a \`name:\` + \`steps:\` skeleton
|
|
51182
|
+
|
|
51183
|
+
The \`compose\` action is the catch-all assembly step (audio mux, video
|
|
51184
|
+
overlay, etc.) \u2014 useful at the tail of a pipeline.
|
|
51185
|
+
`;
|
|
51186
|
+
META = {
|
|
51187
|
+
scene: {
|
|
51188
|
+
title: "Scene authoring with vibe",
|
|
51189
|
+
summary: "Author per-scene HTML compositions and render to MP4 (BUILD flow)",
|
|
51190
|
+
steps: [
|
|
51191
|
+
'Run `vibe init <dir> --visual-style "<style name>"` to scaffold the project + install local composition rules.',
|
|
51192
|
+
"Edit `STORYBOARD.md` with per-beat YAML cues (narration / backdrop / duration).",
|
|
51193
|
+
"Read `SKILL.md` for the framework rules and `DESIGN.md` for the visual-identity hard-gate.",
|
|
51194
|
+
"Run `vibe build <dir>`. With an agent host detected, the CLI emits a `needs-author` plan; the host agent authors each `compositions/scene-<id>.html` and re-invokes to render.",
|
|
51195
|
+
"Run `vibe scene lint --fix` to validate, then `vibe render <dir>` to produce the MP4."
|
|
51196
|
+
],
|
|
51197
|
+
relatedCommands: [
|
|
51198
|
+
"vibe init",
|
|
51199
|
+
"vibe build",
|
|
51200
|
+
"vibe render",
|
|
51201
|
+
"vibe scene list-styles",
|
|
51202
|
+
"vibe scene install-skill",
|
|
51203
|
+
"vibe scene compose-prompts",
|
|
51204
|
+
"vibe scene lint",
|
|
51205
|
+
"vibe scene add"
|
|
51206
|
+
]
|
|
51207
|
+
},
|
|
51208
|
+
pipeline: {
|
|
51209
|
+
title: "YAML pipelines (Video as Code)",
|
|
51210
|
+
summary: "Author and run reproducible multi-step video workflows",
|
|
51211
|
+
steps: [
|
|
51212
|
+
"Sketch the workflow as YAML \u2014 `name`, `description`, then `steps:` with `id` + `action` + inputs/outputs.",
|
|
51213
|
+
"Reference previous step outputs via `$<step-id>.output` (or `$<step-id>.result.<field>` for structured returns).",
|
|
51214
|
+
"Run `vibe run pipeline.yaml --dry-run` to see the resolved graph + cost estimate before spending API budget.",
|
|
51215
|
+
"Add a `budget:` block (tokens / cost_usd / max_tool_errors) to cap expensive runs.",
|
|
51216
|
+
"Run `vibe run pipeline.yaml` to execute. Failed steps checkpoint to `pipeline.yaml.checkpoint.json`; resume with `--resume`."
|
|
51217
|
+
],
|
|
51218
|
+
relatedCommands: [
|
|
51219
|
+
"vibe run",
|
|
51220
|
+
"vibe schema --list",
|
|
51221
|
+
"vibe doctor"
|
|
51222
|
+
]
|
|
51223
|
+
}
|
|
51224
|
+
};
|
|
51225
|
+
CONTENT = {
|
|
51226
|
+
scene: SCENE_WALKTHROUGH,
|
|
51227
|
+
pipeline: PIPELINE_WALKTHROUGH
|
|
51228
|
+
};
|
|
51229
|
+
WALKTHROUGH_TOPICS = ["scene", "pipeline"];
|
|
51230
|
+
}
|
|
51231
|
+
});
|
|
51232
|
+
|
|
50816
51233
|
// src/pipeline/renderers/chrome.ts
|
|
50817
51234
|
import { existsSync as existsSync32 } from "node:fs";
|
|
50818
51235
|
import { homedir as homedir5 } from "node:os";
|
|
@@ -51582,6 +51999,126 @@ var init_scene_build = __esm({
|
|
|
51582
51999
|
}
|
|
51583
52000
|
});
|
|
51584
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
|
+
|
|
51585
52122
|
// src/pipeline/resolver.ts
|
|
51586
52123
|
function resolveStepParams(params, completedSteps) {
|
|
51587
52124
|
const resolved = {};
|
|
@@ -58587,10 +59124,10 @@ var init_ai_suggest_edit = __esm({
|
|
|
58587
59124
|
}
|
|
58588
59125
|
});
|
|
58589
59126
|
|
|
58590
|
-
// src/tools/manifest/
|
|
58591
|
-
var analyzeMediaTool, analyzeVideoTool, analyzeReviewTool, analyzeSuggestTool,
|
|
58592
|
-
var
|
|
58593
|
-
"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"() {
|
|
58594
59131
|
"use strict";
|
|
58595
59132
|
init_zod();
|
|
58596
59133
|
init_define_tool();
|
|
@@ -58713,7 +59250,7 @@ var init_analyze = __esm({
|
|
|
58713
59250
|
};
|
|
58714
59251
|
}
|
|
58715
59252
|
});
|
|
58716
|
-
|
|
59253
|
+
inspectTools = [
|
|
58717
59254
|
analyzeMediaTool,
|
|
58718
59255
|
analyzeVideoTool,
|
|
58719
59256
|
analyzeReviewTool,
|
|
@@ -59049,13 +59586,13 @@ var init_generate2 = __esm({
|
|
|
59049
59586
|
}
|
|
59050
59587
|
});
|
|
59051
59588
|
|
|
59052
|
-
// src/tools/manifest/
|
|
59589
|
+
// src/tools/manifest/remix.ts
|
|
59053
59590
|
import { writeFile as writeFile43 } from "node:fs/promises";
|
|
59054
59591
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
59055
59592
|
import { join as join13 } from "node:path";
|
|
59056
|
-
var pipelineHighlightsTool, pipelineAutoShortsTool, pipelineRunTool, pipelineRegenerateSceneTool,
|
|
59057
|
-
var
|
|
59058
|
-
"src/tools/manifest/
|
|
59593
|
+
var pipelineHighlightsTool, pipelineAutoShortsTool, pipelineRunTool, pipelineRegenerateSceneTool, remixTools;
|
|
59594
|
+
var init_remix = __esm({
|
|
59595
|
+
"src/tools/manifest/remix.ts"() {
|
|
59059
59596
|
"use strict";
|
|
59060
59597
|
init_zod();
|
|
59061
59598
|
init_define_tool();
|
|
@@ -59238,7 +59775,7 @@ var init_pipeline2 = __esm({
|
|
|
59238
59775
|
};
|
|
59239
59776
|
}
|
|
59240
59777
|
});
|
|
59241
|
-
|
|
59778
|
+
remixTools = [
|
|
59242
59779
|
pipelineHighlightsTool,
|
|
59243
59780
|
pipelineAutoShortsTool,
|
|
59244
59781
|
pipelineRunTool,
|
|
@@ -60062,7 +60599,7 @@ var init_hyperframes = __esm({
|
|
|
60062
60599
|
// src/commands/export.ts
|
|
60063
60600
|
import { readFile as readFile40, access as access8 } from "node:fs/promises";
|
|
60064
60601
|
import { resolve as resolve61, basename as basename21 } from "node:path";
|
|
60065
|
-
import { spawn } from "node:child_process";
|
|
60602
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
60066
60603
|
function timelineBaseName(path2) {
|
|
60067
60604
|
const name = basename21(path2);
|
|
60068
60605
|
if (name.endsWith(".vibe.json")) return name.slice(0, -".vibe.json".length);
|
|
@@ -60536,7 +61073,7 @@ function buildFFmpegArgs(clips, sources, presetSettings, outputPath, options, so
|
|
|
60536
61073
|
}
|
|
60537
61074
|
function runFFmpegProcess(ffmpegPath, args, onProgress) {
|
|
60538
61075
|
return new Promise((resolve64, reject) => {
|
|
60539
|
-
const ffmpeg =
|
|
61076
|
+
const ffmpeg = spawn3(ffmpegPath, args, {
|
|
60540
61077
|
stdio: ["pipe", "pipe", "pipe"]
|
|
60541
61078
|
});
|
|
60542
61079
|
let duration = 0;
|
|
@@ -61819,320 +62356,6 @@ Audio:`);
|
|
|
61819
62356
|
}
|
|
61820
62357
|
});
|
|
61821
62358
|
|
|
61822
|
-
// src/commands/_shared/walkthroughs/walkthroughs.ts
|
|
61823
|
-
function loadWalkthrough(topic) {
|
|
61824
|
-
const meta = META[topic];
|
|
61825
|
-
const content = CONTENT[topic];
|
|
61826
|
-
if (!meta || !content) {
|
|
61827
|
-
throw new Error(`Unknown walkthrough topic: ${topic}`);
|
|
61828
|
-
}
|
|
61829
|
-
return {
|
|
61830
|
-
topic,
|
|
61831
|
-
title: meta.title,
|
|
61832
|
-
summary: meta.summary,
|
|
61833
|
-
steps: meta.steps,
|
|
61834
|
-
relatedCommands: meta.relatedCommands,
|
|
61835
|
-
content
|
|
61836
|
-
};
|
|
61837
|
-
}
|
|
61838
|
-
function listWalkthroughs() {
|
|
61839
|
-
return WALKTHROUGH_TOPICS.map((topic) => ({
|
|
61840
|
-
topic,
|
|
61841
|
-
title: META[topic].title,
|
|
61842
|
-
summary: META[topic].summary
|
|
61843
|
-
}));
|
|
61844
|
-
}
|
|
61845
|
-
function isWalkthroughTopic(value) {
|
|
61846
|
-
return typeof value === "string" && WALKTHROUGH_TOPICS.includes(value);
|
|
61847
|
-
}
|
|
61848
|
-
var SCENE_WALKTHROUGH, PIPELINE_WALKTHROUGH, META, CONTENT, WALKTHROUGH_TOPICS;
|
|
61849
|
-
var init_walkthroughs = __esm({
|
|
61850
|
-
"src/commands/_shared/walkthroughs/walkthroughs.ts"() {
|
|
61851
|
-
"use strict";
|
|
61852
|
-
SCENE_WALKTHROUGH = `# Scene authoring with vibe
|
|
61853
|
-
|
|
61854
|
-
A scene project is a directory that is **bilingual**: it works with both
|
|
61855
|
-
\`vibe\` and \`npx hyperframes\`. Each scene is one HTML file with scoped CSS
|
|
61856
|
-
and a paused GSAP timeline. Cheap to edit, cheap to lint, expensive only
|
|
61857
|
-
at render.
|
|
61858
|
-
|
|
61859
|
-
\`vibe build\` (v0.60+) is the supported one-shot driver from a
|
|
61860
|
-
written storyboard to an MP4. Plan H (v0.70) added \`--mode agent\` so the
|
|
61861
|
-
host agent itself authors the per-beat HTML \u2014 no internal LLM call.
|
|
61862
|
-
|
|
61863
|
-
## Three authoring paths
|
|
61864
|
-
|
|
61865
|
-
| Path | Command | When to use |
|
|
61866
|
-
|---|---|---|
|
|
61867
|
-
| **One-shot (default, v0.60+)** | \`vibe build [project-dir]\` | STORYBOARD.md has YAML frontmatter + per-beat cues |
|
|
61868
|
-
| **High-craft (manual)** | \`DESIGN.md\` + local composition rules in your agent | Maximum control: hand-author each scene |
|
|
61869
|
-
| **Quick draft** | \`vibe scene add --style <preset>\` | No agent or no API keys; fast iteration |
|
|
61870
|
-
|
|
61871
|
-
Recommend \`vibe build\` whenever the user has a STORYBOARD with
|
|
61872
|
-
narration / backdrop intent.
|
|
61873
|
-
|
|
61874
|
-
## High-craft path
|
|
61875
|
-
|
|
61876
|
-
1. \`vibe init my-promo --visual-style "Swiss Pulse"\` \u2014 seeds
|
|
61877
|
-
\`DESIGN.md\` (palette, typography, motion, transitions) plus the
|
|
61878
|
-
\`vibe.project.yaml\` / \`hyperframes.json\` / \`index.html\` scaffold.
|
|
61879
|
-
In Plan H this **also installs local composition rules** at the
|
|
61880
|
-
right place for your host (\`.claude/skills/hyperframes/\` for Claude
|
|
61881
|
-
Code, \`.cursor/rules/hyperframes.mdc\` for Cursor, universal
|
|
61882
|
-
\`SKILL.md\` for everyone else).
|
|
61883
|
-
2. Read \`SKILL.md\` (or the host-specific copy) \u2014 Hyperframes
|
|
61884
|
-
framework rules, motion principles, type system, transition recipes.
|
|
61885
|
-
3. Read \`DESIGN.md\` \u2014 project-specific palette / typography / motion
|
|
61886
|
-
signature (visual identity hard-gate).
|
|
61887
|
-
4. Author each scene HTML directly under \`compositions/scene-<id>.html\`
|
|
61888
|
-
using the rules from steps 2 and 3. The skill enforces the visual
|
|
61889
|
-
identity contract \u2014 scenes that contradict DESIGN.md fail lint.
|
|
61890
|
-
5. \`vibe scene lint --fix\` for mechanical issues, \`vibe render my-promo\`
|
|
61891
|
-
to MP4.
|
|
61892
|
-
|
|
61893
|
-
## Quick-draft path
|
|
61894
|
-
|
|
61895
|
-
\`\`\`bash
|
|
61896
|
-
vibe init my-promo -r 16:9 -d 30
|
|
61897
|
-
vibe scene add intro --style announcement \\
|
|
61898
|
-
--headline "Ship videos, not clicks"
|
|
61899
|
-
vibe scene lint
|
|
61900
|
-
vibe render my-promo
|
|
61901
|
-
\`\`\`
|
|
61902
|
-
|
|
61903
|
-
\`vibe init\` is **idempotent** \u2014 running it on an existing Hyperframes
|
|
61904
|
-
directory merges \`hyperframes.json\` instead of clobbering it. Safe to
|
|
61905
|
-
invoke on user-provided projects.
|
|
61906
|
-
|
|
61907
|
-
## Subcommands
|
|
61908
|
-
|
|
61909
|
-
\`\`\`bash
|
|
61910
|
-
# Project flow (top-level \u2014 preferred entry points)
|
|
61911
|
-
vibe init <dir> [-r 16:9|9:16|1:1|4:5] [-d <sec>] [--visual-style "<name>"]
|
|
61912
|
-
vibe build [<dir>] [--mode agent|batch|auto] # H3 dispatch
|
|
61913
|
-
vibe render [<dir>] [--fps 30] [--quality standard] [--format mp4]
|
|
61914
|
-
|
|
61915
|
-
# Lower-level scene authoring
|
|
61916
|
-
vibe scene list-styles [<name>] # list / show vendored visual identities
|
|
61917
|
-
vibe scene install-skill [<dir>] [--host all] # retroactive composition-rules install
|
|
61918
|
-
vibe scene add <name> --style <preset> [...]
|
|
61919
|
-
vibe scene compose-prompts [<dir>] [--beat <id>] # H2: emit plan, no LLM call
|
|
61920
|
-
vibe scene lint [<root>] [--json] [--fix]
|
|
61921
|
-
\`\`\`
|
|
61922
|
-
|
|
61923
|
-
## Style presets (for \`vibe scene add --style\`)
|
|
61924
|
-
|
|
61925
|
-
- **simple** \u2014 backdrop + bottom caption (default)
|
|
61926
|
-
- **announcement** \u2014 single huge headline, gradient text
|
|
61927
|
-
- **explainer** \u2014 kicker + title + subtitle stack
|
|
61928
|
-
- **kinetic-type** \u2014 words animate in word-by-word
|
|
61929
|
-
- **product-shot** \u2014 corner label + bottom headline + slow zoom
|
|
61930
|
-
|
|
61931
|
-
All presets accept \`--narration <text|file>\`, \`--visuals <prompt>\`,
|
|
61932
|
-
\`--headline\`, \`--kicker\`. With \`--narration\`, scene duration auto-derives
|
|
61933
|
-
from the generated TTS audio.
|
|
61934
|
-
|
|
61935
|
-
## STORYBOARD-to-MP4 (one command, v0.60+)
|
|
61936
|
-
|
|
61937
|
-
\`\`\`bash
|
|
61938
|
-
vibe init my-promo --visual-style "Swiss Pulse" -d 12
|
|
61939
|
-
# (edit STORYBOARD.md with per-beat YAML cues \u2014 narration, backdrop, duration)
|
|
61940
|
-
vibe build my-promo
|
|
61941
|
-
\`\`\`
|
|
61942
|
-
|
|
61943
|
-
\`vibe build\` reads the STORYBOARD frontmatter + per-beat cues,
|
|
61944
|
-
dispatches TTS + image-gen per beat, then either:
|
|
61945
|
-
|
|
61946
|
-
- **\`--mode agent\`** (default when an agent host is detected) \u2014 emits a
|
|
61947
|
-
\`needs-author\` plan via \`vibe scene compose-prompts\`. The host agent
|
|
61948
|
-
authors each \`compositions/scene-<id>.html\` itself, then re-invoking
|
|
61949
|
-
\`vibe build\` proceeds to lint + render.
|
|
61950
|
-
- **\`--mode batch\`** \u2014 VibeFrame runs an internal LLM (Claude / OpenAI /
|
|
61951
|
-
Gemini) to compose the HTML, then renders.
|
|
61952
|
-
|
|
61953
|
-
\`VIBE_BUILD_MODE\` env var overrides the auto-resolve.
|
|
61954
|
-
|
|
61955
|
-
## Lint feedback loop
|
|
61956
|
-
|
|
61957
|
-
\`\`\`bash
|
|
61958
|
-
vibe scene lint --json --fix
|
|
61959
|
-
\`\`\`
|
|
61960
|
-
|
|
61961
|
-
Returns structured findings. The recommended loop: 1) run lint with
|
|
61962
|
-
\`--fix\` (mechanical fixes applied), 2) if \`errorCount > 0\`, edit the
|
|
61963
|
-
scene HTML, 3) re-lint. Cap retries at 3 \u2014 if errors persist, fall back
|
|
61964
|
-
to a template preset (\`vibe scene add <id> --style simple --force\`)
|
|
61965
|
-
and surface the error to the user.
|
|
61966
|
-
|
|
61967
|
-
## When to use VibeFrame vs raw Hyperframes
|
|
61968
|
-
|
|
61969
|
-
| Task | Tool |
|
|
61970
|
-
|------|------|
|
|
61971
|
-
| Generate narration + image, then author scene | \`vibe scene add\` |
|
|
61972
|
-
| Generate a full scenes project from a STORYBOARD | \`vibe build\` |
|
|
61973
|
-
| Hand-tweak a single scene's animation | edit \`compositions/<file>.html\` directly |
|
|
61974
|
-
| Render the project | \`vibe render\` (one canonical entry point) |
|
|
61975
|
-
| Lint | \`vibe scene lint\` *or* \`npx hyperframes lint\` (equivalent) |
|
|
61976
|
-
|
|
61977
|
-
The \`vibe\` CLI adds asset generation, AI orchestration, and pipeline
|
|
61978
|
-
integration on top of Hyperframes' rendering primitives.
|
|
61979
|
-
|
|
61980
|
-
## Quality checklist before render
|
|
61981
|
-
|
|
61982
|
-
- [ ] \`vibe scene lint\` exits 0 (or only warnings)
|
|
61983
|
-
- [ ] \`vibe doctor\` confirms a usable Chrome (required for render)
|
|
61984
|
-
- [ ] Root \`data-duration\` matches the sum of clip durations
|
|
61985
|
-
- [ ] Aspect ratio in \`vibe.project.yaml\` matches the destination platform
|
|
61986
|
-
`;
|
|
61987
|
-
PIPELINE_WALKTHROUGH = `# YAML pipelines (Video as Code)
|
|
61988
|
-
|
|
61989
|
-
A pipeline is a YAML manifest with steps that reference each other's
|
|
61990
|
-
outputs. \`vibe run pipeline.yaml\` executes them with checkpointing and
|
|
61991
|
-
cost estimation.
|
|
61992
|
-
|
|
61993
|
-
## Minimal skeleton
|
|
61994
|
-
|
|
61995
|
-
\`\`\`yaml
|
|
61996
|
-
name: promo-video
|
|
61997
|
-
description: 15s product teaser
|
|
61998
|
-
steps:
|
|
61999
|
-
- id: backdrop
|
|
62000
|
-
action: generate-image
|
|
62001
|
-
prompt: "sleek product shot on white background"
|
|
62002
|
-
output: backdrop.png
|
|
62003
|
-
- id: scene
|
|
62004
|
-
action: generate-video
|
|
62005
|
-
image: $backdrop.output # reference previous step output
|
|
62006
|
-
prompt: "slow camera pan"
|
|
62007
|
-
duration: 5
|
|
62008
|
-
output: scene.mp4
|
|
62009
|
-
- id: voice
|
|
62010
|
-
action: generate-tts
|
|
62011
|
-
text: "Meet the new standard."
|
|
62012
|
-
output: voice.mp3
|
|
62013
|
-
- id: final
|
|
62014
|
-
action: compose
|
|
62015
|
-
video: $scene.output
|
|
62016
|
-
audio: $voice.output
|
|
62017
|
-
output: final.mp4
|
|
62018
|
-
\`\`\`
|
|
62019
|
-
|
|
62020
|
-
## Supported actions
|
|
62021
|
-
|
|
62022
|
-
- \`generate-image\`, \`generate-video\`, \`generate-tts\`, \`generate-music\`,
|
|
62023
|
-
\`generate-sound-effect\`, \`generate-storyboard\`, \`generate-motion\`
|
|
62024
|
-
- \`edit-silence-cut\`, \`edit-jump-cut\`, \`edit-caption\`, \`edit-grade\`,
|
|
62025
|
-
\`edit-reframe\`, \`edit-speed-ramp\`, \`edit-fade\`, \`edit-noise-reduce\`,
|
|
62026
|
-
\`edit-text-overlay\`, \`edit-fill-gaps\`
|
|
62027
|
-
- \`analyze-media\`, \`analyze-video\`, \`analyze-review\`, \`analyze-suggest\`
|
|
62028
|
-
- \`audio-transcribe\`, \`audio-isolate\`, \`audio-voice-clone\`, \`audio-dub\`,
|
|
62029
|
-
\`audio-duck\`
|
|
62030
|
-
- \`detect-scenes\`, \`detect-silence\`, \`detect-beats\`
|
|
62031
|
-
- \`compose\`, \`export\`
|
|
62032
|
-
- \`scene-build\` (Plan H one-shot driver) and \`scene-render\`
|
|
62033
|
-
- \`compose-scenes-with-skills\` (internal-LLM compose pass)
|
|
62034
|
-
|
|
62035
|
-
The full set lives in \`packages/cli/src/pipeline/executor.ts\`.
|
|
62036
|
-
|
|
62037
|
-
## Variable references
|
|
62038
|
-
|
|
62039
|
-
- \`$<step-id>.output\` \u2014 previous step's output path
|
|
62040
|
-
- \`$<step-id>.result.<field>\` \u2014 structured field from JSON result
|
|
62041
|
-
- \`\${ENV_VAR}\` \u2014 environment variable
|
|
62042
|
-
- Values can be templated: \`"\${SCRIPT_TITLE} - Episode \${EPISODE}"\`
|
|
62043
|
-
|
|
62044
|
-
## Running
|
|
62045
|
-
|
|
62046
|
-
\`\`\`bash
|
|
62047
|
-
vibe run pipeline.yaml --dry-run # plan + cost estimate, no execution
|
|
62048
|
-
vibe run pipeline.yaml # execute
|
|
62049
|
-
vibe run pipeline.yaml --resume # retry from last successful step
|
|
62050
|
-
vibe run pipeline.yaml --from scene # start at specific step
|
|
62051
|
-
vibe run pipeline.yaml --provider-video kling # override provider
|
|
62052
|
-
\`\`\`
|
|
62053
|
-
|
|
62054
|
-
Checkpoints land next to the YAML: \`pipeline.yaml.checkpoint.json\`.
|
|
62055
|
-
|
|
62056
|
-
## Authoring tips
|
|
62057
|
-
|
|
62058
|
-
1. **Start from a tiny YAML** \u2014 keep it in your project directory and run
|
|
62059
|
-
\`vibe run pipeline.yaml --dry-run\` before spending provider budget.
|
|
62060
|
-
2. **Dry-run first** \u2014 you see estimated cost and resolved variable
|
|
62061
|
-
graph before spending API credits.
|
|
62062
|
-
3. **Keep step ids short and descriptive** (\`intro\`, \`scene1\`, \`voice\`,
|
|
62063
|
-
\`bgm\`) \u2014 they appear in logs and variable refs.
|
|
62064
|
-
4. **Name outputs** with extensions matching the action (\`.mp4\`, \`.mp3\`,
|
|
62065
|
-
\`.png\`, \`.json\`).
|
|
62066
|
-
5. **Declare \`budget:\`** on expensive pipelines:
|
|
62067
|
-
\`\`\`yaml
|
|
62068
|
-
budget:
|
|
62069
|
-
tokens: 500_000
|
|
62070
|
-
max_tool_errors: 3
|
|
62071
|
-
cost_usd: 5.00
|
|
62072
|
-
\`\`\`
|
|
62073
|
-
6. **Split large pipelines** into smaller YAML files and compose via
|
|
62074
|
-
\`action: run-pipeline\` (nested).
|
|
62075
|
-
|
|
62076
|
-
## Converting ad-hoc shell sessions to pipelines
|
|
62077
|
-
|
|
62078
|
-
When the user has a working shell sequence, extract steps:
|
|
62079
|
-
|
|
62080
|
-
- Each \`vibe ...\` command becomes one step
|
|
62081
|
-
- File outputs become step outputs; downstream \`-i <file>\` references
|
|
62082
|
-
become \`$<id>.output\`
|
|
62083
|
-
- Shared parameters move to a top-level \`defaults:\` section
|
|
62084
|
-
- Wrap the entire chain in a \`name:\` + \`steps:\` skeleton
|
|
62085
|
-
|
|
62086
|
-
The \`compose\` action is the catch-all assembly step (audio mux, video
|
|
62087
|
-
overlay, etc.) \u2014 useful at the tail of a pipeline.
|
|
62088
|
-
`;
|
|
62089
|
-
META = {
|
|
62090
|
-
scene: {
|
|
62091
|
-
title: "Scene authoring with vibe",
|
|
62092
|
-
summary: "Author per-scene HTML compositions and render to MP4 (BUILD flow)",
|
|
62093
|
-
steps: [
|
|
62094
|
-
'Run `vibe init <dir> --visual-style "<style name>"` to scaffold the project + install local composition rules.',
|
|
62095
|
-
"Edit `STORYBOARD.md` with per-beat YAML cues (narration / backdrop / duration).",
|
|
62096
|
-
"Read `SKILL.md` for the framework rules and `DESIGN.md` for the visual-identity hard-gate.",
|
|
62097
|
-
"Run `vibe build <dir>`. With an agent host detected, the CLI emits a `needs-author` plan; the host agent authors each `compositions/scene-<id>.html` and re-invokes to render.",
|
|
62098
|
-
"Run `vibe scene lint --fix` to validate, then `vibe render <dir>` to produce the MP4."
|
|
62099
|
-
],
|
|
62100
|
-
relatedCommands: [
|
|
62101
|
-
"vibe init",
|
|
62102
|
-
"vibe build",
|
|
62103
|
-
"vibe render",
|
|
62104
|
-
"vibe scene list-styles",
|
|
62105
|
-
"vibe scene install-skill",
|
|
62106
|
-
"vibe scene compose-prompts",
|
|
62107
|
-
"vibe scene lint",
|
|
62108
|
-
"vibe scene add"
|
|
62109
|
-
]
|
|
62110
|
-
},
|
|
62111
|
-
pipeline: {
|
|
62112
|
-
title: "YAML pipelines (Video as Code)",
|
|
62113
|
-
summary: "Author and run reproducible multi-step video workflows",
|
|
62114
|
-
steps: [
|
|
62115
|
-
"Sketch the workflow as YAML \u2014 `name`, `description`, then `steps:` with `id` + `action` + inputs/outputs.",
|
|
62116
|
-
"Reference previous step outputs via `$<step-id>.output` (or `$<step-id>.result.<field>` for structured returns).",
|
|
62117
|
-
"Run `vibe run pipeline.yaml --dry-run` to see the resolved graph + cost estimate before spending API budget.",
|
|
62118
|
-
"Add a `budget:` block (tokens / cost_usd / max_tool_errors) to cap expensive runs.",
|
|
62119
|
-
"Run `vibe run pipeline.yaml` to execute. Failed steps checkpoint to `pipeline.yaml.checkpoint.json`; resume with `--resume`."
|
|
62120
|
-
],
|
|
62121
|
-
relatedCommands: [
|
|
62122
|
-
"vibe run",
|
|
62123
|
-
"vibe schema --list",
|
|
62124
|
-
"vibe doctor"
|
|
62125
|
-
]
|
|
62126
|
-
}
|
|
62127
|
-
};
|
|
62128
|
-
CONTENT = {
|
|
62129
|
-
scene: SCENE_WALKTHROUGH,
|
|
62130
|
-
pipeline: PIPELINE_WALKTHROUGH
|
|
62131
|
-
};
|
|
62132
|
-
WALKTHROUGH_TOPICS = ["scene", "pipeline"];
|
|
62133
|
-
}
|
|
62134
|
-
});
|
|
62135
|
-
|
|
62136
62359
|
// src/tools/manifest/walkthrough.ts
|
|
62137
62360
|
var walkthroughSchema, walkthroughTool, walkthroughTools;
|
|
62138
62361
|
var init_walkthrough = __esm({
|
|
@@ -62183,15 +62406,15 @@ var init_walkthrough = __esm({
|
|
|
62183
62406
|
var manifest_exports = {};
|
|
62184
62407
|
__export(manifest_exports, {
|
|
62185
62408
|
agentOnlyTools: () => agentOnlyTools,
|
|
62186
|
-
analyzeTools: () => analyzeTools,
|
|
62187
62409
|
audioTools: () => audioTools,
|
|
62188
62410
|
detectTools: () => detectTools,
|
|
62189
62411
|
editTools: () => editTools,
|
|
62190
62412
|
exportTools: () => exportTools,
|
|
62191
62413
|
generateTools: () => generateTools,
|
|
62414
|
+
inspectTools: () => inspectTools,
|
|
62192
62415
|
manifest: () => manifest,
|
|
62193
|
-
pipelineTools: () => pipelineTools,
|
|
62194
62416
|
projectTools: () => projectTools,
|
|
62417
|
+
remixTools: () => remixTools,
|
|
62195
62418
|
sceneTools: () => sceneTools,
|
|
62196
62419
|
timelineTools: () => timelineTools,
|
|
62197
62420
|
walkthroughTools: () => walkthroughTools
|
|
@@ -62203,9 +62426,9 @@ var init_manifest = __esm({
|
|
|
62203
62426
|
init_scene2();
|
|
62204
62427
|
init_audio2();
|
|
62205
62428
|
init_edit();
|
|
62206
|
-
|
|
62429
|
+
init_inspect();
|
|
62207
62430
|
init_generate2();
|
|
62208
|
-
|
|
62431
|
+
init_remix();
|
|
62209
62432
|
init_detect2();
|
|
62210
62433
|
init_timeline();
|
|
62211
62434
|
init_project2();
|
|
@@ -62216,9 +62439,9 @@ var init_manifest = __esm({
|
|
|
62216
62439
|
...sceneTools,
|
|
62217
62440
|
...audioTools,
|
|
62218
62441
|
...editTools,
|
|
62219
|
-
...
|
|
62442
|
+
...inspectTools,
|
|
62220
62443
|
...generateTools,
|
|
62221
|
-
...
|
|
62444
|
+
...remixTools,
|
|
62222
62445
|
...detectTools,
|
|
62223
62446
|
...timelineTools,
|
|
62224
62447
|
...projectTools,
|
|
@@ -62428,7 +62651,7 @@ init_source();
|
|
|
62428
62651
|
// package.json
|
|
62429
62652
|
var package_default = {
|
|
62430
62653
|
name: "@vibeframe/cli",
|
|
62431
|
-
version: "0.
|
|
62654
|
+
version: "0.81.0",
|
|
62432
62655
|
description: "VibeFrame CLI - natural language video editing from the terminal",
|
|
62433
62656
|
private: false,
|
|
62434
62657
|
license: "MIT",
|
|
@@ -63583,7 +63806,7 @@ function detectMediaType(path2) {
|
|
|
63583
63806
|
init_generate();
|
|
63584
63807
|
init_edit_cmd();
|
|
63585
63808
|
|
|
63586
|
-
// src/commands/
|
|
63809
|
+
// src/commands/inspect.ts
|
|
63587
63810
|
init_esm();
|
|
63588
63811
|
init_source();
|
|
63589
63812
|
init_ora();
|
|
@@ -63598,7 +63821,7 @@ init_sanitize();
|
|
|
63598
63821
|
init_validate();
|
|
63599
63822
|
import { readFile as readFile23, writeFile as writeFile30 } from "node:fs/promises";
|
|
63600
63823
|
import { resolve as resolve33 } from "node:path";
|
|
63601
|
-
var
|
|
63824
|
+
var inspectCommand = new Command("inspect").description("Inspect media using AI (images, videos, YouTube URLs)").addHelpText(
|
|
63602
63825
|
"after",
|
|
63603
63826
|
`
|
|
63604
63827
|
Examples:
|
|
@@ -63616,7 +63839,7 @@ Use '--fields response,model' to limit output size.
|
|
|
63616
63839
|
Run 'vibe schema inspect.<command>' for structured parameter info.
|
|
63617
63840
|
`
|
|
63618
63841
|
);
|
|
63619
|
-
|
|
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) => {
|
|
63620
63843
|
const startedAt = Date.now();
|
|
63621
63844
|
try {
|
|
63622
63845
|
rejectControlChars(prompt3);
|
|
@@ -63693,7 +63916,7 @@ analyzeCommand.command("media").description("Analyze any media: images, videos,
|
|
|
63693
63916
|
exitWithError(apiError(`Analysis failed: ${error.message}`));
|
|
63694
63917
|
}
|
|
63695
63918
|
});
|
|
63696
|
-
|
|
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) => {
|
|
63697
63920
|
const startedAt = Date.now();
|
|
63698
63921
|
try {
|
|
63699
63922
|
rejectControlChars(prompt3);
|
|
@@ -63769,8 +63992,8 @@ analyzeCommand.command("video").description("Analyze video using Gemini (summari
|
|
|
63769
63992
|
exitWithError(apiError(`Video analysis failed: ${error.message}`));
|
|
63770
63993
|
}
|
|
63771
63994
|
});
|
|
63772
|
-
registerReviewCommand(
|
|
63773
|
-
|
|
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) => {
|
|
63774
63997
|
const startedAt = Date.now();
|
|
63775
63998
|
try {
|
|
63776
63999
|
rejectControlChars(instruction);
|
|
@@ -64357,7 +64580,7 @@ audioCommand.command("duck").description("Auto-duck background music when voice
|
|
|
64357
64580
|
}
|
|
64358
64581
|
});
|
|
64359
64582
|
|
|
64360
|
-
// src/commands/
|
|
64583
|
+
// src/commands/remix.ts
|
|
64361
64584
|
init_esm();
|
|
64362
64585
|
init_source();
|
|
64363
64586
|
init_ora();
|
|
@@ -64542,11 +64765,11 @@ function registerScriptPipelineCommands(aiCommand) {
|
|
|
64542
64765
|
});
|
|
64543
64766
|
}
|
|
64544
64767
|
|
|
64545
|
-
// src/commands/
|
|
64768
|
+
// src/commands/remix.ts
|
|
64546
64769
|
init_ai_highlights();
|
|
64547
64770
|
init_ai_animated_caption();
|
|
64548
64771
|
init_output();
|
|
64549
|
-
var
|
|
64772
|
+
var remixCommand = new Command("remix").description(
|
|
64550
64773
|
"Transform existing media (highlights, auto-shorts, animated captions, regenerate-scene)"
|
|
64551
64774
|
).addHelpText(
|
|
64552
64775
|
"after",
|
|
@@ -64580,10 +64803,10 @@ Use '--dry-run' to preview parameters before execution.
|
|
|
64580
64803
|
Run 'vibe schema remix.<command>' for structured parameter info.
|
|
64581
64804
|
`
|
|
64582
64805
|
);
|
|
64583
|
-
registerScriptPipelineCommands(
|
|
64584
|
-
registerHighlightsCommands(
|
|
64806
|
+
registerScriptPipelineCommands(remixCommand);
|
|
64807
|
+
registerHighlightsCommands(remixCommand);
|
|
64585
64808
|
var ANIMATED_CAPTION_STYLES = ["highlight", "bounce", "pop-in", "neon", "karaoke-sweep", "typewriter"];
|
|
64586
|
-
|
|
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(
|
|
64587
64810
|
"after",
|
|
64588
64811
|
`
|
|
64589
64812
|
Examples:
|
|
@@ -69302,9 +69525,54 @@ function validateKeyFormat(configKey, value) {
|
|
|
69302
69525
|
return { ok: false, expected: fmt.example };
|
|
69303
69526
|
}
|
|
69304
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
|
+
|
|
69305
69572
|
// src/commands/setup.ts
|
|
69306
69573
|
init_agent_host_detect();
|
|
69307
69574
|
init_dist2();
|
|
69575
|
+
init_walkthroughs();
|
|
69308
69576
|
var VALID_LLM_PROVIDERS = [
|
|
69309
69577
|
"claude",
|
|
69310
69578
|
"openai",
|
|
@@ -69313,7 +69581,7 @@ var VALID_LLM_PROVIDERS = [
|
|
|
69313
69581
|
"xai",
|
|
69314
69582
|
"openrouter"
|
|
69315
69583
|
];
|
|
69316
|
-
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(
|
|
69317
69585
|
"after",
|
|
69318
69586
|
`
|
|
69319
69587
|
Non-interactive examples (no TTY required):
|
|
@@ -69327,7 +69595,7 @@ Non-interactive examples (no TTY required):
|
|
|
69327
69595
|
return;
|
|
69328
69596
|
}
|
|
69329
69597
|
if (options.show) {
|
|
69330
|
-
await showConfig();
|
|
69598
|
+
await showConfig({ verbose: Boolean(options.verbose) });
|
|
69331
69599
|
return;
|
|
69332
69600
|
}
|
|
69333
69601
|
if (options.reset) {
|
|
@@ -69478,7 +69746,7 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
69478
69746
|
console.log();
|
|
69479
69747
|
if (topIndex === 0) {
|
|
69480
69748
|
await saveConfig(config2);
|
|
69481
|
-
showComplete(config2, "vibe edit silence-cut video.mp4 -o clean.mp4");
|
|
69749
|
+
await showComplete(config2, "vibe edit silence-cut video.mp4 -o clean.mp4");
|
|
69482
69750
|
return;
|
|
69483
69751
|
}
|
|
69484
69752
|
if (topIndex === 3) {
|
|
@@ -69499,7 +69767,7 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
69499
69767
|
console.log();
|
|
69500
69768
|
await collectKeys(config2, pipelineKeys);
|
|
69501
69769
|
await saveConfig(config2);
|
|
69502
|
-
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");
|
|
69503
69771
|
return;
|
|
69504
69772
|
}
|
|
69505
69773
|
console.log(source_default.dim("2. Features"));
|
|
@@ -69521,7 +69789,7 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
69521
69789
|
console.log(source_default.dim(" No features selected. You can re-run setup anytime."));
|
|
69522
69790
|
console.log();
|
|
69523
69791
|
await saveConfig(config2);
|
|
69524
|
-
showComplete(config2, "vibe --help", []);
|
|
69792
|
+
await showComplete(config2, "vibe --help", []);
|
|
69525
69793
|
return;
|
|
69526
69794
|
}
|
|
69527
69795
|
console.log(source_default.dim("3. API keys"));
|
|
@@ -69552,8 +69820,11 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
69552
69820
|
continue;
|
|
69553
69821
|
}
|
|
69554
69822
|
console.log(source_default.dim(` ${keyDef.what}`));
|
|
69555
|
-
console.log(source_default.dim(` Get key: ${keyDef.url}`));
|
|
69556
|
-
const newKey = await promptHidden(
|
|
69823
|
+
console.log(source_default.dim(` Get key: ${keyDef.url} [o] open in browser`));
|
|
69824
|
+
const newKey = await promptHidden(
|
|
69825
|
+
source_default.cyan(` ${keyDef.name.padEnd(14)} ${source_default.dim(keyDef.envVar)}: `),
|
|
69826
|
+
{ openHotkeyUrl: keyDef.url }
|
|
69827
|
+
);
|
|
69557
69828
|
if (newKey.trim()) {
|
|
69558
69829
|
const trimmed = newKey.trim();
|
|
69559
69830
|
config2.providers[keyDef.configKey] = trimmed;
|
|
@@ -69571,7 +69842,7 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
69571
69842
|
console.log();
|
|
69572
69843
|
}
|
|
69573
69844
|
await saveConfig(config2);
|
|
69574
|
-
showComplete(config2, selectedFeatures[0].tryCommand, selectedFeatures);
|
|
69845
|
+
await showComplete(config2, selectedFeatures[0].tryCommand, selectedFeatures);
|
|
69575
69846
|
}
|
|
69576
69847
|
async function collectKeys(config2, keys) {
|
|
69577
69848
|
loadEnv();
|
|
@@ -69587,8 +69858,11 @@ async function collectKeys(config2, keys) {
|
|
|
69587
69858
|
continue;
|
|
69588
69859
|
}
|
|
69589
69860
|
console.log(source_default.dim(` ${keyDef.what}`));
|
|
69590
|
-
console.log(source_default.dim(` Get key: ${keyDef.url}`));
|
|
69591
|
-
const newKey = await promptHidden(
|
|
69861
|
+
console.log(source_default.dim(` Get key: ${keyDef.url} [o] open in browser`));
|
|
69862
|
+
const newKey = await promptHidden(
|
|
69863
|
+
source_default.cyan(` ${keyDef.name.padEnd(14)} ${source_default.dim(keyDef.envVar)}: `),
|
|
69864
|
+
{ openHotkeyUrl: keyDef.url }
|
|
69865
|
+
);
|
|
69592
69866
|
if (newKey.trim()) {
|
|
69593
69867
|
const trimmed = newKey.trim();
|
|
69594
69868
|
config2.providers[keyDef.configKey] = trimmed;
|
|
@@ -69639,7 +69913,11 @@ async function runCustomSetup(config2) {
|
|
|
69639
69913
|
console.log(` ${source_default.green("\u2713")} ${p.name.padEnd(12)} ${maskApiKey(existing)} ${source_default.dim(p.desc)}`);
|
|
69640
69914
|
const change = await promptConfirm(source_default.cyan(" Update?"), false);
|
|
69641
69915
|
if (change) {
|
|
69642
|
-
|
|
69916
|
+
console.log(source_default.dim(` Get key: ${p.url} [o] open in browser`));
|
|
69917
|
+
const newKey = await promptHidden(
|
|
69918
|
+
source_default.cyan(" New key: "),
|
|
69919
|
+
{ openHotkeyUrl: p.url }
|
|
69920
|
+
);
|
|
69643
69921
|
if (newKey.trim()) {
|
|
69644
69922
|
const trimmed = newKey.trim();
|
|
69645
69923
|
config2.providers[p.key] = trimmed;
|
|
@@ -69652,7 +69930,11 @@ async function runCustomSetup(config2) {
|
|
|
69652
69930
|
}
|
|
69653
69931
|
}
|
|
69654
69932
|
} else {
|
|
69655
|
-
|
|
69933
|
+
console.log(source_default.dim(` ${source_default.dim("\u25CB")} ${p.name.padEnd(12)} ${source_default.dim(p.desc)} Get key: ${p.url} [o] open`));
|
|
69934
|
+
const newKey = await promptHidden(
|
|
69935
|
+
source_default.cyan(` ${p.env}: `),
|
|
69936
|
+
{ openHotkeyUrl: p.url }
|
|
69937
|
+
);
|
|
69656
69938
|
if (newKey.trim()) {
|
|
69657
69939
|
const trimmed = newKey.trim();
|
|
69658
69940
|
config2.providers[p.key] = trimmed;
|
|
@@ -69667,14 +69949,15 @@ async function runCustomSetup(config2) {
|
|
|
69667
69949
|
}
|
|
69668
69950
|
console.log();
|
|
69669
69951
|
await saveConfig(config2);
|
|
69670
|
-
showComplete(config2, "vibe doctor");
|
|
69952
|
+
await showComplete(config2, "vibe doctor");
|
|
69671
69953
|
}
|
|
69672
|
-
function showComplete(config2, defaultTryCommand, features = []) {
|
|
69954
|
+
async function showComplete(config2, defaultTryCommand, features = []) {
|
|
69673
69955
|
console.log(source_default.dim("\u2500".repeat(40)));
|
|
69674
69956
|
console.log(source_default.green.bold("\u2713 Setup complete!"));
|
|
69675
69957
|
console.log();
|
|
69676
69958
|
console.log(source_default.dim(` Config: ${CONFIG_PATH}`));
|
|
69677
69959
|
console.log();
|
|
69960
|
+
const primaryTry = features.length > 1 ? features[0].tryCommand : defaultTryCommand;
|
|
69678
69961
|
if (features.length > 1) {
|
|
69679
69962
|
console.log(source_default.bold(" Try these:"));
|
|
69680
69963
|
for (const f of features) {
|
|
@@ -69683,10 +69966,21 @@ function showComplete(config2, defaultTryCommand, features = []) {
|
|
|
69683
69966
|
} else {
|
|
69684
69967
|
console.log(` Try: ${source_default.cyan(defaultTryCommand)}`);
|
|
69685
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
|
+
}
|
|
69686
69975
|
console.log();
|
|
69687
69976
|
console.log(source_default.bold(" Next steps:"));
|
|
69688
69977
|
console.log(source_default.dim(" cd <project>; vibe init Scaffold AGENTS.md / CLAUDE.md / .env.example (project scope)"));
|
|
69689
|
-
|
|
69978
|
+
const hostDetected = detectedAgentHosts().length > 0;
|
|
69979
|
+
for (const w of listWalkthroughs()) {
|
|
69980
|
+
const cmd = `vibe walkthrough ${w.topic}`.padEnd(26);
|
|
69981
|
+
const tag = hostDetected && w.topic === "scene" ? source_default.cyan(" (recommended)") : "";
|
|
69982
|
+
console.log(source_default.dim(` ${cmd}${w.summary}${tag}`));
|
|
69983
|
+
}
|
|
69690
69984
|
console.log(source_default.dim(" vibe doctor Check system health + available commands"));
|
|
69691
69985
|
console.log(source_default.dim(" vibe schema --list Discover every command"));
|
|
69692
69986
|
console.log(source_default.dim(" vibe setup Re-run user-scope setup anytime"));
|
|
@@ -69734,7 +70028,8 @@ function maskApiKey(key) {
|
|
|
69734
70028
|
if (key.length <= 8) return "****";
|
|
69735
70029
|
return `${key.slice(0, 4)}${"*".repeat(8)}${key.slice(-4)}`;
|
|
69736
70030
|
}
|
|
69737
|
-
async function showConfig() {
|
|
70031
|
+
async function showConfig(opts = { verbose: false }) {
|
|
70032
|
+
const { verbose } = opts;
|
|
69738
70033
|
loadEnv();
|
|
69739
70034
|
const cwdEnvPath = resolve42(process.cwd(), ".env");
|
|
69740
70035
|
let hasCwdEnv = false;
|
|
@@ -69785,6 +70080,7 @@ async function showConfig() {
|
|
|
69785
70080
|
{ key: "replicate", name: "Replicate", env: "REPLICATE_API_TOKEN" },
|
|
69786
70081
|
{ key: "openrouter", name: "OpenRouter", env: "OPENROUTER_API_KEY" }
|
|
69787
70082
|
];
|
|
70083
|
+
let unsetCount = 0;
|
|
69788
70084
|
for (const p of providerKeys) {
|
|
69789
70085
|
const configValue = config2?.providers[p.key];
|
|
69790
70086
|
const dotenvValue = dotenvKeys[p.env];
|
|
@@ -69796,23 +70092,31 @@ async function showConfig() {
|
|
|
69796
70092
|
const status = source_default.green("\u2713");
|
|
69797
70093
|
console.log(` ${status} ${p.name.padEnd(12)} ${maskApiKey(value)} (${sources.join(" + ")})`);
|
|
69798
70094
|
} else {
|
|
69799
|
-
|
|
69800
|
-
|
|
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
|
+
}
|
|
69801
70100
|
}
|
|
69802
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
|
+
}
|
|
69803
70105
|
console.log();
|
|
69804
|
-
if (
|
|
69805
|
-
|
|
69806
|
-
|
|
69807
|
-
|
|
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"));
|
|
69808
70118
|
console.log();
|
|
69809
70119
|
}
|
|
69810
|
-
console.log(source_default.bold("Resolution order:"));
|
|
69811
|
-
console.log(source_default.dim(" 1. --api-key CLI option"));
|
|
69812
|
-
console.log(source_default.dim(` 2. ${CONFIG_PATH}`));
|
|
69813
|
-
console.log(source_default.dim(" 3. .env in current directory"));
|
|
69814
|
-
console.log(source_default.dim(" 4. Shell environment variables"));
|
|
69815
|
-
console.log();
|
|
69816
70120
|
}
|
|
69817
70121
|
|
|
69818
70122
|
// src/commands/init.ts
|
|
@@ -70731,11 +71035,13 @@ var FREE_COMMANDS = [
|
|
|
70731
71035
|
"timeline (all)",
|
|
70732
71036
|
"batch import/concat"
|
|
70733
71037
|
];
|
|
70734
|
-
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(
|
|
70735
71039
|
"after",
|
|
70736
71040
|
`
|
|
70737
71041
|
Examples:
|
|
70738
|
-
$ 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
|
|
70739
71045
|
$ vibe doctor --json Machine-readable output
|
|
70740
71046
|
`
|
|
70741
71047
|
).action(async (options) => {
|
|
@@ -70751,7 +71057,10 @@ Examples:
|
|
|
70751
71057
|
});
|
|
70752
71058
|
return;
|
|
70753
71059
|
}
|
|
70754
|
-
printReport(results);
|
|
71060
|
+
printReport(results, { verbose: Boolean(options.verbose) });
|
|
71061
|
+
if (options.testKeys) {
|
|
71062
|
+
await runLiveKeyTests(results);
|
|
71063
|
+
}
|
|
70755
71064
|
});
|
|
70756
71065
|
var REQUIRED_FFMPEG_FILTERS = {
|
|
70757
71066
|
drawtext: {
|
|
@@ -70805,14 +71114,14 @@ async function runDiagnostics() {
|
|
|
70805
71114
|
try {
|
|
70806
71115
|
const filtersResult = await execSafe("ffmpeg", ["-filters"]);
|
|
70807
71116
|
const filtersOutput = filtersResult.stdout;
|
|
70808
|
-
const
|
|
71117
|
+
const platform3 = process.platform;
|
|
70809
71118
|
ffmpegFilters = {};
|
|
70810
71119
|
for (const [filterName, info] of Object.entries(REQUIRED_FFMPEG_FILTERS)) {
|
|
70811
71120
|
const available = filtersOutput.includes(filterName);
|
|
70812
71121
|
ffmpegFilters[filterName] = {
|
|
70813
71122
|
available,
|
|
70814
71123
|
commands: info.commands,
|
|
70815
|
-
...!available && info.fix[
|
|
71124
|
+
...!available && info.fix[platform3] ? { fix: info.fix[platform3] } : {}
|
|
70816
71125
|
};
|
|
70817
71126
|
}
|
|
70818
71127
|
} catch {
|
|
@@ -70914,7 +71223,8 @@ async function runDiagnostics() {
|
|
|
70914
71223
|
totalCount
|
|
70915
71224
|
};
|
|
70916
71225
|
}
|
|
70917
|
-
function printReport(results) {
|
|
71226
|
+
function printReport(results, opts = { verbose: false }) {
|
|
71227
|
+
const { verbose } = opts;
|
|
70918
71228
|
console.log();
|
|
70919
71229
|
console.log(source_default.bold(" System"));
|
|
70920
71230
|
const nodeIcon = results.system.node.ok ? source_default.green("OK") : source_default.red("MISSING");
|
|
@@ -70943,10 +71253,25 @@ function printReport(results) {
|
|
|
70943
71253
|
}
|
|
70944
71254
|
}
|
|
70945
71255
|
if (results.system.optionalTools) {
|
|
70946
|
-
|
|
70947
|
-
|
|
70948
|
-
|
|
70949
|
-
|
|
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) {
|
|
70950
71275
|
console.log(
|
|
70951
71276
|
` ${name.padEnd(11)}${source_default.yellow("MISSING")} ${source_default.dim(`needed by: ${info.commands.join(", ")}`)}`
|
|
70952
71277
|
);
|
|
@@ -70968,29 +71293,31 @@ function printReport(results) {
|
|
|
70968
71293
|
console.log(` Project ${source_default.yellow("NOT INIT")} ${source_default.dim(`Run: vibe init (cwd: ${results.scope.project.cwd})`)}`);
|
|
70969
71294
|
}
|
|
70970
71295
|
console.log(` Agents ${source_default.dim(results.scope.agentHosts.summary)}`);
|
|
70971
|
-
|
|
70972
|
-
|
|
70973
|
-
|
|
70974
|
-
|
|
70975
|
-
|
|
70976
|
-
|
|
70977
|
-
|
|
70978
|
-
|
|
70979
|
-
|
|
70980
|
-
)
|
|
70981
|
-
|
|
70982
|
-
console.log(
|
|
70983
|
-
` Batch LLM ${source_default.yellow("--")} ${source_default.dim("no ANTHROPIC_API_KEY / GOOGLE_API_KEY / OPENAI_API_KEY \u2014 agent-mode only")}`
|
|
70984
|
-
);
|
|
70985
|
-
}
|
|
70986
|
-
if (sc.sceneProjectInCwd) {
|
|
70987
|
-
if (sc.skillInstalled) {
|
|
70988
|
-
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
|
+
);
|
|
70989
71307
|
} else {
|
|
70990
|
-
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)")}`);
|
|
70991
71320
|
}
|
|
70992
|
-
} else {
|
|
70993
|
-
console.log(` SKILL.md ${source_default.dim("(no STORYBOARD.md in cwd \u2014 skill is per-scene-project)")}`);
|
|
70994
71321
|
}
|
|
70995
71322
|
console.log();
|
|
70996
71323
|
console.log(source_default.bold(" API Keys"));
|
|
@@ -71007,16 +71334,24 @@ function printReport(results) {
|
|
|
71007
71334
|
}
|
|
71008
71335
|
}
|
|
71009
71336
|
if (missing.length > 0) {
|
|
71010
|
-
|
|
71011
|
-
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 {
|
|
71012
71345
|
console.log(
|
|
71013
|
-
` ${
|
|
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.`)
|
|
71014
71347
|
);
|
|
71015
71348
|
}
|
|
71016
71349
|
}
|
|
71017
|
-
|
|
71018
|
-
|
|
71019
|
-
|
|
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
|
+
}
|
|
71020
71355
|
console.log();
|
|
71021
71356
|
const pct = Math.round(results.readyCount / results.totalCount * 100);
|
|
71022
71357
|
const readyColor = pct >= 80 ? source_default.green : pct >= 40 ? source_default.yellow : source_default.red;
|
|
@@ -71032,6 +71367,32 @@ function printReport(results) {
|
|
|
71032
71367
|
}
|
|
71033
71368
|
console.log();
|
|
71034
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
|
+
}
|
|
71035
71396
|
function pickNextStep(results, hasMissingProviders) {
|
|
71036
71397
|
if (!results.scope.user.configured) {
|
|
71037
71398
|
return "Next: run 'vibe setup' to configure your user scope (API keys + LLM provider).";
|
|
@@ -72403,48 +72764,42 @@ program2.name("vibe").showSuggestionAfterError(true).description("VibeFrame CLI
|
|
|
72403
72764
|
}).addHelpText(
|
|
72404
72765
|
"after",
|
|
72405
72766
|
`
|
|
72406
|
-
|
|
72407
|
-
|
|
72408
|
-
|
|
72409
|
-
|
|
72410
|
-
|
|
72411
|
-
|
|
72412
|
-
|
|
72413
|
-
|
|
72414
|
-
|
|
72415
|
-
|
|
72416
|
-
|
|
72417
|
-
|
|
72418
|
-
|
|
72419
|
-
|
|
72420
|
-
|
|
72421
|
-
|
|
72422
|
-
|
|
72423
|
-
|
|
72424
|
-
|
|
72425
|
-
|
|
72426
|
-
|
|
72427
|
-
|
|
72428
|
-
|
|
72429
|
-
|
|
72430
|
-
|
|
72431
|
-
|
|
72432
|
-
|
|
72433
|
-
|
|
72434
|
-
|
|
72435
|
-
|
|
72436
|
-
|
|
72437
|
-
|
|
72438
|
-
|
|
72439
|
-
|
|
72440
|
-
|
|
72441
|
-
|
|
72442
|
-
Cost tiers (per call):
|
|
72443
|
-
Free detect, edit (silence-cut/fade/noise-reduce), timeline
|
|
72444
|
-
Low inspect, audio transcribe, generate image ~$0.01-$0.10
|
|
72445
|
-
High generate video, edit image ~$1-$5
|
|
72446
|
-
V.High remix (regenerate-scene, highlights, auto-shorts) ~$5-$50+
|
|
72447
|
-
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+
|
|
72448
72803
|
`
|
|
72449
72804
|
);
|
|
72450
72805
|
program2.hook("preAction", async (thisCommand, actionCommand) => {
|
|
@@ -72506,9 +72861,9 @@ program2.hook("preAction", async (thisCommand, actionCommand) => {
|
|
|
72506
72861
|
});
|
|
72507
72862
|
program2.addCommand(generateCommand);
|
|
72508
72863
|
program2.addCommand(editCommand);
|
|
72509
|
-
program2.addCommand(
|
|
72864
|
+
program2.addCommand(inspectCommand);
|
|
72510
72865
|
program2.addCommand(audioCommand);
|
|
72511
|
-
program2.addCommand(
|
|
72866
|
+
program2.addCommand(remixCommand);
|
|
72512
72867
|
program2.addCommand(setupCommand);
|
|
72513
72868
|
program2.addCommand(initCommand);
|
|
72514
72869
|
program2.addCommand(buildCommand);
|