@vibeframe/mcp-server 0.79.3 → 0.80.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.
Files changed (3) hide show
  1. package/README.md +6 -5
  2. package/dist/index.js +479 -367
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -14031,6 +14031,9 @@ function getSetupProviders() {
14031
14031
  function getAllApiKeys() {
14032
14032
  return [...apiKeyRegistry.values()];
14033
14033
  }
14034
+ function getKeyFormat(configKey) {
14035
+ return apiKeyRegistry.get(configKey)?.keyFormat;
14036
+ }
14034
14037
  function getAllProviders() {
14035
14038
  return [...providerRegistry2.values()];
14036
14039
  }
@@ -14055,7 +14058,8 @@ var init_api_keys = __esm({
14055
14058
  showInSetup: true,
14056
14059
  setupDescription: "gpt-image-2 image gen ($, default since v0.56), Whisper transcribe, Agent",
14057
14060
  envExampleComment: "OpenAI API Key (Whisper transcription, gpt-image-2 \u2014 default text-to-image since v0.56)",
14058
- envExampleUrl: "https://platform.openai.com/api-keys"
14061
+ envExampleUrl: "https://platform.openai.com/api-keys",
14062
+ keyFormat: { prefix: /^sk-/, example: "sk-..." }
14059
14063
  });
14060
14064
  defineApiKey({
14061
14065
  configKey: "google",
@@ -14064,7 +14068,8 @@ var init_api_keys = __esm({
14064
14068
  showInSetup: true,
14065
14069
  setupDescription: "Gemini \u2014 image gen (free tier), video analysis ($), Veo ($$)",
14066
14070
  envExampleComment: "Google API Key (Gemini auto-edit suggestions, image gen, Veo video)",
14067
- envExampleUrl: "https://aistudio.google.com/apikey"
14071
+ envExampleUrl: "https://aistudio.google.com/apikey",
14072
+ keyFormat: { prefix: /^AIza/, example: "AIza..." }
14068
14073
  });
14069
14074
  defineApiKey({
14070
14075
  configKey: "anthropic",
@@ -14073,7 +14078,8 @@ var init_api_keys = __esm({
14073
14078
  showInSetup: true,
14074
14079
  setupDescription: "Claude \u2014 storyboard, color grade, reframe, Agent ($)",
14075
14080
  envExampleComment: "Anthropic API Key (Claude motion graphics & storyboarding)",
14076
- envExampleUrl: "https://console.anthropic.com/"
14081
+ envExampleUrl: "https://console.anthropic.com/",
14082
+ keyFormat: { prefix: /^sk-ant-/, example: "sk-ant-..." }
14077
14083
  });
14078
14084
  defineApiKey({
14079
14085
  configKey: "elevenlabs",
@@ -14082,7 +14088,8 @@ var init_api_keys = __esm({
14082
14088
  showInSetup: true,
14083
14089
  setupDescription: "TTS ($), SFX, music, voice clone, dubbing \u2014 skip to use local Kokoro",
14084
14090
  envExampleComment: "ElevenLabs API Key (text-to-speech \u2014 Kokoro local fallback runs when this is unset, since v0.54)",
14085
- envExampleUrl: "https://elevenlabs.io/api"
14091
+ envExampleUrl: "https://elevenlabs.io/api",
14092
+ keyFormat: { prefix: /^sk_/, example: "sk_..." }
14086
14093
  });
14087
14094
  defineApiKey({
14088
14095
  configKey: "fal",
@@ -14100,7 +14107,8 @@ var init_api_keys = __esm({
14100
14107
  showInSetup: true,
14101
14108
  setupDescription: "Grok \u2014 video gen with audio ($$), image ($), Agent",
14102
14109
  envExampleComment: "xAI API Key (Grok video generation \u2014 fallback when no FAL_KEY)",
14103
- envExampleUrl: "https://console.x.ai/"
14110
+ envExampleUrl: "https://console.x.ai/",
14111
+ keyFormat: { prefix: /^xai-/, example: "xai-..." }
14104
14112
  });
14105
14113
  defineApiKey({
14106
14114
  configKey: "runway",
@@ -14109,7 +14117,8 @@ var init_api_keys = __esm({
14109
14117
  showInSetup: true,
14110
14118
  setupDescription: "Gen-4.5 video generation ($$)",
14111
14119
  envExampleComment: "Runway API Secret (Runway Gen-4.5 video generation)",
14112
- envExampleUrl: "https://app.runwayml.com/settings/api-keys"
14120
+ envExampleUrl: "https://app.runwayml.com/settings/api-keys",
14121
+ keyFormat: { prefix: /^key_/, example: "key_..." }
14113
14122
  });
14114
14123
  defineApiKey({
14115
14124
  configKey: "kling",
@@ -14119,7 +14128,8 @@ var init_api_keys = __esm({
14119
14128
  setupDescription: "v2.5/v3 video \u2014 std ($$) and pro ($$$) modes",
14120
14129
  envExampleComment: "Kling API Key (Kling video generation)",
14121
14130
  envExampleUrl: "https://platform.klingai.com/",
14122
- envExampleExtraLines: ["Format: ACCESS_KEY:SECRET_KEY"]
14131
+ envExampleExtraLines: ["Format: ACCESS_KEY:SECRET_KEY"],
14132
+ keyFormat: { prefix: /:/, example: "ACCESS_KEY:SECRET_KEY" }
14123
14133
  });
14124
14134
  defineApiKey({
14125
14135
  configKey: "replicate",
@@ -14128,7 +14138,8 @@ var init_api_keys = __esm({
14128
14138
  showInSetup: true,
14129
14139
  setupDescription: "MusicGen background music ($, max 30s)",
14130
14140
  envExampleComment: "Replicate API Token (music generation, video upscale, audio restoration)",
14131
- envExampleUrl: "https://replicate.com/account/api-tokens"
14141
+ envExampleUrl: "https://replicate.com/account/api-tokens",
14142
+ keyFormat: { prefix: /^r8_/, example: "r8_..." }
14132
14143
  });
14133
14144
  defineApiKey({
14134
14145
  configKey: "openrouter",
@@ -14137,7 +14148,8 @@ var init_api_keys = __esm({
14137
14148
  showInSetup: true,
14138
14149
  setupDescription: "300+ models via one key \u2014 Agent only (pay per model)",
14139
14150
  envExampleComment: "OpenRouter API Key (300+ AI models via unified API, used by `vibe agent`)",
14140
- envExampleUrl: "https://openrouter.ai/keys"
14151
+ envExampleUrl: "https://openrouter.ai/keys",
14152
+ keyFormat: { prefix: /^sk-or-/, example: "sk-or-..." }
14141
14153
  });
14142
14154
  defineApiKey({
14143
14155
  configKey: "imgbb",
@@ -24922,6 +24934,7 @@ __export(dist_exports, {
24922
24934
  getAllProviders: () => getAllProviders,
24923
24935
  getBestProviderForCapability: () => getBestProviderForCapability,
24924
24936
  getCommandKeyMap: () => getCommandKeyMap,
24937
+ getKeyFormat: () => getKeyFormat,
24925
24938
  getProviderEnvVars: () => getProviderEnvVars,
24926
24939
  getProvidersFor: () => getProvidersFor,
24927
24940
  getSetupProviders: () => getSetupProviders,
@@ -127672,7 +127685,7 @@ var require_typescript2 = __commonJS({
127672
127685
  walkUpParenthesizedTypesAndGetParentAndChild: () => walkUpParenthesizedTypesAndGetParentAndChild,
127673
127686
  whitespaceOrMapCommentRegExp: () => whitespaceOrMapCommentRegExp,
127674
127687
  writeCommentRange: () => writeCommentRange,
127675
- writeFile: () => writeFile43,
127688
+ writeFile: () => writeFile44,
127676
127689
  writeFileEnsuringDirectories: () => writeFileEnsuringDirectories,
127677
127690
  zipWith: () => zipWith
127678
127691
  });
@@ -146315,7 +146328,7 @@ ${lanes.join("\n")}
146315
146328
  sourceFilePath = isSourceFileInCommonSourceDirectory ? sourceFilePath.substring(commonSourceDirectory.length) : sourceFilePath;
146316
146329
  return combinePaths(newDirPath, sourceFilePath);
146317
146330
  }
146318
- function writeFile43(host, diagnostics, fileName, text, writeByteOrderMark, sourceFiles, data) {
146331
+ function writeFile44(host, diagnostics, fileName, text, writeByteOrderMark, sourceFiles, data) {
146319
146332
  host.writeFile(
146320
146333
  fileName,
146321
146334
  text,
@@ -147409,15 +147422,15 @@ ${lanes.join("\n")}
147409
147422
  if (isAccessExpression(name.parent) && isRightSideOfAccessExpression(name)) {
147410
147423
  return walkAccessExpression(name.parent);
147411
147424
  }
147412
- function walkAccessExpression(access7) {
147413
- if (access7.kind === 212) {
147414
- const res = action(access7.name);
147425
+ function walkAccessExpression(access8) {
147426
+ if (access8.kind === 212) {
147427
+ const res = action(access8.name);
147415
147428
  if (res !== void 0) {
147416
147429
  return res;
147417
147430
  }
147418
- } else if (access7.kind === 213) {
147419
- if (isIdentifier(access7.argumentExpression) || isStringLiteralLike(access7.argumentExpression)) {
147420
- const res = action(access7.argumentExpression);
147431
+ } else if (access8.kind === 213) {
147432
+ if (isIdentifier(access8.argumentExpression) || isStringLiteralLike(access8.argumentExpression)) {
147433
+ const res = action(access8.argumentExpression);
147421
147434
  if (res !== void 0) {
147422
147435
  return res;
147423
147436
  }
@@ -147425,11 +147438,11 @@ ${lanes.join("\n")}
147425
147438
  return void 0;
147426
147439
  }
147427
147440
  }
147428
- if (isAccessExpression(access7.expression)) {
147429
- return walkAccessExpression(access7.expression);
147441
+ if (isAccessExpression(access8.expression)) {
147442
+ return walkAccessExpression(access8.expression);
147430
147443
  }
147431
- if (isIdentifier(access7.expression)) {
147432
- return action(access7.expression);
147444
+ if (isIdentifier(access8.expression)) {
147445
+ return action(access8.expression);
147433
147446
  }
147434
147447
  return void 0;
147435
147448
  }
@@ -156682,11 +156695,11 @@ ${lanes.join("\n")}
156682
156695
  )
156683
156696
  );
156684
156697
  }
156685
- function createESDecorateClassElementAccessObject(name, access7) {
156698
+ function createESDecorateClassElementAccessObject(name, access8) {
156686
156699
  const properties = [];
156687
156700
  properties.push(createESDecorateClassElementAccessHasMethod(name));
156688
- if (access7.get) properties.push(createESDecorateClassElementAccessGetMethod(name));
156689
- if (access7.set) properties.push(createESDecorateClassElementAccessSetMethod(name));
156701
+ if (access8.get) properties.push(createESDecorateClassElementAccessGetMethod(name));
156702
+ if (access8.set) properties.push(createESDecorateClassElementAccessSetMethod(name));
156690
156703
  return factory2.createObjectLiteralExpression(properties);
156691
156704
  }
156692
156705
  function createESDecorateClassElementContextObject(contextIn) {
@@ -184203,7 +184216,7 @@ ${lanes.join("\n")}
184203
184216
  return false;
184204
184217
  }
184205
184218
  function isTypeSymbolAccessible(typeSymbol, enclosingDeclaration) {
184206
- const access7 = isSymbolAccessibleWorker(
184219
+ const access8 = isSymbolAccessibleWorker(
184207
184220
  typeSymbol,
184208
184221
  enclosingDeclaration,
184209
184222
  788968,
@@ -184212,10 +184225,10 @@ ${lanes.join("\n")}
184212
184225
  /*allowModules*/
184213
184226
  true
184214
184227
  );
184215
- return access7.accessibility === 0;
184228
+ return access8.accessibility === 0;
184216
184229
  }
184217
184230
  function isValueSymbolAccessible(typeSymbol, enclosingDeclaration) {
184218
- const access7 = isSymbolAccessibleWorker(
184231
+ const access8 = isSymbolAccessibleWorker(
184219
184232
  typeSymbol,
184220
184233
  enclosingDeclaration,
184221
184234
  111551,
@@ -184224,10 +184237,10 @@ ${lanes.join("\n")}
184224
184237
  /*allowModules*/
184225
184238
  true
184226
184239
  );
184227
- return access7.accessibility === 0;
184240
+ return access8.accessibility === 0;
184228
184241
  }
184229
184242
  function isSymbolAccessibleByFlags(typeSymbol, enclosingDeclaration, flags) {
184230
- const access7 = isSymbolAccessibleWorker(
184243
+ const access8 = isSymbolAccessibleWorker(
184231
184244
  typeSymbol,
184232
184245
  enclosingDeclaration,
184233
184246
  flags,
@@ -184236,7 +184249,7 @@ ${lanes.join("\n")}
184236
184249
  /*allowModules*/
184237
184250
  false
184238
184251
  );
184239
- return access7.accessibility === 0;
184252
+ return access8.accessibility === 0;
184240
184253
  }
184241
184254
  function isAnySymbolAccessible(symbols, enclosingDeclaration, initialSymbol, meaning, shouldComputeAliasesToMakeVisible, allowModules) {
184242
184255
  if (!length(symbols)) return;
@@ -204546,19 +204559,19 @@ ${lanes.join("\n")}
204546
204559
  }
204547
204560
  return false;
204548
204561
  }
204549
- function getAccessedPropertyName(access7) {
204550
- if (isPropertyAccessExpression(access7)) {
204551
- return access7.name.escapedText;
204562
+ function getAccessedPropertyName(access8) {
204563
+ if (isPropertyAccessExpression(access8)) {
204564
+ return access8.name.escapedText;
204552
204565
  }
204553
- if (isElementAccessExpression(access7)) {
204554
- return tryGetElementAccessExpressionName(access7);
204566
+ if (isElementAccessExpression(access8)) {
204567
+ return tryGetElementAccessExpressionName(access8);
204555
204568
  }
204556
- if (isBindingElement(access7)) {
204557
- const name = getDestructuringPropertyName(access7);
204569
+ if (isBindingElement(access8)) {
204570
+ const name = getDestructuringPropertyName(access8);
204558
204571
  return name ? escapeLeadingUnderscores(name) : void 0;
204559
204572
  }
204560
- if (isParameter(access7)) {
204561
- return "" + access7.parent.parameters.indexOf(access7);
204573
+ if (isParameter(access8)) {
204574
+ return "" + access8.parent.parameters.indexOf(access8);
204562
204575
  }
204563
204576
  return void 0;
204564
204577
  }
@@ -205773,9 +205786,9 @@ ${lanes.join("\n")}
205773
205786
  type = narrowTypeBySwitchOptionalChainContainment(type, flow.node, (t) => !(t.flags & 131072 || t.flags & 128 && t.value === "undefined"));
205774
205787
  }
205775
205788
  }
205776
- const access7 = getDiscriminantPropertyAccess(expr, type);
205777
- if (access7) {
205778
- type = narrowTypeBySwitchOnDiscriminantProperty(type, access7, flow.node);
205789
+ const access8 = getDiscriminantPropertyAccess(expr, type);
205790
+ if (access8) {
205791
+ type = narrowTypeBySwitchOnDiscriminantProperty(type, access8, flow.node);
205779
205792
  }
205780
205793
  }
205781
205794
  return createFlowType(type, isIncomplete(flowType));
@@ -205937,26 +205950,26 @@ ${lanes.join("\n")}
205937
205950
  }
205938
205951
  function getDiscriminantPropertyAccess(expr, computedType) {
205939
205952
  if (declaredType.flags & 1048576 || computedType.flags & 1048576) {
205940
- const access7 = getCandidateDiscriminantPropertyAccess(expr);
205941
- if (access7) {
205942
- const name = getAccessedPropertyName(access7);
205953
+ const access8 = getCandidateDiscriminantPropertyAccess(expr);
205954
+ if (access8) {
205955
+ const name = getAccessedPropertyName(access8);
205943
205956
  if (name) {
205944
205957
  const type = declaredType.flags & 1048576 && isTypeSubsetOf(computedType, declaredType) ? declaredType : computedType;
205945
205958
  if (isDiscriminantProperty(type, name)) {
205946
- return access7;
205959
+ return access8;
205947
205960
  }
205948
205961
  }
205949
205962
  }
205950
205963
  }
205951
205964
  return void 0;
205952
205965
  }
205953
- function narrowTypeByDiscriminant(type, access7, narrowType2) {
205954
- const propName = getAccessedPropertyName(access7);
205966
+ function narrowTypeByDiscriminant(type, access8, narrowType2) {
205967
+ const propName = getAccessedPropertyName(access8);
205955
205968
  if (propName === void 0) {
205956
205969
  return type;
205957
205970
  }
205958
- const optionalChain = isOptionalChain(access7);
205959
- const removeNullable = strictNullChecks && (optionalChain || isNonNullAccess(access7)) && maybeTypeOfKind(
205971
+ const optionalChain = isOptionalChain(access8);
205972
+ const removeNullable = strictNullChecks && (optionalChain || isNonNullAccess(access8)) && maybeTypeOfKind(
205960
205973
  type,
205961
205974
  98304
205962
205975
  /* Nullable */
@@ -205976,27 +205989,27 @@ ${lanes.join("\n")}
205976
205989
  return !(discriminantType.flags & 131072) && !(narrowedPropType.flags & 131072) && areTypesComparable(narrowedPropType, discriminantType);
205977
205990
  });
205978
205991
  }
205979
- function narrowTypeByDiscriminantProperty(type, access7, operator, value, assumeTrue) {
205992
+ function narrowTypeByDiscriminantProperty(type, access8, operator, value, assumeTrue) {
205980
205993
  if ((operator === 37 || operator === 38) && type.flags & 1048576) {
205981
205994
  const keyPropertyName = getKeyPropertyName(type);
205982
- if (keyPropertyName && keyPropertyName === getAccessedPropertyName(access7)) {
205995
+ if (keyPropertyName && keyPropertyName === getAccessedPropertyName(access8)) {
205983
205996
  const candidate = getConstituentTypeForKeyType(type, getTypeOfExpression(value));
205984
205997
  if (candidate) {
205985
205998
  return operator === (assumeTrue ? 37 : 38) ? candidate : isUnitType(getTypeOfPropertyOfType(candidate, keyPropertyName) || unknownType) ? removeType(type, candidate) : type;
205986
205999
  }
205987
206000
  }
205988
206001
  }
205989
- return narrowTypeByDiscriminant(type, access7, (t) => narrowTypeByEquality(t, operator, value, assumeTrue));
206002
+ return narrowTypeByDiscriminant(type, access8, (t) => narrowTypeByEquality(t, operator, value, assumeTrue));
205990
206003
  }
205991
- function narrowTypeBySwitchOnDiscriminantProperty(type, access7, data) {
205992
- if (data.clauseStart < data.clauseEnd && type.flags & 1048576 && getKeyPropertyName(type) === getAccessedPropertyName(access7)) {
206004
+ function narrowTypeBySwitchOnDiscriminantProperty(type, access8, data) {
206005
+ if (data.clauseStart < data.clauseEnd && type.flags & 1048576 && getKeyPropertyName(type) === getAccessedPropertyName(access8)) {
205993
206006
  const clauseTypes = getSwitchClauseTypes(data.switchStatement).slice(data.clauseStart, data.clauseEnd);
205994
206007
  const candidate = getUnionType(map3(clauseTypes, (t) => getConstituentTypeForKeyType(type, t) || unknownType));
205995
206008
  if (candidate !== unknownType) {
205996
206009
  return candidate;
205997
206010
  }
205998
206011
  }
205999
- return narrowTypeByDiscriminant(type, access7, (t) => narrowTypeBySwitchOnDiscriminant(t, data));
206012
+ return narrowTypeByDiscriminant(type, access8, (t) => narrowTypeBySwitchOnDiscriminant(t, data));
206000
206013
  }
206001
206014
  function narrowTypeByTruthiness(type, expr, assumeTrue) {
206002
206015
  if (isMatchingReference(reference, expr)) {
@@ -206013,9 +206026,9 @@ ${lanes.join("\n")}
206013
206026
  /* NEUndefinedOrNull */
206014
206027
  );
206015
206028
  }
206016
- const access7 = getDiscriminantPropertyAccess(expr, type);
206017
- if (access7) {
206018
- return narrowTypeByDiscriminant(type, access7, (t) => getTypeWithFacts(
206029
+ const access8 = getDiscriminantPropertyAccess(expr, type);
206030
+ if (access8) {
206031
+ return narrowTypeByDiscriminant(type, access8, (t) => getTypeWithFacts(
206019
206032
  t,
206020
206033
  assumeTrue ? 4194304 : 8388608
206021
206034
  /* Falsy */
@@ -206643,9 +206656,9 @@ ${lanes.join("\n")}
206643
206656
  /* NEUndefinedOrNull */
206644
206657
  );
206645
206658
  }
206646
- const access7 = getDiscriminantPropertyAccess(predicateArgument, type);
206647
- if (access7) {
206648
- return narrowTypeByDiscriminant(type, access7, (t) => getNarrowedType(
206659
+ const access8 = getDiscriminantPropertyAccess(predicateArgument, type);
206660
+ if (access8) {
206661
+ return narrowTypeByDiscriminant(type, access8, (t) => getNarrowedType(
206649
206662
  t,
206650
206663
  predicate.type,
206651
206664
  assumeTrue,
@@ -206705,9 +206718,9 @@ ${lanes.join("\n")}
206705
206718
  /* EQUndefinedOrNull */
206706
206719
  );
206707
206720
  }
206708
- const access7 = getDiscriminantPropertyAccess(expr, type);
206709
- if (access7) {
206710
- return narrowTypeByDiscriminant(type, access7, (t) => getTypeWithFacts(
206721
+ const access8 = getDiscriminantPropertyAccess(expr, type);
206722
+ if (access8) {
206723
+ return narrowTypeByDiscriminant(type, access8, (t) => getTypeWithFacts(
206711
206724
  t,
206712
206725
  assumePresent ? 2097152 : 262144
206713
206726
  /* EQUndefinedOrNull */
@@ -255066,7 +255079,7 @@ ${lanes.join("\n")}
255066
255079
  return;
255067
255080
  }
255068
255081
  const buildInfo = host.getBuildInfo() || { version };
255069
- writeFile43(
255082
+ writeFile44(
255070
255083
  host,
255071
255084
  emitterDiagnostics,
255072
255085
  buildInfoPath,
@@ -255278,7 +255291,7 @@ ${lanes.join("\n")}
255278
255291
  }
255279
255292
  if (sourceMapFilePath) {
255280
255293
  const sourceMap = sourceMapGenerator.toString();
255281
- writeFile43(
255294
+ writeFile44(
255282
255295
  host,
255283
255296
  emitterDiagnostics,
255284
255297
  sourceMapFilePath,
@@ -255293,7 +255306,7 @@ ${lanes.join("\n")}
255293
255306
  }
255294
255307
  const text = writer.getText();
255295
255308
  const data = { sourceMapUrlPos, diagnostics: transform2.diagnostics };
255296
- writeFile43(host, emitterDiagnostics, jsFilePath, text, !!compilerOptions.emitBOM, sourceFiles, data);
255309
+ writeFile44(host, emitterDiagnostics, jsFilePath, text, !!compilerOptions.emitBOM, sourceFiles, data);
255297
255310
  writer.clear();
255298
255311
  return !data.skippedDtsWrite;
255299
255312
  }
@@ -261956,9 +261969,9 @@ ${lanes.join("\n")}
261956
261969
  /*ignoreCase*/
261957
261970
  false
261958
261971
  )) {
261959
- const basename17 = getBaseFileName(a.fileName);
261960
- if (basename17 === "lib.d.ts" || basename17 === "lib.es6.d.ts") return 0;
261961
- const name = removeSuffix(removePrefix(basename17, "lib."), ".d.ts");
261972
+ const basename18 = getBaseFileName(a.fileName);
261973
+ if (basename18 === "lib.d.ts" || basename18 === "lib.es6.d.ts") return 0;
261974
+ const name = removeSuffix(removePrefix(basename18, "lib."), ".d.ts");
261962
261975
  const index = libs.indexOf(name);
261963
261976
  if (index !== -1) return index + 1;
261964
261977
  }
@@ -282050,13 +282063,13 @@ interface Symbol {
282050
282063
  for (const element of toConvert.elements) {
282051
282064
  const propertyName = element.propertyName || element.name;
282052
282065
  ts_FindAllReferences_exports.Core.eachSymbolReferenceInFile(element.name, checker, sourceFile, (id) => {
282053
- const access7 = propertyName.kind === 11 ? factory.createElementAccessExpression(factory.createIdentifier(namespaceImportName), factory.cloneNode(propertyName)) : factory.createPropertyAccessExpression(factory.createIdentifier(namespaceImportName), factory.cloneNode(propertyName));
282066
+ const access8 = propertyName.kind === 11 ? factory.createElementAccessExpression(factory.createIdentifier(namespaceImportName), factory.cloneNode(propertyName)) : factory.createPropertyAccessExpression(factory.createIdentifier(namespaceImportName), factory.cloneNode(propertyName));
282054
282067
  if (isShorthandPropertyAssignment(id.parent)) {
282055
- changes.replaceNode(sourceFile, id.parent, factory.createPropertyAssignment(id.text, access7));
282068
+ changes.replaceNode(sourceFile, id.parent, factory.createPropertyAssignment(id.text, access8));
282056
282069
  } else if (isExportSpecifier(id.parent)) {
282057
282070
  neededNamedImports.add(element);
282058
282071
  } else {
282059
- changes.replaceNode(sourceFile, id, access7);
282072
+ changes.replaceNode(sourceFile, id, access8);
282060
282073
  }
282061
282074
  });
282062
282075
  }
@@ -323175,7 +323188,7 @@ ${options.prefix}` : "\n" : options.prefix
323175
323188
  walkUpParenthesizedTypesAndGetParentAndChild: () => walkUpParenthesizedTypesAndGetParentAndChild,
323176
323189
  whitespaceOrMapCommentRegExp: () => whitespaceOrMapCommentRegExp,
323177
323190
  writeCommentRange: () => writeCommentRange,
323178
- writeFile: () => writeFile43,
323191
+ writeFile: () => writeFile44,
323179
323192
  writeFileEnsuringDirectories: () => writeFileEnsuringDirectories,
323180
323193
  zipWith: () => zipWith
323181
323194
  });
@@ -325704,8 +325717,8 @@ ${options.prefix}` : "\n" : options.prefix
325704
325717
  }
325705
325718
  };
325706
325719
  for (const file of files) {
325707
- const basename17 = getBaseFileName(file);
325708
- if (basename17 === "package.json" || basename17 === "bower.json") {
325720
+ const basename18 = getBaseFileName(file);
325721
+ if (basename18 === "package.json" || basename18 === "bower.json") {
325709
325722
  createProjectWatcher(
325710
325723
  file,
325711
325724
  "FileWatcher"
@@ -329377,8 +329390,8 @@ All files are: ${JSON.stringify(names)}`,
329377
329390
  var _a7;
329378
329391
  const fileOrDirectoryPath = removeIgnoredPath(this.toPath(fileOrDirectory));
329379
329392
  if (!fileOrDirectoryPath) return;
329380
- const basename17 = getBaseFileName(fileOrDirectoryPath);
329381
- if (((_a7 = result.affectedModuleSpecifierCacheProjects) == null ? void 0 : _a7.size) && (basename17 === "package.json" || basename17 === "node_modules")) {
329393
+ const basename18 = getBaseFileName(fileOrDirectoryPath);
329394
+ if (((_a7 = result.affectedModuleSpecifierCacheProjects) == null ? void 0 : _a7.size) && (basename18 === "package.json" || basename18 === "node_modules")) {
329382
329395
  result.affectedModuleSpecifierCacheProjects.forEach((project) => {
329383
329396
  var _a23;
329384
329397
  (_a23 = project.getModuleSpecifierCache()) == null ? void 0 : _a23.clear();
@@ -453215,16 +453228,31 @@ var init_project = __esm({
453215
453228
  }
453216
453229
  // ============ Serialization ============
453217
453230
  toJSON() {
453231
+ const state = this.getState();
453218
453232
  return {
453219
453233
  version: "1.0.0",
453220
- state: this.getState()
453234
+ state: {
453235
+ project: state.project,
453236
+ tracks: state.tracks,
453237
+ clips: state.clips,
453238
+ sources: state.sources,
453239
+ transitions: state.transitions
453240
+ }
453221
453241
  };
453222
453242
  }
453223
453243
  static fromJSON(data) {
453224
453244
  const project = new _Project();
453225
453245
  data.state.project.createdAt = new Date(data.state.project.createdAt);
453226
453246
  data.state.project.updatedAt = new Date(data.state.project.updatedAt);
453227
- project.state = data.state;
453247
+ project.state = {
453248
+ ...data.state,
453249
+ currentTime: 0,
453250
+ isPlaying: false,
453251
+ zoom: 50,
453252
+ scrollX: 0,
453253
+ selectedClipIds: [],
453254
+ selectedTrackId: null
453255
+ };
453228
453256
  return project;
453229
453257
  }
453230
453258
  setFilePath(path14) {
@@ -453259,10 +453287,45 @@ var init_engine = __esm({
453259
453287
  }
453260
453288
  });
453261
453289
 
453290
+ // ../cli/src/utils/project-resolver.ts
453291
+ import { access as access5, stat as stat3 } from "node:fs/promises";
453292
+ import { resolve as resolve28 } from "node:path";
453293
+ async function resolveTimelineFile(inputPath, cwd = process.cwd()) {
453294
+ const filePath = resolve28(cwd, inputPath);
453295
+ try {
453296
+ const stats = await stat3(filePath);
453297
+ if (stats.isDirectory()) {
453298
+ const canonical = resolve28(filePath, TIMELINE_FILENAME);
453299
+ try {
453300
+ await access5(canonical);
453301
+ return canonical;
453302
+ } catch {
453303
+ }
453304
+ const legacy = resolve28(filePath, LEGACY_TIMELINE_FILENAME);
453305
+ try {
453306
+ await access5(legacy);
453307
+ return legacy;
453308
+ } catch {
453309
+ return canonical;
453310
+ }
453311
+ }
453312
+ } catch {
453313
+ }
453314
+ return filePath;
453315
+ }
453316
+ var TIMELINE_FILENAME, LEGACY_TIMELINE_FILENAME;
453317
+ var init_project_resolver = __esm({
453318
+ "../cli/src/utils/project-resolver.ts"() {
453319
+ "use strict";
453320
+ TIMELINE_FILENAME = "timeline.json";
453321
+ LEGACY_TIMELINE_FILENAME = "project.vibe.json";
453322
+ }
453323
+ });
453324
+
453262
453325
  // ../cli/src/commands/_shared/execute-fill-gaps.ts
453263
453326
  import { existsSync as existsSync40 } from "node:fs";
453264
453327
  import { readFile as readFile16, writeFile as writeFile16, mkdir as mkdir14, rename as renameFs } from "node:fs/promises";
453265
- import { resolve as resolve28, dirname as dirname20 } from "node:path";
453328
+ import { resolve as resolve29, dirname as dirname20 } from "node:path";
453266
453329
  function detectVideoGaps(videoClips, totalDuration) {
453267
453330
  const gaps = [];
453268
453331
  const sortedClips = [...videoClips].sort((a, b) => a.startTime - b.startTime);
@@ -453341,12 +453404,12 @@ async function executeFillGaps(options) {
453341
453404
  });
453342
453405
  const humanLines = [];
453343
453406
  try {
453344
- onProgress("Loading project...");
453345
- const filePath = resolve28(process.cwd(), options.projectPath);
453407
+ onProgress("Loading timeline...");
453408
+ const filePath = await resolveTimelineFile(options.projectPath);
453346
453409
  if (!existsSync40(filePath)) {
453347
453410
  return {
453348
453411
  success: false,
453349
- error: `Project file not found: ${filePath}`,
453412
+ error: `Timeline file not found: ${filePath}`,
453350
453413
  humanLines
453351
453414
  };
453352
453415
  }
@@ -453477,7 +453540,7 @@ async function executeFillGaps(options) {
453477
453540
  };
453478
453541
  }
453479
453542
  const projectDir = dirname20(filePath);
453480
- const footageDir = options.dir ? resolve28(process.cwd(), options.dir) : resolve28(projectDir, "footage");
453543
+ const footageDir = options.dir ? resolve29(process.cwd(), options.dir) : resolve29(projectDir, "footage");
453481
453544
  if (!existsSync40(footageDir)) {
453482
453545
  await mkdir14(footageDir, { recursive: true });
453483
453546
  }
@@ -453509,7 +453572,7 @@ async function executeFillGaps(options) {
453509
453572
  }
453510
453573
  onProgress("Extracting frame from preceding clip...");
453511
453574
  const frameOffset = clipBefore.sourceStartOffset + clipBefore.duration - 0.1;
453512
- const framePath = resolve28(footageDir, `frame-${gap.start.toFixed(2)}.png`);
453575
+ const framePath = resolve29(footageDir, `frame-${gap.start.toFixed(2)}.png`);
453513
453576
  try {
453514
453577
  await execSafe("ffmpeg", [
453515
453578
  "-i",
@@ -453570,7 +453633,7 @@ async function executeFillGaps(options) {
453570
453633
  continue;
453571
453634
  }
453572
453635
  const videoFileName = `gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}.mp4`;
453573
- const videoPath = resolve28(footageDir, videoFileName);
453636
+ const videoPath = resolve29(footageDir, videoFileName);
453574
453637
  onProgress("Downloading generated video...");
453575
453638
  const videoBuffer = await downloadVideo(finalResult.videoUrl);
453576
453639
  await writeFile16(videoPath, videoBuffer);
@@ -453582,7 +453645,7 @@ async function executeFillGaps(options) {
453582
453645
  const remainingNeeded = targetDuration - generatedDuration;
453583
453646
  const segmentDuration = remainingNeeded > 5 ? "10" : "5";
453584
453647
  onProgress(`Generating additional ${segmentDuration}s segment...`);
453585
- const lastFramePath = resolve28(
453648
+ const lastFramePath = resolve29(
453586
453649
  footageDir,
453587
453650
  `frame-extend-${gap.start.toFixed(2)}-${segmentIndex}.png`
453588
453651
  );
@@ -453638,17 +453701,17 @@ async function executeFillGaps(options) {
453638
453701
  );
453639
453702
  break;
453640
453703
  }
453641
- const segVideoPath = resolve28(
453704
+ const segVideoPath = resolve29(
453642
453705
  footageDir,
453643
453706
  `gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}-seg${segmentIndex}.mp4`
453644
453707
  );
453645
453708
  const segVideoBuffer = await downloadVideo(segFinalResult.videoUrl);
453646
453709
  await writeFile16(segVideoPath, segVideoBuffer);
453647
- const concatListPath = resolve28(footageDir, `concat-${gap.start.toFixed(2)}.txt`);
453710
+ const concatListPath = resolve29(footageDir, `concat-${gap.start.toFixed(2)}.txt`);
453648
453711
  const concatList = generatedVideos.map((v) => `file '${v}'`).join("\n") + `
453649
453712
  file '${segVideoPath}'`;
453650
453713
  await writeFile16(concatListPath, concatList);
453651
- const concatOutputPath = resolve28(
453714
+ const concatOutputPath = resolve29(
453652
453715
  footageDir,
453653
453716
  `gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}-merged.mp4`
453654
453717
  );
@@ -453704,7 +453767,7 @@ file '${segVideoPath}'`;
453704
453767
  humanLines.push("");
453705
453768
  let outputPath = filePath;
453706
453769
  if (generatedCount > 0) {
453707
- outputPath = options.output ? resolve28(process.cwd(), options.output) : filePath;
453770
+ outputPath = options.output ? resolve29(process.cwd(), options.output) : filePath;
453708
453771
  await writeFile16(outputPath, JSON.stringify(project.toJSON(), null, 2));
453709
453772
  humanLines.push(`\u2714 Filled ${generatedCount} gap(s) with AI-generated video`);
453710
453773
  humanLines.push(`Project saved: ${outputPath}`);
@@ -453734,13 +453797,14 @@ var init_execute_fill_gaps = __esm({
453734
453797
  init_engine();
453735
453798
  init_api_key();
453736
453799
  init_exec_safe();
453800
+ init_project_resolver();
453737
453801
  init_ai_helpers();
453738
453802
  }
453739
453803
  });
453740
453804
 
453741
453805
  // ../cli/src/commands/ai-fill-gaps.ts
453742
453806
  function registerFillGapsCommand(aiCommand) {
453743
- aiCommand.command("fill-gaps").description("Fill timeline gaps with AI-generated video (Kling image-to-video)").argument("<project>", "Project file path").option("-p, --provider <provider>", "AI provider (kling)", "kling").option("-o, --output <path>", "Output project path (default: overwrite)").option("-d, --dir <path>", "Directory to save generated videos").option("--prompt <text>", "Custom prompt for video generation").option("--dry-run", "Show gaps without generating").option("--mode <mode>", "Generation mode: std or pro (Kling)", "std").option("-r, --ratio <ratio>", "Aspect ratio: 16:9, 9:16, or 1:1", "16:9").action(async (projectPath, options) => {
453807
+ aiCommand.command("fill-gaps").description("Fill timeline gaps with AI-generated video (Kling image-to-video)").argument("<project>", "Timeline file or directory").option("-p, --provider <provider>", "AI provider (kling)", "kling").option("-o, --output <path>", "Output project path (default: overwrite)").option("-d, --dir <path>", "Directory to save generated videos").option("--prompt <text>", "Custom prompt for video generation").option("--dry-run", "Show gaps without generating").option("--mode <mode>", "Generation mode: std or pro (Kling)", "std").option("-r, --ratio <ratio>", "Aspect ratio: 16:9, 9:16, or 1:1", "16:9").action(async (projectPath, options) => {
453744
453808
  try {
453745
453809
  if (options.output) {
453746
453810
  validateOutputPath(options.output);
@@ -453800,14 +453864,14 @@ __export(edit_cmd_exports, {
453800
453864
  executeSpeedRamp: () => executeSpeedRamp,
453801
453865
  executeUpscale: () => executeUpscale
453802
453866
  });
453803
- import { resolve as resolve29, dirname as dirname21 } from "node:path";
453867
+ import { resolve as resolve30, dirname as dirname21 } from "node:path";
453804
453868
  import { readFile as readFile17, writeFile as writeFile17, mkdir as mkdir15 } from "node:fs/promises";
453805
453869
  async function executeGrade(options) {
453806
453870
  const { videoPath, style, preset, output: output3, analyzeOnly, apiKey } = options;
453807
453871
  try {
453808
453872
  if (!style && !preset) return { success: false, error: "Either style or preset is required" };
453809
453873
  if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
453810
- const absPath = resolve29(process.cwd(), videoPath);
453874
+ const absPath = resolve30(process.cwd(), videoPath);
453811
453875
  let gradeResult;
453812
453876
  if (preset) {
453813
453877
  const claude = new ClaudeProvider();
@@ -453822,7 +453886,7 @@ async function executeGrade(options) {
453822
453886
  if (analyzeOnly) {
453823
453887
  return { success: true, style: preset || style, description: gradeResult.description, ffmpegFilter: gradeResult.ffmpegFilter };
453824
453888
  }
453825
- const outputPath = output3 ? resolve29(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, "-graded$1");
453889
+ const outputPath = output3 ? resolve30(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, "-graded$1");
453826
453890
  await execSafe("ffmpeg", ["-i", absPath, "-vf", gradeResult.ffmpegFilter, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
453827
453891
  return { success: true, outputPath, style: preset || style, description: gradeResult.description, ffmpegFilter: gradeResult.ffmpegFilter };
453828
453892
  } catch (error) {
@@ -453837,7 +453901,7 @@ async function executeSpeedRamp(options) {
453837
453901
  const claudeKey = apiKey || process.env.ANTHROPIC_API_KEY;
453838
453902
  if (!openaiKey) return { success: false, error: "OPENAI_API_KEY required for Whisper transcription" };
453839
453903
  if (!claudeKey) return { success: false, error: "ANTHROPIC_API_KEY required for Claude analysis" };
453840
- const absPath = resolve29(process.cwd(), videoPath);
453904
+ const absPath = resolve30(process.cwd(), videoPath);
453841
453905
  const tempAudio = absPath.replace(/(\.[^.]+)$/, "-temp-audio.mp3");
453842
453906
  await execSafe("ffmpeg", ["-i", absPath, "-vn", "-acodec", "libmp3lame", "-q:a", "2", tempAudio, "-y"]);
453843
453907
  const whisper = new WhisperProvider();
@@ -453862,7 +453926,7 @@ async function executeSpeedRamp(options) {
453862
453926
  if (speedResult.keyframes.length < 2) {
453863
453927
  return { success: false, error: "Not enough keyframes for speed ramping" };
453864
453928
  }
453865
- const outputPath = output3 ? resolve29(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
453929
+ const outputPath = output3 ? resolve30(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
453866
453930
  const setpts = `setpts=${(1 / avgSpeed).toFixed(3)}*PTS`;
453867
453931
  const atempo = avgSpeed >= 0.5 && avgSpeed <= 2 ? `atempo=${avgSpeed.toFixed(3)}` : "";
453868
453932
  if (atempo) {
@@ -453879,7 +453943,7 @@ async function executeReframe(options) {
453879
453943
  const { videoPath, aspect = "9:16", output: output3, analyzeOnly } = options;
453880
453944
  try {
453881
453945
  if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
453882
- const absPath = resolve29(process.cwd(), videoPath);
453946
+ const absPath = resolve30(process.cwd(), videoPath);
453883
453947
  const { stdout: probeOut } = await execSafe("ffprobe", [
453884
453948
  "-v",
453885
453949
  "error",
@@ -453914,7 +453978,7 @@ async function executeReframe(options) {
453914
453978
  keyframeCount: 1
453915
453979
  };
453916
453980
  }
453917
- const outputPath = output3 ? resolve29(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, `-${aspect.replace(":", "x")}$1`);
453981
+ const outputPath = output3 ? resolve30(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, `-${aspect.replace(":", "x")}$1`);
453918
453982
  await execSafe("ffmpeg", ["-i", absPath, "-vf", `crop=${cropWidth}:${cropHeight}:${cropX}:${cropY}`, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
453919
453983
  return { success: true, outputPath, sourceAspect: `${sourceWidth}:${sourceHeight}`, targetAspect: aspect };
453920
453984
  } catch (error) {
@@ -453926,7 +453990,7 @@ async function executeInterpolate(options) {
453926
453990
  try {
453927
453991
  if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
453928
453992
  if (![2, 4, 8].includes(factor)) return { success: false, error: "Factor must be 2, 4, or 8" };
453929
- const absPath = resolve29(process.cwd(), videoPath);
453993
+ const absPath = resolve30(process.cwd(), videoPath);
453930
453994
  const { stdout: fpsOut } = await execSafe("ffprobe", [
453931
453995
  "-v",
453932
453996
  "error",
@@ -453942,7 +454006,7 @@ async function executeInterpolate(options) {
453942
454006
  const originalFps = num / (den || 1);
453943
454007
  const targetFps = options.fps || originalFps * factor;
453944
454008
  const mi = quality === "fast" ? "mi_mode=mci" : "mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1";
453945
- const outputPath = output3 ? resolve29(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, `-slow${factor}x$1`);
454009
+ const outputPath = output3 ? resolve30(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, `-slow${factor}x$1`);
453946
454010
  await execSafe("ffmpeg", ["-i", absPath, "-filter:v", `minterpolate='${mi}:fps=${targetFps}',setpts=${factor}*PTS`, "-an", outputPath, "-y"], { timeout: 6e5 });
453947
454011
  return { success: true, outputPath, originalFps, targetFps, factor };
453948
454012
  } catch (error) {
@@ -453953,7 +454017,7 @@ async function executeUpscale(options) {
453953
454017
  const { videoPath, output: output3, scale = 2, quality = "quality" } = options;
453954
454018
  try {
453955
454019
  if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
453956
- const absPath = resolve29(process.cwd(), videoPath);
454020
+ const absPath = resolve30(process.cwd(), videoPath);
453957
454021
  const { stdout: probeOut } = await execSafe("ffprobe", [
453958
454022
  "-v",
453959
454023
  "error",
@@ -453969,7 +454033,7 @@ async function executeUpscale(options) {
453969
454033
  const targetW = w * scale;
453970
454034
  const targetH = h * scale;
453971
454035
  const scaleFilter = quality === "quality" ? `scale=${targetW}:${targetH}:flags=lanczos` : `scale=${targetW}:${targetH}`;
453972
- const outputPath = output3 ? resolve29(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, `-${scale}x$1`);
454036
+ const outputPath = output3 ? resolve30(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, `-${scale}x$1`);
453973
454037
  await execSafe("ffmpeg", ["-i", absPath, "-vf", scaleFilter, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
453974
454038
  return { success: true, outputPath, originalRes: `${w}x${h}`, targetRes: `${targetW}x${targetH}` };
453975
454039
  } catch (error) {
@@ -454041,7 +454105,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454041
454105
  dryRun: true,
454042
454106
  data: {
454043
454107
  params: {
454044
- videoPath: resolve29(process.cwd(), videoPath),
454108
+ videoPath: resolve30(process.cwd(), videoPath),
454045
454109
  style: options.style || options.preset,
454046
454110
  analyzeOnly: options.analyzeOnly || false
454047
454111
  }
@@ -454068,8 +454132,8 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454068
454132
  }
454069
454133
  spinner2.succeed(source_default.green("Color grade analyzed"));
454070
454134
  if (isJsonMode()) {
454071
- const absPath2 = resolve29(process.cwd(), videoPath);
454072
- const gradeOutputPath = options.output ? resolve29(process.cwd(), options.output) : absPath2.replace(/(\.[^.]+)$/, "-graded$1");
454135
+ const absPath2 = resolve30(process.cwd(), videoPath);
454136
+ const gradeOutputPath = options.output ? resolve30(process.cwd(), options.output) : absPath2.replace(/(\.[^.]+)$/, "-graded$1");
454073
454137
  outputSuccess({
454074
454138
  command: "edit grade",
454075
454139
  startedAt,
@@ -454095,8 +454159,8 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454095
454159
  console.log(source_default.dim("Use without --analyze-only to apply the grade."));
454096
454160
  return;
454097
454161
  }
454098
- const absPath = resolve29(process.cwd(), videoPath);
454099
- const outputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-graded$1");
454162
+ const absPath = resolve30(process.cwd(), videoPath);
454163
+ const outputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-graded$1");
454100
454164
  spinner2.start("Applying color grade...");
454101
454165
  await execSafe("ffmpeg", ["-i", absPath, "-vf", gradeResult.ffmpegFilter, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
454102
454166
  spinner2.succeed(source_default.green("Color grade applied"));
@@ -454126,7 +454190,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454126
454190
  dryRun: true,
454127
454191
  data: {
454128
454192
  params: {
454129
- videoPath: resolve29(process.cwd(), videoPath),
454193
+ videoPath: resolve30(process.cwd(), videoPath),
454130
454194
  texts: options.text,
454131
454195
  style: options.style,
454132
454196
  fontSize: options.fontSize ? parseInt(options.fontSize) : void 0,
@@ -454139,8 +454203,8 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454139
454203
  });
454140
454204
  return;
454141
454205
  }
454142
- const absPath = resolve29(process.cwd(), videoPath);
454143
- const outputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-overlay$1");
454206
+ const absPath = resolve30(process.cwd(), videoPath);
454207
+ const outputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-overlay$1");
454144
454208
  const spinner2 = ora("Applying text overlays...").start();
454145
454209
  const result = await applyTextOverlays({
454146
454210
  videoPath: absPath,
@@ -454198,7 +454262,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454198
454262
  dryRun: true,
454199
454263
  data: {
454200
454264
  params: {
454201
- videoPath: resolve29(process.cwd(), videoPath),
454265
+ videoPath: resolve30(process.cwd(), videoPath),
454202
454266
  style: options.style,
454203
454267
  minSpeed: parseFloat(options.minSpeed),
454204
454268
  maxSpeed: parseFloat(options.maxSpeed),
@@ -454210,7 +454274,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454210
454274
  }
454211
454275
  const openaiApiKey = await requireApiKey("OPENAI_API_KEY", "OpenAI");
454212
454276
  const claudeApiKey = await requireApiKey("ANTHROPIC_API_KEY", "Anthropic", options.apiKey);
454213
- const absPath = resolve29(process.cwd(), videoPath);
454277
+ const absPath = resolve30(process.cwd(), videoPath);
454214
454278
  const spinner2 = ora("Extracting audio...").start();
454215
454279
  const { stdout: speedRampProbe } = await execSafe("ffprobe", [
454216
454280
  "-v",
@@ -454255,7 +454319,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454255
454319
  spinner2.succeed(source_default.green(`Found ${speedResult.keyframes.length} speed keyframes`));
454256
454320
  if (isJsonMode()) {
454257
454321
  const avgSpeed2 = speedResult.keyframes.reduce((sum, kf) => sum + kf.speed, 0) / speedResult.keyframes.length;
454258
- const speedRampOutputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
454322
+ const speedRampOutputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
454259
454323
  outputSuccess({
454260
454324
  command: "edit speed-ramp",
454261
454325
  startedAt,
@@ -454284,7 +454348,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454284
454348
  return;
454285
454349
  }
454286
454350
  spinner2.start("Applying speed ramps...");
454287
- const outputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
454351
+ const outputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
454288
454352
  const avgSpeed = speedResult.keyframes.reduce((sum, kf) => sum + kf.speed, 0) / speedResult.keyframes.length;
454289
454353
  const setpts = `setpts=${(1 / avgSpeed).toFixed(3)}*PTS`;
454290
454354
  const atempo = avgSpeed >= 0.5 && avgSpeed <= 2 ? `atempo=${avgSpeed.toFixed(3)}` : "";
@@ -454318,7 +454382,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454318
454382
  dryRun: true,
454319
454383
  data: {
454320
454384
  params: {
454321
- videoPath: resolve29(process.cwd(), videoPath),
454385
+ videoPath: resolve30(process.cwd(), videoPath),
454322
454386
  aspect: options.aspect,
454323
454387
  focus: options.focus,
454324
454388
  analyzeOnly: options.analyzeOnly || false
@@ -454327,7 +454391,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454327
454391
  });
454328
454392
  return;
454329
454393
  }
454330
- const absPath = resolve29(process.cwd(), videoPath);
454394
+ const absPath = resolve30(process.cwd(), videoPath);
454331
454395
  const spinner2 = ora("Analyzing video...").start();
454332
454396
  const { stdout: probeOut } = await execSafe("ffprobe", [
454333
454397
  "-v",
@@ -454389,7 +454453,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454389
454453
  }
454390
454454
  spinner2.succeed(source_default.green(`Analyzed ${cropKeyframes.length} keyframes`));
454391
454455
  if (isJsonMode()) {
454392
- const reframeOutputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
454456
+ const reframeOutputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
454393
454457
  outputSuccess({
454394
454458
  command: "edit reframe",
454395
454459
  startedAt,
@@ -454424,7 +454488,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454424
454488
  }
454425
454489
  console.log();
454426
454490
  if (options.keyframes) {
454427
- const keyframesPath = resolve29(process.cwd(), options.keyframes);
454491
+ const keyframesPath = resolve30(process.cwd(), options.keyframes);
454428
454492
  await writeFile17(keyframesPath, JSON.stringify(cropKeyframes, null, 2));
454429
454493
  console.log(source_default.green(`Keyframes saved to: ${keyframesPath}`));
454430
454494
  }
@@ -454436,7 +454500,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454436
454500
  const avgCropY = Math.round(cropKeyframes.reduce((sum, kf) => sum + kf.cropY, 0) / cropKeyframes.length);
454437
454501
  const cropWidth = cropKeyframes[0]?.cropWidth || sourceWidth;
454438
454502
  const cropHeight = cropKeyframes[0]?.cropHeight || sourceHeight;
454439
- const outputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
454503
+ const outputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
454440
454504
  spinner2.start("Applying reframe...");
454441
454505
  await execSafe("ffmpeg", ["-i", absPath, "-vf", `crop=${cropWidth}:${cropHeight}:${avgCropX}:${avgCropY}`, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
454442
454506
  spinner2.succeed(source_default.green("Reframe applied"));
@@ -454472,7 +454536,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454472
454536
  dryRun: true,
454473
454537
  data: {
454474
454538
  params: {
454475
- imagePaths: imagePaths.map((p) => resolve29(process.cwd(), p)),
454539
+ imagePaths: imagePaths.map((p) => resolve30(process.cwd(), p)),
454476
454540
  prompt: prompt3,
454477
454541
  provider,
454478
454542
  model: options.model,
@@ -454493,7 +454557,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454493
454557
  const spinner2 = ora(`Reading ${imagePaths.length} image(s)...`).start();
454494
454558
  const imageBuffers = [];
454495
454559
  for (const imagePath of imagePaths) {
454496
- const absPath = resolve29(process.cwd(), imagePath);
454560
+ const absPath = resolve30(process.cwd(), imagePath);
454497
454561
  const buffer = await readFile17(absPath);
454498
454562
  imageBuffers.push(buffer);
454499
454563
  }
@@ -454542,7 +454606,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454542
454606
  }
454543
454607
  spinner2.succeed(source_default.green("Image edited"));
454544
454608
  const img = result.images[0];
454545
- const outputPath = resolve29(process.cwd(), options.output);
454609
+ const outputPath = resolve30(process.cwd(), options.output);
454546
454610
  const saveImage = async () => {
454547
454611
  await mkdir15(dirname21(outputPath), { recursive: true });
454548
454612
  if (img.base64) {
@@ -454584,7 +454648,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454584
454648
  if (options.output) {
454585
454649
  validateOutputPath(options.output);
454586
454650
  }
454587
- const absPath = resolve29(process.cwd(), videoPath);
454651
+ const absPath = resolve30(process.cwd(), videoPath);
454588
454652
  const factor = parseInt(options.factor);
454589
454653
  if (![2, 4, 8].includes(factor)) {
454590
454654
  exitWithError(usageError("Factor must be 2, 4, or 8"));
@@ -454605,7 +454669,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454605
454669
  });
454606
454670
  return;
454607
454671
  }
454608
- const outputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-slow${factor}x$1`);
454672
+ const outputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-slow${factor}x$1`);
454609
454673
  const spinner2 = ora(`Creating ${factor}x slow motion...`).start();
454610
454674
  try {
454611
454675
  const { stdout: fpsOut } = await execSafe("ffprobe", [
@@ -454666,7 +454730,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454666
454730
  if (options.output) {
454667
454731
  validateOutputPath(options.output);
454668
454732
  }
454669
- const absPath = resolve29(process.cwd(), videoPath);
454733
+ const absPath = resolve30(process.cwd(), videoPath);
454670
454734
  const scale = parseInt(options.scale);
454671
454735
  if (scale !== 2 && scale !== 4) {
454672
454736
  exitWithError(usageError("Scale must be 2 or 4"));
@@ -454688,7 +454752,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454688
454752
  return;
454689
454753
  }
454690
454754
  if (options.ffmpeg) {
454691
- const outputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-upscaled-${scale}x$1`);
454755
+ const outputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-upscaled-${scale}x$1`);
454692
454756
  const spinner3 = ora(`Upscaling video with FFmpeg (${scale}x)...`).start();
454693
454757
  try {
454694
454758
  const { stdout: probeOut } = await execSafe("ffprobe", [
@@ -454749,7 +454813,7 @@ __export(ai_image_exports, {
454749
454813
  executeImageGenerate: () => executeImageGenerate,
454750
454814
  executeThumbnailBestFrame: () => executeThumbnailBestFrame
454751
454815
  });
454752
- import { resolve as resolve31, dirname as dirname24 } from "node:path";
454816
+ import { resolve as resolve33, dirname as dirname24 } from "node:path";
454753
454817
  import { readFile as readFile18, writeFile as writeFile19, mkdir as mkdir17 } from "node:fs/promises";
454754
454818
  import { existsSync as existsSync42 } from "node:fs";
454755
454819
  async function executeImageGenerate(options) {
@@ -454792,7 +454856,7 @@ async function executeImageGenerate(options) {
454792
454856
  } else {
454793
454857
  return { success: false, error: "No image data available" };
454794
454858
  }
454795
- outputPath = resolve31(process.cwd(), output3);
454859
+ outputPath = resolve33(process.cwd(), output3);
454796
454860
  await mkdir17(dirname24(outputPath), { recursive: true });
454797
454861
  await writeFile19(outputPath, buffer);
454798
454862
  }
@@ -454827,7 +454891,7 @@ async function executeImageGenerate(options) {
454827
454891
  if (output3 && result.images.length > 0) {
454828
454892
  const img = result.images[0];
454829
454893
  if (img.base64) {
454830
- outputPath = resolve31(process.cwd(), output3);
454894
+ outputPath = resolve33(process.cwd(), output3);
454831
454895
  await mkdir17(dirname24(outputPath), { recursive: true });
454832
454896
  await writeFile19(outputPath, Buffer.from(img.base64, "base64"));
454833
454897
  }
@@ -454863,7 +454927,7 @@ async function executeImageGenerate(options) {
454863
454927
  } else {
454864
454928
  return { success: false, error: "No image data available" };
454865
454929
  }
454866
- outputPath = resolve31(process.cwd(), output3);
454930
+ outputPath = resolve33(process.cwd(), output3);
454867
454931
  await mkdir17(dirname24(outputPath), { recursive: true });
454868
454932
  await writeFile19(outputPath, buffer);
454869
454933
  }
@@ -454894,7 +454958,7 @@ async function executeGeminiEdit(options) {
454894
454958
  if (!key2) return { success: false, error: "GOOGLE_API_KEY required" };
454895
454959
  const imageBuffers = [];
454896
454960
  for (const imagePath of imagePaths) {
454897
- const absPath = resolve31(process.cwd(), imagePath);
454961
+ const absPath = resolve33(process.cwd(), imagePath);
454898
454962
  if (!existsSync42(absPath)) {
454899
454963
  return { success: false, error: `Image not found: ${absPath}` };
454900
454964
  }
@@ -454922,7 +454986,7 @@ async function executeGeminiEdit(options) {
454922
454986
  const img = result.images[0];
454923
454987
  let outputPath;
454924
454988
  if (img.base64) {
454925
- outputPath = resolve31(process.cwd(), output3);
454989
+ outputPath = resolve33(process.cwd(), output3);
454926
454990
  await mkdir17(dirname24(outputPath), { recursive: true });
454927
454991
  await writeFile19(outputPath, Buffer.from(img.base64, "base64"));
454928
454992
  }
@@ -455015,7 +455079,7 @@ __export(ai_analyze_exports, {
455015
455079
  registerAnalyzeCommands: () => registerAnalyzeCommands
455016
455080
  });
455017
455081
  import { readFile as readFile19 } from "node:fs/promises";
455018
- import { extname as extname8, resolve as resolve33 } from "node:path";
455082
+ import { extname as extname8, resolve as resolve34 } from "node:path";
455019
455083
  import { existsSync as existsSync43 } from "node:fs";
455020
455084
  async function executeGeminiVideo(options) {
455021
455085
  try {
@@ -455034,7 +455098,7 @@ async function executeGeminiVideo(options) {
455034
455098
  if (isYouTube) {
455035
455099
  videoData = options.source;
455036
455100
  } else {
455037
- const absPath = resolve33(process.cwd(), options.source);
455101
+ const absPath = resolve34(process.cwd(), options.source);
455038
455102
  if (!existsSync43(absPath)) {
455039
455103
  return { success: false, error: `File not found: ${absPath}` };
455040
455104
  }
@@ -455107,7 +455171,7 @@ async function executeAnalyze(options) {
455107
455171
  }
455108
455172
  imageBuffer = Buffer.from(await response.arrayBuffer());
455109
455173
  } else {
455110
- const absPath = resolve33(process.cwd(), source3);
455174
+ const absPath = resolve34(process.cwd(), source3);
455111
455175
  if (!existsSync43(absPath)) {
455112
455176
  return { success: false, error: `File not found: ${absPath}` };
455113
455177
  }
@@ -455142,7 +455206,7 @@ async function executeAnalyze(options) {
455142
455206
  }
455143
455207
  videoData = Buffer.from(await response.arrayBuffer());
455144
455208
  } else {
455145
- const absPath = resolve33(process.cwd(), source3);
455209
+ const absPath = resolve34(process.cwd(), source3);
455146
455210
  if (!existsSync43(absPath)) {
455147
455211
  return { success: false, error: `File not found: ${absPath}` };
455148
455212
  }
@@ -455281,7 +455345,7 @@ __export(ai_review_exports, {
455281
455345
  registerReviewCommand: () => registerReviewCommand
455282
455346
  });
455283
455347
  import { readFile as readFile20, rename as rename4 } from "node:fs/promises";
455284
- import { resolve as resolve34 } from "node:path";
455348
+ import { resolve as resolve35 } from "node:path";
455285
455349
  import { existsSync as existsSync44 } from "node:fs";
455286
455350
  function parseReviewFeedback(response) {
455287
455351
  let cleaned = response.trim();
@@ -455306,7 +455370,7 @@ function parseReviewFeedback(response) {
455306
455370
  }
455307
455371
  async function executeReview(options) {
455308
455372
  const { videoPath, storyboardPath, autoApply = false, verify = false, model = "flash" } = options;
455309
- const absVideoPath = resolve34(process.cwd(), videoPath);
455373
+ const absVideoPath = resolve35(process.cwd(), videoPath);
455310
455374
  if (!existsSync44(absVideoPath)) {
455311
455375
  return { success: false, error: `Video not found: ${absVideoPath}` };
455312
455376
  }
@@ -455316,7 +455380,7 @@ async function executeReview(options) {
455316
455380
  }
455317
455381
  let storyboardContext = "";
455318
455382
  if (storyboardPath) {
455319
- const absStoryboardPath = resolve34(process.cwd(), storyboardPath);
455383
+ const absStoryboardPath = resolve35(process.cwd(), storyboardPath);
455320
455384
  if (existsSync44(absStoryboardPath)) {
455321
455385
  const content = await readFile20(absStoryboardPath, "utf-8");
455322
455386
  storyboardContext = `
@@ -455372,7 +455436,7 @@ Score each category 1-10. For fixable issues, provide an FFmpeg filter in autoFi
455372
455436
  };
455373
455437
  if (autoApply && feedback.autoFixable.length > 0) {
455374
455438
  let currentInput = absVideoPath;
455375
- const outputBase = options.outputPath ? resolve34(process.cwd(), options.outputPath) : absVideoPath.replace(/(\.[^.]+)$/, "-reviewed$1");
455439
+ const outputBase = options.outputPath ? resolve35(process.cwd(), options.outputPath) : absVideoPath.replace(/(\.[^.]+)$/, "-reviewed$1");
455376
455440
  for (const fix of feedback.autoFixable) {
455377
455441
  if (fix.type === "color_grade" && fix.ffmpegFilter) {
455378
455442
  try {
@@ -455526,7 +455590,7 @@ __export(ai_motion_exports, {
455526
455590
  executeMotion: () => executeMotion,
455527
455591
  registerMotionCommand: () => registerMotionCommand
455528
455592
  });
455529
- import { resolve as resolve36 } from "node:path";
455593
+ import { resolve as resolve37 } from "node:path";
455530
455594
  import { existsSync as existsSync45 } from "node:fs";
455531
455595
  import { readFile as readFile22, writeFile as writeFile21 } from "node:fs/promises";
455532
455596
  async function executeMotion(options) {
@@ -455551,7 +455615,7 @@ async function executeMotion(options) {
455551
455615
  if (!geminiApiKey) {
455552
455616
  return { success: false, error: "GOOGLE_API_KEY required for image analysis (--image). Run 'vibe setup' or set GOOGLE_API_KEY in .env" };
455553
455617
  }
455554
- const imagePath = resolve36(process.cwd(), options.image);
455618
+ const imagePath = resolve37(process.cwd(), options.image);
455555
455619
  const imageBuffer = await readFile22(imagePath);
455556
455620
  const gemini = new GeminiProvider();
455557
455621
  await gemini.initialize({ apiKey: geminiApiKey });
@@ -455574,7 +455638,7 @@ Use this image analysis to inform the color palette, typography placement, and o
455574
455638
  }
455575
455639
  let result;
455576
455640
  if (options.fromTsx) {
455577
- const tsxPath = resolve36(process.cwd(), options.fromTsx);
455641
+ const tsxPath = resolve37(process.cwd(), options.fromTsx);
455578
455642
  if (!existsSync45(tsxPath)) {
455579
455643
  return { success: false, error: `TSX file not found: ${tsxPath}` };
455580
455644
  }
@@ -455628,7 +455692,7 @@ Use this image analysis to inform the color palette, typography placement, and o
455628
455692
  }
455629
455693
  const { component } = result;
455630
455694
  const defaultOutput = options.video || options.image ? "motion-output.mp4" : options.render ? "motion.webm" : "motion.tsx";
455631
- const outputPath = resolve36(process.cwd(), options.output || defaultOutput);
455695
+ const outputPath = resolve37(process.cwd(), options.output || defaultOutput);
455632
455696
  const codePath = outputPath.replace(/\.\w+$/, ".tsx");
455633
455697
  await writeFile21(codePath, component.code, "utf-8");
455634
455698
  const shouldRender = options.render || !!options.video || !!options.image;
@@ -455647,8 +455711,8 @@ Use this image analysis to inform the color palette, typography placement, and o
455647
455711
  if (notInstalled) {
455648
455712
  return { success: false, codePath, componentName: component.name, error: notInstalled };
455649
455713
  }
455650
- const baseVideo = options.video ? resolve36(process.cwd(), options.video) : void 0;
455651
- const baseImage = options.image ? resolve36(process.cwd(), options.image) : void 0;
455714
+ const baseVideo = options.video ? resolve37(process.cwd(), options.video) : void 0;
455715
+ const baseImage = options.image ? resolve37(process.cwd(), options.image) : void 0;
455652
455716
  if (baseVideo) {
455653
455717
  const videoFileName = "source_video.mp4";
455654
455718
  const wrapped = wrapComponentWithVideo2(component.code, component.name, videoFileName);
@@ -455833,7 +455897,7 @@ var init_ai_motion = __esm({
455833
455897
  });
455834
455898
 
455835
455899
  // ../cli/src/commands/generate/sound-effect.ts
455836
- import { resolve as resolve37 } from "node:path";
455900
+ import { resolve as resolve38 } from "node:path";
455837
455901
  import { writeFile as writeFile22 } from "node:fs/promises";
455838
455902
  async function executeSoundEffect(options) {
455839
455903
  try {
@@ -455855,7 +455919,7 @@ async function executeSoundEffect(options) {
455855
455919
  error: result.error || "Sound effect generation failed"
455856
455920
  };
455857
455921
  }
455858
- const outputPath = resolve37(
455922
+ const outputPath = resolve38(
455859
455923
  process.cwd(),
455860
455924
  options.output || "sound-effect.mp3"
455861
455925
  );
@@ -455910,7 +455974,7 @@ function registerSoundEffectCommand(parent) {
455910
455974
  apiError(result.error || "Sound effect generation failed", true)
455911
455975
  );
455912
455976
  }
455913
- const outputPath = resolve37(process.cwd(), options.output);
455977
+ const outputPath = resolve38(process.cwd(), options.output);
455914
455978
  await writeFile22(outputPath, result.audioBuffer);
455915
455979
  spinner2.succeed(source_default.green("Sound effect generated"));
455916
455980
  if (isJsonMode()) {
@@ -456095,7 +456159,7 @@ var init_video_cancel = __esm({
456095
456159
  });
456096
456160
 
456097
456161
  // ../cli/src/commands/generate/background.ts
456098
- import { resolve as resolve38, dirname as dirname25 } from "node:path";
456162
+ import { resolve as resolve39, dirname as dirname25 } from "node:path";
456099
456163
  import { writeFile as writeFile23, mkdir as mkdir18 } from "node:fs/promises";
456100
456164
  async function executeBackground(options) {
456101
456165
  try {
@@ -456120,7 +456184,7 @@ async function executeBackground(options) {
456120
456184
  } else {
456121
456185
  return { success: false, error: "Provider returned no image data" };
456122
456186
  }
456123
- outputPath = resolve38(process.cwd(), options.output);
456187
+ outputPath = resolve39(process.cwd(), options.output);
456124
456188
  await mkdir18(dirname25(outputPath), { recursive: true });
456125
456189
  await writeFile23(outputPath, buffer);
456126
456190
  }
@@ -456182,7 +456246,7 @@ function registerBackgroundCommand(parent) {
456182
456246
  } else {
456183
456247
  throw new Error("No image data available");
456184
456248
  }
456185
- outputPath = resolve38(process.cwd(), options.output);
456249
+ outputPath = resolve39(process.cwd(), options.output);
456186
456250
  await mkdir18(dirname25(outputPath), { recursive: true });
456187
456251
  await writeFile23(outputPath, buffer);
456188
456252
  }
@@ -456213,7 +456277,7 @@ function registerBackgroundCommand(parent) {
456213
456277
  } else {
456214
456278
  throw new Error("No image data available");
456215
456279
  }
456216
- const outputPath = resolve38(process.cwd(), options.output);
456280
+ const outputPath = resolve39(process.cwd(), options.output);
456217
456281
  await mkdir18(dirname25(outputPath), { recursive: true });
456218
456282
  await writeFile23(outputPath, buffer);
456219
456283
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
@@ -456255,7 +456319,7 @@ var init_sanitize = __esm({
456255
456319
  });
456256
456320
 
456257
456321
  // ../cli/src/commands/generate/storyboard.ts
456258
- import { resolve as resolve39 } from "node:path";
456322
+ import { resolve as resolve40 } from "node:path";
456259
456323
  import { readFile as readFile23, writeFile as writeFile24 } from "node:fs/promises";
456260
456324
  async function executeStoryboard(options) {
456261
456325
  const { content, duration, creativity = "low", output: output3, apiKey } = options;
@@ -456274,7 +456338,7 @@ async function executeStoryboard(options) {
456274
456338
  }
456275
456339
  let outputPath;
456276
456340
  if (output3) {
456277
- outputPath = resolve39(process.cwd(), output3);
456341
+ outputPath = resolve40(process.cwd(), output3);
456278
456342
  await writeFile24(outputPath, JSON.stringify(segments, null, 2), "utf-8");
456279
456343
  }
456280
456344
  return { success: true, segments, segmentCount: segments.length, outputPath };
@@ -456299,7 +456363,7 @@ function registerStoryboardCommand(parent) {
456299
456363
  }
456300
456364
  let textContent2 = content;
456301
456365
  if (options.file) {
456302
- const filePath = resolve39(process.cwd(), content);
456366
+ const filePath = resolve40(process.cwd(), content);
456303
456367
  textContent2 = await readFile23(filePath, "utf-8");
456304
456368
  }
456305
456369
  if (options.dryRun) {
@@ -456341,7 +456405,7 @@ function registerStoryboardCommand(parent) {
456341
456405
  if (seg.visuals) seg.visuals = sanitizeLLMResponse(seg.visuals);
456342
456406
  }
456343
456407
  if (options.output) {
456344
- const outputPath = resolve39(process.cwd(), options.output);
456408
+ const outputPath = resolve40(process.cwd(), options.output);
456345
456409
  await writeFile24(outputPath, JSON.stringify(segments, null, 2), "utf-8");
456346
456410
  if (isJsonMode()) {
456347
456411
  outputSuccess({
@@ -456384,7 +456448,7 @@ function registerStoryboardCommand(parent) {
456384
456448
  }
456385
456449
  console.log();
456386
456450
  if (options.output) {
456387
- console.log(source_default.green(`Saved to: ${resolve39(process.cwd(), options.output)}`));
456451
+ console.log(source_default.green(`Saved to: ${resolve40(process.cwd(), options.output)}`));
456388
456452
  }
456389
456453
  } catch (error) {
456390
456454
  const msg = error instanceof Error ? error.message : String(error);
@@ -456462,7 +456526,7 @@ var init_tty = __esm({
456462
456526
  });
456463
456527
 
456464
456528
  // ../cli/src/commands/generate/speech.ts
456465
- import { resolve as resolve40 } from "node:path";
456529
+ import { resolve as resolve41 } from "node:path";
456466
456530
  import { writeFile as writeFile25 } from "node:fs/promises";
456467
456531
  async function executeSpeech(options) {
456468
456532
  try {
@@ -456480,7 +456544,7 @@ async function executeSpeech(options) {
456480
456544
  if (!result.success || !result.audioBuffer) {
456481
456545
  return { success: false, error: result.error || "TTS generation failed" };
456482
456546
  }
456483
- const outputPath = resolve40(process.cwd(), options.output || "output.mp3");
456547
+ const outputPath = resolve41(process.cwd(), options.output || "output.mp3");
456484
456548
  await writeFile25(outputPath, result.audioBuffer);
456485
456549
  return { success: true, outputPath, characterCount: result.characterCount };
456486
456550
  } catch (error) {
@@ -456556,7 +456620,7 @@ function registerSpeechCommand(parent) {
456556
456620
  spinner2.fail(result.error || "TTS generation failed");
456557
456621
  exitWithError(apiError(result.error || "TTS generation failed", true));
456558
456622
  }
456559
- const outputPath = resolve40(process.cwd(), options.output);
456623
+ const outputPath = resolve41(process.cwd(), options.output);
456560
456624
  await writeFile25(outputPath, result.audioBuffer);
456561
456625
  spinner2.succeed(source_default.green("Speech generated"));
456562
456626
  if (options.fitDuration && options.fitDuration > 0) {
@@ -456642,7 +456706,7 @@ var init_speech = __esm({
456642
456706
  });
456643
456707
 
456644
456708
  // ../cli/src/commands/generate/music.ts
456645
- import { resolve as resolve41 } from "node:path";
456709
+ import { resolve as resolve43 } from "node:path";
456646
456710
  import { writeFile as writeFile26 } from "node:fs/promises";
456647
456711
  import { existsSync as existsSync46 } from "node:fs";
456648
456712
  async function executeMusic(options) {
@@ -456665,7 +456729,7 @@ async function executeMusic(options) {
456665
456729
  if (!result2.success || !result2.audioBuffer) {
456666
456730
  return { success: false, error: result2.error || "Music generation failed" };
456667
456731
  }
456668
- const outputPath2 = resolve41(process.cwd(), options.output || "music.mp3");
456732
+ const outputPath2 = resolve43(process.cwd(), options.output || "music.mp3");
456669
456733
  await writeFile26(outputPath2, result2.audioBuffer);
456670
456734
  return { success: true, outputPath: outputPath2, provider: "elevenlabs", duration: duration2 };
456671
456735
  }
@@ -456690,7 +456754,7 @@ async function executeMusic(options) {
456690
456754
  if (!response.ok)
456691
456755
  return { success: false, error: "Failed to download generated audio" };
456692
456756
  const audioBuffer = Buffer.from(await response.arrayBuffer());
456693
- const outputPath = resolve41(process.cwd(), options.output || "music.mp3");
456757
+ const outputPath = resolve43(process.cwd(), options.output || "music.mp3");
456694
456758
  await writeFile26(outputPath, audioBuffer);
456695
456759
  return { success: true, outputPath, provider: "replicate", duration };
456696
456760
  } catch (error) {
@@ -456754,7 +456818,7 @@ function registerMusicCommand(parent) {
456754
456818
  spinner2.fail(result.error || "Music generation failed");
456755
456819
  exitWithError(apiError(result.error || "Music generation failed", true));
456756
456820
  }
456757
- const outputPath = resolve41(process.cwd(), options.output);
456821
+ const outputPath = resolve43(process.cwd(), options.output);
456758
456822
  await writeFile26(outputPath, result.audioBuffer);
456759
456823
  spinner2.succeed(source_default.green("Music generated successfully"));
456760
456824
  if (isJsonMode()) {
@@ -456787,7 +456851,7 @@ function registerMusicCommand(parent) {
456787
456851
  const duration = Math.max(1, Math.min(30, parseFloat(options.duration)));
456788
456852
  if (options.melody) {
456789
456853
  spinner2.text = "Uploading melody reference...";
456790
- const absPath = resolve41(process.cwd(), options.melody);
456854
+ const absPath = resolve43(process.cwd(), options.melody);
456791
456855
  if (!existsSync46(absPath)) {
456792
456856
  spinner2.fail(`Melody file not found: ${options.melody}`);
456793
456857
  exitWithError(notFoundError(options.melody));
@@ -456829,7 +456893,7 @@ function registerMusicCommand(parent) {
456829
456893
  exitWithError(apiError("Failed to download generated audio", true));
456830
456894
  }
456831
456895
  const audioBuffer = Buffer.from(await response.arrayBuffer());
456832
- const outputPath = resolve41(process.cwd(), options.output);
456896
+ const outputPath = resolve43(process.cwd(), options.output);
456833
456897
  await writeFile26(outputPath, audioBuffer);
456834
456898
  spinner2.succeed(source_default.green("Music generated successfully"));
456835
456899
  if (isJsonMode()) {
@@ -456871,7 +456935,7 @@ var init_music = __esm({
456871
456935
  });
456872
456936
 
456873
456937
  // ../cli/src/commands/generate/thumbnail.ts
456874
- import { resolve as resolve43, dirname as dirname26, basename as basename10, extname as extname9 } from "node:path";
456938
+ import { resolve as resolve44, dirname as dirname26, basename as basename10, extname as extname9 } from "node:path";
456875
456939
  import { existsSync as existsSync47 } from "node:fs";
456876
456940
  import { writeFile as writeFile27, mkdir as mkdir19 } from "node:fs/promises";
456877
456941
  function registerThumbnailCommand(parent) {
@@ -456883,7 +456947,7 @@ function registerThumbnailCommand(parent) {
456883
456947
  validateOutputPath(options.output);
456884
456948
  }
456885
456949
  if (options.bestFrame) {
456886
- const absVideoPath = resolve43(process.cwd(), options.bestFrame);
456950
+ const absVideoPath = resolve44(process.cwd(), options.bestFrame);
456887
456951
  if (!existsSync47(absVideoPath)) {
456888
456952
  exitWithError(notFoundError(absVideoPath));
456889
456953
  }
@@ -456901,7 +456965,7 @@ function registerThumbnailCommand(parent) {
456901
456965
  const spinner3 = ora("Analyzing video for best frame...").start();
456902
456966
  const result2 = await executeThumbnailBestFrame({
456903
456967
  videoPath: absVideoPath,
456904
- outputPath: resolve43(process.cwd(), outputPath),
456968
+ outputPath: resolve44(process.cwd(), outputPath),
456905
456969
  prompt: options.prompt,
456906
456970
  model: options.model,
456907
456971
  apiKey: apiKey2
@@ -456963,7 +457027,7 @@ function registerThumbnailCommand(parent) {
456963
457027
  } else {
456964
457028
  throw new Error("No image data available");
456965
457029
  }
456966
- outputPath = resolve43(process.cwd(), options.output);
457030
+ outputPath = resolve44(process.cwd(), options.output);
456967
457031
  await mkdir19(dirname26(outputPath), { recursive: true });
456968
457032
  await writeFile27(outputPath, buffer);
456969
457033
  }
@@ -456994,7 +457058,7 @@ function registerThumbnailCommand(parent) {
456994
457058
  } else {
456995
457059
  throw new Error("No image data available");
456996
457060
  }
456997
- const outputPath = resolve43(process.cwd(), options.output);
457061
+ const outputPath = resolve44(process.cwd(), options.output);
456998
457062
  await mkdir19(dirname26(outputPath), { recursive: true });
456999
457063
  await writeFile27(outputPath, buffer);
457000
457064
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
@@ -457023,7 +457087,7 @@ var init_thumbnail = __esm({
457023
457087
  });
457024
457088
 
457025
457089
  // ../cli/src/commands/generate/video-status.ts
457026
- import { resolve as resolve44 } from "node:path";
457090
+ import { resolve as resolve45 } from "node:path";
457027
457091
  import { writeFile as writeFile28 } from "node:fs/promises";
457028
457092
  function getStatusColor(status) {
457029
457093
  switch (status) {
@@ -457062,7 +457126,7 @@ function registerVideoStatusCommand(parent) {
457062
457126
  let outputPath;
457063
457127
  if (options.output && result.videoUrl) {
457064
457128
  const buffer = await downloadVideo(result.videoUrl);
457065
- outputPath = resolve44(process.cwd(), options.output);
457129
+ outputPath = resolve45(process.cwd(), options.output);
457066
457130
  await writeFile28(outputPath, buffer);
457067
457131
  }
457068
457132
  outputSuccess({
@@ -457096,7 +457160,7 @@ function registerVideoStatusCommand(parent) {
457096
457160
  const downloadSpinner = ora("Downloading video...").start();
457097
457161
  try {
457098
457162
  const buffer = await downloadVideo(result.videoUrl);
457099
- const outputPath = resolve44(process.cwd(), options.output);
457163
+ const outputPath = resolve45(process.cwd(), options.output);
457100
457164
  await writeFile28(outputPath, buffer);
457101
457165
  downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
457102
457166
  } catch (err) {
@@ -457130,7 +457194,7 @@ function registerVideoStatusCommand(parent) {
457130
457194
  let outputPath;
457131
457195
  if (options.output && result.videoUrl) {
457132
457196
  const buffer = await downloadVideo(result.videoUrl, apiKey);
457133
- outputPath = resolve44(process.cwd(), options.output);
457197
+ outputPath = resolve45(process.cwd(), options.output);
457134
457198
  await writeFile28(outputPath, buffer);
457135
457199
  }
457136
457200
  outputSuccess({
@@ -457168,7 +457232,7 @@ function registerVideoStatusCommand(parent) {
457168
457232
  const downloadSpinner = ora("Downloading video...").start();
457169
457233
  try {
457170
457234
  const buffer = await downloadVideo(result.videoUrl, apiKey);
457171
- const outputPath = resolve44(process.cwd(), options.output);
457235
+ const outputPath = resolve45(process.cwd(), options.output);
457172
457236
  await writeFile28(outputPath, buffer);
457173
457237
  downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
457174
457238
  } catch (err) {
@@ -457197,7 +457261,7 @@ function registerVideoStatusCommand(parent) {
457197
457261
  let outputPath;
457198
457262
  if (options.output && result.videoUrl) {
457199
457263
  const buffer = await downloadVideo(result.videoUrl, apiKey);
457200
- outputPath = resolve44(process.cwd(), options.output);
457264
+ outputPath = resolve45(process.cwd(), options.output);
457201
457265
  await writeFile28(outputPath, buffer);
457202
457266
  }
457203
457267
  outputSuccess({
@@ -457236,7 +457300,7 @@ function registerVideoStatusCommand(parent) {
457236
457300
  const downloadSpinner = ora("Downloading video...").start();
457237
457301
  try {
457238
457302
  const buffer = await downloadVideo(result.videoUrl, apiKey);
457239
- const outputPath = resolve44(process.cwd(), options.output);
457303
+ const outputPath = resolve45(process.cwd(), options.output);
457240
457304
  await writeFile28(outputPath, buffer);
457241
457305
  downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
457242
457306
  } catch (err) {
@@ -457271,7 +457335,7 @@ var init_video_status = __esm({
457271
457335
  });
457272
457336
 
457273
457337
  // ../cli/src/commands/generate/video-extend.ts
457274
- import { resolve as resolve45 } from "node:path";
457338
+ import { resolve as resolve46 } from "node:path";
457275
457339
  import { writeFile as writeFile29 } from "node:fs/promises";
457276
457340
  function registerVideoExtendCommand(parent) {
457277
457341
  parent.command("video-extend", { hidden: true }).description("Extend video duration (Kling by video ID, Veo by operation name)").argument("<id>", "Kling video ID or Veo operation name").option("-p, --provider <provider>", "Provider: kling, veo", "kling").option("-k, --api-key <key>", "API key (KLING_API_KEY or GOOGLE_API_KEY)").option("-o, --output <path>", "Output file path").option("--prompt <text>", "Continuation prompt").option("-d, --duration <sec>", "Duration: 5 or 10 (Kling), 4/6/8 (Veo)", "5").option("--negative <prompt>", "Negative prompt (what to avoid, Kling only)").option("--veo-model <model>", "Veo model: 3.0, 3.1, 3.1-fast", "3.1").option("--no-wait", "Start extension and return task ID without waiting").option("--dry-run", "Preview parameters without executing").action(async (id, options) => {
@@ -457348,7 +457412,7 @@ function registerVideoExtendCommand(parent) {
457348
457412
  let outputPath;
457349
457413
  if (options.output && finalResult.videoUrl) {
457350
457414
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
457351
- outputPath = resolve45(process.cwd(), options.output);
457415
+ outputPath = resolve46(process.cwd(), options.output);
457352
457416
  await writeFile29(outputPath, buffer);
457353
457417
  }
457354
457418
  outputSuccess({
@@ -457376,7 +457440,7 @@ function registerVideoExtendCommand(parent) {
457376
457440
  const downloadSpinner = ora("Downloading video...").start();
457377
457441
  try {
457378
457442
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
457379
- const outputPath = resolve45(process.cwd(), options.output);
457443
+ const outputPath = resolve46(process.cwd(), options.output);
457380
457444
  await writeFile29(outputPath, buffer);
457381
457445
  downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
457382
457446
  } catch (err) {
@@ -457437,7 +457501,7 @@ function registerVideoExtendCommand(parent) {
457437
457501
  let outputPath;
457438
457502
  if (options.output && finalResult.videoUrl) {
457439
457503
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
457440
- outputPath = resolve45(process.cwd(), options.output);
457504
+ outputPath = resolve46(process.cwd(), options.output);
457441
457505
  await writeFile29(outputPath, buffer);
457442
457506
  }
457443
457507
  outputSuccess({
@@ -457462,7 +457526,7 @@ function registerVideoExtendCommand(parent) {
457462
457526
  const downloadSpinner = ora("Downloading video...").start();
457463
457527
  try {
457464
457528
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
457465
- const outputPath = resolve45(process.cwd(), options.output);
457529
+ const outputPath = resolve46(process.cwd(), options.output);
457466
457530
  await writeFile29(outputPath, buffer);
457467
457531
  downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
457468
457532
  } catch (err) {
@@ -457553,7 +457617,7 @@ var init_openai_image2 = __esm({
457553
457617
  });
457554
457618
 
457555
457619
  // ../cli/src/commands/generate/image.ts
457556
- import { resolve as resolve46, dirname as dirname27 } from "node:path";
457620
+ import { resolve as resolve47, dirname as dirname27 } from "node:path";
457557
457621
  import { fileURLToPath as fileURLToPath4 } from "node:url";
457558
457622
  import { writeFile as writeFile30, mkdir as mkdir20 } from "node:fs/promises";
457559
457623
  function registerImageCommand(parent) {
@@ -457669,7 +457733,7 @@ Examples:
457669
457733
  source_default.green(`Generated ${result.images.length} image(s) with OpenAI ${modelLabel}`)
457670
457734
  );
457671
457735
  if (isJsonMode()) {
457672
- const outputPath = options.output ? resolve46(process.cwd(), options.output) : void 0;
457736
+ const outputPath = options.output ? resolve47(process.cwd(), options.output) : void 0;
457673
457737
  if (outputPath && result.images.length > 0) {
457674
457738
  const img = result.images[0];
457675
457739
  let buffer;
@@ -457727,7 +457791,7 @@ Examples:
457727
457791
  } else {
457728
457792
  throw new Error("No image data available");
457729
457793
  }
457730
- const outputPath = resolve46(process.cwd(), options.output);
457794
+ const outputPath = resolve47(process.cwd(), options.output);
457731
457795
  await mkdir20(dirname27(outputPath), { recursive: true });
457732
457796
  await writeFile30(outputPath, buffer);
457733
457797
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
@@ -457799,7 +457863,7 @@ Examples:
457799
457863
  source_default.green(`Generated ${result.images.length} image(s) with Gemini (${usedLabel})`)
457800
457864
  );
457801
457865
  if (isJsonMode()) {
457802
- const outputPath = options.output ? resolve46(process.cwd(), options.output) : void 0;
457866
+ const outputPath = options.output ? resolve47(process.cwd(), options.output) : void 0;
457803
457867
  if (outputPath && result.images.length > 0) {
457804
457868
  const img = result.images[0];
457805
457869
  const buffer = Buffer.from(img.base64, "base64");
@@ -457835,7 +457899,7 @@ Examples:
457835
457899
  try {
457836
457900
  const img = result.images[0];
457837
457901
  const buffer = Buffer.from(img.base64, "base64");
457838
- const outputPath = resolve46(process.cwd(), options.output);
457902
+ const outputPath = resolve47(process.cwd(), options.output);
457839
457903
  await mkdir20(dirname27(outputPath), { recursive: true });
457840
457904
  await writeFile30(outputPath, buffer);
457841
457905
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
@@ -457886,7 +457950,7 @@ Examples:
457886
457950
  source_default.green(`Generated ${result.images.length} image(s) with xAI Grok`)
457887
457951
  );
457888
457952
  if (isJsonMode()) {
457889
- const outputPath = options.output ? resolve46(process.cwd(), options.output) : void 0;
457953
+ const outputPath = options.output ? resolve47(process.cwd(), options.output) : void 0;
457890
457954
  if (outputPath && result.images.length > 0) {
457891
457955
  const img = result.images[0];
457892
457956
  let buffer;
@@ -457938,7 +458002,7 @@ Examples:
457938
458002
  } else {
457939
458003
  throw new Error("No image data available");
457940
458004
  }
457941
- const outputPath = resolve46(process.cwd(), options.output);
458005
+ const outputPath = resolve47(process.cwd(), options.output);
457942
458006
  await mkdir20(dirname27(outputPath), { recursive: true });
457943
458007
  await writeFile30(outputPath, buffer);
457944
458008
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
@@ -457952,7 +458016,7 @@ Examples:
457952
458016
  const { spawn: spawn10 } = await import("child_process");
457953
458017
  const __filename2 = fileURLToPath4(import.meta.url);
457954
458018
  const __dirname3 = dirname27(__filename2);
457955
- const scriptPath = resolve46(
458019
+ const scriptPath = resolve47(
457956
458020
  __dirname3,
457957
458021
  "../../../../.claude/skills/runway-video/scripts/image.py"
457958
458022
  );
@@ -457960,7 +458024,7 @@ Examples:
457960
458024
  spinner2.fail("Output path required for Runway");
457961
458025
  exitWithError(usageError("Output path required for Runway. Use -o option."));
457962
458026
  }
457963
- const outputPath = resolve46(process.cwd(), options.output);
458027
+ const outputPath = resolve47(process.cwd(), options.output);
457964
458028
  const args = [scriptPath, prompt3, "-o", outputPath, "-r", options.ratio || "16:9"];
457965
458029
  spinner2.text = "Generating image with Runway (gemini_2.5_flash)...";
457966
458030
  await new Promise((resolvePromise, reject) => {
@@ -458970,7 +459034,7 @@ var init_dist3 = __esm({
458970
459034
 
458971
459035
  // ../cli/src/commands/_shared/video-utils.ts
458972
459036
  import { writeFile as writeFile31, unlink as unlink5, rename as rename5 } from "node:fs/promises";
458973
- import { resolve as resolve47, basename as basename11 } from "node:path";
459037
+ import { resolve as resolve48, basename as basename11 } from "node:path";
458974
459038
  function sleep(ms) {
458975
459039
  return new Promise((resolve64) => setTimeout(resolve64, ms));
458976
459040
  }
@@ -459004,7 +459068,7 @@ async function extendVideoToTarget(videoPath, targetDuration, outputDir, sceneLa
459004
459068
  const actualDuration = await getVideoDuration(videoPath);
459005
459069
  if (actualDuration >= targetDuration - 0.1) return;
459006
459070
  const ratio = targetDuration / actualDuration;
459007
- const extendedPath = resolve47(outputDir, `${basename11(videoPath, ".mp4")}-extended.mp4`);
459071
+ const extendedPath = resolve48(outputDir, `${basename11(videoPath, ".mp4")}-extended.mp4`);
459008
459072
  if (ratio > 1.4 && options?.kling && options?.videoId) {
459009
459073
  try {
459010
459074
  options.onProgress?.(`${sceneLabel}: Extending via Kling API...`);
@@ -459020,17 +459084,17 @@ async function extendVideoToTarget(videoPath, targetDuration, outputDir, sceneLa
459020
459084
  6e5
459021
459085
  );
459022
459086
  if (waitResult.status === "completed" && waitResult.videoUrl) {
459023
- const extendedVideoPath = resolve47(
459087
+ const extendedVideoPath = resolve48(
459024
459088
  outputDir,
459025
459089
  `${basename11(videoPath, ".mp4")}-kling-ext.mp4`
459026
459090
  );
459027
459091
  const buffer = await downloadVideo(waitResult.videoUrl);
459028
459092
  await writeFile31(extendedVideoPath, buffer);
459029
- const concatPath = resolve47(
459093
+ const concatPath = resolve48(
459030
459094
  outputDir,
459031
459095
  `${basename11(videoPath, ".mp4")}-concat.mp4`
459032
459096
  );
459033
- const listPath = resolve47(
459097
+ const listPath = resolve48(
459034
459098
  outputDir,
459035
459099
  `${basename11(videoPath, ".mp4")}-concat.txt`
459036
459100
  );
@@ -459272,7 +459336,7 @@ var init_video_providers = __esm({
459272
459336
 
459273
459337
  // ../cli/src/commands/ai-script-pipeline.ts
459274
459338
  import { readFile as readFile24, writeFile as writeFile32, unlink as unlink6, rename as rename6 } from "node:fs/promises";
459275
- import { resolve as resolve48, extname as extname10 } from "node:path";
459339
+ import { resolve as resolve49, extname as extname10 } from "node:path";
459276
459340
  import { existsSync as existsSync48 } from "node:fs";
459277
459341
  async function executeRegenerateScene(options) {
459278
459342
  const result = {
@@ -459281,12 +459345,12 @@ async function executeRegenerateScene(options) {
459281
459345
  failedScenes: []
459282
459346
  };
459283
459347
  try {
459284
- const outputDir = resolve48(process.cwd(), options.projectDir);
459348
+ const outputDir = resolve49(process.cwd(), options.projectDir);
459285
459349
  if (!existsSync48(outputDir)) {
459286
459350
  return { ...result, error: `Project directory not found: ${outputDir}` };
459287
459351
  }
459288
- const yamlPath = resolve48(outputDir, "storyboard.yaml");
459289
- const jsonPath = resolve48(outputDir, "storyboard.json");
459352
+ const yamlPath = resolve49(outputDir, "storyboard.yaml");
459353
+ const jsonPath = resolve49(outputDir, "storyboard.json");
459290
459354
  const storyboardPath = existsSync48(yamlPath) ? yamlPath : existsSync48(jsonPath) ? jsonPath : null;
459291
459355
  if (!storyboardPath) {
459292
459356
  return { ...result, error: `Storyboard not found in: ${outputDir} (expected storyboard.yaml or storyboard.json)` };
@@ -459346,9 +459410,9 @@ async function executeRegenerateScene(options) {
459346
459410
  let storyboardMutated = false;
459347
459411
  for (const sceneNum of options.scenes) {
459348
459412
  const segment = segments[sceneNum - 1];
459349
- const narrationPath = resolve48(outputDir, `narration-${sceneNum}.mp3`);
459350
- const imagePath = resolve48(outputDir, `scene-${sceneNum}.png`);
459351
- const videoPath = resolve48(outputDir, `scene-${sceneNum}.mp4`);
459413
+ const narrationPath = resolve49(outputDir, `narration-${sceneNum}.mp3`);
459414
+ const imagePath = resolve49(outputDir, `scene-${sceneNum}.png`);
459415
+ const videoPath = resolve49(outputDir, `scene-${sceneNum}.mp4`);
459352
459416
  let sceneFailed = false;
459353
459417
  if (regenerateNarration && elevenlabsApiKey) {
459354
459418
  options.onProgress?.(`Scene ${sceneNum}: regenerating narration...`);
@@ -459379,14 +459443,14 @@ IMPORTANT - Character appearance must match exactly: ${characterDesc}`;
459379
459443
  let referenceImageBuffer;
459380
459444
  const refSceneNum = options.referenceScene;
459381
459445
  if (refSceneNum && refSceneNum >= 1 && refSceneNum <= segments.length && refSceneNum !== sceneNum) {
459382
- const refImagePath = resolve48(outputDir, `scene-${refSceneNum}.png`);
459446
+ const refImagePath = resolve49(outputDir, `scene-${refSceneNum}.png`);
459383
459447
  if (existsSync48(refImagePath)) {
459384
459448
  referenceImageBuffer = await readFile24(refImagePath);
459385
459449
  }
459386
459450
  } else if (!refSceneNum) {
459387
459451
  for (let i = 1; i <= segments.length; i++) {
459388
459452
  if (i !== sceneNum) {
459389
- const otherImagePath = resolve48(outputDir, `scene-${i}.png`);
459453
+ const otherImagePath = resolve49(outputDir, `scene-${i}.png`);
459390
459454
  if (existsSync48(otherImagePath)) {
459391
459455
  referenceImageBuffer = await readFile24(otherImagePath);
459392
459456
  break;
@@ -459509,7 +459573,7 @@ Generate the single-person scene image now.`;
459509
459573
  const targetDuration = segment.duration;
459510
459574
  const actualVideoDuration = await getVideoDuration(videoPath);
459511
459575
  if (actualVideoDuration < targetDuration - 0.1) {
459512
- const extendedPath = resolve48(outputDir, `scene-${sceneNum}-extended.mp4`);
459576
+ const extendedPath = resolve49(outputDir, `scene-${sceneNum}-extended.mp4`);
459513
459577
  await extendVideoNaturally(videoPath, targetDuration, extendedPath);
459514
459578
  await unlink6(videoPath);
459515
459579
  await rename6(extendedPath, videoPath);
@@ -459552,7 +459616,7 @@ Generate the single-person scene image now.`;
459552
459616
  const targetDuration = segment.duration;
459553
459617
  const actualVideoDuration = await getVideoDuration(videoPath);
459554
459618
  if (actualVideoDuration < targetDuration - 0.1) {
459555
- const extendedPath = resolve48(outputDir, `scene-${sceneNum}-extended.mp4`);
459619
+ const extendedPath = resolve49(outputDir, `scene-${sceneNum}-extended.mp4`);
459556
459620
  await extendVideoNaturally(videoPath, targetDuration, extendedPath);
459557
459621
  await unlink6(videoPath);
459558
459622
  await rename6(extendedPath, videoPath);
@@ -459646,7 +459710,7 @@ Generate the single-person scene image now.`;
459646
459710
  const targetDuration = segment.duration;
459647
459711
  const actualVideoDuration = await getVideoDuration(videoPath);
459648
459712
  if (actualVideoDuration < targetDuration - 0.1) {
459649
- const extendedPath = resolve48(outputDir, `scene-${sceneNum}-extended.mp4`);
459713
+ const extendedPath = resolve49(outputDir, `scene-${sceneNum}-extended.mp4`);
459650
459714
  await extendVideoNaturally(videoPath, targetDuration, extendedPath);
459651
459715
  await unlink6(videoPath);
459652
459716
  await rename6(extendedPath, videoPath);
@@ -459702,7 +459766,7 @@ var init_ai_script_pipeline = __esm({
459702
459766
  });
459703
459767
 
459704
459768
  // ../cli/src/commands/generate/video.ts
459705
- import { resolve as resolve49 } from "node:path";
459769
+ import { resolve as resolve50 } from "node:path";
459706
459770
  import { readFile as readFile25, writeFile as writeFile33 } from "node:fs/promises";
459707
459771
  function registerVideoCommand(parent) {
459708
459772
  parent.command("video").alias("vid").description("Generate video using AI (Seedance, Grok, Kling, Runway, or Veo)").argument("[prompt]", "Text prompt describing the video (interactive if omitted)").option("-p, --provider <provider>", "Provider: seedance (ByteDance Seedance 2.0 via fal.ai), grok, kling, runway, veo. `fal` is a backwards-compatible alias for seedance.").option("-k, --api-key <key>", "API key (or set FAL_KEY / XAI_API_KEY / RUNWAY_API_SECRET / KLING_API_KEY / GOOGLE_API_KEY env)").option("-o, --output <path>", "Output file path (downloads video)").option("-i, --image <path>", "Reference image for image-to-video").option(
@@ -459781,7 +459845,7 @@ Examples:
459781
459845
  let referenceImage;
459782
459846
  let isImageToVideo = false;
459783
459847
  if (options.image) {
459784
- const imagePath = resolve49(process.cwd(), options.image);
459848
+ const imagePath = resolve50(process.cwd(), options.image);
459785
459849
  const imageBuffer = await readFile25(imagePath);
459786
459850
  const ext = options.image.toLowerCase().split(".").pop();
459787
459851
  const mimeTypes = {
@@ -459986,7 +460050,7 @@ Examples:
459986
460050
  const veoDuration = parseInt(options.duration) <= 6 ? 6 : 8;
459987
460051
  let lastFrame;
459988
460052
  if (options.lastFrame) {
459989
- const lastFramePath = resolve49(process.cwd(), options.lastFrame);
460053
+ const lastFramePath = resolve50(process.cwd(), options.lastFrame);
459990
460054
  const lastFrameBuffer = await readFile25(lastFramePath);
459991
460055
  const ext = options.lastFrame.toLowerCase().split(".").pop();
459992
460056
  const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
@@ -459996,7 +460060,7 @@ Examples:
459996
460060
  if (options.refImages && options.refImages.length > 0) {
459997
460061
  refImages = [];
459998
460062
  for (const refPath of options.refImages.slice(0, 3)) {
459999
- const absRefPath = resolve49(process.cwd(), refPath);
460063
+ const absRefPath = resolve50(process.cwd(), refPath);
460000
460064
  const refBuffer = await readFile25(absRefPath);
460001
460065
  const ext = refPath.toLowerCase().split(".").pop();
460002
460066
  const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
@@ -460115,7 +460179,7 @@ Examples:
460115
460179
  let outputPath;
460116
460180
  if (options.output && finalResult.videoUrl) {
460117
460181
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
460118
- outputPath = resolve49(process.cwd(), options.output);
460182
+ outputPath = resolve50(process.cwd(), options.output);
460119
460183
  await writeFile33(outputPath, buffer);
460120
460184
  }
460121
460185
  outputSuccess({
@@ -460143,7 +460207,7 @@ Examples:
460143
460207
  const downloadSpinner = ora("Downloading video...").start();
460144
460208
  try {
460145
460209
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
460146
- const outputPath = resolve49(process.cwd(), options.output);
460210
+ const outputPath = resolve50(process.cwd(), options.output);
460147
460211
  await writeFile33(outputPath, buffer);
460148
460212
  downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
460149
460213
  } catch (err) {
@@ -460267,7 +460331,7 @@ __export(ai_video_exports, {
460267
460331
  executeVideoStatus: () => executeVideoStatus
460268
460332
  });
460269
460333
  import { readFile as readFile26, writeFile as writeFile34 } from "node:fs/promises";
460270
- import { resolve as resolve50 } from "node:path";
460334
+ import { resolve as resolve51 } from "node:path";
460271
460335
  async function executeVideoGenerate(options) {
460272
460336
  const {
460273
460337
  prompt: prompt3,
@@ -460298,7 +460362,7 @@ async function executeVideoGenerate(options) {
460298
460362
  if (!key2) return { success: false, error: `${envKeyMap[provider]} required for ${provider}` };
460299
460363
  let referenceImage;
460300
460364
  if (image) {
460301
- const imagePath = resolve50(process.cwd(), image);
460365
+ const imagePath = resolve51(process.cwd(), image);
460302
460366
  const imageBuffer = await readFile26(imagePath);
460303
460367
  const ext = image.toLowerCase().split(".").pop();
460304
460368
  const mimeTypes = { jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", webp: "image/webp" };
@@ -460330,7 +460394,7 @@ async function executeVideoGenerate(options) {
460330
460394
  let outputPath;
460331
460395
  if (output3 && result.videoUrl) {
460332
460396
  const buffer = await downloadVideo(result.videoUrl, key2);
460333
- outputPath = resolve50(process.cwd(), output3);
460397
+ outputPath = resolve51(process.cwd(), output3);
460334
460398
  await writeFile34(outputPath, buffer);
460335
460399
  }
460336
460400
  return { success: true, taskId: result.id, status: "completed", videoUrl: result.videoUrl, outputPath, provider: "seedance" };
@@ -460352,7 +460416,7 @@ async function executeVideoGenerate(options) {
460352
460416
  let outputPath;
460353
460417
  if (output3 && finalResult.videoUrl) {
460354
460418
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
460355
- outputPath = resolve50(process.cwd(), output3);
460419
+ outputPath = resolve51(process.cwd(), output3);
460356
460420
  await writeFile34(outputPath, buffer);
460357
460421
  }
460358
460422
  return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath, provider: "runway" };
@@ -460386,7 +460450,7 @@ async function executeVideoGenerate(options) {
460386
460450
  let outputPath;
460387
460451
  if (output3 && finalResult.videoUrl) {
460388
460452
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
460389
- outputPath = resolve50(process.cwd(), output3);
460453
+ outputPath = resolve51(process.cwd(), output3);
460390
460454
  await writeFile34(outputPath, buffer);
460391
460455
  }
460392
460456
  return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath, provider: "kling" };
@@ -460413,7 +460477,7 @@ async function executeVideoGenerate(options) {
460413
460477
  let outputPath;
460414
460478
  if (output3 && finalResult.videoUrl) {
460415
460479
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
460416
- outputPath = resolve50(process.cwd(), output3);
460480
+ outputPath = resolve51(process.cwd(), output3);
460417
460481
  await writeFile34(outputPath, buffer);
460418
460482
  }
460419
460483
  return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, outputPath, provider: "veo" };
@@ -460434,7 +460498,7 @@ async function executeVideoGenerate(options) {
460434
460498
  let outputPath;
460435
460499
  if (output3 && finalResult.videoUrl) {
460436
460500
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
460437
- outputPath = resolve50(process.cwd(), output3);
460501
+ outputPath = resolve51(process.cwd(), output3);
460438
460502
  await writeFile34(outputPath, buffer);
460439
460503
  }
460440
460504
  return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath, provider: "grok" };
@@ -460461,7 +460525,7 @@ async function executeVideoStatus(options) {
460461
460525
  let outputPath;
460462
460526
  if (output3 && result.videoUrl) {
460463
460527
  const buffer = await downloadVideo(result.videoUrl, key2);
460464
- outputPath = resolve50(process.cwd(), output3);
460528
+ outputPath = resolve51(process.cwd(), output3);
460465
460529
  await writeFile34(outputPath, buffer);
460466
460530
  }
460467
460531
  return { success: true, taskId, status: result.status, progress: result.progress, videoUrl: result.videoUrl, outputPath };
@@ -460476,7 +460540,7 @@ async function executeVideoStatus(options) {
460476
460540
  let outputPath;
460477
460541
  if (output3 && result.videoUrl) {
460478
460542
  const buffer = await downloadVideo(result.videoUrl, key2);
460479
- outputPath = resolve50(process.cwd(), output3);
460543
+ outputPath = resolve51(process.cwd(), output3);
460480
460544
  await writeFile34(outputPath, buffer);
460481
460545
  }
460482
460546
  return { success: true, taskId, status: result.status, videoUrl: result.videoUrl, duration: result.duration, outputPath };
@@ -460521,7 +460585,7 @@ async function executeVideoExtend(options) {
460521
460585
  let outputPath;
460522
460586
  if (output3 && finalResult.videoUrl) {
460523
460587
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
460524
- outputPath = resolve50(process.cwd(), output3);
460588
+ outputPath = resolve51(process.cwd(), output3);
460525
460589
  await writeFile34(outputPath, buffer);
460526
460590
  }
460527
460591
  return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath };
@@ -460544,7 +460608,7 @@ async function executeVideoExtend(options) {
460544
460608
  let outputPath;
460545
460609
  if (output3 && finalResult.videoUrl) {
460546
460610
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
460547
- outputPath = resolve50(process.cwd(), output3);
460611
+ outputPath = resolve51(process.cwd(), output3);
460548
460612
  await writeFile34(outputPath, buffer);
460549
460613
  }
460550
460614
  return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, outputPath };
@@ -460572,13 +460636,13 @@ __export(detect_exports, {
460572
460636
  executeDetectSilence: () => executeDetectSilence
460573
460637
  });
460574
460638
  import { readFile as readFile28, writeFile as writeFile36 } from "node:fs/promises";
460575
- import { resolve as resolve53, basename as basename13 } from "node:path";
460639
+ import { resolve as resolve54, basename as basename13 } from "node:path";
460576
460640
  async function executeDetectScenes(options) {
460577
460641
  try {
460578
460642
  if (!commandExists("ffmpeg")) {
460579
460643
  return { success: false, error: "FFmpeg not found. Install with: brew install ffmpeg" };
460580
460644
  }
460581
- const absPath = resolve53(process.cwd(), options.videoPath);
460645
+ const absPath = resolve54(process.cwd(), options.videoPath);
460582
460646
  const threshold = options.threshold ?? 0.3;
460583
460647
  const { stdout: sceneStdout, stderr: sceneStderr } = await execSafe("ffmpeg", [
460584
460648
  "-i",
@@ -460609,7 +460673,7 @@ async function executeDetectScenes(options) {
460609
460673
  duration: (i < scenes.length - 1 ? scenes[i + 1].timestamp : totalDuration) - s.timestamp
460610
460674
  }));
460611
460675
  if (options.outputPath) {
460612
- const outputPath = resolve53(process.cwd(), options.outputPath);
460676
+ const outputPath = resolve54(process.cwd(), options.outputPath);
460613
460677
  await writeFile36(outputPath, JSON.stringify({ source: absPath, totalDuration, threshold, scenes: result }, null, 2), "utf-8");
460614
460678
  }
460615
460679
  return { success: true, scenes: result, totalDuration };
@@ -460622,7 +460686,7 @@ async function executeDetectSilence(options) {
460622
460686
  if (!commandExists("ffmpeg")) {
460623
460687
  return { success: false, error: "FFmpeg not found. Install with: brew install ffmpeg" };
460624
460688
  }
460625
- const absPath = resolve53(process.cwd(), options.mediaPath);
460689
+ const absPath = resolve54(process.cwd(), options.mediaPath);
460626
460690
  const noise = options.noise ?? "-30";
460627
460691
  const duration = options.duration ?? "0.5";
460628
460692
  const { stdout: silStdout, stderr: silStderr } = await execSafe("ffmpeg", [
@@ -460656,7 +460720,7 @@ async function executeDetectSilence(options) {
460656
460720
  }
460657
460721
  }
460658
460722
  if (options.outputPath) {
460659
- const outputPath = resolve53(process.cwd(), options.outputPath);
460723
+ const outputPath = resolve54(process.cwd(), options.outputPath);
460660
460724
  await writeFile36(outputPath, JSON.stringify({ source: absPath, silences }, null, 2), "utf-8");
460661
460725
  }
460662
460726
  return { success: true, silences };
@@ -460669,7 +460733,7 @@ async function executeDetectBeats(options) {
460669
460733
  if (!commandExists("ffmpeg")) {
460670
460734
  return { success: false, error: "FFmpeg not found. Install with: brew install ffmpeg" };
460671
460735
  }
460672
- const absPath = resolve53(process.cwd(), options.audioPath);
460736
+ const absPath = resolve54(process.cwd(), options.audioPath);
460673
460737
  const { stdout: beatStdout, stderr: beatStderr } = await execSafe("ffmpeg", [
460674
460738
  "-i",
460675
460739
  absPath,
@@ -460705,7 +460769,7 @@ async function executeDetectBeats(options) {
460705
460769
  }
460706
460770
  }
460707
460771
  if (options.outputPath) {
460708
- const outputPath = resolve53(process.cwd(), options.outputPath);
460772
+ const outputPath = resolve54(process.cwd(), options.outputPath);
460709
460773
  await writeFile36(outputPath, JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2), "utf-8");
460710
460774
  }
460711
460775
  return { success: true, beats, beatCount: beats.length };
@@ -460756,7 +460820,7 @@ var init_detect = __esm({
460756
460820
  spinner2.fail("FFmpeg not found");
460757
460821
  exitWithError(generalError("FFmpeg not found", "Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)"));
460758
460822
  }
460759
- const absPath = resolve53(process.cwd(), videoPath);
460823
+ const absPath = resolve54(process.cwd(), videoPath);
460760
460824
  const threshold = parseFloat(options.threshold);
460761
460825
  spinner2.text = "Analyzing video...";
460762
460826
  const { stdout: sceneStdout, stderr: sceneStderr } = await execSafe("ffmpeg", [
@@ -460797,7 +460861,7 @@ var init_detect = __esm({
460797
460861
  }
460798
460862
  console.log();
460799
460863
  if (options.output) {
460800
- const outputPath = resolve53(process.cwd(), options.output);
460864
+ const outputPath = resolve54(process.cwd(), options.output);
460801
460865
  const result = {
460802
460866
  source: absPath,
460803
460867
  totalDuration,
@@ -460813,7 +460877,7 @@ var init_detect = __esm({
460813
460877
  console.log(source_default.green(`Saved to: ${outputPath}`));
460814
460878
  }
460815
460879
  if (options.project) {
460816
- const projectPath = resolve53(process.cwd(), options.project);
460880
+ const projectPath = resolve54(process.cwd(), options.project);
460817
460881
  const content = await readFile28(projectPath, "utf-8");
460818
460882
  const data = JSON.parse(content);
460819
460883
  const project = Project.fromJSON(data);
@@ -460871,7 +460935,7 @@ var init_detect = __esm({
460871
460935
  });
460872
460936
  return;
460873
460937
  }
460874
- const absPath = resolve53(process.cwd(), mediaPath);
460938
+ const absPath = resolve54(process.cwd(), mediaPath);
460875
460939
  const noise = options.noise;
460876
460940
  const duration = options.duration;
460877
460941
  const { stdout: silStdout, stderr: silStderr } = await execSafe("ffmpeg", [
@@ -460920,7 +460984,7 @@ var init_detect = __esm({
460920
460984
  }
460921
460985
  console.log();
460922
460986
  if (options.output) {
460923
- const outputPath = resolve53(process.cwd(), options.output);
460987
+ const outputPath = resolve54(process.cwd(), options.output);
460924
460988
  await writeFile36(
460925
460989
  outputPath,
460926
460990
  JSON.stringify({ source: absPath, silences }, null, 2),
@@ -460955,7 +461019,7 @@ var init_detect = __esm({
460955
461019
  });
460956
461020
  return;
460957
461021
  }
460958
- const absPath = resolve53(process.cwd(), audioPath);
461022
+ const absPath = resolve54(process.cwd(), audioPath);
460959
461023
  const { stdout: beatStdout, stderr: beatStderr } = await execSafe("ffmpeg", [
460960
461024
  "-i",
460961
461025
  absPath,
@@ -461005,7 +461069,7 @@ var init_detect = __esm({
461005
461069
  }
461006
461070
  console.log();
461007
461071
  if (options.output) {
461008
- const outputPath = resolve53(process.cwd(), options.output);
461072
+ const outputPath = resolve54(process.cwd(), options.output);
461009
461073
  await writeFile36(
461010
461074
  outputPath,
461011
461075
  JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2),
@@ -461024,8 +461088,8 @@ var init_detect = __esm({
461024
461088
 
461025
461089
  // ../cli/src/pipeline/renderers/html-clips.ts
461026
461090
  function relAsset(url) {
461027
- const basename17 = url.split("/").pop() ?? url;
461028
- return `assets/${basename17}`;
461091
+ const basename18 = url.split("/").pop() ?? url;
461092
+ return `assets/${basename18}`;
461029
461093
  }
461030
461094
  function buildClipElements(state) {
461031
461095
  return state.clips.map((clip) => {
@@ -461199,7 +461263,7 @@ __export(project_builder_exports, {
461199
461263
  buildTempProject: () => buildTempProject,
461200
461264
  resolveSourceUrl: () => resolveSourceUrl
461201
461265
  });
461202
- import { mkdtemp as mkdtemp4, mkdir as mkdir24, copyFile as copyFile4, writeFile as writeFile41, rm as rm5, readdir as readdir4 } from "node:fs/promises";
461266
+ import { mkdtemp as mkdtemp4, mkdir as mkdir25, copyFile as copyFile4, writeFile as writeFile42, rm as rm5, readdir as readdir4 } from "node:fs/promises";
461203
461267
  import { existsSync as existsSync51 } from "node:fs";
461204
461268
  import { tmpdir as tmpdir6 } from "node:os";
461205
461269
  import { createRequire } from "node:module";
@@ -461207,7 +461271,7 @@ import * as path13 from "node:path";
461207
461271
  async function buildTempProject(state, projectFileDir) {
461208
461272
  const dir = await mkdtemp4(path13.join(tmpdir6(), "vibeframe-hf-"));
461209
461273
  const assetsDir = path13.join(dir, "assets");
461210
- await mkdir24(assetsDir, { recursive: true });
461274
+ await mkdir25(assetsDir, { recursive: true });
461211
461275
  const copied = /* @__PURE__ */ new Map();
461212
461276
  for (const source3 of state.sources) {
461213
461277
  if (copied.has(source3.id)) continue;
@@ -461223,7 +461287,7 @@ async function buildTempProject(state, projectFileDir) {
461223
461287
  await copyLottieRuntime(dir);
461224
461288
  }
461225
461289
  const html = generateCompositionHtml(state);
461226
- await writeFile41(path13.join(dir, "index.html"), html, "utf-8");
461290
+ await writeFile42(path13.join(dir, "index.html"), html, "utf-8");
461227
461291
  return {
461228
461292
  dir,
461229
461293
  cleanup: () => rm5(dir, { recursive: true, force: true })
@@ -461237,7 +461301,7 @@ async function copyLottieRuntime(tempDir) {
461237
461301
  const wasmSrc = path13.join(path13.dirname(webEntry), "dotlottie-player.wasm");
461238
461302
  const vendorDir = path13.join(tempDir, "vendor");
461239
461303
  const wcDest = path13.join(vendorDir, "dotlottie-wc");
461240
- await mkdir24(wcDest, { recursive: true });
461304
+ await mkdir25(wcDest, { recursive: true });
461241
461305
  for (const file of await readdir4(wcDistDir)) {
461242
461306
  if (file.endsWith(".map") || file.endsWith(".d.ts")) continue;
461243
461307
  await copyFile4(path13.join(wcDistDir, file), path13.join(wcDest, file));
@@ -463279,7 +463343,7 @@ init_ai_edit();
463279
463343
  init_api_key();
463280
463344
  init_exec_safe();
463281
463345
  init_remotion();
463282
- import { resolve as resolve30, dirname as dirname23, basename as basename9 } from "node:path";
463346
+ import { resolve as resolve31, dirname as dirname23, basename as basename9 } from "node:path";
463283
463347
  import { writeFile as writeFile18, mkdir as mkdir16, rm as rm4 } from "node:fs/promises";
463284
463348
  import { existsSync as existsSync41 } from "node:fs";
463285
463349
  import { tmpdir as tmpdir4 } from "node:os";
@@ -463431,9 +463495,9 @@ async function executeAnimatedCaption(options) {
463431
463495
  } catch {
463432
463496
  }
463433
463497
  const effectiveFontSize = fontSize ?? Math.round(height * 0.04);
463434
- const tmpAudioDir = resolve30(tmpdir4(), `vf-ac-${Date.now()}`);
463498
+ const tmpAudioDir = resolve31(tmpdir4(), `vf-ac-${Date.now()}`);
463435
463499
  await mkdir16(tmpAudioDir, { recursive: true });
463436
- const audioPath = resolve30(tmpAudioDir, "audio.wav");
463500
+ const audioPath = resolve31(tmpAudioDir, "audio.wav");
463437
463501
  await execSafe("ffmpeg", [
463438
463502
  "-y",
463439
463503
  "-i",
@@ -463460,7 +463524,7 @@ async function executeAnimatedCaption(options) {
463460
463524
  return { success: false, error: "No words detected in transcription" };
463461
463525
  }
463462
463526
  const groups = groupWords(transcript.words, { wordsPerGroup, maxChars });
463463
- const absOutputPath = resolve30(process.cwd(), outputPath);
463527
+ const absOutputPath = resolve31(process.cwd(), outputPath);
463464
463528
  const outDir = dirname23(absOutputPath);
463465
463529
  if (!existsSync41(outDir)) {
463466
463530
  await mkdir16(outDir, { recursive: true });
@@ -463471,7 +463535,7 @@ async function executeAnimatedCaption(options) {
463471
463535
  effectiveStyle,
463472
463536
  { highlightColor, fontSize: effectiveFontSize, position, width, height }
463473
463537
  );
463474
- const assPath = resolve30(tmpAudioDir, "captions.ass");
463538
+ const assPath = resolve31(tmpAudioDir, "captions.ass");
463475
463539
  await writeFile18(assPath, assContent, "utf-8");
463476
463540
  const escapedAssPath = assPath.replace(/\\/g, "\\\\").replace(/:/g, "\\:");
463477
463541
  await execSafe("ffmpeg", [
@@ -463876,7 +463940,7 @@ var editFillGapsTool = defineTool({
463876
463940
  cost: "high",
463877
463941
  description: "Fill timeline gaps with AI-generated video using Kling image-to-video. Detects empty regions in a project's timeline, extracts the last frame of the preceding clip, and generates a continuation video. Requires KLING_API_KEY and IMGBB_API_KEY (image hosting for Kling).",
463878
463942
  schema: z3.object({
463879
- projectPath: z3.string().describe("Project file path (.vibe.json)"),
463943
+ projectPath: z3.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
463880
463944
  output: z3.string().optional().describe("Output project path (default: overwrite input)"),
463881
463945
  dir: z3.string().optional().describe("Directory to save generated videos (default: <projectDir>/footage)"),
463882
463946
  prompt: z3.string().optional().describe("Custom prompt for video generation (default: 'Continue the scene naturally with subtle motion')"),
@@ -463940,12 +464004,12 @@ init_dist();
463940
464004
  init_engine();
463941
464005
  init_ai_helpers();
463942
464006
  import { readFile as readFile21, writeFile as writeFile20 } from "node:fs/promises";
463943
- import { resolve as resolve35 } from "node:path";
464007
+ import { resolve as resolve36 } from "node:path";
463944
464008
  async function executeSuggestEdit(options) {
463945
464009
  try {
463946
464010
  const apiKey = options.apiKey ?? process.env.GOOGLE_API_KEY;
463947
464011
  if (!apiKey) return { success: false, error: "GOOGLE_API_KEY required for suggest" };
463948
- const filePath = resolve35(process.cwd(), options.projectPath);
464012
+ const filePath = resolve36(process.cwd(), options.projectPath);
463949
464013
  const content = await readFile21(filePath, "utf-8");
463950
464014
  const data = JSON.parse(content);
463951
464015
  const project = Project.fromJSON(data);
@@ -464065,7 +464129,7 @@ var analyzeSuggestTool = defineTool({
464065
464129
  cost: "low",
464066
464130
  description: "Get natural-language edit suggestions for a project from Gemini. Returns suggestions array with type/confidence/clipIds. With `apply: true`, applies the first suggestion in place. Requires GOOGLE_API_KEY.",
464067
464131
  schema: z4.object({
464068
- projectPath: z4.string().describe("Project file path (.vibe.json)"),
464132
+ projectPath: z4.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
464069
464133
  instruction: z4.string().describe("Natural-language instruction (e.g. 'trim all clips to 5 seconds', 'add transitions between every clip')"),
464070
464134
  apply: z4.boolean().optional().describe("Apply the first suggestion in place")
464071
464135
  }),
@@ -464427,7 +464491,7 @@ init_ai_script_pipeline();
464427
464491
 
464428
464492
  // ../cli/src/commands/ai-highlights.ts
464429
464493
  import { readFile as readFile27, writeFile as writeFile35, mkdir as mkdir21 } from "node:fs/promises";
464430
- import { resolve as resolve51, dirname as dirname28, basename as basename12, extname as extname11 } from "node:path";
464494
+ import { resolve as resolve53, dirname as dirname28, basename as basename12, extname as extname11 } from "node:path";
464431
464495
  import { existsSync as existsSync49 } from "node:fs";
464432
464496
  init_dist();
464433
464497
  init_engine();
@@ -464458,7 +464522,7 @@ function filterHighlights(highlights, options) {
464458
464522
  }
464459
464523
  async function executeHighlights(options) {
464460
464524
  try {
464461
- const absPath = resolve51(process.cwd(), options.media);
464525
+ const absPath = resolve53(process.cwd(), options.media);
464462
464526
  if (!existsSync49(absPath)) {
464463
464527
  return { success: false, highlights: [], totalDuration: 0, totalHighlightDuration: 0, error: `File not found: ${absPath}` };
464464
464528
  }
@@ -464606,7 +464670,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
464606
464670
  totalHighlightDuration
464607
464671
  };
464608
464672
  if (options.output) {
464609
- const outputPath = resolve51(process.cwd(), options.output);
464673
+ const outputPath = resolve53(process.cwd(), options.output);
464610
464674
  await writeFile35(outputPath, JSON.stringify({
464611
464675
  sourceFile: absPath,
464612
464676
  totalDuration: sourceDuration,
@@ -464641,7 +464705,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
464641
464705
  currentTime += highlight.duration;
464642
464706
  }
464643
464707
  }
464644
- const projectPath = resolve51(process.cwd(), options.project);
464708
+ const projectPath = resolve53(process.cwd(), options.project);
464645
464709
  await writeFile35(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
464646
464710
  extractResult.projectPath = projectPath;
464647
464711
  }
@@ -464661,7 +464725,7 @@ async function executeAutoShorts(options) {
464661
464725
  if (!commandExists("ffmpeg")) {
464662
464726
  return { success: false, shorts: [], error: "FFmpeg not found" };
464663
464727
  }
464664
- const absPath = resolve51(process.cwd(), options.video);
464728
+ const absPath = resolve53(process.cwd(), options.video);
464665
464729
  if (!existsSync49(absPath)) {
464666
464730
  return { success: false, shorts: [], error: `File not found: ${absPath}` };
464667
464731
  }
@@ -464789,7 +464853,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
464789
464853
  }))
464790
464854
  };
464791
464855
  }
464792
- const outputDir = options.outputDir ? resolve51(process.cwd(), options.outputDir) : dirname28(absPath);
464856
+ const outputDir = options.outputDir ? resolve53(process.cwd(), options.outputDir) : dirname28(absPath);
464793
464857
  if (options.outputDir && !existsSync49(outputDir)) {
464794
464858
  await mkdir21(outputDir, { recursive: true });
464795
464859
  }
@@ -464800,7 +464864,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
464800
464864
  for (let i = 0; i < selectedHighlights.length; i++) {
464801
464865
  const h = selectedHighlights[i];
464802
464866
  const baseName = basename12(absPath, extname11(absPath));
464803
- const outputPath = resolve51(outputDir, `${baseName}-short-${i + 1}.mp4`);
464867
+ const outputPath = resolve53(outputDir, `${baseName}-short-${i + 1}.mp4`);
464804
464868
  const { stdout: probeOut } = await execSafe("ffprobe", [
464805
464869
  "-v",
464806
464870
  "error",
@@ -464868,7 +464932,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
464868
464932
 
464869
464933
  // ../cli/src/pipeline/executor.ts
464870
464934
  var import_yaml7 = __toESM(require_dist(), 1);
464871
- import { resolve as resolve54 } from "node:path";
464935
+ import { resolve as resolve55 } from "node:path";
464872
464936
  import { readFile as readFile29, writeFile as writeFile37, mkdir as mkdir23 } from "node:fs/promises";
464873
464937
  import { existsSync as existsSync50 } from "node:fs";
464874
464938
 
@@ -464976,9 +465040,9 @@ function registerAction(action, handler4) {
464976
465040
  }
464977
465041
  function getOutput(params, outputDir, defaultName) {
464978
465042
  if (params.output && typeof params.output === "string") {
464979
- return resolve54(outputDir, params.output);
465043
+ return resolve55(outputDir, params.output);
464980
465044
  }
464981
- return resolve54(outputDir, defaultName);
465045
+ return resolve55(outputDir, defaultName);
464982
465046
  }
464983
465047
  async function ensureActionsRegistered() {
464984
465048
  if (Object.keys(ACTION_HANDLERS).length > 0) return;
@@ -465131,7 +465195,7 @@ async function ensureActionsRegistered() {
465131
465195
  const { executeSceneBuild: executeSceneBuild2 } = await Promise.resolve().then(() => (init_scene_build(), scene_build_exports));
465132
465196
  const projectRel = params.project ?? ".";
465133
465197
  const r = await executeSceneBuild2({
465134
- projectDir: resolve54(outputDir, projectRel),
465198
+ projectDir: resolve55(outputDir, projectRel),
465135
465199
  mode: params.mode,
465136
465200
  effort: params.effort,
465137
465201
  composer: params.composer,
@@ -465157,7 +465221,7 @@ async function ensureActionsRegistered() {
465157
465221
  const { executeSceneRender: executeSceneRender2 } = await Promise.resolve().then(() => (init_scene_render(), scene_render_exports));
465158
465222
  const projectRel = params.project ?? ".";
465159
465223
  const r = await executeSceneRender2({
465160
- projectDir: resolve54(outputDir, projectRel),
465224
+ projectDir: resolve55(outputDir, projectRel),
465161
465225
  root: params.root,
465162
465226
  output: params.output,
465163
465227
  fps: params.fps,
@@ -465181,7 +465245,7 @@ async function ensureActionsRegistered() {
465181
465245
  });
465182
465246
  }
465183
465247
  async function loadPipeline(filePath) {
465184
- const absPath = resolve54(process.cwd(), filePath);
465248
+ const absPath = resolve55(process.cwd(), filePath);
465185
465249
  if (!existsSync50(absPath)) {
465186
465250
  throw new Error(`Pipeline file not found: ${absPath}`);
465187
465251
  }
@@ -465201,13 +465265,13 @@ async function loadPipeline(filePath) {
465201
465265
  var CHECKPOINT_FILE = ".pipeline-state.yaml";
465202
465266
  async function executePipeline(manifest2, options = {}) {
465203
465267
  await ensureActionsRegistered();
465204
- const outputDir = resolve54(process.cwd(), options.outputDir || `${manifest2.name}-output`);
465268
+ const outputDir = resolve55(process.cwd(), options.outputDir || `${manifest2.name}-output`);
465205
465269
  await mkdir23(outputDir, { recursive: true });
465206
465270
  const completedSteps = /* @__PURE__ */ new Map();
465207
465271
  const results = [];
465208
465272
  const startTime = Date.now();
465209
465273
  if (options.resume) {
465210
- const checkpointPath = resolve54(outputDir, CHECKPOINT_FILE);
465274
+ const checkpointPath = resolve55(outputDir, CHECKPOINT_FILE);
465211
465275
  if (existsSync50(checkpointPath)) {
465212
465276
  const checkpointContent = await readFile29(checkpointPath, "utf-8");
465213
465277
  const checkpoint = (0, import_yaml7.parse)(checkpointContent);
@@ -465328,7 +465392,7 @@ async function executePipeline(manifest2, options = {}) {
465328
465392
  }))
465329
465393
  };
465330
465394
  await writeFile37(
465331
- resolve54(outputDir, CHECKPOINT_FILE),
465395
+ resolve55(outputDir, CHECKPOINT_FILE),
465332
465396
  (0, import_yaml7.stringify)(checkpoint, { indent: 2 }),
465333
465397
  "utf-8"
465334
465398
  );
@@ -465385,7 +465449,7 @@ var pipelineHighlightsTool = defineTool({
465385
465449
  schema: z6.object({
465386
465450
  media: z6.string().describe("Path to the input video file"),
465387
465451
  output: z6.string().optional().describe("Output path for the highlights compilation"),
465388
- project: z6.string().optional().describe("Path to .vibe.json project to add highlights to"),
465452
+ project: z6.string().optional().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file to add highlights to"),
465389
465453
  duration: z6.number().optional().describe("Maximum duration per highlight in seconds (default: 30)"),
465390
465454
  count: z6.number().optional().describe("Maximum number of highlights to extract (default: 5)"),
465391
465455
  threshold: z6.number().optional().describe("Minimum confidence threshold 0-1 (default: 0.7)"),
@@ -465635,14 +465699,17 @@ var detectTools = [
465635
465699
 
465636
465700
  // ../cli/src/tools/manifest/timeline.ts
465637
465701
  import { z as z8 } from "zod";
465638
- import { resolve as resolve56 } from "node:path";
465702
+ import { mkdir as mkdir24, writeFile as writeFile40 } from "node:fs/promises";
465703
+ import { basename as basename14, resolve as resolve56 } from "node:path";
465704
+ init_engine();
465705
+ init_project_resolver();
465639
465706
 
465640
465707
  // ../cli/src/tools/manifest/_project-io.ts
465641
465708
  init_engine();
465709
+ init_project_resolver();
465642
465710
  import { readFile as readFile30, writeFile as writeFile39 } from "node:fs/promises";
465643
- import { resolve as resolve55 } from "node:path";
465644
465711
  async function loadProject(projectPath, cwd) {
465645
- const absPath = resolve55(cwd, projectPath);
465712
+ const absPath = await resolveTimelineFile(projectPath, cwd);
465646
465713
  const content = await readFile30(absPath, "utf-8");
465647
465714
  const data = JSON.parse(content);
465648
465715
  return { project: Project.fromJSON(data), absPath };
@@ -465667,13 +465734,70 @@ var MEDIA_TYPES = {
465667
465734
  gif: "image",
465668
465735
  webp: "image"
465669
465736
  };
465737
+ var timelineCreateTool = defineTool({
465738
+ name: "timeline_create",
465739
+ category: "timeline",
465740
+ cost: "free",
465741
+ description: "Create a low-level timeline JSON file for FFmpeg-style editing",
465742
+ schema: z8.object({
465743
+ name: z8.string().describe("Timeline name or directory path"),
465744
+ outputPath: z8.string().optional().describe("Output file path. Defaults to <name>/timeline.json"),
465745
+ fps: z8.number().optional().describe("Frames per second (default: 30)")
465746
+ }),
465747
+ async execute(args, ctx) {
465748
+ const projectName = args.name === "." ? basename14(ctx.workingDirectory) : basename14(resolve56(ctx.workingDirectory, args.name));
465749
+ const project = new Project(projectName);
465750
+ if (args.fps) project.setFrameRate(args.fps);
465751
+ let outputPath;
465752
+ if (args.outputPath) {
465753
+ outputPath = resolve56(ctx.workingDirectory, args.outputPath);
465754
+ } else {
465755
+ const dirPath = resolve56(ctx.workingDirectory, args.name);
465756
+ await mkdir24(dirPath, { recursive: true });
465757
+ outputPath = resolve56(dirPath, TIMELINE_FILENAME);
465758
+ }
465759
+ await writeFile40(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
465760
+ return {
465761
+ success: true,
465762
+ data: { name: projectName, outputPath },
465763
+ humanLines: [`Created timeline "${projectName}" at ${outputPath}`]
465764
+ };
465765
+ }
465766
+ });
465767
+ var timelineInfoTool = defineTool({
465768
+ name: "timeline_info",
465769
+ category: "timeline",
465770
+ cost: "free",
465771
+ description: "Get information about a timeline JSON file. Legacy *.vibe.json files are supported.",
465772
+ schema: z8.object({
465773
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file")
465774
+ }),
465775
+ async execute(args, ctx) {
465776
+ const { project } = await loadProject(args.projectPath, ctx.workingDirectory);
465777
+ const meta = project.getMeta();
465778
+ const info = {
465779
+ name: meta.name,
465780
+ aspectRatio: meta.aspectRatio,
465781
+ frameRate: meta.frameRate,
465782
+ duration: meta.duration,
465783
+ sources: project.getSources().length,
465784
+ tracks: project.getTracks().length,
465785
+ clips: project.getClips().length
465786
+ };
465787
+ return {
465788
+ success: true,
465789
+ data: info,
465790
+ humanLines: [JSON.stringify(info, null, 2)]
465791
+ };
465792
+ }
465793
+ });
465670
465794
  var timelineAddSourceTool = defineTool({
465671
465795
  name: "timeline_add_source",
465672
465796
  category: "timeline",
465673
465797
  cost: "free",
465674
- description: "Add a media source (video, audio, image) to the project",
465798
+ description: "Add a media source (video, audio, image) to the timeline",
465675
465799
  schema: z8.object({
465676
- projectPath: z8.string().describe("Path to the project file"),
465800
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465677
465801
  mediaPath: z8.string().describe("Path to the media file"),
465678
465802
  name: z8.string().optional().describe("Optional name for the source"),
465679
465803
  duration: z8.number().optional().describe("Duration of the media in seconds (default: 10)")
@@ -465698,7 +465822,7 @@ var timelineAddClipTool = defineTool({
465698
465822
  cost: "free",
465699
465823
  description: "Add a clip to the timeline from an existing source",
465700
465824
  schema: z8.object({
465701
- projectPath: z8.string().describe("Path to the project file"),
465825
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465702
465826
  sourceId: z8.string().describe("ID of the media source"),
465703
465827
  trackId: z8.string().optional().describe("ID of the track to add clip to (optional, uses first video track)"),
465704
465828
  startTime: z8.number().optional().describe("Start time on timeline in seconds (default: 0)"),
@@ -465729,7 +465853,7 @@ var timelineSplitClipTool = defineTool({
465729
465853
  cost: "free",
465730
465854
  description: "Split a clip at a specific time",
465731
465855
  schema: z8.object({
465732
- projectPath: z8.string().describe("Path to the project file"),
465856
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465733
465857
  clipId: z8.string().describe("ID of the clip to split"),
465734
465858
  splitTime: z8.number().describe("Time to split at (relative to clip start) in seconds")
465735
465859
  }),
@@ -465747,7 +465871,7 @@ var timelineTrimClipTool = defineTool({
465747
465871
  cost: "free",
465748
465872
  description: "Trim a clip by adjusting its start or end",
465749
465873
  schema: z8.object({
465750
- projectPath: z8.string().describe("Path to the project file"),
465874
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465751
465875
  clipId: z8.string().describe("ID of the clip to trim"),
465752
465876
  trimStart: z8.number().optional().describe("New source start offset in seconds"),
465753
465877
  trimEnd: z8.number().optional().describe("New duration in seconds")
@@ -465766,7 +465890,7 @@ var timelineMoveClipTool = defineTool({
465766
465890
  cost: "free",
465767
465891
  description: "Move a clip to a new position or track",
465768
465892
  schema: z8.object({
465769
- projectPath: z8.string().describe("Path to the project file"),
465893
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465770
465894
  clipId: z8.string().describe("ID of the clip to move"),
465771
465895
  newStartTime: z8.number().optional().describe("New start time on timeline in seconds"),
465772
465896
  newTrackId: z8.string().optional().describe("ID of the target track (optional)")
@@ -465788,7 +465912,7 @@ var timelineDeleteClipTool = defineTool({
465788
465912
  cost: "free",
465789
465913
  description: "Delete a clip from the timeline",
465790
465914
  schema: z8.object({
465791
- projectPath: z8.string().describe("Path to the project file"),
465915
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465792
465916
  clipId: z8.string().describe("ID of the clip to delete")
465793
465917
  }),
465794
465918
  async execute(args, ctx) {
@@ -465804,7 +465928,7 @@ var timelineDuplicateClipTool = defineTool({
465804
465928
  cost: "free",
465805
465929
  description: "Duplicate a clip on the timeline (optionally at a new start time)",
465806
465930
  schema: z8.object({
465807
- projectPath: z8.string().describe("Path to the project file"),
465931
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465808
465932
  clipId: z8.string().describe("ID of the clip to duplicate"),
465809
465933
  newStartTime: z8.number().optional().describe("Start time for the duplicated clip (optional, places after original)")
465810
465934
  }),
@@ -465822,7 +465946,7 @@ var timelineAddEffectTool = defineTool({
465822
465946
  cost: "free",
465823
465947
  description: "Add an effect to a clip",
465824
465948
  schema: z8.object({
465825
- projectPath: z8.string().describe("Path to the project file"),
465949
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465826
465950
  clipId: z8.string().describe("ID of the clip"),
465827
465951
  effectType: z8.string().describe("Effect type: fadeIn, fadeOut, blur, brightness, contrast, saturation, grayscale, sepia, invert"),
465828
465952
  startTime: z8.number().optional().describe("Effect start time relative to clip (default: 0)"),
@@ -465848,7 +465972,7 @@ var timelineAddTrackTool = defineTool({
465848
465972
  cost: "free",
465849
465973
  description: "Add a new track to the timeline",
465850
465974
  schema: z8.object({
465851
- projectPath: z8.string().describe("Path to the project file"),
465975
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465852
465976
  trackType: z8.string().describe("Track type: video or audio"),
465853
465977
  name: z8.string().optional().describe("Track name (optional)")
465854
465978
  }),
@@ -465874,7 +465998,7 @@ var timelineListTool = defineTool({
465874
465998
  cost: "free",
465875
465999
  description: "List all sources, tracks, and clips in a project",
465876
466000
  schema: z8.object({
465877
- projectPath: z8.string().describe("Path to the project file")
466001
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file")
465878
466002
  }),
465879
466003
  async execute(args, ctx) {
465880
466004
  const { project } = await loadProject(args.projectPath, ctx.workingDirectory);
@@ -465891,6 +466015,8 @@ var timelineListTool = defineTool({
465891
466015
  }
465892
466016
  });
465893
466017
  var timelineTools = [
466018
+ timelineCreateTool,
466019
+ timelineInfoTool,
465894
466020
  timelineAddSourceTool,
465895
466021
  timelineAddClipTool,
465896
466022
  timelineSplitClipTool,
@@ -465906,16 +466032,16 @@ var timelineTools = [
465906
466032
  // ../cli/src/tools/manifest/project.ts
465907
466033
  import { z as z9 } from "zod";
465908
466034
  import { resolve as resolve57 } from "node:path";
465909
- import { writeFile as writeFile40 } from "node:fs/promises";
466035
+ import { writeFile as writeFile41 } from "node:fs/promises";
465910
466036
  init_engine();
465911
466037
  var projectCreateTool = defineTool({
465912
466038
  name: "project_create",
465913
466039
  category: "project",
465914
466040
  cost: "free",
465915
- description: "Create a new VibeFrame project file",
466041
+ description: "Deprecated alias for creating low-level timeline state. Prefer timeline_create.",
465916
466042
  schema: z9.object({
465917
466043
  name: z9.string().describe("Project name"),
465918
- outputPath: z9.string().optional().describe("Output file path (defaults to {name}.vibe.json)"),
466044
+ outputPath: z9.string().optional().describe("Output file path (defaults to {name}.vibe.json for legacy compatibility)"),
465919
466045
  width: z9.number().optional().describe("Video width in pixels (default: 1920)"),
465920
466046
  height: z9.number().optional().describe("Video height in pixels (default: 1080)"),
465921
466047
  fps: z9.number().optional().describe("Frames per second (default: 30)")
@@ -465924,11 +466050,11 @@ var projectCreateTool = defineTool({
465924
466050
  const outputPath = resolve57(ctx.workingDirectory, args.outputPath ?? `${args.name}.vibe.json`);
465925
466051
  const project = new Project(args.name);
465926
466052
  if (args.fps) project.setFrameRate(args.fps);
465927
- await writeFile40(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
466053
+ await writeFile41(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
465928
466054
  return {
465929
466055
  success: true,
465930
466056
  data: { name: args.name, outputPath },
465931
- humanLines: [`Created project "${args.name}" at ${outputPath}`]
466057
+ humanLines: [`Created legacy timeline project "${args.name}" at ${outputPath}`]
465932
466058
  };
465933
466059
  }
465934
466060
  });
@@ -465936,9 +466062,9 @@ var projectInfoTool = defineTool({
465936
466062
  name: "project_info",
465937
466063
  category: "project",
465938
466064
  cost: "free",
465939
- description: "Get information about a VibeFrame project",
466065
+ description: "Deprecated alias for timeline_info. Legacy *.vibe.json files remain supported.",
465940
466066
  schema: z9.object({
465941
- projectPath: z9.string().describe("Path to the .vibe.json project file")
466067
+ projectPath: z9.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file")
465942
466068
  }),
465943
466069
  async execute(args, ctx) {
465944
466070
  const { project } = await loadProject(args.projectPath, ctx.workingDirectory);
@@ -465976,19 +466102,15 @@ init_engine();
465976
466102
  init_exec_safe();
465977
466103
  init_output();
465978
466104
  init_validate();
465979
- import { readFile as readFile31, access as access5, stat as stat3 } from "node:fs/promises";
465980
- import { resolve as resolve59, basename as basename15 } from "node:path";
466105
+ init_project_resolver();
466106
+ import { readFile as readFile31, access as access6 } from "node:fs/promises";
466107
+ import { resolve as resolve59, basename as basename16 } from "node:path";
465981
466108
  import { spawn as spawn9 } from "node:child_process";
465982
- async function resolveProjectPath(inputPath) {
465983
- const filePath = resolve59(process.cwd(), inputPath);
465984
- try {
465985
- const stats = await stat3(filePath);
465986
- if (stats.isDirectory()) {
465987
- return resolve59(filePath, "project.vibe.json");
465988
- }
465989
- } catch {
465990
- }
465991
- return filePath;
466109
+ function timelineBaseName(path14) {
466110
+ const name = basename16(path14);
466111
+ if (name.endsWith(".vibe.json")) return name.slice(0, -".vibe.json".length);
466112
+ if (name.endsWith(".json")) return name.slice(0, -".json".length);
466113
+ return basename16(path14, ".vibe.json");
465992
466114
  }
465993
466115
  async function getMediaDuration(filePath, mediaType, defaultImageDuration = 5) {
465994
466116
  if (mediaType === "image") {
@@ -466057,7 +466179,7 @@ async function runExport(projectPath, outputPath, options = {}) {
466057
466179
  message: "FFmpeg not found. Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)"
466058
466180
  };
466059
466181
  }
466060
- const filePath = await resolveProjectPath(projectPath);
466182
+ const filePath = await resolveTimelineFile(projectPath);
466061
466183
  const content = await readFile31(filePath, "utf-8");
466062
466184
  const data = JSON.parse(content);
466063
466185
  const project = Project.fromJSON(data);
@@ -466079,7 +466201,7 @@ async function runExport(projectPath, outputPath, options = {}) {
466079
466201
  const source3 = sources.find((s) => s.id === clip.sourceId);
466080
466202
  if (source3) {
466081
466203
  try {
466082
- await access5(source3.url);
466204
+ await access6(source3.url);
466083
466205
  if (!sourceActualDurationMap.has(source3.id)) {
466084
466206
  try {
466085
466207
  const dur = await getMediaDuration(source3.url, source3.type);
@@ -466114,20 +466236,20 @@ async function runExport(projectPath, outputPath, options = {}) {
466114
466236
  };
466115
466237
  }
466116
466238
  }
466117
- var exportCommand = new Command("export").description("Export project to video file").argument("<project>", "Project file path").option("-o, --output <path>", "Output file path").option("--format <format>", "Output format (mp4, webm, mov, gif)", "mp4").option(
466239
+ var exportCommand = new Command("export").description("Export project to video file").argument("<project>", "Timeline file or directory").option("-o, --output <path>", "Output file path").option("--format <format>", "Output format (mp4, webm, mov, gif)", "mp4").option(
466118
466240
  "--preset <preset>",
466119
466241
  "Quality preset (draft, standard, high, ultra)",
466120
466242
  "standard"
466121
466243
  ).option("--overwrite", "Overwrite output file if exists", false).option("--gap-fill <strategy>", "Gap filling strategy (black, extend)", "extend").option("--backend <name>", "Render backend: ffmpeg (default) | hyperframes (experimental)", "ffmpeg").option("--bitrate <value>", "Video bitrate (e.g. 5000k, 8M) \u2014 overrides preset").option("--fps <number>", "Frames per second (e.g. 24, 30, 60) \u2014 overrides preset").option("--resolution <WxH>", "Output resolution (e.g. 1920x1080) \u2014 overrides preset").option("--codec <codec>", "Video codec: h264 (default) | h265 | vp9 \u2014 overrides preset").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
466122
466244
  Examples:
466123
- $ vibe export project.vibe.json -o output.mp4
466124
- $ vibe export project.vibe.json -o output.mp4 --preset high --overwrite
466125
- $ vibe export project.vibe.json -o output.webm --format webm
466126
- $ vibe export project.vibe.json -o output.gif --format gif
466127
- $ vibe export project.vibe.json -o out.mp4 --bitrate 5000k --fps 24 --codec h265
466128
- $ vibe export project.vibe.json -o out.mp4 --preset high --fps 60
466129
-
466130
- Cost: Free (no API keys needed). Requires FFmpeg.
466245
+ $ vibe export timeline.json -o output.mp4
466246
+ $ vibe export my-video -o output.mp4 --preset high --overwrite
466247
+ $ vibe export timeline.json -o output.webm --format webm
466248
+ $ vibe export timeline.json -o output.gif --format gif
466249
+ $ vibe export timeline.json -o out.mp4 --bitrate 5000k --fps 24 --codec h265
466250
+ $ vibe export timeline.json -o out.mp4 --preset high --fps 60
466251
+
466252
+ Cost: Free (no API keys needed). Requires FFmpeg. Legacy *.vibe.json files remain supported.
466131
466253
  GIF format: 15fps, no audio, looping. Good for previews and sharing.
466132
466254
  Custom flags (--bitrate, --fps, --resolution, --codec) override preset values.
466133
466255
  Run 'vibe schema export' for structured parameter info.`).action(async (projectPath, options) => {
@@ -466181,7 +466303,7 @@ Run 'vibe schema export' for structured parameter info.`).action(async (projectP
466181
466303
  exitWithError(generalError("FFmpeg not found", "Install with: brew install ffmpeg (macOS), apt install ffmpeg (Linux), or winget install ffmpeg (Windows)"));
466182
466304
  }
466183
466305
  spinner2.text = "Loading project...";
466184
- const filePath = await resolveProjectPath(projectPath);
466306
+ const filePath = await resolveTimelineFile(projectPath);
466185
466307
  const content = await readFile31(filePath, "utf-8");
466186
466308
  const data = JSON.parse(content);
466187
466309
  const project = Project.fromJSON(data);
@@ -466192,7 +466314,7 @@ Run 'vibe schema export' for structured parameter info.`).action(async (projectP
466192
466314
  }
466193
466315
  const outputPath = options.output ? resolve59(process.cwd(), options.output) : resolve59(
466194
466316
  process.cwd(),
466195
- `${basename15(projectPath, ".vibe.json")}.${options.format}`
466317
+ `${timelineBaseName(projectPath)}.${options.format}`
466196
466318
  );
466197
466319
  const basePresetSettings = getPresetSettings(options.preset, summary.aspectRatio);
466198
466320
  const presetSettings = applyCustomOverrides(basePresetSettings, customOverrides);
@@ -466205,7 +466327,7 @@ Run 'vibe schema export' for structured parameter info.`).action(async (projectP
466205
466327
  const source3 = sources.find((s) => s.id === clip.sourceId);
466206
466328
  if (source3) {
466207
466329
  try {
466208
- await access5(source3.url);
466330
+ await access6(source3.url);
466209
466331
  if (!sourceActualDurationMap.has(source3.id)) {
466210
466332
  try {
466211
466333
  const dur = await getMediaDuration(source3.url, source3.type);
@@ -466781,16 +466903,16 @@ function getPresetSettings(preset, aspectRatio) {
466781
466903
  async function runHyperframesExport(projectPath, options, spinner2, startedAt) {
466782
466904
  spinner2.text = "Loading project...";
466783
466905
  const { readFile: readFile34 } = await import("node:fs/promises");
466784
- const { resolve: resolve64, basename: basename17 } = await import("node:path");
466906
+ const { resolve: resolve64 } = await import("node:path");
466785
466907
  const { Project: Project2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
466786
466908
  const { createHyperframesBackend: createHyperframesBackend2 } = await Promise.resolve().then(() => (init_hyperframes(), hyperframes_exports));
466787
466909
  const { exitWithError: exitWithError2, generalError: generalError2, outputSuccess: outputSuccess2 } = await Promise.resolve().then(() => (init_output(), output_exports));
466788
466910
  const chalk2 = (await Promise.resolve().then(() => (init_source(), source_exports))).default;
466789
- const filePath = resolve64(process.cwd(), projectPath);
466911
+ const filePath = await resolveTimelineFile(projectPath);
466790
466912
  const content = await readFile34(filePath, "utf-8");
466791
466913
  const project = Project2.fromJSON(JSON.parse(content));
466792
466914
  const state = project.getState();
466793
- const outputPath = options.output ? resolve64(process.cwd(), options.output) : resolve64(process.cwd(), `${basename17(projectPath, ".vibe.json")}.${options.format ?? "mp4"}`);
466915
+ const outputPath = options.output ? resolve64(process.cwd(), options.output) : resolve64(process.cwd(), `${timelineBaseName(projectPath)}.${options.format ?? "mp4"}`);
466794
466916
  const quality = ["draft", "standard", "high"].includes(options.preset ?? "") ? options.preset : "standard";
466795
466917
  const backend = createHyperframesBackend2();
466796
466918
  spinner2.text = "Rendering with Hyperframes...";
@@ -466827,9 +466949,9 @@ var exportVideoTool = defineTool({
466827
466949
  name: "export_video",
466828
466950
  category: "export",
466829
466951
  cost: "free",
466830
- description: "Export a VibeFrame project to a video file (MP4, WebM, or MOV). Requires FFmpeg.",
466952
+ description: "Export a VibeFrame timeline to a video file (MP4, WebM, or MOV). Requires FFmpeg.",
466831
466953
  schema: z10.object({
466832
- projectPath: z10.string().describe("Path to the .vibe.json project file"),
466954
+ projectPath: z10.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
466833
466955
  outputPath: z10.string().describe("Output video file path (e.g., output.mp4)"),
466834
466956
  preset: z10.enum(["draft", "standard", "high", "ultra"]).optional().describe("Quality preset (default: standard)"),
466835
466957
  format: z10.enum(["mp4", "webm", "mov"]).optional().describe("Output format (default: mp4)"),
@@ -466854,11 +466976,12 @@ var exportVideoTool = defineTool({
466854
466976
  var exportTools = [exportVideoTool];
466855
466977
 
466856
466978
  // ../cli/src/tools/manifest/agent-only.ts
466857
- import { readFile as readFile32, writeFile as writeFile42, readdir as readdir5, stat as stat4, access as access6, unlink as unlink7 } from "node:fs/promises";
466858
- import { resolve as resolve61, join as join33, basename as basename16, extname as extname12 } from "node:path";
466979
+ import { readFile as readFile32, writeFile as writeFile43, readdir as readdir5, stat as stat4, access as access7, unlink as unlink7 } from "node:fs/promises";
466980
+ import { resolve as resolve61, join as join33, basename as basename17, extname as extname12 } from "node:path";
466859
466981
  import { z as z11 } from "zod";
466860
466982
  init_engine();
466861
466983
  init_exec_safe();
466984
+ init_project_resolver();
466862
466985
  function matchPattern(filename, pattern) {
466863
466986
  const regex2 = new RegExp(
466864
466987
  "^" + pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".") + "$",
@@ -466981,7 +467104,7 @@ var fsWriteTool = defineTool({
466981
467104
  async execute(args, ctx) {
466982
467105
  try {
466983
467106
  const absPath = resolve61(ctx.workingDirectory, args.path);
466984
- await writeFile42(absPath, args.content, "utf-8");
467107
+ await writeFile43(absPath, args.content, "utf-8");
466985
467108
  return { success: true, data: { bytes: args.content.length }, humanLines: [`File written: ${args.path} (${formatSize(args.content.length)})`] };
466986
467109
  } catch (error) {
466987
467110
  return { success: false, error: `Failed to write file: ${error instanceof Error ? error.message : String(error)}` };
@@ -467000,7 +467123,7 @@ var fsExistsTool = defineTool({
467000
467123
  async execute(args, ctx) {
467001
467124
  const absPath = resolve61(ctx.workingDirectory, args.path);
467002
467125
  try {
467003
- await access6(absPath);
467126
+ await access7(absPath);
467004
467127
  const stats = await stat4(absPath);
467005
467128
  const type = stats.isDirectory() ? "directory" : "file";
467006
467129
  return { success: true, data: { exists: true, type }, humanLines: [`${type} exists: ${args.path}`] };
@@ -467016,7 +467139,7 @@ var batchImportTool = defineTool({
467016
467139
  surfaces: ["agent"],
467017
467140
  description: "Import multiple media files from a directory into a project. Scans directory for video, audio, and image files.",
467018
467141
  schema: z11.object({
467019
- project: z11.string().describe("Project file path"),
467142
+ project: z11.string().describe("Timeline file or directory"),
467020
467143
  directory: z11.string().describe("Directory containing media files to import"),
467021
467144
  recursive: z11.boolean().optional().describe("Search subdirectories recursively (default: false)"),
467022
467145
  filter: z11.string().optional().describe("Filter files by extension, comma-separated (e.g., '.mp4,.mov')"),
@@ -467053,7 +467176,7 @@ var batchImportTool = defineTool({
467053
467176
  mediaFiles.sort();
467054
467177
  const addedSources = [];
467055
467178
  for (const mediaFile of mediaFiles) {
467056
- const mediaName = basename16(mediaFile);
467179
+ const mediaName = basename17(mediaFile);
467057
467180
  const mediaType = detectMediaType(mediaFile);
467058
467181
  let duration = imageDuration;
467059
467182
  if (mediaType !== "image") {
@@ -467063,7 +467186,7 @@ var batchImportTool = defineTool({
467063
467186
  const source3 = project.addSource({ name: mediaName, type: mediaType, url: mediaFile, duration });
467064
467187
  addedSources.push({ id: source3.id, name: mediaName, type: mediaType });
467065
467188
  }
467066
- await writeFile42(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467189
+ await writeFile43(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467067
467190
  return {
467068
467191
  success: true,
467069
467192
  data: { count: addedSources.length, sources: addedSources },
@@ -467085,7 +467208,7 @@ var batchConcatTool = defineTool({
467085
467208
  surfaces: ["agent"],
467086
467209
  description: "Concatenate multiple sources into sequential clips on the timeline",
467087
467210
  schema: z11.object({
467088
- project: z11.string().describe("Project file path"),
467211
+ project: z11.string().describe("Timeline file or directory"),
467089
467212
  sourceIds: z11.array(z11.string()).optional().describe("Source IDs to concatenate. If empty with useAll=true, uses all sources."),
467090
467213
  useAll: z11.boolean().optional().describe("Use all sources in the project (default: false)"),
467091
467214
  trackId: z11.string().optional().describe("Track to place clips on (auto-selects if not specified)"),
@@ -467131,7 +467254,7 @@ var batchConcatTool = defineTool({
467131
467254
  createdClips.push({ id: clip.id, sourceName: source3.name, startTime: currentTime, duration: source3.duration });
467132
467255
  currentTime += source3.duration + gap;
467133
467256
  }
467134
- await writeFile42(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467257
+ await writeFile43(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467135
467258
  const totalDuration = currentTime - gap - startTime;
467136
467259
  return {
467137
467260
  success: true,
@@ -467154,7 +467277,7 @@ var batchApplyEffectTool = defineTool({
467154
467277
  surfaces: ["agent"],
467155
467278
  description: "Apply an effect to multiple clips at once",
467156
467279
  schema: z11.object({
467157
- project: z11.string().describe("Project file path"),
467280
+ project: z11.string().describe("Timeline file or directory"),
467158
467281
  clipIds: z11.array(z11.string()).optional().describe("Clip IDs to apply effect to. If empty with useAll=true, applies to all clips."),
467159
467282
  useAll: z11.boolean().optional().describe("Apply to all clips in the project (default: false)"),
467160
467283
  effectType: z11.enum(["fadeIn", "fadeOut", "blur", "brightness", "contrast", "saturation", "speed", "volume"]).describe("Effect type to apply"),
@@ -467192,7 +467315,7 @@ var batchApplyEffectTool = defineTool({
467192
467315
  });
467193
467316
  if (effect) appliedEffects.push({ clipId: clip.id, effectId: effect.id });
467194
467317
  }
467195
- await writeFile42(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467318
+ await writeFile43(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467196
467319
  return {
467197
467320
  success: true,
467198
467321
  data: { applied: appliedEffects.length, effectType: args.effectType },
@@ -467203,17 +467326,6 @@ var batchApplyEffectTool = defineTool({
467203
467326
  }
467204
467327
  }
467205
467328
  });
467206
- async function resolveProjectPath2(inputPath, cwd) {
467207
- const filePath = resolve61(cwd, inputPath);
467208
- try {
467209
- const stats = await stat4(filePath);
467210
- if (stats.isDirectory()) {
467211
- return resolve61(filePath, "project.vibe.json");
467212
- }
467213
- } catch {
467214
- }
467215
- return filePath;
467216
- }
467217
467329
  var timelineClearTool = defineTool({
467218
467330
  name: "timeline_clear",
467219
467331
  category: "agent-only",
@@ -467221,13 +467333,13 @@ var timelineClearTool = defineTool({
467221
467333
  surfaces: ["agent"],
467222
467334
  description: "Clear timeline contents (remove clips, tracks, or sources)",
467223
467335
  schema: z11.object({
467224
- project: z11.string().describe("Project file path"),
467336
+ project: z11.string().describe("Timeline file or directory"),
467225
467337
  what: z11.enum(["clips", "tracks", "sources", "all"]).optional().describe("What to clear: clips (default), tracks, sources, or all"),
467226
467338
  keepTracks: z11.boolean().optional().describe("When clearing 'all', keep default empty tracks (default: true)")
467227
467339
  }),
467228
467340
  async execute(args, ctx) {
467229
467341
  try {
467230
- const filePath = await resolveProjectPath2(args.project, ctx.workingDirectory);
467342
+ const filePath = await resolveTimelineFile(args.project, ctx.workingDirectory);
467231
467343
  const content = await readFile32(filePath, "utf-8");
467232
467344
  const data = JSON.parse(content);
467233
467345
  const project = Project.fromJSON(data);
@@ -467270,7 +467382,7 @@ var timelineClearTool = defineTool({
467270
467382
  removed.sources++;
467271
467383
  }
467272
467384
  }
467273
- await writeFile42(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467385
+ await writeFile43(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467274
467386
  const parts = [];
467275
467387
  if (removed.clips > 0) parts.push(`${removed.clips} clips`);
467276
467388
  if (removed.tracks > 0) parts.push(`${removed.tracks} tracks`);
@@ -467293,16 +467405,16 @@ var projectSetTool = defineTool({
467293
467405
  category: "agent-only",
467294
467406
  cost: "free",
467295
467407
  surfaces: ["agent"],
467296
- description: "Update project settings (name, aspect ratio, frame rate)",
467408
+ description: "Update timeline settings (name, aspect ratio, frame rate)",
467297
467409
  schema: z11.object({
467298
- projectPath: z11.string().describe("Project file path"),
467410
+ projectPath: z11.string().describe("Timeline file or directory"),
467299
467411
  name: z11.string().optional().describe("New project name"),
467300
467412
  aspectRatio: z11.enum(["16:9", "9:16", "1:1", "4:5"]).optional().describe("New aspect ratio"),
467301
467413
  fps: z11.number().optional().describe("New frame rate")
467302
467414
  }),
467303
467415
  async execute(args, ctx) {
467304
467416
  try {
467305
- const filePath = await resolveProjectPath2(args.projectPath, ctx.workingDirectory);
467417
+ const filePath = await resolveTimelineFile(args.projectPath, ctx.workingDirectory);
467306
467418
  const content = await readFile32(filePath, "utf-8");
467307
467419
  const data = JSON.parse(content);
467308
467420
  const project = Project.fromJSON(data);
@@ -467319,7 +467431,7 @@ var projectSetTool = defineTool({
467319
467431
  project.setFrameRate(args.fps);
467320
467432
  updates.push(`Frame Rate: ${args.fps} fps`);
467321
467433
  }
467322
- await writeFile42(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467434
+ await writeFile43(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467323
467435
  return {
467324
467436
  success: true,
467325
467437
  data: { updates },
@@ -467340,11 +467452,11 @@ var projectOpenTool = defineTool({
467340
467452
  surfaces: ["agent"],
467341
467453
  description: "Open an existing project and set it as the current context",
467342
467454
  schema: z11.object({
467343
- projectPath: z11.string().describe("Project file path")
467455
+ projectPath: z11.string().describe("Timeline file or directory")
467344
467456
  }),
467345
467457
  async execute(args, ctx) {
467346
467458
  try {
467347
- const filePath = await resolveProjectPath2(args.projectPath, ctx.workingDirectory);
467459
+ const filePath = await resolveTimelineFile(args.projectPath, ctx.workingDirectory);
467348
467460
  const { project } = await loadProject(filePath, "");
467349
467461
  ctx.agent?.setProjectPath(filePath);
467350
467462
  const summary = project.getSummary();
@@ -467378,7 +467490,7 @@ var projectSaveTool = defineTool({
467378
467490
  surfaces: ["agent"],
467379
467491
  description: "Save the current project (uses ctx.agent.projectPath if no path given)",
467380
467492
  schema: z11.object({
467381
- projectPath: z11.string().optional().describe("Project file path (uses current agent project if omitted)")
467493
+ projectPath: z11.string().optional().describe("Timeline file or directory (uses current agent timeline if omitted)")
467382
467494
  }),
467383
467495
  async execute(args, ctx) {
467384
467496
  const path14 = args.projectPath ?? ctx.agent?.projectPath ?? null;
@@ -467389,7 +467501,7 @@ var projectSaveTool = defineTool({
467389
467501
  };
467390
467502
  }
467391
467503
  try {
467392
- const filePath = await resolveProjectPath2(path14, ctx.workingDirectory);
467504
+ const filePath = await resolveTimelineFile(path14, ctx.workingDirectory);
467393
467505
  const { project, absPath } = await loadProject(filePath, "");
467394
467506
  await saveProject(absPath, project);
467395
467507
  return {
@@ -467412,7 +467524,7 @@ var exportAudioTool = defineTool({
467412
467524
  surfaces: ["agent"],
467413
467525
  description: "Export audio track from a project. Not implemented \u2014 use export_video then strip audio with FFmpeg.",
467414
467526
  schema: z11.object({
467415
- project: z11.string().describe("Project file path"),
467527
+ project: z11.string().describe("Timeline file or directory"),
467416
467528
  output: z11.string().optional().describe("Output audio file path"),
467417
467529
  format: z11.enum(["mp3", "wav", "aac"]).optional().describe("Output format (mp3, wav, aac)")
467418
467530
  }),
@@ -467430,7 +467542,7 @@ var exportSubtitlesTool = defineTool({
467430
467542
  surfaces: ["agent"],
467431
467543
  description: "Export subtitles from transcription. Not implemented \u2014 use audio_transcribe to generate subtitles from audio.",
467432
467544
  schema: z11.object({
467433
- project: z11.string().describe("Project file path"),
467545
+ project: z11.string().describe("Timeline file or directory"),
467434
467546
  output: z11.string().optional().describe("Output subtitle file path"),
467435
467547
  format: z11.enum(["srt", "vtt"]).optional().describe("Subtitle format (srt, vtt)")
467436
467548
  }),
@@ -467673,7 +467785,7 @@ var mediaConcatTool = defineTool({
467673
467785
  } else {
467674
467786
  const tempList = resolve61(ctx.workingDirectory, `concat-list-${Date.now()}.txt`);
467675
467787
  const listContent = args.inputs.map((i) => `file '${resolve61(ctx.workingDirectory, i)}'`).join("\n");
467676
- await writeFile42(tempList, listContent, "utf-8");
467788
+ await writeFile43(tempList, listContent, "utf-8");
467677
467789
  try {
467678
467790
  await execSafe(
467679
467791
  "ffmpeg",
@@ -468310,7 +468422,7 @@ async function readResource(uri) {
468310
468422
  uri,
468311
468423
  mimeType: "application/json",
468312
468424
  text: JSON.stringify({
468313
- error: "No project loaded. Set VIBE_PROJECT_PATH environment variable or use project_create tool."
468425
+ error: "No timeline loaded. Set VIBE_PROJECT_PATH to timeline.json or use timeline_create."
468314
468426
  })
468315
468427
  }
468316
468428
  ]
@@ -468406,7 +468518,7 @@ var prompts = [
468406
468518
  },
468407
468519
  {
468408
468520
  name: "projectPath",
468409
- description: "Path to the project file",
468521
+ description: "Path to timeline.json or a legacy *.vibe.json file",
468410
468522
  required: false
468411
468523
  }
468412
468524
  ]
@@ -468524,7 +468636,7 @@ function getPrompt(name, args) {
468524
468636
  type: "text",
468525
468637
  text: `Help me edit a video with the following instruction: "${args.instruction}"
468526
468638
 
468527
- ${args.projectPath ? `Project file: ${args.projectPath}` : "No project file specified."}
468639
+ ${args.projectPath ? `Timeline file: ${args.projectPath}` : "No timeline file specified."}
468528
468640
 
468529
468641
  Please analyze the request and suggest the appropriate timeline tools to use. Consider:
468530
468642
  1. What clips need to be affected?