@vibeframe/cli 0.91.7 → 0.91.9

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 +401 -180
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -31792,7 +31792,7 @@ async function promptHidden(question, opts = {}) {
31792
31792
  }
31793
31793
  });
31794
31794
  }
31795
- async function promptSelect(_question, options, defaultIndex = 0) {
31795
+ async function promptSelect(_question, options, defaultIndex = 0, opts = {}) {
31796
31796
  const input = getTTYInputStream();
31797
31797
  if (typeof input.setRawMode === "function") {
31798
31798
  return new Promise((resolve64) => {
@@ -31827,6 +31827,12 @@ async function promptSelect(_question, options, defaultIndex = 0) {
31827
31827
  input.setRawMode(false);
31828
31828
  process.stdout.write("\n");
31829
31829
  process.exit(1);
31830
+ } else if (opts.backIndex !== void 0 && (char === "\x1B" || char === "\x1B[D")) {
31831
+ finished = true;
31832
+ input.setRawMode(false);
31833
+ input.removeListener("data", onData);
31834
+ process.stdout.write("\n");
31835
+ resolve64(opts.backIndex);
31830
31836
  } else if (char === "\x1B[A" || char === "k") {
31831
31837
  selected = (selected - 1 + options.length) % options.length;
31832
31838
  render();
@@ -31982,6 +31988,11 @@ async function promptMultiSelect(_question, options, defaultSelected = [], opts
31982
31988
  input.setRawMode(false);
31983
31989
  process.stdout.write("\n");
31984
31990
  process.exit(1);
31991
+ } else if (opts.backIndex !== void 0 && (char === "\x1B" || char === "\x1B[D")) {
31992
+ for (let i = 0; i < selected.length; i++) selected[i] = false;
31993
+ selected[opts.backIndex] = true;
31994
+ finished = true;
31995
+ finish();
31985
31996
  } else if (char === " ") {
31986
31997
  selected[cursor] = !selected[cursor];
31987
31998
  userToggled = true;
@@ -62962,7 +62973,7 @@ init_source();
62962
62973
  // package.json
62963
62974
  var package_default = {
62964
62975
  name: "@vibeframe/cli",
62965
- version: "0.91.7",
62976
+ version: "0.91.9",
62966
62977
  description: "VibeFrame CLI - natural language video editing from the terminal",
62967
62978
  private: false,
62968
62979
  license: "MIT",
@@ -69963,14 +69974,19 @@ var VALID_SCOPES = ["user", "project"];
69963
69974
  function parseScope(raw) {
69964
69975
  const v = String(raw ?? "user");
69965
69976
  if (!VALID_SCOPES.includes(v)) {
69966
- exitWithError(generalError(
69967
- `Invalid --scope: ${v}`,
69968
- `Must be one of: ${VALID_SCOPES.join(", ")}`
69969
- ));
69977
+ exitWithError(
69978
+ generalError(`Invalid --scope: ${v}`, `Must be one of: ${VALID_SCOPES.join(", ")}`)
69979
+ );
69970
69980
  }
69971
69981
  return v;
69972
69982
  }
69973
- 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(
69983
+ 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(
69984
+ "-v, --verbose",
69985
+ "With --show: include unset providers + Resolution order + Defaults block"
69986
+ ).option("--claude-code", "Show Claude Code integration guide").option("-y, --yes", "Non-interactive: write config without prompting (CI / devcontainer)").option(
69987
+ "--provider <id>",
69988
+ "Set the Agent LLM provider (claude | openai | gemini | xai | openrouter | ollama)"
69989
+ ).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(
69974
69990
  "--scope <scope>",
69975
69991
  "Where to save: 'user' (~/.vibeframe/config.yaml, shared) or 'project' (./.vibeframe/config.yaml, gitignored, this project only)",
69976
69992
  "user"
@@ -70020,10 +70036,12 @@ Exit codes (non-interactive):
70020
70036
  return;
70021
70037
  }
70022
70038
  if (!hasTTY()) {
70023
- exitWithError(generalError(
70024
- "Interactive setup requires a terminal.",
70025
- "Run 'vibe setup' directly from your terminal, or use 'vibe setup --yes --provider <id> --import-env' for CI."
70026
- ));
70039
+ exitWithError(
70040
+ generalError(
70041
+ "Interactive setup requires a terminal.",
70042
+ "Run 'vibe setup' directly from your terminal, or use 'vibe setup --yes --provider <id> --import-env' for CI."
70043
+ )
70044
+ );
70027
70045
  }
70028
70046
  try {
70029
70047
  await runSetupWizard(options.full, scope);
@@ -70040,24 +70058,50 @@ var AI_FEATURES = [
70040
70058
  desc: "generate + edit",
70041
70059
  defaultProvider: "OpenAI gpt-image-2 (Artificial Analysis #1, since v0.56)",
70042
70060
  alsoAvailable: "Gemini Nano Banana, Grok Imagine",
70043
- 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)" }],
70061
+ keys: [
70062
+ {
70063
+ configKey: "openai",
70064
+ envVar: "OPENAI_API_KEY",
70065
+ name: "OpenAI",
70066
+ url: "https://platform.openai.com/api-keys",
70067
+ what: "gpt-image-2 image generation + editing (also Whisper, Agent)"
70068
+ }
70069
+ ],
70044
70070
  providerChoices: [
70045
70071
  {
70046
70072
  label: "OpenAI gpt-image-2",
70047
70073
  desc: "recommended default, image generation + editing",
70048
- 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)" },
70074
+ key: {
70075
+ configKey: "openai",
70076
+ envVar: "OPENAI_API_KEY",
70077
+ name: "OpenAI",
70078
+ url: "https://platform.openai.com/api-keys",
70079
+ what: "gpt-image-2 image generation + editing (also Whisper, Agent)"
70080
+ },
70049
70081
  defaultFor: { kind: "image", value: "openai" }
70050
70082
  },
70051
70083
  {
70052
70084
  label: "Gemini",
70053
70085
  desc: "Google image generation + multimodal analysis",
70054
- key: { configKey: "google", envVar: "GOOGLE_API_KEY", name: "Google", url: "https://aistudio.google.com/apikey", what: "Gemini image generation and multimodal analysis" },
70086
+ key: {
70087
+ configKey: "google",
70088
+ envVar: "GOOGLE_API_KEY",
70089
+ name: "Google",
70090
+ url: "https://aistudio.google.com/apikey",
70091
+ what: "Gemini image generation and multimodal analysis"
70092
+ },
70055
70093
  defaultFor: { kind: "image", value: "gemini" }
70056
70094
  },
70057
70095
  {
70058
70096
  label: "Grok",
70059
70097
  desc: "xAI image generation",
70060
- key: { configKey: "xai", envVar: "XAI_API_KEY", name: "xAI", url: "https://console.x.ai/", what: "Grok image generation and Agent" },
70098
+ key: {
70099
+ configKey: "xai",
70100
+ envVar: "XAI_API_KEY",
70101
+ name: "xAI",
70102
+ url: "https://console.x.ai/",
70103
+ what: "Grok image generation and Agent"
70104
+ },
70061
70105
  defaultFor: { kind: "image", value: "grok" }
70062
70106
  }
70063
70107
  ],
@@ -70068,36 +70112,74 @@ var AI_FEATURES = [
70068
70112
  desc: "generate + extend",
70069
70113
  defaultProvider: "Seedance 2.0 via fal.ai (Artificial Analysis #2 t2v + i2v, since v0.57)",
70070
70114
  alsoAvailable: "Grok Imagine, Kling, Runway Gen-4.5, Google Veo",
70071
- 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" }],
70115
+ keys: [
70116
+ {
70117
+ configKey: "fal",
70118
+ envVar: "FAL_KEY",
70119
+ name: "Seedance 2.0 (via fal.ai)",
70120
+ url: "https://fal.ai/dashboard/keys",
70121
+ what: "ByteDance Seedance 2.0 text-to-video and image-to-video"
70122
+ }
70123
+ ],
70072
70124
  providerChoices: [
70073
70125
  {
70074
70126
  label: "Seedance 2.0 via fal.ai",
70075
70127
  desc: "recommended default, text-to-video + image-to-video",
70076
- 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" },
70128
+ key: {
70129
+ configKey: "fal",
70130
+ envVar: "FAL_KEY",
70131
+ name: "Seedance 2.0 (via fal.ai)",
70132
+ url: "https://fal.ai/dashboard/keys",
70133
+ what: "ByteDance Seedance 2.0 text-to-video and image-to-video"
70134
+ },
70077
70135
  defaultFor: { kind: "video", value: "seedance" }
70078
70136
  },
70079
70137
  {
70080
70138
  label: "Grok",
70081
70139
  desc: "xAI video generation with audio",
70082
- key: { configKey: "xai", envVar: "XAI_API_KEY", name: "xAI", url: "https://console.x.ai/", what: "Grok video generation and Agent" },
70140
+ key: {
70141
+ configKey: "xai",
70142
+ envVar: "XAI_API_KEY",
70143
+ name: "xAI",
70144
+ url: "https://console.x.ai/",
70145
+ what: "Grok video generation and Agent"
70146
+ },
70083
70147
  defaultFor: { kind: "video", value: "grok" }
70084
70148
  },
70085
70149
  {
70086
70150
  label: "Kling",
70087
70151
  desc: "Kling v2.5/v3 video generation",
70088
- key: { configKey: "kling", envVar: "KLING_API_KEY", name: "Kling", url: "https://platform.klingai.com/", what: "Kling video generation" },
70152
+ key: {
70153
+ configKey: "kling",
70154
+ envVar: "KLING_API_KEY",
70155
+ name: "Kling",
70156
+ url: "https://platform.klingai.com/",
70157
+ what: "Kling video generation"
70158
+ },
70089
70159
  defaultFor: { kind: "video", value: "kling" }
70090
70160
  },
70091
70161
  {
70092
70162
  label: "Runway",
70093
70163
  desc: "Runway Gen-4.5 video generation",
70094
- key: { configKey: "runway", envVar: "RUNWAY_API_SECRET", name: "Runway", url: "https://app.runwayml.com/settings/api-keys", what: "Runway Gen-4.5 video generation" },
70164
+ key: {
70165
+ configKey: "runway",
70166
+ envVar: "RUNWAY_API_SECRET",
70167
+ name: "Runway",
70168
+ url: "https://app.runwayml.com/settings/api-keys",
70169
+ what: "Runway Gen-4.5 video generation"
70170
+ },
70095
70171
  defaultFor: { kind: "video", value: "runway" }
70096
70172
  },
70097
70173
  {
70098
70174
  label: "Veo",
70099
70175
  desc: "Google Veo video generation",
70100
- key: { configKey: "google", envVar: "GOOGLE_API_KEY", name: "Google", url: "https://aistudio.google.com/apikey", what: "Google Veo video generation" },
70176
+ key: {
70177
+ configKey: "google",
70178
+ envVar: "GOOGLE_API_KEY",
70179
+ name: "Google",
70180
+ url: "https://aistudio.google.com/apikey",
70181
+ what: "Google Veo video generation"
70182
+ },
70101
70183
  defaultFor: { kind: "video", value: "veo" }
70102
70184
  }
70103
70185
  ],
@@ -70108,12 +70190,26 @@ var AI_FEATURES = [
70108
70190
  desc: "TTS, SFX, music, voice clone",
70109
70191
  defaultProvider: "ElevenLabs (paid, premium quality) \u2014 falls back to local Kokoro when no key (free, since v0.54)",
70110
70192
  alsoAvailable: "Replicate MusicGen (music only)",
70111
- 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)" }],
70193
+ keys: [
70194
+ {
70195
+ configKey: "elevenlabs",
70196
+ envVar: "ELEVENLABS_API_KEY",
70197
+ name: "ElevenLabs",
70198
+ url: "https://elevenlabs.io/app/settings/api-keys",
70199
+ what: "Text-to-speech, sound effects, music, voice cloning (skip to use local Kokoro)"
70200
+ }
70201
+ ],
70112
70202
  providerChoices: [
70113
70203
  {
70114
70204
  label: "ElevenLabs",
70115
70205
  desc: "premium TTS, SFX, music, voice clone",
70116
- 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" }
70206
+ key: {
70207
+ configKey: "elevenlabs",
70208
+ envVar: "ELEVENLABS_API_KEY",
70209
+ name: "ElevenLabs",
70210
+ url: "https://elevenlabs.io/app/settings/api-keys",
70211
+ what: "Text-to-speech, sound effects, music, voice cloning"
70212
+ }
70117
70213
  },
70118
70214
  {
70119
70215
  label: "Kokoro local",
@@ -70123,7 +70219,13 @@ var AI_FEATURES = [
70123
70219
  {
70124
70220
  label: "Replicate MusicGen",
70125
70221
  desc: "background music generation",
70126
- key: { configKey: "replicate", envVar: "REPLICATE_API_TOKEN", name: "Replicate", url: "https://replicate.com/account/api-tokens", what: "MusicGen background music" }
70222
+ key: {
70223
+ configKey: "replicate",
70224
+ envVar: "REPLICATE_API_TOKEN",
70225
+ name: "Replicate",
70226
+ url: "https://replicate.com/account/api-tokens",
70227
+ what: "MusicGen background music"
70228
+ }
70127
70229
  }
70128
70230
  ],
70129
70231
  tryCommand: 'vibe generate speech "Hello world" -o hello.mp3'
@@ -70134,8 +70236,20 @@ var AI_FEATURES = [
70134
70236
  defaultProvider: "Whisper (transcription) + Claude (reasoning)",
70135
70237
  alsoAvailable: "",
70136
70238
  keys: [
70137
- { configKey: "openai", envVar: "OPENAI_API_KEY", name: "OpenAI", url: "https://platform.openai.com/api-keys", what: "Whisper transcription (captions, jump-cut)" },
70138
- { configKey: "anthropic", envVar: "ANTHROPIC_API_KEY", name: "Anthropic", url: "https://console.anthropic.com/settings/keys", what: "Claude (color grade, reframe, motion graphics)" }
70239
+ {
70240
+ configKey: "openai",
70241
+ envVar: "OPENAI_API_KEY",
70242
+ name: "OpenAI",
70243
+ url: "https://platform.openai.com/api-keys",
70244
+ what: "Whisper transcription (captions, jump-cut)"
70245
+ },
70246
+ {
70247
+ configKey: "anthropic",
70248
+ envVar: "ANTHROPIC_API_KEY",
70249
+ name: "Anthropic",
70250
+ url: "https://console.anthropic.com/settings/keys",
70251
+ what: "Claude (color grade, reframe, motion graphics)"
70252
+ }
70139
70253
  ],
70140
70254
  tryCommand: "vibe edit caption video.mp4 -o captioned.mp4"
70141
70255
  }
@@ -70166,6 +70280,14 @@ function isProviderChoiceConfigured(config2, choice) {
70166
70280
  }
70167
70281
  return false;
70168
70282
  }
70283
+ function isFeatureConfigured(config2, feature) {
70284
+ if (feature.providerChoices?.some((choice) => isProviderChoiceConfigured(config2, choice))) {
70285
+ return true;
70286
+ }
70287
+ return feature.keys.some(
70288
+ (keyDef) => Boolean(config2.providers[keyDef.configKey])
70289
+ );
70290
+ }
70169
70291
  function mergeSelectedFeatures(current, next) {
70170
70292
  const merged = [...current];
70171
70293
  for (const feature of next) {
@@ -70184,10 +70306,12 @@ async function runNonInteractiveSetup(opts) {
70184
70306
  const changes = [];
70185
70307
  if (opts.provider) {
70186
70308
  if (!VALID_LLM_PROVIDERS.includes(opts.provider)) {
70187
- exitWithError(generalError(
70188
- `Invalid --provider: ${opts.provider}`,
70189
- `Must be one of: ${VALID_LLM_PROVIDERS.join(", ")}`
70190
- ));
70309
+ exitWithError(
70310
+ generalError(
70311
+ `Invalid --provider: ${opts.provider}`,
70312
+ `Must be one of: ${VALID_LLM_PROVIDERS.join(", ")}`
70313
+ )
70314
+ );
70191
70315
  }
70192
70316
  if (config2.llm.provider !== opts.provider) {
70193
70317
  config2.llm.provider = opts.provider;
@@ -70254,7 +70378,11 @@ async function runNonInteractiveSetup(opts) {
70254
70378
  }
70255
70379
  if (failures > 0) {
70256
70380
  console.error();
70257
- console.error(source_default.red(`Verification failed: ${failures} key${failures === 1 ? "" : "s"} returned non-2xx.`));
70381
+ console.error(
70382
+ source_default.red(
70383
+ `Verification failed: ${failures} key${failures === 1 ? "" : "s"} returned non-2xx.`
70384
+ )
70385
+ );
70258
70386
  process.exit(7);
70259
70387
  }
70260
70388
  }
@@ -70263,15 +70391,11 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70263
70391
  console.log();
70264
70392
  const cfgPath = getConfigPath(scope).replace(homedir5(), "~");
70265
70393
  const scopeNote = scope === "project" ? "applies to this project only \xB7 add .vibeframe/ to .gitignore" : "applies to every project for this user";
70266
- console.log(
70267
- source_default.bold.magenta("VibeFrame Setup") + source_default.bold(` \u2014 ${scope} scope`)
70268
- );
70394
+ console.log(source_default.bold.magenta("VibeFrame Setup") + source_default.bold(` \u2014 ${scope} scope`));
70269
70395
  console.log(source_default.dim(`${cfgPath} \xB7 ${scopeNote}`));
70270
70396
  if (scope === "user") {
70271
70397
  console.log(
70272
- source_default.dim(
70273
- "Tip: for per-project keys, cd into a project and run: vibe setup --scope project"
70274
- )
70398
+ source_default.dim("Tip: for per-project keys, cd into a project and run: vibe setup --scope project")
70275
70399
  );
70276
70400
  }
70277
70401
  console.log(source_default.dim("\u2500".repeat(40)));
@@ -70312,10 +70436,34 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70312
70436
  if (topIndex === 2) {
70313
70437
  config2.llm.provider = "claude";
70314
70438
  const pipelineKeys = [
70315
- { configKey: "anthropic", envVar: "ANTHROPIC_API_KEY", name: "Anthropic", url: "https://console.anthropic.com/settings/keys", what: "Claude \u2014 storyboard generation + reasoning" },
70316
- { 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" },
70317
- { 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" },
70318
- { 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)" }
70439
+ {
70440
+ configKey: "anthropic",
70441
+ envVar: "ANTHROPIC_API_KEY",
70442
+ name: "Anthropic",
70443
+ url: "https://console.anthropic.com/settings/keys",
70444
+ what: "Claude \u2014 storyboard generation + reasoning"
70445
+ },
70446
+ {
70447
+ configKey: "openai",
70448
+ envVar: "OPENAI_API_KEY",
70449
+ name: "OpenAI",
70450
+ url: "https://platform.openai.com/api-keys",
70451
+ what: "gpt-image-2 image generation (default since v0.56) + Whisper word-level transcribe"
70452
+ },
70453
+ {
70454
+ configKey: "fal",
70455
+ envVar: "FAL_KEY",
70456
+ name: "fal.ai",
70457
+ url: "https://fal.ai/dashboard/keys",
70458
+ what: "Seedance 2.0 \u2014 video generation, default since v0.57"
70459
+ },
70460
+ {
70461
+ configKey: "elevenlabs",
70462
+ envVar: "ELEVENLABS_API_KEY",
70463
+ name: "ElevenLabs",
70464
+ url: "https://elevenlabs.io/app/settings/api-keys",
70465
+ what: "Text-to-speech narration + music (skip to use local Kokoro)"
70466
+ }
70319
70467
  ];
70320
70468
  console.log(source_default.dim("2. API keys"));
70321
70469
  console.log(source_default.bold("Pipeline requires these API keys:"));
@@ -70323,10 +70471,19 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70323
70471
  console.log();
70324
70472
  await collectKeys(config2, pipelineKeys);
70325
70473
  await saveConfig(config2, { scope });
70326
- await completeOrContinue(config2, "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format", [], scope);
70474
+ await completeOrContinue(
70475
+ config2,
70476
+ "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format",
70477
+ [],
70478
+ scope
70479
+ );
70327
70480
  return;
70328
70481
  }
70329
70482
  const result = await runAIFeaturesSetup(config2, scope);
70483
+ if (result.back) {
70484
+ await completeOrContinue(config2, "vibe --help", [], scope);
70485
+ return;
70486
+ }
70330
70487
  await saveConfig(config2, { scope });
70331
70488
  await completeOrContinue(config2, result.tryCommand, result.selectedFeatures, scope);
70332
70489
  }
@@ -70346,6 +70503,10 @@ async function completeOrContinue(config2, tryCommand, selectedFeatures, scope)
70346
70503
  console.log();
70347
70504
  if (action === 0) {
70348
70505
  const result = await runAIFeaturesSetup(config2, scope);
70506
+ if (result.back) {
70507
+ await completeOrContinue(config2, tryCommand, selectedFeatures, scope);
70508
+ return;
70509
+ }
70349
70510
  const mergedFeatures = mergeSelectedFeatures(selectedFeatures, result.selectedFeatures);
70350
70511
  const mergedTryCommand = selectedFeatures.length > 0 ? tryCommand : result.tryCommand;
70351
70512
  await saveConfig(config2, { scope });
@@ -70361,142 +70522,176 @@ async function completeOrContinue(config2, tryCommand, selectedFeatures, scope)
70361
70522
  await showComplete(config2, tryCommand, selectedFeatures, scope);
70362
70523
  }
70363
70524
  async function runAIFeaturesSetup(config2, _scope) {
70364
- console.log(source_default.dim("2. Features"));
70365
- console.log(source_default.bold("Which AI features do you need?"));
70366
- 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.`));
70367
- console.log(source_default.dim(" Shortcut: enter alone picks only the highlighted feature."));
70368
- console.log();
70369
- const featureLabels = AI_FEATURES.map((f) => {
70370
- const keyCount = f.keys.length;
70371
- const tag = source_default.dim(`${keyCount} key${keyCount > 1 ? "s" : ""}`);
70372
- return `${f.label} ${source_default.dim(`(${f.desc})`)} ${tag}`;
70373
- });
70374
- const picked = await promptMultiSelect(
70375
- source_default.cyan(" Pick (e.g. 1,3 or 'all'): "),
70376
- featureLabels,
70377
- [],
70378
- { pickFocusedOnEnter: true }
70379
- );
70380
- const selectedFeatures = picked.map((i) => AI_FEATURES[i]);
70381
- console.log();
70382
- if (selectedFeatures.length === 0) {
70383
- console.log(source_default.dim(" No features selected. You can re-run setup anytime."));
70525
+ featureSelection: for (; ; ) {
70526
+ console.log(source_default.dim("2. Features"));
70527
+ console.log(source_default.bold("Which AI features do you need?"));
70528
+ console.log(
70529
+ source_default.dim(
70530
+ ` ${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.`
70531
+ )
70532
+ );
70533
+ console.log(source_default.dim(" Shortcut: enter alone picks only the highlighted feature."));
70534
+ console.log(
70535
+ source_default.dim(
70536
+ ` Select ${source_default.bold("Back")} or press ${source_default.bold("Esc/\u2190")} to return to the setup checkpoint.`
70537
+ )
70538
+ );
70384
70539
  console.log();
70385
- return { tryCommand: "vibe --help", selectedFeatures: [] };
70386
- }
70387
- const plannedKeys = /* @__PURE__ */ new Map();
70388
- console.log(source_default.dim("3. Providers"));
70389
- console.log(source_default.bold("Choose providers for each selected feature"));
70390
- 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.`));
70391
- console.log();
70392
- for (const feature of selectedFeatures) {
70393
- const keysForFeature = [];
70394
- if (feature.providerChoices && feature.providerChoices.length > 0) {
70395
- console.log(source_default.bold.cyan(` ${feature.label}`));
70396
- console.log(source_default.dim(` Default path: ${feature.defaultProvider}`));
70397
- if (feature.alsoAvailable) {
70398
- console.log(source_default.dim(` Alternatives: ${feature.alsoAvailable}`));
70399
- }
70540
+ const backIndex = AI_FEATURES.length;
70541
+ const featureLabels = [
70542
+ ...AI_FEATURES.map((f) => {
70543
+ const keyCount = f.keys.length;
70544
+ const tag = source_default.dim(`${keyCount} key${keyCount > 1 ? "s" : ""}`);
70545
+ return `${f.label} ${source_default.dim(`(${f.desc})`)} ${tag}`;
70546
+ }),
70547
+ `Back ${source_default.dim("(return to setup checkpoint)")}`
70548
+ ];
70549
+ const configuredFeatures = AI_FEATURES.map((feature) => isFeatureConfigured(config2, feature));
70550
+ const picked = await promptMultiSelect(
70551
+ source_default.cyan(" Pick (e.g. 1,3 or 'all'): "),
70552
+ featureLabels,
70553
+ [...configuredFeatures, false],
70554
+ { pickFocusedOnEnter: true, backIndex }
70555
+ );
70556
+ if (picked.includes(backIndex)) {
70400
70557
  console.log();
70401
- const defaultSelected = feature.providerChoices.map(
70402
- (choice) => isProviderChoiceConfigured(config2, choice)
70403
- );
70404
- const providerLabels = feature.providerChoices.map((choice) => {
70405
- const keyHint = choice.keyless ? source_default.dim("no key") : choice.key ? source_default.dim(choice.key.envVar) : source_default.dim("no key");
70406
- const defaultHint = choice === feature.providerChoices?.[0] ? source_default.dim("recommended default") : "";
70407
- return [
70408
- choice.label,
70409
- defaultHint,
70410
- source_default.dim(`- ${choice.desc}`),
70411
- keyHint
70412
- ].filter(Boolean).join(" ");
70413
- });
70414
- const pickedProviders = await promptMultiSelect(
70415
- source_default.cyan(" Providers (arrow + enter picks one, space adds more): "),
70416
- providerLabels,
70417
- defaultSelected,
70418
- { pickFocusedOnEnter: true, preserveDefaultSelectionOnEnter: true }
70419
- );
70420
- const selectedChoices = pickedProviders.map((i) => feature.providerChoices[i]);
70421
- const defaultChoice = selectedChoices.find((choice) => choice.defaultFor);
70422
- if (defaultChoice) {
70423
- applyProviderDefault(config2, defaultChoice);
70424
- }
70425
- for (const choice of selectedChoices) {
70426
- if (choice.key) addUniqueKey(keysForFeature, choice.key);
70427
- }
70428
- if (selectedChoices.some((choice) => choice.keyless)) {
70429
- console.log(source_default.dim(" No API key needed for selected local provider(s)."));
70430
- }
70558
+ return { tryCommand: "vibe --help", selectedFeatures: [], back: true };
70559
+ }
70560
+ const selectedFeatures = picked.filter((i) => i < AI_FEATURES.length).map((i) => AI_FEATURES[i]);
70561
+ console.log();
70562
+ if (selectedFeatures.length === 0) {
70563
+ console.log(source_default.dim(" No features selected. You can re-run setup anytime."));
70431
70564
  console.log();
70432
- } else {
70433
- for (const keyDef of feature.keys) {
70434
- addUniqueKey(keysForFeature, keyDef);
70435
- }
70565
+ return { tryCommand: "vibe --help", selectedFeatures: [] };
70436
70566
  }
70437
- plannedKeys.set(feature.label, keysForFeature);
70438
- }
70439
- const needsKeys = [...plannedKeys.values()].some((keys) => keys.length > 0);
70440
- if (needsKeys) {
70441
- console.log(source_default.dim("4. API keys"));
70442
- console.log(source_default.bold("API Keys"));
70443
- console.log(source_default.dim(" Saved locally, never shared. Press Enter to skip."));
70567
+ const plannedKeys = /* @__PURE__ */ new Map();
70568
+ console.log(source_default.dim("3. Providers"));
70569
+ console.log(source_default.bold("Choose providers for each selected feature"));
70570
+ console.log(
70571
+ source_default.dim(
70572
+ ` Recommended default is highlighted. Press ${source_default.bold("enter")} to pick the highlighted provider, ${source_default.bold("space")} to choose multiple, or ${source_default.bold("Esc/\u2190")} to go back.`
70573
+ )
70574
+ );
70444
70575
  console.log();
70445
- const collectedKeys = /* @__PURE__ */ new Set();
70446
70576
  for (const feature of selectedFeatures) {
70447
- const keysForFeature = plannedKeys.get(feature.label) ?? [];
70448
- if (keysForFeature.length === 0) {
70449
- continue;
70450
- }
70451
- console.log(source_default.bold.cyan(` ${feature.label}`));
70452
- console.log(source_default.dim(` Default: ${feature.defaultProvider}`));
70453
- if (feature.alsoAvailable) {
70454
- console.log(source_default.dim(` Also available: ${feature.alsoAvailable}`));
70577
+ const keysForFeature = [];
70578
+ if (feature.providerChoices && feature.providerChoices.length > 0) {
70579
+ console.log(source_default.bold.cyan(` ${feature.label}`));
70580
+ console.log(source_default.dim(` Default path: ${feature.defaultProvider}`));
70581
+ if (feature.alsoAvailable) {
70582
+ console.log(source_default.dim(` Alternatives: ${feature.alsoAvailable}`));
70583
+ }
70584
+ console.log();
70585
+ const defaultSelected = feature.providerChoices.map(
70586
+ (choice) => isProviderChoiceConfigured(config2, choice)
70587
+ );
70588
+ const providerLabels = feature.providerChoices.map((choice) => {
70589
+ const keyHint = choice.keyless ? source_default.dim("no key") : choice.key ? source_default.dim(choice.key.envVar) : source_default.dim("no key");
70590
+ const defaultHint = choice === feature.providerChoices?.[0] ? source_default.dim("recommended default") : "";
70591
+ return [choice.label, defaultHint, source_default.dim(`- ${choice.desc}`), keyHint].filter(Boolean).join(" ");
70592
+ });
70593
+ const backProviderIndex = providerLabels.length;
70594
+ const pickedProviders = await promptMultiSelect(
70595
+ source_default.cyan(" Providers (arrow + enter picks one, space adds more): "),
70596
+ [...providerLabels, `Back ${source_default.dim("(choose different features)")}`],
70597
+ [...defaultSelected, false],
70598
+ {
70599
+ pickFocusedOnEnter: true,
70600
+ preserveDefaultSelectionOnEnter: true,
70601
+ backIndex: backProviderIndex
70602
+ }
70603
+ );
70604
+ if (pickedProviders.includes(backProviderIndex)) {
70605
+ console.log();
70606
+ continue featureSelection;
70607
+ }
70608
+ const selectedChoices = pickedProviders.filter((i) => i < feature.providerChoices.length).map((i) => feature.providerChoices[i]);
70609
+ const defaultChoice = selectedChoices.find((choice) => choice.defaultFor);
70610
+ if (defaultChoice) {
70611
+ applyProviderDefault(config2, defaultChoice);
70612
+ }
70613
+ for (const choice of selectedChoices) {
70614
+ if (choice.key) addUniqueKey(keysForFeature, choice.key);
70615
+ }
70616
+ if (selectedChoices.some((choice) => choice.keyless)) {
70617
+ console.log(source_default.dim(" No API key needed for selected local provider(s)."));
70618
+ }
70619
+ console.log();
70620
+ } else {
70621
+ for (const keyDef of feature.keys) {
70622
+ addUniqueKey(keysForFeature, keyDef);
70623
+ }
70455
70624
  }
70625
+ plannedKeys.set(feature.label, keysForFeature);
70626
+ }
70627
+ const needsKeys = [...plannedKeys.values()].some((keys) => keys.length > 0);
70628
+ if (needsKeys) {
70629
+ console.log(source_default.dim("4. API keys"));
70630
+ console.log(source_default.bold("API Keys"));
70631
+ console.log(source_default.dim(" Saved locally, never shared. Press Enter to skip."));
70456
70632
  console.log();
70457
- for (const keyDef of keysForFeature) {
70458
- if (collectedKeys.has(keyDef.configKey)) {
70459
- console.log(` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} (already set above)`);
70633
+ const collectedKeys = /* @__PURE__ */ new Set();
70634
+ for (const feature of selectedFeatures) {
70635
+ const keysForFeature = plannedKeys.get(feature.label) ?? [];
70636
+ if (keysForFeature.length === 0) {
70460
70637
  continue;
70461
70638
  }
70462
- loadEnv();
70463
- const configValue = config2.providers[keyDef.configKey];
70464
- const envValue = process.env[keyDef.envVar];
70465
- if (configValue || envValue) {
70466
- const value = configValue || envValue;
70467
- const source = configValue ? "config" : ".env";
70468
- console.log(` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(value)} ${source_default.dim(`(${source})`)}`);
70469
- collectedKeys.add(keyDef.configKey);
70470
- continue;
70639
+ console.log(source_default.bold.cyan(` ${feature.label}`));
70640
+ console.log(source_default.dim(` Default: ${feature.defaultProvider}`));
70641
+ if (feature.alsoAvailable) {
70642
+ console.log(source_default.dim(` Also available: ${feature.alsoAvailable}`));
70471
70643
  }
70472
- console.log(source_default.dim(` ${keyDef.what}`));
70473
- console.log(source_default.dim(` Get key: ${keyDef.url} [o] open in browser`));
70474
- const newKey = await promptHidden(
70475
- source_default.cyan(` ${keyDef.name.padEnd(14)} ${source_default.dim(keyDef.envVar)}: `),
70476
- { openHotkeyUrl: keyDef.url }
70477
- );
70478
- if (newKey.trim()) {
70479
- const trimmed = newKey.trim();
70480
- config2.providers[keyDef.configKey] = trimmed;
70481
- const fmt = validateKeyFormat(keyDef.configKey, trimmed);
70482
- if (!fmt.ok && fmt.expected) {
70483
- console.log(` ${source_default.yellow("\u26A0")} Saved, but format looks unusual ${source_default.dim(`(expected ${fmt.expected})`)}`);
70644
+ console.log();
70645
+ for (const keyDef of keysForFeature) {
70646
+ if (collectedKeys.has(keyDef.configKey)) {
70647
+ console.log(` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} (already set above)`);
70648
+ continue;
70649
+ }
70650
+ loadEnv();
70651
+ const configValue = config2.providers[keyDef.configKey];
70652
+ const envValue = process.env[keyDef.envVar];
70653
+ if (configValue || envValue) {
70654
+ const value = configValue || envValue;
70655
+ const source = configValue ? "config" : ".env";
70656
+ console.log(
70657
+ ` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(value)} ${source_default.dim(`(${source})`)}`
70658
+ );
70659
+ collectedKeys.add(keyDef.configKey);
70660
+ continue;
70661
+ }
70662
+ console.log(source_default.dim(` ${keyDef.what}`));
70663
+ console.log(source_default.dim(` Get key: ${keyDef.url} [o] open in browser`));
70664
+ const newKey = await promptHidden(
70665
+ source_default.cyan(` ${keyDef.name.padEnd(14)} ${source_default.dim(keyDef.envVar)}: `),
70666
+ { openHotkeyUrl: keyDef.url }
70667
+ );
70668
+ if (newKey.trim()) {
70669
+ const trimmed = newKey.trim();
70670
+ config2.providers[keyDef.configKey] = trimmed;
70671
+ const fmt = validateKeyFormat(keyDef.configKey, trimmed);
70672
+ if (!fmt.ok && fmt.expected) {
70673
+ console.log(
70674
+ ` ${source_default.yellow("\u26A0")} Saved, but format looks unusual ${source_default.dim(`(expected ${fmt.expected})`)}`
70675
+ );
70676
+ } else {
70677
+ console.log(` ${source_default.green("\u2713")} Saved`);
70678
+ }
70679
+ collectedKeys.add(keyDef.configKey);
70484
70680
  } else {
70485
- console.log(` ${source_default.green("\u2713")} Saved`);
70681
+ console.log(
70682
+ ` ${source_default.yellow("\u26A0")} Skipped ${source_default.dim(`(set ${keyDef.envVar} in .env later)`)}`
70683
+ );
70486
70684
  }
70487
- collectedKeys.add(keyDef.configKey);
70488
- } else {
70489
- console.log(` ${source_default.yellow("\u26A0")} Skipped ${source_default.dim(`(set ${keyDef.envVar} in .env later)`)}`);
70490
70685
  }
70686
+ console.log();
70491
70687
  }
70688
+ } else {
70689
+ console.log(source_default.dim("4. API keys"));
70690
+ console.log(source_default.dim(" No API keys needed for the selected provider(s)."));
70492
70691
  console.log();
70493
70692
  }
70494
- } else {
70495
- console.log(source_default.dim("4. API keys"));
70496
- console.log(source_default.dim(" No API keys needed for the selected provider(s)."));
70497
- console.log();
70693
+ return { tryCommand: selectedFeatures[0].tryCommand, selectedFeatures };
70498
70694
  }
70499
- return { tryCommand: selectedFeatures[0].tryCommand, selectedFeatures };
70500
70695
  }
70501
70696
  async function collectKeys(config2, keys) {
70502
70697
  loadEnv();
@@ -70504,11 +70699,15 @@ async function collectKeys(config2, keys) {
70504
70699
  const configValue = config2.providers[keyDef.configKey];
70505
70700
  const envValue = process.env[keyDef.envVar];
70506
70701
  if (configValue) {
70507
- console.log(` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(configValue)} ${source_default.dim("(config)")}`);
70702
+ console.log(
70703
+ ` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(configValue)} ${source_default.dim("(config)")}`
70704
+ );
70508
70705
  continue;
70509
70706
  }
70510
70707
  if (envValue) {
70511
- console.log(` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(envValue)} ${source_default.dim("(.env)")}`);
70708
+ console.log(
70709
+ ` ${source_default.green("\u2713")} ${keyDef.name.padEnd(14)} ${maskApiKey(envValue)} ${source_default.dim("(.env)")}`
70710
+ );
70512
70711
  continue;
70513
70712
  }
70514
70713
  console.log(source_default.dim(` ${keyDef.what}`));
@@ -70522,12 +70721,16 @@ async function collectKeys(config2, keys) {
70522
70721
  config2.providers[keyDef.configKey] = trimmed;
70523
70722
  const fmt = validateKeyFormat(keyDef.configKey, trimmed);
70524
70723
  if (!fmt.ok && fmt.expected) {
70525
- console.log(` ${source_default.yellow("\u26A0")} Saved, but format looks unusual ${source_default.dim(`(expected ${fmt.expected})`)}`);
70724
+ console.log(
70725
+ ` ${source_default.yellow("\u26A0")} Saved, but format looks unusual ${source_default.dim(`(expected ${fmt.expected})`)}`
70726
+ );
70526
70727
  } else {
70527
70728
  console.log(` ${source_default.green("\u2713")} Saved`);
70528
70729
  }
70529
70730
  } else {
70530
- console.log(` ${source_default.yellow("\u26A0")} Skipped ${source_default.dim(`(set ${keyDef.envVar} in .env later)`)}`);
70731
+ console.log(
70732
+ ` ${source_default.yellow("\u26A0")} Skipped ${source_default.dim(`(set ${keyDef.envVar} in .env later)`)}`
70733
+ );
70531
70734
  }
70532
70735
  }
70533
70736
  console.log();
@@ -70564,37 +70767,41 @@ async function runCustomSetup(config2, scope = "user", opts = {}) {
70564
70767
  for (const p of allProviders) {
70565
70768
  const existing = config2.providers[p.key];
70566
70769
  if (existing) {
70567
- console.log(` ${source_default.green("\u2713")} ${p.name.padEnd(12)} ${maskApiKey(existing)} ${source_default.dim(p.desc)}`);
70770
+ console.log(
70771
+ ` ${source_default.green("\u2713")} ${p.name.padEnd(12)} ${maskApiKey(existing)} ${source_default.dim(p.desc)}`
70772
+ );
70568
70773
  const change = await promptConfirm(source_default.cyan(" Update?"), false);
70569
70774
  if (change) {
70570
70775
  console.log(source_default.dim(` Get key: ${p.url} [o] open in browser`));
70571
- const newKey = await promptHidden(
70572
- source_default.cyan(" New key: "),
70573
- { openHotkeyUrl: p.url }
70574
- );
70776
+ const newKey = await promptHidden(source_default.cyan(" New key: "), { openHotkeyUrl: p.url });
70575
70777
  if (newKey.trim()) {
70576
70778
  const trimmed = newKey.trim();
70577
70779
  config2.providers[p.key] = trimmed;
70578
70780
  const fmt = validateKeyFormat(p.key, trimmed);
70579
70781
  if (!fmt.ok && fmt.expected) {
70580
- console.log(source_default.yellow(` \u26A0 Updated, but format looks unusual (expected ${fmt.expected})`));
70782
+ console.log(
70783
+ source_default.yellow(` \u26A0 Updated, but format looks unusual (expected ${fmt.expected})`)
70784
+ );
70581
70785
  } else {
70582
70786
  console.log(source_default.green(" \u2713 Updated"));
70583
70787
  }
70584
70788
  }
70585
70789
  }
70586
70790
  } else {
70587
- console.log(source_default.dim(` ${source_default.dim("\u25CB")} ${p.name.padEnd(12)} ${source_default.dim(p.desc)} Get key: ${p.url} [o] open`));
70588
- const newKey = await promptHidden(
70589
- source_default.cyan(` ${p.env}: `),
70590
- { openHotkeyUrl: p.url }
70791
+ console.log(
70792
+ source_default.dim(
70793
+ ` ${source_default.dim("\u25CB")} ${p.name.padEnd(12)} ${source_default.dim(p.desc)} Get key: ${p.url} [o] open`
70794
+ )
70591
70795
  );
70796
+ const newKey = await promptHidden(source_default.cyan(` ${p.env}: `), { openHotkeyUrl: p.url });
70592
70797
  if (newKey.trim()) {
70593
70798
  const trimmed = newKey.trim();
70594
70799
  config2.providers[p.key] = trimmed;
70595
70800
  const fmt = validateKeyFormat(p.key, trimmed);
70596
70801
  if (!fmt.ok && fmt.expected) {
70597
- console.log(` ${source_default.yellow("\u26A0")} Saved, but format looks unusual ${source_default.dim(`(expected ${fmt.expected})`)}`);
70802
+ console.log(
70803
+ ` ${source_default.yellow("\u26A0")} Saved, but format looks unusual ${source_default.dim(`(expected ${fmt.expected})`)}`
70804
+ );
70598
70805
  } else {
70599
70806
  console.log(` ${source_default.green("\u2713")} Saved`);
70600
70807
  }
@@ -70631,14 +70838,20 @@ async function showComplete(config2, defaultTryCommand, features = [], scope = "
70631
70838
  }
70632
70839
  console.log();
70633
70840
  console.log(source_default.bold(" Next steps:"));
70634
- console.log(source_default.dim(" cd <project>; vibe init Scaffold AGENTS.md / CLAUDE.md / .env.example (project scope)"));
70841
+ console.log(
70842
+ source_default.dim(
70843
+ " cd <project>; vibe init Scaffold AGENTS.md / CLAUDE.md / .env.example (project scope)"
70844
+ )
70845
+ );
70635
70846
  const hostDetected = detectedAgentHosts().length > 0;
70636
70847
  for (const w of listWalkthroughs()) {
70637
70848
  const cmd = `vibe walkthrough ${w.topic}`.padEnd(26);
70638
70849
  const tag = hostDetected && w.topic === "scene" ? source_default.cyan(" (recommended)") : "";
70639
70850
  console.log(source_default.dim(` ${cmd}${w.summary}${tag}`));
70640
70851
  }
70641
- console.log(source_default.dim(" vibe doctor --test-keys Live-check each provider key against its API"));
70852
+ console.log(
70853
+ source_default.dim(" vibe doctor --test-keys Live-check each provider key against its API")
70854
+ );
70642
70855
  console.log(source_default.dim(" vibe doctor Check system health + available commands"));
70643
70856
  console.log(source_default.dim(" vibe schema --list Discover every command"));
70644
70857
  console.log(source_default.dim(" vibe setup Re-run user-scope setup anytime"));
@@ -70773,7 +70986,11 @@ async function showConfig(opts = { verbose: false }) {
70773
70986
  }
70774
70987
  }
70775
70988
  if (!verbose && unsetCount > 0) {
70776
- console.log(source_default.dim(` (${unsetCount} provider${unsetCount === 1 ? "" : "s"} unset \u2014 run with --verbose to list)`));
70989
+ console.log(
70990
+ source_default.dim(
70991
+ ` (${unsetCount} provider${unsetCount === 1 ? "" : "s"} unset \u2014 run with --verbose to list)`
70992
+ )
70993
+ );
70777
70994
  }
70778
70995
  console.log();
70779
70996
  if (verbose) {
@@ -70785,8 +71002,12 @@ async function showConfig(opts = { verbose: false }) {
70785
71002
  }
70786
71003
  console.log(source_default.bold("Resolution order:"));
70787
71004
  console.log(source_default.dim(" 1. --api-key CLI option"));
70788
- console.log(source_default.dim(` 2. Active config scope: ${activeScope === "project" ? projectPath : userPath}`));
70789
- console.log(source_default.dim(` (project takes priority when present at cwd; user is ignored in that case)`));
71005
+ console.log(
71006
+ source_default.dim(` 2. Active config scope: ${activeScope === "project" ? projectPath : userPath}`)
71007
+ );
71008
+ console.log(
71009
+ source_default.dim(` (project takes priority when present at cwd; user is ignored in that case)`)
71010
+ );
70790
71011
  console.log(source_default.dim(" 3. .env / shell environment variables (process.env)"));
70791
71012
  console.log();
70792
71013
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeframe/cli",
3
- "version": "0.91.7",
3
+ "version": "0.91.9",
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.7",
187
- "@vibeframe/core": "0.91.7"
186
+ "@vibeframe/ai-providers": "0.91.9",
187
+ "@vibeframe/core": "0.91.9"
188
188
  },
189
189
  "engines": {
190
190
  "node": ">=20"