@vibeframe/cli 0.91.3 → 0.91.6

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 +111 -20
  2. package/package.json +5 -4
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.6",
62924
62963
  description: "VibeFrame CLI - natural language video editing from the terminal",
62925
62964
  private: false,
62926
62965
  license: "MIT",
@@ -63084,6 +63123,7 @@ var package_default = {
63084
63123
  start: "tsx src/index.ts",
63085
63124
  lint: "eslint --ext .ts,.tsx src/",
63086
63125
  test: "vitest",
63126
+ pretest: "node build.js",
63087
63127
  prepublishOnly: "node build.js"
63088
63128
  },
63089
63129
  dependencies: {
@@ -70110,6 +70150,15 @@ function applyProviderDefault(config2, choice) {
70110
70150
  config2.defaults.videoProvider = choice.defaultFor.value;
70111
70151
  }
70112
70152
  }
70153
+ function mergeSelectedFeatures(current, next) {
70154
+ const merged = [...current];
70155
+ for (const feature of next) {
70156
+ if (!merged.some((f) => f.label === feature.label)) {
70157
+ merged.push(feature);
70158
+ }
70159
+ }
70160
+ return merged;
70161
+ }
70113
70162
  async function runNonInteractiveSetup(opts) {
70114
70163
  const scope = opts.scope ?? "user";
70115
70164
  let config2 = await loadConfig({ scope });
@@ -70235,11 +70284,13 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70235
70284
  console.log();
70236
70285
  if (topIndex === 0) {
70237
70286
  await saveConfig(config2, { scope });
70238
- await showComplete(config2, "vibe edit silence-cut video.mp4 -o clean.mp4", [], scope);
70287
+ await completeOrContinue(config2, "vibe edit silence-cut video.mp4 -o clean.mp4", [], scope);
70239
70288
  return;
70240
70289
  }
70241
70290
  if (topIndex === 3) {
70242
- await runCustomSetup(config2, scope);
70291
+ await runCustomSetup(config2, scope, { showComplete: false });
70292
+ await saveConfig(config2, { scope });
70293
+ await completeOrContinue(config2, "vibe doctor --test-keys", [], scope);
70243
70294
  return;
70244
70295
  }
70245
70296
  if (topIndex === 2) {
@@ -70256,9 +70307,44 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70256
70307
  console.log();
70257
70308
  await collectKeys(config2, pipelineKeys);
70258
70309
  await saveConfig(config2, { scope });
70259
- await showComplete(config2, "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format", [], scope);
70310
+ await completeOrContinue(config2, "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format", [], scope);
70260
70311
  return;
70261
70312
  }
70313
+ const result = await runAIFeaturesSetup(config2, scope);
70314
+ await saveConfig(config2, { scope });
70315
+ await completeOrContinue(config2, result.tryCommand, result.selectedFeatures, scope);
70316
+ }
70317
+ async function completeOrContinue(config2, tryCommand, selectedFeatures, scope) {
70318
+ console.log(source_default.dim("Setup checkpoint"));
70319
+ console.log(source_default.bold("Anything else to configure?"));
70320
+ console.log();
70321
+ const action = await promptSelect(
70322
+ source_default.cyan(" Next: "),
70323
+ [
70324
+ `Add or update AI features ${source_default.dim("(images, videos, audio, editing)")}`,
70325
+ `Open full provider list ${source_default.dim("(every supported provider)")}`,
70326
+ "Finish setup"
70327
+ ],
70328
+ 2
70329
+ );
70330
+ console.log();
70331
+ if (action === 0) {
70332
+ const result = await runAIFeaturesSetup(config2, scope);
70333
+ const mergedFeatures = mergeSelectedFeatures(selectedFeatures, result.selectedFeatures);
70334
+ const mergedTryCommand = selectedFeatures.length > 0 ? tryCommand : result.tryCommand;
70335
+ await saveConfig(config2, { scope });
70336
+ await completeOrContinue(config2, mergedTryCommand, mergedFeatures, scope);
70337
+ return;
70338
+ }
70339
+ if (action === 1) {
70340
+ await runCustomSetup(config2, scope, { showComplete: false });
70341
+ await saveConfig(config2, { scope });
70342
+ await completeOrContinue(config2, tryCommand, selectedFeatures, scope);
70343
+ return;
70344
+ }
70345
+ await showComplete(config2, tryCommand, selectedFeatures, scope);
70346
+ }
70347
+ async function runAIFeaturesSetup(config2, _scope) {
70262
70348
  console.log(source_default.dim("2. Features"));
70263
70349
  console.log(source_default.bold("Which AI features do you need?"));
70264
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.`));
@@ -70280,14 +70366,12 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70280
70366
  if (selectedFeatures.length === 0) {
70281
70367
  console.log(source_default.dim(" No features selected. You can re-run setup anytime."));
70282
70368
  console.log();
70283
- await saveConfig(config2, { scope });
70284
- await showComplete(config2, "vibe --help", [], scope);
70285
- return;
70369
+ return { tryCommand: "vibe --help", selectedFeatures: [] };
70286
70370
  }
70287
70371
  const plannedKeys = /* @__PURE__ */ new Map();
70288
70372
  console.log(source_default.dim("3. Providers"));
70289
70373
  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.`));
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.`));
70291
70375
  console.log();
70292
70376
  for (const feature of selectedFeatures) {
70293
70377
  const keysForFeature = [];
@@ -70298,10 +70382,16 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70298
70382
  console.log(source_default.dim(` Alternatives: ${feature.alsoAvailable}`));
70299
70383
  }
70300
70384
  console.log();
70301
- const defaultSelected = feature.providerChoices.map((_, i) => i === 0);
70385
+ const defaultSelected = feature.providerChoices.map(() => false);
70302
70386
  const providerLabels = feature.providerChoices.map((choice) => {
70303
70387
  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}`;
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(" ");
70305
70395
  });
70306
70396
  const pickedProviders = await promptMultiSelect(
70307
70397
  source_default.cyan(" Providers (arrow + enter picks one, space adds more): "),
@@ -70388,8 +70478,7 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
70388
70478
  console.log(source_default.dim(" No API keys needed for the selected provider(s)."));
70389
70479
  console.log();
70390
70480
  }
70391
- await saveConfig(config2, { scope });
70392
- await showComplete(config2, selectedFeatures[0].tryCommand, selectedFeatures, scope);
70481
+ return { tryCommand: selectedFeatures[0].tryCommand, selectedFeatures };
70393
70482
  }
70394
70483
  async function collectKeys(config2, keys) {
70395
70484
  loadEnv();
@@ -70425,7 +70514,7 @@ async function collectKeys(config2, keys) {
70425
70514
  }
70426
70515
  console.log();
70427
70516
  }
70428
- async function runCustomSetup(config2, scope = "user") {
70517
+ async function runCustomSetup(config2, scope = "user", opts = {}) {
70429
70518
  console.log(source_default.bold("1. Agent LLM Provider") + source_default.dim(" (for vibe agent)"));
70430
70519
  console.log(source_default.dim(" Only needed if you use the interactive Agent mode."));
70431
70520
  console.log();
@@ -70496,7 +70585,9 @@ async function runCustomSetup(config2, scope = "user") {
70496
70585
  }
70497
70586
  console.log();
70498
70587
  await saveConfig(config2, { scope });
70499
- await showComplete(config2, "vibe doctor", [], scope);
70588
+ if (opts.showComplete !== false) {
70589
+ await showComplete(config2, "vibe doctor", [], scope);
70590
+ }
70500
70591
  }
70501
70592
  async function showComplete(config2, defaultTryCommand, features = [], scope = "user") {
70502
70593
  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.6",
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.6",
187
+ "@vibeframe/core": "0.91.6"
188
188
  },
189
189
  "engines": {
190
190
  "node": ">=20"
@@ -195,6 +195,7 @@
195
195
  "dev": "tsc --watch",
196
196
  "start": "tsx src/index.ts",
197
197
  "lint": "eslint --ext .ts,.tsx src/",
198
- "test": "vitest"
198
+ "test": "vitest",
199
+ "pretest": "node build.js"
199
200
  }
200
201
  }