@mixio-pro/kalaasetu-mcp 2.3.27 → 2.3.28-exp

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 (149) hide show
  1. package/bin/cli.js +1 -1
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +22 -0
  4. package/dist/storage/gcs.d.ts +12 -0
  5. package/dist/storage/gcs.js +87 -0
  6. package/dist/storage/index.d.ts +2 -0
  7. package/dist/storage/index.js +26 -0
  8. package/dist/storage/interface.d.ts +7 -0
  9. package/dist/storage/interface.js +1 -0
  10. package/dist/storage/local.d.ts +10 -0
  11. package/dist/storage/local.js +50 -0
  12. package/dist/tools/byteplus/common.d.ts +43 -0
  13. package/dist/tools/byteplus/common.js +162 -0
  14. package/dist/tools/byteplus/image-to-video.d.ts +60 -0
  15. package/dist/tools/byteplus/image-to-video.js +303 -0
  16. package/dist/tools/byteplus/index.js +3 -0
  17. package/dist/tools/byteplus/reference-to-video.d.ts +58 -0
  18. package/dist/tools/byteplus/reference-to-video.js +257 -0
  19. package/dist/tools/byteplus/scene-video.d.ts +57 -0
  20. package/dist/tools/byteplus/scene-video.js +344 -0
  21. package/dist/tools/fal/config.d.ts +61 -0
  22. package/dist/tools/fal/config.js +303 -0
  23. package/dist/tools/fal/dynamic-tools.d.ts +44 -0
  24. package/dist/tools/fal/dynamic-tools.js +332 -0
  25. package/dist/tools/fal/generate.d.ts +41 -0
  26. package/dist/tools/fal/generate.js +326 -0
  27. package/{src/tools/fal/index.ts → dist/tools/fal/index.d.ts} +0 -1
  28. package/dist/tools/fal/index.js +8 -0
  29. package/dist/tools/fal/models.d.ts +31 -0
  30. package/dist/tools/fal/models.js +236 -0
  31. package/dist/tools/fal/storage.d.ts +19 -0
  32. package/dist/tools/fal/storage.js +107 -0
  33. package/dist/tools/generate-image.d.ts +26 -0
  34. package/dist/tools/generate-image.js +228 -0
  35. package/dist/tools/generate-scene-image.d.ts +34 -0
  36. package/dist/tools/generate-scene-image.js +279 -0
  37. package/dist/tools/get-status.d.ts +25 -0
  38. package/dist/tools/get-status.js +366 -0
  39. package/dist/tools/image-to-video.d.ts +48 -0
  40. package/dist/tools/image-to-video.js +377 -0
  41. package/dist/tools/ingredients-to-video.d.ts +48 -0
  42. package/dist/tools/ingredients-to-video.js +389 -0
  43. package/dist/tools/mixio/common.d.ts +26 -0
  44. package/dist/tools/mixio/common.js +124 -0
  45. package/dist/tools/mixio/face-swap.d.ts +20 -0
  46. package/dist/tools/mixio/face-swap.js +66 -0
  47. package/dist/tools/mixio/grok.d.ts +56 -0
  48. package/dist/tools/mixio/grok.js +158 -0
  49. package/dist/tools/mixio/index.js +5 -0
  50. package/dist/tools/mixio/multi-angle-batch.d.ts +46 -0
  51. package/dist/tools/mixio/multi-angle-batch.js +91 -0
  52. package/dist/tools/mixio/multi-angle.d.ts +42 -0
  53. package/dist/tools/mixio/multi-angle.js +90 -0
  54. package/dist/tools/mixio/next-scene.d.ts +20 -0
  55. package/dist/tools/mixio/next-scene.js +60 -0
  56. package/dist/tools/perplexity.d.ts +29 -0
  57. package/dist/tools/perplexity.js +196 -0
  58. package/dist/tools/smallestai/client.d.ts +5 -0
  59. package/dist/tools/smallestai/client.js +40 -0
  60. package/{src/tools/smallestai/index.ts → dist/tools/smallestai/index.d.ts} +1 -6
  61. package/dist/tools/smallestai/index.js +4 -0
  62. package/dist/tools/smallestai/stt.d.ts +14 -0
  63. package/dist/tools/smallestai/stt.js +55 -0
  64. package/dist/tools/smallestai/tts.d.ts +35 -0
  65. package/dist/tools/smallestai/tts.js +100 -0
  66. package/dist/tools/smallestai/voice-clones.d.ts +47 -0
  67. package/dist/tools/smallestai/voice-clones.js +150 -0
  68. package/dist/tools/youtube.d.ts +14 -0
  69. package/dist/tools/youtube.js +67 -0
  70. package/dist/utils/endpoint-encoder.d.ts +9 -0
  71. package/dist/utils/endpoint-encoder.js +24 -0
  72. package/dist/utils/filename.d.ts +6 -0
  73. package/dist/utils/filename.js +33 -0
  74. package/dist/utils/google-auth.d.ts +13 -0
  75. package/dist/utils/google-auth.js +119 -0
  76. package/dist/utils/image-grid.d.ts +15 -0
  77. package/dist/utils/image-grid.js +103 -0
  78. package/dist/utils/index.d.ts +1 -0
  79. package/dist/utils/index.js +1 -0
  80. package/dist/utils/logger.d.ts +6 -0
  81. package/dist/utils/logger.js +82 -0
  82. package/dist/utils/openmeter.d.ts +56 -0
  83. package/dist/utils/openmeter.js +184 -0
  84. package/dist/utils/remote-config.d.ts +6 -0
  85. package/dist/utils/remote-config.js +125 -0
  86. package/dist/utils/remote-sync.d.ts +21 -0
  87. package/dist/utils/remote-sync.js +71 -0
  88. package/dist/utils/sanitize.d.ts +10 -0
  89. package/dist/utils/sanitize.js +33 -0
  90. package/dist/utils/tool-credits.d.ts +22 -0
  91. package/dist/utils/tool-credits.js +277 -0
  92. package/dist/utils/tool-pricing.d.ts +61 -0
  93. package/dist/utils/tool-pricing.js +136 -0
  94. package/dist/utils/tool-wrapper.d.ts +43 -0
  95. package/dist/utils/tool-wrapper.js +121 -0
  96. package/dist/utils/url-file.d.ts +11 -0
  97. package/dist/utils/url-file.js +79 -0
  98. package/package.json +7 -5
  99. package/src/index.ts +0 -162
  100. package/src/runtime-env.test.ts +0 -77
  101. package/src/storage/gcs.ts +0 -116
  102. package/src/storage/index.ts +0 -32
  103. package/src/storage/interface.ts +0 -7
  104. package/src/storage/local.ts +0 -58
  105. package/src/tools/byteplus/README.md +0 -52
  106. package/src/tools/byteplus/common.ts +0 -206
  107. package/src/tools/byteplus/image-to-video.ts +0 -419
  108. package/src/tools/byteplus/reference-to-video.ts +0 -351
  109. package/src/tools/byteplus/scene-video.ts +0 -466
  110. package/src/tools/fal/config.ts +0 -430
  111. package/src/tools/fal/dynamic-tools.ts +0 -454
  112. package/src/tools/fal/generate.ts +0 -453
  113. package/src/tools/fal/models.ts +0 -297
  114. package/src/tools/fal/storage.ts +0 -139
  115. package/src/tools/generate-image.ts +0 -289
  116. package/src/tools/generate-scene-image.ts +0 -362
  117. package/src/tools/get-status.ts +0 -466
  118. package/src/tools/image-to-video.ts +0 -492
  119. package/src/tools/ingredients-to-video.ts +0 -530
  120. package/src/tools/mixio/common.ts +0 -155
  121. package/src/tools/mixio/face-swap.ts +0 -105
  122. package/src/tools/mixio/grok.ts +0 -233
  123. package/src/tools/mixio/multi-angle-batch.ts +0 -132
  124. package/src/tools/mixio/multi-angle.ts +0 -124
  125. package/src/tools/mixio/next-scene.ts +0 -87
  126. package/src/tools/perplexity.ts +0 -260
  127. package/src/tools/smallestai/client.ts +0 -54
  128. package/src/tools/smallestai/stt.ts +0 -72
  129. package/src/tools/smallestai/tts.ts +0 -135
  130. package/src/tools/smallestai/voice-clones.ts +0 -194
  131. package/src/tools/youtube.ts +0 -89
  132. package/src/utils/endpoint-encoder.ts +0 -28
  133. package/src/utils/filename.ts +0 -38
  134. package/src/utils/google-auth.ts +0 -166
  135. package/src/utils/image-grid.ts +0 -125
  136. package/src/utils/index.ts +0 -0
  137. package/src/utils/logger.ts +0 -104
  138. package/src/utils/openmeter.ts +0 -246
  139. package/src/utils/remote-config.test.ts +0 -162
  140. package/src/utils/remote-config.ts +0 -157
  141. package/src/utils/remote-sync.ts +0 -98
  142. package/src/utils/sanitize.ts +0 -35
  143. package/src/utils/tool-credits.ts +0 -319
  144. package/src/utils/tool-pricing.ts +0 -239
  145. package/src/utils/tool-wrapper.test.ts +0 -55
  146. package/src/utils/tool-wrapper.ts +0 -174
  147. package/src/utils/url-file.ts +0 -92
  148. /package/{src/tools/byteplus/index.ts → dist/tools/byteplus/index.d.ts} +0 -0
  149. /package/{src/tools/mixio/index.ts → dist/tools/mixio/index.d.ts} +0 -0
package/bin/cli.js CHANGED
@@ -7,7 +7,7 @@ import { dirname, join } from 'path';
7
7
 
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = dirname(__filename);
10
- const indexPath = join(__dirname, '..', 'src', 'index.ts');
10
+ const indexPath = join(__dirname, '..', 'dist', 'index.js');
11
11
 
12
12
  // Try to run with Bun first
13
13
  const bunProcess = spawn('bun', [indexPath], {
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+ var kw=Object.defineProperty;var Nw=(i)=>i;function Rw(i,n){this[i]=Nw.bind(null,n)}var ji=(i,n)=>{for(var w in n)kw(i,w,{get:n[w],enumerable:!0,configurable:!0,set:Rw.bind(n,w)})};var c=(i,n)=>()=>(i&&(n=i(i=0)),n);var Tn=import.meta.require;import yi from"winston";import En from"winston-transport-sentry-node";import xi from"path";import Ln from"fs";import cw from"os";import Pw from"crypto";var xw,Ui,ui,Uw,uw,pw="https://349c280f4b1c731bc1ac1a1189cae5e7@o4510770034245632.ingest.us.sentry.io/4510770047025152",ow,kn,pi,Nn,tw,lw,Pi,gw,In,M;var D=c(()=>{xw=En.default||En,{combine:Ui,timestamp:ui,printf:Uw,colorize:uw}=yi.format,ow=Uw(({level:i,message:n,timestamp:w})=>{return`${w} [${i}] ${n}`}),kn=process.env.LOG_LEVEL||"info",pi=[new yi.transports.Console({stderrLevels:["error","warn","info","http","verbose","debug","silly"],format:Ui(uw(),ui({format:"HH:mm:ss"}),ow)})],Nn=process.cwd(),tw=Pw.createHash("md5").update(Nn).digest("hex").substring(0,8),lw=xi.basename(Nn).replace(/\s+/g,"-"),Pi=xi.join(cw.homedir(),".mixio","logs"),gw=xi.join(Pi,`${tw}-${lw}.log`);try{if(!Ln.existsSync(Pi))Ln.mkdirSync(Pi,{recursive:!0});pi.push(new yi.transports.File({filename:gw,level:kn,format:Ui(ui(),yi.format.json())}))}catch(i){console.error("Failed to initialize file logging transport:",i)}In=process.env.SENTRY_DSN||pw;if(In)pi.push(new xw({sentry:{dsn:In,environment:"development"},level:"error"}));M=yi.createLogger({level:kn,format:Ui(ui(),yi.format.json()),defaultMeta:{service:"kalaasetu-mcp"},transports:pi});M.info("Sentry error tracking enabled");console.log=(...i)=>M.info(i.map(String).join(" "));console.info=(...i)=>M.info(i.map(String).join(" "));console.warn=(...i)=>M.warn(i.map(String).join(" "));console.error=(...i)=>M.error(i.map(String).join(" "))});import*as oi from"fs";import*as Di from"path";import{mkdir as aw,readFile as Rn,writeFile as sw}from"fs/promises";async function cn(i){let{name:n,remoteUrl:w,envVar:b,fallback:h,validate:_}=i,y=Di.join(zn,`${n}.json`);if(b&&process.env[b]){let $=process.env[b];try{if(oi.existsSync($)){let m=await Rn($,"utf-8"),v=JSON.parse(m);if(!_||_(v))return M.info(`[Sync] Using local override from ${b}: ${$}`),v}}catch(m){M.info(`[Sync] Failed to read local override from ${b}: ${m}`)}}try{M.info(`[Sync] Attempting to fetch ${n} from ${w}...`);let $=await fetch(w,{signal:AbortSignal.timeout(5000)});if($.ok){let m=await $.json();if(!_||_(m))return await aw(zn,{recursive:!0}),await sw(y,JSON.stringify(m,null,2)),M.info(`[Sync] Successfully updated ${n} and cached at ${y}`),m;M.info(`[Sync] Remote data for ${n} failed validation.`)}else M.info(`[Sync] Remote fetch for ${n} failed with status: ${$.status}`)}catch($){M.info(`[Sync] Error fetching ${n} from remote: ${$}`)}try{if(oi.existsSync(y)){let $=await Rn(y,"utf-8"),m=JSON.parse($);if(m&&(!_||_(m)))return M.info(`[Sync] Using cached version of ${n} from ${y}`),m}}catch($){M.info(`[Sync] Failed to read cache for ${n}: ${$}`)}return M.info(`[Sync] All sync methods failed for ${n}. Using internal defaults.`),h}var __dirname="/Users/kaustubh/playground/indie/mixio/kaustubha/kalaasetu/mcp/ts/src/utils",zn;var Pn=c(()=>{D();zn=Di.resolve(__dirname,"..","..",".cache")});import*as Ci from"fs";import*as Si from"path";function g(){let i=process.env[xn];if(!i)throw Error(`${xn} environment variable not set`);return i}function Ai(i){return typeof i==="object"&&i!==null&&!Array.isArray(i)}function rw(i,n){if(!Ai(i)||typeof i.value!=="number")return M.warn(`[FAL Config] Ignoring invalid pricing range rule for preset '${n}'.`),null;if(i.min!==void 0&&typeof i.min!=="number"||i.max!==void 0&&typeof i.max!=="number")return M.warn(`[FAL Config] Ignoring invalid pricing range boundaries for preset '${n}'.`),null;if(i.includeMin!==void 0&&typeof i.includeMin!=="boolean"||i.includeMax!==void 0&&typeof i.includeMax!=="boolean")return M.warn(`[FAL Config] Ignoring invalid pricing range inclusivity for preset '${n}'.`),null;return{value:i.value,...i.min!==void 0?{min:i.min}:{},...i.max!==void 0?{max:i.max}:{},...i.includeMin!==void 0?{includeMin:i.includeMin}:{},...i.includeMax!==void 0?{includeMax:i.includeMax}:{}}}function ew(i,n){if(!Ai(i))return M.warn(`[FAL Config] Ignoring non-object pricing modifier for preset '${n}'.`),null;let{field:w,mode:b,operation:h}=i;if(typeof w!=="string"||b!=="discrete"&&b!=="range"&&b!=="step"||h!=="add"&&h!=="multiply")return M.warn(`[FAL Config] Ignoring invalid pricing modifier shape for preset '${n}'.`),null;if(b==="discrete"){if(!Ai(i.map))return M.warn(`[FAL Config] Ignoring invalid discrete pricing map for preset '${n}'.`),null;let _={};for(let[y,$]of Object.entries(i.map))if(typeof $==="number")_[y]=$;if(Object.keys(_).length===0)return M.warn(`[FAL Config] Ignoring empty discrete pricing map for preset '${n}'.`),null;return{field:w,mode:b,operation:h,map:_}}if(b==="range"){if(!Array.isArray(i.ranges))return M.warn(`[FAL Config] Ignoring invalid range pricing rules for preset '${n}'.`),null;let _=i.ranges.map((y)=>rw(y,n)).filter((y)=>y!==null);if(_.length===0)return M.warn(`[FAL Config] Ignoring empty range pricing rules for preset '${n}'.`),null;return{field:w,mode:b,operation:h,ranges:_}}if(typeof i.step!=="number"||i.step<=0)return M.warn(`[FAL Config] Ignoring invalid step pricing 'step' value for preset '${n}'.`),null;if(typeof i.valuePerStep!=="number")return M.warn(`[FAL Config] Ignoring invalid step pricing 'valuePerStep' for preset '${n}'.`),null;if(i.offset!==void 0&&typeof i.offset!=="number")return M.warn(`[FAL Config] Ignoring invalid step pricing 'offset' for preset '${n}'.`),null;return{field:w,mode:b,operation:h,step:i.step,valuePerStep:i.valuePerStep,...i.offset!==void 0?{offset:i.offset}:{}}}function ib(i,n){if(!Ai(i)||typeof i.baseCredits!=="number"){M.warn(`[FAL Config] Ignoring invalid pricing block for preset '${n}'.`);return}let w={baseCredits:i.baseCredits};if(Array.isArray(i.modifiers)){let b=i.modifiers.map((h)=>ew(h,n)).filter((h)=>h!==null);if(b.length>0)w.modifiers=b}if(typeof i.minCredits==="number")w.minCredits=i.minCredits;if(typeof i.maxCredits==="number")w.maxCredits=i.maxCredits;if(i.rounding==="ceil"||i.rounding==="floor"||i.rounding==="round"||i.rounding==="none")w.rounding=i.rounding;return w}function nb(i){if(i.pricing===void 0)return i;let n=ib(i.pricing,i.presetName);if(!n){let{pricing:w,...b}=i;return b}return{...i,pricing:n}}function wb(i){return{presets:i.presets.map(nb)}}async function on(){let i=process.env.FAL_CONFIG_URL||"https://config.mixio.pro/mcp/fal/config.json",n=await cn({name:"fal-config",remoteUrl:i,envVar:"FAL_CONFIG_JSON_PATH",fallback:{presets:pn},validate:(w)=>{return w&&Array.isArray(w.presets)}});return ti=wb(n),ti}function u(){return ti}function tn(i){let n=process.env.FAL_CONFIG_JSON_PATH;if(!n){let w=["fal-config.json",Si.join(__dirname,"../../fal-config.json"),Si.join(__dirname,"../../../fal-config.json")];for(let b of w)if(Ci.existsSync(b)){n=b;break}}if(!n)return M.warn("Cannot save config: no config file path found."),!1;try{let w=Si.resolve(n);return Ci.writeFileSync(w,JSON.stringify(i,null,2),"utf-8"),!0}catch(w){return M.error(`Error saving FAL config: ${w.message}`),!1}}var __dirname="/Users/kaustubh/playground/indie/mixio/kaustubha/kalaasetu/mcp/ts/src/tools/fal",O="https://queue.fal.run",Un="https://rest.alpha.fal.ai",un=30000,wi=600000,xn="FAL_KEY",pn,ti;var a=c(()=>{D();Pn();pn=[{presetName:"i2v_pro",intent:"Generate high-quality cinematic video with audio from a static image using LTX Video 2.0 Pro.",modelId:"fal-ai/ltx-2/image-to-video",inputType:"image",outputType:"video",input_schema:{prompt:{type:"string",description:"Detailed description of the motion and scene."},image_url:{type:"string",description:"URL of the start frame image."},negative_prompt:{type:"string",description:"Elements to avoid in the video."},aspect_ratio:{type:"string",enum:["16:9","9:16","1:1","4:3","3:4"],default:"16:9"},completion_mode:{type:"string",enum:["time","motion"],default:"time"},duration:{type:"string",enum:["5","10"],default:"5",description:"Duration in seconds."},seed:{type:"number",description:"Random seed for reproducibility."}},transformers:{types:{duration:"number"}}},{presetName:"v2v_retake",intent:"Perform selective video editing and targetted alterations on existing videos using LTX-2.",modelId:"fal-ai/ltx-2/retake-video",inputType:"video",outputType:"video",input_schema:{prompt:{type:"string",description:"New prompt defining the changes."},video_url:{type:"string",description:"URL of the video to edit."},start_time:{type:"number",description:"Start timestamp for the edit.",default:0},end_time:{type:"number",description:"End timestamp for the edit."}}}],ti={presets:pn}});function ln(i){if(typeof i==="number"&&Number.isFinite(i))return i;if(typeof i==="string"){let n=Number(i);if(Number.isFinite(n))return n}return}function bb(i,n){switch(n){case"floor":return Math.floor(i);case"round":return Math.round(i);case"none":return i;case"ceil":default:return Math.ceil(i)}}function hb(i,n){let w=n[i.field];if(w===void 0)return{matched:!1,input:w};if(i.mode==="discrete"){let m=String(w),v=i.map[m];if(v===void 0)return{matched:!1,input:w};return{matched:!0,effect:v,input:w}}if(i.mode==="range"){let m=ln(w);if(m===void 0)return{matched:!1,input:w};for(let v of i.ranges){let V=v.includeMin??!0,J=v.includeMax??!0,d=v.min===void 0?!0:V?m>=v.min:m>v.min,Z=v.max===void 0?!0:J?m<=v.max:m<v.max;if(d&&Z)return{matched:!0,effect:v.value,input:w}}return{matched:!1,input:w}}let b=ln(w);if(b===void 0||i.step<=0)return{matched:!1,input:w};let h=i.offset??0,_=b-h;if(_<0)return{matched:!1,input:w};return{matched:!0,effect:Math.floor(_/i.step)*i.valuePerStep,input:w}}function gi(i,n={}){let w=i.modifiers??[],b=i.baseCredits,h=[];for(let V of w){let J=b,d=hb(V,n);if(!d.matched||d.effect===void 0){h.push({field:V.field,mode:V.mode,operation:V.operation,input:d.input,matched:!1,before:J,after:b});continue}b=V.operation==="add"?b+d.effect:b*d.effect,h.push({field:V.field,mode:V.mode,operation:V.operation,input:d.input,matched:!0,effect:d.effect,before:J,after:b})}let _=b,y=i.rounding??"ceil",$=bb(_,y),m=$,v=$;if(i.minCredits!==void 0)v=Math.max(v,i.minCredits);if(i.maxCredits!==void 0)v=Math.min(v,i.maxCredits);return{credits:v,baseCredits:i.baseCredits,preRoundedCredits:_,roundedCredits:$,rounding:y,clamp:{minCredits:i.minCredits,maxCredits:i.maxCredits,applied:m!==v,before:m,after:v},modifiers:h}}function si(i,n){if(n?.resume_endpoint)return{credits:0,provider:i.startsWith("fal_")||i.startsWith("mixio_")?"fal-ai":"unknown",chargeable:!1,modelName:i,pricingSource:"none"};if(i.startsWith("fal_")||i.startsWith("mixio_")){let h=i.startsWith("fal_")?i.slice(4):i.slice(6);if(h==="generate"&&n?.preset_name)h=String(n.preset_name);let _=u().presets.find(($)=>$.presetName===h||`fal_${$.presetName}`===i||`mixio_${$.presetName}`===i);if(_?.pricing){let $=gi(_.pricing,n||{});return{credits:$.credits,provider:"fal-ai",chargeable:$.credits>0,modelName:_.modelId||i,pricingSource:"fal-preset-pricing",pricingBreakdown:$}}if(_)return{credits:15,provider:"fal-ai",chargeable:!0,modelName:_.modelId||i,pricingSource:"legacy-fallback"};let y=ai[i];if(y)return y;return{credits:15,provider:"fal-ai",chargeable:!0,modelName:i,pricingSource:"legacy-fallback"}}let w=_b[i];if(w){let h=gi(w,n||{}),_=ai[i];return{credits:h.credits,provider:_?.provider||"unknown",chargeable:h.credits>0,modelName:_?.modelName||i,pricingSource:"static-tool-pricing",pricingBreakdown:h}}let b=ai[i];if(b)return b;return{credits:0,provider:"unknown",chargeable:!1}}var _b,ai;var gn=c(()=>{a();_b={generateVideoi2v:{baseCredits:360,modifiers:[{field:"model_id",mode:"discrete",operation:"multiply",map:{"veo-3.1-fast-generate-001":1,"veo-3.1-fast":1,"veo-3.1":0.6666666666666666}},{field:"duration_seconds",mode:"discrete",operation:"multiply",map:{"4":0.5,"6":0.75,"8":1}}]},generateVideoIngredientsToVideo:{baseCredits:360,modifiers:[{field:"model_id",mode:"discrete",operation:"multiply",map:{"veo-3.1-fast-generate-001":1,"veo-3.1-fast":1,"veo-3.1":0.6666666666666666}},{field:"duration_seconds",mode:"discrete",operation:"multiply",map:{"4":0.5,"6":0.75,"8":1}}]},generateVideoSeedance:{baseCredits:240,modifiers:[{field:"duration",mode:"discrete",operation:"multiply",map:{"5":0.5,"10":1}},{field:"ratio",mode:"discrete",operation:"multiply",map:{adaptive:1.2}}]},generateVideoSeedanceRef:{baseCredits:288,modifiers:[{field:"duration",mode:"discrete",operation:"multiply",map:{"5":0.5,"10":1}},{field:"ratio",mode:"discrete",operation:"multiply",map:{adaptive:1.2}}]},generateVideoSeedanceScene:{baseCredits:360,modifiers:[{field:"duration",mode:"discrete",operation:"multiply",map:{"5":0.5,"10":1}},{field:"ratio",mode:"discrete",operation:"multiply",map:{adaptive:1.2}}]}},ai={generateImage:{credits:0,provider:"google-gemini",chargeable:!1,modelName:"gemini-3.1-flash-image-preview"},editImage:{credits:5,provider:"google-gemini",chargeable:!0,modelName:"gemini-3.1-flash-image-preview"},generateImageConversational:{credits:5,provider:"google-gemini",chargeable:!0,modelName:"gemini-3.1-flash-image-preview"},generateVideoi2v:{credits:180,provider:"google-vertex",chargeable:!0,modelName:"veo-3.1-fast-generate-001"},generateVideoIngredientsToVideo:{credits:180,provider:"google-vertex",chargeable:!0,modelName:"veo-3.1-fast-generate-001"},fal_ltx_image_to_video:{credits:15,provider:"fal-ai",chargeable:!0,modelName:"fal-ai/ltx-2/image-to-video"},fal_ltx_retake_video:{credits:15,provider:"fal-ai",chargeable:!0,modelName:"fal-ai/ltx-2/retake-video"},fal_upload_file:{credits:0,provider:"fal-ai",chargeable:!1},fal_list_presets:{credits:0,provider:"fal-ai",chargeable:!1},fal_get_preset_details:{credits:0,provider:"fal-ai",chargeable:!1},get_generation_status:{credits:0,provider:"internal",chargeable:!1}}});var Ti={};ji(Ti,{trackToolRefund:()=>$b,trackToolCall:()=>bn,requireClientId:()=>ri,initOpenMeter:()=>an,getUserId:()=>nn,getProjectId:()=>ei,getOpenMeter:()=>wn,getClientId:()=>fi});import{OpenMeter as yb}from"@openmeter/sdk";function fi(){let i=process.env.CLIENT_ID;if(!i)throw Error("CLIENT_ID environment variable is required. Set CLIENT_ID to your customer identifier for usage tracking.");return i}function ei(){return process.env.PROJECT_ID||"unknown"}function nn(){let i=process.env.USER_ID;if(i)return i;return`${process.env.CLIENT_ID||"client"}_default`}function an(){let i=fi();if(!Yi)Yi=new yb({baseUrl:Fi.baseUrl,apiKey:Fi.apiToken}),M.info(`[OpenMeter] Client initialized for customer: ${i}`);return Yi}function wn(){if(!Yi)return an();return Yi}function sn(i){if(!i)return;return{credits:i.credits,base:i.baseCredits,pre_round:i.preRoundedCredits,rounding:i.rounding,clamp_applied:i.clamp.applied,modifiers:i.modifiers.map((n)=>({field:n.field,mode:n.mode,operation:n.operation,matched:n.matched,effect:n.effect}))}}async function bn(i){let n=fi(),w=wn();if(!w)return;let b=si(i.toolName,i.toolArgs),h=sn(b.pricingBreakdown);try{await w.events.ingest({id:i.requestId??"u_"+crypto.randomUUID(),source:Fi.source,type:"tool_calls",time:new Date,subject:n,data:{value:1,provider:b.provider,credit:b.credits,mcp_name:"kalaasetu-mcp",model_name:b.modelName||i.toolName,project_id:i.projectId||ei(),session_id:i.sessionId||"unknown",tool_name:i.toolName,customer_id:n,user_id:nn(),pricing_source:b.pricingSource??"none",pricing_breakdown:h,refund:!1,...i.toolArgs||{}}}),M.info(`[OpenMeter] Tracked tool call: ${i.toolName} (${b.credits} credits) for customer: ${n}`)}catch(_){M.error("[OpenMeter] Failed to track tool call:",_)}}async function $b(i){let n=fi(),w=wn();if(!w)return;let b=si(i.toolName,i.toolArgs),h=sn(b.pricingBreakdown);try{await w.events.ingest({id:i.requestId?`r_${i.requestId}`:"ru_"+crypto.randomUUID(),source:Fi.source,type:"tool_calls",time:new Date,subject:n,data:{value:1,provider:b.provider,credit:-Math.abs(b.credits),mcp_name:"kalaasetu-mcp",model_name:b.modelName||i.toolName,project_id:i.projectId||ei(),session_id:i.sessionId||"unknown",tool_name:i.toolName,customer_id:n,user_id:nn(),pricing_source:b.pricingSource??"none",pricing_breakdown:h,refund:!0,...i.toolArgs||{}}}),M.info(`[OpenMeter] Tracked tool refund: ${i.toolName} (${-Math.abs(b.credits)} credits) for customer: ${n}`)}catch(_){M.error("[OpenMeter] Failed to track tool refund:",_)}}var Fi,Yi=null,ri;var qi=c(()=>{gn();D();Fi={apiToken:"om_ftRYHNOtv5gRqPaXkItHlWmiiloAI9QD.73hmGa8o1a179gi1189QLn3beQq8wmKhB5eYnBOZwmw",baseUrl:"https://openmeter.cloud",source:"kalaasetu-mcp"};ri=fi});var $n={};ji($n,{encodeTrackingContext:()=>bi,decodeTrackingContext:()=>yn});function bi(i){try{let n=JSON.stringify(i);return Buffer.from(n,"utf-8").toString("base64")}catch(n){return""}}function yn(i){try{let n=Buffer.from(i,"base64").toString("utf-8");return JSON.parse(n)}catch(n){return null}}import*as p from"fs";import*as L from"path";class Mn{basePath;constructor(i=process.cwd()){this.basePath=i}async init(){}async readFile(i){let n=i;if(!L.isAbsolute(i))n=L.resolve(this.basePath,i);return p.promises.readFile(n)}async writeFile(i,n){let w=i;if(!L.isAbsolute(i))w=L.resolve(this.basePath,i);let b=L.dirname(w);if(!p.existsSync(b))await p.promises.mkdir(b,{recursive:!0});return await p.promises.writeFile(w,n),w}async exists(i){let n=i;if(!L.isAbsolute(i))n=L.resolve(this.basePath,i);try{return await p.promises.access(n,p.constants.F_OK),!0}catch{return!1}}async getPublicUrl(i){let n=i;if(!L.isAbsolute(i))n=L.resolve(this.basePath,i);return n}}var nw=()=>{};import{GoogleAuth as ww}from"google-auth-library";import{exec as Hb}from"child_process";import*as bw from"path";async function Ob(i){if(Qi.url===i&&Qi.credentials)return Qi.credentials;let n=new AbortController,w=setTimeout(()=>n.abort(),Bb);try{let b=await fetch(i,{signal:n.signal});if(clearTimeout(w),!b.ok)return console.warn(`GOOGLE_SERVICE_ACCOUNT_JSON_URL fetch failed (${b.status} ${b.statusText}), falling back to other methods. URL: ${i}`),null;let h=await b.text(),_;try{_=JSON.parse(h)}catch{return console.warn(`GOOGLE_SERVICE_ACCOUNT_JSON_URL returned invalid JSON, falling back to other methods. URL: ${i}`),null}let y={credentials:_,projectId:_.project_id};return Qi.url=i,Qi.credentials=y,y}catch(b){return clearTimeout(w),console.warn(`GOOGLE_SERVICE_ACCOUNT_JSON_URL fetch error: ${b.message}, falling back to other methods. URL: ${i}`),null}}async function mn(i={}){let n={scopes:i.scopes||["https://www.googleapis.com/auth/cloud-platform"]};if(process.env.GOOGLE_SERVICE_ACCOUNT_JSON_URL){let w=await Ob(process.env.GOOGLE_SERVICE_ACCOUNT_JSON_URL);if(w){if(n.credentials=w.credentials,w.projectId)n.projectId=w.projectId;return new ww(n)}}if(process.env.GOOGLE_SERVICE_ACCOUNT_JSON)try{let w=JSON.parse(process.env.GOOGLE_SERVICE_ACCOUNT_JSON);if(n.credentials=w,w.project_id)n.projectId=w.project_id}catch(w){console.warn("Failed to parse GOOGLE_SERVICE_ACCOUNT_JSON, falling back to other methods:",w)}else if(process.env.GOOGLE_SERVICE_ACCOUNT_JSON_PATH){let w=bw.resolve(process.env.GOOGLE_SERVICE_ACCOUNT_JSON_PATH.replace(/^["']|["']$/g,""));n.keyFilename=w}return new ww(n)}async function s(i={}){try{let b=await(await(await mn(i)).getClient()).getAccessToken();if(b.token)return b.token;throw Error("No token returned from GoogleAuth")}catch(n){return console.warn("GoogleAuth failed, falling back to gcloud CLI:",n),await new Promise((w,b)=>{Hb("gcloud auth print-access-token",(h,_,y)=>{if(h){b(Error(`Failed to fetch an access token (Auth Library and gcloud): ${y||h.message}`));return}let $=(_||"").trim();if(!$){b(Error("Failed to fetch an access token: empty token from gcloud"));return}w($)})})}}var Qi,Bb=5000;var Gi=c(()=>{Qi={url:null,credentials:null}});import*as Hi from"path";class Vn{bucket;auth=null;constructor(i){this.bucket=i}async init(){this.auth=await mn({scopes:["https://www.googleapis.com/auth/cloud-platform"]});try{await this.auth.getClient()}catch(i){console.warn(`Warning: Could not initialize GCS client: ${i}`)}}async getAccessToken(){return s({scopes:["https://www.googleapis.com/auth/cloud-platform"]})}async readFile(i){let n=Hi.basename(i),w=`https://storage.googleapis.com/storage/v1/b/${this.bucket}/o/${encodeURIComponent(n)}?alt=media`,b=await this.getAccessToken(),h=await fetch(w,{headers:{Authorization:`Bearer ${b}`}});if(!h.ok)throw Error(`Failed to read file from GCS: ${h.status} ${h.statusText}`);let _=await h.arrayBuffer();return Buffer.from(_)}async writeFile(i,n){let w=Hi.basename(i),b=Buffer.isBuffer(n)?n:Buffer.from(n),h=`https://storage.googleapis.com/upload/storage/v1/b/${this.bucket}/o?uploadType=media&name=${encodeURIComponent(w)}`,_=await this.getAccessToken(),y=await fetch(h,{method:"POST",headers:{Authorization:`Bearer ${_}`,"Content-Type":"application/octet-stream","Content-Length":b.length.toString()},body:new Uint8Array(b)});if(!y.ok){let $=await y.text();throw Error(`Failed to upload to GCS: ${y.status} ${$}`)}return`https://storage.googleapis.com/${this.bucket}/${w}`}async exists(i){try{let n=Hi.basename(i),w=`https://storage.googleapis.com/storage/v1/b/${this.bucket}/o/${encodeURIComponent(n)}`,b=await this.getAccessToken();return(await fetch(w,{method:"GET",headers:{Authorization:`Bearer ${b}`}})).ok}catch{return!1}}async getPublicUrl(i){let n=Hi.basename(i);return`https://storage.googleapis.com/${this.bucket}/${n}`}}var hw=c(()=>{Gi()});var _w={};ji(_w,{getStorage:()=>H});function H(){if(!Bi){let i=process.env.STORAGE_PROVIDER||"local";if(M.info(`Initializing storage provider: ${i}`),M.info(`Base path (cwd): ${process.cwd()}`),i==="gcs"){let n=process.env.GCS_BUCKET;if(!n)throw Error("GCS_BUCKET is required when using gcs storage");Bi=new Vn(n)}else Bi=new Mn(process.cwd());Bi.init().catch((n)=>M.error("Failed to init storage:",n))}return Bi}var Bi=null;var R=c(()=>{nw();hw();D()});var Zn={};ji(Zn,{generateTimestampedFilename:()=>o});import*as Mi from"path";function o(i){let w=new Date().toISOString().replace(/[-:]/g,"").replace(/\.\d{3}Z$/,"").replace("T","_"),b=Mi.dirname(i),h=Mi.basename(i),_=h.lastIndexOf("."),y;if(_>0){let $=h.substring(0,_),m=h.substring(_);y=`${w}_${$}${m}`}else y=`${w}_${h}`;if(b===".")return y;return Mi.join(b,y)}var _i=()=>{};import{FastMCP as Zh}from"fastmcp";var ci={name:"@mixio-pro/kalaasetu-mcp",version:"2.3.28-exp",description:"A powerful Model Context Protocol server providing AI tools for content generation and analysis",type:"module",module:"dist/index.js",main:"dist/index.js",bin:{"kalaasetu-mcp":"bin/cli.js"},files:["dist","bin","fal-config.json","README.md","LICENSE"],scripts:{start:"bun run src/index.ts",dev:"bun --watch src/index.ts",build:'bun build ./src/index.ts --outdir ./dist --target bun --minify --no-sourcemap --external "@fal-ai/client" --external "@google/genai" --external "@openmeter/sdk" --external "@sentry/node" --external "@types/node" --external "@types/sharp" --external "@types/wav" --external "dotenv" --external "fastmcp" --external "form-data" --external "google-auth-library" --external "jsonata" --external "sharp" --external "wav" --external "winston" --external "winston-transport-sentry-node" --external "zod"',prepublishOnly:"bun run build"},keywords:["mcp","model-context-protocol","ai","gemini","perplexity","video-generation","image-generation","tts","vertex-ai","fal-ai"],author:"Kalaasetu",license:"MIT",repository:{type:"git",url:"git+https://github.com/mixiopro/kalaasetu-mcp.git"},bugs:{url:"https://github.com/mixiopro/kalaasetu-mcp/issues"},homepage:"https://github.com/mixiopro/kalaasetu-mcp#readme",devDependencies:{"@types/bun":"latest"},peerDependencies:{typescript:"^5"},dependencies:{"@fal-ai/client":"^1.7.2","@google/genai":"^1.28.0","@openmeter/sdk":"^1.0.0-beta.226","@sentry/node":"^10.36.0","@types/node":"^24.10.1","@types/sharp":"^0.32.0","@types/wav":"^1.0.4",dotenv:"^17.3.1",fastmcp:"3.26.8","form-data":"^4.0.5","google-auth-library":"^10.5.0",jsonata:"^2.1.0",sharp:"^0.34.5",wav:"^1.0.2",winston:"^3.19.0","winston-transport-sentry-node":"^3.0.0",zod:"^4.1.12"}};a();import{z as Li}from"zod";D();qi();import{z as mb}from"zod";D();import{join as vb}from"path";import{existsSync as db,readFileSync as Jb}from"fs";import*as rn from"dotenv";function Mb(i){try{let w=i.replace(/^Bearer\s+/i,"").split(".");if(w.length!==3||!w[1])return null;let b=w[1],h=Buffer.from(b,"base64").toString("utf-8");return JSON.parse(h)}catch(n){return M.warn(`Failed to decode JWT: ${n}`),null}}function $i(i){if(!i)return i;return i.trim().replace(/^(['"])(.*)\1$/,"$2")}async function Ei(i){try{if(!(i?.enabled??!0)){M.info("\u2139\uFE0F Remote config disabled via CLI flag.");return}M.info("\uD83D\uDCE1 Checking for remote config...");let w=process.env.VSCODE_CWD||process.cwd(),b={},h=vb(w,".env.local");if(db(h))try{b=rn.parse(Jb(h)),M.info(`\uD83D\uDD11 Loaded environment details from ${h}`)}catch(v){M.warn(`Failed to read env file: ${v}`)}let _=$i(b.MIXIO_TOKEN||b.MIXIO_CONFIG_JWT)||$i(process.env.MIXIO_TOKEN||process.env.MIXIO_CONFIG_JWT),y=$i(b.CLIENT_ID)||$i(process.env.CLIENT_ID),$=$i(b.PROJECT_ID)||$i(process.env.PROJECT_ID);if(_){process.env.MIXIO_TOKEN_FOUND=_;let v=Mb(_);if(v)y=(v.clientId||v.client||v.client_id||y)?.toString()?.trim(),$=(v.projectId||v.project||v.project_id||$||"default")?.toString()?.trim()}if(y)process.env.CLIENT_ID=y;if($)process.env.PROJECT_ID=$;if(M.error(`\uD83D\uDD0D Config check: CLIENT_ID=${process.env.CLIENT_ID}, PROJECT_ID=${process.env.PROJECT_ID}`),!_||!y||!$){M.info(`\u2139\uFE0F Remote config skipped: token=${!!_}, client=${y||"missing"}, project=${$||"missing"}. Continuing with local env.`);return}let m=`https://config.mixio.pro/secrets/${y}/${$}/env.json`;try{M.info(`\uD83C\uDF10 Fetching remote config from ${m}...`);let v=await fetch(m,{headers:{Authorization:`Bearer ${_}`},signal:AbortSignal.timeout?.(1e4)});if(!v.ok)throw Error(`HTTP error! status: ${v.status}`);let V=await v.json(),J=0;for(let[d,Z]of Object.entries(V))if(Z!==void 0){let W=typeof Z==="string"?Z.trim():String(Z);process.env[d]=W,J++}M.info(`\u2705 Successfully loaded ${J} environment variables from remote config.`)}catch(v){M.warn(`\u26A0\uFE0F Failed to fetch remote config: ${v}. Continuing with local env.`)}}catch(n){M.warn(`\u26A0\uFE0F Unexpected error in loadRemoteConfig: ${n}. Continuing with local env.`)}}function Vb(i,n){let w=i instanceof Error?i.message:String(i);if(i instanceof mb.ZodError)w=`Validation Error: ${i.issues.map((h)=>`[${h.path.join(".")}] ${h.message}`).join("; ")}`;else{let b=i;if(b?.status||b?.statusText){let h=b.status?`[${b.status}]`:"",_=b.statusText||"";if(!w.includes(String(b.status)))w=`API Error ${h} ${_}: ${w}`.trim()}}return M.error(`[Tool Error] ${n?`${n}: `:""}${w}`,i),`Tool execution failed${n?` in ${n}`:""}: ${w}`}function Y(i){let n={};for(let[w,b]of Object.entries(i)){if(b===null||b===void 0)continue;let h=typeof b;if(h==="number"||h==="boolean")n[w]=b;else if(h==="string"){if(b.length>200)continue;n[w]=b}}return n}async function f(i,n,w){try{if(await Ei({enabled:!0}),ri(),w)bn(w).catch((h)=>{M.error("[OpenMeter] Tracking background error:",h)});M.info(`[Tool Request] ${n||"unknown"}`,{tool:n,args:w?.toolArgs,requestId:w?.requestId});let b=await i();return M.info(`[Tool Response] ${n||"unknown"}`,{tool:n,result:typeof b==="string"?b.length>1000?b.substring(0,1000)+"...":b:b,requestId:w?.requestId}),b}catch(b){let h=Vb(b,n);if(w)Promise.resolve().then(() => (qi(),Ti)).then(({trackToolRefund:_})=>{return _(w)}).catch((_)=>{M.error("[OpenMeter] Tracking refund background error:",_)});return{isError:!0,content:[{type:"text",text:h}]}}}D();function Zb(i){try{let n=i?.components?.schemas;if(!n)return null;let w=Object.keys(n).find((_)=>_.toLowerCase().includes("input")&&!_.toLowerCase().includes("output"));if(!w)return null;let b=n[w];if(!b?.properties)return null;let h={};for(let[_,y]of Object.entries(b.properties))h[_]={type:y.type,description:y.description,...y.enum&&{enum:y.enum},...y.default!==void 0&&{default:y.default},...y.examples&&{example:y.examples[0]}};return h}catch(n){return null}}var hn={name:"fal_list_presets",description:"The entry point for discovering fal.ai capabilities on this server. Lists all available generation presets, including their high-level 'intent' (e.g., 'Generate cinematic video'), input/output types, and INPUT SCHEMA with parameter details. Call this first when you need to perform an AI generation task.",parameters:Li.object({refresh_schemas:Li.boolean().optional().describe("If true, re-fetch schemas from FAL API even if cached.")}),timeoutMs:60000,execute:async(i,n)=>{return f(async()=>{let w=u(),b=!1;for(let _ of w.presets){let $=!(_.input_schema&&Object.keys(_.input_schema).length>0)||i.refresh_schemas;if(M.debug(`[fal_list_presets] ${_.presetName}: shouldFetch=${$}, hasSchema=${!!_.input_schema}, refresh=${i.refresh_schemas}`),$)try{let m=`https://fal.ai/api/openapi/queue/openapi.json?endpoint_id=${_.modelId}`;M.debug(`[fal_list_presets] Fetching schema from: ${m}`);let v=await fetch(m,{method:"GET",signal:AbortSignal.timeout(1e4)});if(v.ok){let V=await v.json(),J=Zb(V);if(M.debug(`[fal_list_presets] Extracted schema for ${_.presetName}:`,J?Object.keys(J):null),J)_.input_schema=J,b=!0}else M.warn(`[fal_list_presets] Fetch failed: ${v.status}`)}catch(m){M.warn(`[fal_list_presets] Error fetching schema for ${_.presetName}:`,m.message)}}if(b){M.info("[fal_list_presets] Saving updated config...");let _=tn(w);M.info(`[fal_list_presets] Config saved: ${_}`)}let h=w.presets.map((_)=>({presetName:_.presetName,intent:_.intent,inputType:_.inputType,outputType:_.outputType,description:_.description,inputSchema:_.input_schema}));return JSON.stringify(h,null,2)},"fal_list_presets",{toolName:"fal_list_presets",toolArgs:Y(i),requestId:n?.requestId})}},_n={name:"fal_get_preset_details",description:"Retrieve full details for a specific generation preset. This tool fetches both the local preset configuration (like 'defaultParams') and the live model metadata (schema, benchmarks, etc.) from fal.ai. Use this to understand the full capabilities and constraints of a model. ONLY USE WHEN WORKING WITH FAL MODELS/PRESETS.",parameters:Li.object({preset_name:Li.string().describe("The name of the preset to inspect (e.g., 'cinematic_image').")}),timeoutMs:30000,execute:async(i,n)=>{return f(async()=>{let b=u().presets.find((y)=>y.presetName===i.preset_name);if(!b)throw Error(`Preset '${i.preset_name}' not found.`);let h=null,_="none";try{let y=`https://fal.ai/api/openapi/queue/openapi.json?endpoint_id=${b.modelId}`,$=await Xb(y);if($)h=$,_="api"}catch(y){}if(!h&&b.input_schema)h=b.input_schema,_="local_config";return JSON.stringify({preset:b,modelMetadata:h,_meta:{schemaSource:_}},null,2)},"fal_get_preset_details",{toolName:"fal_get_preset_details",toolArgs:Y(i),requestId:n?.requestId})}};async function Xb(i){let n=await fetch(i,{method:"GET",signal:AbortSignal.timeout(un)});if(!n.ok){let w=await n.text();throw Error(`[${n.status}] API error: ${w}`)}return n.json()}import{z as vi}from"zod";a();async function Wb(i){return new Promise((n)=>setTimeout(n,i))}async function di(i,n="GET",w){let b={Authorization:`Key ${g()}`,"Content-Type":"application/json"},h={method:n,headers:b,signal:AbortSignal.timeout(wi)};if(w&&(n==="POST"||n==="PUT"))h.body=JSON.stringify(w);let _=await fetch(i,h);if(!_.ok){let y=await _.text();if(_.status===404)return{status:"IN_PROGRESS_WAITING",detail:"Request not yet available in queue."};throw Error(`[${_.status}] API error: ${y}`)}return _.json()}function Sb(i){return Object.fromEntries(Object.entries(i).filter(([n,w])=>w!=null))}var vn={name:"fal_generate",description:"The primary tool for generating AI content (images, videos, etc.) using fal.ai. This tool handles polling internally and streams progress updates to the client. If the generation takes too long (timeout or error), it returns a 'resume_endpoint' that you can use to resume polling. Use 'fal_list_presets' to discover available intents and names. PREREQUISITE: If using local files as parameters, you MUST upload them first using 'fal_upload_file' and use the resulting CDN URL. ONLY USE WHEN WORKING WITH FAL MODELS/PRESETS.",parameters:vi.object({preset_name:vi.string().optional().describe("Required for new requests. The unique name of the generation preset (e.g., 'ltx_image_to_video'). Obtain this from 'fal_list_presets'."),parameters:vi.record(vi.string(),vi.any()).describe("A dictionary of model-specific parameters (e.g., { 'prompt': '...', 'image_url': '...' }). These override the default values defined in the preset. NOTE: For image-to-video or video-to-video tasks, use 'fal_upload_file' first and pass the resulting CDN URL here."),resume_endpoint:vi.string().optional().describe("If provided, the tool will resume polling for an existing request instead of starting a new one. Use the 'resume_endpoint' returned in an 'IN_PROGRESS' response or after a timeout error.")}),timeoutMs:90000,execute:async(i,n)=>{return f(async()=>{let w,b,h,_=u();if(i.resume_endpoint)if(i.resume_endpoint.startsWith("http")){w=i.resume_endpoint,b=i.resume_endpoint.replace(/\/status$/,"");let J=i.resume_endpoint.split("/");h=(J[J.length-1]||"").replace("/status","")||J[J.length-2]||"unknown",n?.log?.info(`Resuming with FAL URL: ${i.resume_endpoint}`)}else{let J;if(i.preset_name){let d=_.presets.find((Z)=>Z.presetName===i.preset_name);if(d)J=d.modelId,n?.log?.info(`Using model from preset '${i.preset_name}': ${J}`)}if(i.resume_endpoint.includes("::")){let d=i.resume_endpoint.split("::"),Z=d[0],W=d[1]||"";h=W;let X=J||Z;w=`${O}/${X}/requests/${W}/status`,b=`${O}/${X}/requests/${W}`,n?.log?.info(`Resuming polling for ${X} request: ${W}`)}else{if(h=i.resume_endpoint,J)w=`${O}/${J}/requests/${h}/status`,b=`${O}/${J}/requests/${h}`,n?.log?.info(`Resuming polling with explicit model: ${J}`);else w=`${O}/requests/${i.resume_endpoint}/status`,b=`${O}/requests/${i.resume_endpoint}`;try{await di(w,"GET")}catch(d){if(`${d}`.includes("405")||`${d}`.includes("404")){n?.log?.info("Generic status URL failed, attempting to recover model-specific URL...");let Z=!1;for(let W of _.presets){let X=`${O}/${W.modelId}/requests/${h}/status`;try{await di(X,"GET"),w=X,b=`${O}/${W.modelId}/requests/${h}`,n?.log?.info(`Recovered session using model: ${W.modelId}`),Z=!0;break}catch(S){}}if(!Z)n?.log?.info("Could not recover session URL. Assuming generic URL (might fail).")}}n?.log?.info(`Resuming polling for request: ${i.resume_endpoint}`)}}else{if(!i.preset_name)throw Error("preset_name is required when starting a new request.");let J=_.presets.find((S)=>S.presetName===i.preset_name);if(!J)throw Error(`Preset '${i.preset_name}' not found. Use fal_list_presets to see available options.`);try{let S=g();if(n?.streamContent)await n.streamContent({type:"text",text:`[FAL] \u2713 API key found (${S.slice(0,8)}...). Using preset: ${i.preset_name} \u2192 model: ${J.modelId}`})}catch(S){throw S}let d={...J.defaultParams||{},...i.parameters||{}},Z=Sb(d),W=`${O}/${J.modelId}`;if(n?.streamContent)await n.streamContent({type:"text",text:`[FAL] Submitting generation request to ${J.modelId}...`});let X=await di(W,"POST",Z);if(!X.request_id&&!X.status_url)return JSON.stringify(X);if(h=X.request_id||X.status_url?.split("/").pop()||"",!h)throw Error("Could not extract request ID from response");if(w=X.status_url||`${O}/${J.modelId}/requests/${h}/status`,b=X.response_url||`${O}/${J.modelId}/requests/${h}`,n?.streamContent)await n.streamContent({type:"text",text:`[FAL] Generation started. resume_endpoint: ${w} (use this URL to check status)`})}if(i.resume_endpoint&&n?.streamContent)await n.streamContent({type:"text",text:`[FAL] Resuming status check for job: ${h}`});let y=Date.now(),$=60000,m=0,v=3000;while(Date.now()-y<$){m++;let J;try{J=await di(w,"GET")}catch(d){if(`${d}`.includes("405"))n?.log?.info(`Status check 405 on ${w}, trying fallback to responseUrl...`),J=await di(b,"GET"),w=b;else throw d}if(J.status_url)w=J.status_url;if(J.response_url)b=J.response_url;if(n?.reportProgress){let d=J.queue_position??0,Z=Date.now()-y,W=Math.min(Math.round(Z/$*100),99);await n.reportProgress({progress:W,total:100})}if(n?.streamContent&&m%5===0)await n.streamContent({type:"text",text:`[FAL] Still processing... (${Math.round((Date.now()-y)/1000)}s elapsed, status: ${J.status})`});if(J.status==="COMPLETED"){if(n?.reportProgress)await n.reportProgress({progress:100,total:100});let d=await di(b,"GET");return JSON.stringify(d)}if(J.status==="FAILED"){try{let{trackToolRefund:d}=await Promise.resolve().then(() => (qi(),Ti));await d({toolName:"fal_generate",toolArgs:Y(i)})}catch(d){n?.log?.debug("Refund tracking background error:",d)}throw Error(`Generation failed: ${JSON.stringify(J.error||J)}`)}await Wb(v)}let V=i.resume_endpoint&&i.resume_endpoint.includes("::")?i.resume_endpoint.split("::")[0]:i.preset_name?_.presets.find((J)=>J.presetName===i.preset_name)?.modelId:"unknown";return JSON.stringify({status:"IN_PROGRESS",request_id:h,resume_endpoint:`${w}||${bi({toolName:"fal_generate",toolArgs:Y(i),requestId:n?.requestId})}`,status_url:w,response_url:b,message:"The generation is still in progress. Call this tool again with resume_endpoint (the URL) to continue polling."})},"fal_generate",{toolName:"fal_generate",toolArgs:Y(i),requestId:n?.requestId})}};import{z as en}from"zod";import*as Ji from"fs";a();D();import*as Ii from"path";function Yb(i){let n=Ii.extname(i).toLowerCase();return{".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png",".gif":"image/gif",".webp":"image/webp",".mp4":"video/mp4",".webm":"video/webm",".mov":"video/quicktime",".mp3":"audio/mpeg",".wav":"audio/wav",".ogg":"audio/ogg",".pdf":"application/pdf",".json":"application/json",".txt":"text/plain"}[n]||"application/octet-stream"}var dn={name:"fal_upload_file",description:"Upload a local file (image, video, audio) to fal.ai CDN storage. CRITICAL: You MUST use this tool to upload local files before passing their URLs to generation tools in FAL. ONLY USE WHEN WORKING WITH FAL MODELS/PRESETSIt returns a public 'file_url' which should be used as input for 'fal_generate'.",parameters:en.object({path:en.string().describe("The absolute local path to the file to upload (e.g., '/Users/name/images/input.jpg').")}),timeoutMs:300000,execute:async(i,n)=>{return f(async()=>{if(!Ji.existsSync(i.path))throw Error(`File not found: ${i.path}`);let w=Ii.basename(i.path),b=Ji.statSync(i.path).size,h=Yb(i.path),_=`${Un}/storage/upload/initiate?storage_type=fal-cdn-v3`,y={content_type:h,file_name:w};M.debug(`[fal_upload] Initiating upload for ${w}...`);let $=await fetch(_,{method:"POST",headers:{Authorization:`Key ${g()}`,"Content-Type":"application/json"},body:JSON.stringify(y),signal:AbortSignal.timeout(wi)});if(!$.ok){let Z=await $.text();throw Error(`[${$.status}] Failed to initiate upload: ${Z}`)}let m=await $.json(),{file_url:v,upload_url:V}=m;M.debug("[fal_upload] Uploading file content...");let J=Ji.readFileSync(i.path),d=await fetch(V,{method:"PUT",headers:{"Content-Type":h},body:J,signal:AbortSignal.timeout(wi)});if(!d.ok){let Z=await d.text();throw Error(`[${d.status}] Failed to upload file: ${Z}`)}return M.info("[fal_upload] Upload completed successfully"),JSON.stringify({file_url:v,file_name:w,file_size:b,content_type:h})},"fal_upload_file",{toolName:"fal_upload_file",toolArgs:Y(i),requestId:n?.requestId})}};a();import{z as Jn}from"zod";function hi(i){if(i===null||i===void 0)return i;if(typeof i!=="object")return i;if(Array.isArray(i))return i.map(hi);let n={};for(let w of Object.keys(i))if(w==="bytesBase64Encoded"||w==="base64"||w==="data"||w==="content"&&typeof i[w]==="string"&&i[w].length>1e4)n[w]="[LARGE_DATA_HIDDEN]";else n[w]=hi(i[w]);return n}a();async function fb(i){return new Promise((n)=>setTimeout(n,i))}async function ki(i,n="GET",w){let b={Authorization:`Key ${g()}`,"Content-Type":"application/json"},h={method:n,headers:b,signal:AbortSignal.timeout(wi)};if(w&&(n==="POST"||n==="PUT"))h.body=JSON.stringify(w);let _=await fetch(i,h);if(!_.ok){let y=await _.text();if(_.status===404)return{status:"IN_PROGRESS_WAITING",detail:"Request not yet available in queue."};throw Error(`[${_.status}] API error: ${y}`)}return _.json()}function qb(i){return Object.fromEntries(Object.entries(i).filter(([n,w])=>w!=null))}function Qb(i,n){let w={};if(i){for(let[_,y]of Object.entries(i))if(w[_]={...y},n&&n[_]!==void 0)w[_].default=n[_]}let b={type:"object",properties:w},h=Jn.fromJSONSchema(b);return h=h.extend({output_path:Jn.string().optional().describe("Optional local path/filename to save the final generated asset when status is checked via get_generation_status."),resume_endpoint:Jn.string().optional().describe("If provided, resume polling for an existing request instead of starting a new one. Use the 'resume_endpoint' returned in an 'IN_PROGRESS' response.")}),h}function Gb(i){let n=Qb(i.input_schema,i.defaultParams),w=i.presetName.startsWith("mixio_")?i.presetName:`mixio_${i.presetName}`;return{name:w,description:i.intent+(i.description?` ${i.description}`:"")+` [Model: ${i.modelId}]`,parameters:n,timeoutMs:90000,execute:async(b,h)=>{return f(async()=>{let _,y,$;if(b.resume_endpoint){let d=b.resume_endpoint.split("||"),Z=d[d.length-1],X=(Z&&!Z.startsWith("http")&&!Z.includes("/")?(()=>{try{return yn(Z)}catch{return null}})():null)?.toolName&&d.length>1?d.slice(0,-1).join("||"):b.resume_endpoint;if(X.startsWith("http")){_=X,y=X.replace(/\/status$/,"");let S=X.split("/");$=(S[S.length-1]||"").replace("/status","")||S[S.length-2]||"unknown",h?.log?.info(`Resuming with FAL URL: ${X}`)}else $=X,_=`${O}/${i.modelId}/requests/${$}/status`,y=`${O}/${i.modelId}/requests/${$}`,h?.log?.info(`Resuming polling for ${i.modelId} request: ${$}`)}else{try{let G=g();if(h?.streamContent)await h.streamContent({type:"text",text:`[FAL] \u2713 API key found (${G.slice(0,8)}...). Using model: ${i.modelId}`})}catch(G){throw G}let{resume_endpoint:d,output_path:Z,...W}=b,X={};if(i.input_schema){for(let[G,F]of Object.entries(i.input_schema))if(F.default!==void 0)X[G]=F.default}let S={...X,...i.defaultParams||{},...W};if(i.transformers?.types){for(let[G,F]of Object.entries(i.transformers.types))if(S[G]!==void 0){if(F==="number"){let l=Number(S[G]);if(!Number.isNaN(l))S[G]=l}else if(F==="boolean")S[G]=S[G]==="true"||S[G]===!0}}if(i.input_schema)for(let[G,F]of Object.entries(i.input_schema)){let l=F;if(l.type==="string"&&Array.isArray(l.enum)&&l.enum.every((ni)=>typeof ni==="string"&&!Number.isNaN(Number(ni)))&&S[G]!==void 0){let ni=Number(S[G]);if(!Number.isNaN(ni))S[G]=ni}}let K=qb(S),Q=`${O}/${i.modelId}`;if(h?.streamContent)await h.streamContent({type:"text",text:`[FAL] Submitting generation request to ${i.modelId}...`});let q=await ki(Q,"POST",K);if(!q.request_id&&!q.status_url)return JSON.stringify(hi(q));if($=q.request_id||q.status_url?.split("/").pop()||"",!$)throw Error("Could not extract request ID from response");if(_=q.status_url||`${O}/${i.modelId}/requests/${$}/status`,y=q.response_url||`${O}/${i.modelId}/requests/${$}`,h?.streamContent)await h.streamContent({type:"text",text:`[FAL] Generation started. resume_endpoint: ${_}`})}if(b.resume_endpoint&&h?.streamContent)await h.streamContent({type:"text",text:`[FAL] Resuming status check for job: ${$}`});let m=Date.now(),v=60000,V=0,J=3000;while(Date.now()-m<v){V++;let d;try{d=await ki(_,"GET")}catch(Z){if(`${Z}`.includes("405"))h?.log?.info(`Status check 405 on ${_}, trying fallback...`),d=await ki(y,"GET"),_=y;else throw Z}if(d.status_url)_=d.status_url;if(d.response_url)y=d.response_url;if(h?.reportProgress){let Z=Date.now()-m,W=Math.min(Math.round(Z/v*100),99);await h.reportProgress({progress:W,total:100})}if(h?.streamContent&&V%5===0)await h.streamContent({type:"text",text:`[FAL] Still processing... (${Math.round((Date.now()-m)/1000)}s elapsed, status: ${d.status})`});if(d.status==="COMPLETED"){if(h?.reportProgress)await h.reportProgress({progress:100,total:100});let Z=await ki(y,"GET");return JSON.stringify(hi(Z))}if(d.status==="FAILED")throw Error(`Generation failed: ${JSON.stringify(d.error||d)}`);await fb(J)}return JSON.stringify({status:"IN_PROGRESS",request_id:$,resume_endpoint:`${_}||${bi({toolName:w,toolArgs:Y(b),requestId:h?.requestId})}`,status_url:_,response_url:y,message:"The generation is still in progress. Call this tool again with resume_endpoint to continue polling."})},i.presetName,{toolName:w,toolArgs:Y(b),requestId:h?.requestId})}}}function iw(){return u().presets.filter((n)=>n.enabled!==!1).map((n)=>Gb(n))}R();_i();import{z as t}from"zod";import{GoogleGenAI as Kb}from"@google/genai";import*as $w from"fs";import*as Xn from"path";R();D();import*as r from"fs";import*as e from"path";import*as yw from"os";async function j(i){if(i.startsWith("http://")||i.startsWith("https://")){let w=yw.tmpdir(),b=new URL(i).pathname,h=e.extname(b)||".tmp",_=`mcp_download_${Date.now()}${h}`,y=e.join(w,_);try{let $=await fetch(i);if(!$.ok)throw Error(`Failed to download URL: ${i} (${$.status} ${$.statusText})`);let m=await $.arrayBuffer(),v=Buffer.from(m);return r.writeFileSync(y,v),{path:y,isTemp:!0,cleanup:()=>{try{if(r.existsSync(y))r.unlinkSync(y)}catch(V){M.error(`Failed to cleanup temp file ${y}:`,V)}}}}catch($){try{if(r.existsSync(y))r.unlinkSync(y)}catch{}throw Error(`Failed to process URL ${i}: ${$.message}`)}}else{if(!await H().exists(i)){let h=e.isAbsolute(i),_=h?i:e.resolve(process.cwd(),i);throw Error(`File not found: ${i}
4
+ Resolved path: ${_}
5
+ Is absolute: ${h}
6
+ CWD: ${process.cwd()}`)}return{path:i,isTemp:!1,cleanup:()=>{}}}}function jb(){return new Kb({apiKey:process.env.GEMINI_API_KEY||""})}async function Db(i){let n=await j(i);try{let w;if(n.isTemp)w=$w.readFileSync(n.path);else w=await H().readFile(n.path);return{inlineData:{data:Buffer.from(w).toString("base64"),mimeType:Ab(n.path)}}}finally{n.cleanup()}}function Ab(i){switch(Xn.extname(i).toLowerCase()){case".jpg":case".jpeg":return"image/jpeg";case".webp":return"image/webp";case".png":default:return"image/png"}}function Cb(i){if(!i)return;let n=i.trim().toLowerCase();if(n==="image/jpg")return"image/jpeg";return n}function Fb(i){switch(Xn.extname(i).toLowerCase()){case".jpg":case".jpeg":return"image/jpeg";case".png":return"image/png";case".webp":return"image/webp";default:return}}function Tb(i){switch(i){case"image/jpeg":return"jpg";case"image/webp":return"webp";case"image/png":default:return"png"}}var vw={name:"generateImage",description:"Generate high-quality images from text prompts using Google's Imagen 3 model via Gemini. This tool supports conversational history with reference images and their descriptions. Use this tool when you need to provide specific reference images with context/descriptions to guide the generation.",parameters:t.object({prompt:t.string().describe("Detailed text description of the image to generate."),aspect_ratio:t.string().describe("Supported ratios: 1:1, 3:4, 4:3, 9:16, or 16:9. Get the default from the production_bible for the project."),resolution:t.string().describe("Supported resolutions: 1K, 2K, 4K. Get the default from the production_bible for the project."),output_path:t.string().optional().describe("Optional specific local path or filename to save the image. You MUST provide a clear, descriptive path representing the asset's purpose and context (e.g., 'characters/bob/front_view.png', 'locations/cafe/interior.jpg'). If omitted, a timestamped filename is generated automatically."),reference_images:t.array(t.object({path:t.string().describe("Local path or URL to the reference image."),description:t.string().optional().describe("Optional description of the reference image.")})).optional().describe("Optional: List of reference images with optional descriptions to guide the style or content.")}),timeoutMs:300000,execute:async(i,n)=>{return f(async()=>{try{let w=[];if(i.reference_images&&Array.isArray(i.reference_images))for(let J of i.reference_images){if(J.description)w.push({text:J.description});let d=await Db(J.path);w.push(d)}w.push({text:i.prompt});let h=(i.reference_images?.length||0)>=2?["gemini-3-pro-image-preview","gemini-3.1-flash-image-preview","gemini-3-flash-image-preview"]:["gemini-3.1-flash-image-preview","gemini-3-pro-image-preview","gemini-3-flash-image-preview"],y=(i.output_path?Fb(i.output_path):void 0)||"image/png",m=await(async()=>{let J;for(let d of h)try{let Z={responseModalities:["TEXT","IMAGE"],imageConfig:{aspectRatio:i.aspect_ratio,imageSize:i.resolution},tools:[]};if(d.includes("3.1"))Z.thinkingConfig={includeThoughts:!0,thinkingLevel:"HIGH"};return await jb().models.generateContent({model:d,contents:w,config:Z})}catch(Z){J=Z,console.warn(`\u26A0\uFE0F ${d} failed (${Z.message}), falling back to next...`)}throw Error(`All models failed. Last error: ${J?.message||"unknown"}`)})(),v=[],V="";if(m.candidates&&m.candidates[0]?.content?.parts){for(let J of m.candidates[0].content.parts)if(J.text)V+=J.text;else if(J.inlineData?.data){let d=J.inlineData.data,W=Cb(J.inlineData.mimeType)||y,X=i.output_path||o(`generated_image.${Tb(W)}`),K=await H().writeFile(X,Buffer.from(d,"base64"));v.push({url:K,filename:X,mimeType:W})}}if(v.length>0)return JSON.stringify({url:v?.[0]?.url,images:v,message:V||"Image generated successfully"});return V||"Image generation completed but no image was produced"}catch(w){throw Error(`Image generation failed: ${w.message}`)}},"gemini-generateImage",{toolName:"generateImage",toolArgs:Y(i),requestId:n?.requestId})}};R();_i();import{z as T}from"zod";import{GoogleGenAI as Ib}from"@google/genai";import*as Sn from"path";R();import Wn from"sharp";import*as dw from"fs";D();function Eb(i){if(i<=1)return{cols:1,rows:1};if(i<=2)return{cols:2,rows:1};if(i<=4)return{cols:2,rows:2};if(i<=6)return{cols:3,rows:2};if(i<=9)return{cols:3,rows:3};let n=4,w=Math.ceil(i/n);return{cols:n,rows:w}}async function Lb(i){let n=await j(i);try{if(n.isTemp)return dw.readFileSync(n.path);else{let w=H();return Buffer.from(await w.readFile(n.path))}}finally{n.cleanup()}}async function Jw(i,n){if(i.length===0)throw Error("At least one image is required to create a grid.");let w=n?.maxWidth??2048,b=n?.gap??8,h=await Promise.all(i.map(Lb));if(h.length===1)return Wn(h[0]).resize({width:w}).png().toBuffer();let{cols:_,rows:y}=Eb(h.length),$=Math.floor((w-b*(_-1))/_),m=Math.floor($*9/16),v=$*_+b*(_-1),V=m*y+b*(y-1),d=(await Promise.all(h.map((W)=>Wn(W).resize({width:$,height:m,fit:"cover",position:"centre"}).png().toBuffer()))).map((W,X)=>{let S=X%_,K=Math.floor(X/_);return{input:W,left:S*($+b),top:K*(m+b)}});return M.info(`[ImageGrid] Compositing ${h.length} images into ${_}\xD7${y} grid (${v}\xD7${V}px)`),await Wn({create:{width:v,height:V,channels:3,background:{r:0,g:0,b:0}}}).composite(d).png().toBuffer()}import*as Mw from"fs";function kb(){return new Ib({apiKey:process.env.GEMINI_API_KEY||""})}async function Nb(i){let n=await j(i);try{let w;if(n.isTemp)w=Mw.readFileSync(n.path);else w=await H().readFile(n.path);return{inlineData:{data:Buffer.from(w).toString("base64"),mimeType:Rb(n.path)}}}finally{n.cleanup()}}function Rb(i){switch(Sn.extname(i).toLowerCase()){case".jpg":case".jpeg":return"image/jpeg";case".webp":return"image/webp";case".png":default:return"image/png"}}function zb(i){switch(Sn.extname(i).toLowerCase()){case".jpg":case".jpeg":return"image/jpeg";case".png":return"image/png";case".webp":return"image/webp";default:return}}function cb(i){if(!i)return;let n=i.trim().toLowerCase();if(n==="image/jpg")return"image/jpeg";return n}function Pb(i){switch(i){case"image/jpeg":return"jpg";case"image/webp":return"webp";case"image/png":default:return"png"}}var xb="You are generating the next image in a continuous visual sequence. The following grid shows previous scenes in chronological order. You MUST maintain exact visual consistency across all of the following: character appearances (face, hair, clothing, proportions), lighting direction and color temperature, color palette and color grading, environment details and set dressing, props and objects, overall art style and rendering technique. Treat the grid as your visual continuity reference sheet.",mw={name:"generateSceneImage",description:"Generate scene-consistent images by using previous scene outputs as a reference grid. Previous scene images are composited into a single grid collage and used as a visual continuity sheet. Additional character, location, or style reference images can be provided separately. Use this tool when generating sequential shots that must maintain visual consistency (same characters, lighting, color palette, environment, and art style).",parameters:T.object({prompt:T.string().describe("Creative direction for the next scene image to generate."),scene_images:T.array(T.object({path:T.string().describe("Local path or URL to a previous scene image."),description:T.string().optional().describe("Optional description of this scene (e.g., 'Shot 1: wide establishing shot of the caf\xE9 at sunset').")})).describe("Ordered list of previous scene images. These will be composited into a single grid collage for visual continuity reference."),reference_images:T.array(T.object({path:T.string().describe("Local path or URL to the reference image."),description:T.string().optional().describe("Description of this reference (e.g., 'Main character Elena - front view', 'Caf\xE9 interior reference').")})).optional().describe("Optional: Individual character, location, or style reference images. These are passed separately from the scene grid."),aspect_ratio:T.string().describe("Supported ratios: 1:1, 3:4, 4:3, 9:16, or 16:9. Get the default from the production_bible for the project."),resolution:T.string().describe("Supported resolutions: 1K, 2K, 4K. Get the default from the production_bible for the project."),output_path:T.string().describe("Specific local path or filename to save the image. You MUST provide a clear, descriptive path representing the asset's purpose and context (e.g., 'scenes/scene_03/shot_02.png'). If omitted, a timestamped filename is generated automatically.")}),timeoutMs:300000,execute:async(i,n)=>{return f(async()=>{try{let w=[];if(w.push({text:xb}),i.scene_images.length>0){let J=i.scene_images.map((W)=>W.path),d=await Jw(J),Z=i.scene_images.map((W,X)=>`Scene ${X+1}${W.description?`: ${W.description}`:""}`).join(" \u2192 ");w.push({text:`Previous scenes grid (${i.scene_images.length} shots, in chronological order): ${Z}`}),w.push({inlineData:{data:d.toString("base64"),mimeType:"image/png"}})}if(i.reference_images&&Array.isArray(i.reference_images))for(let J of i.reference_images){if(J.description)w.push({text:`Reference: ${J.description}`});let d=await Nb(J.path);w.push(d)}w.push({text:`Generate the next scene maintaining full visual consistency: ${i.prompt}`});let h=(i.scene_images.length>0?1:0)+(i.reference_images?.length||0)>3?["gemini-3-pro-image-preview","gemini-3.1-flash-image-preview","gemini-3-flash-image-preview"]:["gemini-3.1-flash-image-preview","gemini-3-pro-image-preview","gemini-3-flash-image-preview"],y=(i.output_path?zb(i.output_path):void 0)||"image/png",m=await(async()=>{let J;for(let d of h)try{let Z={responseModalities:["TEXT","IMAGE"],imageConfig:{aspectRatio:i.aspect_ratio,imageSize:i.resolution},tools:[]};if(d.includes("3.1"))Z.thinkingConfig={includeThoughts:!0,thinkingLevel:"HIGH"};return await kb().models.generateContent({model:d,contents:w,config:Z})}catch(Z){J=Z,console.warn(`\u26A0\uFE0F ${d} failed (${Z.message}), falling back to next...`)}throw Error(`All models failed. Last error: ${J?.message||"unknown"}`)})(),v=[],V="";if(m.candidates&&m.candidates[0]?.content?.parts){for(let J of m.candidates[0].content.parts)if(J.text)V+=J.text;else if(J.inlineData?.data){let d=J.inlineData.data,W=cb(J.inlineData.mimeType)||y,X=i.output_path||o(`scene_image.${Pb(W)}`),K=await H().writeFile(X,Buffer.from(d,"base64"));v.push({url:K,filename:X,mimeType:W})}}if(v.length>0)return JSON.stringify({url:v?.[0]?.url,images:v,message:V||"Scene image generated with visual consistency maintained",scene_count:i.scene_images.length,reference_count:i.reference_images?.length||0});return V||"Scene image generation completed but no image was produced"}catch(w){throw Error(`Scene image generation failed: ${w.message}`)}},"gemini-generateSceneImage",{toolName:"generateSceneImage",toolArgs:Y(i),requestId:n?.requestId})}};R();import{z as C}from"zod";Gi();import{z as Yn}from"zod";D();Gi();R();import*as Ww from"path";function Sw(){let i=process.env.FAL_KEY;if(!i)throw Error("FAL_KEY environment variable not set");return i}async function Ub(i){let n=Sw(),w=await fetch(i,{method:"GET",headers:{Authorization:`Key ${n}`,"Content-Type":"application/json"}});if(!w.ok){let b=await w.text();throw Error(`FAL API error [${w.status}]: ${b}`)}return await w.json()}async function ub(i){let n=Sw(),w=await fetch(i,{method:"GET",headers:{Authorization:`Key ${n}`,"Content-Type":"application/json"}});if(!w.ok){let b=await w.text();throw Error(`FAL API error [${w.status}]: ${b}`)}return await w.json()}function pb(i){return i.replace(/\/status$/,"")}function Vw(i){let n=i.split("?")[0]?.toLowerCase()||"";if(n.endsWith(".mp4"))return"mp4";if(n.endsWith(".mov"))return"mov";if(n.endsWith(".webm"))return"webm";if(n.endsWith(".jpg")||n.endsWith(".jpeg"))return"jpg";if(n.endsWith(".webp"))return"webp";if(n.endsWith(".png"))return"png";return"bin"}function Zw(i){switch(i){case"mp4":return"video/mp4";case"mov":return"video/quicktime";case"webm":return"video/webm";case"jpg":return"image/jpeg";case"webp":return"image/webp";case"png":return"image/png";default:return"application/octet-stream"}}function Xw(i,n){if(n===0)return i;let w=Ww.extname(i);if(!w)return`${i}_${n}`;return`${i.slice(0,-w.length)}_${n}${w}`}function ob(i){if(!i||typeof i!=="object")return;let n=i?.toolArgs?.output_path;if(typeof n==="string"&&n.length>0)return n;let w=i?.toolArgs?.parameters?.output_path;if(typeof w==="string"&&w.length>0)return w;return}async function tb(i,n){let w=H(),{generateTimestampedFilename:b}=await Promise.resolve().then(() => (_i(),Zn)),h=[],_=[],y=Array.isArray(i?.videos)?i.videos:[],$=Array.isArray(i?.images)?i.images:[],m=(v)=>{if(typeof v==="string")return v;if(v&&typeof v.url==="string")return v.url;return};for(let v=0;v<y.length;v++){let V=m(y[v]);if(!V||!V.startsWith("http"))continue;let J=await fetch(V);if(!J.ok)continue;let d=Buffer.from(await J.arrayBuffer()),Z=Vw(V),W=n?Xw(n,v):b(`fal_video_output_${v}.${Z==="bin"?"mp4":Z}`),X=await w.writeFile(W,d);h.push({url:X,filename:W,mimeType:Zw(Z==="bin"?"mp4":Z)})}for(let v=0;v<$.length;v++){let V=m($[v]);if(!V||!V.startsWith("http"))continue;let J=await fetch(V);if(!J.ok)continue;let d=Buffer.from(await J.arrayBuffer()),Z=Vw(V),W=b(`fal_image_output_${v}.${Z==="bin"?"png":Z}`),X=n?Xw(n,v):W,S=await w.writeFile(X,d);_.push({url:S,filename:X,mimeType:Zw(Z==="bin"?"png":Z)})}return{savedVideos:h,savedImages:_}}async function Oi(i){let n=await s(),w=i.split("||"),b=w[0]||"",h=w[1]||"",_=w[2]||"";if(!b||!h)throw Error("Invalid Vertex resume_endpoint format. Expected 'fetchUrl||operationName[||outputPath]'.");let y=await fetch(b,{method:"POST",headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json"},body:JSON.stringify({operationName:h})});if(!y.ok){let v=await y.text();throw Error(`Vertex AI API error [${y.status}]: ${v}`)}let $=await y.json();if($.done&&$.error){let v=typeof $.error==="object"?$.error.message||$.error.code||JSON.stringify($.error):String($.error);return $._vertexError=v,$}if(!!$.done||!!$.response){let v=$.response||$;if(Array.isArray(v?.videos)&&v.videos.length>0){let{getStorage:V}=await Promise.resolve().then(() => (R(),_w)),{generateTimestampedFilename:J}=await Promise.resolve().then(() => (_i(),Zn)),d=V(),Z=[];for(let W=0;W<v.videos.length;W++){let X=v.videos[W];if(X?.bytesBase64Encoded){let S;if(_)S=W===0?_:_.replace(/\.mp4$/i,`_${W}.mp4`);else S=J(`video_output_${W}.mp4`);let K=Buffer.from(X.bytesBase64Encoded,"base64"),Q=await d.writeFile(S,K);Z.push({url:Q,filename:S,mimeType:"video/mp4"}),delete X.bytesBase64Encoded}}if(Z.length>0)v.saved_videos=Z}}return $}var Yw={name:"get_generation_status",description:"Check the status or retrieve the result of a generation operation that was started by 'fal_generate', 'generateVideoi2v', or 'generateVideoIngredientsToVideo'. Use this when the original generation tool returned an 'IN_PROGRESS' status with a 'resume_endpoint'. Pass the resume_endpoint exactly as it was returned. For FAL operations, the resume_endpoint is a full URL. For Vertex AI operations, the resume_endpoint may be the composite fetch URL format returned by the tool.",parameters:Yn.object({resume_endpoint:Yn.string().describe("The resume_endpoint returned by the original generation tool. For FAL: This is a full URL (starts with 'https://queue.fal.run/...'). For Vertex AI: This is typically the composite string 'fetchUrl||operationName||outputPath' with optional tracking context appended."),source:Yn.enum(["fal","vertex","auto"]).optional().default("auto").describe("Source of the operation: 'fal' for FAL AI, 'vertex' for Google Vertex AI, or 'auto' to auto-detect based on resume_endpoint format.")}),timeoutMs:300000,execute:async(i,n)=>{return f(async()=>{let{resume_endpoint:w,source:b="auto"}=i,h="mixio-pro",_="us-central1",y=null,$=w;if(w.includes("||")){let d=w.split("||"),Z=d[d.length-1];if(Z&&!Z.startsWith("http")&&!Z.includes("/")&&!Z.includes("mixio-pro"))try{let{decodeTrackingContext:W}=await Promise.resolve().then(() => $n);if(y=W(Z),y?.toolName)$=d.slice(0,-1).join("||");else y=null,$=w}catch(W){}}let m=b;if(b==="auto")if($.startsWith("https://queue.fal.run")||$.startsWith("https://fal.run"))m="fal";else m="vertex";let v;if(m==="fal"){let d=await Ub($);if(d?.status==="COMPLETED"){let W=pb($),X=await ub(W),S=ob(y),{savedVideos:K,savedImages:Q}=await tb(X,S);if(K.length>0)X.saved_videos=K;if(Q.length>0)X.saved_images=Q;v={...X,status:"COMPLETED"}}else v=d}else v=await Oi($);let V=v.status||(v.done?"COMPLETED":"IN_PROGRESS"),J=hi(v);if(V==="FAILED"&&y?.toolName)try{let{trackToolRefund:d}=await Promise.resolve().then(() => (qi(),Ti));await d(y)}catch(d){M.error("[OpenMeter] Async refund tracking background error:",d)}return JSON.stringify({source:m,status:V,resume_endpoint:w,result:J,message:V==="COMPLETED"?m==="fal"?"Generation completed! Check 'result.saved_videos' or 'result.saved_images' for downloaded asset URLs.":"Generation completed! Check 'result.response.saved_videos' for the video URLs.":V==="FAILED"?"Generation failed. Check the 'result' field for error details.":"Generation is still in progress. Call this tool again with the same resume_endpoint to check later."},null,2)},"get_generation_status",{toolName:"get_generation_status",toolArgs:Y(i),requestId:n?.requestId})}};async function lb(i){return new Promise((n)=>setTimeout(n,i))}async function fn(i){let n=await j(i);try{let w;if(n.isTemp){let _=(await import("fs")).readFileSync(n.path);w=Buffer.from(_).toString("base64")}else{let _=await H().readFile(n.path);w=Buffer.from(_).toString("base64")}return{data:w,mimeType:"image/png"}}finally{n.cleanup()}}var fw={name:"generateVideoi2v",description:"Generate professional-quality cinematic videos from a starting image and text prompt using Google's Vertex AI Veo models. This tool follows a 'Synchronous Facade' pattern: it handles polling internally but can be paused/resumed. If the generation takes too long, it returns a 'resume_endpoint' that you MUST use to call this tool again to pick up progress. It produces state-of-the-art cinematic results. ONLY USE WHEN WORKING WITH GOOGLE VERTEX AI MODELS.",parameters:C.object({prompt:C.string().optional().describe("Required for new requests. Descriptive text for the video action and style (e.g., 'A robot walking through a neon city at night')."),image_path:C.string().optional().describe("Absolute local path or URL to the STARTING image frame."),last_frame_path:C.string().optional().describe("Optional: Absolute local path or URL to the ENDING image frame to guide the video's conclusion."),aspect_ratio:C.string().optional().default("16:9").describe("Target aspect ratio: '16:9' (landscape) or '9:16' (vertical)."),duration_seconds:C.string().optional().default("6").describe("Target duration. Vertex AI ONLY supports exactly '4', '6', or '8' seconds. Other values will be rounded to the nearest supported step."),resolution:C.string().optional().describe("Target resolution: '720p' or '1080p'. Default is '720p'."),negative_prompt:C.string().optional().describe("Use this param with things to avoid in a video if user is retrying the video generation again and again with feedback on unwanted elements. Visual elements or styles to EXCLUDE from the generated video."),person_generation:C.string().optional().default("allow_all").describe("Policy for generating people: 'allow_adult' (standard) or 'allow_all'. Note: Gemini 1.5+ safety filters apply."),reference_images:C.array(C.string()).optional().describe("Optional: Additional images (up to 3) to guide style or character consistency."),output_path:C.string().describe("Specific local path or filename to save the video. You MUST provide a clear, descriptive path representing the asset's purpose and context (e.g., 'scenes/intro/robot_walking.mp4'). If omitted, a timestamped filename is generated automatically."),generate_audio:C.boolean().optional().describe("If true, Vertex will attempt to synthesize synchronized audio for the video.").default(!1),resume_endpoint:C.string().optional().describe("If provided, the tool will check the status of an existing Vertex operation instead of starting a new one. Use the 'resume_endpoint' returned in an 'IN_PROGRESS' response.")}),timeoutMs:90000,async execute(i,n){return f(async()=>{let _=parseInt(i.duration_seconds||"6");if(isNaN(_))_=6;if(_=[4,6,8].reduce((Q,q)=>{return Math.abs(q-_)<Math.abs(Q-_)?q:Q}),_===4&&parseInt(i.duration_seconds||"6")===5)_=6;if(_===6&&parseInt(i.duration_seconds||"6")===7)_=8;let $;try{if(n?.streamContent)await n.streamContent({type:"text",text:"[Vertex] Authenticating with Google Cloud (project: mixio-pro, location: us-central1)..."});if($=await s(),n?.streamContent)await n.streamContent({type:"text",text:"[Vertex] \u2713 Authentication successful. Token acquired."})}catch(Q){let q=Q?.message||String(Q);if(n?.streamContent)await n.streamContent({type:"text",text:`[Vertex] \u2717 Authentication FAILED: ${q}. Check GOOGLE_APPLICATION_CREDENTIALS or run 'gcloud auth application-default login'.`});throw Error(`Google Cloud authentication failed: ${q}`)}let m="https://us-central1-aiplatform.googleapis.com/v1/projects/mixio-pro/locations/us-central1/publishers/google/models/veo-3.1-lite-generate-001:fetchPredictOperation",v;if(i.resume_endpoint)if(i.resume_endpoint.includes("/"))v=i.resume_endpoint;else v=`projects/mixio-pro/locations/us-central1/publishers/google/models/veo-3.1-lite-generate-001/operations/${i.resume_endpoint}`;let V;if(!v){if(!i.prompt)throw Error("prompt is required when starting a new generation.");if(n?.streamContent)await n.streamContent({type:"text",text:"[Vertex] Submitting video generation request to Veo model: veo-3.1-lite-generate-001..."});let Q="https://us-central1-aiplatform.googleapis.com/v1/projects/mixio-pro/locations/us-central1/publishers/google/models/veo-3.1-lite-generate-001:predictLongRunning",q=void 0;if(i.image_path){let{data:N,mimeType:Wi}=await fn(i.image_path);q={image:{bytesBase64Encoded:N,mimeType:Wi}}}let G=void 0;if(i.last_frame_path){let{data:N,mimeType:Wi}=await fn(i.last_frame_path);G={lastFrame:{bytesBase64Encoded:N,mimeType:Wi}}}let F=void 0;if(i.reference_images){let N;if(typeof i.reference_images==="string")if(i.reference_images.startsWith("[")&&i.reference_images.endsWith("]"))try{N=JSON.parse(i.reference_images)}catch{throw Error("Invalid reference_images format")}else N=[i.reference_images];else if(Array.isArray(i.reference_images))N=i.reference_images;else throw Error("Invalid reference_images: must be array or string");if(N.length>0)F=await Promise.all(N.slice(0,3).map(async(Wi)=>{let{data:Lw,mimeType:Iw}=await fn(Wi);return{image:{bytesBase64Encoded:Lw,mimeType:Iw},referenceType:"asset"}}))}let l=i.person_generation||(i.image_path?"allow_adult":"allow_all"),ni=i.prompt,Fw=i.negative_prompt,Tw=[{prompt:ni,...q||{},...G||{},...F?{referenceImages:F}:{}}],Ew={aspectRatio:i.aspect_ratio||"9:16",durationSeconds:_,resolution:i.resolution||"720p",negativePrompt:Fw,generateAudio:i.generate_audio||!1,personGeneration:l},Ki=await fetch(Q,{method:"POST",headers:{Authorization:`Bearer ${$}`,"Content-Type":"application/json"},body:JSON.stringify({instances:Tw,parameters:Ew})});if(!Ki.ok){let N=await Ki.text();throw Error(`Vertex request failed: ${Ki.status} ${N}`)}let zi=await Ki.json();v=zi.name||zi.operation||"",V=zi}if(!v)throw Error("Vertex did not return an operation name for long-running request");let J=i.output_path||"",d=`${m}||${v}||${J}`;if(n?.streamContent){let Q=!!i.resume_endpoint;await n.streamContent({type:"text",text:Q?"[Vertex] Resuming status check for job":`[Vertex] Video generation started. resume_endpoint: ${d} (use this to check status if needed)`})}let Z=V?!!V.done||!!V.response:!1,W=Date.now(),X=60000;while(!Z&&Date.now()-W<X){if(await lb(1e4),V=await Oi(d),Z=!!V.done||!!V.response,n?.reportProgress){let Q=Date.now()-W,q=Math.min(Math.round(Q/X*100),99);await n.reportProgress({progress:q,total:100})}if(n?.streamContent&&!Z)await n.streamContent({type:"text",text:`[Vertex] Still processing... (${Math.round((Date.now()-W)/1000)}s elapsed)`})}if(!Z){let{encodeTrackingContext:Q}=await Promise.resolve().then(() => $n),q=Q({toolName:"generateVideoi2v",toolArgs:Y(i),requestId:n?.requestId});return JSON.stringify({status:"IN_PROGRESS",request_id:v,resume_endpoint:`${d}||${q}`,message:"Still in progress. Call this tool again with resume_endpoint to continue checking."})}if(V.error||V._vertexError){let Q=V._vertexError||(typeof V.error==="object"?V.error.message||V.error.code||JSON.stringify(V.error):String(V.error));return JSON.stringify({status:"ERROR",message:`Vertex AI video generation failed: ${Q}`,operationName:v,error:typeof V.error==="object"?{code:V.error.code,message:V.error.message,status:V.error.status}:V.error})}let S=V.response||V;if(Array.isArray(S.saved_videos)&&S.saved_videos.length>0)return JSON.stringify({videos:S.saved_videos,message:"Video(s) generated successfully"});let K=S?Object.keys(S):[];return JSON.stringify({status:"ERROR",message:"Vertex operation completed but no videos were found in the response.",operationName:v,responseKeys:K,hint:"The response structure may have changed. Check the Vertex AI documentation or search for the expected response format."})},"imageToVideo",{toolName:"generateVideoi2v",toolArgs:Y(i),requestId:n?.requestId})}};R();import*as Gw from"path";import{z as A}from"zod";Gi();var Ni="mixio-pro",mi="us-central1",qn="veo-3.1-fast-generate-001",qw=3,Qw=60000,gb=1e4;async function ab(i){return new Promise((n)=>setTimeout(n,i))}function sb(i){switch(Gw.extname(i).toLowerCase()){case".jpg":case".jpeg":return"image/jpeg";case".webp":return"image/webp";case".gif":return"image/gif";case".bmp":return"image/bmp";case".heic":return"image/heic";case".heif":return"image/heif";case".png":default:return"image/png"}}async function rb(i){let n=await j(i);try{let w;if(n.isTemp){let h=(await import("fs")).readFileSync(n.path);w=Buffer.from(h).toString("base64")}else{let h=await H().readFile(n.path);w=Buffer.from(h).toString("base64")}return{data:w,mimeType:sb(n.path)}}finally{n.cleanup()}}function Hw(i){return`https://${mi}-aiplatform.googleapis.com/v1/projects/${Ni}/locations/${mi}/publishers/google/models/${i}:fetchPredictOperation`}function eb(i,n){let w=Hw(n);if(i.includes("||")){let b=i.split("||"),h=b[0]||"",_=b[1]||"";if(h.startsWith("http")&&_)return{fetchUrl:h,operationName:_,outputPath:b[2]||"",trackingContext:b.length>3?b.slice(3).join("||"):void 0}}if(i.includes("/"))return{fetchUrl:w,operationName:i};return{fetchUrl:w,operationName:`projects/${Ni}/locations/${mi}/publishers/google/models/${n}/operations/${i}`}}function ih(i){let n=parseInt(i||"6"),w=Number.isNaN(n)?6:n,h=[4,6,8].reduce((_,y)=>{return Math.abs(y-w)<Math.abs(_-w)?y:_});if(h===4&&w===5)return 6;if(h===6&&w===7)return 8;return h}function nh(i){if(!i)throw Error("reference_images is required when starting a new generation.");let n;if(typeof i==="string")if(i.startsWith("[")&&i.endsWith("]"))try{let w=JSON.parse(i);if(!Array.isArray(w)||!w.every((b)=>typeof b==="string"))throw Error("Invalid reference_images format");n=w}catch{throw Error("Invalid reference_images format. Expected a string path/URL or a JSON array of string paths/URLs.")}else n=[i];else if(Array.isArray(i))n=i;else throw Error("Invalid reference_images: must be an array of strings or a string.");if(n.length===0)throw Error("reference_images is required when starting a new generation.");if(n.length>qw)throw Error(`reference_images supports a maximum of ${qw} images for Vertex reference-image video generation.`);return n}async function wh(i){let n=nh(i);return Promise.all(n.map(async(w)=>{let{data:b,mimeType:h}=await rb(w);return{image:{bytesBase64Encoded:b,mimeType:h},referenceType:"asset"}}))}var Bw={name:"generateVideoIngredientsToVideo",description:"Generate cinematic videos from 1-3 REFERENCE IMAGES plus a text prompt using Google's Vertex AI Veo models. This is the reference-images-guided Vertex video tool ('ingredients to video'). It follows a synchronous-facade async pattern: it polls internally, and if the job takes too long it returns a 'resume_endpoint' for continued status checks. This v1 tool supports ASSET reference images only. It uses veo-3.1-fast-generate-001 by default and surfaces Vertex errors clearly if that model/payload combination is rejected.",parameters:A.object({prompt:A.string().optional().describe("Required for new requests. Descriptive text for the video action and style."),reference_images:A.union([A.array(A.string()),A.string()]).optional().describe("Required for new requests. One to three absolute local paths or URLs to asset reference images."),aspect_ratio:A.string().optional().default("16:9").describe("Target aspect ratio: '16:9' (landscape) or '9:16' (vertical)."),duration_seconds:A.string().optional().default("6").describe("Target duration. Vertex AI supports exactly '4', '6', or '8' seconds. Other values are rounded to the nearest supported step, rounding up on ties."),resolution:A.string().optional().describe("Target resolution: '720p' or '1080p'. Default is '720p'."),negative_prompt:A.string().optional().describe("Visual elements or styles to exclude from the generated video."),generate_audio:A.boolean().optional().default(!1).describe("If true, Vertex will attempt to synthesize synchronized audio for the video."),person_generation:A.string().optional().default("allow_all").describe("Policy for generating people: 'allow_adult' (standard) or 'allow_all'."),output_path:A.string().optional().describe("Specific local path or filename to save the video. If omitted, a timestamped filename is generated automatically."),model_id:A.string().optional().default(qn).describe(`Specific Vertex Veo model ID to use. Default value is ${qn}.`),resume_endpoint:A.string().optional().describe("If provided, the tool will check the status of an existing Vertex operation instead of starting a new one. Use the 'resume_endpoint' returned in an 'IN_PROGRESS' response.")}),timeoutMs:90000,async execute(i,n){return f(async()=>{let w=i.model_id||qn,b=ih(i.duration_seconds),h;try{if(n?.streamContent)await n.streamContent({type:"text",text:`[Vertex] Authenticating with Google Cloud (project: ${Ni}, location: ${mi})...`});if(h=await s(),n?.streamContent)await n.streamContent({type:"text",text:"[Vertex] \u2713 Authentication successful. Token acquired."})}catch(X){let S=X?.message||String(X);if(n?.streamContent)await n.streamContent({type:"text",text:`[Vertex] \u2717 Authentication FAILED: ${S}. Check GOOGLE_APPLICATION_CREDENTIALS or run 'gcloud auth application-default login'.`});throw Error(`Google Cloud authentication failed: ${S}`)}let _=Hw(w),y,$=i.output_path||"",m,v;if(i.resume_endpoint){let X=eb(i.resume_endpoint,w);_=X.fetchUrl,y=X.operationName,$=X.outputPath||$,m=X.trackingContext}if(!y){if(!i.prompt)throw Error("prompt is required when starting a new reference-image video generation.");let X=await wh(i.reference_images);if(n?.streamContent)await n.streamContent({type:"text",text:`[Vertex] Submitting reference-image video generation request to Veo model: ${w}...`});let S=`https://${mi}-aiplatform.googleapis.com/v1/projects/${Ni}/locations/${mi}/publishers/google/models/${w}:predictLongRunning`,K=[{prompt:i.prompt,referenceImages:X}],Q={aspectRatio:i.aspect_ratio||"16:9",durationSeconds:b,resolution:i.resolution||"720p",negativePrompt:i.negative_prompt,generateAudio:i.generate_audio??!1,personGeneration:i.person_generation||"allow_all"},q=await fetch(S,{method:"POST",headers:{Authorization:`Bearer ${h}`,"Content-Type":"application/json"},body:JSON.stringify({instances:K,parameters:Q})});if(!q.ok){let F=await q.text();throw Error(`Vertex reference-image request failed for model ${w}: ${q.status} ${F}`)}let G=await q.json();y=G.name||G.operation||"",v=G}if(!y)throw Error("Vertex did not return an operation name for the long-running reference-image request.");let V=`${_}||${y}||${$}`;if(n?.streamContent)await n.streamContent({type:"text",text:i.resume_endpoint?"[Vertex] Resuming status check for reference-image video job":`[Vertex] Reference-image video generation started. resume_endpoint: ${V} (use this to check status if needed)`});let J=v?!!v.done||!!v.response:!1,d=Date.now();while(!J&&Date.now()-d<Qw){if(await ab(gb),v=await Oi(V),J=!!v.done||!!v.response,n?.reportProgress){let X=Date.now()-d,S=Math.min(Math.round(X/Qw*100),99);await n.reportProgress({progress:S,total:100})}if(n?.streamContent&&!J)await n.streamContent({type:"text",text:`[Vertex] Still processing... (${Math.round((Date.now()-d)/1000)}s elapsed)`})}if(!J){let X=m||bi({toolName:"generateVideoIngredientsToVideo",toolArgs:Y(i),requestId:n?.requestId});return JSON.stringify({status:"IN_PROGRESS",request_id:y,resume_endpoint:`${V}||${X}`,message:"Still in progress. Call this tool again with resume_endpoint to continue checking."})}if(v.error||v._vertexError){let X=v._vertexError||(typeof v.error==="object"?v.error.message||v.error.code||JSON.stringify(v.error):String(v.error));return JSON.stringify({status:"ERROR",message:`Vertex AI reference-image video generation failed: ${X}`,operationName:y,error:typeof v.error==="object"?{code:v.error.code,message:v.error.message,status:v.error.status}:v.error})}let Z=v.response||v;if(Array.isArray(Z.saved_videos)&&Z.saved_videos.length>0)return JSON.stringify({videos:Z.saved_videos,message:"Video(s) generated successfully"});let W=Z?Object.keys(Z):[];return JSON.stringify({status:"ERROR",message:"Vertex operation completed but no videos were found in the response.",operationName:y,responseKeys:W,hint:"The response structure may have changed. Check the Vertex AI documentation or inspect the expected response format."})},"ingredientsToVideo",{toolName:"generateVideoIngredientsToVideo",toolArgs:Y(i),requestId:n?.requestId})}};D();var bh="https://waves-api.smallest.ai";class Ow{getApiKey(){let i=process.env.WAVES_API_KEY||"";if(!i)M.warn("WAVES_API_KEY environment variable is not set. Waves API calls will fail.");return i}async request(i,n){let w=i.startsWith("http")?i:`${bh}${i}`,b=new Headers(n.headers||{});if(!b.has("Authorization"))b.set("Authorization",`Bearer ${this.getApiKey()}`);try{let h=await fetch(w,{...n,headers:b});if(!h.ok){let _="";try{_=await h.text()}catch(y){}throw M.error(`Waves API Error: Status=${h.status}, URL=${w}, Response=${_}`),Error(`Waves API request failed: ${h.status} ${h.statusText} - ${_}`)}return h}catch(h){throw M.error(`Failed to execute Waves API request to ${w}: ${h.message}`),h}}}var P=new Ow;import{z as I}from"zod";R();_i();var Qn={name:"smallestAiTtsToWav",description:"Generate TTS audio and save it as a WAV file using Smallest AI's Waves API. Supports 'lightning' and 'lightning-large' models.",parameters:I.object({text:I.string().describe("The text to synthesize."),voiceId:I.string().describe("The ID of the voice to use (e.g. from smallestAiListVoices)."),model:I.enum(["lightning","lightning-large"]).default("lightning").describe("The TTS model to use."),language:I.string().optional().describe("Language code (required for lightning-large model, e.g., 'en', 'hi', etc.)."),add_wav_header:I.boolean().default(!0).describe("Whether to add a WAV header to the output."),sample_rate:I.number().default(24000).describe("The sample rate for the audio in Hz."),speed:I.number().default(1).describe("Playback speed factor."),consistency:I.number().default(0.5).describe("Voice consistency level."),similarity:I.number().default(0).describe("Voice similarity level."),enhancement:I.number().default(1).describe("Enhancement level."),output_path:I.string().optional().describe("Optional: Output file path. Defaults to a timestamped filename.")}),timeoutMs:300000,execute:async(i,n)=>{return f(async()=>{try{let w={text:i.text,voice_id:i.voiceId,add_wav_header:i.add_wav_header,sample_rate:i.sample_rate,speed:i.speed,consistency:i.consistency,similarity:i.similarity,enhancement:i.enhancement,output_format:"wav"},b="";if(i.model==="lightning")b="/api/v1/lightning/get_speech";else if(i.model==="lightning-large"){if(!i.language)throw Error("Language parameter is required for the lightning-large model.");b="/api/v1/lightning-large/get_speech",w.language=i.language}else throw Error(`Unsupported model: ${i.model}`);let _=await(await P.request(b,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(w)})).arrayBuffer(),y=Buffer.from(_),$=i.output_path||o("smallest_tts.wav"),v=await H().writeFile($,y);return JSON.stringify({audio:{url:v,filename:$,mimeType:"audio/wav",size:y.length},message:"Audio generated successfully via Smallest AI"})}catch(w){throw Error(`Smallest AI TTS generation failed: ${w.message}`)}},"smallestai-ttsToWav",{toolName:"smallestAiTtsToWav",toolArgs:Y(i),requestId:n?.requestId})}};import{z as Gn}from"zod";import*as Kw from"fs";var Hn={name:"smallestAiTranscribeAudio",description:"Transcribe audio to text using Smallest AI's Pulse STT. Features low-latency transcriptions.",parameters:Gn.object({audio_path:Gn.string().describe("Absolute local path or URL to the audio file to transcribe."),language:Gn.string().optional().describe("Optional: Language code (e.g. 'en') to improve accuracy.")}),timeoutMs:300000,execute:async(i,n)=>{return f(async()=>{let w=await j(i.audio_path);try{let h=Kw.readFileSync(w.path),_=new Blob([h],{type:"audio/wav"}),y=new FormData;if(y.append("file",_,"audio.wav"),i.language)y.append("language",i.language);let m=await(await P.request("/api/v1/pulse/transcribe",{method:"POST",body:y})).json();return JSON.stringify({message:"Audio transcribed successfully via Smallest AI Pulse STT",transcription:m})}catch(b){throw Error(`Speech to Text transcription failed: ${b.message}`)}finally{w.cleanup()}},"smallestai-transcribeAudio",{toolName:"smallestAiTranscribeAudio",toolArgs:Y(i),requestId:n?.requestId})}};import{z as x}from"zod";import*as jw from"fs";var Bn={name:"smallestAiListVoices",description:"Lists all available pre-set voices from the Smallest AI Waves API.",parameters:x.object({}),timeoutMs:30000,execute:async(i,n)=>{return f(async()=>{try{let b=await(await P.request("/api/v1/lightning/get_voices",{method:"GET"})).json();return JSON.stringify(b)}catch(w){throw Error(`Failed to list Smallest AI voices: ${w.message}`)}},"smallestai-listVoices",{toolName:"smallestAiListVoices",toolArgs:Y(i),requestId:n?.requestId})}},On={name:"smallestAiCreateClone",description:"Creates a new voice clone on the Smallest AI Waves API using a provided audio file.",parameters:x.object({model:x.string().default("lightning-large").describe("The model to use for cloning (e.g., 'lightning-large')."),displayName:x.string().describe("The desired display name for the new clone."),audio_path:x.string().describe("Absolute local path or URL to the source audio file (.wav format recommended).")}),timeoutMs:300000,execute:async(i,n)=>{return f(async()=>{let w=await j(i.audio_path);try{let b=jw.readFileSync(w.path),h=new Blob([b],{type:"audio/wav"}),_=new FormData;_.append("file",h,"voice.wav"),_.append("displayName",i.displayName);let y=`/api/v1/${i.model}/add_voice`,m=await(await P.request(y,{method:"POST",body:_})).json();return JSON.stringify({message:"Voice clone created successfully",data:m})}catch(b){throw Error(`Failed to create Smallest AI voice clone: ${b.message}`)}finally{w.cleanup()}},"smallestai-createClone",{toolName:"smallestAiCreateClone",toolArgs:Y(i),requestId:n?.requestId})}},Kn={name:"smallestAiListClones",description:"Lists the available voice clones for a specified model from the Smallest AI Waves API.",parameters:x.object({model:x.string().default("lightning-large").describe("The model for which to list clones (e.g., 'lightning-large').")}),timeoutMs:30000,execute:async(i,n)=>{return f(async()=>{try{let w=`/api/v1/${i.model}/get_cloned_voices`,h=await(await P.request(w,{method:"GET"})).json();return JSON.stringify(h)}catch(w){throw Error(`Failed to list Smallest AI clones: ${w.message}`)}},"smallestai-listClones",{toolName:"smallestAiListClones",toolArgs:Y(i),requestId:n?.requestId})}},jn={name:"smallestAiDeleteClone",description:"Deletes a specific voice clone from the Smallest AI API.",parameters:x.object({model:x.string().default("lightning-large").describe("The model the clone belongs to."),voiceId:x.string().describe("The unique identifier of the voice clone to delete.")}),timeoutMs:30000,execute:async(i,n)=>{return f(async()=>{try{let w=`/api/v1/${i.model}`,h=await(await P.request(w,{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({voiceId:i.voiceId})})).json();return JSON.stringify({message:"Clone deleted successfully",data:h})}catch(w){throw Error(`Failed to delete Smallest AI clone: ${w.message}`)}},"smallestai-deleteClone",{toolName:"smallestAiDeleteClone",toolArgs:Y(i),requestId:n?.requestId})}};import{z as ii}from"zod";D();R();_i();import*as Aw from"fs";var Vi="https://mixio--qwen-image-edit-qwenimageeditapp-web.modal.run",Cw="https://mixio--qwen-image-edit-qwenimageeditapp-face-swap-web.modal.run/face-swap",Dn="https://grok2api.mixio.pro",Dw="GROK_API_KEY";function An(){let i=process.env[Dw];if(!i)throw Error(`${Dw} environment variable not set`);return i}async function k(i,n,w){let b=await j(w);try{let h;if(b.isTemp)h=Aw.readFileSync(b.path);else{let V=H();h=Buffer.from(await V.readFile(b.path))}let _=b.path.split("/").pop()||"image.png",y=_.split(".").pop()?.toLowerCase()||"png",m={png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",webp:"image/webp"}[y]||"image/png",v=new Blob([new Uint8Array(h)],{type:m});i.append(n,v,_)}catch(h){throw M.error(`Failed to read image for Mixio: ${h.message}`),h}finally{b.cleanup()}}async function Ri(i,n,w="mixio_result.png"){let b=H(),h=n||o(w),_;if(Buffer.isBuffer(i))_=i;else if(i.startsWith("data:image")){let $=i.split(",")[1]||"";_=Buffer.from($,"base64")}else if(i.startsWith("http")||i.startsWith("https")){let $=await fetch(i);if(!$.ok)throw Error(`Failed to download image from ${i}`);_=Buffer.from(await $.arrayBuffer())}else _=Buffer.from(i,"base64");return{url:await b.writeFile(h,_),path:h}}async function z(i,n,w="mixio_result"){let b=i.headers.get("content-type")||"";if(b.includes("application/json")){let y=await i.json();if(y.url)return await Ri(y.url,n,`${w}.png`);let $=y.image||y.data;if(Array.isArray($)){let m=$[0];$=m?.url||m?.image||m}if($)return await Ri($,n,`${w}.png`);return y}if(b.includes("application/zip")){let y=Buffer.from(await i.arrayBuffer()),{url:$,path:m}=await Ri(y,n,`${w}.zip`);return{status:"COMPLETED",message:"Batch results generated as a ZIP archive.",zip_url:$,zip_path:m}}let h=Buffer.from(await i.arrayBuffer()),_=b.includes("jpeg")?"jpg":"png";return await Ri(h,n,`${w}.${_}`)}var hh=ii.enum(["front view","front-right quarter view","right side view","back-right quarter view","back view","back-left quarter view","left side view","front-left quarter view"]),_h=ii.enum(["low-angle shot","eye-level shot","elevated shot","high-angle shot"]),yh=ii.enum(["close-up","medium shot","wide shot"]),$h={name:"mixio_multi_angle",description:`Precise 3D-like camera control for image editing using Qwen-Image-Edit-2511. Use this for steering azimuth, elevation, and distance of the camera relative to the subject.
7
+
8
+ **Prompt Format**: [azimuth] [elevation] [distance] [instruction]
9
+ - **Azimuth**: front view, front-right, right, back-right, back, back-left, left, front-left.
10
+ - **Elevation**: high-angle shot, eye-level shot, low-angle shot, bird-view, worm-view.
11
+ - **Distance**: extreme wide shot, wide shot, medium shot, close up, macro shot.
12
+
13
+ Example: 'front view eye-level shot medium shot turn the car red'`,parameters:ii.object({image_path:ii.string().describe("Absolute local path or URL to the base image."),azimuth:hh.describe("Horizontal angle (e.g., 'front view', 'right side view')."),elevation:_h.describe("Vertical angle (e.g., 'eye-level shot', 'high-angle shot')."),distance:yh.describe("Camera distance or zoom (e.g., 'medium shot', 'wide shot')."),negative_prompt:ii.string().optional().default("").describe("Elements to avoid."),seed:ii.number().optional().default(42).describe("Random seed."),output_path:ii.string().describe("Local path to save the resulting PNG.")}),timeoutMs:120000,async execute(i,n){return f(async()=>{let w=new FormData;await k(w,"image",i.image_path);let h=[i.azimuth,i.elevation,i.distance].join(" ").trim();if(w.append("prompt",h),w.append("lora_type","multi_angle"),w.append("negative_prompt",i.negative_prompt||""),w.append("seed",(i.seed??42).toString()),n?.streamContent)await n.streamContent({type:"text",text:"[Mixio] Submitting Multi-Angle edit request..."});let _=await fetch(Vi,{method:"POST",body:w});if(!_.ok){let $=await _.text();throw Error(`Mixio API error [${_.status}]: ${$}`)}let y=await z(_,i.output_path);return JSON.stringify({status:"COMPLETED",message:"Multi-angle edit completed.",...y,seed:i.seed??42})},"mixioMultiAngle",{toolName:"mixio_multi_angle",toolArgs:Y(i),requestId:n?.requestId})}};import{z as U}from"zod";var vh=U.enum(["front view","front-right quarter view","right side view","back-right quarter view","back view","back-left quarter view","left side view","front-left quarter view"]),dh=U.enum(["low-angle shot","eye-level shot","elevated shot","high-angle shot"]),Jh=U.enum(["close-up","medium shot","wide shot"]),Mh={name:"mixio_multi_angle_batch",description:`Precise 3D-like camera control for image editing using Qwen-Image-Edit-2511. Generates multiple images in a single batch process and returns a ZIP file.
14
+
15
+ **Prompt Format**: Each batch prompt optionally takes [azimuth] [elevation] [distance] [instruction]`,parameters:U.object({image_path:U.string().describe("Absolute local path or URL to the base image."),batch_prompts:U.array(U.object({azimuth:vh,elevation:dh,distance:Jh})).describe("Array of configurations for batch processing. Returns a .zip containing all generated images."),negative_prompt:U.string().optional().default("").describe("Elements to avoid."),seed:U.number().optional().default(42).describe("Random seed."),output_path:U.string().describe("Local path to save the resulting ZIP archive.")}),timeoutMs:180000,async execute(i,n){return f(async()=>{if(!i.batch_prompts||i.batch_prompts.length===0)throw Error("batch_prompts array cannot be empty.");let w=new FormData;await k(w,"image",i.image_path);for(let _ of i.batch_prompts){let y=[_.azimuth,_.elevation,_.distance];w.append("prompt",y.join(" ").trim())}if(w.append("lora_type","multi_angle"),w.append("negative_prompt",i.negative_prompt||""),w.append("seed",(i.seed??42).toString()),n?.streamContent)await n.streamContent({type:"text",text:`[Mixio] Submitting Multi-Angle Batch edit request for ${i.batch_prompts.length} prompts...`});let b=await fetch(Vi,{method:"POST",body:w});if(!b.ok){let _=await b.text();throw Error(`Mixio API error [${b.status}]: ${_}`)}let h=await z(b,i.output_path);return JSON.stringify({status:"COMPLETED",message:"Multi-angle batch edit completed.",...h,seed:i.seed??42})},"mixioMultiAngleBatch",{toolName:"mixio_multi_angle_batch",toolArgs:Y(i),requestId:n?.requestId})}};import{z as Zi}from"zod";var mh={name:"mixio_next_scene",description:`Cinematic scene transition and narrative progression tool using Qwen-Image-Edit-2511. Generates the next logical visual state or camera movement based on the input image.
16
+
17
+ Example: 'The camera drifts slowly forward as mist thickens and the warrior unsheathes her glowing sword.'`,parameters:Zi.object({image_path:Zi.string().describe("Absolute local path or URL to the current scene image."),prompt:Zi.string().describe("Instruction for the next cinematic beat or camera motion."),negative_prompt:Zi.string().optional().default("").describe("Elements to avoid."),seed:Zi.number().optional().default(42).describe("Random seed."),output_path:Zi.string().describe("Local path to save the resulting PNG.")}),timeoutMs:120000,async execute(i,n){return f(async()=>{let w=new FormData;if(await k(w,"image",i.image_path),w.append("prompt",i.prompt),w.append("lora_type","next_scene"),w.append("negative_prompt",i.negative_prompt||""),w.append("seed",(i.seed??42).toString()),n?.streamContent)await n.streamContent({type:"text",text:"[Mixio] Submitting Next-Scene request..."});let b=await fetch(Vi,{method:"POST",body:w});if(!b.ok){let _=await b.text();throw Error(`Mixio API error [${b.status}]: ${_}`)}let h=await z(b,i.output_path);return JSON.stringify({status:"COMPLETED",message:"Next-scene transition completed.",...h,seed:i.seed??42})},"mixioNextScene",{toolName:"mixio_next_scene",toolArgs:Y(i),requestId:n?.requestId})}};import{z as Xi}from"zod";var Vh={name:"mixio_face_swap",description:`High-fidelity face transplanting tool using Qwen-Image-Edit-2511. Specifically designed to swap a subject's face onto a base body image while maintaining extreme structural and environmental consistency.
18
+
19
+ HOW IT WORKS:
20
+ - **Body Image**: The primary image providing the environment, lighting, and pose.
21
+ - **Face Image**: The source image for the facial features (eyes, nose, hair, skin tone).
22
+ - **Structural Preservation**: The tool strictly preserves the physical traits of the face image while adapting expressions and orientation from the body image.`,parameters:Xi.object({body_image_path:Xi.string().describe("Absolute local path or URL to the base body image (Target)."),face_image_path:Xi.string().describe("Absolute local path or URL to the face source image (Source)."),negative_prompt:Xi.string().optional().default("").describe("What to avoid in the generation."),seed:Xi.number().optional().default(42).describe("Random seed for reproducibility."),output_path:Xi.string().describe("Local path to save the resulting PNG.")}),timeoutMs:120000,async execute(i,n){return f(async()=>{let w=new FormData;if(await k(w,"body_image",i.body_image_path),await k(w,"face_image",i.face_image_path),w.append("negative_prompt",i.negative_prompt||""),w.append("seed",(i.seed??42).toString()),n?.streamContent)await n.streamContent({type:"text",text:"[Mixio] Submitting face swap request..."});let b=await fetch(Cw,{method:"POST",body:w});if(!b.ok){let _=await b.text();throw Error(`Mixio Face Swap API error [${b.status}]: ${_}`)}let h=await z(b,i.output_path);return JSON.stringify({status:"COMPLETED",message:"Face swapped successfully.",...h,seed:i.seed??42})},"mixioFaceSwap",{toolName:"mixio_face_swap",toolArgs:Y(i),requestId:n?.requestId})}};import{z as E}from"zod";var Cn={name:"mixioEditImage",description:"Edit an image using premium image models. This tool allows for image-to-image transformations based on a prompt.",parameters:E.object({image_path:E.string().describe("Absolute local path or URL to the source image."),prompt:E.string().describe("Descriptive text for the desired changes."),output_path:E.string().describe("Local path to save the resulting edited image."),n:E.number().optional().default(1).describe("Number of images to generate."),size:E.enum(["1280x720","720x1280","1792x1024","1024x1792","1024x1024"]).describe("Target resolution. Refer to the production bible for default values.")}),timeoutMs:120000,async execute(i,n){return f(async()=>{let w=An(),b=new FormData;if(await k(b,"image",i.image_path),b.append("model","grok-imagine-1.0-edit"),b.append("prompt",i.prompt),b.append("n",(i.n??1).toString()),b.append("size",i.size),n?.streamContent)await n.streamContent({type:"text",text:"[Mixio] Submitting image edit request..."});let h=await fetch(`${Dn}/v1/images/edits`,{method:"POST",headers:{Authorization:`Bearer ${w}`},body:b});if(!h.ok){let y=await h.text();throw Error(`Image Edit API error [${h.status}]: ${y}`)}let _=await z(h,i.output_path);return JSON.stringify({status:"COMPLETED",message:"Image edited successfully.",..._})},"mixioEditImage",{toolName:"mixioEditImage",toolArgs:Y(i),requestId:n?.requestId})}},Fn={name:"mixioImageToVideo",description:"Generate video from an image or text using premium video models.",parameters:E.object({prompt:E.string().describe("Descriptive text for the video action."),image_path:E.string().optional().describe("Absolute local path or URL to the starting image frame."),output_path:E.string().describe("Local path to save the resulting video."),seconds:E.number().min(6).max(30).optional().default(6).describe("Duration in seconds (6-30)."),quality:E.enum(["standard","high"]).optional().default("standard").describe("Video quality: 'standard' (480p) or 'high' (720p)."),size:E.enum(["1280x720","720x1280","1792x1024","1024x1792","1024x1024"]).describe("Target resolution. Refer to the production bible for default values.")}),timeoutMs:300000,async execute(i,n){return f(async()=>{let w=An(),b=i.image_path?.startsWith("http"),h=new FormData;if(i.image_path&&!b)await k(h,"input_reference",i.image_path),h.append("model","grok-imagine-1.0-video"),h.append("prompt",i.prompt),h.append("seconds",(i.seconds??6).toString()),h.append("quality",i.quality??"standard"),h.append("size",i.size);let _={model:"grok-imagine-1.0-video",prompt:i.prompt,seconds:i.seconds??6,quality:i.quality??"standard",size:i.size};if(b)_.image_reference={image_url:i.image_path};if(n?.streamContent)await n.streamContent({type:"text",text:"[Mixio] Submitting video generation request..."});let y=await fetch(`${Dn}/v1/videos`,{method:"POST",headers:{Authorization:`Bearer ${w}`,...i.image_path&&!b?{}:{"Content-Type":"application/json"}},body:i.image_path&&!b?h:JSON.stringify(_)});if(!y.ok){let V=await y.text();throw Error(`Video Generation API error [${y.status}]: ${V}`)}let $=await y.json(),m=$.data?.[0]?.url||$.url||$.choices?.[0]?.video?.url;if(!m)throw Error(`Failed to find video URL in response: ${JSON.stringify($)}`);let v=await z(new Response(JSON.stringify({url:m}),{headers:{"Content-Type":"application/json"}}),i.output_path,"mixio_video");return JSON.stringify({status:"COMPLETED",message:"Video generated successfully.",...v})},"mixioImageToVideo",{toolName:"mixioImageToVideo",toolArgs:Y(i),requestId:n?.requestId})}};a();D();import{z as Xh}from"zod";var B=new Zh({name:"Kalaasetu MCP Server",version:ci.version});async function Wh(){let i=process.argv.slice(2),n=i.find((v)=>v.startsWith("--transport=")),w=i.find((v)=>v.startsWith("--port=")),b=n?.split("=")[1]??"stdio",h=w?.split("=")[1],_=h?parseInt(h,10):3000;M.info("\uD83D\uDE80 Initializing Kalaasetu MCP Server...");let y=i.includes("--no-remote-config");await Ei({enabled:!y}),await Promise.all([on()]);let $=process.env.GOOGLE_VEO_ENABLED!=="false",m=process.env.GOOGLE_IMAGE_ENABLED!=="false";if($)B.addTool(fw),B.addTool(Bw);if(m)B.addTool(vw),B.addTool(mw);if(process.env.WAVES_ENABLED&&process.env.WAVES_API_KEY)B.addTool(Qn),B.addTool(Hn),B.addTool(On),B.addTool(Kn),B.addTool(jn),B.addTool(Bn);if(process.env.FAL_ENABLED&&process.env.FAL_KEY){B.addTool(hn),B.addTool(_n),B.addTool(dn),B.addTool(vn);let v=iw();for(let V of v)B.addTool(V)}if(process.env.GROK_ENABLED==="true")B.addTool(Cn),B.addTool(Fn);if(B.addTool(Yw),B.addTool({name:"get_version_"+process.env.CLIENT_ID,description:"Get the current version of the Kalaasetu MCP server",parameters:Xh.object({}),execute:async()=>{return JSON.stringify({version:ci.version,clientId:process.env.CLIENT_ID,projectId:process.env.PROJECT_ID,env:process.env,mixioTokenFound:process.env.MIXIO_TOKEN_FOUND,mixioToken:process.env.MIXIO_TOKEN})}}),b==="sse"||b==="httpStream")M.info(`\u2705 Starting server on port ${_} with transport: ${b}...`),B.start({transportType:"httpStream",httpStream:{port:_}});else M.info("\u2705 Starting server with transport: stdio..."),B.start({transportType:"stdio"})}Wh().catch((i)=>{M.error("\u274C Failed to start server:",i),process.exit(1)});
@@ -0,0 +1,12 @@
1
+ import type { StorageProvider } from "./interface";
2
+ export declare class GCSStorageProvider implements StorageProvider {
3
+ private bucket;
4
+ private auth;
5
+ constructor(bucket: string);
6
+ init(): Promise<void>;
7
+ private getAccessToken;
8
+ readFile(filePath: string): Promise<Buffer>;
9
+ writeFile(filePath: string, data: Buffer | string): Promise<string>;
10
+ exists(filePath: string): Promise<boolean>;
11
+ getPublicUrl(filePath: string): Promise<string>;
12
+ }
@@ -0,0 +1,87 @@
1
+ import { GoogleAuth } from "google-auth-library";
2
+ import * as path from "path";
3
+ import { getGoogleAuthClient, getGoogleAccessToken, } from "../utils/google-auth";
4
+ export class GCSStorageProvider {
5
+ bucket;
6
+ auth = null;
7
+ constructor(bucket) {
8
+ this.bucket = bucket;
9
+ }
10
+ async init() {
11
+ this.auth = await getGoogleAuthClient({
12
+ scopes: ["https://www.googleapis.com/auth/cloud-platform"],
13
+ });
14
+ try {
15
+ await this.auth.getClient();
16
+ }
17
+ catch (error) {
18
+ console.warn(`Warning: Could not initialize GCS client: ${error}`);
19
+ }
20
+ }
21
+ async getAccessToken() {
22
+ // Use the centralized helper which includes gcloud fallback if needed,
23
+ // although GCSStorageProvider primarily relies on the initialized GoogleAuth.
24
+ // However, if we want to support the same fallback logic as tools:
25
+ return getGoogleAccessToken({
26
+ scopes: ["https://www.googleapis.com/auth/cloud-platform"],
27
+ });
28
+ }
29
+ async readFile(filePath) {
30
+ const objectName = path.basename(filePath);
31
+ const url = `https://storage.googleapis.com/storage/v1/b/${this.bucket}/o/${encodeURIComponent(objectName)}?alt=media`;
32
+ const token = await this.getAccessToken();
33
+ const response = await fetch(url, {
34
+ headers: {
35
+ Authorization: `Bearer ${token}`,
36
+ },
37
+ });
38
+ if (!response.ok) {
39
+ throw new Error(`Failed to read file from GCS: ${response.status} ${response.statusText}`);
40
+ }
41
+ const arrayBuffer = await response.arrayBuffer();
42
+ return Buffer.from(arrayBuffer);
43
+ }
44
+ async writeFile(filePath, data) {
45
+ const objectName = path.basename(filePath);
46
+ const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
47
+ // Upload using JSON API
48
+ const url = `https://storage.googleapis.com/upload/storage/v1/b/${this.bucket}/o?uploadType=media&name=${encodeURIComponent(objectName)}`;
49
+ const token = await this.getAccessToken();
50
+ const response = await fetch(url, {
51
+ method: "POST",
52
+ headers: {
53
+ Authorization: `Bearer ${token}`,
54
+ "Content-Type": "application/octet-stream",
55
+ "Content-Length": buffer.length.toString(),
56
+ },
57
+ body: new Uint8Array(buffer),
58
+ });
59
+ if (!response.ok) {
60
+ const errorText = await response.text();
61
+ throw new Error(`Failed to upload to GCS: ${response.status} ${errorText}`);
62
+ }
63
+ // Return public URL
64
+ return `https://storage.googleapis.com/${this.bucket}/${objectName}`;
65
+ }
66
+ async exists(filePath) {
67
+ try {
68
+ const objectName = path.basename(filePath);
69
+ const url = `https://storage.googleapis.com/storage/v1/b/${this.bucket}/o/${encodeURIComponent(objectName)}`;
70
+ const token = await this.getAccessToken();
71
+ const response = await fetch(url, {
72
+ method: "GET",
73
+ headers: {
74
+ Authorization: `Bearer ${token}`,
75
+ },
76
+ });
77
+ return response.ok;
78
+ }
79
+ catch {
80
+ return false;
81
+ }
82
+ }
83
+ async getPublicUrl(filePath) {
84
+ const objectName = path.basename(filePath);
85
+ return `https://storage.googleapis.com/${this.bucket}/${objectName}`;
86
+ }
87
+ }
@@ -0,0 +1,2 @@
1
+ import type { StorageProvider } from "./interface";
2
+ export declare function getStorage(): StorageProvider;
@@ -0,0 +1,26 @@
1
+ import { LocalStorageProvider } from "./local";
2
+ import { GCSStorageProvider } from "./gcs";
3
+ import { logger } from "../utils/logger";
4
+ let storageInstance = null;
5
+ export function getStorage() {
6
+ if (!storageInstance) {
7
+ const type = process.env.STORAGE_PROVIDER || "local";
8
+ logger.info(`Initializing storage provider: ${type}`);
9
+ logger.info(`Base path (cwd): ${process.cwd()}`);
10
+ if (type === "gcs") {
11
+ const bucket = process.env.GCS_BUCKET;
12
+ if (!bucket) {
13
+ throw new Error("GCS_BUCKET is required when using gcs storage");
14
+ }
15
+ storageInstance = new GCSStorageProvider(bucket);
16
+ }
17
+ else {
18
+ storageInstance = new LocalStorageProvider(process.cwd());
19
+ }
20
+ // Initialize async
21
+ storageInstance
22
+ .init()
23
+ .catch((err) => logger.error("Failed to init storage:", err));
24
+ }
25
+ return storageInstance;
26
+ }
@@ -0,0 +1,7 @@
1
+ export interface StorageProvider {
2
+ init(): Promise<void>;
3
+ readFile(path: string): Promise<Buffer>;
4
+ writeFile(path: string, data: Buffer | string): Promise<string>;
5
+ exists(path: string): Promise<boolean>;
6
+ getPublicUrl(path: string): Promise<string>;
7
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { StorageProvider } from "./interface";
2
+ export declare class LocalStorageProvider implements StorageProvider {
3
+ private basePath;
4
+ constructor(basePath?: string);
5
+ init(): Promise<void>;
6
+ readFile(filePath: string): Promise<Buffer>;
7
+ writeFile(filePath: string, data: Buffer | string): Promise<string>;
8
+ exists(filePath: string): Promise<boolean>;
9
+ getPublicUrl(filePath: string): Promise<string>;
10
+ }
@@ -0,0 +1,50 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ export class LocalStorageProvider {
4
+ basePath;
5
+ constructor(basePath = process.cwd()) {
6
+ this.basePath = basePath;
7
+ }
8
+ async init() {
9
+ // No-op for local
10
+ }
11
+ async readFile(filePath) {
12
+ let fullPath = filePath;
13
+ if (!path.isAbsolute(filePath)) {
14
+ fullPath = path.resolve(this.basePath, filePath);
15
+ }
16
+ return fs.promises.readFile(fullPath);
17
+ }
18
+ async writeFile(filePath, data) {
19
+ let fullPath = filePath;
20
+ if (!path.isAbsolute(filePath)) {
21
+ fullPath = path.resolve(this.basePath, filePath);
22
+ }
23
+ const dir = path.dirname(fullPath);
24
+ if (!fs.existsSync(dir)) {
25
+ await fs.promises.mkdir(dir, { recursive: true });
26
+ }
27
+ await fs.promises.writeFile(fullPath, data);
28
+ return fullPath;
29
+ }
30
+ async exists(filePath) {
31
+ let fullPath = filePath;
32
+ if (!path.isAbsolute(filePath)) {
33
+ fullPath = path.resolve(this.basePath, filePath);
34
+ }
35
+ try {
36
+ await fs.promises.access(fullPath, fs.constants.F_OK);
37
+ return true;
38
+ }
39
+ catch {
40
+ return false;
41
+ }
42
+ }
43
+ async getPublicUrl(filePath) {
44
+ let fullPath = filePath;
45
+ if (!path.isAbsolute(filePath)) {
46
+ fullPath = path.resolve(this.basePath, filePath);
47
+ }
48
+ return fullPath;
49
+ }
50
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Shared utilities for BytePlus Seedance video generation tools.
3
+ */
4
+ export declare const DEFAULT_MODEL = "seedance-1-5-pro-251215";
5
+ export declare function wait(ms: number): Promise<void>;
6
+ /**
7
+ * Resolve an image input (local path or URL) to a URL usable by the BytePlus API.
8
+ * Local files are converted to base64 data URIs.
9
+ * HTTP(S) URLs are returned as-is.
10
+ */
11
+ export declare function resolveImageUrl(input: string): Promise<string>;
12
+ /**
13
+ * Ensure the BYTEPLUS_API_KEY env var is set.
14
+ */
15
+ export declare function requireApiKey(): string;
16
+ /**
17
+ * Submit a video generation task to the BytePlus API.
18
+ * Returns the task ID.
19
+ */
20
+ export declare function createTask(apiKey: string, requestBody: any): Promise<string>;
21
+ /**
22
+ * Check the current status of a task.
23
+ * Returns the raw API response object.
24
+ */
25
+ export declare function getTaskStatus(apiKey: string, taskId: string): Promise<any>;
26
+ /**
27
+ * Download a video from a URL and save it to storage.
28
+ * Returns the saved file path/URL, or undefined if download failed.
29
+ */
30
+ export declare function downloadAndSaveVideo(videoUrl: string, outputPath?: string, fileNameDefault?: string): Promise<string | undefined>;
31
+ /**
32
+ * Poll a BytePlus task until it reaches a terminal state or the timeout expires.
33
+ *
34
+ * Returns { status, result, taskId } where:
35
+ * - status: "succeeded" | "failed" | "cancelled" | "expired" | "timeout"
36
+ * - result: the raw API response (for succeeded/failed)
37
+ * - taskId: the task ID being polled
38
+ */
39
+ export declare function pollUntilDone(apiKey: string, taskId: string, context: any, maxPollMs?: number, label?: string): Promise<{
40
+ status: string;
41
+ result: any;
42
+ taskId: string;
43
+ }>;