@vibeframe/cli 0.115.0 → 0.115.1

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.
@@ -0,0 +1 @@
1
+ export {};
@@ -7,3 +7,22 @@
7
7
  */
8
8
  import type { Command } from "commander";
9
9
  export declare function registerVideoCommand(parent: Command): void;
10
+ /**
11
+ * Cost figure for a REAL (non-dry-run) generation envelope.
12
+ *
13
+ * Seedance has a token-accurate estimator; every other provider reports the
14
+ * command's tier upper bound with a warning naming it an estimate. Without
15
+ * this the success envelope defaulted to costUsd 0, which an agent budget
16
+ * loop reads as "free" - the hybrid-brew dogfood run billed Runway twice
17
+ * while reporting $0.
18
+ */
19
+ export declare function realRunCost(provider: string, options: {
20
+ duration?: string;
21
+ resolution?: string;
22
+ ratio?: string;
23
+ seedanceModel?: string;
24
+ refVideos?: string[];
25
+ }): {
26
+ costUsd: number;
27
+ warnings: string[];
28
+ };
@@ -76,6 +76,13 @@ export interface SuccessEnvelopeOptions {
76
76
  /** Pass-through of `--dry-run` flag — surfaces as a top-level `dryRun: true` in the envelope. */
77
77
  dryRun?: boolean;
78
78
  }
79
+ /** Look up the upper-bound cost estimate for a command (used by dry-run). */
80
+ /**
81
+ * Exported for real-run envelopes that want the same tier bound the dry-run
82
+ * default uses (e.g. `generate video` on providers without an accurate
83
+ * estimator) instead of the misleading non-dry default of 0.
84
+ */
85
+ export declare function lookupCostEstimateUpperBound(command: string): number;
79
86
  /**
80
87
  * Emit a canonical success envelope (#33 — 2c). JSON mode prints the
81
88
  * envelope; quiet mode prints a single primary value extracted from
package/dist/index.js CHANGED
@@ -22744,10 +22744,10 @@ var require_resolve_block_map = __commonJS({
22744
22744
  let offset = bm.offset;
22745
22745
  let commentEnd = null;
22746
22746
  for (const collItem of bm.items) {
22747
- const { start, key, sep: sep2, value } = collItem;
22747
+ const { start, key, sep: sep3, value } = collItem;
22748
22748
  const keyProps = resolveProps.resolveProps(start, {
22749
22749
  indicator: "explicit-key-ind",
22750
- next: key ?? sep2?.[0],
22750
+ next: key ?? sep3?.[0],
22751
22751
  offset,
22752
22752
  onError,
22753
22753
  parentIndent: bm.indent,
@@ -22761,7 +22761,7 @@ var require_resolve_block_map = __commonJS({
22761
22761
  else if ("indent" in key && key.indent !== bm.indent)
22762
22762
  onError(offset, "BAD_INDENT", startColMsg);
22763
22763
  }
22764
- if (!keyProps.anchor && !keyProps.tag && !sep2) {
22764
+ if (!keyProps.anchor && !keyProps.tag && !sep3) {
22765
22765
  commentEnd = keyProps.end;
22766
22766
  if (keyProps.comment) {
22767
22767
  if (map.comment)
@@ -22785,7 +22785,7 @@ var require_resolve_block_map = __commonJS({
22785
22785
  ctx.atKey = false;
22786
22786
  if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
22787
22787
  onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
22788
- const valueProps = resolveProps.resolveProps(sep2 ?? [], {
22788
+ const valueProps = resolveProps.resolveProps(sep3 ?? [], {
22789
22789
  indicator: "map-value-ind",
22790
22790
  next: value,
22791
22791
  offset: keyNode.range[2],
@@ -22801,7 +22801,7 @@ var require_resolve_block_map = __commonJS({
22801
22801
  if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
22802
22802
  onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
22803
22803
  }
22804
- const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep2, null, valueProps, onError);
22804
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep3, null, valueProps, onError);
22805
22805
  if (ctx.schema.compat)
22806
22806
  utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError);
22807
22807
  offset = valueNode.range[2];
@@ -22892,7 +22892,7 @@ var require_resolve_end = __commonJS({
22892
22892
  let comment = "";
22893
22893
  if (end) {
22894
22894
  let hasSpace = false;
22895
- let sep2 = "";
22895
+ let sep3 = "";
22896
22896
  for (const token of end) {
22897
22897
  const { source, type } = token;
22898
22898
  switch (type) {
@@ -22906,13 +22906,13 @@ var require_resolve_end = __commonJS({
22906
22906
  if (!comment)
22907
22907
  comment = cb;
22908
22908
  else
22909
- comment += sep2 + cb;
22910
- sep2 = "";
22909
+ comment += sep3 + cb;
22910
+ sep3 = "";
22911
22911
  break;
22912
22912
  }
22913
22913
  case "newline":
22914
22914
  if (comment)
22915
- sep2 += source;
22915
+ sep3 += source;
22916
22916
  hasSpace = true;
22917
22917
  break;
22918
22918
  default:
@@ -22955,18 +22955,18 @@ var require_resolve_flow_collection = __commonJS({
22955
22955
  let offset = fc.offset + fc.start.source.length;
22956
22956
  for (let i = 0; i < fc.items.length; ++i) {
22957
22957
  const collItem = fc.items[i];
22958
- const { start, key, sep: sep2, value } = collItem;
22958
+ const { start, key, sep: sep3, value } = collItem;
22959
22959
  const props = resolveProps.resolveProps(start, {
22960
22960
  flow: fcName,
22961
22961
  indicator: "explicit-key-ind",
22962
- next: key ?? sep2?.[0],
22962
+ next: key ?? sep3?.[0],
22963
22963
  offset,
22964
22964
  onError,
22965
22965
  parentIndent: fc.indent,
22966
22966
  startOnNewline: false
22967
22967
  });
22968
22968
  if (!props.found) {
22969
- if (!props.anchor && !props.tag && !sep2 && !value) {
22969
+ if (!props.anchor && !props.tag && !sep3 && !value) {
22970
22970
  if (i === 0 && props.comma)
22971
22971
  onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
22972
22972
  else if (i < fc.items.length - 1)
@@ -23020,8 +23020,8 @@ var require_resolve_flow_collection = __commonJS({
23020
23020
  }
23021
23021
  }
23022
23022
  }
23023
- if (!isMap && !sep2 && !props.found) {
23024
- const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep2, null, props, onError);
23023
+ if (!isMap && !sep3 && !props.found) {
23024
+ const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep3, null, props, onError);
23025
23025
  coll.items.push(valueNode);
23026
23026
  offset = valueNode.range[2];
23027
23027
  if (isBlock(value))
@@ -23033,7 +23033,7 @@ var require_resolve_flow_collection = __commonJS({
23033
23033
  if (isBlock(key))
23034
23034
  onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
23035
23035
  ctx.atKey = false;
23036
- const valueProps = resolveProps.resolveProps(sep2 ?? [], {
23036
+ const valueProps = resolveProps.resolveProps(sep3 ?? [], {
23037
23037
  flow: fcName,
23038
23038
  indicator: "map-value-ind",
23039
23039
  next: value,
@@ -23044,8 +23044,8 @@ var require_resolve_flow_collection = __commonJS({
23044
23044
  });
23045
23045
  if (valueProps.found) {
23046
23046
  if (!isMap && !props.found && ctx.options.strict) {
23047
- if (sep2)
23048
- for (const st of sep2) {
23047
+ if (sep3)
23048
+ for (const st of sep3) {
23049
23049
  if (st === valueProps.found)
23050
23050
  break;
23051
23051
  if (st.type === "newline") {
@@ -23062,7 +23062,7 @@ var require_resolve_flow_collection = __commonJS({
23062
23062
  else
23063
23063
  onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
23064
23064
  }
23065
- const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep2, null, valueProps, onError) : null;
23065
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep3, null, valueProps, onError) : null;
23066
23066
  if (valueNode) {
23067
23067
  if (isBlock(value))
23068
23068
  onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
@@ -23242,7 +23242,7 @@ var require_resolve_block_scalar = __commonJS({
23242
23242
  chompStart = i + 1;
23243
23243
  }
23244
23244
  let value = "";
23245
- let sep2 = "";
23245
+ let sep3 = "";
23246
23246
  let prevMoreIndented = false;
23247
23247
  for (let i = 0; i < contentStart; ++i)
23248
23248
  value += lines[i][0].slice(trimIndent) + "\n";
@@ -23259,24 +23259,24 @@ var require_resolve_block_scalar = __commonJS({
23259
23259
  indent = "";
23260
23260
  }
23261
23261
  if (type === Scalar.Scalar.BLOCK_LITERAL) {
23262
- value += sep2 + indent.slice(trimIndent) + content;
23263
- sep2 = "\n";
23262
+ value += sep3 + indent.slice(trimIndent) + content;
23263
+ sep3 = "\n";
23264
23264
  } else if (indent.length > trimIndent || content[0] === " ") {
23265
- if (sep2 === " ")
23266
- sep2 = "\n";
23267
- else if (!prevMoreIndented && sep2 === "\n")
23268
- sep2 = "\n\n";
23269
- value += sep2 + indent.slice(trimIndent) + content;
23270
- sep2 = "\n";
23265
+ if (sep3 === " ")
23266
+ sep3 = "\n";
23267
+ else if (!prevMoreIndented && sep3 === "\n")
23268
+ sep3 = "\n\n";
23269
+ value += sep3 + indent.slice(trimIndent) + content;
23270
+ sep3 = "\n";
23271
23271
  prevMoreIndented = true;
23272
23272
  } else if (content === "") {
23273
- if (sep2 === "\n")
23273
+ if (sep3 === "\n")
23274
23274
  value += "\n";
23275
23275
  else
23276
- sep2 = "\n";
23276
+ sep3 = "\n";
23277
23277
  } else {
23278
- value += sep2 + content;
23279
- sep2 = " ";
23278
+ value += sep3 + content;
23279
+ sep3 = " ";
23280
23280
  prevMoreIndented = false;
23281
23281
  }
23282
23282
  }
@@ -23458,25 +23458,25 @@ var require_resolve_flow_scalar = __commonJS({
23458
23458
  if (!match)
23459
23459
  return source;
23460
23460
  let res = match[1];
23461
- let sep2 = " ";
23461
+ let sep3 = " ";
23462
23462
  let pos = first.lastIndex;
23463
23463
  line.lastIndex = pos;
23464
23464
  while (match = line.exec(source)) {
23465
23465
  if (match[1] === "") {
23466
- if (sep2 === "\n")
23467
- res += sep2;
23466
+ if (sep3 === "\n")
23467
+ res += sep3;
23468
23468
  else
23469
- sep2 = "\n";
23469
+ sep3 = "\n";
23470
23470
  } else {
23471
- res += sep2 + match[1];
23472
- sep2 = " ";
23471
+ res += sep3 + match[1];
23472
+ sep3 = " ";
23473
23473
  }
23474
23474
  pos = line.lastIndex;
23475
23475
  }
23476
23476
  const last = /[ \t]*(.*)/sy;
23477
23477
  last.lastIndex = pos;
23478
23478
  match = last.exec(source);
23479
- return res + sep2 + (match?.[1] ?? "");
23479
+ return res + sep3 + (match?.[1] ?? "");
23480
23480
  }
23481
23481
  function doubleQuotedValue(source, onError) {
23482
23482
  let res = "";
@@ -24278,14 +24278,14 @@ var require_cst_stringify = __commonJS({
24278
24278
  }
24279
24279
  }
24280
24280
  }
24281
- function stringifyItem({ start, key, sep: sep2, value }) {
24281
+ function stringifyItem({ start, key, sep: sep3, value }) {
24282
24282
  let res = "";
24283
24283
  for (const st of start)
24284
24284
  res += st.source;
24285
24285
  if (key)
24286
24286
  res += stringifyToken(key);
24287
- if (sep2)
24288
- for (const st of sep2)
24287
+ if (sep3)
24288
+ for (const st of sep3)
24289
24289
  res += st.source;
24290
24290
  if (value)
24291
24291
  res += stringifyToken(value);
@@ -25435,18 +25435,18 @@ var require_parser = __commonJS({
25435
25435
  if (this.type === "map-value-ind") {
25436
25436
  const prev = getPrevProps(this.peek(2));
25437
25437
  const start = getFirstKeyStartProps(prev);
25438
- let sep2;
25438
+ let sep3;
25439
25439
  if (scalar.end) {
25440
- sep2 = scalar.end;
25441
- sep2.push(this.sourceToken);
25440
+ sep3 = scalar.end;
25441
+ sep3.push(this.sourceToken);
25442
25442
  delete scalar.end;
25443
25443
  } else
25444
- sep2 = [this.sourceToken];
25444
+ sep3 = [this.sourceToken];
25445
25445
  const map = {
25446
25446
  type: "block-map",
25447
25447
  offset: scalar.offset,
25448
25448
  indent: scalar.indent,
25449
- items: [{ start, key: scalar, sep: sep2 }]
25449
+ items: [{ start, key: scalar, sep: sep3 }]
25450
25450
  };
25451
25451
  this.onKeyLine = true;
25452
25452
  this.stack[this.stack.length - 1] = map;
@@ -25599,15 +25599,15 @@ var require_parser = __commonJS({
25599
25599
  } else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
25600
25600
  const start2 = getFirstKeyStartProps(it.start);
25601
25601
  const key = it.key;
25602
- const sep2 = it.sep;
25603
- sep2.push(this.sourceToken);
25602
+ const sep3 = it.sep;
25603
+ sep3.push(this.sourceToken);
25604
25604
  delete it.key;
25605
25605
  delete it.sep;
25606
25606
  this.stack.push({
25607
25607
  type: "block-map",
25608
25608
  offset: this.offset,
25609
25609
  indent: this.indent,
25610
- items: [{ start: start2, key, sep: sep2 }]
25610
+ items: [{ start: start2, key, sep: sep3 }]
25611
25611
  });
25612
25612
  } else if (start.length > 0) {
25613
25613
  it.sep = it.sep.concat(start, this.sourceToken);
@@ -25801,13 +25801,13 @@ var require_parser = __commonJS({
25801
25801
  const prev = getPrevProps(parent);
25802
25802
  const start = getFirstKeyStartProps(prev);
25803
25803
  fixFlowSeqItems(fc);
25804
- const sep2 = fc.end.splice(1, fc.end.length);
25805
- sep2.push(this.sourceToken);
25804
+ const sep3 = fc.end.splice(1, fc.end.length);
25805
+ sep3.push(this.sourceToken);
25806
25806
  const map = {
25807
25807
  type: "block-map",
25808
25808
  offset: fc.offset,
25809
25809
  indent: fc.indent,
25810
- items: [{ start, key: fc, sep: sep2 }]
25810
+ items: [{ start, key: fc, sep: sep3 }]
25811
25811
  };
25812
25812
  this.onKeyLine = true;
25813
25813
  this.stack[this.stack.length - 1] = map;
@@ -38639,9 +38639,12 @@ Examples:
38639
38639
  outputPath = resolve28(process.cwd(), options.output);
38640
38640
  await writeFile25(outputPath, buffer);
38641
38641
  }
38642
+ const cost = realRunCost(provider, options);
38642
38643
  outputSuccess({
38643
38644
  command: "generate video",
38644
38645
  startedAt,
38646
+ costUsd: cost.costUsd,
38647
+ warnings: cost.warnings,
38645
38648
  data: {
38646
38649
  provider,
38647
38650
  taskId: result?.id,
@@ -38678,6 +38681,26 @@ Examples:
38678
38681
  }
38679
38682
  });
38680
38683
  }
38684
+ function realRunCost(provider, options) {
38685
+ if (provider === "seedance" || provider === "fal") {
38686
+ return {
38687
+ costUsd: estimateSeedanceVideoCostUsd({
38688
+ durationSec: Number(options.duration) || 5,
38689
+ resolution: options.resolution,
38690
+ aspectRatio: options.ratio,
38691
+ fast: options.seedanceModel === "fast",
38692
+ hasVideoReference: Boolean(options.refVideos)
38693
+ }),
38694
+ warnings: []
38695
+ };
38696
+ }
38697
+ return {
38698
+ costUsd: lookupCostEstimateUpperBound("generate video") ?? 5,
38699
+ warnings: [
38700
+ `costUsd is the tier upper bound for ${provider} - actual provider billing is typically lower and is not metered here.`
38701
+ ]
38702
+ };
38703
+ }
38681
38704
  async function prepareSeedanceReferences2(opts) {
38682
38705
  const references = [];
38683
38706
  for (const sourcePath of opts.refImages ?? []) {
@@ -58155,7 +58178,7 @@ var init_design_parse = __esm({
58155
58178
 
58156
58179
  // src/commands/_shared/build-asset-reference.ts
58157
58180
  import { existsSync as existsSync45 } from "node:fs";
58158
- import { extname as extname12, isAbsolute as isAbsolute5, relative as relative9, resolve as resolve54, sep } from "node:path";
58181
+ import { extname as extname12, isAbsolute as isAbsolute5, relative as relative9, resolve as resolve54, sep as sep2 } from "node:path";
58159
58182
  function resolveTypedAssetReference(projectDir, kind, value) {
58160
58183
  const raw = stringOrUndefined2(value);
58161
58184
  if (!raw || !looksLikeAssetPath(raw)) return null;
@@ -58202,7 +58225,7 @@ function resolveReference(projectDir, kind, raw, source, forcedError) {
58202
58225
  return {
58203
58226
  kind,
58204
58227
  raw,
58205
- relPath: withinProject ? rel.split(sep).join("/") : void 0,
58228
+ relPath: withinProject ? rel.split(sep2).join("/") : void 0,
58206
58229
  absPath: withinProject ? absPath : void 0,
58207
58230
  ext,
58208
58231
  exists,
@@ -60356,10 +60379,29 @@ async function executeSceneBuild(opts) {
60356
60379
  });
60357
60380
  warnings.push(...buildPlan.warnings);
60358
60381
  retryWith.push(...buildPlan.retryWith);
60359
- const finishBuildResult = (result) => finalizeBuildResult(projectDir, startedAt, {
60360
- providerResolution: buildPlan.providerResolution,
60361
- ...result
60362
- });
60382
+ const finishBuildResult = async (result) => {
60383
+ const withResolution = {
60384
+ providerResolution: buildPlan.providerResolution,
60385
+ ...result
60386
+ };
60387
+ let reportResult = withResolution;
60388
+ if (opts.beatId && result.beats?.length) {
60389
+ try {
60390
+ const parsedAll = parseStoryboard(await loadStoryboardMarkdown(projectDir));
60391
+ reportResult = {
60392
+ ...withResolution,
60393
+ beats: mergeBeatOutcomes(
60394
+ collectExistingBeatOutcomes(parsedAll.beats, projectDir),
60395
+ result.beats
60396
+ ),
60397
+ beatSummary: void 0
60398
+ // recomputed from the merged beats
60399
+ };
60400
+ } catch {
60401
+ }
60402
+ }
60403
+ return finalizeBuildResult(projectDir, startedAt, withResolution, reportResult);
60404
+ };
60363
60405
  if (shouldRunStage(selectedStage, "assets") || shouldRunStage(selectedStage, "sync")) {
60364
60406
  if (!ffmpegToolsAvailable()) {
60365
60407
  return finishBuildResult({
@@ -62171,26 +62213,30 @@ async function apiKeyForVideoProvider(provider, projectDir) {
62171
62213
  const providerKey = provider === "seedance" ? "fal" : provider === "grok" ? "xai" : provider === "veo" ? "google" : provider;
62172
62214
  return getApiKeyFromConfig(providerKey, { cwd: projectDir });
62173
62215
  }
62174
- async function finalizeBuildResult(projectDir, startedAt, result) {
62216
+ async function finalizeBuildResult(projectDir, startedAt, result, reportResult = result) {
62175
62217
  const reportPath = join27(projectDir, "build-report.json");
62176
- if (result.stageReports) {
62177
- for (const report of Object.values(result.stageReports)) {
62178
- if (report.status === "pending") report.status = "skipped";
62218
+ for (const source of /* @__PURE__ */ new Set([result, reportResult])) {
62219
+ if (source.stageReports) {
62220
+ for (const report of Object.values(source.stageReports)) {
62221
+ if (report.status === "pending") report.status = "skipped";
62222
+ }
62179
62223
  }
62180
62224
  }
62181
- const withMeta = {
62182
- ...result,
62183
- status: result.status ?? buildWorkflowStatus(result),
62184
- currentStage: result.currentStage ?? buildCurrentStage(result),
62185
- beatSummary: result.beatSummary ?? summarizeBuildBeats(projectDir, result.beats),
62186
- sceneRepair: result.sceneRepair ?? skippedSceneRepairSummary(),
62225
+ const decorate = (base) => ({
62226
+ ...base,
62227
+ status: base.status ?? buildWorkflowStatus(base),
62228
+ currentStage: base.currentStage ?? buildCurrentStage(base),
62229
+ beatSummary: base.beatSummary ?? summarizeBuildBeats(projectDir, base.beats),
62230
+ sceneRepair: base.sceneRepair ?? skippedSceneRepairSummary(),
62187
62231
  reportPath,
62188
62232
  totalLatencyMs: Date.now() - startedAt
62189
- };
62233
+ });
62234
+ const withMeta = decorate(result);
62235
+ const reportMeta = reportResult === result ? withMeta : decorate(reportResult);
62190
62236
  try {
62191
62237
  await writeFile45(
62192
62238
  reportPath,
62193
- JSON.stringify(toBuildReport(projectDir, withMeta), null, 2) + "\n",
62239
+ JSON.stringify(toBuildReport(projectDir, reportMeta), null, 2) + "\n",
62194
62240
  "utf-8"
62195
62241
  );
62196
62242
  } catch {
@@ -72728,7 +72774,7 @@ init_source();
72728
72774
  // package.json
72729
72775
  var package_default = {
72730
72776
  name: "@vibeframe/cli",
72731
- version: "0.115.0",
72777
+ version: "0.115.1",
72732
72778
  description: "Frontier AI video generation for coding agents - Seedance, Runway, Veo, and Kling on your own keys, behind a hard cost cap",
72733
72779
  private: false,
72734
72780
  license: "MIT",
@@ -79739,8 +79785,8 @@ var HOST_CONFIG_DIRS = {
79739
79785
  };
79740
79786
  function isOnPath(binary, env2) {
79741
79787
  const path2 = env2.PATH ?? env2.Path ?? "";
79742
- const sep2 = process.platform === "win32" ? ";" : ":";
79743
- for (const dir of path2.split(sep2)) {
79788
+ const sep3 = process.platform === "win32" ? ";" : ":";
79789
+ for (const dir of path2.split(sep3)) {
79744
79790
  if (!dir) continue;
79745
79791
  if (existsSync39(join20(dir, binary))) return true;
79746
79792
  if (process.platform === "win32" && existsSync39(join20(dir, `${binary}.exe`))) return true;
@@ -80986,7 +81032,7 @@ init_esm();
80986
81032
  init_source();
80987
81033
  import { existsSync as existsSync41 } from "node:fs";
80988
81034
  import { mkdir as mkdir22, readFile as readFile36, writeFile as writeFile40 } from "node:fs/promises";
80989
- import { basename as basename19, dirname as dirname17, resolve as resolve50 } from "node:path";
81035
+ import { basename as basename19, dirname as dirname17, resolve as resolve50, sep } from "node:path";
80990
81036
  init_scene_project();
80991
81037
  init_visual_styles();
80992
81038
 
@@ -82166,10 +82212,14 @@ async function runSceneInit(projectDirArg, options, startedAt) {
82166
82212
  const storyboardPath2 = resolve50(projectDir, "STORYBOARD.md");
82167
82213
  const designPath = resolve50(projectDir, "DESIGN.md");
82168
82214
  if (options.force || result.created.includes(storyboardPath2) || !existsSync41(storyboardPath2)) {
82169
- const plan = await writeStoryboardAsBundle(projectDir, draft.storyboardMd);
82215
+ const plan = await rewriteBundleFromMarkdown(projectDir, draft.storyboardMd);
82170
82216
  if (!result.created.includes(storyboardPath2)) result.created.push(storyboardPath2);
82171
- for (const file of plan.scenes) {
82172
- const scenePath = resolve50(projectDir, file.path);
82217
+ const planScenePaths = new Set(plan.scenes.map((file) => resolve50(projectDir, file.path)));
82218
+ const scenesDir = resolve50(projectDir, "scenes") + sep;
82219
+ result.created = result.created.filter(
82220
+ (path2) => !path2.startsWith(scenesDir) || planScenePaths.has(path2)
82221
+ );
82222
+ for (const scenePath of planScenePaths) {
82173
82223
  if (!result.created.includes(scenePath)) result.created.push(scenePath);
82174
82224
  }
82175
82225
  }
@@ -34178,10 +34178,29 @@ async function executeSceneBuild(opts) {
34178
34178
  });
34179
34179
  warnings.push(...buildPlan.warnings);
34180
34180
  retryWith.push(...buildPlan.retryWith);
34181
- const finishBuildResult = (result) => finalizeBuildResult(projectDir, startedAt, {
34182
- providerResolution: buildPlan.providerResolution,
34183
- ...result
34184
- });
34181
+ const finishBuildResult = async (result) => {
34182
+ const withResolution = {
34183
+ providerResolution: buildPlan.providerResolution,
34184
+ ...result
34185
+ };
34186
+ let reportResult = withResolution;
34187
+ if (opts.beatId && result.beats?.length) {
34188
+ try {
34189
+ const parsedAll = parseStoryboard(await loadStoryboardMarkdown(projectDir));
34190
+ reportResult = {
34191
+ ...withResolution,
34192
+ beats: mergeBeatOutcomes(
34193
+ collectExistingBeatOutcomes(parsedAll.beats, projectDir),
34194
+ result.beats
34195
+ ),
34196
+ beatSummary: void 0
34197
+ // recomputed from the merged beats
34198
+ };
34199
+ } catch {
34200
+ }
34201
+ }
34202
+ return finalizeBuildResult(projectDir, startedAt, withResolution, reportResult);
34203
+ };
34185
34204
  if (shouldRunStage(selectedStage, "assets") || shouldRunStage(selectedStage, "sync")) {
34186
34205
  if (!ffmpegToolsAvailable()) {
34187
34206
  return finishBuildResult({
@@ -35993,26 +36012,30 @@ async function apiKeyForVideoProvider(provider, projectDir) {
35993
36012
  const providerKey = provider === "seedance" ? "fal" : provider === "grok" ? "xai" : provider === "veo" ? "google" : provider;
35994
36013
  return getApiKeyFromConfig(providerKey, { cwd: projectDir });
35995
36014
  }
35996
- async function finalizeBuildResult(projectDir, startedAt, result) {
36015
+ async function finalizeBuildResult(projectDir, startedAt, result, reportResult = result) {
35997
36016
  const reportPath = join16(projectDir, "build-report.json");
35998
- if (result.stageReports) {
35999
- for (const report of Object.values(result.stageReports)) {
36000
- if (report.status === "pending") report.status = "skipped";
36017
+ for (const source of /* @__PURE__ */ new Set([result, reportResult])) {
36018
+ if (source.stageReports) {
36019
+ for (const report of Object.values(source.stageReports)) {
36020
+ if (report.status === "pending") report.status = "skipped";
36021
+ }
36001
36022
  }
36002
36023
  }
36003
- const withMeta = {
36004
- ...result,
36005
- status: result.status ?? buildWorkflowStatus(result),
36006
- currentStage: result.currentStage ?? buildCurrentStage(result),
36007
- beatSummary: result.beatSummary ?? summarizeBuildBeats(projectDir, result.beats),
36008
- sceneRepair: result.sceneRepair ?? skippedSceneRepairSummary(),
36024
+ const decorate = (base) => ({
36025
+ ...base,
36026
+ status: base.status ?? buildWorkflowStatus(base),
36027
+ currentStage: base.currentStage ?? buildCurrentStage(base),
36028
+ beatSummary: base.beatSummary ?? summarizeBuildBeats(projectDir, base.beats),
36029
+ sceneRepair: base.sceneRepair ?? skippedSceneRepairSummary(),
36009
36030
  reportPath,
36010
36031
  totalLatencyMs: Date.now() - startedAt
36011
- };
36032
+ });
36033
+ const withMeta = decorate(result);
36034
+ const reportMeta = reportResult === result ? withMeta : decorate(reportResult);
36012
36035
  try {
36013
36036
  await writeFile17(
36014
36037
  reportPath,
36015
- JSON.stringify(toBuildReport(projectDir, withMeta), null, 2) + "\n",
36038
+ JSON.stringify(toBuildReport(projectDir, reportMeta), null, 2) + "\n",
36016
36039
  "utf-8"
36017
36040
  );
36018
36041
  } catch {
@@ -45568,9 +45591,12 @@ Examples:
45568
45591
  outputPath = resolve49(process.cwd(), options.output);
45569
45592
  await writeFile35(outputPath, buffer);
45570
45593
  }
45594
+ const cost = realRunCost(provider, options);
45571
45595
  outputSuccess({
45572
45596
  command: "generate video",
45573
45597
  startedAt,
45598
+ costUsd: cost.costUsd,
45599
+ warnings: cost.warnings,
45574
45600
  data: {
45575
45601
  provider,
45576
45602
  taskId: result?.id,
@@ -45607,6 +45633,26 @@ Examples:
45607
45633
  }
45608
45634
  });
45609
45635
  }
45636
+ function realRunCost(provider, options) {
45637
+ if (provider === "seedance" || provider === "fal") {
45638
+ return {
45639
+ costUsd: estimateSeedanceVideoCostUsd({
45640
+ durationSec: Number(options.duration) || 5,
45641
+ resolution: options.resolution,
45642
+ aspectRatio: options.ratio,
45643
+ fast: options.seedanceModel === "fast",
45644
+ hasVideoReference: Boolean(options.refVideos)
45645
+ }),
45646
+ warnings: []
45647
+ };
45648
+ }
45649
+ return {
45650
+ costUsd: lookupCostEstimateUpperBound("generate video") ?? 5,
45651
+ warnings: [
45652
+ `costUsd is the tier upper bound for ${provider} - actual provider billing is typically lower and is not metered here.`
45653
+ ]
45654
+ };
45655
+ }
45610
45656
  async function prepareSeedanceReferences2(opts) {
45611
45657
  const references = [];
45612
45658
  for (const sourcePath of opts.refImages ?? []) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeframe/cli",
3
- "version": "0.115.0",
3
+ "version": "0.115.1",
4
4
  "description": "Frontier AI video generation for coding agents - Seedance, Runway, Veo, and Kling on your own keys, behind a hard cost cap",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -91,8 +91,8 @@
91
91
  "tsx": "^4.21.0",
92
92
  "typescript": "^5.3.3",
93
93
  "vitest": "^1.2.2",
94
- "@vibeframe/ai-providers": "0.115.0",
95
- "@vibeframe/core": "0.115.0"
94
+ "@vibeframe/core": "0.115.1",
95
+ "@vibeframe/ai-providers": "0.115.1"
96
96
  },
97
97
  "engines": {
98
98
  "node": ">=20"