@agimon-ai/video-editor-mcp 0.10.2 → 0.10.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const e=require(`./stdio-1ofTrT91.cjs`);let t=require(`node:child_process`),n=require(`node:fs`);n=e.M(n,1);let r=require(`node:path`);r=e.M(r,1);let i=require(`commander`),a=require(`@agimon-ai/foundation-port-registry`),o=require(`@agimon-ai/foundation-process-registry`),s=require(`chalk`);s=e.M(s,1);var c=`0.10.1`;const l=[`pnpm-workspace.yaml`,`nx.json`,`.git`],u=`video-editor-mcp-http`,d=`tool`;function f(e=process.cwd()){let t=r.default.resolve(e);for(;;){for(let e of l)if((0,n.existsSync)(r.default.join(t,e)))return t;let e=r.default.dirname(t);if(e===t)return process.cwd();t=e}}const p=new i.Command(`http-serve`).description(`Start Remotion Studio for video editing`).option(`-p, --port <port>`,`Port to run Remotion Studio on`,String(a.DEFAULT_PORT_RANGE.min)).action(async e=>{let n;try{let i=Number.parseInt(e.port,10),c=new a.PortRegistryService(process.env.PORT_REGISTRY_PATH),l=f(),p=i?{min:i,max:i}:a.DEFAULT_PORT_RANGE,m=await c.reservePort({repositoryPath:l,serviceName:u,serviceType:d,preferredPort:i||a.DEFAULT_PORT_RANGE.min,portRange:p,pid:process.pid,host:`127.0.0.1`,force:!0});if(!m.success||!m.record)throw Error(m.error||`Failed to reserve port ${i}`);let h=m.record.port;n=await(0,o.createProcessLease)({repositoryPath:l,serviceName:u,serviceType:d,pid:process.pid,port:h,host:`127.0.0.1`,command:process.argv[1],args:process.argv.slice(2)});let g=r.default.resolve(__dirname,`..`);console.error(s.default.green(`Starting Remotion Studio on port ${h}...`)),console.error(s.default.gray(` Working directory: ${g}`));let _=(0,t.spawn)(r.default.join(g,`node_modules`,`.bin`,`remotion`),[`studio`,`--port`,String(h)],{stdio:`inherit`,cwd:g});_.on(`error`,e=>{console.error(s.default.red(`Failed to start Remotion Studio: ${e.message}`)),process.exit(1)});let v=async e=>{_.kill(e),await n?.release(),await c.releasePort({repositoryPath:l,serviceName:u,serviceType:d,pid:process.pid}),process.exit(0)};process.on(`SIGINT`,()=>v(`SIGINT`)),process.on(`SIGTERM`,()=>v(`SIGTERM`))}catch(e){await n?.release(),console.error(`Error executing http-serve:`,e),process.exit(1)}}),m=[`pnpm-workspace.yaml`,`nx.json`,`.git`];function h(e=process.cwd()){let t=r.default.resolve(e);for(;;){for(let e of m)if((0,n.existsSync)(r.default.join(t,e)))return t;let e=r.default.dirname(t);if(e===t)return process.cwd();t=e}}async function g(e,t){await e.start();let n=async n=>{console.error(`\nReceived ${n}, shutting down gracefully...`);try{await e.stop(),await t?.(),process.exit(0)}catch(e){console.error(`Error during shutdown:`,e),process.exit(1)}};process.on(`SIGINT`,()=>n(`SIGINT`)),process.on(`SIGTERM`,()=>n(`SIGTERM`))}const _=new i.Command(`mcp-serve`).description(`Start MCP server with specified transport`).option(`-t, --type <type>`,`Transport type: stdio`,`stdio`).option(`--proxy <url>`,`Proxy URL for yt-dlp (HTTP/HTTPS/SOCKS5, e.g. socks5://user:pass@host:port)`).action(async t=>{let n;try{let r=t.type.toLowerCase(),i=h();if(r===`stdio`){let r=new e.t(e.n(e.r({proxyUrl:t.proxy})));n=await(0,o.createProcessLease)({repositoryPath:i,serviceName:`video-editor-mcp-stdio`,pid:process.pid,metadata:{transport:`stdio`}}),await g(r,async()=>{await n?.release()})}else console.error(`Unknown transport type: ${r}. Use: stdio`),process.exit(1)}catch(e){await n?.release(),console.error(`Failed to start MCP server:`,e),process.exit(1)}}),v=new i.Command(`analyze-video`).description(`Analyze one or more local video files with Gemini Code Assist`).requiredOption(`-v, --video <paths...>`,`Paths to local video files to analyze`).requiredOption(`-p, --prompt <text>`,`Prompt to send with the video(s)`).option(`-m, --model <id>`,`Gemini model to use`,`gemini-2.5-flash-lite`).option(`--pretty`,`Pretty-print the full JSON result`,!1).action(async t=>{try{if(!Array.isArray(t.video)||t.video.length===0)throw Error(`At least one video path is required.`);process.stderr.write(s.default.blue(`🎥 Starting video analysis...
2
+ const e=require(`./stdio-1ofTrT91.cjs`);let t=require(`node:child_process`),n=require(`node:fs`);n=e.M(n,1);let r=require(`node:path`);r=e.M(r,1);let i=require(`commander`),a=require(`@agimon-ai/foundation-port-registry`),o=require(`@agimon-ai/foundation-process-registry`),s=require(`chalk`);s=e.M(s,1);var c=`0.10.3`;const l=[`pnpm-workspace.yaml`,`nx.json`,`.git`],u=`video-editor-mcp-http`,d=`tool`;function f(e=process.cwd()){let t=r.default.resolve(e);for(;;){for(let e of l)if((0,n.existsSync)(r.default.join(t,e)))return t;let e=r.default.dirname(t);if(e===t)return process.cwd();t=e}}const p=new i.Command(`http-serve`).description(`Start Remotion Studio for video editing`).option(`-p, --port <port>`,`Port to run Remotion Studio on`,String(a.DEFAULT_PORT_RANGE.min)).action(async e=>{let n;try{let i=Number.parseInt(e.port,10),c=new a.PortRegistryService(process.env.PORT_REGISTRY_PATH),l=f(),p=i?{min:i,max:i}:a.DEFAULT_PORT_RANGE,m=await c.reservePort({repositoryPath:l,serviceName:u,serviceType:d,preferredPort:i||a.DEFAULT_PORT_RANGE.min,portRange:p,pid:process.pid,host:`127.0.0.1`,force:!0});if(!m.success||!m.record)throw Error(m.error||`Failed to reserve port ${i}`);let h=m.record.port;n=await(0,o.createProcessLease)({repositoryPath:l,serviceName:u,serviceType:d,pid:process.pid,port:h,host:`127.0.0.1`,command:process.argv[1],args:process.argv.slice(2)});let g=r.default.resolve(__dirname,`..`);console.error(s.default.green(`Starting Remotion Studio on port ${h}...`)),console.error(s.default.gray(` Working directory: ${g}`));let _=(0,t.spawn)(r.default.join(g,`node_modules`,`.bin`,`remotion`),[`studio`,`--port`,String(h)],{stdio:`inherit`,cwd:g});_.on(`error`,e=>{console.error(s.default.red(`Failed to start Remotion Studio: ${e.message}`)),process.exit(1)});let v=async e=>{_.kill(e),await n?.release(),await c.releasePort({repositoryPath:l,serviceName:u,serviceType:d,pid:process.pid}),process.exit(0)};process.on(`SIGINT`,()=>v(`SIGINT`)),process.on(`SIGTERM`,()=>v(`SIGTERM`))}catch(e){await n?.release(),console.error(`Error executing http-serve:`,e),process.exit(1)}}),m=[`pnpm-workspace.yaml`,`nx.json`,`.git`];function h(e=process.cwd()){let t=r.default.resolve(e);for(;;){for(let e of m)if((0,n.existsSync)(r.default.join(t,e)))return t;let e=r.default.dirname(t);if(e===t)return process.cwd();t=e}}async function g(e,t){await e.start();let n=async n=>{console.error(`\nReceived ${n}, shutting down gracefully...`);try{await e.stop(),await t?.(),process.exit(0)}catch(e){console.error(`Error during shutdown:`,e),process.exit(1)}};process.on(`SIGINT`,()=>n(`SIGINT`)),process.on(`SIGTERM`,()=>n(`SIGTERM`))}const _=new i.Command(`mcp-serve`).description(`Start MCP server with specified transport`).option(`-t, --type <type>`,`Transport type: stdio`,`stdio`).option(`--proxy <url>`,`Proxy URL for yt-dlp (HTTP/HTTPS/SOCKS5, e.g. socks5://user:pass@host:port)`).action(async t=>{let n;try{let r=t.type.toLowerCase(),i=h();if(r===`stdio`){let r=new e.t(e.n(e.r({proxyUrl:t.proxy})));n=await(0,o.createProcessLease)({repositoryPath:i,serviceName:`video-editor-mcp-stdio`,pid:process.pid,metadata:{transport:`stdio`}}),await g(r,async()=>{await n?.release()})}else console.error(`Unknown transport type: ${r}. Use: stdio`),process.exit(1)}catch(e){await n?.release(),console.error(`Failed to start MCP server:`,e),process.exit(1)}}),v=new i.Command(`analyze-video`).description(`Analyze one or more local video files with Gemini Code Assist`).requiredOption(`-v, --video <paths...>`,`Paths to local video files to analyze`).requiredOption(`-p, --prompt <text>`,`Prompt to send with the video(s)`).option(`-m, --model <id>`,`Gemini model to use`,`gemini-2.5-flash-lite`).option(`--pretty`,`Pretty-print the full JSON result`,!1).action(async t=>{try{if(!Array.isArray(t.video)||t.video.length===0)throw Error(`At least one video path is required.`);process.stderr.write(s.default.blue(`🎥 Starting video analysis...
3
3
  `)),process.stderr.write(s.default.gray(` Videos: ${t.video.join(`, `)}\n`)),process.stderr.write(s.default.gray(` Prompt: ${t.prompt}\n`)),process.stderr.write(s.default.gray(` Model: ${t.model}\n`));let n=await e.r().get(e.h.VideoAnalysisService).analyzeVideos({videoPaths:t.video,prompt:t.prompt,model:t.model});if(process.stderr.write(s.default.green(`✓ Resolved project: ${n.resolvedProject}\n`)),process.stderr.write(s.default.green(`✓ Videos processed: ${n.videoCount}\n`)),t.pretty){process.stdout.write(`${JSON.stringify(n,null,2)}\n`);return}if(n.responseText){process.stdout.write(`${n.responseText}\n`);return}process.stdout.write(`${JSON.stringify(n.rawResponse,null,2)}\n`)}catch(e){let t=e instanceof Error?e.message:String(e);process.stderr.write(s.default.red(`Error analyzing video: ${t}\n`)),process.exit(1)}}),y=e=>Number(e),b=e=>Number.parseInt(e,10),x=()=>(0,n.existsSync)(r.default.resolve(__dirname,`../package.json`))?r.default.resolve(__dirname,`..`):r.default.resolve(__dirname,`../..`),S=e=>{if(e.output)return r.default.resolve(e.output);let t=r.default.resolve(e.outputDir??r.default.join(x(),`public/music`)),n=e.filename??`ace-step-music`;return r.default.join(t,`${n}.${e.audioFormat}`)},C=new i.Command(`generate-music`).description(`Generate background music using ACE-Step 1.5`).requiredOption(`-p, --prompt <text>`,`Music description for ACE-Step text-to-music generation`).option(`-f, --filename <name>`,`Output filename without extension (default: ace-step-music)`).option(`-o, --output <path>`,`Explicit output audio path. Overrides filename/output-dir.`).option(`--output-dir <path>`,`Custom output directory (default: Remotion public/music/)`).option(`--ace-step-path <path>`,`Path to local ACE-Step-1.5 checkout`).option(`--lyrics <text>`,`Lyrics to use. Defaults to [Instrumental] for background music.`).option(`--duration <seconds>`,`Target duration in seconds (default: 30)`,y).option(`--bpm <number>`,`Optional BPM metadata`,y).option(`--keyscale <text>`,`Optional key/scale metadata, e.g. C minor`).option(`--time-signature <text>`,`Optional time signature metadata, e.g. 4/4`).option(`--vocal-language <code>`,`Vocal language code, or unknown`).option(`--seed <number>`,`Optional fixed seed for reproducible generation`,b).option(`--inference-steps <number>`,`Diffusion inference steps (default: 8)`,b).option(`--audio-format <format>`,`Output audio format: wav, mp3, flac`,`wav`).option(`--backend <backend>`,`ACE-Step LM backend: mlx, pt, vllm`,`mlx`).option(`--config-path <name>`,`ACE-Step DiT model config (default: acestep-v15-turbo)`).option(`--lm-model-path <name>`,`ACE-Step LM model (default: acestep-5Hz-lm-0.6B)`).option(`--timeout-ms <number>`,`Generation timeout in milliseconds`,b).option(`--pretty`,`Pretty-print the JSON result`,!1).action(async t=>{try{if(![`wav`,`mp3`,`flac`].includes(t.audioFormat))throw Error(`Unsupported audio format: ${t.audioFormat}`);if(![`mlx`,`pt`,`vllm`].includes(t.backend))throw Error(`Unsupported backend: ${t.backend}`);let n=S(t);process.stderr.write(s.default.blue(`Starting ACE-Step music generation...
4
4
  `)),process.stderr.write(s.default.gray(` Prompt: ${t.prompt}\n`)),process.stderr.write(s.default.gray(` Output: ${n}\n`)),process.stderr.write(s.default.gray(` Backend: ${t.backend}\n`));let i=e.r().get(e.h.AceStepMusicService);if(!await i.isAvailable(t.aceStepPath))throw Error(`ACE-Step 1.5 is not available. Clone https://github.com/ACE-Step/ACE-Step-1.5 and set ACE_STEP_15_DIR or pass --ace-step-path.`);let a=await i.generateMusic({prompt:t.prompt,outputPath:n,aceStepPath:t.aceStepPath,lyrics:t.lyrics,duration:t.duration,bpm:t.bpm,keyscale:t.keyscale,timeSignature:t.timeSignature,vocalLanguage:t.vocalLanguage,seed:t.seed,inferenceSteps:t.inferenceSteps,audioFormat:t.audioFormat,backend:t.backend,configPath:t.configPath,lmModelPath:t.lmModelPath,timeoutMs:t.timeoutMs}),o={...a,compositionSrc:r.default.dirname(n)===r.default.resolve(x(),`public/music`)?`/music/${r.default.basename(n)}`:void 0};process.stderr.write(s.default.green(`Music generated successfully: ${a.outputPath}\n`)),process.stdout.write(`${JSON.stringify(o,null,t.pretty?2:0)}\n`)}catch(e){let t=e instanceof Error?e.message:String(e);process.stderr.write(s.default.red(`Error generating music: ${t}\n`)),process.exit(1)}}),w=new i.Command(`render`).description(`Render a video from JSON props file`).requiredOption(`-i, --input <path>`,`Path to JSON props file`).requiredOption(`-o, --output <path>`,`Output video file path`).option(`-c, --composition <id>`,`Composition ID`,`Main`).option(`--codec <codec>`,`Video codec (h264, h265, vp8, vp9)`,`h264`).option(`--dry-run`,`Validate props and assets without rendering`).action(async t=>{try{process.stderr.write(s.default.blue(t.dryRun?`🔎 Starting render dry run...
5
5
  `:`🎬 Starting video render...
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{_ as e,h as t,n,r,t as i}from"./stdio-KMqWPqUm.mjs";import{spawn as a}from"node:child_process";import o,{existsSync as s}from"node:fs";import c from"node:path";import{Command as l}from"commander";import{DEFAULT_PORT_RANGE as u,PortRegistryService as d}from"@agimon-ai/foundation-port-registry";import{createProcessLease as f}from"@agimon-ai/foundation-process-registry";import p from"chalk";var m=`0.10.1`;const h=[`pnpm-workspace.yaml`,`nx.json`,`.git`],g=`video-editor-mcp-http`,_=`tool`;function v(e=process.cwd()){let t=c.resolve(e);for(;;){for(let e of h)if(s(c.join(t,e)))return t;let e=c.dirname(t);if(e===t)return process.cwd();t=e}}const y=new l(`http-serve`).description(`Start Remotion Studio for video editing`).option(`-p, --port <port>`,`Port to run Remotion Studio on`,String(u.min)).action(async e=>{let t;try{let n=Number.parseInt(e.port,10),r=new d(process.env.PORT_REGISTRY_PATH),i=v(),o=n?{min:n,max:n}:u,s=await r.reservePort({repositoryPath:i,serviceName:g,serviceType:_,preferredPort:n||u.min,portRange:o,pid:process.pid,host:`127.0.0.1`,force:!0});if(!s.success||!s.record)throw Error(s.error||`Failed to reserve port ${n}`);let l=s.record.port;t=await f({repositoryPath:i,serviceName:g,serviceType:_,pid:process.pid,port:l,host:`127.0.0.1`,command:process.argv[1],args:process.argv.slice(2)});let m=c.resolve(import.meta.dirname,`..`);console.error(p.green(`Starting Remotion Studio on port ${l}...`)),console.error(p.gray(` Working directory: ${m}`));let h=a(c.join(m,`node_modules`,`.bin`,`remotion`),[`studio`,`--port`,String(l)],{stdio:`inherit`,cwd:m});h.on(`error`,e=>{console.error(p.red(`Failed to start Remotion Studio: ${e.message}`)),process.exit(1)});let y=async e=>{h.kill(e),await t?.release(),await r.releasePort({repositoryPath:i,serviceName:g,serviceType:_,pid:process.pid}),process.exit(0)};process.on(`SIGINT`,()=>y(`SIGINT`)),process.on(`SIGTERM`,()=>y(`SIGTERM`))}catch(e){await t?.release(),console.error(`Error executing http-serve:`,e),process.exit(1)}}),b=[`pnpm-workspace.yaml`,`nx.json`,`.git`];function x(e=process.cwd()){let t=c.resolve(e);for(;;){for(let e of b)if(s(c.join(t,e)))return t;let e=c.dirname(t);if(e===t)return process.cwd();t=e}}async function S(e,t){await e.start();let n=async n=>{console.error(`\nReceived ${n}, shutting down gracefully...`);try{await e.stop(),await t?.(),process.exit(0)}catch(e){console.error(`Error during shutdown:`,e),process.exit(1)}};process.on(`SIGINT`,()=>n(`SIGINT`)),process.on(`SIGTERM`,()=>n(`SIGTERM`))}const C=new l(`mcp-serve`).description(`Start MCP server with specified transport`).option(`-t, --type <type>`,`Transport type: stdio`,`stdio`).option(`--proxy <url>`,`Proxy URL for yt-dlp (HTTP/HTTPS/SOCKS5, e.g. socks5://user:pass@host:port)`).action(async e=>{let t;try{let a=e.type.toLowerCase(),o=x();if(a===`stdio`){let a=new i(n(r({proxyUrl:e.proxy})));t=await f({repositoryPath:o,serviceName:`video-editor-mcp-stdio`,pid:process.pid,metadata:{transport:`stdio`}}),await S(a,async()=>{await t?.release()})}else console.error(`Unknown transport type: ${a}. Use: stdio`),process.exit(1)}catch(e){await t?.release(),console.error(`Failed to start MCP server:`,e),process.exit(1)}}),w=new l(`analyze-video`).description(`Analyze one or more local video files with Gemini Code Assist`).requiredOption(`-v, --video <paths...>`,`Paths to local video files to analyze`).requiredOption(`-p, --prompt <text>`,`Prompt to send with the video(s)`).option(`-m, --model <id>`,`Gemini model to use`,`gemini-2.5-flash-lite`).option(`--pretty`,`Pretty-print the full JSON result`,!1).action(async e=>{try{if(!Array.isArray(e.video)||e.video.length===0)throw Error(`At least one video path is required.`);process.stderr.write(p.blue(`🎥 Starting video analysis...
2
+ import{_ as e,h as t,n,r,t as i}from"./stdio-KMqWPqUm.mjs";import{spawn as a}from"node:child_process";import o,{existsSync as s}from"node:fs";import c from"node:path";import{Command as l}from"commander";import{DEFAULT_PORT_RANGE as u,PortRegistryService as d}from"@agimon-ai/foundation-port-registry";import{createProcessLease as f}from"@agimon-ai/foundation-process-registry";import p from"chalk";var m=`0.10.3`;const h=[`pnpm-workspace.yaml`,`nx.json`,`.git`],g=`video-editor-mcp-http`,_=`tool`;function v(e=process.cwd()){let t=c.resolve(e);for(;;){for(let e of h)if(s(c.join(t,e)))return t;let e=c.dirname(t);if(e===t)return process.cwd();t=e}}const y=new l(`http-serve`).description(`Start Remotion Studio for video editing`).option(`-p, --port <port>`,`Port to run Remotion Studio on`,String(u.min)).action(async e=>{let t;try{let n=Number.parseInt(e.port,10),r=new d(process.env.PORT_REGISTRY_PATH),i=v(),o=n?{min:n,max:n}:u,s=await r.reservePort({repositoryPath:i,serviceName:g,serviceType:_,preferredPort:n||u.min,portRange:o,pid:process.pid,host:`127.0.0.1`,force:!0});if(!s.success||!s.record)throw Error(s.error||`Failed to reserve port ${n}`);let l=s.record.port;t=await f({repositoryPath:i,serviceName:g,serviceType:_,pid:process.pid,port:l,host:`127.0.0.1`,command:process.argv[1],args:process.argv.slice(2)});let m=c.resolve(import.meta.dirname,`..`);console.error(p.green(`Starting Remotion Studio on port ${l}...`)),console.error(p.gray(` Working directory: ${m}`));let h=a(c.join(m,`node_modules`,`.bin`,`remotion`),[`studio`,`--port`,String(l)],{stdio:`inherit`,cwd:m});h.on(`error`,e=>{console.error(p.red(`Failed to start Remotion Studio: ${e.message}`)),process.exit(1)});let y=async e=>{h.kill(e),await t?.release(),await r.releasePort({repositoryPath:i,serviceName:g,serviceType:_,pid:process.pid}),process.exit(0)};process.on(`SIGINT`,()=>y(`SIGINT`)),process.on(`SIGTERM`,()=>y(`SIGTERM`))}catch(e){await t?.release(),console.error(`Error executing http-serve:`,e),process.exit(1)}}),b=[`pnpm-workspace.yaml`,`nx.json`,`.git`];function x(e=process.cwd()){let t=c.resolve(e);for(;;){for(let e of b)if(s(c.join(t,e)))return t;let e=c.dirname(t);if(e===t)return process.cwd();t=e}}async function S(e,t){await e.start();let n=async n=>{console.error(`\nReceived ${n}, shutting down gracefully...`);try{await e.stop(),await t?.(),process.exit(0)}catch(e){console.error(`Error during shutdown:`,e),process.exit(1)}};process.on(`SIGINT`,()=>n(`SIGINT`)),process.on(`SIGTERM`,()=>n(`SIGTERM`))}const C=new l(`mcp-serve`).description(`Start MCP server with specified transport`).option(`-t, --type <type>`,`Transport type: stdio`,`stdio`).option(`--proxy <url>`,`Proxy URL for yt-dlp (HTTP/HTTPS/SOCKS5, e.g. socks5://user:pass@host:port)`).action(async e=>{let t;try{let a=e.type.toLowerCase(),o=x();if(a===`stdio`){let a=new i(n(r({proxyUrl:e.proxy})));t=await f({repositoryPath:o,serviceName:`video-editor-mcp-stdio`,pid:process.pid,metadata:{transport:`stdio`}}),await S(a,async()=>{await t?.release()})}else console.error(`Unknown transport type: ${a}. Use: stdio`),process.exit(1)}catch(e){await t?.release(),console.error(`Failed to start MCP server:`,e),process.exit(1)}}),w=new l(`analyze-video`).description(`Analyze one or more local video files with Gemini Code Assist`).requiredOption(`-v, --video <paths...>`,`Paths to local video files to analyze`).requiredOption(`-p, --prompt <text>`,`Prompt to send with the video(s)`).option(`-m, --model <id>`,`Gemini model to use`,`gemini-2.5-flash-lite`).option(`--pretty`,`Pretty-print the full JSON result`,!1).action(async e=>{try{if(!Array.isArray(e.video)||e.video.length===0)throw Error(`At least one video path is required.`);process.stderr.write(p.blue(`🎥 Starting video analysis...
3
3
  `)),process.stderr.write(p.gray(` Videos: ${e.video.join(`, `)}\n`)),process.stderr.write(p.gray(` Prompt: ${e.prompt}\n`)),process.stderr.write(p.gray(` Model: ${e.model}\n`));let n=await r().get(t.VideoAnalysisService).analyzeVideos({videoPaths:e.video,prompt:e.prompt,model:e.model});if(process.stderr.write(p.green(`✓ Resolved project: ${n.resolvedProject}\n`)),process.stderr.write(p.green(`✓ Videos processed: ${n.videoCount}\n`)),e.pretty){process.stdout.write(`${JSON.stringify(n,null,2)}\n`);return}if(n.responseText){process.stdout.write(`${n.responseText}\n`);return}process.stdout.write(`${JSON.stringify(n.rawResponse,null,2)}\n`)}catch(e){let t=e instanceof Error?e.message:String(e);process.stderr.write(p.red(`Error analyzing video: ${t}\n`)),process.exit(1)}}),T=e=>Number(e),E=e=>Number.parseInt(e,10),D=()=>s(c.resolve(import.meta.dirname,`../package.json`))?c.resolve(import.meta.dirname,`..`):c.resolve(import.meta.dirname,`../..`),O=e=>{if(e.output)return c.resolve(e.output);let t=c.resolve(e.outputDir??c.join(D(),`public/music`)),n=e.filename??`ace-step-music`;return c.join(t,`${n}.${e.audioFormat}`)},k=new l(`generate-music`).description(`Generate background music using ACE-Step 1.5`).requiredOption(`-p, --prompt <text>`,`Music description for ACE-Step text-to-music generation`).option(`-f, --filename <name>`,`Output filename without extension (default: ace-step-music)`).option(`-o, --output <path>`,`Explicit output audio path. Overrides filename/output-dir.`).option(`--output-dir <path>`,`Custom output directory (default: Remotion public/music/)`).option(`--ace-step-path <path>`,`Path to local ACE-Step-1.5 checkout`).option(`--lyrics <text>`,`Lyrics to use. Defaults to [Instrumental] for background music.`).option(`--duration <seconds>`,`Target duration in seconds (default: 30)`,T).option(`--bpm <number>`,`Optional BPM metadata`,T).option(`--keyscale <text>`,`Optional key/scale metadata, e.g. C minor`).option(`--time-signature <text>`,`Optional time signature metadata, e.g. 4/4`).option(`--vocal-language <code>`,`Vocal language code, or unknown`).option(`--seed <number>`,`Optional fixed seed for reproducible generation`,E).option(`--inference-steps <number>`,`Diffusion inference steps (default: 8)`,E).option(`--audio-format <format>`,`Output audio format: wav, mp3, flac`,`wav`).option(`--backend <backend>`,`ACE-Step LM backend: mlx, pt, vllm`,`mlx`).option(`--config-path <name>`,`ACE-Step DiT model config (default: acestep-v15-turbo)`).option(`--lm-model-path <name>`,`ACE-Step LM model (default: acestep-5Hz-lm-0.6B)`).option(`--timeout-ms <number>`,`Generation timeout in milliseconds`,E).option(`--pretty`,`Pretty-print the JSON result`,!1).action(async e=>{try{if(![`wav`,`mp3`,`flac`].includes(e.audioFormat))throw Error(`Unsupported audio format: ${e.audioFormat}`);if(![`mlx`,`pt`,`vllm`].includes(e.backend))throw Error(`Unsupported backend: ${e.backend}`);let n=O(e);process.stderr.write(p.blue(`Starting ACE-Step music generation...
4
4
  `)),process.stderr.write(p.gray(` Prompt: ${e.prompt}\n`)),process.stderr.write(p.gray(` Output: ${n}\n`)),process.stderr.write(p.gray(` Backend: ${e.backend}\n`));let i=r().get(t.AceStepMusicService);if(!await i.isAvailable(e.aceStepPath))throw Error(`ACE-Step 1.5 is not available. Clone https://github.com/ACE-Step/ACE-Step-1.5 and set ACE_STEP_15_DIR or pass --ace-step-path.`);let a=await i.generateMusic({prompt:e.prompt,outputPath:n,aceStepPath:e.aceStepPath,lyrics:e.lyrics,duration:e.duration,bpm:e.bpm,keyscale:e.keyscale,timeSignature:e.timeSignature,vocalLanguage:e.vocalLanguage,seed:e.seed,inferenceSteps:e.inferenceSteps,audioFormat:e.audioFormat,backend:e.backend,configPath:e.configPath,lmModelPath:e.lmModelPath,timeoutMs:e.timeoutMs}),o={...a,compositionSrc:c.dirname(n)===c.resolve(D(),`public/music`)?`/music/${c.basename(n)}`:void 0};process.stderr.write(p.green(`Music generated successfully: ${a.outputPath}\n`)),process.stdout.write(`${JSON.stringify(o,null,e.pretty?2:0)}\n`)}catch(e){let t=e instanceof Error?e.message:String(e);process.stderr.write(p.red(`Error generating music: ${t}\n`)),process.exit(1)}}),A=new l(`render`).description(`Render a video from JSON props file`).requiredOption(`-i, --input <path>`,`Path to JSON props file`).requiredOption(`-o, --output <path>`,`Output video file path`).option(`-c, --composition <id>`,`Composition ID`,`Main`).option(`--codec <codec>`,`Video codec (h264, h265, vp8, vp9)`,`h264`).option(`--dry-run`,`Validate props and assets without rendering`).action(async n=>{try{process.stderr.write(p.blue(n.dryRun?`🔎 Starting render dry run...
5
5
  `:`🎬 Starting video render...
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agimon-ai/video-editor-mcp",
3
3
  "description": "MCP server for video editing with Remotion",
4
- "version": "0.10.2",
4
+ "version": "0.10.4",
5
5
  "license": "AGPL-3.0",
6
6
  "keywords": [
7
7
  "mcp",
@@ -45,9 +45,9 @@
45
45
  "remotion": "4.0.454",
46
46
  "sharp": "0.34.5",
47
47
  "zod": "4.4.1",
48
- "@agimon-ai/foundation-port-registry": "0.10.2",
49
- "@agimon-ai/foundation-process-registry": "0.10.2",
50
- "@agimon-ai/foundation-validator": "0.7.2"
48
+ "@agimon-ai/foundation-port-registry": "0.10.4",
49
+ "@agimon-ai/foundation-process-registry": "0.10.4",
50
+ "@agimon-ai/foundation-validator": "0.7.4"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/node": "25.6.0",