@vibeframe/cli 0.91.3 → 0.91.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 +110 -20
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -31683,6 +31683,18 @@ var init_open_url = __esm({
31683
31683
  // src/utils/tty.ts
31684
31684
  import { createInterface as createInterface2 } from "node:readline";
31685
31685
  import { ReadStream } from "node:tty";
31686
+ function splitTTYInput(chunk) {
31687
+ const tokens = [];
31688
+ for (let i = 0; i < chunk.length; i++) {
31689
+ if (chunk[i] === "\x1B" && chunk[i + 1] === "[" && i + 2 < chunk.length) {
31690
+ tokens.push(chunk.slice(i, i + 3));
31691
+ i += 2;
31692
+ } else {
31693
+ tokens.push(chunk[i]);
31694
+ }
31695
+ }
31696
+ return tokens;
31697
+ }
31686
31698
  function getTTYInputStream() {
31687
31699
  if (process.stdin.isTTY) {
31688
31700
  return process.stdin;
@@ -31736,14 +31748,16 @@ async function prompt2(question) {
31736
31748
  async function promptHidden(question, opts = {}) {
31737
31749
  const input = getTTYInputStream();
31738
31750
  return new Promise((resolve64) => {
31739
- process.stdout.write(question);
31740
31751
  let value = "";
31741
31752
  if (typeof input.setRawMode === "function") {
31742
31753
  input.setRawMode(true);
31743
31754
  input.resume();
31744
31755
  input.setEncoding("utf8");
31745
- const onData = (char) => {
31756
+ let finished = false;
31757
+ const handleChar = (char) => {
31758
+ if (finished) return;
31746
31759
  if (char === "\n" || char === "\r" || char === "") {
31760
+ finished = true;
31747
31761
  input.setRawMode(false);
31748
31762
  input.removeListener("data", onData);
31749
31763
  process.stdout.write("\n");
@@ -31764,10 +31778,14 @@ async function promptHidden(question, opts = {}) {
31764
31778
  process.stdout.write("*".repeat(char.length));
31765
31779
  }
31766
31780
  };
31781
+ const onData = (chunk) => {
31782
+ for (const char of splitTTYInput(chunk)) handleChar(char);
31783
+ };
31767
31784
  input.on("data", onData);
31785
+ process.stdout.write(question);
31768
31786
  } else {
31769
31787
  const rl = createInterface2({ input, output: process.stdout });
31770
- rl.question("", (answer) => {
31788
+ rl.question(question, (answer) => {
31771
31789
  rl.close();
31772
31790
  resolve64(answer);
31773
31791
  });
@@ -31796,8 +31814,11 @@ async function promptSelect(_question, options, defaultIndex = 0) {
31796
31814
  input.setRawMode(true);
31797
31815
  input.resume();
31798
31816
  input.setEncoding("utf8");
31799
- const onData = (char) => {
31817
+ let finished = false;
31818
+ const handleChar = (char) => {
31819
+ if (finished) return;
31800
31820
  if (char === "\r" || char === "\n") {
31821
+ finished = true;
31801
31822
  input.setRawMode(false);
31802
31823
  input.removeListener("data", onData);
31803
31824
  process.stdout.write("\n");
@@ -31814,6 +31835,7 @@ async function promptSelect(_question, options, defaultIndex = 0) {
31814
31835
  render();
31815
31836
  } else if (char >= "1" && char <= String(options.length)) {
31816
31837
  selected = parseInt(char, 10) - 1;
31838
+ finished = true;
31817
31839
  input.setRawMode(false);
31818
31840
  input.removeListener("data", onData);
31819
31841
  render();
@@ -31821,6 +31843,9 @@ async function promptSelect(_question, options, defaultIndex = 0) {
31821
31843
  resolve64(selected);
31822
31844
  }
31823
31845
  };
31846
+ const onData = (chunk) => {
31847
+ for (const char of splitTTYInput(chunk)) handleChar(char);
31848
+ };
31824
31849
  input.on("data", onData);
31825
31850
  });
31826
31851
  }
@@ -31861,8 +31886,11 @@ async function promptConfirm(question, defaultYes = true) {
31861
31886
  input.setRawMode(true);
31862
31887
  input.resume();
31863
31888
  input.setEncoding("utf8");
31864
- const onData = (char) => {
31889
+ let finished = false;
31890
+ const handleChar = (char) => {
31891
+ if (finished) return;
31865
31892
  if (char === "\r" || char === "\n") {
31893
+ finished = true;
31866
31894
  input.setRawMode(false);
31867
31895
  input.removeListener("data", onData);
31868
31896
  resolve64(selected === 0);
@@ -31875,18 +31903,23 @@ async function promptConfirm(question, defaultYes = true) {
31875
31903
  render();
31876
31904
  } else if (char === "y" || char === "Y") {
31877
31905
  selected = 0;
31906
+ finished = true;
31878
31907
  input.setRawMode(false);
31879
31908
  input.removeListener("data", onData);
31880
31909
  render();
31881
31910
  resolve64(true);
31882
31911
  } else if (char === "n" || char === "N") {
31883
31912
  selected = 1;
31913
+ finished = true;
31884
31914
  input.setRawMode(false);
31885
31915
  input.removeListener("data", onData);
31886
31916
  render();
31887
31917
  resolve64(false);
31888
31918
  }
31889
31919
  };
31920
+ const onData = (chunk) => {
31921
+ for (const char of splitTTYInput(chunk)) handleChar(char);
31922
+ };
31890
31923
  input.on("data", onData);
31891
31924
  });
31892
31925
  }
@@ -31931,13 +31964,16 @@ async function promptMultiSelect(_question, options, defaultSelected = [], opts
31931
31964
  }
31932
31965
  resolve64(result);
31933
31966
  };
31934
- const onData = (char) => {
31967
+ let finished = false;
31968
+ const handleChar = (char) => {
31969
+ if (finished) return;
31935
31970
  if (char === "\r" || char === "\n") {
31936
31971
  if (pickFocused && !userToggled) {
31937
31972
  for (let i = 0; i < selected.length; i++) selected[i] = false;
31938
31973
  selected[cursor] = true;
31939
31974
  render();
31940
31975
  }
31976
+ finished = true;
31941
31977
  finish();
31942
31978
  } else if (char === "") {
31943
31979
  input.setRawMode(false);
@@ -31965,6 +32001,9 @@ async function promptMultiSelect(_question, options, defaultSelected = [], opts
31965
32001
  render();
31966
32002
  }
31967
32003
  };
32004
+ const onData = (chunk) => {
32005
+ for (const char of splitTTYInput(chunk)) handleChar(char);
32006
+ };
31968
32007
  input.on("data", onData);
31969
32008
  });
31970
32009
  }
@@ -62920,7 +62959,7 @@ init_source();
62920
62959
  // package.json
62921
62960
  var package_default = {
62922
62961
  name: "@vibeframe/cli",
62923
- version: "0.91.3",
62962
+ version: "0.91.4",
62924
62963
  description: "VibeFrame CLI - natural language video editing from the terminal",
62925
62964
  private: false,
62926
62965
  license: "MIT",
@@ -70110,6 +70149,15 @@ function applyProviderDefault(config2, choice) {
70110
70149
  config2.defaults.videoProvider = choice.defaultFor.value;
70111
70150
  }
70112
70151
  }
70152
+ function mergeSelectedFeatures(current, next) {
70153
+ const merged = [...current];
70154
+ for (const feature of next) {
70155
+ if (!merged.some((f) => f.label === feature.label)) {
70156
+ merged.push(feature);
70157
+ }
70158
+ }
70159
+ return merged;
70160
+ }
70113
70161
  async function runNonInteractiveSetup(opts) {
70114
70162
  const scope = opts.scope ?? "user";
70115
70163
  let config2 = await loadConfig({ scope });
@@ -70235,11 +70283,13 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70235
70283
  console.log();
70236
70284
  if (topIndex === 0) {
70237
70285
  await saveConfig(config2, { scope });
70238
- await showComplete(config2, "vibe edit silence-cut video.mp4 -o clean.mp4", [], scope);
70286
+ await completeOrContinue(config2, "vibe edit silence-cut video.mp4 -o clean.mp4", [], scope);
70239
70287
  return;
70240
70288
  }
70241
70289
  if (topIndex === 3) {
70242
- await runCustomSetup(config2, scope);
70290
+ await runCustomSetup(config2, scope, { showComplete: false });
70291
+ await saveConfig(config2, { scope });
70292
+ await completeOrContinue(config2, "vibe doctor --test-keys", [], scope);
70243
70293
  return;
70244
70294
  }
70245
70295
  if (topIndex === 2) {
@@ -70256,9 +70306,44 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70256
70306
  console.log();
70257
70307
  await collectKeys(config2, pipelineKeys);
70258
70308
  await saveConfig(config2, { scope });
70259
- await showComplete(config2, "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format", [], scope);
70309
+ await completeOrContinue(config2, "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format", [], scope);
70260
70310
  return;
70261
70311
  }
70312
+ const result = await runAIFeaturesSetup(config2, scope);
70313
+ await saveConfig(config2, { scope });
70314
+ await completeOrContinue(config2, result.tryCommand, result.selectedFeatures, scope);
70315
+ }
70316
+ async function completeOrContinue(config2, tryCommand, selectedFeatures, scope) {
70317
+ console.log(source_default.dim("Setup checkpoint"));
70318
+ console.log(source_default.bold("Anything else to configure?"));
70319
+ console.log();
70320
+ const action = await promptSelect(
70321
+ source_default.cyan(" Next: "),
70322
+ [
70323
+ `Add or update AI features ${source_default.dim("(images, videos, audio, editing)")}`,
70324
+ `Open full provider list ${source_default.dim("(every supported provider)")}`,
70325
+ "Finish setup"
70326
+ ],
70327
+ 2
70328
+ );
70329
+ console.log();
70330
+ if (action === 0) {
70331
+ const result = await runAIFeaturesSetup(config2, scope);
70332
+ const mergedFeatures = mergeSelectedFeatures(selectedFeatures, result.selectedFeatures);
70333
+ const mergedTryCommand = selectedFeatures.length > 0 ? tryCommand : result.tryCommand;
70334
+ await saveConfig(config2, { scope });
70335
+ await completeOrContinue(config2, mergedTryCommand, mergedFeatures, scope);
70336
+ return;
70337
+ }
70338
+ if (action === 1) {
70339
+ await runCustomSetup(config2, scope, { showComplete: false });
70340
+ await saveConfig(config2, { scope });
70341
+ await completeOrContinue(config2, tryCommand, selectedFeatures, scope);
70342
+ return;
70343
+ }
70344
+ await showComplete(config2, tryCommand, selectedFeatures, scope);
70345
+ }
70346
+ async function runAIFeaturesSetup(config2, _scope) {
70262
70347
  console.log(source_default.dim("2. Features"));
70263
70348
  console.log(source_default.bold("Which AI features do you need?"));
70264
70349
  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.`));
@@ -70280,14 +70365,12 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70280
70365
  if (selectedFeatures.length === 0) {
70281
70366
  console.log(source_default.dim(" No features selected. You can re-run setup anytime."));
70282
70367
  console.log();
70283
- await saveConfig(config2, { scope });
70284
- await showComplete(config2, "vibe --help", [], scope);
70285
- return;
70368
+ return { tryCommand: "vibe --help", selectedFeatures: [] };
70286
70369
  }
70287
70370
  const plannedKeys = /* @__PURE__ */ new Map();
70288
70371
  console.log(source_default.dim("3. Providers"));
70289
70372
  console.log(source_default.bold("Choose providers for each selected feature"));
70290
- console.log(source_default.dim(` Recommended default is highlighted. Press ${source_default.bold("enter")} to pick it, or use ${source_default.bold("space")} to add multiple.`));
70373
+ 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.`));
70291
70374
  console.log();
70292
70375
  for (const feature of selectedFeatures) {
70293
70376
  const keysForFeature = [];
@@ -70298,10 +70381,16 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70298
70381
  console.log(source_default.dim(` Alternatives: ${feature.alsoAvailable}`));
70299
70382
  }
70300
70383
  console.log();
70301
- const defaultSelected = feature.providerChoices.map((_, i) => i === 0);
70384
+ const defaultSelected = feature.providerChoices.map(() => false);
70302
70385
  const providerLabels = feature.providerChoices.map((choice) => {
70303
70386
  const keyHint = choice.keyless ? source_default.dim("no key") : choice.key ? source_default.dim(choice.key.envVar) : source_default.dim("no key");
70304
- return `${choice.label} ${source_default.dim(`- ${choice.desc}`)} ${keyHint}`;
70387
+ const defaultHint = choice === feature.providerChoices?.[0] ? source_default.dim("recommended default") : "";
70388
+ return [
70389
+ choice.label,
70390
+ defaultHint,
70391
+ source_default.dim(`- ${choice.desc}`),
70392
+ keyHint
70393
+ ].filter(Boolean).join(" ");
70305
70394
  });
70306
70395
  const pickedProviders = await promptMultiSelect(
70307
70396
  source_default.cyan(" Providers (arrow + enter picks one, space adds more): "),
@@ -70388,8 +70477,7 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70388
70477
  console.log(source_default.dim(" No API keys needed for the selected provider(s)."));
70389
70478
  console.log();
70390
70479
  }
70391
- await saveConfig(config2, { scope });
70392
- await showComplete(config2, selectedFeatures[0].tryCommand, selectedFeatures, scope);
70480
+ return { tryCommand: selectedFeatures[0].tryCommand, selectedFeatures };
70393
70481
  }
70394
70482
  async function collectKeys(config2, keys) {
70395
70483
  loadEnv();
@@ -70425,7 +70513,7 @@ async function collectKeys(config2, keys) {
70425
70513
  }
70426
70514
  console.log();
70427
70515
  }
70428
- async function runCustomSetup(config2, scope = "user") {
70516
+ async function runCustomSetup(config2, scope = "user", opts = {}) {
70429
70517
  console.log(source_default.bold("1. Agent LLM Provider") + source_default.dim(" (for vibe agent)"));
70430
70518
  console.log(source_default.dim(" Only needed if you use the interactive Agent mode."));
70431
70519
  console.log();
@@ -70496,7 +70584,9 @@ async function runCustomSetup(config2, scope = "user") {
70496
70584
  }
70497
70585
  console.log();
70498
70586
  await saveConfig(config2, { scope });
70499
- await showComplete(config2, "vibe doctor", [], scope);
70587
+ if (opts.showComplete !== false) {
70588
+ await showComplete(config2, "vibe doctor", [], scope);
70589
+ }
70500
70590
  }
70501
70591
  async function showComplete(config2, defaultTryCommand, features = [], scope = "user") {
70502
70592
  console.log(source_default.dim("\u2500".repeat(40)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeframe/cli",
3
- "version": "0.91.3",
3
+ "version": "0.91.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/ai-providers": "0.91.3",
187
- "@vibeframe/core": "0.91.3"
186
+ "@vibeframe/ai-providers": "0.91.4",
187
+ "@vibeframe/core": "0.91.4"
188
188
  },
189
189
  "engines": {
190
190
  "node": ">=20"