@vibeframe/cli 0.84.0 → 0.85.0
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 +103 -17
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -51503,22 +51503,30 @@ var init_key_live_test = __esm({
|
|
|
51503
51503
|
signal
|
|
51504
51504
|
)
|
|
51505
51505
|
},
|
|
51506
|
-
// The three below still have no cheap authenticated GET as of
|
|
51507
|
-
//
|
|
51508
|
-
//
|
|
51509
|
-
//
|
|
51510
|
-
// blank-check.
|
|
51506
|
+
// The three below still have no cheap authenticated GET as of
|
|
51507
|
+
// 2026-04-30 (re-checked while shipping v0.85). Surface them as
|
|
51508
|
+
// `skipped` so the user knows we didn't blank-check; revisit when a
|
|
51509
|
+
// provider publishes an account/me endpoint.
|
|
51511
51510
|
fal: {
|
|
51511
|
+
// Probed: /api/account, /v1/account, /v1/me, /queue/health, /v1/users/me,
|
|
51512
|
+
// /api/users/me, /v1/billing — all 404 with the standard `Authorization:
|
|
51513
|
+
// Key <key>` header. The platform docs reference an "Accounts API" but
|
|
51514
|
+
// its endpoint paths are unpublished as of this check.
|
|
51512
51515
|
name: "fal.ai",
|
|
51513
|
-
test: async () => ({ ok: false, skipped: true, message: "no auth-only endpoint
|
|
51516
|
+
test: async () => ({ ok: false, skipped: true, message: "no auth-only endpoint (checked 2026-04-30)" })
|
|
51514
51517
|
},
|
|
51515
51518
|
kling: {
|
|
51519
|
+
// Per-request HMAC signing means we'd need to sign every probe with the
|
|
51520
|
+
// key's secret half plus a timestamp — possible, but the cheapest
|
|
51521
|
+
// signed endpoint is also a generation request. Not worth the code.
|
|
51516
51522
|
name: "Kling",
|
|
51517
|
-
test: async () => ({ ok: false, skipped: true, message: "
|
|
51523
|
+
test: async () => ({ ok: false, skipped: true, message: "HMAC-signed per request (checked 2026-04-30)" })
|
|
51518
51524
|
},
|
|
51519
51525
|
imgbb: {
|
|
51526
|
+
// Only documented route is POST /1/upload. Probing it would consume an
|
|
51527
|
+
// upload quota even if we send a 1×1 PNG, so SKIP is the right call.
|
|
51520
51528
|
name: "ImgBB",
|
|
51521
|
-
test: async () => ({ ok: false, skipped: true, message: "only
|
|
51529
|
+
test: async () => ({ ok: false, skipped: true, message: "only route is upload (checked 2026-04-30)" })
|
|
51522
51530
|
}
|
|
51523
51531
|
};
|
|
51524
51532
|
}
|
|
@@ -62757,6 +62765,10 @@ function toAgentDefinition(t) {
|
|
|
62757
62765
|
return {
|
|
62758
62766
|
name: t.name,
|
|
62759
62767
|
description: t.description,
|
|
62768
|
+
// Propagate the manifest's cost tier so the agent's executor can
|
|
62769
|
+
// mandate a confirm prompt for high-spend tools without needing a
|
|
62770
|
+
// parallel SSOT.
|
|
62771
|
+
cost: t.cost,
|
|
62760
62772
|
parameters: {
|
|
62761
62773
|
type: "object",
|
|
62762
62774
|
properties,
|
|
@@ -62825,7 +62837,7 @@ init_source();
|
|
|
62825
62837
|
// package.json
|
|
62826
62838
|
var package_default = {
|
|
62827
62839
|
name: "@vibeframe/cli",
|
|
62828
|
-
version: "0.
|
|
62840
|
+
version: "0.85.0",
|
|
62829
62841
|
description: "VibeFrame CLI - natural language video editing from the terminal",
|
|
62830
62842
|
private: false,
|
|
62831
62843
|
license: "MIT",
|
|
@@ -72448,10 +72460,26 @@ function maskSensitiveArgs(args) {
|
|
|
72448
72460
|
}
|
|
72449
72461
|
return masked;
|
|
72450
72462
|
}
|
|
72463
|
+
function estimateToolCost(cost) {
|
|
72464
|
+
if (!cost) return 0;
|
|
72465
|
+
switch (cost) {
|
|
72466
|
+
case "free":
|
|
72467
|
+
return 0;
|
|
72468
|
+
case "low":
|
|
72469
|
+
return 0.05;
|
|
72470
|
+
case "medium":
|
|
72471
|
+
return 0.5;
|
|
72472
|
+
case "high":
|
|
72473
|
+
return 3;
|
|
72474
|
+
case "very-high":
|
|
72475
|
+
return 25;
|
|
72476
|
+
}
|
|
72477
|
+
}
|
|
72451
72478
|
var AgentExecutor = class {
|
|
72452
72479
|
adapter = null;
|
|
72453
72480
|
registry;
|
|
72454
72481
|
memory;
|
|
72482
|
+
cumulativeUsd = 0;
|
|
72455
72483
|
context;
|
|
72456
72484
|
config;
|
|
72457
72485
|
initialized = false;
|
|
@@ -72539,12 +72567,39 @@ var AgentExecutor = class {
|
|
|
72539
72567
|
}
|
|
72540
72568
|
/**
|
|
72541
72569
|
* Execute a single tool
|
|
72570
|
+
*
|
|
72571
|
+
* Confirm-prompt logic:
|
|
72572
|
+
* - `noConfirm: true` → never prompt (automation / CI)
|
|
72573
|
+
* - `confirmAlways: true` → prompt for every tool call
|
|
72574
|
+
* - default → prompt only when the tool's
|
|
72575
|
+
* cost is high/very-high (the
|
|
72576
|
+
* `costGate`)
|
|
72577
|
+
*
|
|
72578
|
+
* The two non-trivial cases require `confirmCallback` to be set; if
|
|
72579
|
+
* it isn't, no prompt fires and the tool runs.
|
|
72542
72580
|
*/
|
|
72543
72581
|
async executeTool(toolCall) {
|
|
72544
|
-
|
|
72582
|
+
const def = this.registry.getDefinition(toolCall.name);
|
|
72583
|
+
const cost = def?.cost;
|
|
72584
|
+
const isExpensive = cost === "high" || cost === "very-high";
|
|
72585
|
+
if (this.config.budgetUsd !== void 0) {
|
|
72586
|
+
const estimate = estimateToolCost(cost);
|
|
72587
|
+
if (this.cumulativeUsd + estimate > this.config.budgetUsd) {
|
|
72588
|
+
const remaining = (this.config.budgetUsd - this.cumulativeUsd).toFixed(2);
|
|
72589
|
+
return {
|
|
72590
|
+
toolCallId: toolCall.id,
|
|
72591
|
+
success: false,
|
|
72592
|
+
output: "",
|
|
72593
|
+
error: `Budget exceeded: ${toolCall.name} estimated at $${estimate.toFixed(2)} but only $${remaining} remains of $${this.config.budgetUsd.toFixed(2)} cap.`
|
|
72594
|
+
};
|
|
72595
|
+
}
|
|
72596
|
+
}
|
|
72597
|
+
const shouldConfirm = !this.config.noConfirm && this.config.confirmCallback && (this.config.confirmAlways || isExpensive);
|
|
72598
|
+
if (shouldConfirm && this.config.confirmCallback) {
|
|
72545
72599
|
const confirmed = await this.config.confirmCallback(
|
|
72546
72600
|
toolCall.name,
|
|
72547
|
-
toolCall.arguments
|
|
72601
|
+
toolCall.arguments,
|
|
72602
|
+
cost
|
|
72548
72603
|
);
|
|
72549
72604
|
if (!confirmed) {
|
|
72550
72605
|
return {
|
|
@@ -72560,8 +72615,18 @@ var AgentExecutor = class {
|
|
|
72560
72615
|
this.context
|
|
72561
72616
|
);
|
|
72562
72617
|
result.toolCallId = toolCall.id;
|
|
72618
|
+
if (result.success) {
|
|
72619
|
+
this.cumulativeUsd += estimateToolCost(cost);
|
|
72620
|
+
}
|
|
72563
72621
|
return result;
|
|
72564
72622
|
}
|
|
72623
|
+
/**
|
|
72624
|
+
* Cumulative tier-estimated USD spent in this session. Updates after
|
|
72625
|
+
* every successful tool call. Useful for status output / `tools` REPL.
|
|
72626
|
+
*/
|
|
72627
|
+
getCumulativeUsd() {
|
|
72628
|
+
return this.cumulativeUsd;
|
|
72629
|
+
}
|
|
72565
72630
|
/**
|
|
72566
72631
|
* Update context (e.g., when project changes)
|
|
72567
72632
|
*/
|
|
@@ -72601,7 +72666,7 @@ init_config();
|
|
|
72601
72666
|
init_tty();
|
|
72602
72667
|
init_api_key();
|
|
72603
72668
|
init_output();
|
|
72604
|
-
async function promptConfirm2(toolName, args) {
|
|
72669
|
+
async function promptConfirm2(toolName, args, cost) {
|
|
72605
72670
|
const { createInterface: createInterface4 } = await import("node:readline");
|
|
72606
72671
|
const rl = createInterface4({
|
|
72607
72672
|
input: process.stdin,
|
|
@@ -72611,7 +72676,15 @@ async function promptConfirm2(toolName, args) {
|
|
|
72611
72676
|
return new Promise((resolve64) => {
|
|
72612
72677
|
const argsStr = JSON.stringify(args, null, 2);
|
|
72613
72678
|
console.log();
|
|
72614
|
-
|
|
72679
|
+
const tierColor = {
|
|
72680
|
+
"free": source_default.green,
|
|
72681
|
+
"low": source_default.cyan,
|
|
72682
|
+
"medium": source_default.yellow,
|
|
72683
|
+
"high": source_default.yellow,
|
|
72684
|
+
"very-high": source_default.red
|
|
72685
|
+
};
|
|
72686
|
+
const costBadge = cost ? ` ${tierColor[cost](`[${cost.toUpperCase()}]`)}` : "";
|
|
72687
|
+
console.log(source_default.yellow(`Execute ${source_default.bold(toolName)}?${costBadge}`));
|
|
72615
72688
|
console.log(source_default.dim(argsStr));
|
|
72616
72689
|
rl.question(source_default.cyan("(y/n): "), (answer) => {
|
|
72617
72690
|
rl.close();
|
|
@@ -72621,7 +72694,12 @@ async function promptConfirm2(toolName, args) {
|
|
|
72621
72694
|
}
|
|
72622
72695
|
async function startAgent(options = {}) {
|
|
72623
72696
|
const isNonInteractive = !!options.input;
|
|
72624
|
-
const
|
|
72697
|
+
const confirmAlways = options.confirm || false;
|
|
72698
|
+
const noConfirm = options.noConfirm || false;
|
|
72699
|
+
const budgetUsd = options.budgetUsd ? parseFloat(options.budgetUsd) : void 0;
|
|
72700
|
+
if (budgetUsd !== void 0 && (Number.isNaN(budgetUsd) || budgetUsd < 0)) {
|
|
72701
|
+
exitWithError(generalError(`Invalid --budget-usd: ${options.budgetUsd}`, "Must be a non-negative number (e.g., --budget-usd 5)"));
|
|
72702
|
+
}
|
|
72625
72703
|
if (!isNonInteractive && !hasTTY()) {
|
|
72626
72704
|
exitWithError(generalError("Agent mode requires a terminal.", "Run 'vibe agent' directly from your terminal, or use --input <query> for non-interactive mode."));
|
|
72627
72705
|
}
|
|
@@ -72658,7 +72736,13 @@ async function startAgent(options = {}) {
|
|
|
72658
72736
|
maxTurns,
|
|
72659
72737
|
verbose,
|
|
72660
72738
|
projectPath: options.project,
|
|
72661
|
-
|
|
72739
|
+
// Always supply the callback so the cost gate (high/very-high
|
|
72740
|
+
// tools) can prompt even without `--confirm`. The executor
|
|
72741
|
+
// decides whether to invoke based on `confirmAlways` / `noConfirm`.
|
|
72742
|
+
confirmCallback: noConfirm ? void 0 : promptConfirm2,
|
|
72743
|
+
confirmAlways,
|
|
72744
|
+
noConfirm,
|
|
72745
|
+
budgetUsd
|
|
72662
72746
|
});
|
|
72663
72747
|
await agent.initialize();
|
|
72664
72748
|
spinner2.succeed(source_default.green("Agent initialized"));
|
|
@@ -72695,9 +72779,11 @@ async function startAgent(options = {}) {
|
|
|
72695
72779
|
console.log();
|
|
72696
72780
|
console.log(source_default.dim(` v${version} \xB7 ${provider}${options.model ? ` \xB7 ${options.model}` : ""} \xB7 ${cwd}`));
|
|
72697
72781
|
console.log();
|
|
72782
|
+
const confirmStatus = noConfirm ? source_default.dim("no-confirm") : confirmAlways ? source_default.yellow("confirm mode") : source_default.dim("cost gate (high/very-high)");
|
|
72698
72783
|
const statusParts = [
|
|
72699
72784
|
source_default.green(`${toolCount} tools`),
|
|
72700
|
-
|
|
72785
|
+
confirmStatus,
|
|
72786
|
+
budgetUsd !== void 0 ? source_default.magenta(`budget: $${budgetUsd.toFixed(2)}`) : null,
|
|
72701
72787
|
options.project ? source_default.blue(`project: ${options.project}`) : null
|
|
72702
72788
|
].filter(Boolean);
|
|
72703
72789
|
console.log(source_default.dim(" ") + statusParts.join(source_default.dim(" \xB7 ")));
|
|
@@ -72811,7 +72897,7 @@ async function startAgent(options = {}) {
|
|
|
72811
72897
|
rl.prompt();
|
|
72812
72898
|
});
|
|
72813
72899
|
}
|
|
72814
|
-
var agentCommand = new Command("agent").description("Start the AI agent with natural language interface").option("-p, --provider <provider>", "LLM provider (openai, claude, gemini, ollama, xai, openrouter)", "openai").option("-m, --model <model>", "Model to use (provider-specific)").option("--project <path>", "Timeline file or directory to load").option("-v, --verbose", "Show verbose output including tool calls").option("--max-turns <n>", "Maximum turns per request", "10").option("-i, --input <query>", "Run a single query and exit (non-interactive)").option("-c, --confirm", "Confirm before
|
|
72900
|
+
var agentCommand = new Command("agent").description("Start the AI agent with natural language interface").option("-p, --provider <provider>", "LLM provider (openai, claude, gemini, ollama, xai, openrouter)", "openai").option("-m, --model <model>", "Model to use (provider-specific)").option("--project <path>", "Timeline file or directory to load").option("-v, --verbose", "Show verbose output including tool calls").option("--max-turns <n>", "Maximum turns per request", "10").option("-i, --input <query>", "Run a single query and exit (non-interactive)").option("-c, --confirm", "Confirm before EVERY tool execution (overrides cost gate)").option("--no-confirm", "Disable all confirm prompts including the high/very-high cost gate (CI / automation)").option("--budget-usd <usd>", "Reject tool calls past this cumulative USD ceiling (tier-estimated, conservative)").action(async (options) => {
|
|
72815
72901
|
await startAgent(options);
|
|
72816
72902
|
});
|
|
72817
72903
|
function getEnvVar(provider) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeframe/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.85.0",
|
|
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.
|
|
187
|
-
"@vibeframe/core": "0.
|
|
186
|
+
"@vibeframe/ai-providers": "0.85.0",
|
|
187
|
+
"@vibeframe/core": "0.85.0"
|
|
188
188
|
},
|
|
189
189
|
"engines": {
|
|
190
190
|
"node": ">=20"
|