@vibeframe/cli 0.96.0 → 0.96.4

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.
Files changed (2) hide show
  1. package/dist/index.js +133 -21
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -24528,7 +24528,7 @@ var init_fal = __esm({
24528
24528
  displayName: "Seedance 2.0",
24529
24529
  gateway: "fal.ai",
24530
24530
  // `fal` is a deprecated v0.x alias kept so existing scripts keep working.
24531
- // Will be removed at the 1.0 cut (see docs/1.0-readiness.md).
24531
+ // Review this alias at the 1.0 cut.
24532
24532
  aliases: ["fal"],
24533
24533
  models: ["seedance-2.0", "seedance-2.0-fast"],
24534
24534
  capabilities: ["text-to-video", "image-to-video", "native-audio"],
@@ -25847,8 +25847,8 @@ async function isConfigured() {
25847
25847
  }
25848
25848
  return false;
25849
25849
  }
25850
- async function getApiKeyFromConfig(providerKey) {
25851
- const config2 = await loadConfig();
25850
+ async function getApiKeyFromConfig(providerKey, options = {}) {
25851
+ const config2 = await loadConfig({ cwd: options.cwd });
25852
25852
  if (config2?.providers[providerKey]) {
25853
25853
  return config2.providers[providerKey];
25854
25854
  }
@@ -28827,6 +28827,20 @@ Requirements (non-negotiable):
28827
28827
  This is the #2 source of "text disappears mid-beat" bugs after \`.clip\` sizing.
28828
28828
  - Timed children inside the composition have \`class="clip"\` plus
28829
28829
  \`data-start\`, \`data-duration\`, \`data-track-index\`.
28830
+ - If the beat cues include \`backdrop\`, the build step has already generated
28831
+ \`assets/backdrop-${ctx.beat.id}.png\`. Use that local file as the full-frame
28832
+ visual backdrop. Do NOT replace it with abstract CSS, an external stock image,
28833
+ Unsplash, a CDN URL, or a remote placeholder.
28834
+ - The exact backdrop path string is \`assets/backdrop-${ctx.beat.id}.png\`.
28835
+ Do NOT prefix it with \`../\` or \`./\`: sub-composition fragments are mounted
28836
+ from the project root \`index.html\`, so \`../assets/...\` resolves outside the
28837
+ project and renders black.
28838
+ - Do not import external font or image URLs. Use the project DESIGN.md font
28839
+ choice when explicit; otherwise use \`Inter\`, which is available in the
28840
+ deterministic render font map.
28841
+ - If the beat cues include \`narration\`, do not embed an \`<audio>\` tag in the
28842
+ scene fragment. The root timeline wires \`assets/narration-${ctx.beat.id}.wav\`
28843
+ or \`assets/narration-${ctx.beat.id}.mp3\` separately.
28830
28844
  - **\`.clip\` elements get visibility control from the framework but NO
28831
28845
  sizing.** Always give \`.clip\` explicit fill via CSS:
28832
28846
  \`{ position: absolute; inset: 0; }\` (or equivalent
@@ -29027,6 +29041,18 @@ async function composeBeatWithRetry(ctx, overrides) {
29027
29041
  ${formatLintFeedback(lint2.findings)}`
29028
29042
  );
29029
29043
  }
29044
+ async function resolveComposerConfigAware(explicit, cwd) {
29045
+ if (explicit) {
29046
+ const configKey = await getApiKeyFromConfig(CONFIG_PROVIDER_BY_COMPOSER[explicit], { cwd });
29047
+ if (configKey) return { provider: explicit, apiKey: configKey };
29048
+ return resolveComposer(explicit);
29049
+ }
29050
+ for (const candidate of ["claude", "gemini", "openai"]) {
29051
+ const configKey = await getApiKeyFromConfig(CONFIG_PROVIDER_BY_COMPOSER[candidate], { cwd });
29052
+ if (configKey) return { provider: candidate, apiKey: configKey };
29053
+ }
29054
+ return resolveComposer();
29055
+ }
29030
29056
  async function executeComposeScenesWithSkills(params, outputDir, overrides) {
29031
29057
  const projectRoot = params.project ? resolve9(outputDir, params.project) : resolve9(outputDir);
29032
29058
  const designPath = resolve9(projectRoot, params.design ?? "DESIGN.md");
@@ -29051,7 +29077,7 @@ async function executeComposeScenesWithSkills(params, outputDir, overrides) {
29051
29077
  let provider;
29052
29078
  let apiKey;
29053
29079
  try {
29054
- const resolved = resolveComposer(params.composer);
29080
+ const resolved = await resolveComposerConfigAware(params.composer, projectRoot);
29055
29081
  provider = resolved.provider;
29056
29082
  apiKey = resolved.apiKey;
29057
29083
  } catch {
@@ -29156,7 +29182,7 @@ ${failures.map((f) => ` - ${f.beatId}: ${f.error}`).join("\n")}`,
29156
29182
  data: aggregateData
29157
29183
  };
29158
29184
  }
29159
- var MODEL_SETTINGS_BY_PROVIDER, ComposeBeatError, defaultCallLLM;
29185
+ var MODEL_SETTINGS_BY_PROVIDER, ComposeBeatError, defaultCallLLM, CONFIG_PROVIDER_BY_COMPOSER;
29160
29186
  var init_compose_scenes_skills = __esm({
29161
29187
  "src/commands/_shared/compose-scenes-skills.ts"() {
29162
29188
  "use strict";
@@ -29164,6 +29190,7 @@ var init_compose_scenes_skills = __esm({
29164
29190
  init_scene_lint();
29165
29191
  init_storyboard_parse();
29166
29192
  init_composer_resolve();
29193
+ init_config();
29167
29194
  MODEL_SETTINGS_BY_PROVIDER = {
29168
29195
  // Anthropic Claude Sonnet 4.6 — v0.69 baseline. ~9 s/beat, $3/$15 per MTok.
29169
29196
  claude: {
@@ -29254,6 +29281,11 @@ var init_compose_scenes_skills = __esm({
29254
29281
  outputTokens: usage?.candidatesTokenCount ?? 0
29255
29282
  };
29256
29283
  };
29284
+ CONFIG_PROVIDER_BY_COMPOSER = {
29285
+ claude: "anthropic",
29286
+ openai: "openai",
29287
+ gemini: "google"
29288
+ };
29257
29289
  }
29258
29290
  });
29259
29291
 
@@ -52528,9 +52560,7 @@ overlay, etc.) \u2014 useful at the tail of a pipeline.
52528
52560
 
52529
52561
  The CLI has three orchestrating commands that coordinate other primitives:
52530
52562
  \`vibe agent\`, \`vibe build\`, \`vibe run\`. New users routinely ask which one
52531
- they want for a given task. The full audit lives in
52532
- [\`docs/cli-architecture.md\`](../../../docs/cli-architecture.md); this
52533
- guide is the operator-facing summary.
52563
+ they want for a given task. This guide is the operator-facing summary.
52534
52564
 
52535
52565
  If you already use Claude Code, Codex, Cursor, Aider, Gemini CLI, OpenCode,
52536
52566
  or another coding agent, let that host drive \`vibe\` directly through shell
@@ -53448,7 +53478,7 @@ async function dispatchBackdrop(beat, ctx) {
53448
53478
  return { status: "cached", path: rel };
53449
53479
  }
53450
53480
  loadSceneBuildEnv(ctx.projectDir);
53451
- const apiKey = process.env.OPENAI_API_KEY ?? "";
53481
+ const apiKey = await getApiKeyFromConfig("openai", { cwd: ctx.projectDir }) ?? process.env.OPENAI_API_KEY ?? "";
53452
53482
  if (!apiKey) {
53453
53483
  const error = "OPENAI_API_KEY not set \u2014 cannot dispatch backdrop";
53454
53484
  ctx.onProgress({ type: "backdrop-failed", beatId: beat.id, error });
@@ -53580,6 +53610,7 @@ var init_scene_build = __esm({
53580
53610
  init_compose_scenes_skills();
53581
53611
  init_compose_prompts();
53582
53612
  init_agent_host_detect();
53613
+ init_config();
53583
53614
  init_scene_render();
53584
53615
  init_storyboard_parse();
53585
53616
  init_scene_project();
@@ -54360,25 +54391,102 @@ function getOutput(params, outputDir, defaultName) {
54360
54391
  }
54361
54392
  return resolve57(outputDir, defaultName);
54362
54393
  }
54394
+ function stringParam(value) {
54395
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
54396
+ }
54397
+ function numberParam2(value) {
54398
+ if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
54399
+ if (typeof value === "string" && value.trim() !== "") {
54400
+ const n = Number(value);
54401
+ return Number.isFinite(n) ? n : void 0;
54402
+ }
54403
+ return void 0;
54404
+ }
54405
+ async function resolvePipelineImageProvider(provider) {
54406
+ const explicit = stringParam(provider)?.toLowerCase();
54407
+ if (explicit) return explicit;
54408
+ await loadProviderDefaults();
54409
+ return resolveProvider("image")?.name ?? "gemini";
54410
+ }
54411
+ async function resolvePipelineVideoProvider(provider) {
54412
+ const explicit = stringParam(provider)?.toLowerCase();
54413
+ if (explicit === "fal") return "seedance";
54414
+ if (explicit) return explicit;
54415
+ await loadProviderDefaults();
54416
+ return resolveProvider("video")?.name ?? "grok";
54417
+ }
54418
+ function providerKeyForImage(provider) {
54419
+ switch (provider) {
54420
+ case "openai":
54421
+ return "openai";
54422
+ case "gemini":
54423
+ return "google";
54424
+ case "grok":
54425
+ return "xai";
54426
+ default:
54427
+ return void 0;
54428
+ }
54429
+ }
54430
+ function providerKeyForVideo(provider) {
54431
+ switch (provider) {
54432
+ case "seedance":
54433
+ case "fal":
54434
+ return "fal";
54435
+ case "grok":
54436
+ return "xai";
54437
+ case "kling":
54438
+ return "kling";
54439
+ case "runway":
54440
+ return "runway";
54441
+ case "veo":
54442
+ return "google";
54443
+ default:
54444
+ return void 0;
54445
+ }
54446
+ }
54447
+ async function apiKeyForProvider(providerKey) {
54448
+ return providerKey ? getApiKeyFromConfig(providerKey) : void 0;
54449
+ }
54363
54450
  async function ensureActionsRegistered() {
54364
54451
  if (Object.keys(ACTION_HANDLERS).length > 0) return;
54365
54452
  registerAction("generate-image", async (params, outputDir) => {
54366
54453
  const { executeImageGenerate: executeImageGenerate2 } = await Promise.resolve().then(() => (init_ai_image(), ai_image_exports));
54367
54454
  const output = getOutput(params, outputDir, "image.png");
54368
- const r = await executeImageGenerate2({ prompt: params.prompt, provider: params.provider, output, model: params.model, ratio: params.ratio });
54455
+ const provider = await resolvePipelineImageProvider(params.provider);
54456
+ const r = await executeImageGenerate2({
54457
+ prompt: params.prompt,
54458
+ provider,
54459
+ output,
54460
+ model: stringParam(params.model),
54461
+ ratio: stringParam(params.ratio),
54462
+ size: stringParam(params.size),
54463
+ quality: stringParam(params.quality),
54464
+ style: stringParam(params.style),
54465
+ count: numberParam2(params.count),
54466
+ apiKey: await apiKeyForProvider(providerKeyForImage(provider))
54467
+ });
54369
54468
  return { id: "", action: "generate-image", success: r.success, output: r.outputPath, data: { provider: r.provider, model: r.model }, error: r.error };
54370
54469
  });
54371
54470
  registerAction("generate-video", async (params, outputDir) => {
54372
54471
  const { executeVideoGenerate: executeVideoGenerate2 } = await Promise.resolve().then(() => (init_ai_video(), ai_video_exports));
54373
54472
  const output = getOutput(params, outputDir, "video.mp4");
54473
+ const provider = await resolvePipelineVideoProvider(params.provider);
54374
54474
  const r = await executeVideoGenerate2({
54375
54475
  prompt: params.prompt,
54376
- provider: params.provider,
54377
- image: params.image,
54378
- duration: params.duration,
54379
- ratio: params.ratio,
54476
+ provider,
54477
+ image: stringParam(params.image),
54478
+ duration: numberParam2(params.duration),
54479
+ ratio: stringParam(params.ratio),
54480
+ seed: numberParam2(params.seed),
54481
+ mode: stringParam(params.mode),
54482
+ negative: stringParam(params.negative),
54483
+ resolution: stringParam(params.resolution),
54484
+ veoModel: stringParam(params.veoModel),
54485
+ runwayModel: stringParam(params.runwayModel),
54486
+ seedanceModel: stringParam(params.seedanceModel),
54380
54487
  output,
54381
- wait: true
54488
+ wait: true,
54489
+ apiKey: await apiKeyForProvider(providerKeyForVideo(provider))
54382
54490
  });
54383
54491
  return { id: "", action: "generate-video", success: r.success, output: r.outputPath || r.videoUrl, data: { taskId: r.taskId, provider: r.provider, videoUrl: r.videoUrl }, error: r.error };
54384
54492
  });
@@ -54782,6 +54890,8 @@ var init_executor = __esm({
54782
54890
  import_yaml8 = __toESM(require_dist(), 1);
54783
54891
  init_resolver();
54784
54892
  init_output();
54893
+ init_config();
54894
+ init_provider_resolver();
54785
54895
  ACTION_METADATA = {
54786
54896
  "generate-image": { id: "generate-image", title: "Generate image", category: "generate", command: "generate image", outputs: ["image"] },
54787
54897
  "generate-video": { id: "generate-video", title: "Generate video", category: "generate", command: "generate video", outputs: ["video"], requiredKeys: ["provider-dependent"] },
@@ -64048,7 +64158,7 @@ init_source();
64048
64158
  // package.json
64049
64159
  var package_default = {
64050
64160
  name: "@vibeframe/cli",
64051
- version: "0.96.0",
64161
+ version: "0.96.4",
64052
64162
  description: "VibeFrame CLI - natural language video editing from the terminal",
64053
64163
  private: false,
64054
64164
  license: "MIT",
@@ -66476,7 +66586,8 @@ function inferType(opt, name) {
66476
66586
  "<ms>",
66477
66587
  "<n>",
66478
66588
  "<count>",
66479
- "<duration>"
66589
+ "<duration>",
66590
+ "<usd>"
66480
66591
  ];
66481
66592
  if (numericFlags.some((f) => opt.flags.includes(f))) {
66482
66593
  return "number";
@@ -66497,7 +66608,8 @@ function inferType(opt, name) {
66497
66608
  "fps",
66498
66609
  "bitrate",
66499
66610
  "width",
66500
- "height"
66611
+ "height",
66612
+ "budgetUsd"
66501
66613
  ];
66502
66614
  if (numericNames.includes(name)) {
66503
66615
  return "number";
@@ -74750,8 +74862,8 @@ async function startAgent(options = {}) {
74750
74862
  const isNonInteractive = !!options.input;
74751
74863
  const confirmAlways = options.confirm || false;
74752
74864
  const noConfirm = options.noConfirm || false;
74753
- const budgetUsd = options.budgetUsd ? parseFloat(options.budgetUsd) : void 0;
74754
- if (budgetUsd !== void 0 && (Number.isNaN(budgetUsd) || budgetUsd < 0)) {
74865
+ const budgetUsd = options.budgetUsd !== void 0 ? Number(options.budgetUsd) : void 0;
74866
+ if (budgetUsd !== void 0 && (!Number.isFinite(budgetUsd) || budgetUsd < 0)) {
74755
74867
  exitWithError(generalError(`Invalid --budget-usd: ${options.budgetUsd}`, "Must be a non-negative number (e.g., --budget-usd 5)"));
74756
74868
  }
74757
74869
  if (!isNonInteractive && !hasTTY()) {
@@ -74956,7 +75068,7 @@ async function startAgent(options = {}) {
74956
75068
  rl.prompt();
74957
75069
  });
74958
75070
  }
74959
- var agentCommand = new Command("agent").description("Optional built-in natural-language agent (fallback when no external coding agent is driving vibe)").option("-p, --provider <provider>", "LLM provider (openai, claude, gemini, ollama, xai, openrouter)", "openai").option("-m, --model <model>", "Model to use (provider-specific)").option("--project <path>", "Timeline file or directory to load").option("-v, --verbose", "Show verbose output including tool calls").option("--max-turns <n>", "Maximum turns per request", "10").option("-i, --input <query>", "Run a single query and exit (non-interactive)").option("-c, --confirm", "Confirm before every tool \u2014 broadens the default cost gate (paid only) to all calls").option("--no-confirm", "Disable all confirm prompts including the high/very-high cost gate (CI / automation)").option("--budget-usd <usd>", "Reject tool calls past this cumulative USD ceiling (tier-estimated, conservative)").action(async (options) => {
75071
+ var agentCommand = new Command("agent").description("Optional built-in natural-language agent (fallback when no external coding agent is driving vibe)").option("-p, --provider <provider>", "LLM provider (openai, claude, gemini, ollama, xai, openrouter)", "openai").option("-m, --model <model>", "Model to use (provider-specific)").option("--project <path>", "Timeline file or directory to load").option("-v, --verbose", "Show verbose output including tool calls").option("--max-turns <n>", "Maximum turns per request", "10").option("-i, --input <query>", "Run a single query and exit (non-interactive)").option("-c, --confirm", "Confirm before every tool \u2014 broadens the default cost gate (paid only) to all calls").option("--no-confirm", "Disable all confirm prompts including the high/very-high cost gate (CI / automation)").option("--budget-usd <usd>", "Reject tool calls past this cumulative USD ceiling using conservative tier estimates", parseFloat).action(async (options) => {
74960
75072
  await startAgent(options);
74961
75073
  });
74962
75074
  function getEnvVar(provider) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeframe/cli",
3
- "version": "0.96.0",
3
+ "version": "0.96.4",
4
4
  "description": "VibeFrame CLI - natural language video editing from the terminal",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -183,8 +183,8 @@
183
183
  "tsx": "^4.21.0",
184
184
  "typescript": "^5.3.3",
185
185
  "vitest": "^1.2.2",
186
- "@vibeframe/core": "0.96.0",
187
- "@vibeframe/ai-providers": "0.96.0"
186
+ "@vibeframe/ai-providers": "0.96.4",
187
+ "@vibeframe/core": "0.96.4"
188
188
  },
189
189
  "engines": {
190
190
  "node": ">=20"