@vibeframe/cli 0.91.6 → 0.91.8

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 +398 -178
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -31969,7 +31969,10 @@ async function promptMultiSelect(_question, options, defaultSelected = [], opts
31969
31969
  if (finished) return;
31970
31970
  if (char === "\r" || char === "\n") {
31971
31971
  if (pickFocused && !userToggled) {
31972
- for (let i = 0; i < selected.length; i++) selected[i] = false;
31972
+ const hasDefaultSelection = selected.some(Boolean);
31973
+ if (!opts.preserveDefaultSelectionOnEnter || !hasDefaultSelection) {
31974
+ for (let i = 0; i < selected.length; i++) selected[i] = false;
31975
+ }
31973
31976
  selected[cursor] = true;
31974
31977
  render();
31975
31978
  }
@@ -62959,7 +62962,7 @@ init_source();
62959
62962
  // package.json
62960
62963
  var package_default = {
62961
62964
  name: "@vibeframe/cli",
62962
- version: "0.91.6",
62965
+ version: "0.91.8",
62963
62966
  description: "VibeFrame CLI - natural language video editing from the terminal",
62964
62967
  private: false,
62965
62968
  license: "MIT",
@@ -69960,14 +69963,19 @@ var VALID_SCOPES = ["user", "project"];
69960
69963
  function parseScope(raw) {
69961
69964
  const v = String(raw ?? "user");
69962
69965
  if (!VALID_SCOPES.includes(v)) {
69963
- exitWithError(generalError(
69964
- `Invalid --scope: ${v}`,
69965
- `Must be one of: ${VALID_SCOPES.join(", ")}`
69966
- ));
69966
+ exitWithError(
69967
+ generalError(`Invalid --scope: ${v}`, `Must be one of: ${VALID_SCOPES.join(", ")}`)
69968
+ );
69967
69969
  }
69968
69970
  return v;
69969
69971
  }
69970
- var setupCommand = new Command("setup").description("Configure VibeFrame (LLM provider, API keys)").option("--reset", "Reset configuration to defaults").option("--full", "Run full setup with all optional providers").option("--show", "Show current configuration (for debugging)").option("-v, --verbose", "With --show: include unset providers + Resolution order + Defaults block").option("--claude-code", "Show Claude Code integration guide").option("-y, --yes", "Non-interactive: write config without prompting (CI / devcontainer)").option("--provider <id>", "Set the Agent LLM provider (claude | openai | gemini | xai | openrouter | ollama)").option("--import-env", "Promote API keys from .env / shell env into config.yaml").option("--test", "After save, live-test each configured key (exits 7 if any FAIL)").option(
69972
+ 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(
69973
+ "-v, --verbose",
69974
+ "With --show: include unset providers + Resolution order + Defaults block"
69975
+ ).option("--claude-code", "Show Claude Code integration guide").option("-y, --yes", "Non-interactive: write config without prompting (CI / devcontainer)").option(
69976
+ "--provider <id>",
69977
+ "Set the Agent LLM provider (claude | openai | gemini | xai | openrouter | ollama)"
69978
+ ).option("--import-env", "Promote API keys from .env / shell env into config.yaml").option("--test", "After save, live-test each configured key (exits 7 if any FAIL)").option(
69971
69979
  "--scope <scope>",
69972
69980
  "Where to save: 'user' (~/.vibeframe/config.yaml, shared) or 'project' (./.vibeframe/config.yaml, gitignored, this project only)",
69973
69981
  "user"
@@ -70017,10 +70025,12 @@ Exit codes (non-interactive):
70017
70025
  return;
70018
70026
  }
70019
70027
  if (!hasTTY()) {
70020
- exitWithError(generalError(
70021
- "Interactive setup requires a terminal.",
70022
- "Run 'vibe setup' directly from your terminal, or use 'vibe setup --yes --provider <id> --import-env' for CI."
70023
- ));
70028
+ exitWithError(
70029
+ generalError(
70030
+ "Interactive setup requires a terminal.",
70031
+ "Run 'vibe setup' directly from your terminal, or use 'vibe setup --yes --provider <id> --import-env' for CI."
70032
+ )
70033
+ );
70024
70034
  }
70025
70035
  try {
70026
70036
  await runSetupWizard(options.full, scope);
@@ -70037,24 +70047,50 @@ var AI_FEATURES = [
70037
70047
  desc: "generate + edit",
70038
70048
  defaultProvider: "OpenAI gpt-image-2 (Artificial Analysis #1, since v0.56)",
70039
70049
  alsoAvailable: "Gemini Nano Banana, Grok Imagine",
70040
- keys: [{ configKey: "openai", envVar: "OPENAI_API_KEY", name: "OpenAI", url: "https://platform.openai.com/api-keys", what: "gpt-image-2 image generation + editing (also Whisper, Agent)" }],
70050
+ keys: [
70051
+ {
70052
+ configKey: "openai",
70053
+ envVar: "OPENAI_API_KEY",
70054
+ name: "OpenAI",
70055
+ url: "https://platform.openai.com/api-keys",
70056
+ what: "gpt-image-2 image generation + editing (also Whisper, Agent)"
70057
+ }
70058
+ ],
70041
70059
  providerChoices: [
70042
70060
  {
70043
70061
  label: "OpenAI gpt-image-2",
70044
70062
  desc: "recommended default, image generation + editing",
70045
- key: { configKey: "openai", envVar: "OPENAI_API_KEY", name: "OpenAI", url: "https://platform.openai.com/api-keys", what: "gpt-image-2 image generation + editing (also Whisper, Agent)" },
70063
+ key: {
70064
+ configKey: "openai",
70065
+ envVar: "OPENAI_API_KEY",
70066
+ name: "OpenAI",
70067
+ url: "https://platform.openai.com/api-keys",
70068
+ what: "gpt-image-2 image generation + editing (also Whisper, Agent)"
70069
+ },
70046
70070
  defaultFor: { kind: "image", value: "openai" }
70047
70071
  },
70048
70072
  {
70049
70073
  label: "Gemini",
70050
70074
  desc: "Google image generation + multimodal analysis",
70051
- key: { configKey: "google", envVar: "GOOGLE_API_KEY", name: "Google", url: "https://aistudio.google.com/apikey", what: "Gemini image generation and multimodal analysis" },
70075
+ key: {
70076
+ configKey: "google",
70077
+ envVar: "GOOGLE_API_KEY",
70078
+ name: "Google",
70079
+ url: "https://aistudio.google.com/apikey",
70080
+ what: "Gemini image generation and multimodal analysis"
70081
+ },
70052
70082
  defaultFor: { kind: "image", value: "gemini" }
70053
70083
  },
70054
70084
  {
70055
70085
  label: "Grok",
70056
70086
  desc: "xAI image generation",
70057
- key: { configKey: "xai", envVar: "XAI_API_KEY", name: "xAI", url: "https://console.x.ai/", what: "Grok image generation and Agent" },
70087
+ key: {
70088
+ configKey: "xai",
70089
+ envVar: "XAI_API_KEY",
70090
+ name: "xAI",
70091
+ url: "https://console.x.ai/",
70092
+ what: "Grok image generation and Agent"
70093
+ },
70058
70094
  defaultFor: { kind: "image", value: "grok" }
70059
70095
  }
70060
70096
  ],
@@ -70065,36 +70101,74 @@ var AI_FEATURES = [
70065
70101
  desc: "generate + extend",
70066
70102
  defaultProvider: "Seedance 2.0 via fal.ai (Artificial Analysis #2 t2v + i2v, since v0.57)",
70067
70103
  alsoAvailable: "Grok Imagine, Kling, Runway Gen-4.5, Google Veo",
70068
- keys: [{ configKey: "fal", envVar: "FAL_KEY", name: "Seedance 2.0 (via fal.ai)", url: "https://fal.ai/dashboard/keys", what: "ByteDance Seedance 2.0 text-to-video and image-to-video" }],
70104
+ keys: [
70105
+ {
70106
+ configKey: "fal",
70107
+ envVar: "FAL_KEY",
70108
+ name: "Seedance 2.0 (via fal.ai)",
70109
+ url: "https://fal.ai/dashboard/keys",
70110
+ what: "ByteDance Seedance 2.0 text-to-video and image-to-video"
70111
+ }
70112
+ ],
70069
70113
  providerChoices: [
70070
70114
  {
70071
70115
  label: "Seedance 2.0 via fal.ai",
70072
70116
  desc: "recommended default, text-to-video + image-to-video",
70073
- key: { configKey: "fal", envVar: "FAL_KEY", name: "Seedance 2.0 (via fal.ai)", url: "https://fal.ai/dashboard/keys", what: "ByteDance Seedance 2.0 text-to-video and image-to-video" },
70117
+ key: {
70118
+ configKey: "fal",
70119
+ envVar: "FAL_KEY",
70120
+ name: "Seedance 2.0 (via fal.ai)",
70121
+ url: "https://fal.ai/dashboard/keys",
70122
+ what: "ByteDance Seedance 2.0 text-to-video and image-to-video"
70123
+ },
70074
70124
  defaultFor: { kind: "video", value: "seedance" }
70075
70125
  },
70076
70126
  {
70077
70127
  label: "Grok",
70078
70128
  desc: "xAI video generation with audio",
70079
- key: { configKey: "xai", envVar: "XAI_API_KEY", name: "xAI", url: "https://console.x.ai/", what: "Grok video generation and Agent" },
70129
+ key: {
70130
+ configKey: "xai",
70131
+ envVar: "XAI_API_KEY",
70132
+ name: "xAI",
70133
+ url: "https://console.x.ai/",
70134
+ what: "Grok video generation and Agent"
70135
+ },
70080
70136
  defaultFor: { kind: "video", value: "grok" }
70081
70137
  },
70082
70138
  {
70083
70139
  label: "Kling",
70084
70140
  desc: "Kling v2.5/v3 video generation",
70085
- key: { configKey: "kling", envVar: "KLING_API_KEY", name: "Kling", url: "https://platform.klingai.com/", what: "Kling video generation" },
70141
+ key: {
70142
+ configKey: "kling",
70143
+ envVar: "KLING_API_KEY",
70144
+ name: "Kling",
70145
+ url: "https://platform.klingai.com/",
70146
+ what: "Kling video generation"
70147
+ },
70086
70148
  defaultFor: { kind: "video", value: "kling" }
70087
70149
  },
70088
70150
  {
70089
70151
  label: "Runway",
70090
70152
  desc: "Runway Gen-4.5 video generation",
70091
- key: { configKey: "runway", envVar: "RUNWAY_API_SECRET", name: "Runway", url: "https://app.runwayml.com/settings/api-keys", what: "Runway Gen-4.5 video generation" },
70153
+ key: {
70154
+ configKey: "runway",
70155
+ envVar: "RUNWAY_API_SECRET",
70156
+ name: "Runway",
70157
+ url: "https://app.runwayml.com/settings/api-keys",
70158
+ what: "Runway Gen-4.5 video generation"
70159
+ },
70092
70160
  defaultFor: { kind: "video", value: "runway" }
70093
70161
  },
70094
70162
  {
70095
70163
  label: "Veo",
70096
70164
  desc: "Google Veo video generation",
70097
- key: { configKey: "google", envVar: "GOOGLE_API_KEY", name: "Google", url: "https://aistudio.google.com/apikey", what: "Google Veo video generation" },
70165
+ key: {
70166
+ configKey: "google",
70167
+ envVar: "GOOGLE_API_KEY",
70168
+ name: "Google",
70169
+ url: "https://aistudio.google.com/apikey",
70170
+ what: "Google Veo video generation"
70171
+ },
70098
70172
  defaultFor: { kind: "video", value: "veo" }
70099
70173
  }
70100
70174
  ],
@@ -70105,12 +70179,26 @@ var AI_FEATURES = [
70105
70179
  desc: "TTS, SFX, music, voice clone",
70106
70180
  defaultProvider: "ElevenLabs (paid, premium quality) \u2014 falls back to local Kokoro when no key (free, since v0.54)",
70107
70181
  alsoAvailable: "Replicate MusicGen (music only)",
70108
- keys: [{ configKey: "elevenlabs", envVar: "ELEVENLABS_API_KEY", name: "ElevenLabs", url: "https://elevenlabs.io/app/settings/api-keys", what: "Text-to-speech, sound effects, music, voice cloning (skip to use local Kokoro)" }],
70182
+ keys: [
70183
+ {
70184
+ configKey: "elevenlabs",
70185
+ envVar: "ELEVENLABS_API_KEY",
70186
+ name: "ElevenLabs",
70187
+ url: "https://elevenlabs.io/app/settings/api-keys",
70188
+ what: "Text-to-speech, sound effects, music, voice cloning (skip to use local Kokoro)"
70189
+ }
70190
+ ],
70109
70191
  providerChoices: [
70110
70192
  {
70111
70193
  label: "ElevenLabs",
70112
70194
  desc: "premium TTS, SFX, music, voice clone",
70113
- key: { configKey: "elevenlabs", envVar: "ELEVENLABS_API_KEY", name: "ElevenLabs", url: "https://elevenlabs.io/app/settings/api-keys", what: "Text-to-speech, sound effects, music, voice cloning" }
70195
+ key: {
70196
+ configKey: "elevenlabs",
70197
+ envVar: "ELEVENLABS_API_KEY",
70198
+ name: "ElevenLabs",
70199
+ url: "https://elevenlabs.io/app/settings/api-keys",
70200
+ what: "Text-to-speech, sound effects, music, voice cloning"
70201
+ }
70114
70202
  },
70115
70203
  {
70116
70204
  label: "Kokoro local",
@@ -70120,7 +70208,13 @@ var AI_FEATURES = [
70120
70208
  {
70121
70209
  label: "Replicate MusicGen",
70122
70210
  desc: "background music generation",
70123
- key: { configKey: "replicate", envVar: "REPLICATE_API_TOKEN", name: "Replicate", url: "https://replicate.com/account/api-tokens", what: "MusicGen background music" }
70211
+ key: {
70212
+ configKey: "replicate",
70213
+ envVar: "REPLICATE_API_TOKEN",
70214
+ name: "Replicate",
70215
+ url: "https://replicate.com/account/api-tokens",
70216
+ what: "MusicGen background music"
70217
+ }
70124
70218
  }
70125
70219
  ],
70126
70220
  tryCommand: 'vibe generate speech "Hello world" -o hello.mp3'
@@ -70131,8 +70225,20 @@ var AI_FEATURES = [
70131
70225
  defaultProvider: "Whisper (transcription) + Claude (reasoning)",
70132
70226
  alsoAvailable: "",
70133
70227
  keys: [
70134
- { configKey: "openai", envVar: "OPENAI_API_KEY", name: "OpenAI", url: "https://platform.openai.com/api-keys", what: "Whisper transcription (captions, jump-cut)" },
70135
- { configKey: "anthropic", envVar: "ANTHROPIC_API_KEY", name: "Anthropic", url: "https://console.anthropic.com/settings/keys", what: "Claude (color grade, reframe, motion graphics)" }
70228
+ {
70229
+ configKey: "openai",
70230
+ envVar: "OPENAI_API_KEY",
70231
+ name: "OpenAI",
70232
+ url: "https://platform.openai.com/api-keys",
70233
+ what: "Whisper transcription (captions, jump-cut)"
70234
+ },
70235
+ {
70236
+ configKey: "anthropic",
70237
+ envVar: "ANTHROPIC_API_KEY",
70238
+ name: "Anthropic",
70239
+ url: "https://console.anthropic.com/settings/keys",
70240
+ what: "Claude (color grade, reframe, motion graphics)"
70241
+ }
70136
70242
  ],
70137
70243
  tryCommand: "vibe edit caption video.mp4 -o captioned.mp4"
70138
70244
  }
@@ -70150,6 +70256,27 @@ function applyProviderDefault(config2, choice) {
70150
70256
  config2.defaults.videoProvider = choice.defaultFor.value;
70151
70257
  }
70152
70258
  }
70259
+ function isProviderChoiceConfigured(config2, choice) {
70260
+ if (choice.key) {
70261
+ const value = config2.providers[choice.key.configKey];
70262
+ if (value) return true;
70263
+ }
70264
+ if (choice.defaultFor?.kind === "image") {
70265
+ return config2.defaults.imageProvider === choice.defaultFor.value;
70266
+ }
70267
+ if (choice.defaultFor?.kind === "video") {
70268
+ return config2.defaults.videoProvider === choice.defaultFor.value;
70269
+ }
70270
+ return false;
70271
+ }
70272
+ function isFeatureConfigured(config2, feature) {
70273
+ if (feature.providerChoices?.some((choice) => isProviderChoiceConfigured(config2, choice))) {
70274
+ return true;
70275
+ }
70276
+ return feature.keys.some(
70277
+ (keyDef) => Boolean(config2.providers[keyDef.configKey])
70278
+ );
70279
+ }
70153
70280
  function mergeSelectedFeatures(current, next) {
70154
70281
  const merged = [...current];
70155
70282
  for (const feature of next) {
@@ -70168,10 +70295,12 @@ async function runNonInteractiveSetup(opts) {
70168
70295
  const changes = [];
70169
70296
  if (opts.provider) {
70170
70297
  if (!VALID_LLM_PROVIDERS.includes(opts.provider)) {
70171
- exitWithError(generalError(
70172
- `Invalid --provider: ${opts.provider}`,
70173
- `Must be one of: ${VALID_LLM_PROVIDERS.join(", ")}`
70174
- ));
70298
+ exitWithError(
70299
+ generalError(
70300
+ `Invalid --provider: ${opts.provider}`,
70301
+ `Must be one of: ${VALID_LLM_PROVIDERS.join(", ")}`
70302
+ )
70303
+ );
70175
70304
  }
70176
70305
  if (config2.llm.provider !== opts.provider) {
70177
70306
  config2.llm.provider = opts.provider;
@@ -70238,7 +70367,11 @@ async function runNonInteractiveSetup(opts) {
70238
70367
  }
70239
70368
  if (failures > 0) {
70240
70369
  console.error();
70241
- console.error(source_default.red(`Verification failed: ${failures} key${failures === 1 ? "" : "s"} returned non-2xx.`));
70370
+ console.error(
70371
+ source_default.red(
70372
+ `Verification failed: ${failures} key${failures === 1 ? "" : "s"} returned non-2xx.`
70373
+ )
70374
+ );
70242
70375
  process.exit(7);
70243
70376
  }
70244
70377
  }
@@ -70247,15 +70380,11 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70247
70380
  console.log();
70248
70381
  const cfgPath = getConfigPath(scope).replace(homedir5(), "~");
70249
70382
  const scopeNote = scope === "project" ? "applies to this project only \xB7 add .vibeframe/ to .gitignore" : "applies to every project for this user";
70250
- console.log(
70251
- source_default.bold.magenta("VibeFrame Setup") + source_default.bold(` \u2014 ${scope} scope`)
70252
- );
70383
+ console.log(source_default.bold.magenta("VibeFrame Setup") + source_default.bold(` \u2014 ${scope} scope`));
70253
70384
  console.log(source_default.dim(`${cfgPath} \xB7 ${scopeNote}`));
70254
70385
  if (scope === "user") {
70255
70386
  console.log(
70256
- source_default.dim(
70257
- "Tip: for per-project keys, cd into a project and run: vibe setup --scope project"
70258
- )
70387
+ source_default.dim("Tip: for per-project keys, cd into a project and run: vibe setup --scope project")
70259
70388
  );
70260
70389
  }
70261
70390
  console.log(source_default.dim("\u2500".repeat(40)));
@@ -70296,10 +70425,34 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70296
70425
  if (topIndex === 2) {
70297
70426
  config2.llm.provider = "claude";
70298
70427
  const pipelineKeys = [
70299
- { configKey: "anthropic", envVar: "ANTHROPIC_API_KEY", name: "Anthropic", url: "https://console.anthropic.com/settings/keys", what: "Claude \u2014 storyboard generation + reasoning" },
70300
- { configKey: "openai", envVar: "OPENAI_API_KEY", name: "OpenAI", url: "https://platform.openai.com/api-keys", what: "gpt-image-2 image generation (default since v0.56) + Whisper word-level transcribe" },
70301
- { configKey: "fal", envVar: "FAL_KEY", name: "fal.ai", url: "https://fal.ai/dashboard/keys", what: "Seedance 2.0 \u2014 video generation, default since v0.57" },
70302
- { configKey: "elevenlabs", envVar: "ELEVENLABS_API_KEY", name: "ElevenLabs", url: "https://elevenlabs.io/app/settings/api-keys", what: "Text-to-speech narration + music (skip to use local Kokoro)" }
70428
+ {
70429
+ configKey: "anthropic",
70430
+ envVar: "ANTHROPIC_API_KEY",
70431
+ name: "Anthropic",
70432
+ url: "https://console.anthropic.com/settings/keys",
70433
+ what: "Claude \u2014 storyboard generation + reasoning"
70434
+ },
70435
+ {
70436
+ configKey: "openai",
70437
+ envVar: "OPENAI_API_KEY",
70438
+ name: "OpenAI",
70439
+ url: "https://platform.openai.com/api-keys",
70440
+ what: "gpt-image-2 image generation (default since v0.56) + Whisper word-level transcribe"
70441
+ },
70442
+ {
70443
+ configKey: "fal",
70444
+ envVar: "FAL_KEY",
70445
+ name: "fal.ai",
70446
+ url: "https://fal.ai/dashboard/keys",
70447
+ what: "Seedance 2.0 \u2014 video generation, default since v0.57"
70448
+ },
70449
+ {
70450
+ configKey: "elevenlabs",
70451
+ envVar: "ELEVENLABS_API_KEY",
70452
+ name: "ElevenLabs",
70453
+ url: "https://elevenlabs.io/app/settings/api-keys",
70454
+ what: "Text-to-speech narration + music (skip to use local Kokoro)"
70455
+ }
70303
70456
  ];
70304
70457
  console.log(source_default.dim("2. API keys"));
70305
70458
  console.log(source_default.bold("Pipeline requires these API keys:"));
@@ -70307,10 +70460,19 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70307
70460
  console.log();
70308
70461
  await collectKeys(config2, pipelineKeys);
70309
70462
  await saveConfig(config2, { scope });
70310
- await completeOrContinue(config2, "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format", [], scope);
70463
+ await completeOrContinue(
70464
+ config2,
70465
+ "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format",
70466
+ [],
70467
+ scope
70468
+ );
70311
70469
  return;
70312
70470
  }
70313
70471
  const result = await runAIFeaturesSetup(config2, scope);
70472
+ if (result.back) {
70473
+ await completeOrContinue(config2, "vibe --help", [], scope);
70474
+ return;
70475
+ }
70314
70476
  await saveConfig(config2, { scope });
70315
70477
  await completeOrContinue(config2, result.tryCommand, result.selectedFeatures, scope);
70316
70478
  }
@@ -70330,6 +70492,10 @@ async function completeOrContinue(config2, tryCommand, selectedFeatures, scope)
70330
70492
  console.log();
70331
70493
  if (action === 0) {
70332
70494
  const result = await runAIFeaturesSetup(config2, scope);
70495
+ if (result.back) {
70496
+ await completeOrContinue(config2, tryCommand, selectedFeatures, scope);
70497
+ return;
70498
+ }
70333
70499
  const mergedFeatures = mergeSelectedFeatures(selectedFeatures, result.selectedFeatures);
70334
70500
  const mergedTryCommand = selectedFeatures.length > 0 ? tryCommand : result.tryCommand;
70335
70501
  await saveConfig(config2, { scope });
@@ -70345,140 +70511,168 @@ async function completeOrContinue(config2, tryCommand, selectedFeatures, scope)
70345
70511
  await showComplete(config2, tryCommand, selectedFeatures, scope);
70346
70512
  }
70347
70513
  async function runAIFeaturesSetup(config2, _scope) {
70348
- console.log(source_default.dim("2. Features"));
70349
- console.log(source_default.bold("Which AI features do you need?"));
70350
- console.log(source_default.dim(` ${source_default.bold("Most users pick more than one.")} Press ${source_default.bold("space")} on each feature you want, then ${source_default.bold("enter")} to confirm.`));
70351
- console.log(source_default.dim(" Shortcut: enter alone picks only the highlighted feature."));
70352
- console.log();
70353
- const featureLabels = AI_FEATURES.map((f) => {
70354
- const keyCount = f.keys.length;
70355
- const tag = source_default.dim(`${keyCount} key${keyCount > 1 ? "s" : ""}`);
70356
- return `${f.label} ${source_default.dim(`(${f.desc})`)} ${tag}`;
70357
- });
70358
- const picked = await promptMultiSelect(
70359
- source_default.cyan(" Pick (e.g. 1,3 or 'all'): "),
70360
- featureLabels,
70361
- [],
70362
- { pickFocusedOnEnter: true }
70363
- );
70364
- const selectedFeatures = picked.map((i) => AI_FEATURES[i]);
70365
- console.log();
70366
- if (selectedFeatures.length === 0) {
70367
- console.log(source_default.dim(" No features selected. You can re-run setup anytime."));
70514
+ featureSelection: for (; ; ) {
70515
+ console.log(source_default.dim("2. Features"));
70516
+ console.log(source_default.bold("Which AI features do you need?"));
70517
+ console.log(
70518
+ source_default.dim(
70519
+ ` ${source_default.bold("Most users pick more than one.")} Press ${source_default.bold("space")} on each feature you want, then ${source_default.bold("enter")} to confirm.`
70520
+ )
70521
+ );
70522
+ console.log(source_default.dim(" Shortcut: enter alone picks only the highlighted feature."));
70523
+ console.log(source_default.dim(` Select ${source_default.bold("Back")} to return to the setup checkpoint.`));
70368
70524
  console.log();
70369
- return { tryCommand: "vibe --help", selectedFeatures: [] };
70370
- }
70371
- const plannedKeys = /* @__PURE__ */ new Map();
70372
- console.log(source_default.dim("3. Providers"));
70373
- console.log(source_default.bold("Choose providers for each selected feature"));
70374
- console.log(source_default.dim(` Recommended default is highlighted. Press ${source_default.bold("enter")} to pick the highlighted provider, or ${source_default.bold("space")} to choose multiple.`));
70375
- console.log();
70376
- for (const feature of selectedFeatures) {
70377
- const keysForFeature = [];
70378
- if (feature.providerChoices && feature.providerChoices.length > 0) {
70379
- console.log(source_default.bold.cyan(` ${feature.label}`));
70380
- console.log(source_default.dim(` Default path: ${feature.defaultProvider}`));
70381
- if (feature.alsoAvailable) {
70382
- console.log(source_default.dim(` Alternatives: ${feature.alsoAvailable}`));
70383
- }
70525
+ const backIndex = AI_FEATURES.length;
70526
+ const featureLabels = [
70527
+ ...AI_FEATURES.map((f) => {
70528
+ const keyCount = f.keys.length;
70529
+ const tag = source_default.dim(`${keyCount} key${keyCount > 1 ? "s" : ""}`);
70530
+ return `${f.label} ${source_default.dim(`(${f.desc})`)} ${tag}`;
70531
+ }),
70532
+ `Back ${source_default.dim("(return to setup checkpoint)")}`
70533
+ ];
70534
+ const configuredFeatures = AI_FEATURES.map((feature) => isFeatureConfigured(config2, feature));
70535
+ const picked = await promptMultiSelect(
70536
+ source_default.cyan(" Pick (e.g. 1,3 or 'all'): "),
70537
+ featureLabels,
70538
+ [...configuredFeatures, false],
70539
+ { pickFocusedOnEnter: true, preserveDefaultSelectionOnEnter: true }
70540
+ );
70541
+ if (picked.includes(backIndex)) {
70384
70542
  console.log();
70385
- const defaultSelected = feature.providerChoices.map(() => false);
70386
- const providerLabels = feature.providerChoices.map((choice) => {
70387
- const keyHint = choice.keyless ? source_default.dim("no key") : choice.key ? source_default.dim(choice.key.envVar) : source_default.dim("no key");
70388
- const defaultHint = choice === feature.providerChoices?.[0] ? source_default.dim("recommended default") : "";
70389
- return [
70390
- choice.label,
70391
- defaultHint,
70392
- source_default.dim(`- ${choice.desc}`),
70393
- keyHint
70394
- ].filter(Boolean).join(" ");
70395
- });
70396
- const pickedProviders = await promptMultiSelect(
70397
- source_default.cyan(" Providers (arrow + enter picks one, space adds more): "),
70398
- providerLabels,
70399
- defaultSelected,
70400
- { pickFocusedOnEnter: true }
70401
- );
70402
- const selectedChoices = pickedProviders.map((i) => feature.providerChoices[i]);
70403
- const defaultChoice = selectedChoices.find((choice) => choice.defaultFor);
70404
- if (defaultChoice) {
70405
- applyProviderDefault(config2, defaultChoice);
70406
- }
70407
- for (const choice of selectedChoices) {
70408
- if (choice.key) addUniqueKey(keysForFeature, choice.key);
70409
- }
70410
- if (selectedChoices.some((choice) => choice.keyless)) {
70411
- console.log(source_default.dim(" No API key needed for selected local provider(s)."));
70412
- }
70543
+ return { tryCommand: "vibe --help", selectedFeatures: [], back: true };
70544
+ }
70545
+ const selectedFeatures = picked.filter((i) => i < AI_FEATURES.length).map((i) => AI_FEATURES[i]);
70546
+ console.log();
70547
+ if (selectedFeatures.length === 0) {
70548
+ console.log(source_default.dim(" No features selected. You can re-run setup anytime."));
70413
70549
  console.log();
70414
- } else {
70415
- for (const keyDef of feature.keys) {
70416
- addUniqueKey(keysForFeature, keyDef);
70417
- }
70550
+ return { tryCommand: "vibe --help", selectedFeatures: [] };
70418
70551
  }
70419
- plannedKeys.set(feature.label, keysForFeature);
70420
- }
70421
- const needsKeys = [...plannedKeys.values()].some((keys) => keys.length > 0);
70422
- if (needsKeys) {
70423
- console.log(source_default.dim("4. API keys"));
70424
- console.log(source_default.bold("API Keys"));
70425
- console.log(source_default.dim(" Saved locally, never shared. Press Enter to skip."));
70552
+ const plannedKeys = /* @__PURE__ */ new Map();
70553
+ console.log(source_default.dim("3. Providers"));
70554
+ console.log(source_default.bold("Choose providers for each selected feature"));
70555
+ console.log(
70556
+ source_default.dim(
70557
+ ` Recommended default is highlighted. Press ${source_default.bold("enter")} to pick the highlighted provider, or ${source_default.bold("space")} to choose multiple.`
70558
+ )
70559
+ );
70426
70560
  console.log();
70427
- const collectedKeys = /* @__PURE__ */ new Set();
70428
70561
  for (const feature of selectedFeatures) {
70429
- const keysForFeature = plannedKeys.get(feature.label) ?? [];
70430
- if (keysForFeature.length === 0) {
70431
- continue;
70432
- }
70433
- console.log(source_default.bold.cyan(` ${feature.label}`));
70434
- console.log(source_default.dim(` Default: ${feature.defaultProvider}`));
70435
- if (feature.alsoAvailable) {
70436
- console.log(source_default.dim(` Also available: ${feature.alsoAvailable}`));
70562
+ const keysForFeature = [];
70563
+ if (feature.providerChoices && feature.providerChoices.length > 0) {
70564
+ console.log(source_default.bold.cyan(` ${feature.label}`));
70565
+ console.log(source_default.dim(` Default path: ${feature.defaultProvider}`));
70566
+ if (feature.alsoAvailable) {
70567
+ console.log(source_default.dim(` Alternatives: ${feature.alsoAvailable}`));
70568
+ }
70569
+ console.log();
70570
+ const defaultSelected = feature.providerChoices.map(
70571
+ (choice) => isProviderChoiceConfigured(config2, choice)
70572
+ );
70573
+ const providerLabels = feature.providerChoices.map((choice) => {
70574
+ const keyHint = choice.keyless ? source_default.dim("no key") : choice.key ? source_default.dim(choice.key.envVar) : source_default.dim("no key");
70575
+ const defaultHint = choice === feature.providerChoices?.[0] ? source_default.dim("recommended default") : "";
70576
+ return [choice.label, defaultHint, source_default.dim(`- ${choice.desc}`), keyHint].filter(Boolean).join(" ");
70577
+ });
70578
+ const backProviderIndex = providerLabels.length;
70579
+ const pickedProviders = await promptMultiSelect(
70580
+ source_default.cyan(" Providers (arrow + enter picks one, space adds more): "),
70581
+ [...providerLabels, `Back ${source_default.dim("(choose different features)")}`],
70582
+ [...defaultSelected, false],
70583
+ { pickFocusedOnEnter: true, preserveDefaultSelectionOnEnter: true }
70584
+ );
70585
+ if (pickedProviders.includes(backProviderIndex)) {
70586
+ console.log();
70587
+ continue featureSelection;
70588
+ }
70589
+ const selectedChoices = pickedProviders.filter((i) => i < feature.providerChoices.length).map((i) => feature.providerChoices[i]);
70590
+ const defaultChoice = selectedChoices.find((choice) => choice.defaultFor);
70591
+ if (defaultChoice) {
70592
+ applyProviderDefault(config2, defaultChoice);
70593
+ }
70594
+ for (const choice of selectedChoices) {
70595
+ if (choice.key) addUniqueKey(keysForFeature, choice.key);
70596
+ }
70597
+ if (selectedChoices.some((choice) => choice.keyless)) {
70598
+ console.log(source_default.dim(" No API key needed for selected local provider(s)."));
70599
+ }
70600
+ console.log();
70601
+ } else {
70602
+ for (const keyDef of feature.keys) {
70603
+ addUniqueKey(keysForFeature, keyDef);
70604
+ }
70437
70605
  }
70606
+ plannedKeys.set(feature.label, keysForFeature);
70607
+ }
70608
+ const needsKeys = [...plannedKeys.values()].some((keys) => keys.length > 0);
70609
+ if (needsKeys) {
70610
+ console.log(source_default.dim("4. API keys"));
70611
+ console.log(source_default.bold("API Keys"));
70612
+ console.log(source_default.dim(" Saved locally, never shared. Press Enter to skip."));
70438
70613
  console.log();
70439
- for (const keyDef of keysForFeature) {
70440
- if (collectedKeys.has(keyDef.configKey)) {
70441
- console.log(` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} (already set above)`);
70614
+ const collectedKeys = /* @__PURE__ */ new Set();
70615
+ for (const feature of selectedFeatures) {
70616
+ const keysForFeature = plannedKeys.get(feature.label) ?? [];
70617
+ if (keysForFeature.length === 0) {
70442
70618
  continue;
70443
70619
  }
70444
- loadEnv();
70445
- const configValue = config2.providers[keyDef.configKey];
70446
- const envValue = process.env[keyDef.envVar];
70447
- if (configValue || envValue) {
70448
- const value = configValue || envValue;
70449
- const source = configValue ? "config" : ".env";
70450
- console.log(` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(value)} ${source_default.dim(`(${source})`)}`);
70451
- collectedKeys.add(keyDef.configKey);
70452
- continue;
70620
+ console.log(source_default.bold.cyan(` ${feature.label}`));
70621
+ console.log(source_default.dim(` Default: ${feature.defaultProvider}`));
70622
+ if (feature.alsoAvailable) {
70623
+ console.log(source_default.dim(` Also available: ${feature.alsoAvailable}`));
70453
70624
  }
70454
- console.log(source_default.dim(` ${keyDef.what}`));
70455
- console.log(source_default.dim(` Get key: ${keyDef.url} [o] open in browser`));
70456
- const newKey = await promptHidden(
70457
- source_default.cyan(` ${keyDef.name.padEnd(14)} ${source_default.dim(keyDef.envVar)}: `),
70458
- { openHotkeyUrl: keyDef.url }
70459
- );
70460
- if (newKey.trim()) {
70461
- const trimmed = newKey.trim();
70462
- config2.providers[keyDef.configKey] = trimmed;
70463
- const fmt = validateKeyFormat(keyDef.configKey, trimmed);
70464
- if (!fmt.ok && fmt.expected) {
70465
- console.log(` ${source_default.yellow("\u26A0")} Saved, but format looks unusual ${source_default.dim(`(expected ${fmt.expected})`)}`);
70625
+ console.log();
70626
+ for (const keyDef of keysForFeature) {
70627
+ if (collectedKeys.has(keyDef.configKey)) {
70628
+ console.log(` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} (already set above)`);
70629
+ continue;
70630
+ }
70631
+ loadEnv();
70632
+ const configValue = config2.providers[keyDef.configKey];
70633
+ const envValue = process.env[keyDef.envVar];
70634
+ if (configValue || envValue) {
70635
+ const value = configValue || envValue;
70636
+ const source = configValue ? "config" : ".env";
70637
+ console.log(
70638
+ ` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(value)} ${source_default.dim(`(${source})`)}`
70639
+ );
70640
+ collectedKeys.add(keyDef.configKey);
70641
+ continue;
70642
+ }
70643
+ console.log(source_default.dim(` ${keyDef.what}`));
70644
+ console.log(source_default.dim(` Get key: ${keyDef.url} [o] open in browser`));
70645
+ const newKey = await promptHidden(
70646
+ source_default.cyan(` ${keyDef.name.padEnd(14)} ${source_default.dim(keyDef.envVar)}: `),
70647
+ { openHotkeyUrl: keyDef.url }
70648
+ );
70649
+ if (newKey.trim()) {
70650
+ const trimmed = newKey.trim();
70651
+ config2.providers[keyDef.configKey] = trimmed;
70652
+ const fmt = validateKeyFormat(keyDef.configKey, trimmed);
70653
+ if (!fmt.ok && fmt.expected) {
70654
+ console.log(
70655
+ ` ${source_default.yellow("\u26A0")} Saved, but format looks unusual ${source_default.dim(`(expected ${fmt.expected})`)}`
70656
+ );
70657
+ } else {
70658
+ console.log(` ${source_default.green("\u2713")} Saved`);
70659
+ }
70660
+ collectedKeys.add(keyDef.configKey);
70466
70661
  } else {
70467
- console.log(` ${source_default.green("\u2713")} Saved`);
70662
+ console.log(
70663
+ ` ${source_default.yellow("\u26A0")} Skipped ${source_default.dim(`(set ${keyDef.envVar} in .env later)`)}`
70664
+ );
70468
70665
  }
70469
- collectedKeys.add(keyDef.configKey);
70470
- } else {
70471
- console.log(` ${source_default.yellow("\u26A0")} Skipped ${source_default.dim(`(set ${keyDef.envVar} in .env later)`)}`);
70472
70666
  }
70667
+ console.log();
70473
70668
  }
70669
+ } else {
70670
+ console.log(source_default.dim("4. API keys"));
70671
+ console.log(source_default.dim(" No API keys needed for the selected provider(s)."));
70474
70672
  console.log();
70475
70673
  }
70476
- } else {
70477
- console.log(source_default.dim("4. API keys"));
70478
- console.log(source_default.dim(" No API keys needed for the selected provider(s)."));
70479
- console.log();
70674
+ return { tryCommand: selectedFeatures[0].tryCommand, selectedFeatures };
70480
70675
  }
70481
- return { tryCommand: selectedFeatures[0].tryCommand, selectedFeatures };
70482
70676
  }
70483
70677
  async function collectKeys(config2, keys) {
70484
70678
  loadEnv();
@@ -70486,11 +70680,15 @@ async function collectKeys(config2, keys) {
70486
70680
  const configValue = config2.providers[keyDef.configKey];
70487
70681
  const envValue = process.env[keyDef.envVar];
70488
70682
  if (configValue) {
70489
- console.log(` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(configValue)} ${source_default.dim("(config)")}`);
70683
+ console.log(
70684
+ ` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(configValue)} ${source_default.dim("(config)")}`
70685
+ );
70490
70686
  continue;
70491
70687
  }
70492
70688
  if (envValue) {
70493
- console.log(` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(envValue)} ${source_default.dim("(.env)")}`);
70689
+ console.log(
70690
+ ` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(envValue)} ${source_default.dim("(.env)")}`
70691
+ );
70494
70692
  continue;
70495
70693
  }
70496
70694
  console.log(source_default.dim(` ${keyDef.what}`));
@@ -70504,12 +70702,16 @@ async function collectKeys(config2, keys) {
70504
70702
  config2.providers[keyDef.configKey] = trimmed;
70505
70703
  const fmt = validateKeyFormat(keyDef.configKey, trimmed);
70506
70704
  if (!fmt.ok && fmt.expected) {
70507
- console.log(` ${source_default.yellow("\u26A0")} Saved, but format looks unusual ${source_default.dim(`(expected ${fmt.expected})`)}`);
70705
+ console.log(
70706
+ ` ${source_default.yellow("\u26A0")} Saved, but format looks unusual ${source_default.dim(`(expected ${fmt.expected})`)}`
70707
+ );
70508
70708
  } else {
70509
70709
  console.log(` ${source_default.green("\u2713")} Saved`);
70510
70710
  }
70511
70711
  } else {
70512
- console.log(` ${source_default.yellow("\u26A0")} Skipped ${source_default.dim(`(set ${keyDef.envVar} in .env later)`)}`);
70712
+ console.log(
70713
+ ` ${source_default.yellow("\u26A0")} Skipped ${source_default.dim(`(set ${keyDef.envVar} in .env later)`)}`
70714
+ );
70513
70715
  }
70514
70716
  }
70515
70717
  console.log();
@@ -70546,37 +70748,41 @@ async function runCustomSetup(config2, scope = "user", opts = {}) {
70546
70748
  for (const p of allProviders) {
70547
70749
  const existing = config2.providers[p.key];
70548
70750
  if (existing) {
70549
- console.log(` ${source_default.green("\u2713")} ${p.name.padEnd(12)} ${maskApiKey(existing)} ${source_default.dim(p.desc)}`);
70751
+ console.log(
70752
+ ` ${source_default.green("\u2713")} ${p.name.padEnd(12)} ${maskApiKey(existing)} ${source_default.dim(p.desc)}`
70753
+ );
70550
70754
  const change = await promptConfirm(source_default.cyan(" Update?"), false);
70551
70755
  if (change) {
70552
70756
  console.log(source_default.dim(` Get key: ${p.url} [o] open in browser`));
70553
- const newKey = await promptHidden(
70554
- source_default.cyan(" New key: "),
70555
- { openHotkeyUrl: p.url }
70556
- );
70757
+ const newKey = await promptHidden(source_default.cyan(" New key: "), { openHotkeyUrl: p.url });
70557
70758
  if (newKey.trim()) {
70558
70759
  const trimmed = newKey.trim();
70559
70760
  config2.providers[p.key] = trimmed;
70560
70761
  const fmt = validateKeyFormat(p.key, trimmed);
70561
70762
  if (!fmt.ok && fmt.expected) {
70562
- console.log(source_default.yellow(` \u26A0 Updated, but format looks unusual (expected ${fmt.expected})`));
70763
+ console.log(
70764
+ source_default.yellow(` \u26A0 Updated, but format looks unusual (expected ${fmt.expected})`)
70765
+ );
70563
70766
  } else {
70564
70767
  console.log(source_default.green(" \u2713 Updated"));
70565
70768
  }
70566
70769
  }
70567
70770
  }
70568
70771
  } else {
70569
- console.log(source_default.dim(` ${source_default.dim("\u25CB")} ${p.name.padEnd(12)} ${source_default.dim(p.desc)} Get key: ${p.url} [o] open`));
70570
- const newKey = await promptHidden(
70571
- source_default.cyan(` ${p.env}: `),
70572
- { openHotkeyUrl: p.url }
70772
+ console.log(
70773
+ source_default.dim(
70774
+ ` ${source_default.dim("\u25CB")} ${p.name.padEnd(12)} ${source_default.dim(p.desc)} Get key: ${p.url} [o] open`
70775
+ )
70573
70776
  );
70777
+ const newKey = await promptHidden(source_default.cyan(` ${p.env}: `), { openHotkeyUrl: p.url });
70574
70778
  if (newKey.trim()) {
70575
70779
  const trimmed = newKey.trim();
70576
70780
  config2.providers[p.key] = trimmed;
70577
70781
  const fmt = validateKeyFormat(p.key, trimmed);
70578
70782
  if (!fmt.ok && fmt.expected) {
70579
- console.log(` ${source_default.yellow("\u26A0")} Saved, but format looks unusual ${source_default.dim(`(expected ${fmt.expected})`)}`);
70783
+ console.log(
70784
+ ` ${source_default.yellow("\u26A0")} Saved, but format looks unusual ${source_default.dim(`(expected ${fmt.expected})`)}`
70785
+ );
70580
70786
  } else {
70581
70787
  console.log(` ${source_default.green("\u2713")} Saved`);
70582
70788
  }
@@ -70613,14 +70819,20 @@ async function showComplete(config2, defaultTryCommand, features = [], scope = "
70613
70819
  }
70614
70820
  console.log();
70615
70821
  console.log(source_default.bold(" Next steps:"));
70616
- console.log(source_default.dim(" cd <project>; vibe init Scaffold AGENTS.md / CLAUDE.md / .env.example (project scope)"));
70822
+ console.log(
70823
+ source_default.dim(
70824
+ " cd <project>; vibe init Scaffold AGENTS.md / CLAUDE.md / .env.example (project scope)"
70825
+ )
70826
+ );
70617
70827
  const hostDetected = detectedAgentHosts().length > 0;
70618
70828
  for (const w of listWalkthroughs()) {
70619
70829
  const cmd = `vibe walkthrough ${w.topic}`.padEnd(26);
70620
70830
  const tag = hostDetected && w.topic === "scene" ? source_default.cyan(" (recommended)") : "";
70621
70831
  console.log(source_default.dim(` ${cmd}${w.summary}${tag}`));
70622
70832
  }
70623
- console.log(source_default.dim(" vibe doctor --test-keys Live-check each provider key against its API"));
70833
+ console.log(
70834
+ source_default.dim(" vibe doctor --test-keys Live-check each provider key against its API")
70835
+ );
70624
70836
  console.log(source_default.dim(" vibe doctor Check system health + available commands"));
70625
70837
  console.log(source_default.dim(" vibe schema --list Discover every command"));
70626
70838
  console.log(source_default.dim(" vibe setup Re-run user-scope setup anytime"));
@@ -70755,7 +70967,11 @@ async function showConfig(opts = { verbose: false }) {
70755
70967
  }
70756
70968
  }
70757
70969
  if (!verbose && unsetCount > 0) {
70758
- console.log(source_default.dim(` (${unsetCount} provider${unsetCount === 1 ? "" : "s"} unset \u2014 run with --verbose to list)`));
70970
+ console.log(
70971
+ source_default.dim(
70972
+ ` (${unsetCount} provider${unsetCount === 1 ? "" : "s"} unset \u2014 run with --verbose to list)`
70973
+ )
70974
+ );
70759
70975
  }
70760
70976
  console.log();
70761
70977
  if (verbose) {
@@ -70767,8 +70983,12 @@ async function showConfig(opts = { verbose: false }) {
70767
70983
  }
70768
70984
  console.log(source_default.bold("Resolution order:"));
70769
70985
  console.log(source_default.dim(" 1. --api-key CLI option"));
70770
- console.log(source_default.dim(` 2. Active config scope: ${activeScope === "project" ? projectPath : userPath}`));
70771
- console.log(source_default.dim(` (project takes priority when present at cwd; user is ignored in that case)`));
70986
+ console.log(
70987
+ source_default.dim(` 2. Active config scope: ${activeScope === "project" ? projectPath : userPath}`)
70988
+ );
70989
+ console.log(
70990
+ source_default.dim(` (project takes priority when present at cwd; user is ignored in that case)`)
70991
+ );
70772
70992
  console.log(source_default.dim(" 3. .env / shell environment variables (process.env)"));
70773
70993
  console.log();
70774
70994
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeframe/cli",
3
- "version": "0.91.6",
3
+ "version": "0.91.8",
4
4
  "description": "VibeFrame CLI - natural language video editing from the terminal",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -183,8 +183,8 @@
183
183
  "tsx": "^4.21.0",
184
184
  "typescript": "^5.3.3",
185
185
  "vitest": "^1.2.2",
186
- "@vibeframe/ai-providers": "0.91.6",
187
- "@vibeframe/core": "0.91.6"
186
+ "@vibeframe/ai-providers": "0.91.8",
187
+ "@vibeframe/core": "0.91.8"
188
188
  },
189
189
  "engines": {
190
190
  "node": ">=20"