@vibeframe/mcp-server 0.79.3 → 0.80.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +6 -5
  2. package/dist/index.js +489 -368
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -14025,12 +14025,16 @@ function getSetupProviders() {
14025
14025
  key: k.configKey,
14026
14026
  name: k.label,
14027
14027
  env: k.envVar,
14028
- desc: k.setupDescription ?? ""
14028
+ desc: k.setupDescription ?? "",
14029
+ url: k.envExampleUrl
14029
14030
  }));
14030
14031
  }
14031
14032
  function getAllApiKeys() {
14032
14033
  return [...apiKeyRegistry.values()];
14033
14034
  }
14035
+ function getKeyFormat(configKey) {
14036
+ return apiKeyRegistry.get(configKey)?.keyFormat;
14037
+ }
14034
14038
  function getAllProviders() {
14035
14039
  return [...providerRegistry2.values()];
14036
14040
  }
@@ -14055,7 +14059,8 @@ var init_api_keys = __esm({
14055
14059
  showInSetup: true,
14056
14060
  setupDescription: "gpt-image-2 image gen ($, default since v0.56), Whisper transcribe, Agent",
14057
14061
  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"
14062
+ envExampleUrl: "https://platform.openai.com/api-keys",
14063
+ keyFormat: { prefix: /^sk-/, example: "sk-..." }
14059
14064
  });
14060
14065
  defineApiKey({
14061
14066
  configKey: "google",
@@ -14064,7 +14069,8 @@ var init_api_keys = __esm({
14064
14069
  showInSetup: true,
14065
14070
  setupDescription: "Gemini \u2014 image gen (free tier), video analysis ($), Veo ($$)",
14066
14071
  envExampleComment: "Google API Key (Gemini auto-edit suggestions, image gen, Veo video)",
14067
- envExampleUrl: "https://aistudio.google.com/apikey"
14072
+ envExampleUrl: "https://aistudio.google.com/apikey",
14073
+ keyFormat: { prefix: /^AIza/, example: "AIza..." }
14068
14074
  });
14069
14075
  defineApiKey({
14070
14076
  configKey: "anthropic",
@@ -14073,7 +14079,8 @@ var init_api_keys = __esm({
14073
14079
  showInSetup: true,
14074
14080
  setupDescription: "Claude \u2014 storyboard, color grade, reframe, Agent ($)",
14075
14081
  envExampleComment: "Anthropic API Key (Claude motion graphics & storyboarding)",
14076
- envExampleUrl: "https://console.anthropic.com/"
14082
+ envExampleUrl: "https://console.anthropic.com/",
14083
+ keyFormat: { prefix: /^sk-ant-/, example: "sk-ant-..." }
14077
14084
  });
14078
14085
  defineApiKey({
14079
14086
  configKey: "elevenlabs",
@@ -14082,7 +14089,8 @@ var init_api_keys = __esm({
14082
14089
  showInSetup: true,
14083
14090
  setupDescription: "TTS ($), SFX, music, voice clone, dubbing \u2014 skip to use local Kokoro",
14084
14091
  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"
14092
+ envExampleUrl: "https://elevenlabs.io/api",
14093
+ keyFormat: { prefix: /^sk_/, example: "sk_..." }
14086
14094
  });
14087
14095
  defineApiKey({
14088
14096
  configKey: "fal",
@@ -14100,7 +14108,8 @@ var init_api_keys = __esm({
14100
14108
  showInSetup: true,
14101
14109
  setupDescription: "Grok \u2014 video gen with audio ($$), image ($), Agent",
14102
14110
  envExampleComment: "xAI API Key (Grok video generation \u2014 fallback when no FAL_KEY)",
14103
- envExampleUrl: "https://console.x.ai/"
14111
+ envExampleUrl: "https://console.x.ai/",
14112
+ keyFormat: { prefix: /^xai-/, example: "xai-..." }
14104
14113
  });
14105
14114
  defineApiKey({
14106
14115
  configKey: "runway",
@@ -14109,7 +14118,8 @@ var init_api_keys = __esm({
14109
14118
  showInSetup: true,
14110
14119
  setupDescription: "Gen-4.5 video generation ($$)",
14111
14120
  envExampleComment: "Runway API Secret (Runway Gen-4.5 video generation)",
14112
- envExampleUrl: "https://app.runwayml.com/settings/api-keys"
14121
+ envExampleUrl: "https://app.runwayml.com/settings/api-keys",
14122
+ keyFormat: { prefix: /^key_/, example: "key_..." }
14113
14123
  });
14114
14124
  defineApiKey({
14115
14125
  configKey: "kling",
@@ -14119,7 +14129,8 @@ var init_api_keys = __esm({
14119
14129
  setupDescription: "v2.5/v3 video \u2014 std ($$) and pro ($$$) modes",
14120
14130
  envExampleComment: "Kling API Key (Kling video generation)",
14121
14131
  envExampleUrl: "https://platform.klingai.com/",
14122
- envExampleExtraLines: ["Format: ACCESS_KEY:SECRET_KEY"]
14132
+ envExampleExtraLines: ["Format: ACCESS_KEY:SECRET_KEY"],
14133
+ keyFormat: { prefix: /:/, example: "ACCESS_KEY:SECRET_KEY" }
14123
14134
  });
14124
14135
  defineApiKey({
14125
14136
  configKey: "replicate",
@@ -14128,7 +14139,8 @@ var init_api_keys = __esm({
14128
14139
  showInSetup: true,
14129
14140
  setupDescription: "MusicGen background music ($, max 30s)",
14130
14141
  envExampleComment: "Replicate API Token (music generation, video upscale, audio restoration)",
14131
- envExampleUrl: "https://replicate.com/account/api-tokens"
14142
+ envExampleUrl: "https://replicate.com/account/api-tokens",
14143
+ keyFormat: { prefix: /^r8_/, example: "r8_..." }
14132
14144
  });
14133
14145
  defineApiKey({
14134
14146
  configKey: "openrouter",
@@ -14137,7 +14149,8 @@ var init_api_keys = __esm({
14137
14149
  showInSetup: true,
14138
14150
  setupDescription: "300+ models via one key \u2014 Agent only (pay per model)",
14139
14151
  envExampleComment: "OpenRouter API Key (300+ AI models via unified API, used by `vibe agent`)",
14140
- envExampleUrl: "https://openrouter.ai/keys"
14152
+ envExampleUrl: "https://openrouter.ai/keys",
14153
+ keyFormat: { prefix: /^sk-or-/, example: "sk-or-..." }
14141
14154
  });
14142
14155
  defineApiKey({
14143
14156
  configKey: "imgbb",
@@ -24922,6 +24935,7 @@ __export(dist_exports, {
24922
24935
  getAllProviders: () => getAllProviders,
24923
24936
  getBestProviderForCapability: () => getBestProviderForCapability,
24924
24937
  getCommandKeyMap: () => getCommandKeyMap,
24938
+ getKeyFormat: () => getKeyFormat,
24925
24939
  getProviderEnvVars: () => getProviderEnvVars,
24926
24940
  getProvidersFor: () => getProvidersFor,
24927
24941
  getSetupProviders: () => getSetupProviders,
@@ -127672,7 +127686,7 @@ var require_typescript2 = __commonJS({
127672
127686
  walkUpParenthesizedTypesAndGetParentAndChild: () => walkUpParenthesizedTypesAndGetParentAndChild,
127673
127687
  whitespaceOrMapCommentRegExp: () => whitespaceOrMapCommentRegExp,
127674
127688
  writeCommentRange: () => writeCommentRange,
127675
- writeFile: () => writeFile43,
127689
+ writeFile: () => writeFile44,
127676
127690
  writeFileEnsuringDirectories: () => writeFileEnsuringDirectories,
127677
127691
  zipWith: () => zipWith
127678
127692
  });
@@ -146315,7 +146329,7 @@ ${lanes.join("\n")}
146315
146329
  sourceFilePath = isSourceFileInCommonSourceDirectory ? sourceFilePath.substring(commonSourceDirectory.length) : sourceFilePath;
146316
146330
  return combinePaths(newDirPath, sourceFilePath);
146317
146331
  }
146318
- function writeFile43(host, diagnostics, fileName, text, writeByteOrderMark, sourceFiles, data) {
146332
+ function writeFile44(host, diagnostics, fileName, text, writeByteOrderMark, sourceFiles, data) {
146319
146333
  host.writeFile(
146320
146334
  fileName,
146321
146335
  text,
@@ -147409,15 +147423,15 @@ ${lanes.join("\n")}
147409
147423
  if (isAccessExpression(name.parent) && isRightSideOfAccessExpression(name)) {
147410
147424
  return walkAccessExpression(name.parent);
147411
147425
  }
147412
- function walkAccessExpression(access7) {
147413
- if (access7.kind === 212) {
147414
- const res = action(access7.name);
147426
+ function walkAccessExpression(access8) {
147427
+ if (access8.kind === 212) {
147428
+ const res = action(access8.name);
147415
147429
  if (res !== void 0) {
147416
147430
  return res;
147417
147431
  }
147418
- } else if (access7.kind === 213) {
147419
- if (isIdentifier(access7.argumentExpression) || isStringLiteralLike(access7.argumentExpression)) {
147420
- const res = action(access7.argumentExpression);
147432
+ } else if (access8.kind === 213) {
147433
+ if (isIdentifier(access8.argumentExpression) || isStringLiteralLike(access8.argumentExpression)) {
147434
+ const res = action(access8.argumentExpression);
147421
147435
  if (res !== void 0) {
147422
147436
  return res;
147423
147437
  }
@@ -147425,11 +147439,11 @@ ${lanes.join("\n")}
147425
147439
  return void 0;
147426
147440
  }
147427
147441
  }
147428
- if (isAccessExpression(access7.expression)) {
147429
- return walkAccessExpression(access7.expression);
147442
+ if (isAccessExpression(access8.expression)) {
147443
+ return walkAccessExpression(access8.expression);
147430
147444
  }
147431
- if (isIdentifier(access7.expression)) {
147432
- return action(access7.expression);
147445
+ if (isIdentifier(access8.expression)) {
147446
+ return action(access8.expression);
147433
147447
  }
147434
147448
  return void 0;
147435
147449
  }
@@ -156682,11 +156696,11 @@ ${lanes.join("\n")}
156682
156696
  )
156683
156697
  );
156684
156698
  }
156685
- function createESDecorateClassElementAccessObject(name, access7) {
156699
+ function createESDecorateClassElementAccessObject(name, access8) {
156686
156700
  const properties = [];
156687
156701
  properties.push(createESDecorateClassElementAccessHasMethod(name));
156688
- if (access7.get) properties.push(createESDecorateClassElementAccessGetMethod(name));
156689
- if (access7.set) properties.push(createESDecorateClassElementAccessSetMethod(name));
156702
+ if (access8.get) properties.push(createESDecorateClassElementAccessGetMethod(name));
156703
+ if (access8.set) properties.push(createESDecorateClassElementAccessSetMethod(name));
156690
156704
  return factory2.createObjectLiteralExpression(properties);
156691
156705
  }
156692
156706
  function createESDecorateClassElementContextObject(contextIn) {
@@ -184203,7 +184217,7 @@ ${lanes.join("\n")}
184203
184217
  return false;
184204
184218
  }
184205
184219
  function isTypeSymbolAccessible(typeSymbol, enclosingDeclaration) {
184206
- const access7 = isSymbolAccessibleWorker(
184220
+ const access8 = isSymbolAccessibleWorker(
184207
184221
  typeSymbol,
184208
184222
  enclosingDeclaration,
184209
184223
  788968,
@@ -184212,10 +184226,10 @@ ${lanes.join("\n")}
184212
184226
  /*allowModules*/
184213
184227
  true
184214
184228
  );
184215
- return access7.accessibility === 0;
184229
+ return access8.accessibility === 0;
184216
184230
  }
184217
184231
  function isValueSymbolAccessible(typeSymbol, enclosingDeclaration) {
184218
- const access7 = isSymbolAccessibleWorker(
184232
+ const access8 = isSymbolAccessibleWorker(
184219
184233
  typeSymbol,
184220
184234
  enclosingDeclaration,
184221
184235
  111551,
@@ -184224,10 +184238,10 @@ ${lanes.join("\n")}
184224
184238
  /*allowModules*/
184225
184239
  true
184226
184240
  );
184227
- return access7.accessibility === 0;
184241
+ return access8.accessibility === 0;
184228
184242
  }
184229
184243
  function isSymbolAccessibleByFlags(typeSymbol, enclosingDeclaration, flags) {
184230
- const access7 = isSymbolAccessibleWorker(
184244
+ const access8 = isSymbolAccessibleWorker(
184231
184245
  typeSymbol,
184232
184246
  enclosingDeclaration,
184233
184247
  flags,
@@ -184236,7 +184250,7 @@ ${lanes.join("\n")}
184236
184250
  /*allowModules*/
184237
184251
  false
184238
184252
  );
184239
- return access7.accessibility === 0;
184253
+ return access8.accessibility === 0;
184240
184254
  }
184241
184255
  function isAnySymbolAccessible(symbols, enclosingDeclaration, initialSymbol, meaning, shouldComputeAliasesToMakeVisible, allowModules) {
184242
184256
  if (!length(symbols)) return;
@@ -204546,19 +204560,19 @@ ${lanes.join("\n")}
204546
204560
  }
204547
204561
  return false;
204548
204562
  }
204549
- function getAccessedPropertyName(access7) {
204550
- if (isPropertyAccessExpression(access7)) {
204551
- return access7.name.escapedText;
204563
+ function getAccessedPropertyName(access8) {
204564
+ if (isPropertyAccessExpression(access8)) {
204565
+ return access8.name.escapedText;
204552
204566
  }
204553
- if (isElementAccessExpression(access7)) {
204554
- return tryGetElementAccessExpressionName(access7);
204567
+ if (isElementAccessExpression(access8)) {
204568
+ return tryGetElementAccessExpressionName(access8);
204555
204569
  }
204556
- if (isBindingElement(access7)) {
204557
- const name = getDestructuringPropertyName(access7);
204570
+ if (isBindingElement(access8)) {
204571
+ const name = getDestructuringPropertyName(access8);
204558
204572
  return name ? escapeLeadingUnderscores(name) : void 0;
204559
204573
  }
204560
- if (isParameter(access7)) {
204561
- return "" + access7.parent.parameters.indexOf(access7);
204574
+ if (isParameter(access8)) {
204575
+ return "" + access8.parent.parameters.indexOf(access8);
204562
204576
  }
204563
204577
  return void 0;
204564
204578
  }
@@ -205773,9 +205787,9 @@ ${lanes.join("\n")}
205773
205787
  type = narrowTypeBySwitchOptionalChainContainment(type, flow.node, (t) => !(t.flags & 131072 || t.flags & 128 && t.value === "undefined"));
205774
205788
  }
205775
205789
  }
205776
- const access7 = getDiscriminantPropertyAccess(expr, type);
205777
- if (access7) {
205778
- type = narrowTypeBySwitchOnDiscriminantProperty(type, access7, flow.node);
205790
+ const access8 = getDiscriminantPropertyAccess(expr, type);
205791
+ if (access8) {
205792
+ type = narrowTypeBySwitchOnDiscriminantProperty(type, access8, flow.node);
205779
205793
  }
205780
205794
  }
205781
205795
  return createFlowType(type, isIncomplete(flowType));
@@ -205937,26 +205951,26 @@ ${lanes.join("\n")}
205937
205951
  }
205938
205952
  function getDiscriminantPropertyAccess(expr, computedType) {
205939
205953
  if (declaredType.flags & 1048576 || computedType.flags & 1048576) {
205940
- const access7 = getCandidateDiscriminantPropertyAccess(expr);
205941
- if (access7) {
205942
- const name = getAccessedPropertyName(access7);
205954
+ const access8 = getCandidateDiscriminantPropertyAccess(expr);
205955
+ if (access8) {
205956
+ const name = getAccessedPropertyName(access8);
205943
205957
  if (name) {
205944
205958
  const type = declaredType.flags & 1048576 && isTypeSubsetOf(computedType, declaredType) ? declaredType : computedType;
205945
205959
  if (isDiscriminantProperty(type, name)) {
205946
- return access7;
205960
+ return access8;
205947
205961
  }
205948
205962
  }
205949
205963
  }
205950
205964
  }
205951
205965
  return void 0;
205952
205966
  }
205953
- function narrowTypeByDiscriminant(type, access7, narrowType2) {
205954
- const propName = getAccessedPropertyName(access7);
205967
+ function narrowTypeByDiscriminant(type, access8, narrowType2) {
205968
+ const propName = getAccessedPropertyName(access8);
205955
205969
  if (propName === void 0) {
205956
205970
  return type;
205957
205971
  }
205958
- const optionalChain = isOptionalChain(access7);
205959
- const removeNullable = strictNullChecks && (optionalChain || isNonNullAccess(access7)) && maybeTypeOfKind(
205972
+ const optionalChain = isOptionalChain(access8);
205973
+ const removeNullable = strictNullChecks && (optionalChain || isNonNullAccess(access8)) && maybeTypeOfKind(
205960
205974
  type,
205961
205975
  98304
205962
205976
  /* Nullable */
@@ -205976,27 +205990,27 @@ ${lanes.join("\n")}
205976
205990
  return !(discriminantType.flags & 131072) && !(narrowedPropType.flags & 131072) && areTypesComparable(narrowedPropType, discriminantType);
205977
205991
  });
205978
205992
  }
205979
- function narrowTypeByDiscriminantProperty(type, access7, operator, value, assumeTrue) {
205993
+ function narrowTypeByDiscriminantProperty(type, access8, operator, value, assumeTrue) {
205980
205994
  if ((operator === 37 || operator === 38) && type.flags & 1048576) {
205981
205995
  const keyPropertyName = getKeyPropertyName(type);
205982
- if (keyPropertyName && keyPropertyName === getAccessedPropertyName(access7)) {
205996
+ if (keyPropertyName && keyPropertyName === getAccessedPropertyName(access8)) {
205983
205997
  const candidate = getConstituentTypeForKeyType(type, getTypeOfExpression(value));
205984
205998
  if (candidate) {
205985
205999
  return operator === (assumeTrue ? 37 : 38) ? candidate : isUnitType(getTypeOfPropertyOfType(candidate, keyPropertyName) || unknownType) ? removeType(type, candidate) : type;
205986
206000
  }
205987
206001
  }
205988
206002
  }
205989
- return narrowTypeByDiscriminant(type, access7, (t) => narrowTypeByEquality(t, operator, value, assumeTrue));
206003
+ return narrowTypeByDiscriminant(type, access8, (t) => narrowTypeByEquality(t, operator, value, assumeTrue));
205990
206004
  }
205991
- function narrowTypeBySwitchOnDiscriminantProperty(type, access7, data) {
205992
- if (data.clauseStart < data.clauseEnd && type.flags & 1048576 && getKeyPropertyName(type) === getAccessedPropertyName(access7)) {
206005
+ function narrowTypeBySwitchOnDiscriminantProperty(type, access8, data) {
206006
+ if (data.clauseStart < data.clauseEnd && type.flags & 1048576 && getKeyPropertyName(type) === getAccessedPropertyName(access8)) {
205993
206007
  const clauseTypes = getSwitchClauseTypes(data.switchStatement).slice(data.clauseStart, data.clauseEnd);
205994
206008
  const candidate = getUnionType(map3(clauseTypes, (t) => getConstituentTypeForKeyType(type, t) || unknownType));
205995
206009
  if (candidate !== unknownType) {
205996
206010
  return candidate;
205997
206011
  }
205998
206012
  }
205999
- return narrowTypeByDiscriminant(type, access7, (t) => narrowTypeBySwitchOnDiscriminant(t, data));
206013
+ return narrowTypeByDiscriminant(type, access8, (t) => narrowTypeBySwitchOnDiscriminant(t, data));
206000
206014
  }
206001
206015
  function narrowTypeByTruthiness(type, expr, assumeTrue) {
206002
206016
  if (isMatchingReference(reference, expr)) {
@@ -206013,9 +206027,9 @@ ${lanes.join("\n")}
206013
206027
  /* NEUndefinedOrNull */
206014
206028
  );
206015
206029
  }
206016
- const access7 = getDiscriminantPropertyAccess(expr, type);
206017
- if (access7) {
206018
- return narrowTypeByDiscriminant(type, access7, (t) => getTypeWithFacts(
206030
+ const access8 = getDiscriminantPropertyAccess(expr, type);
206031
+ if (access8) {
206032
+ return narrowTypeByDiscriminant(type, access8, (t) => getTypeWithFacts(
206019
206033
  t,
206020
206034
  assumeTrue ? 4194304 : 8388608
206021
206035
  /* Falsy */
@@ -206643,9 +206657,9 @@ ${lanes.join("\n")}
206643
206657
  /* NEUndefinedOrNull */
206644
206658
  );
206645
206659
  }
206646
- const access7 = getDiscriminantPropertyAccess(predicateArgument, type);
206647
- if (access7) {
206648
- return narrowTypeByDiscriminant(type, access7, (t) => getNarrowedType(
206660
+ const access8 = getDiscriminantPropertyAccess(predicateArgument, type);
206661
+ if (access8) {
206662
+ return narrowTypeByDiscriminant(type, access8, (t) => getNarrowedType(
206649
206663
  t,
206650
206664
  predicate.type,
206651
206665
  assumeTrue,
@@ -206705,9 +206719,9 @@ ${lanes.join("\n")}
206705
206719
  /* EQUndefinedOrNull */
206706
206720
  );
206707
206721
  }
206708
- const access7 = getDiscriminantPropertyAccess(expr, type);
206709
- if (access7) {
206710
- return narrowTypeByDiscriminant(type, access7, (t) => getTypeWithFacts(
206722
+ const access8 = getDiscriminantPropertyAccess(expr, type);
206723
+ if (access8) {
206724
+ return narrowTypeByDiscriminant(type, access8, (t) => getTypeWithFacts(
206711
206725
  t,
206712
206726
  assumePresent ? 2097152 : 262144
206713
206727
  /* EQUndefinedOrNull */
@@ -255066,7 +255080,7 @@ ${lanes.join("\n")}
255066
255080
  return;
255067
255081
  }
255068
255082
  const buildInfo = host.getBuildInfo() || { version };
255069
- writeFile43(
255083
+ writeFile44(
255070
255084
  host,
255071
255085
  emitterDiagnostics,
255072
255086
  buildInfoPath,
@@ -255278,7 +255292,7 @@ ${lanes.join("\n")}
255278
255292
  }
255279
255293
  if (sourceMapFilePath) {
255280
255294
  const sourceMap = sourceMapGenerator.toString();
255281
- writeFile43(
255295
+ writeFile44(
255282
255296
  host,
255283
255297
  emitterDiagnostics,
255284
255298
  sourceMapFilePath,
@@ -255293,7 +255307,7 @@ ${lanes.join("\n")}
255293
255307
  }
255294
255308
  const text = writer.getText();
255295
255309
  const data = { sourceMapUrlPos, diagnostics: transform2.diagnostics };
255296
- writeFile43(host, emitterDiagnostics, jsFilePath, text, !!compilerOptions.emitBOM, sourceFiles, data);
255310
+ writeFile44(host, emitterDiagnostics, jsFilePath, text, !!compilerOptions.emitBOM, sourceFiles, data);
255297
255311
  writer.clear();
255298
255312
  return !data.skippedDtsWrite;
255299
255313
  }
@@ -261956,9 +261970,9 @@ ${lanes.join("\n")}
261956
261970
  /*ignoreCase*/
261957
261971
  false
261958
261972
  )) {
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");
261973
+ const basename18 = getBaseFileName(a.fileName);
261974
+ if (basename18 === "lib.d.ts" || basename18 === "lib.es6.d.ts") return 0;
261975
+ const name = removeSuffix(removePrefix(basename18, "lib."), ".d.ts");
261962
261976
  const index = libs.indexOf(name);
261963
261977
  if (index !== -1) return index + 1;
261964
261978
  }
@@ -282050,13 +282064,13 @@ interface Symbol {
282050
282064
  for (const element of toConvert.elements) {
282051
282065
  const propertyName = element.propertyName || element.name;
282052
282066
  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));
282067
+ const access8 = propertyName.kind === 11 ? factory.createElementAccessExpression(factory.createIdentifier(namespaceImportName), factory.cloneNode(propertyName)) : factory.createPropertyAccessExpression(factory.createIdentifier(namespaceImportName), factory.cloneNode(propertyName));
282054
282068
  if (isShorthandPropertyAssignment(id.parent)) {
282055
- changes.replaceNode(sourceFile, id.parent, factory.createPropertyAssignment(id.text, access7));
282069
+ changes.replaceNode(sourceFile, id.parent, factory.createPropertyAssignment(id.text, access8));
282056
282070
  } else if (isExportSpecifier(id.parent)) {
282057
282071
  neededNamedImports.add(element);
282058
282072
  } else {
282059
- changes.replaceNode(sourceFile, id, access7);
282073
+ changes.replaceNode(sourceFile, id, access8);
282060
282074
  }
282061
282075
  });
282062
282076
  }
@@ -323175,7 +323189,7 @@ ${options.prefix}` : "\n" : options.prefix
323175
323189
  walkUpParenthesizedTypesAndGetParentAndChild: () => walkUpParenthesizedTypesAndGetParentAndChild,
323176
323190
  whitespaceOrMapCommentRegExp: () => whitespaceOrMapCommentRegExp,
323177
323191
  writeCommentRange: () => writeCommentRange,
323178
- writeFile: () => writeFile43,
323192
+ writeFile: () => writeFile44,
323179
323193
  writeFileEnsuringDirectories: () => writeFileEnsuringDirectories,
323180
323194
  zipWith: () => zipWith
323181
323195
  });
@@ -325704,8 +325718,8 @@ ${options.prefix}` : "\n" : options.prefix
325704
325718
  }
325705
325719
  };
325706
325720
  for (const file of files) {
325707
- const basename17 = getBaseFileName(file);
325708
- if (basename17 === "package.json" || basename17 === "bower.json") {
325721
+ const basename18 = getBaseFileName(file);
325722
+ if (basename18 === "package.json" || basename18 === "bower.json") {
325709
325723
  createProjectWatcher(
325710
325724
  file,
325711
325725
  "FileWatcher"
@@ -329377,8 +329391,8 @@ All files are: ${JSON.stringify(names)}`,
329377
329391
  var _a7;
329378
329392
  const fileOrDirectoryPath = removeIgnoredPath(this.toPath(fileOrDirectory));
329379
329393
  if (!fileOrDirectoryPath) return;
329380
- const basename17 = getBaseFileName(fileOrDirectoryPath);
329381
- if (((_a7 = result.affectedModuleSpecifierCacheProjects) == null ? void 0 : _a7.size) && (basename17 === "package.json" || basename17 === "node_modules")) {
329394
+ const basename18 = getBaseFileName(fileOrDirectoryPath);
329395
+ if (((_a7 = result.affectedModuleSpecifierCacheProjects) == null ? void 0 : _a7.size) && (basename18 === "package.json" || basename18 === "node_modules")) {
329382
329396
  result.affectedModuleSpecifierCacheProjects.forEach((project) => {
329383
329397
  var _a23;
329384
329398
  (_a23 = project.getModuleSpecifierCache()) == null ? void 0 : _a23.clear();
@@ -453215,16 +453229,31 @@ var init_project = __esm({
453215
453229
  }
453216
453230
  // ============ Serialization ============
453217
453231
  toJSON() {
453232
+ const state = this.getState();
453218
453233
  return {
453219
453234
  version: "1.0.0",
453220
- state: this.getState()
453235
+ state: {
453236
+ project: state.project,
453237
+ tracks: state.tracks,
453238
+ clips: state.clips,
453239
+ sources: state.sources,
453240
+ transitions: state.transitions
453241
+ }
453221
453242
  };
453222
453243
  }
453223
453244
  static fromJSON(data) {
453224
453245
  const project = new _Project();
453225
453246
  data.state.project.createdAt = new Date(data.state.project.createdAt);
453226
453247
  data.state.project.updatedAt = new Date(data.state.project.updatedAt);
453227
- project.state = data.state;
453248
+ project.state = {
453249
+ ...data.state,
453250
+ currentTime: 0,
453251
+ isPlaying: false,
453252
+ zoom: 50,
453253
+ scrollX: 0,
453254
+ selectedClipIds: [],
453255
+ selectedTrackId: null
453256
+ };
453228
453257
  return project;
453229
453258
  }
453230
453259
  setFilePath(path14) {
@@ -453259,10 +453288,45 @@ var init_engine = __esm({
453259
453288
  }
453260
453289
  });
453261
453290
 
453291
+ // ../cli/src/utils/project-resolver.ts
453292
+ import { access as access5, stat as stat3 } from "node:fs/promises";
453293
+ import { resolve as resolve28 } from "node:path";
453294
+ async function resolveTimelineFile(inputPath, cwd = process.cwd()) {
453295
+ const filePath = resolve28(cwd, inputPath);
453296
+ try {
453297
+ const stats = await stat3(filePath);
453298
+ if (stats.isDirectory()) {
453299
+ const canonical = resolve28(filePath, TIMELINE_FILENAME);
453300
+ try {
453301
+ await access5(canonical);
453302
+ return canonical;
453303
+ } catch {
453304
+ }
453305
+ const legacy = resolve28(filePath, LEGACY_TIMELINE_FILENAME);
453306
+ try {
453307
+ await access5(legacy);
453308
+ return legacy;
453309
+ } catch {
453310
+ return canonical;
453311
+ }
453312
+ }
453313
+ } catch {
453314
+ }
453315
+ return filePath;
453316
+ }
453317
+ var TIMELINE_FILENAME, LEGACY_TIMELINE_FILENAME;
453318
+ var init_project_resolver = __esm({
453319
+ "../cli/src/utils/project-resolver.ts"() {
453320
+ "use strict";
453321
+ TIMELINE_FILENAME = "timeline.json";
453322
+ LEGACY_TIMELINE_FILENAME = "project.vibe.json";
453323
+ }
453324
+ });
453325
+
453262
453326
  // ../cli/src/commands/_shared/execute-fill-gaps.ts
453263
453327
  import { existsSync as existsSync40 } from "node:fs";
453264
453328
  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";
453329
+ import { resolve as resolve29, dirname as dirname20 } from "node:path";
453266
453330
  function detectVideoGaps(videoClips, totalDuration) {
453267
453331
  const gaps = [];
453268
453332
  const sortedClips = [...videoClips].sort((a, b) => a.startTime - b.startTime);
@@ -453341,12 +453405,12 @@ async function executeFillGaps(options) {
453341
453405
  });
453342
453406
  const humanLines = [];
453343
453407
  try {
453344
- onProgress("Loading project...");
453345
- const filePath = resolve28(process.cwd(), options.projectPath);
453408
+ onProgress("Loading timeline...");
453409
+ const filePath = await resolveTimelineFile(options.projectPath);
453346
453410
  if (!existsSync40(filePath)) {
453347
453411
  return {
453348
453412
  success: false,
453349
- error: `Project file not found: ${filePath}`,
453413
+ error: `Timeline file not found: ${filePath}`,
453350
453414
  humanLines
453351
453415
  };
453352
453416
  }
@@ -453477,7 +453541,7 @@ async function executeFillGaps(options) {
453477
453541
  };
453478
453542
  }
453479
453543
  const projectDir = dirname20(filePath);
453480
- const footageDir = options.dir ? resolve28(process.cwd(), options.dir) : resolve28(projectDir, "footage");
453544
+ const footageDir = options.dir ? resolve29(process.cwd(), options.dir) : resolve29(projectDir, "footage");
453481
453545
  if (!existsSync40(footageDir)) {
453482
453546
  await mkdir14(footageDir, { recursive: true });
453483
453547
  }
@@ -453509,7 +453573,7 @@ async function executeFillGaps(options) {
453509
453573
  }
453510
453574
  onProgress("Extracting frame from preceding clip...");
453511
453575
  const frameOffset = clipBefore.sourceStartOffset + clipBefore.duration - 0.1;
453512
- const framePath = resolve28(footageDir, `frame-${gap.start.toFixed(2)}.png`);
453576
+ const framePath = resolve29(footageDir, `frame-${gap.start.toFixed(2)}.png`);
453513
453577
  try {
453514
453578
  await execSafe("ffmpeg", [
453515
453579
  "-i",
@@ -453570,7 +453634,7 @@ async function executeFillGaps(options) {
453570
453634
  continue;
453571
453635
  }
453572
453636
  const videoFileName = `gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}.mp4`;
453573
- const videoPath = resolve28(footageDir, videoFileName);
453637
+ const videoPath = resolve29(footageDir, videoFileName);
453574
453638
  onProgress("Downloading generated video...");
453575
453639
  const videoBuffer = await downloadVideo(finalResult.videoUrl);
453576
453640
  await writeFile16(videoPath, videoBuffer);
@@ -453582,7 +453646,7 @@ async function executeFillGaps(options) {
453582
453646
  const remainingNeeded = targetDuration - generatedDuration;
453583
453647
  const segmentDuration = remainingNeeded > 5 ? "10" : "5";
453584
453648
  onProgress(`Generating additional ${segmentDuration}s segment...`);
453585
- const lastFramePath = resolve28(
453649
+ const lastFramePath = resolve29(
453586
453650
  footageDir,
453587
453651
  `frame-extend-${gap.start.toFixed(2)}-${segmentIndex}.png`
453588
453652
  );
@@ -453638,17 +453702,17 @@ async function executeFillGaps(options) {
453638
453702
  );
453639
453703
  break;
453640
453704
  }
453641
- const segVideoPath = resolve28(
453705
+ const segVideoPath = resolve29(
453642
453706
  footageDir,
453643
453707
  `gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}-seg${segmentIndex}.mp4`
453644
453708
  );
453645
453709
  const segVideoBuffer = await downloadVideo(segFinalResult.videoUrl);
453646
453710
  await writeFile16(segVideoPath, segVideoBuffer);
453647
- const concatListPath = resolve28(footageDir, `concat-${gap.start.toFixed(2)}.txt`);
453711
+ const concatListPath = resolve29(footageDir, `concat-${gap.start.toFixed(2)}.txt`);
453648
453712
  const concatList = generatedVideos.map((v) => `file '${v}'`).join("\n") + `
453649
453713
  file '${segVideoPath}'`;
453650
453714
  await writeFile16(concatListPath, concatList);
453651
- const concatOutputPath = resolve28(
453715
+ const concatOutputPath = resolve29(
453652
453716
  footageDir,
453653
453717
  `gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}-merged.mp4`
453654
453718
  );
@@ -453704,7 +453768,7 @@ file '${segVideoPath}'`;
453704
453768
  humanLines.push("");
453705
453769
  let outputPath = filePath;
453706
453770
  if (generatedCount > 0) {
453707
- outputPath = options.output ? resolve28(process.cwd(), options.output) : filePath;
453771
+ outputPath = options.output ? resolve29(process.cwd(), options.output) : filePath;
453708
453772
  await writeFile16(outputPath, JSON.stringify(project.toJSON(), null, 2));
453709
453773
  humanLines.push(`\u2714 Filled ${generatedCount} gap(s) with AI-generated video`);
453710
453774
  humanLines.push(`Project saved: ${outputPath}`);
@@ -453734,13 +453798,14 @@ var init_execute_fill_gaps = __esm({
453734
453798
  init_engine();
453735
453799
  init_api_key();
453736
453800
  init_exec_safe();
453801
+ init_project_resolver();
453737
453802
  init_ai_helpers();
453738
453803
  }
453739
453804
  });
453740
453805
 
453741
453806
  // ../cli/src/commands/ai-fill-gaps.ts
453742
453807
  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) => {
453808
+ 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
453809
  try {
453745
453810
  if (options.output) {
453746
453811
  validateOutputPath(options.output);
@@ -453800,14 +453865,14 @@ __export(edit_cmd_exports, {
453800
453865
  executeSpeedRamp: () => executeSpeedRamp,
453801
453866
  executeUpscale: () => executeUpscale
453802
453867
  });
453803
- import { resolve as resolve29, dirname as dirname21 } from "node:path";
453868
+ import { resolve as resolve30, dirname as dirname21 } from "node:path";
453804
453869
  import { readFile as readFile17, writeFile as writeFile17, mkdir as mkdir15 } from "node:fs/promises";
453805
453870
  async function executeGrade(options) {
453806
453871
  const { videoPath, style, preset, output: output3, analyzeOnly, apiKey } = options;
453807
453872
  try {
453808
453873
  if (!style && !preset) return { success: false, error: "Either style or preset is required" };
453809
453874
  if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
453810
- const absPath = resolve29(process.cwd(), videoPath);
453875
+ const absPath = resolve30(process.cwd(), videoPath);
453811
453876
  let gradeResult;
453812
453877
  if (preset) {
453813
453878
  const claude = new ClaudeProvider();
@@ -453822,7 +453887,7 @@ async function executeGrade(options) {
453822
453887
  if (analyzeOnly) {
453823
453888
  return { success: true, style: preset || style, description: gradeResult.description, ffmpegFilter: gradeResult.ffmpegFilter };
453824
453889
  }
453825
- const outputPath = output3 ? resolve29(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, "-graded$1");
453890
+ const outputPath = output3 ? resolve30(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, "-graded$1");
453826
453891
  await execSafe("ffmpeg", ["-i", absPath, "-vf", gradeResult.ffmpegFilter, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
453827
453892
  return { success: true, outputPath, style: preset || style, description: gradeResult.description, ffmpegFilter: gradeResult.ffmpegFilter };
453828
453893
  } catch (error) {
@@ -453837,7 +453902,7 @@ async function executeSpeedRamp(options) {
453837
453902
  const claudeKey = apiKey || process.env.ANTHROPIC_API_KEY;
453838
453903
  if (!openaiKey) return { success: false, error: "OPENAI_API_KEY required for Whisper transcription" };
453839
453904
  if (!claudeKey) return { success: false, error: "ANTHROPIC_API_KEY required for Claude analysis" };
453840
- const absPath = resolve29(process.cwd(), videoPath);
453905
+ const absPath = resolve30(process.cwd(), videoPath);
453841
453906
  const tempAudio = absPath.replace(/(\.[^.]+)$/, "-temp-audio.mp3");
453842
453907
  await execSafe("ffmpeg", ["-i", absPath, "-vn", "-acodec", "libmp3lame", "-q:a", "2", tempAudio, "-y"]);
453843
453908
  const whisper = new WhisperProvider();
@@ -453862,7 +453927,7 @@ async function executeSpeedRamp(options) {
453862
453927
  if (speedResult.keyframes.length < 2) {
453863
453928
  return { success: false, error: "Not enough keyframes for speed ramping" };
453864
453929
  }
453865
- const outputPath = output3 ? resolve29(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
453930
+ const outputPath = output3 ? resolve30(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
453866
453931
  const setpts = `setpts=${(1 / avgSpeed).toFixed(3)}*PTS`;
453867
453932
  const atempo = avgSpeed >= 0.5 && avgSpeed <= 2 ? `atempo=${avgSpeed.toFixed(3)}` : "";
453868
453933
  if (atempo) {
@@ -453879,7 +453944,7 @@ async function executeReframe(options) {
453879
453944
  const { videoPath, aspect = "9:16", output: output3, analyzeOnly } = options;
453880
453945
  try {
453881
453946
  if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
453882
- const absPath = resolve29(process.cwd(), videoPath);
453947
+ const absPath = resolve30(process.cwd(), videoPath);
453883
453948
  const { stdout: probeOut } = await execSafe("ffprobe", [
453884
453949
  "-v",
453885
453950
  "error",
@@ -453914,7 +453979,7 @@ async function executeReframe(options) {
453914
453979
  keyframeCount: 1
453915
453980
  };
453916
453981
  }
453917
- const outputPath = output3 ? resolve29(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, `-${aspect.replace(":", "x")}$1`);
453982
+ const outputPath = output3 ? resolve30(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, `-${aspect.replace(":", "x")}$1`);
453918
453983
  await execSafe("ffmpeg", ["-i", absPath, "-vf", `crop=${cropWidth}:${cropHeight}:${cropX}:${cropY}`, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
453919
453984
  return { success: true, outputPath, sourceAspect: `${sourceWidth}:${sourceHeight}`, targetAspect: aspect };
453920
453985
  } catch (error) {
@@ -453926,7 +453991,7 @@ async function executeInterpolate(options) {
453926
453991
  try {
453927
453992
  if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
453928
453993
  if (![2, 4, 8].includes(factor)) return { success: false, error: "Factor must be 2, 4, or 8" };
453929
- const absPath = resolve29(process.cwd(), videoPath);
453994
+ const absPath = resolve30(process.cwd(), videoPath);
453930
453995
  const { stdout: fpsOut } = await execSafe("ffprobe", [
453931
453996
  "-v",
453932
453997
  "error",
@@ -453942,7 +454007,7 @@ async function executeInterpolate(options) {
453942
454007
  const originalFps = num / (den || 1);
453943
454008
  const targetFps = options.fps || originalFps * factor;
453944
454009
  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`);
454010
+ const outputPath = output3 ? resolve30(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, `-slow${factor}x$1`);
453946
454011
  await execSafe("ffmpeg", ["-i", absPath, "-filter:v", `minterpolate='${mi}:fps=${targetFps}',setpts=${factor}*PTS`, "-an", outputPath, "-y"], { timeout: 6e5 });
453947
454012
  return { success: true, outputPath, originalFps, targetFps, factor };
453948
454013
  } catch (error) {
@@ -453953,7 +454018,7 @@ async function executeUpscale(options) {
453953
454018
  const { videoPath, output: output3, scale = 2, quality = "quality" } = options;
453954
454019
  try {
453955
454020
  if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
453956
- const absPath = resolve29(process.cwd(), videoPath);
454021
+ const absPath = resolve30(process.cwd(), videoPath);
453957
454022
  const { stdout: probeOut } = await execSafe("ffprobe", [
453958
454023
  "-v",
453959
454024
  "error",
@@ -453969,7 +454034,7 @@ async function executeUpscale(options) {
453969
454034
  const targetW = w * scale;
453970
454035
  const targetH = h * scale;
453971
454036
  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`);
454037
+ const outputPath = output3 ? resolve30(process.cwd(), output3) : absPath.replace(/(\.[^.]+)$/, `-${scale}x$1`);
453973
454038
  await execSafe("ffmpeg", ["-i", absPath, "-vf", scaleFilter, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
453974
454039
  return { success: true, outputPath, originalRes: `${w}x${h}`, targetRes: `${targetW}x${targetH}` };
453975
454040
  } catch (error) {
@@ -454041,7 +454106,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454041
454106
  dryRun: true,
454042
454107
  data: {
454043
454108
  params: {
454044
- videoPath: resolve29(process.cwd(), videoPath),
454109
+ videoPath: resolve30(process.cwd(), videoPath),
454045
454110
  style: options.style || options.preset,
454046
454111
  analyzeOnly: options.analyzeOnly || false
454047
454112
  }
@@ -454068,8 +454133,8 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454068
454133
  }
454069
454134
  spinner2.succeed(source_default.green("Color grade analyzed"));
454070
454135
  if (isJsonMode()) {
454071
- const absPath2 = resolve29(process.cwd(), videoPath);
454072
- const gradeOutputPath = options.output ? resolve29(process.cwd(), options.output) : absPath2.replace(/(\.[^.]+)$/, "-graded$1");
454136
+ const absPath2 = resolve30(process.cwd(), videoPath);
454137
+ const gradeOutputPath = options.output ? resolve30(process.cwd(), options.output) : absPath2.replace(/(\.[^.]+)$/, "-graded$1");
454073
454138
  outputSuccess({
454074
454139
  command: "edit grade",
454075
454140
  startedAt,
@@ -454095,8 +454160,8 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454095
454160
  console.log(source_default.dim("Use without --analyze-only to apply the grade."));
454096
454161
  return;
454097
454162
  }
454098
- const absPath = resolve29(process.cwd(), videoPath);
454099
- const outputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-graded$1");
454163
+ const absPath = resolve30(process.cwd(), videoPath);
454164
+ const outputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-graded$1");
454100
454165
  spinner2.start("Applying color grade...");
454101
454166
  await execSafe("ffmpeg", ["-i", absPath, "-vf", gradeResult.ffmpegFilter, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
454102
454167
  spinner2.succeed(source_default.green("Color grade applied"));
@@ -454126,7 +454191,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454126
454191
  dryRun: true,
454127
454192
  data: {
454128
454193
  params: {
454129
- videoPath: resolve29(process.cwd(), videoPath),
454194
+ videoPath: resolve30(process.cwd(), videoPath),
454130
454195
  texts: options.text,
454131
454196
  style: options.style,
454132
454197
  fontSize: options.fontSize ? parseInt(options.fontSize) : void 0,
@@ -454139,8 +454204,8 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454139
454204
  });
454140
454205
  return;
454141
454206
  }
454142
- const absPath = resolve29(process.cwd(), videoPath);
454143
- const outputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-overlay$1");
454207
+ const absPath = resolve30(process.cwd(), videoPath);
454208
+ const outputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-overlay$1");
454144
454209
  const spinner2 = ora("Applying text overlays...").start();
454145
454210
  const result = await applyTextOverlays({
454146
454211
  videoPath: absPath,
@@ -454198,7 +454263,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454198
454263
  dryRun: true,
454199
454264
  data: {
454200
454265
  params: {
454201
- videoPath: resolve29(process.cwd(), videoPath),
454266
+ videoPath: resolve30(process.cwd(), videoPath),
454202
454267
  style: options.style,
454203
454268
  minSpeed: parseFloat(options.minSpeed),
454204
454269
  maxSpeed: parseFloat(options.maxSpeed),
@@ -454210,7 +454275,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454210
454275
  }
454211
454276
  const openaiApiKey = await requireApiKey("OPENAI_API_KEY", "OpenAI");
454212
454277
  const claudeApiKey = await requireApiKey("ANTHROPIC_API_KEY", "Anthropic", options.apiKey);
454213
- const absPath = resolve29(process.cwd(), videoPath);
454278
+ const absPath = resolve30(process.cwd(), videoPath);
454214
454279
  const spinner2 = ora("Extracting audio...").start();
454215
454280
  const { stdout: speedRampProbe } = await execSafe("ffprobe", [
454216
454281
  "-v",
@@ -454255,7 +454320,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454255
454320
  spinner2.succeed(source_default.green(`Found ${speedResult.keyframes.length} speed keyframes`));
454256
454321
  if (isJsonMode()) {
454257
454322
  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");
454323
+ const speedRampOutputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
454259
454324
  outputSuccess({
454260
454325
  command: "edit speed-ramp",
454261
454326
  startedAt,
@@ -454284,7 +454349,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454284
454349
  return;
454285
454350
  }
454286
454351
  spinner2.start("Applying speed ramps...");
454287
- const outputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
454352
+ const outputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
454288
454353
  const avgSpeed = speedResult.keyframes.reduce((sum, kf) => sum + kf.speed, 0) / speedResult.keyframes.length;
454289
454354
  const setpts = `setpts=${(1 / avgSpeed).toFixed(3)}*PTS`;
454290
454355
  const atempo = avgSpeed >= 0.5 && avgSpeed <= 2 ? `atempo=${avgSpeed.toFixed(3)}` : "";
@@ -454318,7 +454383,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454318
454383
  dryRun: true,
454319
454384
  data: {
454320
454385
  params: {
454321
- videoPath: resolve29(process.cwd(), videoPath),
454386
+ videoPath: resolve30(process.cwd(), videoPath),
454322
454387
  aspect: options.aspect,
454323
454388
  focus: options.focus,
454324
454389
  analyzeOnly: options.analyzeOnly || false
@@ -454327,7 +454392,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454327
454392
  });
454328
454393
  return;
454329
454394
  }
454330
- const absPath = resolve29(process.cwd(), videoPath);
454395
+ const absPath = resolve30(process.cwd(), videoPath);
454331
454396
  const spinner2 = ora("Analyzing video...").start();
454332
454397
  const { stdout: probeOut } = await execSafe("ffprobe", [
454333
454398
  "-v",
@@ -454389,7 +454454,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454389
454454
  }
454390
454455
  spinner2.succeed(source_default.green(`Analyzed ${cropKeyframes.length} keyframes`));
454391
454456
  if (isJsonMode()) {
454392
- const reframeOutputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
454457
+ const reframeOutputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
454393
454458
  outputSuccess({
454394
454459
  command: "edit reframe",
454395
454460
  startedAt,
@@ -454424,7 +454489,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454424
454489
  }
454425
454490
  console.log();
454426
454491
  if (options.keyframes) {
454427
- const keyframesPath = resolve29(process.cwd(), options.keyframes);
454492
+ const keyframesPath = resolve30(process.cwd(), options.keyframes);
454428
454493
  await writeFile17(keyframesPath, JSON.stringify(cropKeyframes, null, 2));
454429
454494
  console.log(source_default.green(`Keyframes saved to: ${keyframesPath}`));
454430
454495
  }
@@ -454436,7 +454501,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454436
454501
  const avgCropY = Math.round(cropKeyframes.reduce((sum, kf) => sum + kf.cropY, 0) / cropKeyframes.length);
454437
454502
  const cropWidth = cropKeyframes[0]?.cropWidth || sourceWidth;
454438
454503
  const cropHeight = cropKeyframes[0]?.cropHeight || sourceHeight;
454439
- const outputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
454504
+ const outputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
454440
454505
  spinner2.start("Applying reframe...");
454441
454506
  await execSafe("ffmpeg", ["-i", absPath, "-vf", `crop=${cropWidth}:${cropHeight}:${avgCropX}:${avgCropY}`, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
454442
454507
  spinner2.succeed(source_default.green("Reframe applied"));
@@ -454472,7 +454537,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454472
454537
  dryRun: true,
454473
454538
  data: {
454474
454539
  params: {
454475
- imagePaths: imagePaths.map((p) => resolve29(process.cwd(), p)),
454540
+ imagePaths: imagePaths.map((p) => resolve30(process.cwd(), p)),
454476
454541
  prompt: prompt3,
454477
454542
  provider,
454478
454543
  model: options.model,
@@ -454493,7 +454558,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454493
454558
  const spinner2 = ora(`Reading ${imagePaths.length} image(s)...`).start();
454494
454559
  const imageBuffers = [];
454495
454560
  for (const imagePath of imagePaths) {
454496
- const absPath = resolve29(process.cwd(), imagePath);
454561
+ const absPath = resolve30(process.cwd(), imagePath);
454497
454562
  const buffer = await readFile17(absPath);
454498
454563
  imageBuffers.push(buffer);
454499
454564
  }
@@ -454542,7 +454607,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454542
454607
  }
454543
454608
  spinner2.succeed(source_default.green("Image edited"));
454544
454609
  const img = result.images[0];
454545
- const outputPath = resolve29(process.cwd(), options.output);
454610
+ const outputPath = resolve30(process.cwd(), options.output);
454546
454611
  const saveImage = async () => {
454547
454612
  await mkdir15(dirname21(outputPath), { recursive: true });
454548
454613
  if (img.base64) {
@@ -454584,7 +454649,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454584
454649
  if (options.output) {
454585
454650
  validateOutputPath(options.output);
454586
454651
  }
454587
- const absPath = resolve29(process.cwd(), videoPath);
454652
+ const absPath = resolve30(process.cwd(), videoPath);
454588
454653
  const factor = parseInt(options.factor);
454589
454654
  if (![2, 4, 8].includes(factor)) {
454590
454655
  exitWithError(usageError("Factor must be 2, 4, or 8"));
@@ -454605,7 +454670,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454605
454670
  });
454606
454671
  return;
454607
454672
  }
454608
- const outputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-slow${factor}x$1`);
454673
+ const outputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-slow${factor}x$1`);
454609
454674
  const spinner2 = ora(`Creating ${factor}x slow motion...`).start();
454610
454675
  try {
454611
454676
  const { stdout: fpsOut } = await execSafe("ffprobe", [
@@ -454666,7 +454731,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454666
454731
  if (options.output) {
454667
454732
  validateOutputPath(options.output);
454668
454733
  }
454669
- const absPath = resolve29(process.cwd(), videoPath);
454734
+ const absPath = resolve30(process.cwd(), videoPath);
454670
454735
  const scale = parseInt(options.scale);
454671
454736
  if (scale !== 2 && scale !== 4) {
454672
454737
  exitWithError(usageError("Scale must be 2 or 4"));
@@ -454688,7 +454753,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454688
454753
  return;
454689
454754
  }
454690
454755
  if (options.ffmpeg) {
454691
- const outputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-upscaled-${scale}x$1`);
454756
+ const outputPath = options.output ? resolve30(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-upscaled-${scale}x$1`);
454692
454757
  const spinner3 = ora(`Upscaling video with FFmpeg (${scale}x)...`).start();
454693
454758
  try {
454694
454759
  const { stdout: probeOut } = await execSafe("ffprobe", [
@@ -454749,7 +454814,7 @@ __export(ai_image_exports, {
454749
454814
  executeImageGenerate: () => executeImageGenerate,
454750
454815
  executeThumbnailBestFrame: () => executeThumbnailBestFrame
454751
454816
  });
454752
- import { resolve as resolve31, dirname as dirname24 } from "node:path";
454817
+ import { resolve as resolve33, dirname as dirname24 } from "node:path";
454753
454818
  import { readFile as readFile18, writeFile as writeFile19, mkdir as mkdir17 } from "node:fs/promises";
454754
454819
  import { existsSync as existsSync42 } from "node:fs";
454755
454820
  async function executeImageGenerate(options) {
@@ -454792,7 +454857,7 @@ async function executeImageGenerate(options) {
454792
454857
  } else {
454793
454858
  return { success: false, error: "No image data available" };
454794
454859
  }
454795
- outputPath = resolve31(process.cwd(), output3);
454860
+ outputPath = resolve33(process.cwd(), output3);
454796
454861
  await mkdir17(dirname24(outputPath), { recursive: true });
454797
454862
  await writeFile19(outputPath, buffer);
454798
454863
  }
@@ -454827,7 +454892,7 @@ async function executeImageGenerate(options) {
454827
454892
  if (output3 && result.images.length > 0) {
454828
454893
  const img = result.images[0];
454829
454894
  if (img.base64) {
454830
- outputPath = resolve31(process.cwd(), output3);
454895
+ outputPath = resolve33(process.cwd(), output3);
454831
454896
  await mkdir17(dirname24(outputPath), { recursive: true });
454832
454897
  await writeFile19(outputPath, Buffer.from(img.base64, "base64"));
454833
454898
  }
@@ -454863,7 +454928,7 @@ async function executeImageGenerate(options) {
454863
454928
  } else {
454864
454929
  return { success: false, error: "No image data available" };
454865
454930
  }
454866
- outputPath = resolve31(process.cwd(), output3);
454931
+ outputPath = resolve33(process.cwd(), output3);
454867
454932
  await mkdir17(dirname24(outputPath), { recursive: true });
454868
454933
  await writeFile19(outputPath, buffer);
454869
454934
  }
@@ -454894,7 +454959,7 @@ async function executeGeminiEdit(options) {
454894
454959
  if (!key2) return { success: false, error: "GOOGLE_API_KEY required" };
454895
454960
  const imageBuffers = [];
454896
454961
  for (const imagePath of imagePaths) {
454897
- const absPath = resolve31(process.cwd(), imagePath);
454962
+ const absPath = resolve33(process.cwd(), imagePath);
454898
454963
  if (!existsSync42(absPath)) {
454899
454964
  return { success: false, error: `Image not found: ${absPath}` };
454900
454965
  }
@@ -454922,7 +454987,7 @@ async function executeGeminiEdit(options) {
454922
454987
  const img = result.images[0];
454923
454988
  let outputPath;
454924
454989
  if (img.base64) {
454925
- outputPath = resolve31(process.cwd(), output3);
454990
+ outputPath = resolve33(process.cwd(), output3);
454926
454991
  await mkdir17(dirname24(outputPath), { recursive: true });
454927
454992
  await writeFile19(outputPath, Buffer.from(img.base64, "base64"));
454928
454993
  }
@@ -455015,7 +455080,7 @@ __export(ai_analyze_exports, {
455015
455080
  registerAnalyzeCommands: () => registerAnalyzeCommands
455016
455081
  });
455017
455082
  import { readFile as readFile19 } from "node:fs/promises";
455018
- import { extname as extname8, resolve as resolve33 } from "node:path";
455083
+ import { extname as extname8, resolve as resolve34 } from "node:path";
455019
455084
  import { existsSync as existsSync43 } from "node:fs";
455020
455085
  async function executeGeminiVideo(options) {
455021
455086
  try {
@@ -455034,7 +455099,7 @@ async function executeGeminiVideo(options) {
455034
455099
  if (isYouTube) {
455035
455100
  videoData = options.source;
455036
455101
  } else {
455037
- const absPath = resolve33(process.cwd(), options.source);
455102
+ const absPath = resolve34(process.cwd(), options.source);
455038
455103
  if (!existsSync43(absPath)) {
455039
455104
  return { success: false, error: `File not found: ${absPath}` };
455040
455105
  }
@@ -455107,7 +455172,7 @@ async function executeAnalyze(options) {
455107
455172
  }
455108
455173
  imageBuffer = Buffer.from(await response.arrayBuffer());
455109
455174
  } else {
455110
- const absPath = resolve33(process.cwd(), source3);
455175
+ const absPath = resolve34(process.cwd(), source3);
455111
455176
  if (!existsSync43(absPath)) {
455112
455177
  return { success: false, error: `File not found: ${absPath}` };
455113
455178
  }
@@ -455142,7 +455207,7 @@ async function executeAnalyze(options) {
455142
455207
  }
455143
455208
  videoData = Buffer.from(await response.arrayBuffer());
455144
455209
  } else {
455145
- const absPath = resolve33(process.cwd(), source3);
455210
+ const absPath = resolve34(process.cwd(), source3);
455146
455211
  if (!existsSync43(absPath)) {
455147
455212
  return { success: false, error: `File not found: ${absPath}` };
455148
455213
  }
@@ -455281,7 +455346,7 @@ __export(ai_review_exports, {
455281
455346
  registerReviewCommand: () => registerReviewCommand
455282
455347
  });
455283
455348
  import { readFile as readFile20, rename as rename4 } from "node:fs/promises";
455284
- import { resolve as resolve34 } from "node:path";
455349
+ import { resolve as resolve35 } from "node:path";
455285
455350
  import { existsSync as existsSync44 } from "node:fs";
455286
455351
  function parseReviewFeedback(response) {
455287
455352
  let cleaned = response.trim();
@@ -455306,7 +455371,7 @@ function parseReviewFeedback(response) {
455306
455371
  }
455307
455372
  async function executeReview(options) {
455308
455373
  const { videoPath, storyboardPath, autoApply = false, verify = false, model = "flash" } = options;
455309
- const absVideoPath = resolve34(process.cwd(), videoPath);
455374
+ const absVideoPath = resolve35(process.cwd(), videoPath);
455310
455375
  if (!existsSync44(absVideoPath)) {
455311
455376
  return { success: false, error: `Video not found: ${absVideoPath}` };
455312
455377
  }
@@ -455316,7 +455381,7 @@ async function executeReview(options) {
455316
455381
  }
455317
455382
  let storyboardContext = "";
455318
455383
  if (storyboardPath) {
455319
- const absStoryboardPath = resolve34(process.cwd(), storyboardPath);
455384
+ const absStoryboardPath = resolve35(process.cwd(), storyboardPath);
455320
455385
  if (existsSync44(absStoryboardPath)) {
455321
455386
  const content = await readFile20(absStoryboardPath, "utf-8");
455322
455387
  storyboardContext = `
@@ -455372,7 +455437,7 @@ Score each category 1-10. For fixable issues, provide an FFmpeg filter in autoFi
455372
455437
  };
455373
455438
  if (autoApply && feedback.autoFixable.length > 0) {
455374
455439
  let currentInput = absVideoPath;
455375
- const outputBase = options.outputPath ? resolve34(process.cwd(), options.outputPath) : absVideoPath.replace(/(\.[^.]+)$/, "-reviewed$1");
455440
+ const outputBase = options.outputPath ? resolve35(process.cwd(), options.outputPath) : absVideoPath.replace(/(\.[^.]+)$/, "-reviewed$1");
455376
455441
  for (const fix of feedback.autoFixable) {
455377
455442
  if (fix.type === "color_grade" && fix.ffmpegFilter) {
455378
455443
  try {
@@ -455526,7 +455591,7 @@ __export(ai_motion_exports, {
455526
455591
  executeMotion: () => executeMotion,
455527
455592
  registerMotionCommand: () => registerMotionCommand
455528
455593
  });
455529
- import { resolve as resolve36 } from "node:path";
455594
+ import { resolve as resolve37 } from "node:path";
455530
455595
  import { existsSync as existsSync45 } from "node:fs";
455531
455596
  import { readFile as readFile22, writeFile as writeFile21 } from "node:fs/promises";
455532
455597
  async function executeMotion(options) {
@@ -455551,7 +455616,7 @@ async function executeMotion(options) {
455551
455616
  if (!geminiApiKey) {
455552
455617
  return { success: false, error: "GOOGLE_API_KEY required for image analysis (--image). Run 'vibe setup' or set GOOGLE_API_KEY in .env" };
455553
455618
  }
455554
- const imagePath = resolve36(process.cwd(), options.image);
455619
+ const imagePath = resolve37(process.cwd(), options.image);
455555
455620
  const imageBuffer = await readFile22(imagePath);
455556
455621
  const gemini = new GeminiProvider();
455557
455622
  await gemini.initialize({ apiKey: geminiApiKey });
@@ -455574,7 +455639,7 @@ Use this image analysis to inform the color palette, typography placement, and o
455574
455639
  }
455575
455640
  let result;
455576
455641
  if (options.fromTsx) {
455577
- const tsxPath = resolve36(process.cwd(), options.fromTsx);
455642
+ const tsxPath = resolve37(process.cwd(), options.fromTsx);
455578
455643
  if (!existsSync45(tsxPath)) {
455579
455644
  return { success: false, error: `TSX file not found: ${tsxPath}` };
455580
455645
  }
@@ -455628,7 +455693,7 @@ Use this image analysis to inform the color palette, typography placement, and o
455628
455693
  }
455629
455694
  const { component } = result;
455630
455695
  const defaultOutput = options.video || options.image ? "motion-output.mp4" : options.render ? "motion.webm" : "motion.tsx";
455631
- const outputPath = resolve36(process.cwd(), options.output || defaultOutput);
455696
+ const outputPath = resolve37(process.cwd(), options.output || defaultOutput);
455632
455697
  const codePath = outputPath.replace(/\.\w+$/, ".tsx");
455633
455698
  await writeFile21(codePath, component.code, "utf-8");
455634
455699
  const shouldRender = options.render || !!options.video || !!options.image;
@@ -455647,8 +455712,8 @@ Use this image analysis to inform the color palette, typography placement, and o
455647
455712
  if (notInstalled) {
455648
455713
  return { success: false, codePath, componentName: component.name, error: notInstalled };
455649
455714
  }
455650
- const baseVideo = options.video ? resolve36(process.cwd(), options.video) : void 0;
455651
- const baseImage = options.image ? resolve36(process.cwd(), options.image) : void 0;
455715
+ const baseVideo = options.video ? resolve37(process.cwd(), options.video) : void 0;
455716
+ const baseImage = options.image ? resolve37(process.cwd(), options.image) : void 0;
455652
455717
  if (baseVideo) {
455653
455718
  const videoFileName = "source_video.mp4";
455654
455719
  const wrapped = wrapComponentWithVideo2(component.code, component.name, videoFileName);
@@ -455833,7 +455898,7 @@ var init_ai_motion = __esm({
455833
455898
  });
455834
455899
 
455835
455900
  // ../cli/src/commands/generate/sound-effect.ts
455836
- import { resolve as resolve37 } from "node:path";
455901
+ import { resolve as resolve38 } from "node:path";
455837
455902
  import { writeFile as writeFile22 } from "node:fs/promises";
455838
455903
  async function executeSoundEffect(options) {
455839
455904
  try {
@@ -455855,7 +455920,7 @@ async function executeSoundEffect(options) {
455855
455920
  error: result.error || "Sound effect generation failed"
455856
455921
  };
455857
455922
  }
455858
- const outputPath = resolve37(
455923
+ const outputPath = resolve38(
455859
455924
  process.cwd(),
455860
455925
  options.output || "sound-effect.mp3"
455861
455926
  );
@@ -455910,7 +455975,7 @@ function registerSoundEffectCommand(parent) {
455910
455975
  apiError(result.error || "Sound effect generation failed", true)
455911
455976
  );
455912
455977
  }
455913
- const outputPath = resolve37(process.cwd(), options.output);
455978
+ const outputPath = resolve38(process.cwd(), options.output);
455914
455979
  await writeFile22(outputPath, result.audioBuffer);
455915
455980
  spinner2.succeed(source_default.green("Sound effect generated"));
455916
455981
  if (isJsonMode()) {
@@ -456095,7 +456160,7 @@ var init_video_cancel = __esm({
456095
456160
  });
456096
456161
 
456097
456162
  // ../cli/src/commands/generate/background.ts
456098
- import { resolve as resolve38, dirname as dirname25 } from "node:path";
456163
+ import { resolve as resolve39, dirname as dirname25 } from "node:path";
456099
456164
  import { writeFile as writeFile23, mkdir as mkdir18 } from "node:fs/promises";
456100
456165
  async function executeBackground(options) {
456101
456166
  try {
@@ -456120,7 +456185,7 @@ async function executeBackground(options) {
456120
456185
  } else {
456121
456186
  return { success: false, error: "Provider returned no image data" };
456122
456187
  }
456123
- outputPath = resolve38(process.cwd(), options.output);
456188
+ outputPath = resolve39(process.cwd(), options.output);
456124
456189
  await mkdir18(dirname25(outputPath), { recursive: true });
456125
456190
  await writeFile23(outputPath, buffer);
456126
456191
  }
@@ -456182,7 +456247,7 @@ function registerBackgroundCommand(parent) {
456182
456247
  } else {
456183
456248
  throw new Error("No image data available");
456184
456249
  }
456185
- outputPath = resolve38(process.cwd(), options.output);
456250
+ outputPath = resolve39(process.cwd(), options.output);
456186
456251
  await mkdir18(dirname25(outputPath), { recursive: true });
456187
456252
  await writeFile23(outputPath, buffer);
456188
456253
  }
@@ -456213,7 +456278,7 @@ function registerBackgroundCommand(parent) {
456213
456278
  } else {
456214
456279
  throw new Error("No image data available");
456215
456280
  }
456216
- const outputPath = resolve38(process.cwd(), options.output);
456281
+ const outputPath = resolve39(process.cwd(), options.output);
456217
456282
  await mkdir18(dirname25(outputPath), { recursive: true });
456218
456283
  await writeFile23(outputPath, buffer);
456219
456284
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
@@ -456255,7 +456320,7 @@ var init_sanitize = __esm({
456255
456320
  });
456256
456321
 
456257
456322
  // ../cli/src/commands/generate/storyboard.ts
456258
- import { resolve as resolve39 } from "node:path";
456323
+ import { resolve as resolve40 } from "node:path";
456259
456324
  import { readFile as readFile23, writeFile as writeFile24 } from "node:fs/promises";
456260
456325
  async function executeStoryboard(options) {
456261
456326
  const { content, duration, creativity = "low", output: output3, apiKey } = options;
@@ -456274,7 +456339,7 @@ async function executeStoryboard(options) {
456274
456339
  }
456275
456340
  let outputPath;
456276
456341
  if (output3) {
456277
- outputPath = resolve39(process.cwd(), output3);
456342
+ outputPath = resolve40(process.cwd(), output3);
456278
456343
  await writeFile24(outputPath, JSON.stringify(segments, null, 2), "utf-8");
456279
456344
  }
456280
456345
  return { success: true, segments, segmentCount: segments.length, outputPath };
@@ -456299,7 +456364,7 @@ function registerStoryboardCommand(parent) {
456299
456364
  }
456300
456365
  let textContent2 = content;
456301
456366
  if (options.file) {
456302
- const filePath = resolve39(process.cwd(), content);
456367
+ const filePath = resolve40(process.cwd(), content);
456303
456368
  textContent2 = await readFile23(filePath, "utf-8");
456304
456369
  }
456305
456370
  if (options.dryRun) {
@@ -456341,7 +456406,7 @@ function registerStoryboardCommand(parent) {
456341
456406
  if (seg.visuals) seg.visuals = sanitizeLLMResponse(seg.visuals);
456342
456407
  }
456343
456408
  if (options.output) {
456344
- const outputPath = resolve39(process.cwd(), options.output);
456409
+ const outputPath = resolve40(process.cwd(), options.output);
456345
456410
  await writeFile24(outputPath, JSON.stringify(segments, null, 2), "utf-8");
456346
456411
  if (isJsonMode()) {
456347
456412
  outputSuccess({
@@ -456384,7 +456449,7 @@ function registerStoryboardCommand(parent) {
456384
456449
  }
456385
456450
  console.log();
456386
456451
  if (options.output) {
456387
- console.log(source_default.green(`Saved to: ${resolve39(process.cwd(), options.output)}`));
456452
+ console.log(source_default.green(`Saved to: ${resolve40(process.cwd(), options.output)}`));
456388
456453
  }
456389
456454
  } catch (error) {
456390
456455
  const msg = error instanceof Error ? error.message : String(error);
@@ -456406,6 +456471,13 @@ var init_storyboard = __esm({
456406
456471
  }
456407
456472
  });
456408
456473
 
456474
+ // ../cli/src/utils/open-url.ts
456475
+ var init_open_url = __esm({
456476
+ "../cli/src/utils/open-url.ts"() {
456477
+ "use strict";
456478
+ }
456479
+ });
456480
+
456409
456481
  // ../cli/src/utils/tty.ts
456410
456482
  import { createInterface as createInterface4 } from "node:readline";
456411
456483
  import { ReadStream } from "node:tty";
@@ -456457,12 +456529,13 @@ var ttyStream;
456457
456529
  var init_tty = __esm({
456458
456530
  "../cli/src/utils/tty.ts"() {
456459
456531
  "use strict";
456532
+ init_open_url();
456460
456533
  ttyStream = null;
456461
456534
  }
456462
456535
  });
456463
456536
 
456464
456537
  // ../cli/src/commands/generate/speech.ts
456465
- import { resolve as resolve40 } from "node:path";
456538
+ import { resolve as resolve41 } from "node:path";
456466
456539
  import { writeFile as writeFile25 } from "node:fs/promises";
456467
456540
  async function executeSpeech(options) {
456468
456541
  try {
@@ -456480,7 +456553,7 @@ async function executeSpeech(options) {
456480
456553
  if (!result.success || !result.audioBuffer) {
456481
456554
  return { success: false, error: result.error || "TTS generation failed" };
456482
456555
  }
456483
- const outputPath = resolve40(process.cwd(), options.output || "output.mp3");
456556
+ const outputPath = resolve41(process.cwd(), options.output || "output.mp3");
456484
456557
  await writeFile25(outputPath, result.audioBuffer);
456485
456558
  return { success: true, outputPath, characterCount: result.characterCount };
456486
456559
  } catch (error) {
@@ -456556,7 +456629,7 @@ function registerSpeechCommand(parent) {
456556
456629
  spinner2.fail(result.error || "TTS generation failed");
456557
456630
  exitWithError(apiError(result.error || "TTS generation failed", true));
456558
456631
  }
456559
- const outputPath = resolve40(process.cwd(), options.output);
456632
+ const outputPath = resolve41(process.cwd(), options.output);
456560
456633
  await writeFile25(outputPath, result.audioBuffer);
456561
456634
  spinner2.succeed(source_default.green("Speech generated"));
456562
456635
  if (options.fitDuration && options.fitDuration > 0) {
@@ -456642,7 +456715,7 @@ var init_speech = __esm({
456642
456715
  });
456643
456716
 
456644
456717
  // ../cli/src/commands/generate/music.ts
456645
- import { resolve as resolve41 } from "node:path";
456718
+ import { resolve as resolve43 } from "node:path";
456646
456719
  import { writeFile as writeFile26 } from "node:fs/promises";
456647
456720
  import { existsSync as existsSync46 } from "node:fs";
456648
456721
  async function executeMusic(options) {
@@ -456665,7 +456738,7 @@ async function executeMusic(options) {
456665
456738
  if (!result2.success || !result2.audioBuffer) {
456666
456739
  return { success: false, error: result2.error || "Music generation failed" };
456667
456740
  }
456668
- const outputPath2 = resolve41(process.cwd(), options.output || "music.mp3");
456741
+ const outputPath2 = resolve43(process.cwd(), options.output || "music.mp3");
456669
456742
  await writeFile26(outputPath2, result2.audioBuffer);
456670
456743
  return { success: true, outputPath: outputPath2, provider: "elevenlabs", duration: duration2 };
456671
456744
  }
@@ -456690,7 +456763,7 @@ async function executeMusic(options) {
456690
456763
  if (!response.ok)
456691
456764
  return { success: false, error: "Failed to download generated audio" };
456692
456765
  const audioBuffer = Buffer.from(await response.arrayBuffer());
456693
- const outputPath = resolve41(process.cwd(), options.output || "music.mp3");
456766
+ const outputPath = resolve43(process.cwd(), options.output || "music.mp3");
456694
456767
  await writeFile26(outputPath, audioBuffer);
456695
456768
  return { success: true, outputPath, provider: "replicate", duration };
456696
456769
  } catch (error) {
@@ -456754,7 +456827,7 @@ function registerMusicCommand(parent) {
456754
456827
  spinner2.fail(result.error || "Music generation failed");
456755
456828
  exitWithError(apiError(result.error || "Music generation failed", true));
456756
456829
  }
456757
- const outputPath = resolve41(process.cwd(), options.output);
456830
+ const outputPath = resolve43(process.cwd(), options.output);
456758
456831
  await writeFile26(outputPath, result.audioBuffer);
456759
456832
  spinner2.succeed(source_default.green("Music generated successfully"));
456760
456833
  if (isJsonMode()) {
@@ -456787,7 +456860,7 @@ function registerMusicCommand(parent) {
456787
456860
  const duration = Math.max(1, Math.min(30, parseFloat(options.duration)));
456788
456861
  if (options.melody) {
456789
456862
  spinner2.text = "Uploading melody reference...";
456790
- const absPath = resolve41(process.cwd(), options.melody);
456863
+ const absPath = resolve43(process.cwd(), options.melody);
456791
456864
  if (!existsSync46(absPath)) {
456792
456865
  spinner2.fail(`Melody file not found: ${options.melody}`);
456793
456866
  exitWithError(notFoundError(options.melody));
@@ -456829,7 +456902,7 @@ function registerMusicCommand(parent) {
456829
456902
  exitWithError(apiError("Failed to download generated audio", true));
456830
456903
  }
456831
456904
  const audioBuffer = Buffer.from(await response.arrayBuffer());
456832
- const outputPath = resolve41(process.cwd(), options.output);
456905
+ const outputPath = resolve43(process.cwd(), options.output);
456833
456906
  await writeFile26(outputPath, audioBuffer);
456834
456907
  spinner2.succeed(source_default.green("Music generated successfully"));
456835
456908
  if (isJsonMode()) {
@@ -456871,7 +456944,7 @@ var init_music = __esm({
456871
456944
  });
456872
456945
 
456873
456946
  // ../cli/src/commands/generate/thumbnail.ts
456874
- import { resolve as resolve43, dirname as dirname26, basename as basename10, extname as extname9 } from "node:path";
456947
+ import { resolve as resolve44, dirname as dirname26, basename as basename10, extname as extname9 } from "node:path";
456875
456948
  import { existsSync as existsSync47 } from "node:fs";
456876
456949
  import { writeFile as writeFile27, mkdir as mkdir19 } from "node:fs/promises";
456877
456950
  function registerThumbnailCommand(parent) {
@@ -456883,7 +456956,7 @@ function registerThumbnailCommand(parent) {
456883
456956
  validateOutputPath(options.output);
456884
456957
  }
456885
456958
  if (options.bestFrame) {
456886
- const absVideoPath = resolve43(process.cwd(), options.bestFrame);
456959
+ const absVideoPath = resolve44(process.cwd(), options.bestFrame);
456887
456960
  if (!existsSync47(absVideoPath)) {
456888
456961
  exitWithError(notFoundError(absVideoPath));
456889
456962
  }
@@ -456901,7 +456974,7 @@ function registerThumbnailCommand(parent) {
456901
456974
  const spinner3 = ora("Analyzing video for best frame...").start();
456902
456975
  const result2 = await executeThumbnailBestFrame({
456903
456976
  videoPath: absVideoPath,
456904
- outputPath: resolve43(process.cwd(), outputPath),
456977
+ outputPath: resolve44(process.cwd(), outputPath),
456905
456978
  prompt: options.prompt,
456906
456979
  model: options.model,
456907
456980
  apiKey: apiKey2
@@ -456963,7 +457036,7 @@ function registerThumbnailCommand(parent) {
456963
457036
  } else {
456964
457037
  throw new Error("No image data available");
456965
457038
  }
456966
- outputPath = resolve43(process.cwd(), options.output);
457039
+ outputPath = resolve44(process.cwd(), options.output);
456967
457040
  await mkdir19(dirname26(outputPath), { recursive: true });
456968
457041
  await writeFile27(outputPath, buffer);
456969
457042
  }
@@ -456994,7 +457067,7 @@ function registerThumbnailCommand(parent) {
456994
457067
  } else {
456995
457068
  throw new Error("No image data available");
456996
457069
  }
456997
- const outputPath = resolve43(process.cwd(), options.output);
457070
+ const outputPath = resolve44(process.cwd(), options.output);
456998
457071
  await mkdir19(dirname26(outputPath), { recursive: true });
456999
457072
  await writeFile27(outputPath, buffer);
457000
457073
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
@@ -457023,7 +457096,7 @@ var init_thumbnail = __esm({
457023
457096
  });
457024
457097
 
457025
457098
  // ../cli/src/commands/generate/video-status.ts
457026
- import { resolve as resolve44 } from "node:path";
457099
+ import { resolve as resolve45 } from "node:path";
457027
457100
  import { writeFile as writeFile28 } from "node:fs/promises";
457028
457101
  function getStatusColor(status) {
457029
457102
  switch (status) {
@@ -457062,7 +457135,7 @@ function registerVideoStatusCommand(parent) {
457062
457135
  let outputPath;
457063
457136
  if (options.output && result.videoUrl) {
457064
457137
  const buffer = await downloadVideo(result.videoUrl);
457065
- outputPath = resolve44(process.cwd(), options.output);
457138
+ outputPath = resolve45(process.cwd(), options.output);
457066
457139
  await writeFile28(outputPath, buffer);
457067
457140
  }
457068
457141
  outputSuccess({
@@ -457096,7 +457169,7 @@ function registerVideoStatusCommand(parent) {
457096
457169
  const downloadSpinner = ora("Downloading video...").start();
457097
457170
  try {
457098
457171
  const buffer = await downloadVideo(result.videoUrl);
457099
- const outputPath = resolve44(process.cwd(), options.output);
457172
+ const outputPath = resolve45(process.cwd(), options.output);
457100
457173
  await writeFile28(outputPath, buffer);
457101
457174
  downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
457102
457175
  } catch (err) {
@@ -457130,7 +457203,7 @@ function registerVideoStatusCommand(parent) {
457130
457203
  let outputPath;
457131
457204
  if (options.output && result.videoUrl) {
457132
457205
  const buffer = await downloadVideo(result.videoUrl, apiKey);
457133
- outputPath = resolve44(process.cwd(), options.output);
457206
+ outputPath = resolve45(process.cwd(), options.output);
457134
457207
  await writeFile28(outputPath, buffer);
457135
457208
  }
457136
457209
  outputSuccess({
@@ -457168,7 +457241,7 @@ function registerVideoStatusCommand(parent) {
457168
457241
  const downloadSpinner = ora("Downloading video...").start();
457169
457242
  try {
457170
457243
  const buffer = await downloadVideo(result.videoUrl, apiKey);
457171
- const outputPath = resolve44(process.cwd(), options.output);
457244
+ const outputPath = resolve45(process.cwd(), options.output);
457172
457245
  await writeFile28(outputPath, buffer);
457173
457246
  downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
457174
457247
  } catch (err) {
@@ -457197,7 +457270,7 @@ function registerVideoStatusCommand(parent) {
457197
457270
  let outputPath;
457198
457271
  if (options.output && result.videoUrl) {
457199
457272
  const buffer = await downloadVideo(result.videoUrl, apiKey);
457200
- outputPath = resolve44(process.cwd(), options.output);
457273
+ outputPath = resolve45(process.cwd(), options.output);
457201
457274
  await writeFile28(outputPath, buffer);
457202
457275
  }
457203
457276
  outputSuccess({
@@ -457236,7 +457309,7 @@ function registerVideoStatusCommand(parent) {
457236
457309
  const downloadSpinner = ora("Downloading video...").start();
457237
457310
  try {
457238
457311
  const buffer = await downloadVideo(result.videoUrl, apiKey);
457239
- const outputPath = resolve44(process.cwd(), options.output);
457312
+ const outputPath = resolve45(process.cwd(), options.output);
457240
457313
  await writeFile28(outputPath, buffer);
457241
457314
  downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
457242
457315
  } catch (err) {
@@ -457271,7 +457344,7 @@ var init_video_status = __esm({
457271
457344
  });
457272
457345
 
457273
457346
  // ../cli/src/commands/generate/video-extend.ts
457274
- import { resolve as resolve45 } from "node:path";
457347
+ import { resolve as resolve46 } from "node:path";
457275
457348
  import { writeFile as writeFile29 } from "node:fs/promises";
457276
457349
  function registerVideoExtendCommand(parent) {
457277
457350
  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 +457421,7 @@ function registerVideoExtendCommand(parent) {
457348
457421
  let outputPath;
457349
457422
  if (options.output && finalResult.videoUrl) {
457350
457423
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
457351
- outputPath = resolve45(process.cwd(), options.output);
457424
+ outputPath = resolve46(process.cwd(), options.output);
457352
457425
  await writeFile29(outputPath, buffer);
457353
457426
  }
457354
457427
  outputSuccess({
@@ -457376,7 +457449,7 @@ function registerVideoExtendCommand(parent) {
457376
457449
  const downloadSpinner = ora("Downloading video...").start();
457377
457450
  try {
457378
457451
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
457379
- const outputPath = resolve45(process.cwd(), options.output);
457452
+ const outputPath = resolve46(process.cwd(), options.output);
457380
457453
  await writeFile29(outputPath, buffer);
457381
457454
  downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
457382
457455
  } catch (err) {
@@ -457437,7 +457510,7 @@ function registerVideoExtendCommand(parent) {
457437
457510
  let outputPath;
457438
457511
  if (options.output && finalResult.videoUrl) {
457439
457512
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
457440
- outputPath = resolve45(process.cwd(), options.output);
457513
+ outputPath = resolve46(process.cwd(), options.output);
457441
457514
  await writeFile29(outputPath, buffer);
457442
457515
  }
457443
457516
  outputSuccess({
@@ -457462,7 +457535,7 @@ function registerVideoExtendCommand(parent) {
457462
457535
  const downloadSpinner = ora("Downloading video...").start();
457463
457536
  try {
457464
457537
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
457465
- const outputPath = resolve45(process.cwd(), options.output);
457538
+ const outputPath = resolve46(process.cwd(), options.output);
457466
457539
  await writeFile29(outputPath, buffer);
457467
457540
  downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
457468
457541
  } catch (err) {
@@ -457553,7 +457626,7 @@ var init_openai_image2 = __esm({
457553
457626
  });
457554
457627
 
457555
457628
  // ../cli/src/commands/generate/image.ts
457556
- import { resolve as resolve46, dirname as dirname27 } from "node:path";
457629
+ import { resolve as resolve47, dirname as dirname27 } from "node:path";
457557
457630
  import { fileURLToPath as fileURLToPath4 } from "node:url";
457558
457631
  import { writeFile as writeFile30, mkdir as mkdir20 } from "node:fs/promises";
457559
457632
  function registerImageCommand(parent) {
@@ -457669,7 +457742,7 @@ Examples:
457669
457742
  source_default.green(`Generated ${result.images.length} image(s) with OpenAI ${modelLabel}`)
457670
457743
  );
457671
457744
  if (isJsonMode()) {
457672
- const outputPath = options.output ? resolve46(process.cwd(), options.output) : void 0;
457745
+ const outputPath = options.output ? resolve47(process.cwd(), options.output) : void 0;
457673
457746
  if (outputPath && result.images.length > 0) {
457674
457747
  const img = result.images[0];
457675
457748
  let buffer;
@@ -457727,7 +457800,7 @@ Examples:
457727
457800
  } else {
457728
457801
  throw new Error("No image data available");
457729
457802
  }
457730
- const outputPath = resolve46(process.cwd(), options.output);
457803
+ const outputPath = resolve47(process.cwd(), options.output);
457731
457804
  await mkdir20(dirname27(outputPath), { recursive: true });
457732
457805
  await writeFile30(outputPath, buffer);
457733
457806
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
@@ -457799,7 +457872,7 @@ Examples:
457799
457872
  source_default.green(`Generated ${result.images.length} image(s) with Gemini (${usedLabel})`)
457800
457873
  );
457801
457874
  if (isJsonMode()) {
457802
- const outputPath = options.output ? resolve46(process.cwd(), options.output) : void 0;
457875
+ const outputPath = options.output ? resolve47(process.cwd(), options.output) : void 0;
457803
457876
  if (outputPath && result.images.length > 0) {
457804
457877
  const img = result.images[0];
457805
457878
  const buffer = Buffer.from(img.base64, "base64");
@@ -457835,7 +457908,7 @@ Examples:
457835
457908
  try {
457836
457909
  const img = result.images[0];
457837
457910
  const buffer = Buffer.from(img.base64, "base64");
457838
- const outputPath = resolve46(process.cwd(), options.output);
457911
+ const outputPath = resolve47(process.cwd(), options.output);
457839
457912
  await mkdir20(dirname27(outputPath), { recursive: true });
457840
457913
  await writeFile30(outputPath, buffer);
457841
457914
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
@@ -457886,7 +457959,7 @@ Examples:
457886
457959
  source_default.green(`Generated ${result.images.length} image(s) with xAI Grok`)
457887
457960
  );
457888
457961
  if (isJsonMode()) {
457889
- const outputPath = options.output ? resolve46(process.cwd(), options.output) : void 0;
457962
+ const outputPath = options.output ? resolve47(process.cwd(), options.output) : void 0;
457890
457963
  if (outputPath && result.images.length > 0) {
457891
457964
  const img = result.images[0];
457892
457965
  let buffer;
@@ -457938,7 +458011,7 @@ Examples:
457938
458011
  } else {
457939
458012
  throw new Error("No image data available");
457940
458013
  }
457941
- const outputPath = resolve46(process.cwd(), options.output);
458014
+ const outputPath = resolve47(process.cwd(), options.output);
457942
458015
  await mkdir20(dirname27(outputPath), { recursive: true });
457943
458016
  await writeFile30(outputPath, buffer);
457944
458017
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
@@ -457952,7 +458025,7 @@ Examples:
457952
458025
  const { spawn: spawn10 } = await import("child_process");
457953
458026
  const __filename2 = fileURLToPath4(import.meta.url);
457954
458027
  const __dirname3 = dirname27(__filename2);
457955
- const scriptPath = resolve46(
458028
+ const scriptPath = resolve47(
457956
458029
  __dirname3,
457957
458030
  "../../../../.claude/skills/runway-video/scripts/image.py"
457958
458031
  );
@@ -457960,7 +458033,7 @@ Examples:
457960
458033
  spinner2.fail("Output path required for Runway");
457961
458034
  exitWithError(usageError("Output path required for Runway. Use -o option."));
457962
458035
  }
457963
- const outputPath = resolve46(process.cwd(), options.output);
458036
+ const outputPath = resolve47(process.cwd(), options.output);
457964
458037
  const args = [scriptPath, prompt3, "-o", outputPath, "-r", options.ratio || "16:9"];
457965
458038
  spinner2.text = "Generating image with Runway (gemini_2.5_flash)...";
457966
458039
  await new Promise((resolvePromise, reject) => {
@@ -458970,7 +459043,7 @@ var init_dist3 = __esm({
458970
459043
 
458971
459044
  // ../cli/src/commands/_shared/video-utils.ts
458972
459045
  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";
459046
+ import { resolve as resolve48, basename as basename11 } from "node:path";
458974
459047
  function sleep(ms) {
458975
459048
  return new Promise((resolve64) => setTimeout(resolve64, ms));
458976
459049
  }
@@ -459004,7 +459077,7 @@ async function extendVideoToTarget(videoPath, targetDuration, outputDir, sceneLa
459004
459077
  const actualDuration = await getVideoDuration(videoPath);
459005
459078
  if (actualDuration >= targetDuration - 0.1) return;
459006
459079
  const ratio = targetDuration / actualDuration;
459007
- const extendedPath = resolve47(outputDir, `${basename11(videoPath, ".mp4")}-extended.mp4`);
459080
+ const extendedPath = resolve48(outputDir, `${basename11(videoPath, ".mp4")}-extended.mp4`);
459008
459081
  if (ratio > 1.4 && options?.kling && options?.videoId) {
459009
459082
  try {
459010
459083
  options.onProgress?.(`${sceneLabel}: Extending via Kling API...`);
@@ -459020,17 +459093,17 @@ async function extendVideoToTarget(videoPath, targetDuration, outputDir, sceneLa
459020
459093
  6e5
459021
459094
  );
459022
459095
  if (waitResult.status === "completed" && waitResult.videoUrl) {
459023
- const extendedVideoPath = resolve47(
459096
+ const extendedVideoPath = resolve48(
459024
459097
  outputDir,
459025
459098
  `${basename11(videoPath, ".mp4")}-kling-ext.mp4`
459026
459099
  );
459027
459100
  const buffer = await downloadVideo(waitResult.videoUrl);
459028
459101
  await writeFile31(extendedVideoPath, buffer);
459029
- const concatPath = resolve47(
459102
+ const concatPath = resolve48(
459030
459103
  outputDir,
459031
459104
  `${basename11(videoPath, ".mp4")}-concat.mp4`
459032
459105
  );
459033
- const listPath = resolve47(
459106
+ const listPath = resolve48(
459034
459107
  outputDir,
459035
459108
  `${basename11(videoPath, ".mp4")}-concat.txt`
459036
459109
  );
@@ -459272,7 +459345,7 @@ var init_video_providers = __esm({
459272
459345
 
459273
459346
  // ../cli/src/commands/ai-script-pipeline.ts
459274
459347
  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";
459348
+ import { resolve as resolve49, extname as extname10 } from "node:path";
459276
459349
  import { existsSync as existsSync48 } from "node:fs";
459277
459350
  async function executeRegenerateScene(options) {
459278
459351
  const result = {
@@ -459281,12 +459354,12 @@ async function executeRegenerateScene(options) {
459281
459354
  failedScenes: []
459282
459355
  };
459283
459356
  try {
459284
- const outputDir = resolve48(process.cwd(), options.projectDir);
459357
+ const outputDir = resolve49(process.cwd(), options.projectDir);
459285
459358
  if (!existsSync48(outputDir)) {
459286
459359
  return { ...result, error: `Project directory not found: ${outputDir}` };
459287
459360
  }
459288
- const yamlPath = resolve48(outputDir, "storyboard.yaml");
459289
- const jsonPath = resolve48(outputDir, "storyboard.json");
459361
+ const yamlPath = resolve49(outputDir, "storyboard.yaml");
459362
+ const jsonPath = resolve49(outputDir, "storyboard.json");
459290
459363
  const storyboardPath = existsSync48(yamlPath) ? yamlPath : existsSync48(jsonPath) ? jsonPath : null;
459291
459364
  if (!storyboardPath) {
459292
459365
  return { ...result, error: `Storyboard not found in: ${outputDir} (expected storyboard.yaml or storyboard.json)` };
@@ -459346,9 +459419,9 @@ async function executeRegenerateScene(options) {
459346
459419
  let storyboardMutated = false;
459347
459420
  for (const sceneNum of options.scenes) {
459348
459421
  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`);
459422
+ const narrationPath = resolve49(outputDir, `narration-${sceneNum}.mp3`);
459423
+ const imagePath = resolve49(outputDir, `scene-${sceneNum}.png`);
459424
+ const videoPath = resolve49(outputDir, `scene-${sceneNum}.mp4`);
459352
459425
  let sceneFailed = false;
459353
459426
  if (regenerateNarration && elevenlabsApiKey) {
459354
459427
  options.onProgress?.(`Scene ${sceneNum}: regenerating narration...`);
@@ -459379,14 +459452,14 @@ IMPORTANT - Character appearance must match exactly: ${characterDesc}`;
459379
459452
  let referenceImageBuffer;
459380
459453
  const refSceneNum = options.referenceScene;
459381
459454
  if (refSceneNum && refSceneNum >= 1 && refSceneNum <= segments.length && refSceneNum !== sceneNum) {
459382
- const refImagePath = resolve48(outputDir, `scene-${refSceneNum}.png`);
459455
+ const refImagePath = resolve49(outputDir, `scene-${refSceneNum}.png`);
459383
459456
  if (existsSync48(refImagePath)) {
459384
459457
  referenceImageBuffer = await readFile24(refImagePath);
459385
459458
  }
459386
459459
  } else if (!refSceneNum) {
459387
459460
  for (let i = 1; i <= segments.length; i++) {
459388
459461
  if (i !== sceneNum) {
459389
- const otherImagePath = resolve48(outputDir, `scene-${i}.png`);
459462
+ const otherImagePath = resolve49(outputDir, `scene-${i}.png`);
459390
459463
  if (existsSync48(otherImagePath)) {
459391
459464
  referenceImageBuffer = await readFile24(otherImagePath);
459392
459465
  break;
@@ -459509,7 +459582,7 @@ Generate the single-person scene image now.`;
459509
459582
  const targetDuration = segment.duration;
459510
459583
  const actualVideoDuration = await getVideoDuration(videoPath);
459511
459584
  if (actualVideoDuration < targetDuration - 0.1) {
459512
- const extendedPath = resolve48(outputDir, `scene-${sceneNum}-extended.mp4`);
459585
+ const extendedPath = resolve49(outputDir, `scene-${sceneNum}-extended.mp4`);
459513
459586
  await extendVideoNaturally(videoPath, targetDuration, extendedPath);
459514
459587
  await unlink6(videoPath);
459515
459588
  await rename6(extendedPath, videoPath);
@@ -459552,7 +459625,7 @@ Generate the single-person scene image now.`;
459552
459625
  const targetDuration = segment.duration;
459553
459626
  const actualVideoDuration = await getVideoDuration(videoPath);
459554
459627
  if (actualVideoDuration < targetDuration - 0.1) {
459555
- const extendedPath = resolve48(outputDir, `scene-${sceneNum}-extended.mp4`);
459628
+ const extendedPath = resolve49(outputDir, `scene-${sceneNum}-extended.mp4`);
459556
459629
  await extendVideoNaturally(videoPath, targetDuration, extendedPath);
459557
459630
  await unlink6(videoPath);
459558
459631
  await rename6(extendedPath, videoPath);
@@ -459646,7 +459719,7 @@ Generate the single-person scene image now.`;
459646
459719
  const targetDuration = segment.duration;
459647
459720
  const actualVideoDuration = await getVideoDuration(videoPath);
459648
459721
  if (actualVideoDuration < targetDuration - 0.1) {
459649
- const extendedPath = resolve48(outputDir, `scene-${sceneNum}-extended.mp4`);
459722
+ const extendedPath = resolve49(outputDir, `scene-${sceneNum}-extended.mp4`);
459650
459723
  await extendVideoNaturally(videoPath, targetDuration, extendedPath);
459651
459724
  await unlink6(videoPath);
459652
459725
  await rename6(extendedPath, videoPath);
@@ -459702,7 +459775,7 @@ var init_ai_script_pipeline = __esm({
459702
459775
  });
459703
459776
 
459704
459777
  // ../cli/src/commands/generate/video.ts
459705
- import { resolve as resolve49 } from "node:path";
459778
+ import { resolve as resolve50 } from "node:path";
459706
459779
  import { readFile as readFile25, writeFile as writeFile33 } from "node:fs/promises";
459707
459780
  function registerVideoCommand(parent) {
459708
459781
  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 +459854,7 @@ Examples:
459781
459854
  let referenceImage;
459782
459855
  let isImageToVideo = false;
459783
459856
  if (options.image) {
459784
- const imagePath = resolve49(process.cwd(), options.image);
459857
+ const imagePath = resolve50(process.cwd(), options.image);
459785
459858
  const imageBuffer = await readFile25(imagePath);
459786
459859
  const ext = options.image.toLowerCase().split(".").pop();
459787
459860
  const mimeTypes = {
@@ -459986,7 +460059,7 @@ Examples:
459986
460059
  const veoDuration = parseInt(options.duration) <= 6 ? 6 : 8;
459987
460060
  let lastFrame;
459988
460061
  if (options.lastFrame) {
459989
- const lastFramePath = resolve49(process.cwd(), options.lastFrame);
460062
+ const lastFramePath = resolve50(process.cwd(), options.lastFrame);
459990
460063
  const lastFrameBuffer = await readFile25(lastFramePath);
459991
460064
  const ext = options.lastFrame.toLowerCase().split(".").pop();
459992
460065
  const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
@@ -459996,7 +460069,7 @@ Examples:
459996
460069
  if (options.refImages && options.refImages.length > 0) {
459997
460070
  refImages = [];
459998
460071
  for (const refPath of options.refImages.slice(0, 3)) {
459999
- const absRefPath = resolve49(process.cwd(), refPath);
460072
+ const absRefPath = resolve50(process.cwd(), refPath);
460000
460073
  const refBuffer = await readFile25(absRefPath);
460001
460074
  const ext = refPath.toLowerCase().split(".").pop();
460002
460075
  const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
@@ -460115,7 +460188,7 @@ Examples:
460115
460188
  let outputPath;
460116
460189
  if (options.output && finalResult.videoUrl) {
460117
460190
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
460118
- outputPath = resolve49(process.cwd(), options.output);
460191
+ outputPath = resolve50(process.cwd(), options.output);
460119
460192
  await writeFile33(outputPath, buffer);
460120
460193
  }
460121
460194
  outputSuccess({
@@ -460143,7 +460216,7 @@ Examples:
460143
460216
  const downloadSpinner = ora("Downloading video...").start();
460144
460217
  try {
460145
460218
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
460146
- const outputPath = resolve49(process.cwd(), options.output);
460219
+ const outputPath = resolve50(process.cwd(), options.output);
460147
460220
  await writeFile33(outputPath, buffer);
460148
460221
  downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
460149
460222
  } catch (err) {
@@ -460267,7 +460340,7 @@ __export(ai_video_exports, {
460267
460340
  executeVideoStatus: () => executeVideoStatus
460268
460341
  });
460269
460342
  import { readFile as readFile26, writeFile as writeFile34 } from "node:fs/promises";
460270
- import { resolve as resolve50 } from "node:path";
460343
+ import { resolve as resolve51 } from "node:path";
460271
460344
  async function executeVideoGenerate(options) {
460272
460345
  const {
460273
460346
  prompt: prompt3,
@@ -460298,7 +460371,7 @@ async function executeVideoGenerate(options) {
460298
460371
  if (!key2) return { success: false, error: `${envKeyMap[provider]} required for ${provider}` };
460299
460372
  let referenceImage;
460300
460373
  if (image) {
460301
- const imagePath = resolve50(process.cwd(), image);
460374
+ const imagePath = resolve51(process.cwd(), image);
460302
460375
  const imageBuffer = await readFile26(imagePath);
460303
460376
  const ext = image.toLowerCase().split(".").pop();
460304
460377
  const mimeTypes = { jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", webp: "image/webp" };
@@ -460330,7 +460403,7 @@ async function executeVideoGenerate(options) {
460330
460403
  let outputPath;
460331
460404
  if (output3 && result.videoUrl) {
460332
460405
  const buffer = await downloadVideo(result.videoUrl, key2);
460333
- outputPath = resolve50(process.cwd(), output3);
460406
+ outputPath = resolve51(process.cwd(), output3);
460334
460407
  await writeFile34(outputPath, buffer);
460335
460408
  }
460336
460409
  return { success: true, taskId: result.id, status: "completed", videoUrl: result.videoUrl, outputPath, provider: "seedance" };
@@ -460352,7 +460425,7 @@ async function executeVideoGenerate(options) {
460352
460425
  let outputPath;
460353
460426
  if (output3 && finalResult.videoUrl) {
460354
460427
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
460355
- outputPath = resolve50(process.cwd(), output3);
460428
+ outputPath = resolve51(process.cwd(), output3);
460356
460429
  await writeFile34(outputPath, buffer);
460357
460430
  }
460358
460431
  return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath, provider: "runway" };
@@ -460386,7 +460459,7 @@ async function executeVideoGenerate(options) {
460386
460459
  let outputPath;
460387
460460
  if (output3 && finalResult.videoUrl) {
460388
460461
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
460389
- outputPath = resolve50(process.cwd(), output3);
460462
+ outputPath = resolve51(process.cwd(), output3);
460390
460463
  await writeFile34(outputPath, buffer);
460391
460464
  }
460392
460465
  return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath, provider: "kling" };
@@ -460413,7 +460486,7 @@ async function executeVideoGenerate(options) {
460413
460486
  let outputPath;
460414
460487
  if (output3 && finalResult.videoUrl) {
460415
460488
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
460416
- outputPath = resolve50(process.cwd(), output3);
460489
+ outputPath = resolve51(process.cwd(), output3);
460417
460490
  await writeFile34(outputPath, buffer);
460418
460491
  }
460419
460492
  return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, outputPath, provider: "veo" };
@@ -460434,7 +460507,7 @@ async function executeVideoGenerate(options) {
460434
460507
  let outputPath;
460435
460508
  if (output3 && finalResult.videoUrl) {
460436
460509
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
460437
- outputPath = resolve50(process.cwd(), output3);
460510
+ outputPath = resolve51(process.cwd(), output3);
460438
460511
  await writeFile34(outputPath, buffer);
460439
460512
  }
460440
460513
  return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath, provider: "grok" };
@@ -460461,7 +460534,7 @@ async function executeVideoStatus(options) {
460461
460534
  let outputPath;
460462
460535
  if (output3 && result.videoUrl) {
460463
460536
  const buffer = await downloadVideo(result.videoUrl, key2);
460464
- outputPath = resolve50(process.cwd(), output3);
460537
+ outputPath = resolve51(process.cwd(), output3);
460465
460538
  await writeFile34(outputPath, buffer);
460466
460539
  }
460467
460540
  return { success: true, taskId, status: result.status, progress: result.progress, videoUrl: result.videoUrl, outputPath };
@@ -460476,7 +460549,7 @@ async function executeVideoStatus(options) {
460476
460549
  let outputPath;
460477
460550
  if (output3 && result.videoUrl) {
460478
460551
  const buffer = await downloadVideo(result.videoUrl, key2);
460479
- outputPath = resolve50(process.cwd(), output3);
460552
+ outputPath = resolve51(process.cwd(), output3);
460480
460553
  await writeFile34(outputPath, buffer);
460481
460554
  }
460482
460555
  return { success: true, taskId, status: result.status, videoUrl: result.videoUrl, duration: result.duration, outputPath };
@@ -460521,7 +460594,7 @@ async function executeVideoExtend(options) {
460521
460594
  let outputPath;
460522
460595
  if (output3 && finalResult.videoUrl) {
460523
460596
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
460524
- outputPath = resolve50(process.cwd(), output3);
460597
+ outputPath = resolve51(process.cwd(), output3);
460525
460598
  await writeFile34(outputPath, buffer);
460526
460599
  }
460527
460600
  return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath };
@@ -460544,7 +460617,7 @@ async function executeVideoExtend(options) {
460544
460617
  let outputPath;
460545
460618
  if (output3 && finalResult.videoUrl) {
460546
460619
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
460547
- outputPath = resolve50(process.cwd(), output3);
460620
+ outputPath = resolve51(process.cwd(), output3);
460548
460621
  await writeFile34(outputPath, buffer);
460549
460622
  }
460550
460623
  return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, outputPath };
@@ -460572,13 +460645,13 @@ __export(detect_exports, {
460572
460645
  executeDetectSilence: () => executeDetectSilence
460573
460646
  });
460574
460647
  import { readFile as readFile28, writeFile as writeFile36 } from "node:fs/promises";
460575
- import { resolve as resolve53, basename as basename13 } from "node:path";
460648
+ import { resolve as resolve54, basename as basename13 } from "node:path";
460576
460649
  async function executeDetectScenes(options) {
460577
460650
  try {
460578
460651
  if (!commandExists("ffmpeg")) {
460579
460652
  return { success: false, error: "FFmpeg not found. Install with: brew install ffmpeg" };
460580
460653
  }
460581
- const absPath = resolve53(process.cwd(), options.videoPath);
460654
+ const absPath = resolve54(process.cwd(), options.videoPath);
460582
460655
  const threshold = options.threshold ?? 0.3;
460583
460656
  const { stdout: sceneStdout, stderr: sceneStderr } = await execSafe("ffmpeg", [
460584
460657
  "-i",
@@ -460609,7 +460682,7 @@ async function executeDetectScenes(options) {
460609
460682
  duration: (i < scenes.length - 1 ? scenes[i + 1].timestamp : totalDuration) - s.timestamp
460610
460683
  }));
460611
460684
  if (options.outputPath) {
460612
- const outputPath = resolve53(process.cwd(), options.outputPath);
460685
+ const outputPath = resolve54(process.cwd(), options.outputPath);
460613
460686
  await writeFile36(outputPath, JSON.stringify({ source: absPath, totalDuration, threshold, scenes: result }, null, 2), "utf-8");
460614
460687
  }
460615
460688
  return { success: true, scenes: result, totalDuration };
@@ -460622,7 +460695,7 @@ async function executeDetectSilence(options) {
460622
460695
  if (!commandExists("ffmpeg")) {
460623
460696
  return { success: false, error: "FFmpeg not found. Install with: brew install ffmpeg" };
460624
460697
  }
460625
- const absPath = resolve53(process.cwd(), options.mediaPath);
460698
+ const absPath = resolve54(process.cwd(), options.mediaPath);
460626
460699
  const noise = options.noise ?? "-30";
460627
460700
  const duration = options.duration ?? "0.5";
460628
460701
  const { stdout: silStdout, stderr: silStderr } = await execSafe("ffmpeg", [
@@ -460656,7 +460729,7 @@ async function executeDetectSilence(options) {
460656
460729
  }
460657
460730
  }
460658
460731
  if (options.outputPath) {
460659
- const outputPath = resolve53(process.cwd(), options.outputPath);
460732
+ const outputPath = resolve54(process.cwd(), options.outputPath);
460660
460733
  await writeFile36(outputPath, JSON.stringify({ source: absPath, silences }, null, 2), "utf-8");
460661
460734
  }
460662
460735
  return { success: true, silences };
@@ -460669,7 +460742,7 @@ async function executeDetectBeats(options) {
460669
460742
  if (!commandExists("ffmpeg")) {
460670
460743
  return { success: false, error: "FFmpeg not found. Install with: brew install ffmpeg" };
460671
460744
  }
460672
- const absPath = resolve53(process.cwd(), options.audioPath);
460745
+ const absPath = resolve54(process.cwd(), options.audioPath);
460673
460746
  const { stdout: beatStdout, stderr: beatStderr } = await execSafe("ffmpeg", [
460674
460747
  "-i",
460675
460748
  absPath,
@@ -460705,7 +460778,7 @@ async function executeDetectBeats(options) {
460705
460778
  }
460706
460779
  }
460707
460780
  if (options.outputPath) {
460708
- const outputPath = resolve53(process.cwd(), options.outputPath);
460781
+ const outputPath = resolve54(process.cwd(), options.outputPath);
460709
460782
  await writeFile36(outputPath, JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2), "utf-8");
460710
460783
  }
460711
460784
  return { success: true, beats, beatCount: beats.length };
@@ -460756,7 +460829,7 @@ var init_detect = __esm({
460756
460829
  spinner2.fail("FFmpeg not found");
460757
460830
  exitWithError(generalError("FFmpeg not found", "Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)"));
460758
460831
  }
460759
- const absPath = resolve53(process.cwd(), videoPath);
460832
+ const absPath = resolve54(process.cwd(), videoPath);
460760
460833
  const threshold = parseFloat(options.threshold);
460761
460834
  spinner2.text = "Analyzing video...";
460762
460835
  const { stdout: sceneStdout, stderr: sceneStderr } = await execSafe("ffmpeg", [
@@ -460797,7 +460870,7 @@ var init_detect = __esm({
460797
460870
  }
460798
460871
  console.log();
460799
460872
  if (options.output) {
460800
- const outputPath = resolve53(process.cwd(), options.output);
460873
+ const outputPath = resolve54(process.cwd(), options.output);
460801
460874
  const result = {
460802
460875
  source: absPath,
460803
460876
  totalDuration,
@@ -460813,7 +460886,7 @@ var init_detect = __esm({
460813
460886
  console.log(source_default.green(`Saved to: ${outputPath}`));
460814
460887
  }
460815
460888
  if (options.project) {
460816
- const projectPath = resolve53(process.cwd(), options.project);
460889
+ const projectPath = resolve54(process.cwd(), options.project);
460817
460890
  const content = await readFile28(projectPath, "utf-8");
460818
460891
  const data = JSON.parse(content);
460819
460892
  const project = Project.fromJSON(data);
@@ -460871,7 +460944,7 @@ var init_detect = __esm({
460871
460944
  });
460872
460945
  return;
460873
460946
  }
460874
- const absPath = resolve53(process.cwd(), mediaPath);
460947
+ const absPath = resolve54(process.cwd(), mediaPath);
460875
460948
  const noise = options.noise;
460876
460949
  const duration = options.duration;
460877
460950
  const { stdout: silStdout, stderr: silStderr } = await execSafe("ffmpeg", [
@@ -460920,7 +460993,7 @@ var init_detect = __esm({
460920
460993
  }
460921
460994
  console.log();
460922
460995
  if (options.output) {
460923
- const outputPath = resolve53(process.cwd(), options.output);
460996
+ const outputPath = resolve54(process.cwd(), options.output);
460924
460997
  await writeFile36(
460925
460998
  outputPath,
460926
460999
  JSON.stringify({ source: absPath, silences }, null, 2),
@@ -460955,7 +461028,7 @@ var init_detect = __esm({
460955
461028
  });
460956
461029
  return;
460957
461030
  }
460958
- const absPath = resolve53(process.cwd(), audioPath);
461031
+ const absPath = resolve54(process.cwd(), audioPath);
460959
461032
  const { stdout: beatStdout, stderr: beatStderr } = await execSafe("ffmpeg", [
460960
461033
  "-i",
460961
461034
  absPath,
@@ -461005,7 +461078,7 @@ var init_detect = __esm({
461005
461078
  }
461006
461079
  console.log();
461007
461080
  if (options.output) {
461008
- const outputPath = resolve53(process.cwd(), options.output);
461081
+ const outputPath = resolve54(process.cwd(), options.output);
461009
461082
  await writeFile36(
461010
461083
  outputPath,
461011
461084
  JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2),
@@ -461024,8 +461097,8 @@ var init_detect = __esm({
461024
461097
 
461025
461098
  // ../cli/src/pipeline/renderers/html-clips.ts
461026
461099
  function relAsset(url) {
461027
- const basename17 = url.split("/").pop() ?? url;
461028
- return `assets/${basename17}`;
461100
+ const basename18 = url.split("/").pop() ?? url;
461101
+ return `assets/${basename18}`;
461029
461102
  }
461030
461103
  function buildClipElements(state) {
461031
461104
  return state.clips.map((clip) => {
@@ -461199,7 +461272,7 @@ __export(project_builder_exports, {
461199
461272
  buildTempProject: () => buildTempProject,
461200
461273
  resolveSourceUrl: () => resolveSourceUrl
461201
461274
  });
461202
- import { mkdtemp as mkdtemp4, mkdir as mkdir24, copyFile as copyFile4, writeFile as writeFile41, rm as rm5, readdir as readdir4 } from "node:fs/promises";
461275
+ import { mkdtemp as mkdtemp4, mkdir as mkdir25, copyFile as copyFile4, writeFile as writeFile42, rm as rm5, readdir as readdir4 } from "node:fs/promises";
461203
461276
  import { existsSync as existsSync51 } from "node:fs";
461204
461277
  import { tmpdir as tmpdir6 } from "node:os";
461205
461278
  import { createRequire } from "node:module";
@@ -461207,7 +461280,7 @@ import * as path13 from "node:path";
461207
461280
  async function buildTempProject(state, projectFileDir) {
461208
461281
  const dir = await mkdtemp4(path13.join(tmpdir6(), "vibeframe-hf-"));
461209
461282
  const assetsDir = path13.join(dir, "assets");
461210
- await mkdir24(assetsDir, { recursive: true });
461283
+ await mkdir25(assetsDir, { recursive: true });
461211
461284
  const copied = /* @__PURE__ */ new Map();
461212
461285
  for (const source3 of state.sources) {
461213
461286
  if (copied.has(source3.id)) continue;
@@ -461223,7 +461296,7 @@ async function buildTempProject(state, projectFileDir) {
461223
461296
  await copyLottieRuntime(dir);
461224
461297
  }
461225
461298
  const html = generateCompositionHtml(state);
461226
- await writeFile41(path13.join(dir, "index.html"), html, "utf-8");
461299
+ await writeFile42(path13.join(dir, "index.html"), html, "utf-8");
461227
461300
  return {
461228
461301
  dir,
461229
461302
  cleanup: () => rm5(dir, { recursive: true, force: true })
@@ -461237,7 +461310,7 @@ async function copyLottieRuntime(tempDir) {
461237
461310
  const wasmSrc = path13.join(path13.dirname(webEntry), "dotlottie-player.wasm");
461238
461311
  const vendorDir = path13.join(tempDir, "vendor");
461239
461312
  const wcDest = path13.join(vendorDir, "dotlottie-wc");
461240
- await mkdir24(wcDest, { recursive: true });
461313
+ await mkdir25(wcDest, { recursive: true });
461241
461314
  for (const file of await readdir4(wcDistDir)) {
461242
461315
  if (file.endsWith(".map") || file.endsWith(".d.ts")) continue;
461243
461316
  await copyFile4(path13.join(wcDistDir, file), path13.join(wcDest, file));
@@ -463279,7 +463352,7 @@ init_ai_edit();
463279
463352
  init_api_key();
463280
463353
  init_exec_safe();
463281
463354
  init_remotion();
463282
- import { resolve as resolve30, dirname as dirname23, basename as basename9 } from "node:path";
463355
+ import { resolve as resolve31, dirname as dirname23, basename as basename9 } from "node:path";
463283
463356
  import { writeFile as writeFile18, mkdir as mkdir16, rm as rm4 } from "node:fs/promises";
463284
463357
  import { existsSync as existsSync41 } from "node:fs";
463285
463358
  import { tmpdir as tmpdir4 } from "node:os";
@@ -463431,9 +463504,9 @@ async function executeAnimatedCaption(options) {
463431
463504
  } catch {
463432
463505
  }
463433
463506
  const effectiveFontSize = fontSize ?? Math.round(height * 0.04);
463434
- const tmpAudioDir = resolve30(tmpdir4(), `vf-ac-${Date.now()}`);
463507
+ const tmpAudioDir = resolve31(tmpdir4(), `vf-ac-${Date.now()}`);
463435
463508
  await mkdir16(tmpAudioDir, { recursive: true });
463436
- const audioPath = resolve30(tmpAudioDir, "audio.wav");
463509
+ const audioPath = resolve31(tmpAudioDir, "audio.wav");
463437
463510
  await execSafe("ffmpeg", [
463438
463511
  "-y",
463439
463512
  "-i",
@@ -463460,7 +463533,7 @@ async function executeAnimatedCaption(options) {
463460
463533
  return { success: false, error: "No words detected in transcription" };
463461
463534
  }
463462
463535
  const groups = groupWords(transcript.words, { wordsPerGroup, maxChars });
463463
- const absOutputPath = resolve30(process.cwd(), outputPath);
463536
+ const absOutputPath = resolve31(process.cwd(), outputPath);
463464
463537
  const outDir = dirname23(absOutputPath);
463465
463538
  if (!existsSync41(outDir)) {
463466
463539
  await mkdir16(outDir, { recursive: true });
@@ -463471,7 +463544,7 @@ async function executeAnimatedCaption(options) {
463471
463544
  effectiveStyle,
463472
463545
  { highlightColor, fontSize: effectiveFontSize, position, width, height }
463473
463546
  );
463474
- const assPath = resolve30(tmpAudioDir, "captions.ass");
463547
+ const assPath = resolve31(tmpAudioDir, "captions.ass");
463475
463548
  await writeFile18(assPath, assContent, "utf-8");
463476
463549
  const escapedAssPath = assPath.replace(/\\/g, "\\\\").replace(/:/g, "\\:");
463477
463550
  await execSafe("ffmpeg", [
@@ -463876,7 +463949,7 @@ var editFillGapsTool = defineTool({
463876
463949
  cost: "high",
463877
463950
  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
463951
  schema: z3.object({
463879
- projectPath: z3.string().describe("Project file path (.vibe.json)"),
463952
+ projectPath: z3.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
463880
463953
  output: z3.string().optional().describe("Output project path (default: overwrite input)"),
463881
463954
  dir: z3.string().optional().describe("Directory to save generated videos (default: <projectDir>/footage)"),
463882
463955
  prompt: z3.string().optional().describe("Custom prompt for video generation (default: 'Continue the scene naturally with subtle motion')"),
@@ -463940,12 +464013,12 @@ init_dist();
463940
464013
  init_engine();
463941
464014
  init_ai_helpers();
463942
464015
  import { readFile as readFile21, writeFile as writeFile20 } from "node:fs/promises";
463943
- import { resolve as resolve35 } from "node:path";
464016
+ import { resolve as resolve36 } from "node:path";
463944
464017
  async function executeSuggestEdit(options) {
463945
464018
  try {
463946
464019
  const apiKey = options.apiKey ?? process.env.GOOGLE_API_KEY;
463947
464020
  if (!apiKey) return { success: false, error: "GOOGLE_API_KEY required for suggest" };
463948
- const filePath = resolve35(process.cwd(), options.projectPath);
464021
+ const filePath = resolve36(process.cwd(), options.projectPath);
463949
464022
  const content = await readFile21(filePath, "utf-8");
463950
464023
  const data = JSON.parse(content);
463951
464024
  const project = Project.fromJSON(data);
@@ -464065,7 +464138,7 @@ var analyzeSuggestTool = defineTool({
464065
464138
  cost: "low",
464066
464139
  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
464140
  schema: z4.object({
464068
- projectPath: z4.string().describe("Project file path (.vibe.json)"),
464141
+ projectPath: z4.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
464069
464142
  instruction: z4.string().describe("Natural-language instruction (e.g. 'trim all clips to 5 seconds', 'add transitions between every clip')"),
464070
464143
  apply: z4.boolean().optional().describe("Apply the first suggestion in place")
464071
464144
  }),
@@ -464427,7 +464500,7 @@ init_ai_script_pipeline();
464427
464500
 
464428
464501
  // ../cli/src/commands/ai-highlights.ts
464429
464502
  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";
464503
+ import { resolve as resolve53, dirname as dirname28, basename as basename12, extname as extname11 } from "node:path";
464431
464504
  import { existsSync as existsSync49 } from "node:fs";
464432
464505
  init_dist();
464433
464506
  init_engine();
@@ -464458,7 +464531,7 @@ function filterHighlights(highlights, options) {
464458
464531
  }
464459
464532
  async function executeHighlights(options) {
464460
464533
  try {
464461
- const absPath = resolve51(process.cwd(), options.media);
464534
+ const absPath = resolve53(process.cwd(), options.media);
464462
464535
  if (!existsSync49(absPath)) {
464463
464536
  return { success: false, highlights: [], totalDuration: 0, totalHighlightDuration: 0, error: `File not found: ${absPath}` };
464464
464537
  }
@@ -464606,7 +464679,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
464606
464679
  totalHighlightDuration
464607
464680
  };
464608
464681
  if (options.output) {
464609
- const outputPath = resolve51(process.cwd(), options.output);
464682
+ const outputPath = resolve53(process.cwd(), options.output);
464610
464683
  await writeFile35(outputPath, JSON.stringify({
464611
464684
  sourceFile: absPath,
464612
464685
  totalDuration: sourceDuration,
@@ -464641,7 +464714,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
464641
464714
  currentTime += highlight.duration;
464642
464715
  }
464643
464716
  }
464644
- const projectPath = resolve51(process.cwd(), options.project);
464717
+ const projectPath = resolve53(process.cwd(), options.project);
464645
464718
  await writeFile35(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
464646
464719
  extractResult.projectPath = projectPath;
464647
464720
  }
@@ -464661,7 +464734,7 @@ async function executeAutoShorts(options) {
464661
464734
  if (!commandExists("ffmpeg")) {
464662
464735
  return { success: false, shorts: [], error: "FFmpeg not found" };
464663
464736
  }
464664
- const absPath = resolve51(process.cwd(), options.video);
464737
+ const absPath = resolve53(process.cwd(), options.video);
464665
464738
  if (!existsSync49(absPath)) {
464666
464739
  return { success: false, shorts: [], error: `File not found: ${absPath}` };
464667
464740
  }
@@ -464789,7 +464862,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
464789
464862
  }))
464790
464863
  };
464791
464864
  }
464792
- const outputDir = options.outputDir ? resolve51(process.cwd(), options.outputDir) : dirname28(absPath);
464865
+ const outputDir = options.outputDir ? resolve53(process.cwd(), options.outputDir) : dirname28(absPath);
464793
464866
  if (options.outputDir && !existsSync49(outputDir)) {
464794
464867
  await mkdir21(outputDir, { recursive: true });
464795
464868
  }
@@ -464800,7 +464873,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
464800
464873
  for (let i = 0; i < selectedHighlights.length; i++) {
464801
464874
  const h = selectedHighlights[i];
464802
464875
  const baseName = basename12(absPath, extname11(absPath));
464803
- const outputPath = resolve51(outputDir, `${baseName}-short-${i + 1}.mp4`);
464876
+ const outputPath = resolve53(outputDir, `${baseName}-short-${i + 1}.mp4`);
464804
464877
  const { stdout: probeOut } = await execSafe("ffprobe", [
464805
464878
  "-v",
464806
464879
  "error",
@@ -464868,7 +464941,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
464868
464941
 
464869
464942
  // ../cli/src/pipeline/executor.ts
464870
464943
  var import_yaml7 = __toESM(require_dist(), 1);
464871
- import { resolve as resolve54 } from "node:path";
464944
+ import { resolve as resolve55 } from "node:path";
464872
464945
  import { readFile as readFile29, writeFile as writeFile37, mkdir as mkdir23 } from "node:fs/promises";
464873
464946
  import { existsSync as existsSync50 } from "node:fs";
464874
464947
 
@@ -464976,9 +465049,9 @@ function registerAction(action, handler4) {
464976
465049
  }
464977
465050
  function getOutput(params, outputDir, defaultName) {
464978
465051
  if (params.output && typeof params.output === "string") {
464979
- return resolve54(outputDir, params.output);
465052
+ return resolve55(outputDir, params.output);
464980
465053
  }
464981
- return resolve54(outputDir, defaultName);
465054
+ return resolve55(outputDir, defaultName);
464982
465055
  }
464983
465056
  async function ensureActionsRegistered() {
464984
465057
  if (Object.keys(ACTION_HANDLERS).length > 0) return;
@@ -465131,7 +465204,7 @@ async function ensureActionsRegistered() {
465131
465204
  const { executeSceneBuild: executeSceneBuild2 } = await Promise.resolve().then(() => (init_scene_build(), scene_build_exports));
465132
465205
  const projectRel = params.project ?? ".";
465133
465206
  const r = await executeSceneBuild2({
465134
- projectDir: resolve54(outputDir, projectRel),
465207
+ projectDir: resolve55(outputDir, projectRel),
465135
465208
  mode: params.mode,
465136
465209
  effort: params.effort,
465137
465210
  composer: params.composer,
@@ -465157,7 +465230,7 @@ async function ensureActionsRegistered() {
465157
465230
  const { executeSceneRender: executeSceneRender2 } = await Promise.resolve().then(() => (init_scene_render(), scene_render_exports));
465158
465231
  const projectRel = params.project ?? ".";
465159
465232
  const r = await executeSceneRender2({
465160
- projectDir: resolve54(outputDir, projectRel),
465233
+ projectDir: resolve55(outputDir, projectRel),
465161
465234
  root: params.root,
465162
465235
  output: params.output,
465163
465236
  fps: params.fps,
@@ -465181,7 +465254,7 @@ async function ensureActionsRegistered() {
465181
465254
  });
465182
465255
  }
465183
465256
  async function loadPipeline(filePath) {
465184
- const absPath = resolve54(process.cwd(), filePath);
465257
+ const absPath = resolve55(process.cwd(), filePath);
465185
465258
  if (!existsSync50(absPath)) {
465186
465259
  throw new Error(`Pipeline file not found: ${absPath}`);
465187
465260
  }
@@ -465201,13 +465274,13 @@ async function loadPipeline(filePath) {
465201
465274
  var CHECKPOINT_FILE = ".pipeline-state.yaml";
465202
465275
  async function executePipeline(manifest2, options = {}) {
465203
465276
  await ensureActionsRegistered();
465204
- const outputDir = resolve54(process.cwd(), options.outputDir || `${manifest2.name}-output`);
465277
+ const outputDir = resolve55(process.cwd(), options.outputDir || `${manifest2.name}-output`);
465205
465278
  await mkdir23(outputDir, { recursive: true });
465206
465279
  const completedSteps = /* @__PURE__ */ new Map();
465207
465280
  const results = [];
465208
465281
  const startTime = Date.now();
465209
465282
  if (options.resume) {
465210
- const checkpointPath = resolve54(outputDir, CHECKPOINT_FILE);
465283
+ const checkpointPath = resolve55(outputDir, CHECKPOINT_FILE);
465211
465284
  if (existsSync50(checkpointPath)) {
465212
465285
  const checkpointContent = await readFile29(checkpointPath, "utf-8");
465213
465286
  const checkpoint = (0, import_yaml7.parse)(checkpointContent);
@@ -465328,7 +465401,7 @@ async function executePipeline(manifest2, options = {}) {
465328
465401
  }))
465329
465402
  };
465330
465403
  await writeFile37(
465331
- resolve54(outputDir, CHECKPOINT_FILE),
465404
+ resolve55(outputDir, CHECKPOINT_FILE),
465332
465405
  (0, import_yaml7.stringify)(checkpoint, { indent: 2 }),
465333
465406
  "utf-8"
465334
465407
  );
@@ -465385,7 +465458,7 @@ var pipelineHighlightsTool = defineTool({
465385
465458
  schema: z6.object({
465386
465459
  media: z6.string().describe("Path to the input video file"),
465387
465460
  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"),
465461
+ project: z6.string().optional().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file to add highlights to"),
465389
465462
  duration: z6.number().optional().describe("Maximum duration per highlight in seconds (default: 30)"),
465390
465463
  count: z6.number().optional().describe("Maximum number of highlights to extract (default: 5)"),
465391
465464
  threshold: z6.number().optional().describe("Minimum confidence threshold 0-1 (default: 0.7)"),
@@ -465635,14 +465708,17 @@ var detectTools = [
465635
465708
 
465636
465709
  // ../cli/src/tools/manifest/timeline.ts
465637
465710
  import { z as z8 } from "zod";
465638
- import { resolve as resolve56 } from "node:path";
465711
+ import { mkdir as mkdir24, writeFile as writeFile40 } from "node:fs/promises";
465712
+ import { basename as basename14, resolve as resolve56 } from "node:path";
465713
+ init_engine();
465714
+ init_project_resolver();
465639
465715
 
465640
465716
  // ../cli/src/tools/manifest/_project-io.ts
465641
465717
  init_engine();
465718
+ init_project_resolver();
465642
465719
  import { readFile as readFile30, writeFile as writeFile39 } from "node:fs/promises";
465643
- import { resolve as resolve55 } from "node:path";
465644
465720
  async function loadProject(projectPath, cwd) {
465645
- const absPath = resolve55(cwd, projectPath);
465721
+ const absPath = await resolveTimelineFile(projectPath, cwd);
465646
465722
  const content = await readFile30(absPath, "utf-8");
465647
465723
  const data = JSON.parse(content);
465648
465724
  return { project: Project.fromJSON(data), absPath };
@@ -465667,13 +465743,70 @@ var MEDIA_TYPES = {
465667
465743
  gif: "image",
465668
465744
  webp: "image"
465669
465745
  };
465746
+ var timelineCreateTool = defineTool({
465747
+ name: "timeline_create",
465748
+ category: "timeline",
465749
+ cost: "free",
465750
+ description: "Create a low-level timeline JSON file for FFmpeg-style editing",
465751
+ schema: z8.object({
465752
+ name: z8.string().describe("Timeline name or directory path"),
465753
+ outputPath: z8.string().optional().describe("Output file path. Defaults to <name>/timeline.json"),
465754
+ fps: z8.number().optional().describe("Frames per second (default: 30)")
465755
+ }),
465756
+ async execute(args, ctx) {
465757
+ const projectName = args.name === "." ? basename14(ctx.workingDirectory) : basename14(resolve56(ctx.workingDirectory, args.name));
465758
+ const project = new Project(projectName);
465759
+ if (args.fps) project.setFrameRate(args.fps);
465760
+ let outputPath;
465761
+ if (args.outputPath) {
465762
+ outputPath = resolve56(ctx.workingDirectory, args.outputPath);
465763
+ } else {
465764
+ const dirPath = resolve56(ctx.workingDirectory, args.name);
465765
+ await mkdir24(dirPath, { recursive: true });
465766
+ outputPath = resolve56(dirPath, TIMELINE_FILENAME);
465767
+ }
465768
+ await writeFile40(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
465769
+ return {
465770
+ success: true,
465771
+ data: { name: projectName, outputPath },
465772
+ humanLines: [`Created timeline "${projectName}" at ${outputPath}`]
465773
+ };
465774
+ }
465775
+ });
465776
+ var timelineInfoTool = defineTool({
465777
+ name: "timeline_info",
465778
+ category: "timeline",
465779
+ cost: "free",
465780
+ description: "Get information about a timeline JSON file. Legacy *.vibe.json files are supported.",
465781
+ schema: z8.object({
465782
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file")
465783
+ }),
465784
+ async execute(args, ctx) {
465785
+ const { project } = await loadProject(args.projectPath, ctx.workingDirectory);
465786
+ const meta = project.getMeta();
465787
+ const info = {
465788
+ name: meta.name,
465789
+ aspectRatio: meta.aspectRatio,
465790
+ frameRate: meta.frameRate,
465791
+ duration: meta.duration,
465792
+ sources: project.getSources().length,
465793
+ tracks: project.getTracks().length,
465794
+ clips: project.getClips().length
465795
+ };
465796
+ return {
465797
+ success: true,
465798
+ data: info,
465799
+ humanLines: [JSON.stringify(info, null, 2)]
465800
+ };
465801
+ }
465802
+ });
465670
465803
  var timelineAddSourceTool = defineTool({
465671
465804
  name: "timeline_add_source",
465672
465805
  category: "timeline",
465673
465806
  cost: "free",
465674
- description: "Add a media source (video, audio, image) to the project",
465807
+ description: "Add a media source (video, audio, image) to the timeline",
465675
465808
  schema: z8.object({
465676
- projectPath: z8.string().describe("Path to the project file"),
465809
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465677
465810
  mediaPath: z8.string().describe("Path to the media file"),
465678
465811
  name: z8.string().optional().describe("Optional name for the source"),
465679
465812
  duration: z8.number().optional().describe("Duration of the media in seconds (default: 10)")
@@ -465698,7 +465831,7 @@ var timelineAddClipTool = defineTool({
465698
465831
  cost: "free",
465699
465832
  description: "Add a clip to the timeline from an existing source",
465700
465833
  schema: z8.object({
465701
- projectPath: z8.string().describe("Path to the project file"),
465834
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465702
465835
  sourceId: z8.string().describe("ID of the media source"),
465703
465836
  trackId: z8.string().optional().describe("ID of the track to add clip to (optional, uses first video track)"),
465704
465837
  startTime: z8.number().optional().describe("Start time on timeline in seconds (default: 0)"),
@@ -465729,7 +465862,7 @@ var timelineSplitClipTool = defineTool({
465729
465862
  cost: "free",
465730
465863
  description: "Split a clip at a specific time",
465731
465864
  schema: z8.object({
465732
- projectPath: z8.string().describe("Path to the project file"),
465865
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465733
465866
  clipId: z8.string().describe("ID of the clip to split"),
465734
465867
  splitTime: z8.number().describe("Time to split at (relative to clip start) in seconds")
465735
465868
  }),
@@ -465747,7 +465880,7 @@ var timelineTrimClipTool = defineTool({
465747
465880
  cost: "free",
465748
465881
  description: "Trim a clip by adjusting its start or end",
465749
465882
  schema: z8.object({
465750
- projectPath: z8.string().describe("Path to the project file"),
465883
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465751
465884
  clipId: z8.string().describe("ID of the clip to trim"),
465752
465885
  trimStart: z8.number().optional().describe("New source start offset in seconds"),
465753
465886
  trimEnd: z8.number().optional().describe("New duration in seconds")
@@ -465766,7 +465899,7 @@ var timelineMoveClipTool = defineTool({
465766
465899
  cost: "free",
465767
465900
  description: "Move a clip to a new position or track",
465768
465901
  schema: z8.object({
465769
- projectPath: z8.string().describe("Path to the project file"),
465902
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465770
465903
  clipId: z8.string().describe("ID of the clip to move"),
465771
465904
  newStartTime: z8.number().optional().describe("New start time on timeline in seconds"),
465772
465905
  newTrackId: z8.string().optional().describe("ID of the target track (optional)")
@@ -465788,7 +465921,7 @@ var timelineDeleteClipTool = defineTool({
465788
465921
  cost: "free",
465789
465922
  description: "Delete a clip from the timeline",
465790
465923
  schema: z8.object({
465791
- projectPath: z8.string().describe("Path to the project file"),
465924
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465792
465925
  clipId: z8.string().describe("ID of the clip to delete")
465793
465926
  }),
465794
465927
  async execute(args, ctx) {
@@ -465804,7 +465937,7 @@ var timelineDuplicateClipTool = defineTool({
465804
465937
  cost: "free",
465805
465938
  description: "Duplicate a clip on the timeline (optionally at a new start time)",
465806
465939
  schema: z8.object({
465807
- projectPath: z8.string().describe("Path to the project file"),
465940
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465808
465941
  clipId: z8.string().describe("ID of the clip to duplicate"),
465809
465942
  newStartTime: z8.number().optional().describe("Start time for the duplicated clip (optional, places after original)")
465810
465943
  }),
@@ -465822,7 +465955,7 @@ var timelineAddEffectTool = defineTool({
465822
465955
  cost: "free",
465823
465956
  description: "Add an effect to a clip",
465824
465957
  schema: z8.object({
465825
- projectPath: z8.string().describe("Path to the project file"),
465958
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465826
465959
  clipId: z8.string().describe("ID of the clip"),
465827
465960
  effectType: z8.string().describe("Effect type: fadeIn, fadeOut, blur, brightness, contrast, saturation, grayscale, sepia, invert"),
465828
465961
  startTime: z8.number().optional().describe("Effect start time relative to clip (default: 0)"),
@@ -465848,7 +465981,7 @@ var timelineAddTrackTool = defineTool({
465848
465981
  cost: "free",
465849
465982
  description: "Add a new track to the timeline",
465850
465983
  schema: z8.object({
465851
- projectPath: z8.string().describe("Path to the project file"),
465984
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
465852
465985
  trackType: z8.string().describe("Track type: video or audio"),
465853
465986
  name: z8.string().optional().describe("Track name (optional)")
465854
465987
  }),
@@ -465874,7 +466007,7 @@ var timelineListTool = defineTool({
465874
466007
  cost: "free",
465875
466008
  description: "List all sources, tracks, and clips in a project",
465876
466009
  schema: z8.object({
465877
- projectPath: z8.string().describe("Path to the project file")
466010
+ projectPath: z8.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file")
465878
466011
  }),
465879
466012
  async execute(args, ctx) {
465880
466013
  const { project } = await loadProject(args.projectPath, ctx.workingDirectory);
@@ -465891,6 +466024,8 @@ var timelineListTool = defineTool({
465891
466024
  }
465892
466025
  });
465893
466026
  var timelineTools = [
466027
+ timelineCreateTool,
466028
+ timelineInfoTool,
465894
466029
  timelineAddSourceTool,
465895
466030
  timelineAddClipTool,
465896
466031
  timelineSplitClipTool,
@@ -465906,16 +466041,16 @@ var timelineTools = [
465906
466041
  // ../cli/src/tools/manifest/project.ts
465907
466042
  import { z as z9 } from "zod";
465908
466043
  import { resolve as resolve57 } from "node:path";
465909
- import { writeFile as writeFile40 } from "node:fs/promises";
466044
+ import { writeFile as writeFile41 } from "node:fs/promises";
465910
466045
  init_engine();
465911
466046
  var projectCreateTool = defineTool({
465912
466047
  name: "project_create",
465913
466048
  category: "project",
465914
466049
  cost: "free",
465915
- description: "Create a new VibeFrame project file",
466050
+ description: "Deprecated alias for creating low-level timeline state. Prefer timeline_create.",
465916
466051
  schema: z9.object({
465917
466052
  name: z9.string().describe("Project name"),
465918
- outputPath: z9.string().optional().describe("Output file path (defaults to {name}.vibe.json)"),
466053
+ outputPath: z9.string().optional().describe("Output file path (defaults to {name}.vibe.json for legacy compatibility)"),
465919
466054
  width: z9.number().optional().describe("Video width in pixels (default: 1920)"),
465920
466055
  height: z9.number().optional().describe("Video height in pixels (default: 1080)"),
465921
466056
  fps: z9.number().optional().describe("Frames per second (default: 30)")
@@ -465924,11 +466059,11 @@ var projectCreateTool = defineTool({
465924
466059
  const outputPath = resolve57(ctx.workingDirectory, args.outputPath ?? `${args.name}.vibe.json`);
465925
466060
  const project = new Project(args.name);
465926
466061
  if (args.fps) project.setFrameRate(args.fps);
465927
- await writeFile40(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
466062
+ await writeFile41(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
465928
466063
  return {
465929
466064
  success: true,
465930
466065
  data: { name: args.name, outputPath },
465931
- humanLines: [`Created project "${args.name}" at ${outputPath}`]
466066
+ humanLines: [`Created legacy timeline project "${args.name}" at ${outputPath}`]
465932
466067
  };
465933
466068
  }
465934
466069
  });
@@ -465936,9 +466071,9 @@ var projectInfoTool = defineTool({
465936
466071
  name: "project_info",
465937
466072
  category: "project",
465938
466073
  cost: "free",
465939
- description: "Get information about a VibeFrame project",
466074
+ description: "Deprecated alias for timeline_info. Legacy *.vibe.json files remain supported.",
465940
466075
  schema: z9.object({
465941
- projectPath: z9.string().describe("Path to the .vibe.json project file")
466076
+ projectPath: z9.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file")
465942
466077
  }),
465943
466078
  async execute(args, ctx) {
465944
466079
  const { project } = await loadProject(args.projectPath, ctx.workingDirectory);
@@ -465976,19 +466111,15 @@ init_engine();
465976
466111
  init_exec_safe();
465977
466112
  init_output();
465978
466113
  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";
466114
+ init_project_resolver();
466115
+ import { readFile as readFile31, access as access6 } from "node:fs/promises";
466116
+ import { resolve as resolve59, basename as basename16 } from "node:path";
465981
466117
  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;
466118
+ function timelineBaseName(path14) {
466119
+ const name = basename16(path14);
466120
+ if (name.endsWith(".vibe.json")) return name.slice(0, -".vibe.json".length);
466121
+ if (name.endsWith(".json")) return name.slice(0, -".json".length);
466122
+ return basename16(path14, ".vibe.json");
465992
466123
  }
465993
466124
  async function getMediaDuration(filePath, mediaType, defaultImageDuration = 5) {
465994
466125
  if (mediaType === "image") {
@@ -466057,7 +466188,7 @@ async function runExport(projectPath, outputPath, options = {}) {
466057
466188
  message: "FFmpeg not found. Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)"
466058
466189
  };
466059
466190
  }
466060
- const filePath = await resolveProjectPath(projectPath);
466191
+ const filePath = await resolveTimelineFile(projectPath);
466061
466192
  const content = await readFile31(filePath, "utf-8");
466062
466193
  const data = JSON.parse(content);
466063
466194
  const project = Project.fromJSON(data);
@@ -466079,7 +466210,7 @@ async function runExport(projectPath, outputPath, options = {}) {
466079
466210
  const source3 = sources.find((s) => s.id === clip.sourceId);
466080
466211
  if (source3) {
466081
466212
  try {
466082
- await access5(source3.url);
466213
+ await access6(source3.url);
466083
466214
  if (!sourceActualDurationMap.has(source3.id)) {
466084
466215
  try {
466085
466216
  const dur = await getMediaDuration(source3.url, source3.type);
@@ -466114,20 +466245,20 @@ async function runExport(projectPath, outputPath, options = {}) {
466114
466245
  };
466115
466246
  }
466116
466247
  }
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(
466248
+ 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
466249
  "--preset <preset>",
466119
466250
  "Quality preset (draft, standard, high, ultra)",
466120
466251
  "standard"
466121
466252
  ).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
466253
  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.
466254
+ $ vibe export timeline.json -o output.mp4
466255
+ $ vibe export my-video -o output.mp4 --preset high --overwrite
466256
+ $ vibe export timeline.json -o output.webm --format webm
466257
+ $ vibe export timeline.json -o output.gif --format gif
466258
+ $ vibe export timeline.json -o out.mp4 --bitrate 5000k --fps 24 --codec h265
466259
+ $ vibe export timeline.json -o out.mp4 --preset high --fps 60
466260
+
466261
+ Cost: Free (no API keys needed). Requires FFmpeg. Legacy *.vibe.json files remain supported.
466131
466262
  GIF format: 15fps, no audio, looping. Good for previews and sharing.
466132
466263
  Custom flags (--bitrate, --fps, --resolution, --codec) override preset values.
466133
466264
  Run 'vibe schema export' for structured parameter info.`).action(async (projectPath, options) => {
@@ -466181,7 +466312,7 @@ Run 'vibe schema export' for structured parameter info.`).action(async (projectP
466181
466312
  exitWithError(generalError("FFmpeg not found", "Install with: brew install ffmpeg (macOS), apt install ffmpeg (Linux), or winget install ffmpeg (Windows)"));
466182
466313
  }
466183
466314
  spinner2.text = "Loading project...";
466184
- const filePath = await resolveProjectPath(projectPath);
466315
+ const filePath = await resolveTimelineFile(projectPath);
466185
466316
  const content = await readFile31(filePath, "utf-8");
466186
466317
  const data = JSON.parse(content);
466187
466318
  const project = Project.fromJSON(data);
@@ -466192,7 +466323,7 @@ Run 'vibe schema export' for structured parameter info.`).action(async (projectP
466192
466323
  }
466193
466324
  const outputPath = options.output ? resolve59(process.cwd(), options.output) : resolve59(
466194
466325
  process.cwd(),
466195
- `${basename15(projectPath, ".vibe.json")}.${options.format}`
466326
+ `${timelineBaseName(projectPath)}.${options.format}`
466196
466327
  );
466197
466328
  const basePresetSettings = getPresetSettings(options.preset, summary.aspectRatio);
466198
466329
  const presetSettings = applyCustomOverrides(basePresetSettings, customOverrides);
@@ -466205,7 +466336,7 @@ Run 'vibe schema export' for structured parameter info.`).action(async (projectP
466205
466336
  const source3 = sources.find((s) => s.id === clip.sourceId);
466206
466337
  if (source3) {
466207
466338
  try {
466208
- await access5(source3.url);
466339
+ await access6(source3.url);
466209
466340
  if (!sourceActualDurationMap.has(source3.id)) {
466210
466341
  try {
466211
466342
  const dur = await getMediaDuration(source3.url, source3.type);
@@ -466781,16 +466912,16 @@ function getPresetSettings(preset, aspectRatio) {
466781
466912
  async function runHyperframesExport(projectPath, options, spinner2, startedAt) {
466782
466913
  spinner2.text = "Loading project...";
466783
466914
  const { readFile: readFile34 } = await import("node:fs/promises");
466784
- const { resolve: resolve64, basename: basename17 } = await import("node:path");
466915
+ const { resolve: resolve64 } = await import("node:path");
466785
466916
  const { Project: Project2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
466786
466917
  const { createHyperframesBackend: createHyperframesBackend2 } = await Promise.resolve().then(() => (init_hyperframes(), hyperframes_exports));
466787
466918
  const { exitWithError: exitWithError2, generalError: generalError2, outputSuccess: outputSuccess2 } = await Promise.resolve().then(() => (init_output(), output_exports));
466788
466919
  const chalk2 = (await Promise.resolve().then(() => (init_source(), source_exports))).default;
466789
- const filePath = resolve64(process.cwd(), projectPath);
466920
+ const filePath = await resolveTimelineFile(projectPath);
466790
466921
  const content = await readFile34(filePath, "utf-8");
466791
466922
  const project = Project2.fromJSON(JSON.parse(content));
466792
466923
  const state = project.getState();
466793
- const outputPath = options.output ? resolve64(process.cwd(), options.output) : resolve64(process.cwd(), `${basename17(projectPath, ".vibe.json")}.${options.format ?? "mp4"}`);
466924
+ const outputPath = options.output ? resolve64(process.cwd(), options.output) : resolve64(process.cwd(), `${timelineBaseName(projectPath)}.${options.format ?? "mp4"}`);
466794
466925
  const quality = ["draft", "standard", "high"].includes(options.preset ?? "") ? options.preset : "standard";
466795
466926
  const backend = createHyperframesBackend2();
466796
466927
  spinner2.text = "Rendering with Hyperframes...";
@@ -466827,9 +466958,9 @@ var exportVideoTool = defineTool({
466827
466958
  name: "export_video",
466828
466959
  category: "export",
466829
466960
  cost: "free",
466830
- description: "Export a VibeFrame project to a video file (MP4, WebM, or MOV). Requires FFmpeg.",
466961
+ description: "Export a VibeFrame timeline to a video file (MP4, WebM, or MOV). Requires FFmpeg.",
466831
466962
  schema: z10.object({
466832
- projectPath: z10.string().describe("Path to the .vibe.json project file"),
466963
+ projectPath: z10.string().describe("Path to timeline.json, a timeline directory, or a legacy *.vibe.json file"),
466833
466964
  outputPath: z10.string().describe("Output video file path (e.g., output.mp4)"),
466834
466965
  preset: z10.enum(["draft", "standard", "high", "ultra"]).optional().describe("Quality preset (default: standard)"),
466835
466966
  format: z10.enum(["mp4", "webm", "mov"]).optional().describe("Output format (default: mp4)"),
@@ -466854,11 +466985,12 @@ var exportVideoTool = defineTool({
466854
466985
  var exportTools = [exportVideoTool];
466855
466986
 
466856
466987
  // ../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";
466988
+ import { readFile as readFile32, writeFile as writeFile43, readdir as readdir5, stat as stat4, access as access7, unlink as unlink7 } from "node:fs/promises";
466989
+ import { resolve as resolve61, join as join33, basename as basename17, extname as extname12 } from "node:path";
466859
466990
  import { z as z11 } from "zod";
466860
466991
  init_engine();
466861
466992
  init_exec_safe();
466993
+ init_project_resolver();
466862
466994
  function matchPattern(filename, pattern) {
466863
466995
  const regex2 = new RegExp(
466864
466996
  "^" + pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".") + "$",
@@ -466981,7 +467113,7 @@ var fsWriteTool = defineTool({
466981
467113
  async execute(args, ctx) {
466982
467114
  try {
466983
467115
  const absPath = resolve61(ctx.workingDirectory, args.path);
466984
- await writeFile42(absPath, args.content, "utf-8");
467116
+ await writeFile43(absPath, args.content, "utf-8");
466985
467117
  return { success: true, data: { bytes: args.content.length }, humanLines: [`File written: ${args.path} (${formatSize(args.content.length)})`] };
466986
467118
  } catch (error) {
466987
467119
  return { success: false, error: `Failed to write file: ${error instanceof Error ? error.message : String(error)}` };
@@ -467000,7 +467132,7 @@ var fsExistsTool = defineTool({
467000
467132
  async execute(args, ctx) {
467001
467133
  const absPath = resolve61(ctx.workingDirectory, args.path);
467002
467134
  try {
467003
- await access6(absPath);
467135
+ await access7(absPath);
467004
467136
  const stats = await stat4(absPath);
467005
467137
  const type = stats.isDirectory() ? "directory" : "file";
467006
467138
  return { success: true, data: { exists: true, type }, humanLines: [`${type} exists: ${args.path}`] };
@@ -467016,7 +467148,7 @@ var batchImportTool = defineTool({
467016
467148
  surfaces: ["agent"],
467017
467149
  description: "Import multiple media files from a directory into a project. Scans directory for video, audio, and image files.",
467018
467150
  schema: z11.object({
467019
- project: z11.string().describe("Project file path"),
467151
+ project: z11.string().describe("Timeline file or directory"),
467020
467152
  directory: z11.string().describe("Directory containing media files to import"),
467021
467153
  recursive: z11.boolean().optional().describe("Search subdirectories recursively (default: false)"),
467022
467154
  filter: z11.string().optional().describe("Filter files by extension, comma-separated (e.g., '.mp4,.mov')"),
@@ -467053,7 +467185,7 @@ var batchImportTool = defineTool({
467053
467185
  mediaFiles.sort();
467054
467186
  const addedSources = [];
467055
467187
  for (const mediaFile of mediaFiles) {
467056
- const mediaName = basename16(mediaFile);
467188
+ const mediaName = basename17(mediaFile);
467057
467189
  const mediaType = detectMediaType(mediaFile);
467058
467190
  let duration = imageDuration;
467059
467191
  if (mediaType !== "image") {
@@ -467063,7 +467195,7 @@ var batchImportTool = defineTool({
467063
467195
  const source3 = project.addSource({ name: mediaName, type: mediaType, url: mediaFile, duration });
467064
467196
  addedSources.push({ id: source3.id, name: mediaName, type: mediaType });
467065
467197
  }
467066
- await writeFile42(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467198
+ await writeFile43(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467067
467199
  return {
467068
467200
  success: true,
467069
467201
  data: { count: addedSources.length, sources: addedSources },
@@ -467085,7 +467217,7 @@ var batchConcatTool = defineTool({
467085
467217
  surfaces: ["agent"],
467086
467218
  description: "Concatenate multiple sources into sequential clips on the timeline",
467087
467219
  schema: z11.object({
467088
- project: z11.string().describe("Project file path"),
467220
+ project: z11.string().describe("Timeline file or directory"),
467089
467221
  sourceIds: z11.array(z11.string()).optional().describe("Source IDs to concatenate. If empty with useAll=true, uses all sources."),
467090
467222
  useAll: z11.boolean().optional().describe("Use all sources in the project (default: false)"),
467091
467223
  trackId: z11.string().optional().describe("Track to place clips on (auto-selects if not specified)"),
@@ -467131,7 +467263,7 @@ var batchConcatTool = defineTool({
467131
467263
  createdClips.push({ id: clip.id, sourceName: source3.name, startTime: currentTime, duration: source3.duration });
467132
467264
  currentTime += source3.duration + gap;
467133
467265
  }
467134
- await writeFile42(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467266
+ await writeFile43(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467135
467267
  const totalDuration = currentTime - gap - startTime;
467136
467268
  return {
467137
467269
  success: true,
@@ -467154,7 +467286,7 @@ var batchApplyEffectTool = defineTool({
467154
467286
  surfaces: ["agent"],
467155
467287
  description: "Apply an effect to multiple clips at once",
467156
467288
  schema: z11.object({
467157
- project: z11.string().describe("Project file path"),
467289
+ project: z11.string().describe("Timeline file or directory"),
467158
467290
  clipIds: z11.array(z11.string()).optional().describe("Clip IDs to apply effect to. If empty with useAll=true, applies to all clips."),
467159
467291
  useAll: z11.boolean().optional().describe("Apply to all clips in the project (default: false)"),
467160
467292
  effectType: z11.enum(["fadeIn", "fadeOut", "blur", "brightness", "contrast", "saturation", "speed", "volume"]).describe("Effect type to apply"),
@@ -467192,7 +467324,7 @@ var batchApplyEffectTool = defineTool({
467192
467324
  });
467193
467325
  if (effect) appliedEffects.push({ clipId: clip.id, effectId: effect.id });
467194
467326
  }
467195
- await writeFile42(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467327
+ await writeFile43(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467196
467328
  return {
467197
467329
  success: true,
467198
467330
  data: { applied: appliedEffects.length, effectType: args.effectType },
@@ -467203,17 +467335,6 @@ var batchApplyEffectTool = defineTool({
467203
467335
  }
467204
467336
  }
467205
467337
  });
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
467338
  var timelineClearTool = defineTool({
467218
467339
  name: "timeline_clear",
467219
467340
  category: "agent-only",
@@ -467221,13 +467342,13 @@ var timelineClearTool = defineTool({
467221
467342
  surfaces: ["agent"],
467222
467343
  description: "Clear timeline contents (remove clips, tracks, or sources)",
467223
467344
  schema: z11.object({
467224
- project: z11.string().describe("Project file path"),
467345
+ project: z11.string().describe("Timeline file or directory"),
467225
467346
  what: z11.enum(["clips", "tracks", "sources", "all"]).optional().describe("What to clear: clips (default), tracks, sources, or all"),
467226
467347
  keepTracks: z11.boolean().optional().describe("When clearing 'all', keep default empty tracks (default: true)")
467227
467348
  }),
467228
467349
  async execute(args, ctx) {
467229
467350
  try {
467230
- const filePath = await resolveProjectPath2(args.project, ctx.workingDirectory);
467351
+ const filePath = await resolveTimelineFile(args.project, ctx.workingDirectory);
467231
467352
  const content = await readFile32(filePath, "utf-8");
467232
467353
  const data = JSON.parse(content);
467233
467354
  const project = Project.fromJSON(data);
@@ -467270,7 +467391,7 @@ var timelineClearTool = defineTool({
467270
467391
  removed.sources++;
467271
467392
  }
467272
467393
  }
467273
- await writeFile42(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467394
+ await writeFile43(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467274
467395
  const parts = [];
467275
467396
  if (removed.clips > 0) parts.push(`${removed.clips} clips`);
467276
467397
  if (removed.tracks > 0) parts.push(`${removed.tracks} tracks`);
@@ -467293,16 +467414,16 @@ var projectSetTool = defineTool({
467293
467414
  category: "agent-only",
467294
467415
  cost: "free",
467295
467416
  surfaces: ["agent"],
467296
- description: "Update project settings (name, aspect ratio, frame rate)",
467417
+ description: "Update timeline settings (name, aspect ratio, frame rate)",
467297
467418
  schema: z11.object({
467298
- projectPath: z11.string().describe("Project file path"),
467419
+ projectPath: z11.string().describe("Timeline file or directory"),
467299
467420
  name: z11.string().optional().describe("New project name"),
467300
467421
  aspectRatio: z11.enum(["16:9", "9:16", "1:1", "4:5"]).optional().describe("New aspect ratio"),
467301
467422
  fps: z11.number().optional().describe("New frame rate")
467302
467423
  }),
467303
467424
  async execute(args, ctx) {
467304
467425
  try {
467305
- const filePath = await resolveProjectPath2(args.projectPath, ctx.workingDirectory);
467426
+ const filePath = await resolveTimelineFile(args.projectPath, ctx.workingDirectory);
467306
467427
  const content = await readFile32(filePath, "utf-8");
467307
467428
  const data = JSON.parse(content);
467308
467429
  const project = Project.fromJSON(data);
@@ -467319,7 +467440,7 @@ var projectSetTool = defineTool({
467319
467440
  project.setFrameRate(args.fps);
467320
467441
  updates.push(`Frame Rate: ${args.fps} fps`);
467321
467442
  }
467322
- await writeFile42(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467443
+ await writeFile43(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
467323
467444
  return {
467324
467445
  success: true,
467325
467446
  data: { updates },
@@ -467340,11 +467461,11 @@ var projectOpenTool = defineTool({
467340
467461
  surfaces: ["agent"],
467341
467462
  description: "Open an existing project and set it as the current context",
467342
467463
  schema: z11.object({
467343
- projectPath: z11.string().describe("Project file path")
467464
+ projectPath: z11.string().describe("Timeline file or directory")
467344
467465
  }),
467345
467466
  async execute(args, ctx) {
467346
467467
  try {
467347
- const filePath = await resolveProjectPath2(args.projectPath, ctx.workingDirectory);
467468
+ const filePath = await resolveTimelineFile(args.projectPath, ctx.workingDirectory);
467348
467469
  const { project } = await loadProject(filePath, "");
467349
467470
  ctx.agent?.setProjectPath(filePath);
467350
467471
  const summary = project.getSummary();
@@ -467378,7 +467499,7 @@ var projectSaveTool = defineTool({
467378
467499
  surfaces: ["agent"],
467379
467500
  description: "Save the current project (uses ctx.agent.projectPath if no path given)",
467380
467501
  schema: z11.object({
467381
- projectPath: z11.string().optional().describe("Project file path (uses current agent project if omitted)")
467502
+ projectPath: z11.string().optional().describe("Timeline file or directory (uses current agent timeline if omitted)")
467382
467503
  }),
467383
467504
  async execute(args, ctx) {
467384
467505
  const path14 = args.projectPath ?? ctx.agent?.projectPath ?? null;
@@ -467389,7 +467510,7 @@ var projectSaveTool = defineTool({
467389
467510
  };
467390
467511
  }
467391
467512
  try {
467392
- const filePath = await resolveProjectPath2(path14, ctx.workingDirectory);
467513
+ const filePath = await resolveTimelineFile(path14, ctx.workingDirectory);
467393
467514
  const { project, absPath } = await loadProject(filePath, "");
467394
467515
  await saveProject(absPath, project);
467395
467516
  return {
@@ -467412,7 +467533,7 @@ var exportAudioTool = defineTool({
467412
467533
  surfaces: ["agent"],
467413
467534
  description: "Export audio track from a project. Not implemented \u2014 use export_video then strip audio with FFmpeg.",
467414
467535
  schema: z11.object({
467415
- project: z11.string().describe("Project file path"),
467536
+ project: z11.string().describe("Timeline file or directory"),
467416
467537
  output: z11.string().optional().describe("Output audio file path"),
467417
467538
  format: z11.enum(["mp3", "wav", "aac"]).optional().describe("Output format (mp3, wav, aac)")
467418
467539
  }),
@@ -467430,7 +467551,7 @@ var exportSubtitlesTool = defineTool({
467430
467551
  surfaces: ["agent"],
467431
467552
  description: "Export subtitles from transcription. Not implemented \u2014 use audio_transcribe to generate subtitles from audio.",
467432
467553
  schema: z11.object({
467433
- project: z11.string().describe("Project file path"),
467554
+ project: z11.string().describe("Timeline file or directory"),
467434
467555
  output: z11.string().optional().describe("Output subtitle file path"),
467435
467556
  format: z11.enum(["srt", "vtt"]).optional().describe("Subtitle format (srt, vtt)")
467436
467557
  }),
@@ -467673,7 +467794,7 @@ var mediaConcatTool = defineTool({
467673
467794
  } else {
467674
467795
  const tempList = resolve61(ctx.workingDirectory, `concat-list-${Date.now()}.txt`);
467675
467796
  const listContent = args.inputs.map((i) => `file '${resolve61(ctx.workingDirectory, i)}'`).join("\n");
467676
- await writeFile42(tempList, listContent, "utf-8");
467797
+ await writeFile43(tempList, listContent, "utf-8");
467677
467798
  try {
467678
467799
  await execSafe(
467679
467800
  "ffmpeg",
@@ -468310,7 +468431,7 @@ async function readResource(uri) {
468310
468431
  uri,
468311
468432
  mimeType: "application/json",
468312
468433
  text: JSON.stringify({
468313
- error: "No project loaded. Set VIBE_PROJECT_PATH environment variable or use project_create tool."
468434
+ error: "No timeline loaded. Set VIBE_PROJECT_PATH to timeline.json or use timeline_create."
468314
468435
  })
468315
468436
  }
468316
468437
  ]
@@ -468406,7 +468527,7 @@ var prompts = [
468406
468527
  },
468407
468528
  {
468408
468529
  name: "projectPath",
468409
- description: "Path to the project file",
468530
+ description: "Path to timeline.json or a legacy *.vibe.json file",
468410
468531
  required: false
468411
468532
  }
468412
468533
  ]
@@ -468524,7 +468645,7 @@ function getPrompt(name, args) {
468524
468645
  type: "text",
468525
468646
  text: `Help me edit a video with the following instruction: "${args.instruction}"
468526
468647
 
468527
- ${args.projectPath ? `Project file: ${args.projectPath}` : "No project file specified."}
468648
+ ${args.projectPath ? `Timeline file: ${args.projectPath}` : "No timeline file specified."}
468528
468649
 
468529
468650
  Please analyze the request and suggest the appropriate timeline tools to use. Consider:
468530
468651
  1. What clips need to be affected?