@vibeframe/cli 0.91.2 → 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.
- package/dist/index.js +124 -26
- 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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|
|
@@ -31896,12 +31929,14 @@ async function promptConfirm(question, defaultYes = true) {
|
|
|
31896
31929
|
return answer.toLowerCase().startsWith("y");
|
|
31897
31930
|
}
|
|
31898
31931
|
async function promptMultiSelect(_question, options, defaultSelected = [], opts = {}) {
|
|
31932
|
+
const pickFocused = opts.pickFocusedOnEnter ?? opts.enterSelectsFocusedWhenEmpty ?? false;
|
|
31899
31933
|
const input = getTTYInputStream();
|
|
31900
31934
|
const selected = options.map((_, i) => Boolean(defaultSelected[i]));
|
|
31901
31935
|
if (typeof input.setRawMode === "function") {
|
|
31902
31936
|
return new Promise((resolve64) => {
|
|
31903
31937
|
let cursor = 0;
|
|
31904
31938
|
let renderCount = 0;
|
|
31939
|
+
let userToggled = false;
|
|
31905
31940
|
const render = () => {
|
|
31906
31941
|
if (renderCount > 0) {
|
|
31907
31942
|
process.stdout.write(`\x1B[${options.length}A`);
|
|
@@ -31929,11 +31964,16 @@ async function promptMultiSelect(_question, options, defaultSelected = [], opts
|
|
|
31929
31964
|
}
|
|
31930
31965
|
resolve64(result);
|
|
31931
31966
|
};
|
|
31932
|
-
|
|
31967
|
+
let finished = false;
|
|
31968
|
+
const handleChar = (char) => {
|
|
31969
|
+
if (finished) return;
|
|
31933
31970
|
if (char === "\r" || char === "\n") {
|
|
31934
|
-
if (
|
|
31971
|
+
if (pickFocused && !userToggled) {
|
|
31972
|
+
for (let i = 0; i < selected.length; i++) selected[i] = false;
|
|
31935
31973
|
selected[cursor] = true;
|
|
31974
|
+
render();
|
|
31936
31975
|
}
|
|
31976
|
+
finished = true;
|
|
31937
31977
|
finish();
|
|
31938
31978
|
} else if (char === "") {
|
|
31939
31979
|
input.setRawMode(false);
|
|
@@ -31941,6 +31981,7 @@ async function promptMultiSelect(_question, options, defaultSelected = [], opts
|
|
|
31941
31981
|
process.exit(1);
|
|
31942
31982
|
} else if (char === " ") {
|
|
31943
31983
|
selected[cursor] = !selected[cursor];
|
|
31984
|
+
userToggled = true;
|
|
31944
31985
|
render();
|
|
31945
31986
|
} else if (char === "\x1B[A" || char === "k") {
|
|
31946
31987
|
cursor = (cursor - 1 + options.length) % options.length;
|
|
@@ -31951,13 +31992,18 @@ async function promptMultiSelect(_question, options, defaultSelected = [], opts
|
|
|
31951
31992
|
} else if (char === "a") {
|
|
31952
31993
|
const allOn = selected.every(Boolean);
|
|
31953
31994
|
for (let i = 0; i < selected.length; i++) selected[i] = !allOn;
|
|
31995
|
+
userToggled = true;
|
|
31954
31996
|
render();
|
|
31955
31997
|
} else if (char >= "1" && char <= String(Math.min(options.length, 9))) {
|
|
31956
31998
|
const i = parseInt(char, 10) - 1;
|
|
31957
31999
|
selected[i] = !selected[i];
|
|
32000
|
+
userToggled = true;
|
|
31958
32001
|
render();
|
|
31959
32002
|
}
|
|
31960
32003
|
};
|
|
32004
|
+
const onData = (chunk) => {
|
|
32005
|
+
for (const char of splitTTYInput(chunk)) handleChar(char);
|
|
32006
|
+
};
|
|
31961
32007
|
input.on("data", onData);
|
|
31962
32008
|
});
|
|
31963
32009
|
}
|
|
@@ -62913,7 +62959,7 @@ init_source();
|
|
|
62913
62959
|
// package.json
|
|
62914
62960
|
var package_default = {
|
|
62915
62961
|
name: "@vibeframe/cli",
|
|
62916
|
-
version: "0.91.
|
|
62962
|
+
version: "0.91.4",
|
|
62917
62963
|
description: "VibeFrame CLI - natural language video editing from the terminal",
|
|
62918
62964
|
private: false,
|
|
62919
62965
|
license: "MIT",
|
|
@@ -70103,6 +70149,15 @@ function applyProviderDefault(config2, choice) {
|
|
|
70103
70149
|
config2.defaults.videoProvider = choice.defaultFor.value;
|
|
70104
70150
|
}
|
|
70105
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
|
+
}
|
|
70106
70161
|
async function runNonInteractiveSetup(opts) {
|
|
70107
70162
|
const scope = opts.scope ?? "user";
|
|
70108
70163
|
let config2 = await loadConfig({ scope });
|
|
@@ -70228,11 +70283,13 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
|
|
|
70228
70283
|
console.log();
|
|
70229
70284
|
if (topIndex === 0) {
|
|
70230
70285
|
await saveConfig(config2, { scope });
|
|
70231
|
-
await
|
|
70286
|
+
await completeOrContinue(config2, "vibe edit silence-cut video.mp4 -o clean.mp4", [], scope);
|
|
70232
70287
|
return;
|
|
70233
70288
|
}
|
|
70234
70289
|
if (topIndex === 3) {
|
|
70235
|
-
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);
|
|
70236
70293
|
return;
|
|
70237
70294
|
}
|
|
70238
70295
|
if (topIndex === 2) {
|
|
@@ -70249,13 +70306,48 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
|
|
|
70249
70306
|
console.log();
|
|
70250
70307
|
await collectKeys(config2, pipelineKeys);
|
|
70251
70308
|
await saveConfig(config2, { scope });
|
|
70252
|
-
await
|
|
70309
|
+
await completeOrContinue(config2, "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format", [], scope);
|
|
70253
70310
|
return;
|
|
70254
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) {
|
|
70255
70347
|
console.log(source_default.dim("2. Features"));
|
|
70256
70348
|
console.log(source_default.bold("Which AI features do you need?"));
|
|
70257
|
-
console.log(source_default.dim("
|
|
70258
|
-
console.log(source_default.dim("
|
|
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.`));
|
|
70350
|
+
console.log(source_default.dim(" Shortcut: enter alone picks only the highlighted feature."));
|
|
70259
70351
|
console.log();
|
|
70260
70352
|
const featureLabels = AI_FEATURES.map((f) => {
|
|
70261
70353
|
const keyCount = f.keys.length;
|
|
@@ -70266,21 +70358,19 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
|
|
|
70266
70358
|
source_default.cyan(" Pick (e.g. 1,3 or 'all'): "),
|
|
70267
70359
|
featureLabels,
|
|
70268
70360
|
[],
|
|
70269
|
-
{
|
|
70361
|
+
{ pickFocusedOnEnter: true }
|
|
70270
70362
|
);
|
|
70271
70363
|
const selectedFeatures = picked.map((i) => AI_FEATURES[i]);
|
|
70272
70364
|
console.log();
|
|
70273
70365
|
if (selectedFeatures.length === 0) {
|
|
70274
70366
|
console.log(source_default.dim(" No features selected. You can re-run setup anytime."));
|
|
70275
70367
|
console.log();
|
|
70276
|
-
|
|
70277
|
-
await showComplete(config2, "vibe --help", [], scope);
|
|
70278
|
-
return;
|
|
70368
|
+
return { tryCommand: "vibe --help", selectedFeatures: [] };
|
|
70279
70369
|
}
|
|
70280
70370
|
const plannedKeys = /* @__PURE__ */ new Map();
|
|
70281
70371
|
console.log(source_default.dim("3. Providers"));
|
|
70282
70372
|
console.log(source_default.bold("Choose providers for each selected feature"));
|
|
70283
|
-
console.log(source_default.dim(
|
|
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.`));
|
|
70284
70374
|
console.log();
|
|
70285
70375
|
for (const feature of selectedFeatures) {
|
|
70286
70376
|
const keysForFeature = [];
|
|
@@ -70291,15 +70381,22 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
|
|
|
70291
70381
|
console.log(source_default.dim(` Alternatives: ${feature.alsoAvailable}`));
|
|
70292
70382
|
}
|
|
70293
70383
|
console.log();
|
|
70294
|
-
const defaultSelected = feature.providerChoices.map((
|
|
70384
|
+
const defaultSelected = feature.providerChoices.map(() => false);
|
|
70295
70385
|
const providerLabels = feature.providerChoices.map((choice) => {
|
|
70296
70386
|
const keyHint = choice.keyless ? source_default.dim("no key") : choice.key ? source_default.dim(choice.key.envVar) : source_default.dim("no key");
|
|
70297
|
-
|
|
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(" ");
|
|
70298
70394
|
});
|
|
70299
70395
|
const pickedProviders = await promptMultiSelect(
|
|
70300
|
-
source_default.cyan(" Providers (
|
|
70396
|
+
source_default.cyan(" Providers (arrow + enter picks one, space adds more): "),
|
|
70301
70397
|
providerLabels,
|
|
70302
|
-
defaultSelected
|
|
70398
|
+
defaultSelected,
|
|
70399
|
+
{ pickFocusedOnEnter: true }
|
|
70303
70400
|
);
|
|
70304
70401
|
const selectedChoices = pickedProviders.map((i) => feature.providerChoices[i]);
|
|
70305
70402
|
const defaultChoice = selectedChoices.find((choice) => choice.defaultFor);
|
|
@@ -70380,8 +70477,7 @@ async function runSetupWizard(fullSetup = false, scope = "user") {
|
|
|
70380
70477
|
console.log(source_default.dim(" No API keys needed for the selected provider(s)."));
|
|
70381
70478
|
console.log();
|
|
70382
70479
|
}
|
|
70383
|
-
|
|
70384
|
-
await showComplete(config2, selectedFeatures[0].tryCommand, selectedFeatures, scope);
|
|
70480
|
+
return { tryCommand: selectedFeatures[0].tryCommand, selectedFeatures };
|
|
70385
70481
|
}
|
|
70386
70482
|
async function collectKeys(config2, keys) {
|
|
70387
70483
|
loadEnv();
|
|
@@ -70417,7 +70513,7 @@ async function collectKeys(config2, keys) {
|
|
|
70417
70513
|
}
|
|
70418
70514
|
console.log();
|
|
70419
70515
|
}
|
|
70420
|
-
async function runCustomSetup(config2, scope = "user") {
|
|
70516
|
+
async function runCustomSetup(config2, scope = "user", opts = {}) {
|
|
70421
70517
|
console.log(source_default.bold("1. Agent LLM Provider") + source_default.dim(" (for vibe agent)"));
|
|
70422
70518
|
console.log(source_default.dim(" Only needed if you use the interactive Agent mode."));
|
|
70423
70519
|
console.log();
|
|
@@ -70488,7 +70584,9 @@ async function runCustomSetup(config2, scope = "user") {
|
|
|
70488
70584
|
}
|
|
70489
70585
|
console.log();
|
|
70490
70586
|
await saveConfig(config2, { scope });
|
|
70491
|
-
|
|
70587
|
+
if (opts.showComplete !== false) {
|
|
70588
|
+
await showComplete(config2, "vibe doctor", [], scope);
|
|
70589
|
+
}
|
|
70492
70590
|
}
|
|
70493
70591
|
async function showComplete(config2, defaultTryCommand, features = [], scope = "user") {
|
|
70494
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
|
+
"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.
|
|
187
|
-
"@vibeframe/core": "0.91.
|
|
186
|
+
"@vibeframe/ai-providers": "0.91.4",
|
|
187
|
+
"@vibeframe/core": "0.91.4"
|
|
188
188
|
},
|
|
189
189
|
"engines": {
|
|
190
190
|
"node": ">=20"
|