@conceptcraft/mindframes 0.1.29 → 0.1.30

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 (2) hide show
  1. package/dist/index.js +1 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3306,7 +3306,7 @@ execSync("${e} video generate plan --project .", { stdio: "inherit" });
3306
3306
  const args = process.argv.slice(2).join(" ");
3307
3307
  execSync("${e} video export --project . " + args, { stdio: "inherit" });
3308
3308
  `;await ae(V(r,"plan.ts"),a,"utf-8"),await ae(V(r,"export.ts"),s,"utf-8")}async function Jo(){return process.stdin.isTTY?null:new Promise(t=>{let n="",e=!1;process.stdin.setEncoding("utf-8"),process.stdin.on("data",o=>{n+=o}),process.stdin.on("end",()=>{e||(e=!0,t(n.trim()||null))}),process.stdin.on("error",()=>{e||(e=!0,t(null))}),setTimeout(()=>{!e&&!n&&(e=!0,t(null))},500)})}function ea(t){return t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function ta(t){let n={shortTitle:"Video",elements:[],audio:[],text:[],scenes:[]},e=!0;return t.forEach(o=>{let r=o.startTime*1e3,i=o.endTime*1e3,a=o.durationInSeconds*1e3;n.scenes.push({name:o.name||`Scene ${o.id}`,text:o.text,startMs:r,endMs:i}),o.imagePath?(n.elements.push({startMs:r,endMs:i,imageUrl:o.imagePath,enterTransition:"blur",exitTransition:"blur",animations:[{type:"scale",from:e?1.3:1,to:e?1:1.3,startMs:0,endMs:a}]}),e=!e):o.videoPath&&n.elements.push({startMs:r,endMs:i,videoUrl:o.videoPath,enterTransition:"blur",exitTransition:"blur",animations:[]}),o.audioPath&&n.audio.push({startMs:r,endMs:i,audioUrl:o.audioPath}),o.timestamps&&n.text.push({startMs:r,endMs:i,text:o.text,position:"bottom",animations:[],timestamps:o.timestamps})}),n}async function Tt(t,n){if(t.startsWith("data:")){let r=t.match(/^data:[^;]+;base64,(.+)$/);if(!r)throw new Error("Invalid data URL format");let i=Buffer.from(r[1],"base64");await ae(n,i);return}let e=await fetch(t);if(!e.ok)throw new Error(`Failed to download: ${e.status}`);let o=await e.arrayBuffer();await ae(n,Buffer.from(o))}function na(t){try{let o=new URL(t).pathname.split(".").pop()?.toLowerCase();if(o&&["jpg","jpeg","png","gif","webp"].includes(o))return o}catch{}return"jpg"}var oa=new se("assets").description("Generate assets (voiceover per scene, music, images, video)").option("-s, --script <text>","Narration script (legacy single-script mode)").option("--script-file <path>","Path to script file (legacy) or scenes JSON").option("--scenes <path>","Path to scenes.json (defaults to <project>/public/scenes.json)").option("-p, --project <dir>","Project directory (defaults to current directory; uses <dir>/public for output)").option("-t, --topic <text>","Topic for image search").option("-v, --voice <name>","TTS voice ID (ElevenLabs: Rachel, Josh, Adam; OpenAI: alloy, nova; Gemini: Kore, Puck)").option("-m, --music-prompt <text>","Music description").option("-n, --num-images <number>","Number of images to search/download","5").option("-o, --output <dir>","Output directory","./public").option("-f, --format <format>","Output format: human, json, quiet","human").action(async t=>{let n=t.format,e=n==="human"?Qe("Initializing...").start():null,o=t.project?Xe(process.cwd(),t.project):null;try{let r=await Jo(),i=null;if(t.scenes&&!t.scriptFile&&(t.scriptFile=t.scenes),o&&(t.output=V(o,"public"),t.scriptFile?t.scriptFile=Xe(o,t.scriptFile):!t.script&&!r&&(t.scriptFile=V(o,"public","scenes.json"))),r)try{let w=JSON.parse(r);w.scenes&&Array.isArray(w.scenes)&&(i=w)}catch{}if(!i&&t.scriptFile)try{let w=await Ct(t.scriptFile,"utf-8"),B=JSON.parse(w);B.scenes&&Array.isArray(B.scenes)&&(i=B)}catch{}let a=i?.voice||t.voice,s=i?.voiceId,l=i?.provider,m=i?.model,p=i?.voiceInstructions,k=i?.musicPrompt||t.musicPrompt||"uplifting background music, positive energy",h=i?.musicDuration,f=V(t.output,"audio"),x=V(t.output,"images"),I=V(t.output,"videos");e&&(e.text="Creating directories..."),await _e(f,{recursive:!0}),await _e(x,{recursive:!0}),await _e(I,{recursive:!0});let T=0,y=[],A=0,C=[],g=[];if(i&&i.scenes.length>0){n==="human"&&(e?.stop(),d(`Processing ${i.scenes.length} scenes...`),e?.start());let w=i.scenes.map((z,M)=>{let re=z.script;return z.voiceStyle&&(re=`${z.voiceStyle} ${re}`),{text:re,id:`scene-${M}`}});e&&(e.text="Generating speech for all scenes...");let B=await Mn({texts:w,options:{provider:l,voice:a,voiceId:s,model:m,voiceSettings:i.voiceSettings,instructions:p}});T+=B.totalCost;let K=0;for(let z=0;z<i.scenes.length;z++){let M=i.scenes[z],re=ea(M.name),ee=B.results[z];e&&(e.text=`[${M.name}] Saving audio...`);let It=V(f,`${re}.${ee.format}`);await ae(It,ee.audioData);let we=ee.duration,tr=Math.round(we*je),Be={id:z+1,name:M.name,text:M.script,wordCount:M.script.split(/\s+/).length,startTime:K,endTime:K+we,durationInSeconds:we,durationInFrames:tr,audioPath:`audio/${re}.${ee.format}`,timestamps:ee.timestamps};if(M.imageQuery){e&&(e.text=`[${M.name}] Searching image...`);try{let W=await lt({query:M.imageQuery,options:{maxResults:1,size:"large",safeSearch:!0}}),Ge=W.data.results.flatMap(G=>G.results);if(T+=W.data.totalCost,Ge.length>0){let G=Ge[0],We=na(G.url),ue=`${re}.${We}`,Rt=V(x,ue);await Tt(G.url,Rt),Be.imagePath=`images/${ue}`,C.push({path:`images/${ue}`,url:G.url,width:G.width,height:G.height,query:M.imageQuery})}}catch(W){n==="human"&&(e?.stop(),R(`[${M.name}] Image search failed: ${W instanceof Error?W.message:"Unknown"}`),e?.start())}}if(M.videoQuery){e&&(e.text=`[${M.name}] Searching video...`);try{let W=await Lt({query:M.videoQuery,options:{maxResults:1,license:"free"}}),Ge=W.data.results.flatMap(G=>G.results);if(T+=W.data.totalCost,Ge.length>0){let G=Ge[0],We=G.previewUrl||G.downloadUrl;if(We){let ue=`${re}.mp4`,Rt=V(I,ue);await Tt(We,Rt),Be.videoPath=`videos/${ue}`,g.push({path:`videos/${ue}`,url:We,width:G.width,height:G.height,duration:G.duration,query:M.videoQuery})}}}catch(W){n==="human"&&(e?.stop(),R(`[${M.name}] Video search failed: ${W instanceof Error?W.message:"Unknown"}`),e?.start())}}if(y.push(Be),K+=we,A+=we,n==="human"){e?.stop();let W=[`audio: ${we.toFixed(1)}s`,Be.imagePath?"image":null,Be.videoPath?"video":null].filter(Boolean).join(", ");b(` ${M.name}: ${W}`),e?.start()}}}else{let w=t.script;if(t.scriptFile)try{w=await Ct(t.scriptFile,"utf-8")}catch(ee){e?.stop(),c(`Failed to read script file: ${ee instanceof Error?ee.message:"Unknown error"}`),process.exit(S.INVALID_INPUT)}(!w||w.trim().length===0)&&(e?.stop(),c("Provide scenes via stdin JSON, --scenes/--script-file with scenes JSON, or --script for legacy mode"),process.exit(S.INVALID_INPUT)),w=w.trim();let B=t.topic||w.split(".")[0].slice(0,50);e&&(e.text="Generating voiceover...");let K=await st({text:w,options:{voice:a}}),z=V(f,`voiceover.${K.format}`);await ae(z,K.audioData),T+=K.cost,A=K.duration;let M=Ki(w);y=zi(M,K.duration,je,K.timestamps).map((ee,It)=>({...ee,name:`Section${It+1}`,audioPath:`audio/voiceover.${K.format}`})),n==="human"&&(e?.stop(),b(`Voiceover: ${z} (${K.duration.toFixed(1)}s)`),e?.start())}e&&(e.text="Creating timeline...");let O=ta(y),q=Math.max(O.audio.length>0?Math.max(...O.audio.map(w=>w.endMs)):0,O.text.length>0?Math.max(...O.text.map(w=>w.endMs)):0,O.elements.length>0?Math.max(...O.elements.map(w=>w.endMs)):0),H=q/1e3,oe=h?Math.min(300,Math.max(3,h)):Math.min(300,Math.ceil(H));console.log("[Music Generation] Requesting music:",{prompt:k,requestedDuration:oe,totalAudioDuration:A,actualVideoDuration:H,timelineDurationMs:q});let ve,qe;e&&(e.text="Generating music and thumbnail...");let Qo=`YouTube thumbnail style: BIG BOLD short headline text (like "$50K/MONTH"), dramatic engaging scene, arrows pointing to key elements, high contrast, vibrant colors, clean composition, 16:9. Video context: ${y.map(w=>w.text).join(" ")}`,kt=[],Zo=(async()=>{if(oe<3)return n==="human"&&(e?.stop(),R(`Video duration (${H.toFixed(1)}s) is too short for music generation (minimum 3s).`),e?.start()),null;try{let w=await ct({prompt:k,duration:oe});if(w.status!=="completed"&&w.status!=="failed"&&(w=await de(()=>Je(w.requestId),60,2e3)),w.status==="failed")throw new Error(w.error||"Unknown error");let B=V(f,"music.mp3");return w.audioUrl&&await Tt(w.audioUrl,B),{path:"audio/music.mp3",duration:w.duration||oe,prompt:k,cost:w.cost||0}}catch(w){return n==="human"&&(e?.stop(),R(`Music generation failed: ${w.message}`),e?.start()),null}})();kt.push(Zo);let er=(async()=>{try{let w=await _n({prompt:Qo,options:{width:1280,height:720}});if(w.success&&w.data.url){let B=V(t.output,"thumbnail.jpg");return await Tt(w.data.url,B),T+=w.data.cost||0,B}return null}catch(w){return n==="human"&&(e?.stop(),R(`Thumbnail generation failed: ${w.message}`),e?.start()),null}})();kt.push(er);let[xe,cn]=await Promise.all(kt);xe&&(ve=xe,T+=xe.cost||0,n==="human"&&(e?.stop(),b(`Music: ${V(f,"music.mp3")} (${xe.duration}s)`),xe.duration<H&&R(`Music duration (${xe.duration.toFixed(1)}s) is shorter than video duration (${H.toFixed(1)}s).`),e?.start())),cn&&(qe=cn,n==="human"&&(e?.stop(),b(`Thumbnail: ${qe}`),e?.start())),e&&(e.text="Writing manifest...");let ln=Math.round(H*je),dn={music:ve,thumbnail:qe?"thumbnail.jpg":void 0,images:C,videos:g,scenes:y,timeline:O,totalDurationInFrames:ln,fps:je,totalCost:T,createdAt:new Date().toISOString()},$t=V(t.output,"video-manifest.json");if(await ae($t,JSON.stringify(dn,null,2)),e?.stop(),n==="json"){_(dn);return}if(n==="quiet"){console.log($t);return}console.log(),b("Video assets created successfully!"),console.log(),d(`Scenes: ${y.length} (${ln} frames at ${je}fps)`);for(let w of y){let B=[w.audioPath?"audio":null,w.imagePath?"image":null,w.videoPath?"video":null].filter(Boolean).join(", ");d(` - ${w.name}: ${w.durationInSeconds.toFixed(1)}s [${B}]`)}d(`Music: ${ve?.path} (${ve?.duration}s)`),d(`Manifest: ${$t}`),console.log(),d(`Total cost: $${T.toFixed(4)}`)}catch(r){e?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),ra=new se("find").description("Find stock video clips (supporting)").argument("<query>","Search query").option("-n, --max-results <count>","Maximum number of results","10").option("-o, --orientation <type>","Video orientation: landscape, portrait, square, any","any").option("-l, --license <type>","License type: free, premium, any","free").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{let{maxResults:e,orientation:o,license:r,format:i}=n,a=i==="human"?Qe("Finding videos...").start():null;try{let s=await Lt({query:t,options:{maxResults:parseInt(e,10),orientation:o,license:r}});a?.stop();let l=s.data.results.flatMap(m=>m.results);if(i==="json"){_(s);return}if(i==="quiet"){l.forEach(m=>{console.log(m.previewUrl||m.thumbnailUrl)});return}if(l.length===0){d("No videos found");return}b(`Found ${l.length} videos for "${t}"`),console.log(),l.forEach((m,p)=>{console.log(`[${p+1}] ${m.title}`),console.log(` URL: ${m.previewUrl||m.thumbnailUrl}`),console.log(` Duration: ${m.duration}s | Size: ${m.width}x${m.height}`),console.log(` Provider: ${m.provider}`),console.log()}),d(`Total cost: $${s.data.totalCost.toFixed(4)}`)}catch(s){a?.stop(),c(s instanceof Error?s.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),ia=new se("new").description("Create a new video project from a template").argument("<name>","Project directory name").option("-t, --template <repo>","GitHub repo (user/repo#commit)",Ji).option("--type <type>","Video type: youtube (16:9), tiktok (9:16), or audiogram (1:1)","youtube").option("--no-install","Skip dependency install").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{let e=n.format,o=e==="human"?Qe("Initializing video project...").start():null;try{let r=Le();await _e(r,{recursive:!0});let i=vt(t),a=n.type,s=await tn();if(s.includes(t)){let f=Vo(t,s);o?.stop(),c(`Project "${t}" already exists at: ${i}`),d(`Try: ${u.commands[0]} video generate new ${f}`),process.exit(S.INVALID_INPUT)}/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_.-]+(#[a-zA-Z0-9_.\/-]+)?$/.test(n.template)||(o?.stop(),c(`Invalid template format: "${n.template}". Expected format: owner/repo or owner/repo#branch`),process.exit(S.INVALID_INPUT)),["youtube","tiktok","audiogram"].includes(a)||(o?.stop(),c(`Invalid type "${a}". Use youtube, tiktok, or audiogram.`),process.exit(S.INVALID_INPUT)),o&&(o.text=`Cloning template from ${n.template}...`);let[m,p]=n.template.split("#"),k=p?`-b ${p}`:"";try{Ve(`git clone ${k} --depth 1 https://github.com/${m}.git "${i}"`,{stdio:"pipe"}),await on(V(i,".git"),{recursive:!0,force:!0})}catch(f){o?.stop(),c(`Failed to clone template: ${f instanceof Error?f.message:"Unknown error"}`),process.exit(S.GENERAL_ERROR)}e==="human"&&(o?.stop(),b(`Template downloaded to ${t}/`),o?.start());let h;try{h=await Hi(i)}catch{o?.stop(),c("template.manifest.json not found or invalid in template repo"),process.exit(S.INVALID_INPUT)}if(h.propsSchema&&h.propsSchema!=="video-plan.v1"&&(o?.stop(),c(`Template propsSchema must be video-plan.v1 (found ${h.propsSchema})`),process.exit(S.INVALID_INPUT)),o&&(o.text="Writing scaffold files..."),await Zi(i,a,u.commands[0]),n.install){let f=Wo()?"bun":"npm";o&&(o.text=`Installing dependencies with ${f}...`),await new Promise((x,I)=>{let T=Bi(f,["install"],{cwd:i,stdio:"pipe",shell:!0});T.on("close",y=>{y===0?x():I(new Error(`${f} install failed with code ${y}`))}),T.on("error",I)}),e==="human"&&(o?.stop(),b("Dependencies installed"),o?.start())}if(o?.stop(),e==="json"){_({name:t,path:i,template:n.template,type:a,installed:n.install});return}if(e==="quiet"){console.log(i);return}console.log(),b(`Video project "${t}" created successfully!`),d(`Location: ${i}`),a==="tiktok"?d("Format: TikTok/Reels/Shorts (1080x1920 @ 30fps)"):a==="audiogram"?d("Format: Audiogram (1080x1080 @ 30fps)"):d("Format: YouTube (1920x1080 @ 30fps)"),console.log(),d("Next steps:"),d(` cd ${i}`),n.install||d(` ${Wo()?"bun":"npm"} install`),d(" bun run dev # Preview in Remotion Studio"),d(` ${u.commands[0]} video generate assets --scenes public/scenes.json`),d(` ${u.commands[0]} video generate plan`)}catch(r){o?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),aa=new se("plan").description("Generate video plan from context (via stdin or --context)").option("-c, --context <text>","Context for plan generation").option("-o, --output <path>","Save plan to file").option("-b, --branding <path>","Branding JSON file to include").action(async t=>{let n=Qe("Generating video plan...").start();try{let e=t.context;if(!e){let a=await Jo();a&&(e=a)}e||(n.stop(),c("Provide context via stdin or --context flag"),process.exit(S.INVALID_INPUT));let o;if(t.branding)try{o=await Ct(t.branding,"utf-8")}catch{n.stop(),c(`Could not read branding file: ${t.branding}`),process.exit(S.INVALID_INPUT)}let r=await Gn({context:e,branding:o});n.stop(),r.success||(c(r.error||"Failed to generate plan"),process.exit(S.GENERAL_ERROR));let i=r.data;t.output?(await ae(t.output,i),b(`Plan saved to ${t.output}`)):console.log(i)}catch(e){n.stop(),c(e instanceof Error?e.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),sa=new se("generate").description("Generate parts of a video project").addCommand(ia).addCommand(oa).addCommand(aa),ca=new se("projects").description("List all video projects").option("-f, --format <format>","Output format: human, json","human").action(async t=>{let n=await tn();if(t.format==="json"){_({projectsDir:Le(),projects:n.map(e=>({name:e,path:vt(e)}))});return}if(n.length===0){d("No video projects found"),d(`Projects are stored in: ${Le()}`);return}console.log(`
3309
- Video Projects:`),console.log("-".repeat(50));for(let e of n)console.log(` ${e}`),console.log(` ${vt(e)}`);console.log()}),la=new se("inject").description("Inject thumbnail into video (first frame + file icon)").requiredOption("-i, --video <path>","Input video file").requiredOption("-t, --thumbnail <path>","Thumbnail image").option("-o, --output <path>","Output video (default: video-with-thumb.mp4)").option("-f, --format <format>","Output format: human, json, quiet","human").action(async t=>{let n=t.format,e=n==="human"?Qe("Injecting thumbnail...").start():null;try{let o=Xe(t.video),r=Xe(t.thumbnail),i=t.output?Xe(t.output):o.replace(/\.mp4$/,"-with-thumb.mp4");await nn(o),await nn(r);let a=Wi;if(a)try{await nn(a)}catch{a=null}if(!a)try{a=Ve("which ffmpeg",{encoding:"utf8"}).trim()}catch{throw new Error("ffmpeg not found. Install ffmpeg or ffmpeg-static.")}let s=Gi(a,["-i",o],{encoding:"utf8"});if(s.error)throw new Error(`Failed to probe video: ${s.error.message}`);let l=(s.stderr??"").match(/(\d{2,5})x(\d{2,5})/);if(!l)throw new Error("Could not detect video dimensions");let[,m,p]=l;e&&(e.text="Creating thumbnail frame...");let k="/tmp/cc-thumb-frame.mp4";Ve(`${a} -y -loop 1 -i "${r}" -vf "scale=${m}:${p}:force_original_aspect_ratio=decrease,pad=${m}:${p}:(ow-iw)/2:(oh-ih)/2,setsar=1" -t 0.033 -r 30 -c:v libx264 -pix_fmt yuv420p "${k}"`,{stdio:"pipe"}),e&&(e.text="Concatenating with video...");let h="/tmp/cc-concat-video.mp4";if(Ve(`${a} -y -i "${k}" -i "${o}" -filter_complex "[0:v][1:v]concat=n=2:v=1:a=0[v]" -map "[v]" -map 1:a -c:v libx264 -preset ultrafast -crf 18 -c:a copy "${h}"`,{stdio:"pipe"}),e&&(e.text="Adding file icon thumbnail..."),Ve(`${a} -y -i "${h}" -i "${r}" -map 0 -map 1 -c copy -c:v:1 png -disposition:v:1 attached_pic "${i}"`,{stdio:"pipe"}),await on(k,{force:!0}),await on(h,{force:!0}),e?.stop(),n==="json"){_({success:!0,output:i});return}if(n==="quiet"){console.log(i);return}b(`Thumbnail injected: ${i}`)}catch(o){e?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),da=new se("thumbnail").description("Thumbnail operations").addCommand(la),Yo=new se("video").description("Video generation commands").addCommand(sa).addCommand(ra).addCommand(ca).addCommand(da).addCommand(Go);import{Command as ma}from"commander";import ua from"ora";import{writeFile as pa}from"fs/promises";var Ho=new ma("scrape").description("Extract content from a URL").argument("<url>","URL to scrape").option("-o, --output <path>","Save content to file").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{let e=n.format,o=e==="human"?ua("Scraping URL...").start():null;try{let r=await qn(t);o?.stop(),r.success||(c(r.error||"Failed to scrape URL"),process.exit(S.GENERAL_ERROR));let i=r.data;if(n.output&&(await pa(n.output,i.content,"utf-8"),e==="human"&&b(`Content saved to: ${n.output}`)),e==="json"){_(i);return}if(e==="quiet"){console.log(i.content);return}i.title&&(console.log(),console.log(`Title: ${i.title}`)),i.metadata?.description&&console.log(`Description: ${i.metadata.description}`),console.log(`URL: ${i.url}`),console.log(`Tokens: ~${i.metadata?.tokenUsage?.toLocaleString()||"unknown"}`),i.warning&&R(i.warning),n.output||(console.log(),console.log("--- Content ---"),console.log(i.content)),i.cost&&i.cost>0&&d(`Cost: $${i.cost.toFixed(6)}`)}catch(r){o?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}});import{Command as sn}from"commander";import rn from"ora";import{writeFile as Ko}from"fs/promises";function an(t,n){if(n==="json"){_(t);return}if(n==="quiet"){t.audioUrl?console.log(t.audioUrl):t.requestId?console.log(t.requestId):console.log(t.id);return}d(`Request ID: ${t.requestId||t.id}`),d(`Status: ${t.status}`),t.duration&&d(`Duration: ${t.duration}s`),t.audioUrl&&b(`Audio URL: ${t.audioUrl}`),t.cost!==void 0&&d(`Cost: $${t.cost.toFixed(4)}`),t.error&&c(`Error: ${t.error}`)}async function fa(t,n){if(t.startsWith("data:")){let r=t.match(/^data:[^;]+;base64,(.+)$/);if(!r)throw new Error("Invalid data URL format");let i=Buffer.from(r[1],"base64");await Ko(n,i);return}let e=await fetch(t);if(!e.ok)throw new Error(`Failed to download: ${e.status}`);let o=await e.arrayBuffer();await Ko(n,Buffer.from(o))}var ga=new sn("generate").description("Generate sound effects from a text prompt").requiredOption("-t, --text <text>","Sound effect description (e.g., 'thunder rumbling, rain on window')").option("-d, --duration <seconds>","Duration in seconds (0.5-30)").option("-p, --provider <provider>","Provider (elevenlabs)","elevenlabs").option("--prompt-influence <value>","How closely to follow prompt (0-1)","0.3").option("-l, --loop","Generate seamless looping audio",!1).option("--format <format>","Audio format: mp3, wav, ogg","mp3").option("-o, --output <path>","Output file path").option("--no-wait","Do not wait for completion").option("-f, --output-format <format>","Output format: human, json, quiet","human").action(async t=>{let n;t.duration&&(n=parseFloat(t.duration),(isNaN(n)||n<.5||n>30)&&(c("Duration must be between 0.5 and 30 seconds"),process.exit(S.INVALID_INPUT)));let e;t.promptInfluence&&(e=parseFloat(t.promptInfluence),(isNaN(e)||e<0||e>1)&&(c("Prompt influence must be between 0 and 1"),process.exit(S.INVALID_INPUT)));let o=t.outputFormat,r=o==="human"?rn("Generating sound effects...").start():null;try{let i=await Bn({text:t.text,duration:n,options:{provider:t.provider,promptInfluence:e,loop:t.loop,format:t.format}});if(!t.wait){r?.stop(),an(i,o);return}let a=i;if(i.status!=="completed"&&i.status!=="failed"){let s=i.requestId||i.id;r&&(r.text=`Processing (ID: ${s})...`),a=await de(()=>Mt(s),60,2e3)}if(r?.stop(),a.status==="failed"&&(c(a.error||"Sound effects generation failed"),process.exit(S.GENERAL_ERROR)),an(a,o),t.output&&a.audioUrl){let s=o==="human"?rn("Downloading...").start():null;try{await fa(a.audioUrl,t.output),s?.stop(),o==="human"&&b(`Saved to: ${t.output}`)}catch(l){s?.stop(),R(`Failed to download: ${l instanceof Error?l.message:"Unknown error"}`)}}}catch(i){r?.stop(),c(i instanceof Error?i.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),ha=new sn("status").description("Check status of a sound effects generation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{let e=n.format==="human"?rn("Checking status...").start():null;try{let o=await Mt(t);e?.stop(),an(o,n.format)}catch(o){e?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),zo=new sn("sfx").description("Sound effects generation commands").addCommand(ga).addCommand(ha);var ba="0.1.29",D=new ya,ce=u.commands[0];D.name(ce).description(u.description).version(ba,"-v, --version","Show version number").option("--debug","Enable debug logging").option("--no-color","Disable colored output").configureOutput({outputError:(t,n)=>{n(Z.red(t))}});D.addCommand(Qn);D.addCommand(Zn);D.addCommand(to);D.addCommand(io);D.addCommand(ao);D.addCommand(so);D.addCommand(co);D.addCommand(mo);D.addCommand(po);D.addCommand(go);D.addCommand(bo);D.addCommand(vo);D.addCommand(Ue);D.addCommand(Fo);D.addCommand(Do);D.addCommand(Uo);D.addCommand(Mo);D.addCommand(Yo);D.addCommand(Ho);D.addCommand(zo);var Xo=yo();Xo.commands.length>0&&D.addCommand(Xo);D.on("command:*",t=>{console.error(Z.red(`Error: Unknown command '${t[0]}'`)),console.error(),console.error(`Run '${ce} --help' to see available commands.`),process.exit(1)});D.addHelpText("after",`
3309
+ Video Projects:`),console.log("-".repeat(50));for(let e of n)console.log(` ${e}`),console.log(` ${vt(e)}`);console.log()}),la=new se("inject").description("Inject thumbnail into video (first frame + file icon)").requiredOption("-i, --video <path>","Input video file").requiredOption("-t, --thumbnail <path>","Thumbnail image").option("-o, --output <path>","Output video (default: video-with-thumb.mp4)").option("-f, --format <format>","Output format: human, json, quiet","human").action(async t=>{let n=t.format,e=n==="human"?Qe("Injecting thumbnail...").start():null;try{let o=Xe(t.video),r=Xe(t.thumbnail),i=t.output?Xe(t.output):o.replace(/\.mp4$/,"-with-thumb.mp4");await nn(o),await nn(r);let a=Wi;if(a)try{await nn(a)}catch{a=null}if(!a)try{a=Ve("which ffmpeg",{encoding:"utf8"}).trim()}catch{throw new Error("ffmpeg not found. Install ffmpeg or ffmpeg-static.")}let s=Gi(a,["-i",o],{encoding:"utf8"});if(s.error)throw new Error(`Failed to probe video: ${s.error.message}`);let l=(s.stderr??"").match(/(\d{2,5})x(\d{2,5})/);if(!l)throw new Error("Could not detect video dimensions");let[,m,p]=l;e&&(e.text="Creating thumbnail frame...");let k="/tmp/cc-thumb-frame.mp4";Ve(`${a} -y -loop 1 -i "${r}" -vf "scale=${m}:${p}:force_original_aspect_ratio=decrease,pad=${m}:${p}:(ow-iw)/2:(oh-ih)/2,setsar=1" -t 0.033 -r 30 -c:v libx264 -pix_fmt yuv420p "${k}"`,{stdio:"pipe"}),e&&(e.text="Concatenating with video...");let h="/tmp/cc-concat-video.mp4";if(Ve(`${a} -y -i "${k}" -i "${o}" -filter_complex "[0:v][1:v]concat=n=2:v=1:a=0[v]" -map "[v]" -map 1:a -c:v libx264 -preset ultrafast -crf 18 -c:a copy "${h}"`,{stdio:"pipe"}),e&&(e.text="Adding file icon thumbnail..."),Ve(`${a} -y -i "${h}" -i "${r}" -map 0 -map 1 -c copy -c:v:1 png -disposition:v:1 attached_pic "${i}"`,{stdio:"pipe"}),await on(k,{force:!0}),await on(h,{force:!0}),e?.stop(),n==="json"){_({success:!0,output:i});return}if(n==="quiet"){console.log(i);return}b(`Thumbnail injected: ${i}`)}catch(o){e?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),da=new se("thumbnail").description("Thumbnail operations").addCommand(la),Yo=new se("video").description("Video generation commands").addCommand(sa).addCommand(ra).addCommand(ca).addCommand(da).addCommand(Go);import{Command as ma}from"commander";import ua from"ora";import{writeFile as pa}from"fs/promises";var Ho=new ma("scrape").description("Extract content from a URL").argument("<url>","URL to scrape").option("-o, --output <path>","Save content to file").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{let e=n.format,o=e==="human"?ua("Scraping URL...").start():null;try{let r=await qn(t);o?.stop(),r.success||(c(r.error||"Failed to scrape URL"),process.exit(S.GENERAL_ERROR));let i=r.data;if(n.output&&(await pa(n.output,i.content,"utf-8"),e==="human"&&b(`Content saved to: ${n.output}`)),e==="json"){_(i);return}if(e==="quiet"){console.log(i.content);return}i.title&&(console.log(),console.log(`Title: ${i.title}`)),i.metadata?.description&&console.log(`Description: ${i.metadata.description}`),console.log(`URL: ${i.url}`),console.log(`Tokens: ~${i.metadata?.tokenUsage?.toLocaleString()||"unknown"}`),i.warning&&R(i.warning),n.output||(console.log(),console.log("--- Content ---"),console.log(i.content)),i.cost&&i.cost>0&&d(`Cost: $${i.cost.toFixed(6)}`)}catch(r){o?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}});import{Command as sn}from"commander";import rn from"ora";import{writeFile as Ko}from"fs/promises";function an(t,n){if(n==="json"){_(t);return}if(n==="quiet"){t.audioUrl?console.log(t.audioUrl):t.requestId?console.log(t.requestId):console.log(t.id);return}d(`Request ID: ${t.requestId||t.id}`),d(`Status: ${t.status}`),t.duration&&d(`Duration: ${t.duration}s`),t.audioUrl&&b(`Audio URL: ${t.audioUrl}`),t.cost!==void 0&&d(`Cost: $${t.cost.toFixed(4)}`),t.error&&c(`Error: ${t.error}`)}async function fa(t,n){if(t.startsWith("data:")){let r=t.match(/^data:[^;]+;base64,(.+)$/);if(!r)throw new Error("Invalid data URL format");let i=Buffer.from(r[1],"base64");await Ko(n,i);return}let e=await fetch(t);if(!e.ok)throw new Error(`Failed to download: ${e.status}`);let o=await e.arrayBuffer();await Ko(n,Buffer.from(o))}var ga=new sn("generate").description("Generate sound effects from a text prompt").requiredOption("-t, --text <text>","Sound effect description (e.g., 'thunder rumbling, rain on window')").option("-d, --duration <seconds>","Duration in seconds (0.5-30)").option("-p, --provider <provider>","Provider (elevenlabs)","elevenlabs").option("--prompt-influence <value>","How closely to follow prompt (0-1)","0.3").option("-l, --loop","Generate seamless looping audio",!1).option("--format <format>","Audio format: mp3, wav, ogg","mp3").option("-o, --output <path>","Output file path").option("--no-wait","Do not wait for completion").option("-f, --output-format <format>","Output format: human, json, quiet","human").action(async t=>{let n;t.duration&&(n=parseFloat(t.duration),(isNaN(n)||n<.5||n>30)&&(c("Duration must be between 0.5 and 30 seconds"),process.exit(S.INVALID_INPUT)));let e;t.promptInfluence&&(e=parseFloat(t.promptInfluence),(isNaN(e)||e<0||e>1)&&(c("Prompt influence must be between 0 and 1"),process.exit(S.INVALID_INPUT)));let o=t.outputFormat,r=o==="human"?rn("Generating sound effects...").start():null;try{let i=await Bn({text:t.text,duration:n,options:{provider:t.provider,promptInfluence:e,loop:t.loop,format:t.format}});if(!t.wait){r?.stop(),an(i,o);return}let a=i;if(i.status!=="completed"&&i.status!=="failed"){let s=i.requestId||i.id;r&&(r.text=`Processing (ID: ${s})...`),a=await de(()=>Mt(s),60,2e3)}if(r?.stop(),a.status==="failed"&&(c(a.error||"Sound effects generation failed"),process.exit(S.GENERAL_ERROR)),an(a,o),t.output&&a.audioUrl){let s=o==="human"?rn("Downloading...").start():null;try{await fa(a.audioUrl,t.output),s?.stop(),o==="human"&&b(`Saved to: ${t.output}`)}catch(l){s?.stop(),R(`Failed to download: ${l instanceof Error?l.message:"Unknown error"}`)}}}catch(i){r?.stop(),c(i instanceof Error?i.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),ha=new sn("status").description("Check status of a sound effects generation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{let e=n.format==="human"?rn("Checking status...").start():null;try{let o=await Mt(t);e?.stop(),an(o,n.format)}catch(o){e?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),zo=new sn("sfx").description("Sound effects generation commands").addCommand(ga).addCommand(ha);var ba="0.1.30",D=new ya,ce=u.commands[0];D.name(ce).description(u.description).version(ba,"-v, --version","Show version number").option("--debug","Enable debug logging").option("--no-color","Disable colored output").configureOutput({outputError:(t,n)=>{n(Z.red(t))}});D.addCommand(Qn);D.addCommand(Zn);D.addCommand(to);D.addCommand(io);D.addCommand(ao);D.addCommand(so);D.addCommand(co);D.addCommand(mo);D.addCommand(po);D.addCommand(go);D.addCommand(bo);D.addCommand(vo);D.addCommand(Ue);D.addCommand(Fo);D.addCommand(Do);D.addCommand(Uo);D.addCommand(Mo);D.addCommand(Yo);D.addCommand(Ho);D.addCommand(zo);var Xo=yo();Xo.commands.length>0&&D.addCommand(Xo);D.on("command:*",t=>{console.error(Z.red(`Error: Unknown command '${t[0]}'`)),console.error(),console.error(`Run '${ce} --help' to see available commands.`),process.exit(1)});D.addHelpText("after",`
3310
3310
  ${Z.bold("Examples:")}
3311
3311
  ${Z.gray("# Log in (opens browser)")}
3312
3312
  $ ${ce} login
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conceptcraft/mindframes",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
4
4
  "description": "CLI tool for creating AI-powered presentations with Mindframes",
5
5
  "type": "module",
6
6
  "bin": {