@conceptcraft/mindframes 0.3.11 → 0.3.13

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 +411 -390
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'module'; const require = createRequire(import.meta.url);
3
- var h={id:"mindframes",name:"mindframes",displayName:"Mindframes",description:"CLI tool for Mindframes presentation generation",commands:["mf","mindframes"],apiUrl:"https://www.mindframes.app",docsUrl:"https://docs.mindframes.ai",packageName:"@conceptcraft/mindframes",configDir:".mindframes",apiKeyEnvVar:"MINDFRAMES_API_KEY",apiUrlEnvVar:"MINDFRAMES_API_URL",codexSelfConnectorAppId:"asdk_app_6a2b9629c1608191970dcb3ab374ac55"};import ce from"chalk";import{Command as Sl}from"commander";import{Command as Ki}from"commander";import{randomUUID as an}from"crypto";import{readFileSync as Vi,statSync as ji}from"fs";import{basename as po}from"path";import yt from"chalk";import Fi from"conf";function oo(t={}){let n=(s,l)=>{let d=t[s];return d&&d.trim().length>0?d.trim():l},e=n("NEXT_PUBLIC_PRODUCT_SHORT_NAME","ConceptCraft"),o=n("NEXT_PUBLIC_CLI_COMMAND","ccr"),r=n("NEXT_PUBLIC_CLI_COMMAND_FULL","conceptcraft"),i=n("NEXT_PUBLIC_CLI_CONFIG_DIR",`.${r}`),a=e.toUpperCase().replace(/[^A-Z0-9]/g,"_");return{id:r,name:i.replace(/^\./,""),displayName:e,description:`CLI tool for ${e} presentation generation`,commands:[o,r],apiUrl:n("NEXT_PUBLIC_API_URL","http://localhost:3000"),docsUrl:n("NEXT_PUBLIC_DOCS_URL",`https://docs.${e.toLowerCase()}.ai`),packageName:n("NEXT_PUBLIC_CLI_PACKAGE_NAME","@conceptcraft/cli"),configDir:i,apiKeyEnvVar:`${a}_API_KEY`,apiUrlEnvVar:`${a}_API_URL`,codexSelfConnectorAppId:t.NEXT_PUBLIC_CODEX_SELF_CONNECTOR_APP_ID?.trim()||void 0}}var p=typeof h<"u"&&h?h:oo(process.env);var ro=p.apiUrl,Ui={apiKey:{type:"string"},apiUrl:{type:"string",default:ro},defaultTeamId:{type:"string"},accessToken:{type:"string"},refreshToken:{type:"string"},tokenExpiresAt:{type:"number"},clientId:{type:"string"},clientSecret:{type:"string"}},N=new Fi({projectName:p.name,schema:Ui});function io(){return{apiKey:fe(),apiUrl:j(),defaultTeamId:N.get("defaultTeamId"),accessToken:N.get("accessToken"),refreshToken:N.get("refreshToken"),tokenExpiresAt:N.get("tokenExpiresAt"),clientId:N.get("clientId"),clientSecret:N.get("clientSecret")}}function fe(){let t=process.env[p.apiKeyEnvVar]??process.env.CC_SLIDES_API_KEY;return t||N.get("apiKey")}function nn(t){N.set("apiKey",t)}function j(){let t=process.env[p.apiUrlEnvVar]??process.env.CC_SLIDES_API_URL;return t||(N.get("apiUrl")??ro)}function on(t){N.set("apiUrl",t)}function ut(){return N.get("defaultTeamId")}function Ee(t){N.set("defaultTeamId",t)}function mt(){N.clear()}function nt(){return N.path}function Oe(){return!!fe()}function ao(){return N.get("accessToken")}function so(){return N.get("refreshToken")}function pt(t,n,e){N.set("accessToken",t),N.set("refreshToken",n),N.set("tokenExpiresAt",Date.now()+(e-60)*1e3)}function gt(){N.delete("accessToken"),N.delete("refreshToken"),N.delete("tokenExpiresAt")}function co(){let t=N.get("tokenExpiresAt");return t?Date.now()>=t:!0}function Ce(){return!!N.get("accessToken")&&!!N.get("refreshToken")}function ft(){return N.get("clientId")}function ht(){return N.get("clientSecret")}function lo(t,n){N.set("clientId",t),N.set("clientSecret",n)}var u={SUCCESS:0,GENERAL_ERROR:1,AUTH_ERROR:2,NOT_FOUND:3,RATE_LIMIT:4,NETWORK_ERROR:5,INVALID_INPUT:6};async function _i(){let t=so(),n=ft(),e=j();if(!t||!n)return null;try{let o=await fetch(`${e}/.well-known/oauth-authorization-server`);if(!o.ok)return null;let r=await o.json(),i=new URLSearchParams({grant_type:"refresh_token",refresh_token:t,client_id:n}),a=ht();a&&i.set("client_secret",a);let s=await fetch(r.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()});if(!s.ok)return gt(),null;let l=await s.json();return pt(l.access_token,l.refresh_token,l.expires_in),l.access_token}catch{return null}}async function uo(){return Ce()?co()?_i():ao()||null:null}function ae(){return Ce()||Oe()}async function O(){if(!ae()){let t=p.commands[0],n=p.apiKeyEnvVar;console.error(yt.red("\u2717 Not authenticated.")),console.error(),console.error(yt.bold("To authenticate, run:")),console.error(yt.cyan(` ${t} login`)),console.error(),console.error(yt.gray(`Or set ${n} environment variable.`)),process.exit(u.AUTH_ERROR)}}function Mi(t){return t.length<=14?"****":`${t.slice(0,10)}...${t.slice(-4)}`}function mo(){let t=fe();if(t)return Mi(t)}function rn(t){return["cc_slides_","mcp_","cc_sk_","sk_"].some(e=>t.startsWith(e))}async function de(){let t=await uo();if(t)return{Authorization:`Bearer ${t}`};let n=fe();return n?{"x-api-key":n}:{}}var F=class extends Error{constructor(e,o,r=1,i="operation_failed",a=!1){super(e);this.statusCode=o;this.exitCode=r;this.errorCode=i;this.retryable=a;this.name="ApiError"}statusCode;exitCode;errorCode;retryable},go="Idempotency-Key";function qi(t){return t&&t!=="GET"?{[go]:an()}:{}}async function z(t,n={}){let e=j();if(!ae())throw new F(`Not authenticated. Run '${p.commands[0]} login' or set ${p.apiKeyEnvVar} environment variable.`,401,2,"authentication_required");let o=await de(),r=`${e}${t}`,i={...o,...qi(n.method),...n.headers};n.body&&!n.stream&&(i["Content-Type"]="application/json");let a={method:n.method??"GET",headers:i};n.body&&(a.body=JSON.stringify(n.body));let s;try{s=await fetch(r,a)}catch(d){throw new F(`Network error: ${d instanceof Error?d.message:"Unknown error"}`,0,5,"service_unavailable",!0)}if(!s.ok){let d=await s.text().catch(()=>""),f=Gi(d,s.status),v=1;switch(s.status){case 401:v=2;break;case 403:v=2;break;case 404:v=3;break;case 429:v=4;break;case 500:v=1;break}let I=`[${f.code}] ${f.message}`;throw new F(I,s.status,v,f.code,f.retryable)}return n.stream?s:s.headers.get("content-type")?.includes("application/json")?s.json():s.text()}function Bi(t){switch(t){case 400:return"invalid_input";case 401:return"authentication_required";case 402:return"insufficient_credits";case 403:return"access_denied";case 404:return"not_found";case 429:return"rate_limited";case 503:return"service_unavailable";default:return"operation_failed"}}function Gi(t,n){let e=Bi(n),o=t.trim()||`HTTP ${n}: The request could not be completed.`;try{let r=JSON.parse(t),i=typeof r.error=="object"&&r.error!==null?r.error:void 0;if(r.ok===!1&&typeof i?.code=="string"&&typeof i.message=="string")return{code:i.code,message:i.message,retryable:i.retryable===!0};if(typeof r.error=="string")return{code:/^[a-z][a-z0-9_]+$/.test(r.error)?r.error:e,message:typeof r.message=="string"?r.message:r.error,retryable:n===429||n>=500}}catch{}return{code:e,message:o,retryable:n===429||n>=500}}async function fo(){return z("/api/cli/capabilities")}async function U(t,n,e){let o=e?`?teamId=${encodeURIComponent(e)}`:"";return z(`/api/cli/tool-runs/${encodeURIComponent(t)}/${encodeURIComponent(n)}${o}`)}async function $(t,n){return z(`/api/cli/tools/${encodeURIComponent(t)}`,{body:n,method:"POST"})}async function Wi(t,n,e=120){for(let o=0;o<e;o++){let r=await U(t,n);if(r.done){if(r.error)throw new F(`[${r.error.code??"operation_failed"}] ${r.error.message}`,500,1,r.error.code??"operation_failed",r.error.retryable);return r}await new Promise(i=>setTimeout(i,(r.nextPollAfterSeconds??2)*1e3))}throw new F("[operation_timed_out] The background operation timed out.",408,1,"operation_timed_out",!0)}function bt(t){return t.error||t.status==="failed"||t.status==="errored"||t.status==="cancelled"?"failed":t.done||t.status==="completed"?"completed":t.status==="in_progress"?"processing":"pending"}function Hi(t){try{let e=new URL(t).pathname.split("/").pop()?.split(".").pop()?.toLowerCase();return e&&/^[a-z0-9]+$/.test(e)?e:void 0}catch{return}}function Ji(t){let n=t.toLowerCase().split(".").pop();return{pdf:"application/pdf",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",txt:"text/plain",md:"text/markdown",csv:"text/csv",json:"application/json",html:"text/html",css:"text/css",js:"application/javascript",ts:"text/x-typescript",py:"text/x-python"}[n||""]||"application/octet-stream"}async function zi(t){let n=j();if(!ae())throw new F(`Not authenticated. Run '${p.commands[0]} login' or set ${p.apiKeyEnvVar} environment variable.`,401,2);let e=await de(),o=ji(t),r=po(t),i=Ji(t),a=await fetch(`${n}/api/cli/files/upload`,{method:"POST",headers:{"Content-Type":"application/json",...e},body:JSON.stringify({fileMetadata:{name:r,type:i,size:o.size}})});if(!a.ok){let I=await a.text();throw new F(I||"Failed to get upload URL",a.status,1)}let s=await a.json(),l=Vi(t),d=new FormData;for(let[I,g]of Object.entries(s.fields||{}))d.append(I,g);let f=new Blob([l],{type:i});d.append("file",f,r);let v=await fetch(s.url,{method:"POST",body:d});if(!v.ok)throw new F("Failed to upload file to storage",v.status,1);return{id:an(),name:r,url:s.fileUrl,size:o.size,type:i,selected:!0}}async function ho(t,n){let e=[];for(let o=0;o<t.length;o++){let r=t[o],i=po(r);n?.(o,t.length,i);let a=await zi(r);e.push(a)}return n?.(t.length,t.length,""),e}async function yo(t){let n={};for(let[o,r]of Object.entries(t))r!==void 0&&(n[o]=r);let e=n.designBrandReference??n.brandId??n.brandingId;return e!==void 0&&(n.designBrandReference=e,delete n.brandId,delete n.brandingId),$("createSlides",{...n,approvalReceipt:"cli:create"})}async function bo(t,n=20){let e=new URLSearchParams;return e.set("limit",String(n)),t&&e.set("teamId",t),(await z(`/api/cli/presentations?${e}`)).presentations}async function xe(t){return z(`/api/cli/presentation/${t}`)}async function xo(t){await z(`/api/cli/presentation/${t}`,{method:"DELETE"})}async function vo(t,n={}){let e=j();if(!ae())throw new F(`Not authenticated. Run '${p.commands[0]} login' or set ${p.apiKeyEnvVar} environment variable.`,401,2);let o=await de(),r=await fetch(`${e}/api/presentations/export`,{method:"POST",headers:{"Content-Type":"application/json",...o},body:JSON.stringify({presentationId:t,options:{includeImages:n.includeImages??!0,includeBranding:n.includeBranding??!0,downloadExternalImages:n.includeExternal??!0}})});if(!r.ok)throw new F(await r.text(),r.status,r.status===404?3:1);return r.arrayBuffer()}async function wo(t,n,e={}){let o=j();if(!ae())throw new F(`Not authenticated. Run '${p.commands[0]} login' or set ${p.apiKeyEnvVar} environment variable.`,401,2);let r=await de(),i=new FormData,a=new Blob([t],{type:"application/zip"});i.append("file",a,n),i.append("options",JSON.stringify({dryRun:e.dryRun??!1,remapIds:!0}));let s=await fetch(`${o}/api/presentations/import`,{method:"POST",headers:r,body:i}),l=await s.json();if(!s.ok)throw new F(l.errors?.[0]?.message??"Import failed",s.status,1);return l}async function sn(){return z("/api/cli/branding")}async function So(t,n=25){let e=new URLSearchParams;return e.set("limit",String(n)),t&&e.set("search",t),z(`/api/cli/templates?${e}`)}async function Co(t){return z(`/api/branding/${t}`)}async function Io(t,n,e){return $("extractBranding",{approvalReceipt:e,teamId:n,url:t})}async function he(){return z("/api/cli/whoami")}async function To(){return z("/api/cli/features")}async function ko(t,n,e={}){let o=j();if(!ae())throw new F(`Not authenticated. Run '${p.commands[0]} login' or set ${p.apiKeyEnvVar} environment variable.`,401,2);let r=await de(),i=await fetch(`${o}/api/presentations/${t}/generate-blog`,{method:"POST",headers:{"Content-Type":"application/json",...r},body:JSON.stringify({documentCreatedAt:n,targetWordCount:e.targetWordCount??300,tone:e.tone??"professional",language:e.language??"en",targetAudience:e.targetAudience??"General Audience",blogFormat:e.blogFormat??"narrative",customInstructions:e.customInstructions??"",includeImages:e.includeImages??!0,includeTableOfContents:e.includeTableOfContents??!1})});if(!i.ok)throw new F(await i.text(),i.status,i.status===404?3:1);return i}async function Xi(t){let n=new URLSearchParams;t&&n.set("teamId",t);let e=n.toString();return z(`/api/cli/limits${e?`?${e}`:""}`)}async function Ro(t,n,e){let o=await Xi(e);if(!o.canGenerate[t]){let r=o.remaining[t]??0,i=o.limits[t]??0;throw i===0?new F(`The "${t}" mode is not available on your ${o.planName} plan. Available modes: ${o.availableModes.join(", ")||"none"}`,403,2):new F(`You have reached your ${t} generation limit for this billing cycle (${o.usage[t]??0}/${i} used). Try a different mode: ${o.availableModes.join(", ")||"none available"}`,403,4)}if(o.maxSlidesPerPresentation!==-1&&n>o.maxSlidesPerPresentation)throw new F(`Maximum ${o.maxSlidesPerPresentation} slides allowed on your ${o.planName} plan (requested: ${n}). Try a different mode: ${o.availableModes.join(", ")||"none available"}`,403,6);return o}function Ao(t){return t.replace(/[\u2014\u2013]/g,"-").replace(/[\u201C\u201D]/g,'"').replace(/[\u2018\u2019]/g,"'").replace(/\u2026/g,"...").replace(/\u00A0/g," ").replace(/[\u2010-\u2015]/g,"-").replace(/[\u2032\u2033]/g,"'")}async function xt(t){let n=await $("generateSpeech",{approvalReceipt:"cli:tts-generate",...t,text:Ao(t.text)}),o=(await Wi("generateSpeech",n.runId)).entity?.url;if(!o)throw new F("Speech completed without an audio URL",500);let r=await fetch(o);if(!r.ok)throw new F("Failed to download speech audio",502);return{audioData:Buffer.from(await r.arrayBuffer()),audioUrl:o,duration:0,cost:0,provider:t.options?.provider??"gemini",format:Hi(o)??"mp3",requestId:n.runId}}async function $o(t){let n=j();if(!ae())throw new F(`Not authenticated. Run '${p.commands[0]} login' or set ${p.apiKeyEnvVar} environment variable.`,401,2);let e=await de(),o=an(),r={...t,texts:t.texts.map(s=>({...s,text:Ao(s.text)}))},i;try{i=await fetch(`${n}/api/cli/tts/batch`,{method:"POST",headers:{"Content-Type":"application/json",[go]:o,...e},body:JSON.stringify(r)})}catch(s){throw new F(`Network error: ${s instanceof Error?s.message:"Unknown error"}`,0,5)}if(!i.ok){let s=await i.text().catch(()=>"Unknown error"),l;try{let d=JSON.parse(s);l=d.error||d.message||s}catch{l=s}throw new F(l,i.status,i.status===401?2:1)}let a=await i.json();return a.results=a.results.map(s=>({...s,audioData:Buffer.from(s.audioData,"base64")})),a}async function Eo(t){let n=t?`/api/cli/tts?provider=${t}`:"/api/cli/tts";return z(n)}async function vt(t){return{requestId:(await $("generateMusic",{...t,approvalReceipt:"cli:music-generate"})).runId,status:"pending"}}async function ot(t){let n=await U("generateMusic",t);return{requestId:t,status:bt(n),audioUrl:n.entity?.url,error:n.error?.message}}async function Oo(t){return{requestId:(await $("mixAudio",{...t,approvalReceipt:"cli:mix-create"})).runId,status:"pending"}}async function cn(t){let n=await U("mixAudio",t);return{requestId:t,status:bt(n),outputUrl:n.entity?.url,error:n.error?.message}}async function wt(t){return z("/api/cli/images/search",{method:"POST",body:t})}async function Po(t){return z("/api/cli/images/generate",{method:"POST",body:t})}async function ln(t){return z("/api/cli/videos/search",{method:"POST",body:t})}async function ue(t,n=60,e=2e3){for(let o=0;o<n;o++){let r=await t();if(r.status==="completed"||r.status==="failed")return r;await new Promise(i=>setTimeout(i,e))}throw new F("Operation timed out",408,1)}async function No(t,n){let e=await $("scrape",{teamId:n,url:t});return{data:{content:e.content,cost:e.totalCost??0,metadata:{description:"",format:"markdown",tokenUsage:Math.ceil(e.content.length/4)},title:e.title??"",url:e.url},success:!0}}async function Do(t){let n=await $("generateSfx",{...t,approvalReceipt:"cli:sfx-generate"});return{id:n.runId,requestId:n.runId,status:"pending"}}async function dn(t){let n=await U("generateSfx",t);return{id:n.entity?.id??t,requestId:t,status:bt(n),audioUrl:n.entity?.url,error:n.error?.message}}async function Lo(t){return $("listPresenterOptions",{...t?{voiceLanguage:t}:{}})}async function Fo(t){return{requestId:(await $("generateAvatarVideo",{...t,approvalReceipt:"cli:avatar-generate"})).runId,status:"pending"}}async function un(t){let n=await U("generateAvatarVideo",t);return{durationSec:typeof n.output?.durationSec=="number"?n.output.durationSec:null,error:n.error?.message,requestId:t,status:bt(n),videoUrl:n.entity?.url}}async function mn(t){return $("generateVideoPlan",{...t,approvalReceipt:"cli:video-plan"})}async function Uo(t){return $("createVideo",{...t,approvalReceipt:"cli:video-create"})}async function _o(t){return z("/api/cli/video/plan",{body:t,method:"POST"})}import L from"chalk";import pn from"cli-table3";function C(t,n="human"){n!=="quiet"&&n!=="json"&&console.log(L.green("\u2713"),t)}function c(t,n="human"){if(n!=="quiet"){if(n==="json"){console.error(JSON.stringify({error:t}));return}console.error(L.red("\u2717"),t)}}function _(t,n="human"){n!=="quiet"&&n!=="json"&&console.warn(L.yellow("\u26A0"),t)}function m(t,n="human"){n!=="quiet"&&n!=="json"&&console.log(L.blue("\u2139"),t)}function Pe(t,n="en"){return t?`${j()}/${n}/view/presentations/${t}`:"N/A"}function Mo(t,n={}){let{showLinks:e=!1,language:o="en"}=n,r=(s,l)=>s.length>l?s.slice(0,l-1)+"\u2026":s,i=s=>{try{return new Date(s).toLocaleString("en-US",{month:"short",day:"numeric",hour:"numeric",minute:"2-digit",hour12:!0}).replace(" at ",", ")}catch{return"-"}};if(e){let s=new pn({head:[L.cyan("Slug"),L.cyan("Title"),L.cyan("Slides"),L.cyan("Created"),L.cyan("URL")]});for(let l of t)s.push([r(l.slug||l.id.slice(0,8),30),r(l.title||"Untitled",22),String(l.numberOfSlides||"-"),i(l.createdAt),Pe(l.slug,o)]);return s.toString()}let a=new pn({head:[L.cyan("Slug"),L.cyan("Title"),L.cyan("Slides"),L.cyan("Mode"),L.cyan("Created")],colWidths:[32,28,8,11,18]});for(let s of t)a.push([s.slug||s.id.slice(0,8),s.title||"Untitled",String(s.numberOfSlides||"-"),s.mode||"-",i(s.createdAt)]);return a.toString()}function Vo(t){return t.map(n=>n.slug||n.id).join(`
4
- `)}function jo(t){let n=[...t].sort((r,i)=>{if(r.isDefault&&!i.isDefault)return-1;if(!r.isDefault&&i.isDefault)return 1;let a=r.createdAt?new Date(r.createdAt).getTime():0;return(i.createdAt?new Date(i.createdAt).getTime():0)-a}),e=r=>{if(!r)return"-";try{return new URL(r).href}catch{return r.startsWith("http")?r:`https://${r}`}},o=new pn({head:[L.cyan("Name"),L.cyan("Source"),L.cyan("Color"),L.cyan("Logo"),L.cyan("Default"),L.cyan("ID")]});for(let r of n){let i=r.primaryColor?`${L.bgHex(r.primaryColor)(" ")} ${r.primaryColor}`:"-";o.push([r.name,e(r.sourceUrl),i,r.logoUrl?L.green("\u2713"):L.gray("\u2717"),r.isDefault?L.green("\u2605"):"",r.id])}return o.toString()}function gn(t){try{return new Date(t).toLocaleString()}catch{return t}}function me(t){console.log(),console.log(L.bold(t)),console.log(L.gray("\u2500".repeat(t.length)))}function k(t,n){console.log(` ${L.gray(t+":")} ${n??"-"}`)}function Yi(t){return JSON.stringify(t,null,2)}function S(t){console.log(Yi(t))}var qo=new Ki("capabilities").description("List callable capabilities and their parity state").option("-f, --format <format>","Output format: human, json, quiet","human").action(async t=>{try{let n=await fo();if(t.format==="json"){S(n);return}for(let e of n.capabilities){if(t.format==="quiet"){console.log(e.name);continue}console.log(`${e.name} ${e.state} ${e.milestone}`)}}catch(n){c(n instanceof Error?n.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}});import{mkdirSync as ta,writeFileSync as na}from"fs";import{dirname as Ho,join as oa}from"path";import{Command as ve}from"commander";import rt from"chalk";import{input as ra,password as ia,confirm as Jo,select as aa}from"@inquirer/prompts";import Ct from"ora";import Qi from"conf";var St=new Qi({projectName:"conceptcraft",configName:"feature-cache"}),Zi=3600*1e3,ea=1440*60*1e3;function Bo(t){let n=0;for(let e=0;e<t.length;e++){let o=t.charCodeAt(e);n=(n<<5)-n+o,n=n&n}return n.toString(16)}function Go(){if(!Oe())return null;let t=St.get("featureFlags");if(!t)return null;let n=Bo(fe());if(t.apiKeyHash&&t.apiKeyHash!==n)return Te(),null;let e=Date.now()-t.fetchedAt;return e>ea?null:(e>Zi&&fn(),t.flags)}function fn(){Ie().catch(()=>{})}async function Ie(){let t=await To(),n=fe();return St.set("featureFlags",{flags:t,fetchedAt:Date.now(),apiKeyHash:n?Bo(n):void 0}),t}function Te(){St.delete("featureFlags")}function Wo(){return St.path}var zo=new ve("config").description("Manage CLI configuration").addCommand(new ve("init").description("Initialize configuration interactively").action(async()=>{console.log(),console.log(rt.bold(`${p.displayName} CLI Configuration`)),console.log(rt.gray("\u2500".repeat(35))),console.log();try{let t=await ia({message:"Enter your API key:",mask:"*",validate:o=>!o||o.trim().length===0?"API key is required":rn(o.trim())?!0:"Invalid API key format. Keys should start with 'cc_slides_' or 'mcp_'"});if(nn(t.trim()),await Jo({message:`Use a custom API URL? (default: ${p.apiUrl.replace("https://","")})`,default:!1})){let o=await ra({message:"Enter API URL:",default:j(),validate:r=>{try{return new URL(r),!0}catch{return"Invalid URL format"}}});on(o)}console.log();let e=Ct("Verifying API key...").start();try{let o=await he();if(e.succeed("API key verified!"),console.log(),m(`Logged in as: ${o.user.email}`),o.teams.length===0)_("No teams found for this user.");else if(o.teams.length===1){let r=o.teams[0];Ee(r.id),m(`Team: ${r.name} (${r.planName})`)}else{console.log(),m(`You have access to ${o.teams.length} teams.`);let r=await aa({message:"Select your default team:",choices:o.teams.map(a=>({name:`${a.name} (${a.planName}) - ${a.role}${a.isCurrent?" [current]":""}`,value:a.id})),default:o.currentTeam?.id});Ee(r);let i=o.teams.find(a=>a.id===r);C(`Selected team: ${i?.name}`)}try{await Ie()}catch{}}catch(o){e.fail("Failed to verify API key"),_(`Could not verify API key: ${o instanceof Error?o.message:String(o)}`),_(`You may need to set the team ID manually: ${p.commands[0]} config set team-id <id>`)}console.log(),C("Configuration saved!"),m(`Config file: ${nt()}`),console.log()}catch(t){if(t.name==="ExitPromptError"){console.log(),m("Configuration cancelled.");return}throw t}})).addCommand(new ve("show").description("Show current configuration").option("--verify","Verify API key and show team details").action(async t=>{let n=io();if(me("Current Configuration"),console.log(),k("API Key",mo()??rt.red("Not set")),k("API URL",n.apiUrl),k("Default Team ID",n.defaultTeamId??rt.gray("Not set")),console.log(),k("Config file",nt()),t.verify&&n.apiKey){console.log();let e=Ct("Verifying...").start();try{let o=await he();e.succeed("Verified"),console.log(),k("User",o.user.email),o.currentTeam&&k("Current Team",`${o.currentTeam.name} (${o.currentTeam.planName})`),o.teams.length>1&&k("Total Teams",String(o.teams.length))}catch(o){e.fail("Verification failed"),_(o instanceof Error?o.message:String(o))}}console.log()})).addCommand(new ve("set").description("Set a configuration value").argument("<key>","Configuration key (api-key, api-url, team-id)").argument("<value>","Value to set").action(async(t,n)=>{switch(t){case"api-key":rn(n)||(c("Invalid API key format. Keys should start with 'cc_slides_' or 'mcp_'"),process.exit(6)),nn(n),Te(),C("API key updated"),Ie().catch(()=>{});break;case"api-url":try{new URL(n),on(n),C(`API URL set to: ${n}`)}catch{c("Invalid URL format"),process.exit(6)}break;case"team-id":Ee(n),C(`Default team ID set to: ${n}`);break;default:c(`Unknown config key: ${t}`),console.log(rt.gray("Valid keys: api-key, api-url, team-id")),process.exit(6)}})).addCommand(new ve("clear").description("Clear all configuration").action(async()=>{try{await Jo({message:"Are you sure you want to clear all configuration?",default:!1})?(mt(),Te(),C("Configuration cleared")):m("Cancelled")}catch{m("Cancelled")}})).addCommand(new ve("refresh").description("Refresh cached feature flags").action(async()=>{let t=Ct("Refreshing feature flags...").start();try{await Ie(),t.succeed("Feature flags refreshed"),m(`Run '${p.commands[0]} --help' to see updated commands`)}catch(n){t.fail("Failed to refresh"),c(n instanceof Error?n.message:String(n)),process.exit(1)}})).addCommand(new ve("path").description("Show configuration file path").option("--cache","Show feature cache file path").action(t=>{t.cache?console.log(Wo()):console.log(nt())})).addCommand(new ve("pull").description("Pull your account settings (memory, brand, prefs) into a local config.toml").action(async()=>{let t=Ct("Pulling settings...").start();try{let n=await de(),e=await fetch(`${j()}/api/cli/settings`,{headers:n});if(!e.ok)throw new Error(`Request failed (HTTP ${e.status})`);let o=await e.text(),r=oa(Ho(nt()),"settings.toml");ta(Ho(r),{recursive:!0}),na(r,o,"utf8"),t.succeed("Settings pulled"),m(`Written to ${r}`)}catch(n){t.fail("Failed to pull settings"),c(n instanceof Error?n.message:String(n)),process.exit(1)}}));import{Command as sa}from"commander";import{confirm as ca}from"@inquirer/prompts";var Xo=new sa("delete").description("Delete a presentation").argument("<slug>","Presentation slug (e.g., my-presentation-v1-abc123)").option("-f, --force","Skip confirmation prompt").option("-q, --quiet","Suppress output").action(async(t,n)=>{if(await O(),!n.force)try{if(!await ca({message:`Are you sure you want to delete presentation "${t}"?`,default:!1})){n.quiet||_("Deletion cancelled");return}}catch{n.quiet||_("Deletion cancelled");return}try{await xo(t),n.quiet||C(`Presentation "${t}" deleted`)}catch(e){c(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}});import{Command as Ne}from"commander";import Ko from"chalk";import la from"ora";import{createParser as Bd}from"eventsource-parser";import Wd from"chalk";import Jd from"ora";async function Yo(t,n={}){let e=t.body?.getReader();if(!e)throw new Error("Response body is not readable");let o=new TextDecoder,r="",i=!1;for(;!i;){let a=await e.read();if(i=a.done,a.value){let s=o.decode(a.value,{stream:!0});r+=s,n.quiet||process.stdout.write(s)}}return n.quiet||console.log(),r}function da(){return new Ne("blog").description("Generate a blog post from a presentation").argument("<slug>","Presentation slug").option("--words <count>","Target word count (50-2000)","300").option("--tone <tone>","Writing tone (professional, casual, educational)","professional").option("--audience <text>","Target audience description").option("-f, --format <format>","Output format (human, json, markdown)","human").option("--instructions <text>","Custom instructions for the blog").option("--no-images","Exclude image references").option("--toc","Include table of contents").action(async(t,n)=>{await O();let e=parseInt(n.words,10);(isNaN(e)||e<50||e>2e3)&&(c("Word count must be between 50 and 2000"),process.exit(6));let o=["professional","casual","educational"];o.includes(n.tone)||(c(`Invalid tone. Valid options: ${o.join(", ")}`),process.exit(6));let r=la("Fetching presentation...").start();try{let i=await xe(t);r.text="Generating blog post...";let a=await ko(i.id,i.documentCreatedAt||i.createdAt,{targetWordCount:e,tone:n.tone,targetAudience:n.audience??"General Audience",customInstructions:n.instructions??"",includeImages:!n.noImages,includeTableOfContents:n.toc??!1}),s=await Yo(a,{quiet:!0});r.succeed("Blog generated"),n.format==="json"?console.log(JSON.stringify({presentationId:t,title:i.title,wordCount:e,tone:n.tone,content:s},null,2)):n.format==="markdown"?console.log(s):(console.log(),console.log(Ko.bold(`Blog: ${i.title}`)),console.log(Ko.gray("\u2500".repeat(40))),console.log(),console.log(s),console.log())}catch(i){r.fail("Generation failed"),c(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}})}function ua(){return new Ne("tweets").description("Generate tweets from a presentation").argument("<slug>","Presentation slug").option("--count <n>","Number of tweets to generate","5").option("-f, --format <format>","Output format (human, json)","human").action(async(t,n)=>{await O(),m("Tweet generation coming soon.")})}function ma(){return new Ne("linkedin").description("Generate a LinkedIn carousel from a presentation").argument("<slug>","Presentation slug").option("-f, --format <format>","Output format (human, json)","human").action(async t=>{await O(),m("LinkedIn carousel generation coming soon.")})}function pa(){return new Ne("questions").description("Generate questions for a presentation").argument("<slug>","Presentation slug").option("--count <n>","Number of questions","10").option("-f, --format <format>","Output format (human, json)","human").action(async(t,n)=>{await O(),m("Question generation coming soon.")})}function ga(){return new Ne("cheatsheet").description("Generate a presenter cheat sheet").argument("<slug>","Presentation slug").option("--mode <mode>","Cheat sheet mode (qa-prep, talking-points)","qa-prep").option("-f, --format <format>","Output format (human, json, markdown)","human").action(async(t,n)=>{await O(),m("Cheat sheet generation coming soon.")})}function Qo(){let t=new Ne("derive").description("Generate derivative content from a presentation"),n=Go();return n&&(n.deckToBlog&&t.addCommand(da()),n.deckToTweets&&t.addCommand(ua()),n.linkedInCarousel&&t.addCommand(ma()),n.redTeamQuestions&&t.addCommand(pa()),n.presenterCheatSheet&&t.addCommand(ga())),t}import{Command as fa}from"commander";import{writeFile as ha}from"fs/promises";import{resolve as Zo}from"path";import ya from"ora";var er=new fa("export").description("Export a presentation to ZIP").argument("<slug>","Presentation slug (e.g., my-presentation-v1-abc123)").option("-o, --output <path>","Output file path").option("--include-images","Include images (default: true)",!0).option("--include-branding","Include branding (default: true)",!0).option("--no-external","Skip external image downloads").action(async(t,n)=>{await O();let e=ya("Fetching presentation...").start();try{let o=await xe(t),r=o.title||t,i=o.id,a=t.replace(/[^a-z0-9-]/gi,"_").toLowerCase().substring(0,50),s=new Date().toISOString().split("T")[0],l=`${a}_${s}.zip`,d=n.output?Zo(n.output):Zo(process.cwd(),l);e.text=`Exporting "${r}"...`;let f=await vo(i,{includeImages:n.includeImages,includeBranding:n.includeBranding,includeExternal:!n.noExternal});e.text="Saving file...",await ha(d,Buffer.from(f)),e.succeed("Export complete!"),console.log(),m(`File saved: ${d}`),m(`Size: ${ba(f.byteLength)}`),console.log()}catch(o){e.fail("Export failed"),c(o instanceof Error?o.message:String(o)),process.exit(o.exitCode??1)}});function ba(t){return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:`${(t/(1024*1024)).toFixed(1)} MB`}import{Command as xa}from"commander";import hn from"chalk";var tr=new xa("ideas").description("Generate presentation topic ideas").option("--context <text>","Custom context for idea generation").option("--count <n>","Number of ideas to generate","5").option("-f, --format <format>","Output format (human, json)","human").action(async t=>{await O(),m("Idea generation is available in the web dashboard."),console.log(),console.log(hn.gray("The CLI will support idea generation in a future release.")),console.log(),console.log("For now, try these approaches:"),console.log(hn.gray("` 1. Visit the ${brand.displayName} dashboard and use the idea generator`")),console.log(hn.gray(" 2. Create a presentation with a broad topic and refine it")),console.log()});import{Command as va}from"commander";import{readFile as wa}from"fs/promises";import{resolve as Sa,basename as Ca}from"path";import Ia from"ora";var nr=new va("import").description("Import a presentation from ZIP (admin only)").argument("<file>","Path to ZIP file");nr._hidden=!0;var or=nr.option("--dry-run","Validate without importing").option("--overwrite","Overwrite existing presentations").option("--remap-ids","Generate new IDs (default: true)",!0).action(async(t,n)=>{await O();try{(await he()).user.role!=="admin"&&(c("This command is only available to administrators"),process.exit(2))}catch{c("Failed to verify permissions"),process.exit(2)}let e=Sa(t),o=Ca(e);o.endsWith(".zip")||(c("File must be a ZIP archive"),process.exit(6));let r=Ia("Reading file...").start();try{let i=await wa(e);n.dryRun?r.text="Validating...":r.text="Importing presentation...";let a=await wo(i,o,{dryRun:n.dryRun});if(a.success){if(n.dryRun)r.succeed("Validation passed!"),console.log(),m("The file is valid and can be imported."),a.statistics&&(console.log(),k("Slides",String(a.statistics.slidesImported)),k("Images",String(a.statistics.imagesUploaded)));else if(r.succeed("Import complete!"),console.log(),k("Presentation ID",a.presentationId??"N/A"),k("Document ID",a.documentId??"N/A"),a.statistics&&(k("Slides imported",String(a.statistics.slidesImported)),k("Images uploaded",String(a.statistics.imagesUploaded)),k("Time",`${a.statistics.totalTimeMs}ms`)),a.presentationId){let s=j();k("View URL",`${s}/p/${a.presentationId}`)}if(a.warnings&&a.warnings.length>0){console.log();for(let s of a.warnings)_(s)}console.log()}else{if(r.fail("Import failed"),console.log(),a.errors)for(let s of a.errors)c(`${s.type}: ${s.message}`);process.exit(1)}}catch(i){r.fail("Import failed"),i.code==="ENOENT"&&(c(`File not found: ${e}`),process.exit(3)),c(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}});import{Command as Ta}from"commander";var rr=new Ta("list").description("List presentations").option("-n, --limit <count>","Number of results to return","20").option("-f, --format <format>","Output format (table, json, ids)","table").option("--sort <field>","Sort by field (created, updated, title)").option("--team-id <id>","Team ID (uses default if not specified)").option("-d, --detail","Show detailed output including URLs").option("-l, --language <lang>","Language for URLs","en").action(async t=>{await O();let n=parseInt(t.limit,10);(isNaN(n)||n<1)&&(c("Invalid limit value"),process.exit(6));let e=t.teamId??ut();e||(c("`Team ID required. Set a default with '${brand.commands[0]} config set team-id <id>' or use --team-id`"),process.exit(6));try{let o=await bo(e,n);if(o.length===0){t.format==="json"?console.log(JSON.stringify([])):t.format!=="ids"&&m("No presentations found");return}switch(t.sort&&o.sort((r,i)=>{switch(t.sort){case"created":return new Date(i.createdAt).getTime()-new Date(r.createdAt).getTime();case"title":return(r.title||"").localeCompare(i.title||"");default:return 0}}),t.format){case"json":console.log(JSON.stringify(o,null,2));break;case"ids":console.log(Vo(o));break;default:console.log(Mo(o,{showLinks:t.detail,language:t.language}));break}}catch(o){c(o instanceof Error?o.message:String(o)),process.exit(o.exitCode??1)}});import{Command as ka}from"commander";import ir from"chalk";import ar from"ora";import sr from"http";import{randomBytes as cr,createHash as Ra}from"crypto";import Aa from"open";var $a=`${p.displayName} CLI`,Ea=8765,Oa=8775;function Pa(){return cr(32).toString("base64url")}function Na(t){return Ra("sha256").update(t).digest("base64url")}function Da(){return cr(16).toString("hex")}async function La(t,n){for(let e=t;e<=n;e++)try{return await new Promise((o,r)=>{let i=sr.createServer();i.listen(e,()=>{i.close(()=>o())}),i.on("error",r)}),e}catch{continue}throw new Error(`No available port found between ${t} and ${n}`)}async function Fa(t){let n=await fetch(`${t}/.well-known/oauth-authorization-server`);if(!n.ok)throw new Error(`Failed to fetch OAuth metadata: ${n.status}`);return n.json()}async function Ua(t,n){let e=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_name:$a,redirect_uris:[n],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"none",scope:"presentations:read presentations:write"})});if(!e.ok){let o=await e.text();throw new Error(`Client registration failed: ${o}`)}return e.json()}async function _a(t,n,e,o,r){let i=new URLSearchParams({grant_type:"authorization_code",code:n,redirect_uri:o,client_id:r,code_verifier:e}),a=await fetch(t,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()});if(!a.ok){let s=await a.text();throw new Error(`Token exchange failed: ${s}`)}return a.json()}function Ma(t,n){return new Promise((e,o)=>{let r,i=!1,a=()=>{i||(i=!0,clearTimeout(r),process.off("SIGINT",s),process.off("SIGTERM",s),l.close())},s=()=>{a(),o(new Error("Login cancelled"))},l=sr.createServer((d,f)=>{let v=new URL(d.url||"",`http://localhost:${t}`);if(v.pathname!=="/callback"){f.writeHead(404),f.end("Not found");return}let I=v.searchParams.get("code"),g=v.searchParams.get("state"),T=v.searchParams.get("error"),b=v.searchParams.get("error_description");if(f.writeHead(200,{"Content-Type":"text/html"}),T){f.end(`
3
+ var h={id:"mindframes",name:"mindframes",displayName:"Mindframes",description:"CLI tool for Mindframes presentation generation",commands:["mf","mindframes"],apiUrl:"https://www.mindframes.app",docsUrl:"https://docs.mindframes.ai",packageName:"@conceptcraft/mindframes",configDir:".mindframes",apiKeyEnvVar:"MINDFRAMES_API_KEY",apiUrlEnvVar:"MINDFRAMES_API_URL",codexSelfConnectorAppId:"asdk_app_6a2b9629c1608191970dcb3ab374ac55"};import ue from"chalk";import{Command as Il}from"commander";import{Command as Pa}from"commander";import{randomUUID as pn}from"crypto";import{readFileSync as ba,statSync as wa}from"fs";import{basename as To}from"path";import{spawnSync as aa}from"child_process";import{existsSync as sa,mkdtempSync as ca,rmSync as da,writeFileSync as la}from"fs";import{tmpdir as ua}from"os";import{join as po}from"path";import dn from"ffmpeg-static";var ma=/Duration:\s*(\d+):(\d+):(\d+(?:\.\d+)?)/;function pa(e){let n=ma.exec(e);if(!n)return;let t=Number(n[1])*3600+Number(n[2])*60+Number(n[3]);return Number.isFinite(t)&&t>0?t:void 0}function go(e,n="audio"){if(e.length===0)return;let t=dn&&sa(dn)?dn:"ffmpeg",o=/^[a-z0-9]+$/i.test(n)?n:"audio",r=ca(po(ua(),"mf-tts-duration-")),i=po(r,`speech.${o}`);try{la(i,e);let a=aa(t,["-hide_banner","-i",i],{encoding:"utf8"});return a.error?void 0:pa(a.stderr??"")}finally{da(r,{force:!0,recursive:!0})}}import St from"chalk";import ga from"conf";function fo(e={}){let n=(s,d)=>{let u=e[s];return u&&u.trim().length>0?u.trim():d},t=n("NEXT_PUBLIC_PRODUCT_SHORT_NAME","ConceptCraft"),o=n("NEXT_PUBLIC_CLI_COMMAND","ccr"),r=n("NEXT_PUBLIC_CLI_COMMAND_FULL","conceptcraft"),i=n("NEXT_PUBLIC_CLI_CONFIG_DIR",`.${r}`),a=t.toUpperCase().replace(/[^A-Z0-9]/g,"_");return{id:r,name:i.replace(/^\./,""),displayName:t,description:`CLI tool for ${t} presentation generation`,commands:[o,r],apiUrl:n("NEXT_PUBLIC_API_URL","http://localhost:3000"),docsUrl:n("NEXT_PUBLIC_DOCS_URL",`https://docs.${t.toLowerCase()}.ai`),packageName:n("NEXT_PUBLIC_CLI_PACKAGE_NAME","@conceptcraft/cli"),configDir:i,apiKeyEnvVar:`${a}_API_KEY`,apiUrlEnvVar:`${a}_API_URL`,codexSelfConnectorAppId:e.NEXT_PUBLIC_CODEX_SELF_CONNECTOR_APP_ID?.trim()||void 0}}var g=typeof h<"u"&&h?h:fo(process.env);var ho=g.apiUrl,fa={apiKey:{type:"string"},apiUrl:{type:"string",default:ho},defaultTeamId:{type:"string"},accessToken:{type:"string"},refreshToken:{type:"string"},tokenExpiresAt:{type:"number"},clientId:{type:"string"},clientSecret:{type:"string"}},D=new ga({projectName:g.name,schema:fa});function yo(){return{apiKey:be(),apiUrl:j(),defaultTeamId:D.get("defaultTeamId"),accessToken:D.get("accessToken"),refreshToken:D.get("refreshToken"),tokenExpiresAt:D.get("tokenExpiresAt"),clientId:D.get("clientId"),clientSecret:D.get("clientSecret")}}function be(){let e=process.env[g.apiKeyEnvVar]??process.env.CC_SLIDES_API_KEY;return e||D.get("apiKey")}function ln(e){D.set("apiKey",e)}function j(){let e=process.env[g.apiUrlEnvVar]??process.env.CC_SLIDES_API_URL;return e||(D.get("apiUrl")??ho)}function un(e){D.set("apiUrl",e)}function ht(){return D.get("defaultTeamId")}function Pe(e){D.set("defaultTeamId",e)}function yt(){D.clear()}function it(){return D.path}function Ne(){return!!be()}function bo(){return D.get("accessToken")}function wo(){return D.get("refreshToken")}function bt(e,n,t){D.set("accessToken",e),D.set("refreshToken",n),D.set("tokenExpiresAt",Date.now()+(t-60)*1e3)}function wt(){D.delete("accessToken"),D.delete("refreshToken"),D.delete("tokenExpiresAt")}function vo(){let e=D.get("tokenExpiresAt");return e?Date.now()>=e:!0}function Te(){return!!D.get("accessToken")&&!!D.get("refreshToken")}function vt(){return D.get("clientId")}function xt(){return D.get("clientSecret")}function xo(e,n){D.set("clientId",e),D.set("clientSecret",n)}var l={SUCCESS:0,GENERAL_ERROR:1,AUTH_ERROR:2,NOT_FOUND:3,RATE_LIMIT:4,NETWORK_ERROR:5,INVALID_INPUT:6};async function ha(){let e=wo(),n=vt(),t=j();if(!e||!n)return null;try{let o=await fetch(`${t}/.well-known/oauth-authorization-server`);if(!o.ok)return null;let r=await o.json(),i=new URLSearchParams({grant_type:"refresh_token",refresh_token:e,client_id:n}),a=xt();a&&i.set("client_secret",a);let s=await fetch(r.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()});if(!s.ok)return wt(),null;let d=await s.json();return bt(d.access_token,d.refresh_token,d.expires_in),d.access_token}catch{return null}}async function So(){return Te()?vo()?ha():bo()||null:null}function ce(){return Te()||Ne()}async function P(){if(!ce()){let e=g.commands[0],n=g.apiKeyEnvVar;console.error(St.red("\u2717 Not authenticated.")),console.error(),console.error(St.bold("To authenticate, run:")),console.error(St.cyan(` ${e} login`)),console.error(),console.error(St.gray(`Or set ${n} environment variable.`)),process.exit(l.AUTH_ERROR)}}function ya(e){return e.length<=14?"****":`${e.slice(0,10)}...${e.slice(-4)}`}function Co(){let e=be();if(e)return ya(e)}function mn(e){return["cc_slides_","mcp_","cc_sk_","sk_"].some(t=>e.startsWith(t))}async function ge(){let e=await So();if(e)return{Authorization:`Bearer ${e}`};let n=be();return n?{"x-api-key":n}:{}}var O=class extends Error{constructor(t,o,r=1,i="operation_failed",a=!1){super(t);this.statusCode=o;this.exitCode=r;this.errorCode=i;this.retryable=a;this.name="ApiError"}statusCode;exitCode;errorCode;retryable},Ro="Idempotency-Key";function va(e){return e&&e!=="GET"?{[Ro]:pn()}:{}}async function z(e,n={}){let t=j();if(!ce())throw new O(`Not authenticated. Run '${g.commands[0]} login' or set ${g.apiKeyEnvVar} environment variable.`,401,2,"authentication_required");let o=await ge(),r=`${t}${e}`,i={...o,...va(n.method),...n.headers};n.body&&!n.stream&&(i["Content-Type"]="application/json");let a={method:n.method??"GET",headers:i};n.body&&(a.body=JSON.stringify(n.body));let s;try{s=await fetch(r,a)}catch(u){throw new O(`Network error: ${u instanceof Error?u.message:"Unknown error"}`,0,5,"service_unavailable",!0)}if(!s.ok){let u=await s.text().catch(()=>""),p=Sa(u,s.status),w=1;switch(s.status){case 401:w=2;break;case 403:w=2;break;case 404:w=3;break;case 429:w=4;break;case 500:w=1;break}let I=`[${p.code}] ${p.message}`;throw new O(I,s.status,w,p.code,p.retryable)}return n.stream?s:s.headers.get("content-type")?.includes("application/json")?s.json():s.text()}function xa(e){switch(e){case 400:return"invalid_input";case 401:return"authentication_required";case 402:return"insufficient_credits";case 403:return"access_denied";case 404:return"not_found";case 429:return"rate_limited";case 503:return"service_unavailable";default:return"operation_failed"}}function Sa(e,n){let t=xa(n),o=e.trim()||`HTTP ${n}: The request could not be completed.`;try{let r=JSON.parse(e),i=typeof r.error=="object"&&r.error!==null?r.error:void 0;if(r.ok===!1&&typeof i?.code=="string"&&typeof i.message=="string")return{code:i.code,message:i.message,retryable:i.retryable===!0};if(typeof r.error=="string")return{code:/^[a-z][a-z0-9_]+$/.test(r.error)?r.error:t,message:typeof r.message=="string"?r.message:r.error,retryable:n===429||n>=500}}catch{}return{code:t,message:o,retryable:n===429||n>=500}}async function ko(){return z("/api/cli/capabilities")}async function L(e,n,t){let o=t?`?teamId=${encodeURIComponent(t)}`:"";return z(`/api/cli/tool-runs/${encodeURIComponent(e)}/${encodeURIComponent(n)}${o}`)}async function $(e,n){return z(`/api/cli/tools/${encodeURIComponent(e)}`,{body:n,method:"POST"})}async function Ca(e,n,t=120){let o=0;for(let r=0;r<t;r++){let i;try{i=await L(e,n),o=0}catch(a){if(a instanceof O&&a.retryable&&o<2){o+=1,await new Promise(s=>setTimeout(s,2e3));continue}throw a instanceof O?new O(`${a.message} Request ID: ${n}.`,a.statusCode,a.exitCode,a.errorCode,a.retryable):new O(`${a instanceof Error?a.message:"Unknown error"} Request ID: ${n}.`,0,5,"poll_failed",!0)}if(i.done){if(i.error)throw new O(`[${i.error.code??"operation_failed"}] ${i.error.message} Request ID: ${n}.`,500,1,i.error.code??"operation_failed",i.error.retryable);return i}await new Promise(a=>setTimeout(a,(i.nextPollAfterSeconds??2)*1e3))}throw new O(`[operation_timed_out] The background operation timed out. Request ID: ${n}.`,408,1,"operation_timed_out",!0)}function Ct(e){return e.error||e.status==="failed"||e.status==="errored"||e.status==="cancelled"?"failed":e.done||e.status==="completed"?"completed":e.status==="in_progress"?"processing":"pending"}function Ia(e){try{let t=new URL(e).pathname.split("/").pop()?.split(".").pop()?.toLowerCase();return t&&/^[a-z0-9]+$/.test(t)?t:void 0}catch{return}}function Ta(e){let n=e.toLowerCase().split(".").pop();return{pdf:"application/pdf",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",txt:"text/plain",md:"text/markdown",csv:"text/csv",json:"application/json",html:"text/html",css:"text/css",js:"application/javascript",ts:"text/x-typescript",py:"text/x-python"}[n||""]||"application/octet-stream"}async function Ra(e){let n=j();if(!ce())throw new O(`Not authenticated. Run '${g.commands[0]} login' or set ${g.apiKeyEnvVar} environment variable.`,401,2);let t=await ge(),o=wa(e),r=To(e),i=Ta(e),a=await fetch(`${n}/api/cli/files/upload`,{method:"POST",headers:{"Content-Type":"application/json",...t},body:JSON.stringify({fileMetadata:{name:r,type:i,size:o.size}})});if(!a.ok){let I=await a.text();throw new O(I||"Failed to get upload URL",a.status,1)}let s=await a.json(),d=ba(e),u=new FormData;for(let[I,f]of Object.entries(s.fields||{}))u.append(I,f);let p=new Blob([d],{type:i});u.append("file",p,r);let w=await fetch(s.url,{method:"POST",body:u});if(!w.ok)throw new O("Failed to upload file to storage",w.status,1);return{id:pn(),name:r,url:s.fileUrl,size:o.size,type:i,selected:!0}}async function Ao(e,n){let t=[];for(let o=0;o<e.length;o++){let r=e[o],i=To(r);n?.(o,e.length,i);let a=await Ra(r);t.push(a)}return n?.(e.length,e.length,""),t}async function $o(e){let n={};for(let[o,r]of Object.entries(e))r!==void 0&&(n[o]=r);let t=n.designBrandReference??n.brandId??n.brandingId;return t!==void 0&&(n.designBrandReference=t,delete n.brandId,delete n.brandingId),$("createSlides",{...n,approvalReceipt:"cli:create"})}async function Eo(e,n=20){let t=new URLSearchParams;return t.set("limit",String(n)),e&&t.set("teamId",e),(await z(`/api/cli/presentations?${t}`)).presentations}async function Se(e){return z(`/api/cli/presentation/${encodeURIComponent(e)}`)}async function Oo(e){await z(`/api/cli/presentation/${encodeURIComponent(e)}`,{method:"DELETE"})}async function Po(e,n={}){let t=j();if(!ce())throw new O(`Not authenticated. Run '${g.commands[0]} login' or set ${g.apiKeyEnvVar} environment variable.`,401,2);let o=await ge(),r=await fetch(`${t}/api/presentations/export`,{method:"POST",headers:{"Content-Type":"application/json",...o},body:JSON.stringify({presentationId:e,options:{includeImages:n.includeImages??!0,includeBranding:n.includeBranding??!0,downloadExternalImages:n.includeExternal??!0}})});if(!r.ok)throw new O(await r.text(),r.status,r.status===404?3:1);return r.arrayBuffer()}async function No(e,n,t={}){let o=j();if(!ce())throw new O(`Not authenticated. Run '${g.commands[0]} login' or set ${g.apiKeyEnvVar} environment variable.`,401,2);let r=await ge(),i=new FormData,a=new Blob([e],{type:"application/zip"});i.append("file",a,n),i.append("options",JSON.stringify({dryRun:t.dryRun??!1,remapIds:!0}));let s=await fetch(`${o}/api/presentations/import`,{method:"POST",headers:r,body:i}),d=await s.json();if(!s.ok)throw new O(d.errors?.[0]?.message??"Import failed",s.status,1);return d}async function gn(){return z("/api/cli/branding")}async function Do(e,n=25){let t=new URLSearchParams;return t.set("limit",String(n)),e&&t.set("search",e),z(`/api/cli/templates?${t}`)}async function Lo(e){return z(`/api/branding/${e}`)}async function Uo(e,n,t){return $("extractBranding",{approvalReceipt:t,teamId:n,url:e})}async function we(){return z("/api/cli/whoami")}async function Fo(){return z("/api/cli/features")}async function _o(e,n,t={}){let o=j();if(!ce())throw new O(`Not authenticated. Run '${g.commands[0]} login' or set ${g.apiKeyEnvVar} environment variable.`,401,2);let r=await ge(),i=await fetch(`${o}/api/presentations/${e}/generate-blog`,{method:"POST",headers:{"Content-Type":"application/json",...r},body:JSON.stringify({documentCreatedAt:n,targetWordCount:t.targetWordCount??300,tone:t.tone??"professional",language:t.language??"en",targetAudience:t.targetAudience??"General Audience",blogFormat:t.blogFormat??"narrative",customInstructions:t.customInstructions??"",includeImages:t.includeImages??!0,includeTableOfContents:t.includeTableOfContents??!1})});if(!i.ok)throw new O(await i.text(),i.status,i.status===404?3:1);return i}async function ka(e){let n=new URLSearchParams;e&&n.set("teamId",e);let t=n.toString();return z(`/api/cli/limits${t?`?${t}`:""}`)}async function Vo(e,n,t){let o=await ka(t);if(!o.canGenerate[e]){let r=o.remaining[e]??0,i=o.limits[e]??0;throw i===0?new O(`The "${e}" mode is not available on your ${o.planName} plan. Available modes: ${o.availableModes.join(", ")||"none"}`,403,2):new O(`You have reached your ${e} generation limit for this billing cycle (${o.usage[e]??0}/${i} used). Try a different mode: ${o.availableModes.join(", ")||"none available"}`,403,4)}if(o.maxSlidesPerPresentation!==-1&&n>o.maxSlidesPerPresentation)throw new O(`Maximum ${o.maxSlidesPerPresentation} slides allowed on your ${o.planName} plan (requested: ${n}). Try a different mode: ${o.availableModes.join(", ")||"none available"}`,403,6);return o}function Mo(e){return e.replace(/[\u2014\u2013]/g,"-").replace(/[\u201C\u201D]/g,'"').replace(/[\u2018\u2019]/g,"'").replace(/\u2026/g,"...").replace(/\u00A0/g," ").replace(/[\u2010-\u2015]/g,"-").replace(/[\u2032\u2033]/g,"'")}async function It(e){let n=await $("generateSpeech",{approvalReceipt:"cli:tts-generate",...e,text:Mo(e.text)}),t=await Ca("generateSpeech",n.runId),o=t.entity?.url;if(!o)throw new O(`Speech completed without an audio URL. Request ID: ${n.runId}.`,500);let r;try{r=await fetch(o)}catch(p){throw new O(`${p instanceof Error?p.message:"Failed to download speech audio"} Request ID: ${n.runId}.`,0,5,"download_failed",!0)}if(!r.ok)throw new O(`Failed to download speech audio. Request ID: ${n.runId}.`,r.status,5,"download_failed",r.status===429||r.status>=500);let i=t.output??{},a=e.options??{},s=pe(i.format)??Ia(o)??"mp3",d=Buffer.from(await r.arrayBuffer()),u=Aa(i.durationSec,i.duration,i.duration_s)??go(d,s);if(u===void 0)throw new O(`Speech completed without a measurable duration. Request ID: ${n.runId}.`,500,1,"invalid_audio_metadata");return{audioData:d,audioUrl:o,duration:u,cost:at(i.costUsd)??at(i.cost)??0,provider:pe(i.provider)??a.provider??"gemini",format:s,requestId:n.runId,voiceId:pe(i.voice_id)??pe(i.voiceId),voice:pe(i.voice),model:pe(i.model),speed:at(i.speed)??a.speed,language:pe(i.lang)??pe(i.language)??a.language,langApplied:Io(i.langApplied)??Io(i.lang_applied),timestamps:$a(i.timestamps),wordTimings:Ea(i.timestamps??i.timings)}}function Aa(...e){for(let n of e){let t=typeof n=="number"?n:typeof n=="string"&&n.trim()?Number(n):Number.NaN;if(Number.isFinite(t)&&t>0)return t}}function $a(e){if(!e||typeof e!="object"||Array.isArray(e))return;let n=e,t=n.characters,o=n.characterStartTimesSeconds??n.character_start_times_seconds,r=n.characterEndTimesSeconds??n.character_end_times_seconds;if(!(!Array.isArray(t)||!Array.isArray(o)||!Array.isArray(r))&&!(t.length===0||t.length!==o.length||t.length!==r.length||!t.every(i=>typeof i=="string")||!o.every(i=>typeof i=="number"&&Number.isFinite(i))||!r.every(i=>typeof i=="number"&&Number.isFinite(i))))return{characters:t,characterStartTimesSeconds:o,characterEndTimesSeconds:r}}function Ea(e){if(!Array.isArray(e))return;let n=e.flatMap(t=>{if(!t||typeof t!="object"||Array.isArray(t))return[];let o=t,r=pe(o.text)??pe(o.word),i=at(o.start),a=at(o.end);return r&&i!==void 0&&a!==void 0&&a>=i?[{text:r,start:i,end:a}]:[]});return n.length>0?n:void 0}function pe(e){return typeof e=="string"&&e.trim()?e.trim():void 0}function at(e){return typeof e=="number"&&Number.isFinite(e)?e:void 0}function Io(e){return typeof e=="boolean"?e:void 0}async function jo(e){let n=j();if(!ce())throw new O(`Not authenticated. Run '${g.commands[0]} login' or set ${g.apiKeyEnvVar} environment variable.`,401,2);let t=await ge(),o=pn(),r={...e,texts:e.texts.map(s=>({...s,text:Mo(s.text)}))},i;try{i=await fetch(`${n}/api/cli/tts/batch`,{method:"POST",headers:{"Content-Type":"application/json",[Ro]:o,...t},body:JSON.stringify(r)})}catch(s){throw new O(`Network error: ${s instanceof Error?s.message:"Unknown error"}`,0,5)}if(!i.ok){let s=await i.text().catch(()=>"Unknown error"),d;try{let u=JSON.parse(s);d=u.error||u.message||s}catch{d=s}throw new O(d,i.status,i.status===401?2:1)}let a=await i.json();return a.results=a.results.map(s=>({...s,audioData:Buffer.from(s.audioData,"base64")})),a}async function qo(e){let n=e?`/api/cli/tts?provider=${e}`:"/api/cli/tts";return z(n)}async function Tt(e){return{requestId:(await $("generateMusic",{...e,approvalReceipt:"cli:music-generate"})).runId,status:"pending"}}async function st(e){let n=await L("generateMusic",e);return{requestId:e,status:Ct(n),audioUrl:n.entity?.url,error:n.error?.message}}async function Bo(e){return{requestId:(await $("mixAudio",{...e,approvalReceipt:"cli:mix-create"})).runId,status:"pending"}}async function fn(e){let n=await L("mixAudio",e);return{requestId:e,status:Ct(n),outputUrl:n.entity?.url,error:n.error?.message}}async function Rt(e){return z("/api/cli/images/search",{method:"POST",body:e})}async function Go(e){return z("/api/cli/images/generate",{method:"POST",body:e})}async function hn(e){return z("/api/cli/videos/search",{method:"POST",body:e})}async function K(e,n=60,t=2e3){let o=0;for(let r=0;r<n;r++){let i;try{i=await e(),o=0}catch(a){if(a instanceof O&&a.retryable&&o<2){o+=1,await new Promise(s=>setTimeout(s,t));continue}throw a}if(i.status==="completed"||i.status==="failed")return i;await new Promise(a=>setTimeout(a,t))}throw new O("Operation timed out",408,1)}async function Wo(e,n){let t=await $("scrape",{teamId:n,url:e});return{data:{content:t.content,cost:t.totalCost??0,metadata:{description:"",format:"markdown",tokenUsage:Math.ceil(t.content.length/4)},title:t.title??"",url:t.url},success:!0}}async function Ho(e){let n=await $("generateSfx",{...e,approvalReceipt:"cli:sfx-generate"});return{id:n.runId,requestId:n.runId,status:"pending"}}async function yn(e){let n=await L("generateSfx",e);return{id:n.entity?.id??e,requestId:e,status:Ct(n),audioUrl:n.entity?.url,error:n.error?.message}}async function Jo(e){return $("listPresenterOptions",{...e?{voiceLanguage:e}:{}})}async function zo(e){return{requestId:(await $("generateAvatarVideo",{...e,approvalReceipt:"cli:avatar-generate"})).runId,status:"pending"}}async function bn(e){let n=await L("generateAvatarVideo",e);return{durationSec:typeof n.output?.durationSec=="number"?n.output.durationSec:null,error:n.error?.message,requestId:e,status:Ct(n),videoUrl:n.entity?.url}}async function Xo(e){return $("lipsyncVideo",{...e,approvalReceipt:"cli:video-lipsync"})}async function Yo(){return(await $("listTranslationLanguages",{})).languages}async function Ko(e){return $("translateVideo",{...e,approvalReceipt:"cli:video-translate"})}async function wn(e){return $("generateVideoPlan",{...e,approvalReceipt:"cli:video-plan"})}async function Qo(e){return $("createVideo",{...e,approvalReceipt:"cli:video-create"})}async function Zo(e){return z("/api/cli/video/plan",{body:e,method:"POST"})}import F from"chalk";import vn from"cli-table3";function S(e,n="human"){n!=="quiet"&&n!=="json"&&console.log(F.green("\u2713"),e)}function c(e,n="human"){if(n!=="quiet"){if(n==="json"){console.error(JSON.stringify({error:e}));return}console.error(F.red("\u2717"),e)}}function _(e,n="human"){n!=="quiet"&&n!=="json"&&console.warn(F.yellow("\u26A0"),e)}function m(e,n="human"){n!=="quiet"&&n!=="json"&&console.log(F.blue("\u2139"),e)}function De(e,n="en"){return e?`${j()}/${n}/view/presentations/${e}`:"N/A"}function er(e,n={}){let{showLinks:t=!1,language:o="en"}=n,r=(s,d)=>s.length>d?s.slice(0,d-1)+"\u2026":s,i=s=>{try{return new Date(s).toLocaleString("en-US",{month:"short",day:"numeric",hour:"numeric",minute:"2-digit",hour12:!0}).replace(" at ",", ")}catch{return"-"}};if(t){let s=new vn({head:[F.cyan("Slug"),F.cyan("Title"),F.cyan("Slides"),F.cyan("Created"),F.cyan("URL")]});for(let d of e)s.push([r(d.slug||d.id.slice(0,8),30),r(d.title||"Untitled",22),String(d.numberOfSlides||"-"),i(d.createdAt),De(d.slug,o)]);return s.toString()}let a=new vn({head:[F.cyan("Slug"),F.cyan("Title"),F.cyan("Slides"),F.cyan("Mode"),F.cyan("Created")],colWidths:[32,28,8,11,18]});for(let s of e)a.push([s.slug||s.id.slice(0,8),s.title||"Untitled",String(s.numberOfSlides||"-"),s.mode||"-",i(s.createdAt)]);return a.toString()}function tr(e){return e.map(n=>n.slug||n.id).join(`
4
+ `)}function nr(e){let n=[...e].sort((r,i)=>{if(r.isDefault&&!i.isDefault)return-1;if(!r.isDefault&&i.isDefault)return 1;let a=r.createdAt?new Date(r.createdAt).getTime():0;return(i.createdAt?new Date(i.createdAt).getTime():0)-a}),t=r=>{if(!r)return"-";try{return new URL(r).href}catch{return r.startsWith("http")?r:`https://${r}`}},o=new vn({head:[F.cyan("Name"),F.cyan("Source"),F.cyan("Color"),F.cyan("Logo"),F.cyan("Default"),F.cyan("ID")]});for(let r of n){let i=r.primaryColor?`${F.bgHex(r.primaryColor)(" ")} ${r.primaryColor}`:"-";o.push([r.name,t(r.sourceUrl),i,r.logoUrl?F.green("\u2713"):F.gray("\u2717"),r.isDefault?F.green("\u2605"):"",r.id])}return o.toString()}function xn(e){try{return new Date(e).toLocaleString()}catch{return e}}function fe(e){console.log(),console.log(F.bold(e)),console.log(F.gray("\u2500".repeat(e.length)))}function R(e,n){console.log(` ${F.gray(e+":")} ${n??"-"}`)}function Oa(e){return JSON.stringify(e,null,2)}function x(e){console.log(Oa(e))}var or=new Pa("capabilities").description("List callable capabilities and their parity state").option("-f, --format <format>","Output format: human, json, quiet","human").action(async e=>{try{let n=await ko();if(e.format==="json"){x(n);return}for(let t of n.capabilities){if(e.format==="quiet"){console.log(t.name);continue}console.log(`${t.name} ${t.state} ${t.milestone}`)}}catch(n){c(n instanceof Error?n.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}});import{mkdirSync as Ua,writeFileSync as Fa}from"fs";import{dirname as sr,join as _a}from"path";import{Command as Ce}from"commander";import ct from"chalk";import{input as Va,password as Ma,confirm as cr,select as ja}from"@inquirer/prompts";import At from"ora";import Na from"conf";var kt=new Na({projectName:"conceptcraft",configName:"feature-cache"}),Da=3600*1e3,La=1440*60*1e3;function rr(e){let n=0;for(let t=0;t<e.length;t++){let o=e.charCodeAt(t);n=(n<<5)-n+o,n=n&n}return n.toString(16)}function ir(){if(!Ne())return null;let e=kt.get("featureFlags");if(!e)return null;let n=rr(be());if(e.apiKeyHash&&e.apiKeyHash!==n)return ke(),null;let t=Date.now()-e.fetchedAt;return t>La?null:(t>Da&&Sn(),e.flags)}function Sn(){Re().catch(()=>{})}async function Re(){let e=await Fo(),n=be();return kt.set("featureFlags",{flags:e,fetchedAt:Date.now(),apiKeyHash:n?rr(n):void 0}),e}function ke(){kt.delete("featureFlags")}function ar(){return kt.path}var dr=new Ce("config").description("Manage CLI configuration").addCommand(new Ce("init").description("Initialize configuration interactively").action(async()=>{console.log(),console.log(ct.bold(`${g.displayName} CLI Configuration`)),console.log(ct.gray("\u2500".repeat(35))),console.log();try{let e=await Ma({message:"Enter your API key:",mask:"*",validate:o=>!o||o.trim().length===0?"API key is required":mn(o.trim())?!0:"Invalid API key format. Keys should start with 'cc_slides_' or 'mcp_'"});if(ln(e.trim()),await cr({message:`Use a custom API URL? (default: ${g.apiUrl.replace("https://","")})`,default:!1})){let o=await Va({message:"Enter API URL:",default:j(),validate:r=>{try{return new URL(r),!0}catch{return"Invalid URL format"}}});un(o)}console.log();let t=At("Verifying API key...").start();try{let o=await we();if(t.succeed("API key verified!"),console.log(),m(`Logged in as: ${o.user.email}`),o.teams.length===0)_("No teams found for this user.");else if(o.teams.length===1){let r=o.teams[0];Pe(r.id),m(`Team: ${r.name} (${r.planName})`)}else{console.log(),m(`You have access to ${o.teams.length} teams.`);let r=await ja({message:"Select your default team:",choices:o.teams.map(a=>({name:`${a.name} (${a.planName}) - ${a.role}${a.isCurrent?" [current]":""}`,value:a.id})),default:o.currentTeam?.id});Pe(r);let i=o.teams.find(a=>a.id===r);S(`Selected team: ${i?.name}`)}try{await Re()}catch{}}catch(o){t.fail("Failed to verify API key"),_(`Could not verify API key: ${o instanceof Error?o.message:String(o)}`),_(`You may need to set the team ID manually: ${g.commands[0]} config set team-id <id>`)}console.log(),S("Configuration saved!"),m(`Config file: ${it()}`),console.log()}catch(e){if(e.name==="ExitPromptError"){console.log(),m("Configuration cancelled.");return}throw e}})).addCommand(new Ce("show").description("Show current configuration").option("--verify","Verify API key and show team details").action(async e=>{let n=yo();if(fe("Current Configuration"),console.log(),R("API Key",Co()??ct.red("Not set")),R("API URL",n.apiUrl),R("Default Team ID",n.defaultTeamId??ct.gray("Not set")),console.log(),R("Config file",it()),e.verify&&n.apiKey){console.log();let t=At("Verifying...").start();try{let o=await we();t.succeed("Verified"),console.log(),R("User",o.user.email),o.currentTeam&&R("Current Team",`${o.currentTeam.name} (${o.currentTeam.planName})`),o.teams.length>1&&R("Total Teams",String(o.teams.length))}catch(o){t.fail("Verification failed"),_(o instanceof Error?o.message:String(o))}}console.log()})).addCommand(new Ce("set").description("Set a configuration value").argument("<key>","Configuration key (api-key, api-url, team-id)").argument("<value>","Value to set").action(async(e,n)=>{switch(e){case"api-key":mn(n)||(c("Invalid API key format. Keys should start with 'cc_slides_' or 'mcp_'"),process.exit(6)),ln(n),ke(),S("API key updated"),Re().catch(()=>{});break;case"api-url":try{new URL(n),un(n),S(`API URL set to: ${n}`)}catch{c("Invalid URL format"),process.exit(6)}break;case"team-id":Pe(n),S(`Default team ID set to: ${n}`);break;default:c(`Unknown config key: ${e}`),console.log(ct.gray("Valid keys: api-key, api-url, team-id")),process.exit(6)}})).addCommand(new Ce("clear").description("Clear all configuration").action(async()=>{try{await cr({message:"Are you sure you want to clear all configuration?",default:!1})?(yt(),ke(),S("Configuration cleared")):m("Cancelled")}catch{m("Cancelled")}})).addCommand(new Ce("refresh").description("Refresh cached feature flags").action(async()=>{let e=At("Refreshing feature flags...").start();try{await Re(),e.succeed("Feature flags refreshed"),m(`Run '${g.commands[0]} --help' to see updated commands`)}catch(n){e.fail("Failed to refresh"),c(n instanceof Error?n.message:String(n)),process.exit(1)}})).addCommand(new Ce("path").description("Show configuration file path").option("--cache","Show feature cache file path").action(e=>{e.cache?console.log(ar()):console.log(it())})).addCommand(new Ce("pull").description("Pull your account settings (memory, brand, prefs) into a local config.toml").action(async()=>{let e=At("Pulling settings...").start();try{let n=await ge(),t=await fetch(`${j()}/api/cli/settings`,{headers:n});if(!t.ok)throw new Error(`Request failed (HTTP ${t.status})`);let o=await t.text(),r=_a(sr(it()),"settings.toml");Ua(sr(r),{recursive:!0}),Fa(r,o,"utf8"),e.succeed("Settings pulled"),m(`Written to ${r}`)}catch(n){e.fail("Failed to pull settings"),c(n instanceof Error?n.message:String(n)),process.exit(1)}}));import{Command as qa}from"commander";import{confirm as Ba}from"@inquirer/prompts";var lr=new qa("delete").description("Delete a presentation").argument("<slug>","Presentation slug (e.g., my-presentation-v1-abc123)").option("-f, --force","Skip confirmation prompt").option("-q, --quiet","Suppress output").action(async(e,n)=>{if(await P(),!n.force)try{if(!await Ba({message:`Are you sure you want to delete presentation "${e}"?`,default:!1})){n.quiet||_("Deletion cancelled");return}}catch{n.quiet||_("Deletion cancelled");return}try{await Oo(e),n.quiet||S(`Presentation "${e}" deleted`)}catch(t){c(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}});import{Command as Le}from"commander";import mr from"chalk";import Ga from"ora";import{createParser as Zu}from"eventsource-parser";import tm from"chalk";import om from"ora";async function ur(e,n={}){let t=e.body?.getReader();if(!t)throw new Error("Response body is not readable");let o=new TextDecoder,r="",i=!1;for(;!i;){let a=await t.read();if(i=a.done,a.value){let s=o.decode(a.value,{stream:!0});r+=s,n.quiet||process.stdout.write(s)}}return n.quiet||console.log(),r}function Wa(){return new Le("blog").description("Generate a blog post from a presentation").argument("<slug>","Presentation slug").option("--words <count>","Target word count (50-2000)","300").option("--tone <tone>","Writing tone (professional, casual, educational)","professional").option("--audience <text>","Target audience description").option("-f, --format <format>","Output format (human, json, markdown)","human").option("--instructions <text>","Custom instructions for the blog").option("--no-images","Exclude image references").option("--toc","Include table of contents").action(async(e,n)=>{await P();let t=parseInt(n.words,10);(isNaN(t)||t<50||t>2e3)&&(c("Word count must be between 50 and 2000"),process.exit(6));let o=["professional","casual","educational"];o.includes(n.tone)||(c(`Invalid tone. Valid options: ${o.join(", ")}`),process.exit(6));let r=Ga("Fetching presentation...").start();try{let i=await Se(e);r.text="Generating blog post...";let a=await _o(i.id,i.documentCreatedAt||i.createdAt,{targetWordCount:t,tone:n.tone,targetAudience:n.audience??"General Audience",customInstructions:n.instructions??"",includeImages:!n.noImages,includeTableOfContents:n.toc??!1}),s=await ur(a,{quiet:!0});r.succeed("Blog generated"),n.format==="json"?console.log(JSON.stringify({presentationId:e,title:i.title,wordCount:t,tone:n.tone,content:s},null,2)):n.format==="markdown"?console.log(s):(console.log(),console.log(mr.bold(`Blog: ${i.title}`)),console.log(mr.gray("\u2500".repeat(40))),console.log(),console.log(s),console.log())}catch(i){r.fail("Generation failed"),c(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}})}function Ha(){return new Le("tweets").description("Generate tweets from a presentation").argument("<slug>","Presentation slug").option("--count <n>","Number of tweets to generate","5").option("-f, --format <format>","Output format (human, json)","human").action(async(e,n)=>{await P(),m("Tweet generation coming soon.")})}function Ja(){return new Le("linkedin").description("Generate a LinkedIn carousel from a presentation").argument("<slug>","Presentation slug").option("-f, --format <format>","Output format (human, json)","human").action(async e=>{await P(),m("LinkedIn carousel generation coming soon.")})}function za(){return new Le("questions").description("Generate questions for a presentation").argument("<slug>","Presentation slug").option("--count <n>","Number of questions","10").option("-f, --format <format>","Output format (human, json)","human").action(async(e,n)=>{await P(),m("Question generation coming soon.")})}function Xa(){return new Le("cheatsheet").description("Generate a presenter cheat sheet").argument("<slug>","Presentation slug").option("--mode <mode>","Cheat sheet mode (qa-prep, talking-points)","qa-prep").option("-f, --format <format>","Output format (human, json, markdown)","human").action(async(e,n)=>{await P(),m("Cheat sheet generation coming soon.")})}function pr(){let e=new Le("derive").description("Generate derivative content from a presentation"),n=ir();return n&&(n.deckToBlog&&e.addCommand(Wa()),n.deckToTweets&&e.addCommand(Ha()),n.linkedInCarousel&&e.addCommand(Ja()),n.redTeamQuestions&&e.addCommand(za()),n.presenterCheatSheet&&e.addCommand(Xa())),e}import{Command as Ya}from"commander";import{writeFile as Ka}from"fs/promises";import{resolve as gr}from"path";import Qa from"ora";var fr=new Ya("export").description("Export a presentation to ZIP").argument("<slug>","Presentation slug (e.g., my-presentation-v1-abc123)").option("-o, --output <path>","Output file path").option("--include-images","Include images (default: true)",!0).option("--include-branding","Include branding (default: true)",!0).option("--no-external","Skip external image downloads").action(async(e,n)=>{await P();let t=Qa("Fetching presentation...").start();try{let o=await Se(e),r=o.title||e,i=o.id,a=e.replace(/[^a-z0-9-]/gi,"_").toLowerCase().substring(0,50),s=new Date().toISOString().split("T")[0],d=`${a}_${s}.zip`,u=n.output?gr(n.output):gr(process.cwd(),d);t.text=`Exporting "${r}"...`;let p=await Po(i,{includeImages:n.includeImages,includeBranding:n.includeBranding,includeExternal:!n.noExternal});t.text="Saving file...",await Ka(u,Buffer.from(p)),t.succeed("Export complete!"),console.log(),m(`File saved: ${u}`),m(`Size: ${Za(p.byteLength)}`),console.log()}catch(o){t.fail("Export failed"),c(o instanceof Error?o.message:String(o)),process.exit(o.exitCode??1)}});function Za(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}import{Command as es}from"commander";import Cn from"chalk";var hr=new es("ideas").description("Generate presentation topic ideas").option("--context <text>","Custom context for idea generation").option("--count <n>","Number of ideas to generate","5").option("-f, --format <format>","Output format (human, json)","human").action(async e=>{await P(),m("Idea generation is available in the web dashboard."),console.log(),console.log(Cn.gray("The CLI will support idea generation in a future release.")),console.log(),console.log("For now, try these approaches:"),console.log(Cn.gray("` 1. Visit the ${brand.displayName} dashboard and use the idea generator`")),console.log(Cn.gray(" 2. Create a presentation with a broad topic and refine it")),console.log()});import{Command as ts}from"commander";import{readFile as ns}from"fs/promises";import{resolve as os,basename as rs}from"path";import is from"ora";var yr=new ts("import").description("Import a presentation from ZIP (admin only)").argument("<file>","Path to ZIP file");yr._hidden=!0;var br=yr.option("--dry-run","Validate without importing").option("--overwrite","Overwrite existing presentations").option("--remap-ids","Generate new IDs (default: true)",!0).action(async(e,n)=>{await P();try{(await we()).user.role!=="admin"&&(c("This command is only available to administrators"),process.exit(2))}catch{c("Failed to verify permissions"),process.exit(2)}let t=os(e),o=rs(t);o.endsWith(".zip")||(c("File must be a ZIP archive"),process.exit(6));let r=is("Reading file...").start();try{let i=await ns(t);n.dryRun?r.text="Validating...":r.text="Importing presentation...";let a=await No(i,o,{dryRun:n.dryRun});if(a.success){if(n.dryRun)r.succeed("Validation passed!"),console.log(),m("The file is valid and can be imported."),a.statistics&&(console.log(),R("Slides",String(a.statistics.slidesImported)),R("Images",String(a.statistics.imagesUploaded)));else if(r.succeed("Import complete!"),console.log(),R("Presentation ID",a.presentationId??"N/A"),R("Document ID",a.documentId??"N/A"),a.statistics&&(R("Slides imported",String(a.statistics.slidesImported)),R("Images uploaded",String(a.statistics.imagesUploaded)),R("Time",`${a.statistics.totalTimeMs}ms`)),a.presentationId){let s=j();R("View URL",`${s}/p/${a.presentationId}`)}if(a.warnings&&a.warnings.length>0){console.log();for(let s of a.warnings)_(s)}console.log()}else{if(r.fail("Import failed"),console.log(),a.errors)for(let s of a.errors)c(`${s.type}: ${s.message}`);process.exit(1)}}catch(i){r.fail("Import failed"),i.code==="ENOENT"&&(c(`File not found: ${t}`),process.exit(3)),c(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}});import{Command as as}from"commander";var wr=new as("list").description("List presentations").option("-n, --limit <count>","Number of results to return","20").option("-f, --format <format>","Output format (table, json, ids)","table").option("--sort <field>","Sort by field (created, updated, title)").option("--team-id <id>","Team ID (uses default if not specified)").option("-d, --detail","Show detailed output including URLs").option("-l, --language <lang>","Language for URLs","en").action(async e=>{await P();let n=parseInt(e.limit,10);(isNaN(n)||n<1)&&(c("Invalid limit value"),process.exit(6));let t=e.teamId??ht();t||(c("`Team ID required. Set a default with '${brand.commands[0]} config set team-id <id>' or use --team-id`"),process.exit(6));try{let o=await Eo(t,n);if(o.length===0){e.format==="json"?console.log(JSON.stringify([])):e.format!=="ids"&&m("No presentations found");return}switch(e.sort&&o.sort((r,i)=>{switch(e.sort){case"created":return new Date(i.createdAt).getTime()-new Date(r.createdAt).getTime();case"title":return(r.title||"").localeCompare(i.title||"");default:return 0}}),e.format){case"json":console.log(JSON.stringify(o,null,2));break;case"ids":console.log(tr(o));break;default:console.log(er(o,{showLinks:e.detail,language:e.language}));break}}catch(o){c(o instanceof Error?o.message:String(o)),process.exit(o.exitCode??1)}});import{Command as ss}from"commander";import vr from"chalk";import xr from"ora";import Sr from"http";import{randomBytes as Cr,createHash as cs}from"crypto";import ds from"open";var ls=`${g.displayName} CLI`,us=8765,ms=8775;function ps(){return Cr(32).toString("base64url")}function gs(e){return cs("sha256").update(e).digest("base64url")}function fs(){return Cr(16).toString("hex")}async function hs(e,n){for(let t=e;t<=n;t++)try{return await new Promise((o,r)=>{let i=Sr.createServer();i.listen(t,()=>{i.close(()=>o())}),i.on("error",r)}),t}catch{continue}throw new Error(`No available port found between ${e} and ${n}`)}async function ys(e){let n=await fetch(`${e}/.well-known/oauth-authorization-server`);if(!n.ok)throw new Error(`Failed to fetch OAuth metadata: ${n.status}`);return n.json()}async function bs(e,n){let t=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_name:ls,redirect_uris:[n],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"none",scope:"presentations:read presentations:write"})});if(!t.ok){let o=await t.text();throw new Error(`Client registration failed: ${o}`)}return t.json()}async function ws(e,n,t,o,r){let i=new URLSearchParams({grant_type:"authorization_code",code:n,redirect_uri:o,client_id:r,code_verifier:t}),a=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()});if(!a.ok){let s=await a.text();throw new Error(`Token exchange failed: ${s}`)}return a.json()}function vs(e,n){return new Promise((t,o)=>{let r,i=!1,a=()=>{i||(i=!0,clearTimeout(r),process.off("SIGINT",s),process.off("SIGTERM",s),d.close())},s=()=>{a(),o(new Error("Login cancelled"))},d=Sr.createServer((u,p)=>{let w=new URL(u.url||"",`http://localhost:${e}`);if(w.pathname!=="/callback"){p.writeHead(404),p.end("Not found");return}let I=w.searchParams.get("code"),f=w.searchParams.get("state"),T=w.searchParams.get("error"),b=w.searchParams.get("error_description");if(p.writeHead(200,{"Content-Type":"text/html"}),T){p.end(`
5
5
  <!DOCTYPE html>
6
6
  <html>
7
7
  <head><title>Login Failed</title></head>
@@ -11,7 +11,7 @@ var h={id:"mindframes",name:"mindframes",displayName:"Mindframes",description:"C
11
11
  <p>You can close this window.</p>
12
12
  </body>
13
13
  </html>
14
- `),a(),o(new Error(b||T));return}if(!I||!g){f.end(`
14
+ `),a(),o(new Error(b||T));return}if(!I||!f){p.end(`
15
15
  <!DOCTYPE html>
16
16
  <html>
17
17
  <head><title>Login Failed</title></head>
@@ -21,7 +21,7 @@ var h={id:"mindframes",name:"mindframes",displayName:"Mindframes",description:"C
21
21
  <p>You can close this window.</p>
22
22
  </body>
23
23
  </html>
24
- `),a(),o(new Error("Missing authorization code or state"));return}if(g!==n){f.end(`
24
+ `),a(),o(new Error("Missing authorization code or state"));return}if(f!==n){p.end(`
25
25
  <!DOCTYPE html>
26
26
  <html>
27
27
  <head><title>Login Failed</title></head>
@@ -31,7 +31,7 @@ var h={id:"mindframes",name:"mindframes",displayName:"Mindframes",description:"C
31
31
  <p>You can close this window.</p>
32
32
  </body>
33
33
  </html>
34
- `),a(),o(new Error("State mismatch"));return}f.end(`
34
+ `),a(),o(new Error("State mismatch"));return}p.end(`
35
35
  <!DOCTYPE html>
36
36
  <html>
37
37
  <head><title>Login Successful</title></head>
@@ -40,24 +40,24 @@ var h={id:"mindframes",name:"mindframes",displayName:"Mindframes",description:"C
40
40
  <p>You can close this window and return to the terminal.</p>
41
41
  </body>
42
42
  </html>
43
- `),a(),e({code:I,state:g})});l.listen(t),process.once("SIGINT",s),process.once("SIGTERM",s),r=setTimeout(()=>{a(),o(new Error("Login timed out - no callback received within 5 minutes"))},300*1e3)})}async function Va(t,n){let e=await fetch(`${t}/api/cli/whoami`,{headers:{Authorization:`Bearer ${n}`}});if(!e.ok)throw new Error(`Failed to fetch user info: ${e.status}`);return e.json()}async function ja(t){let n=j(),e=ar("Discovering OAuth server...").start();try{let o=await Fa(n);e.succeed("Connecting to "+n);let r=await La(Ea,Oa),i=`http://localhost:${r}/callback`;console.log("Redirect URI: "+i),console.log("Authorization endpoint: "+o.authorization_endpoint),console.log("Token endpoint: "+o.token_endpoint),console.log("Registration endpoint: "+o.registration_endpoint);let a=ft(),s=ht();if(!a){let x=await Ua(o.registration_endpoint,i);a=x.client_id,s=x.client_secret,lo(a,s)}let l=Pa(),d=Na(l),f=Da(),v=new URLSearchParams({client_id:a,redirect_uri:i,response_type:"code",scope:"presentations:read presentations:write",state:f,code_challenge:d,code_challenge_method:"S256"}),I=`${o.authorization_endpoint}?${v}`;console.log("Authorization URL: "+I),t.browser?(m("Opening browser..."),await Aa(I)):(console.log(ir.bold("Open this URL in your browser:")),console.log(ir.cyan(I)));let g=Ma(r,f),{code:T}=await g;e=ar("Completing login...").start();let b=await _a(o.token_endpoint,T,l,i,a);pt(b.access_token,b.refresh_token,b.expires_in);let y=await Va(n,b.access_token);e.succeed("Logged in!"),console.log(),k("Logged in as",y.user.email),y.currentTeam&&(Ee(y.currentTeam.id),k("Team",`${y.currentTeam.name} (${y.currentTeam.planName})`));try{await Ie()}catch{}console.log(),C("You're all set!"),console.log()}catch(o){throw e.fail("Login failed"),c(o instanceof Error?o.message:String(o)),o}}var lr=new ka("login").description(`Authenticate with ${p.displayName} (opens browser)`).option("--no-browser","Print URL instead of opening browser").action(async t=>{console.log(),Ce()&&(_("You are already logged in."),m(`Run '${p.commands[0]} logout' to log out first, or continue to re-authenticate.`),console.log());try{await ja(t),process.exit(0)}catch{process.exit(1)}});import{Command as qa}from"commander";import{confirm as Ba}from"@inquirer/prompts";var dr=new qa("logout").description("Log out and clear authentication").option("--all","Clear all config including API key").action(async t=>{console.log();let n=Ce(),e=Oe();if(!n&&!e){_("You are not logged in."),console.log();return}if(t.all)try{await Ba({message:"Clear all configuration including API key?",default:!1})?(mt(),Te(),C("All configuration cleared.")):m("Cancelled.")}catch{m("Cancelled.")}else gt(),Te(),C("Logged out successfully."),e&&m("Note: Your API key is still configured. Use --all to clear everything.");console.log()});import{homedir as As}from"os";import{join as $s}from"path";import se from"chalk";import{Command as Es}from"commander";import{spawn as Ga}from"child_process";import{existsSync as Wa,readdirSync as Ha}from"fs";import{homedir as pr}from"os";import{delimiter as ur}from"path";import{query as Ja}from"@anthropic-ai/claude-agent-sdk";function oe(t){if(t===void 0)return null;if(typeof t=="string")return t.length>12e3?`${t.slice(0,12e3)}\u2026`:t;try{let n=JSON.stringify(t);return n.length<=12e3?t:{preview:`${n.slice(0,12e3)}\u2026`,truncated:!0}}catch{return String(t).slice(0,12e3)}}function It(t){let n=typeof t=="string"?t:String(t??"");return n.length>12e3?`${n.slice(0,12e3)}\u2026`:n}function re(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}function D(t){return typeof t=="string"?t:""}function mr(t,n){let e=t.replace(/[/.]/g,"-");return`${pr()}/.claude/projects/${e}/${n}.jsonl`}function za(t){try{return Ha(`${t}/.nvm/versions/node`).map(n=>`${t}/.nvm/versions/node/${n}/bin`).sort().reverse()}catch{return[]}}function Tt(){let t=pr(),n=[`${t}/.local/bin`,`${t}/.claude/local`,`${t}/.bun/bin`,`${t}/bin`,"/opt/homebrew/bin","/usr/local/bin",...za(t)],o=(process.env.PATH??"").split(ur);for(let r of n)o.includes(r)||o.push(r);return o.join(ur)}async function kt(t){let n=t??"claude";return new Promise(e=>{let o=Ga(n,["--version"],{env:{...process.env,PATH:Tt()},stdio:["ignore","pipe","ignore"]}),r="";o.stdout.on("data",i=>{r+=i.toString("utf8")}),o.on("error",()=>e(null)),o.on("close",i=>{if(i!==0)return e(null);let a=r.trim().split(`
44
- `)[0]??"";e(a?{bin:n,version:a}:null)})})}var Xa=new Set(["","default","best"]);function yn(t){let n=t.filter(i=>i.text.trim());if(n.length===0)return"";let e=n[n.length-1],o=n.slice(0,-1);return o.length===0?e.text:`<conversation-history>
43
+ `),a(),t({code:I,state:f})});d.listen(e),process.once("SIGINT",s),process.once("SIGTERM",s),r=setTimeout(()=>{a(),o(new Error("Login timed out - no callback received within 5 minutes"))},300*1e3)})}async function xs(e,n){let t=await fetch(`${e}/api/cli/whoami`,{headers:{Authorization:`Bearer ${n}`}});if(!t.ok)throw new Error(`Failed to fetch user info: ${t.status}`);return t.json()}async function Ss(e){let n=j(),t=xr("Discovering OAuth server...").start();try{let o=await ys(n);t.succeed("Connecting to "+n);let r=await hs(us,ms),i=`http://localhost:${r}/callback`;console.log("Redirect URI: "+i),console.log("Authorization endpoint: "+o.authorization_endpoint),console.log("Token endpoint: "+o.token_endpoint),console.log("Registration endpoint: "+o.registration_endpoint);let a=vt(),s=xt();if(!a){let v=await bs(o.registration_endpoint,i);a=v.client_id,s=v.client_secret,xo(a,s)}let d=ps(),u=gs(d),p=fs(),w=new URLSearchParams({client_id:a,redirect_uri:i,response_type:"code",scope:"presentations:read presentations:write",state:p,code_challenge:u,code_challenge_method:"S256"}),I=`${o.authorization_endpoint}?${w}`;console.log("Authorization URL: "+I),e.browser?(m("Opening browser..."),await ds(I)):(console.log(vr.bold("Open this URL in your browser:")),console.log(vr.cyan(I)));let f=vs(r,p),{code:T}=await f;t=xr("Completing login...").start();let b=await ws(o.token_endpoint,T,d,i,a);bt(b.access_token,b.refresh_token,b.expires_in);let y=await xs(n,b.access_token);t.succeed("Logged in!"),console.log(),R("Logged in as",y.user.email),y.currentTeam&&(Pe(y.currentTeam.id),R("Team",`${y.currentTeam.name} (${y.currentTeam.planName})`));try{await Re()}catch{}console.log(),S("You're all set!"),console.log()}catch(o){throw t.fail("Login failed"),c(o instanceof Error?o.message:String(o)),o}}var Ir=new ss("login").description(`Authenticate with ${g.displayName} (opens browser)`).option("--no-browser","Print URL instead of opening browser").action(async e=>{console.log(),Te()&&(_("You are already logged in."),m(`Run '${g.commands[0]} logout' to log out first, or continue to re-authenticate.`),console.log());try{await Ss(e),process.exit(0)}catch{process.exit(1)}});import{Command as Cs}from"commander";import{confirm as Is}from"@inquirer/prompts";var Tr=new Cs("logout").description("Log out and clear authentication").option("--all","Clear all config including API key").action(async e=>{console.log();let n=Te(),t=Ne();if(!n&&!t){_("You are not logged in."),console.log();return}if(e.all)try{await Is({message:"Clear all configuration including API key?",default:!1})?(yt(),ke(),S("All configuration cleared.")):m("Cancelled.")}catch{m("Cancelled.")}else wt(),ke(),S("Logged out successfully."),t&&m("Note: Your API key is still configured. Use --all to clear everything.");console.log()});import{homedir as dc}from"os";import{join as lc}from"path";import de from"chalk";import{Command as uc}from"commander";import{spawn as Ts}from"child_process";import{existsSync as Rs,readdirSync as ks}from"fs";import{homedir as Ar}from"os";import{delimiter as Rr}from"path";import{query as As}from"@anthropic-ai/claude-agent-sdk";function ie(e){if(e===void 0)return null;if(typeof e=="string")return e.length>12e3?`${e.slice(0,12e3)}\u2026`:e;try{let n=JSON.stringify(e);return n.length<=12e3?e:{preview:`${n.slice(0,12e3)}\u2026`,truncated:!0}}catch{return String(e).slice(0,12e3)}}function $t(e){let n=typeof e=="string"?e:String(e??"");return n.length>12e3?`${n.slice(0,12e3)}\u2026`:n}function ae(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function U(e){return typeof e=="string"?e:""}function kr(e,n){let t=e.replace(/[/.]/g,"-");return`${Ar()}/.claude/projects/${t}/${n}.jsonl`}function $s(e){try{return ks(`${e}/.nvm/versions/node`).map(n=>`${e}/.nvm/versions/node/${n}/bin`).sort().reverse()}catch{return[]}}function Et(){let e=Ar(),n=[`${e}/.local/bin`,`${e}/.claude/local`,`${e}/.bun/bin`,`${e}/bin`,"/opt/homebrew/bin","/usr/local/bin",...$s(e)],o=(process.env.PATH??"").split(Rr);for(let r of n)o.includes(r)||o.push(r);return o.join(Rr)}async function Ot(e){let n=e??"claude";return new Promise(t=>{let o=Ts(n,["--version"],{env:{...process.env,PATH:Et()},stdio:["ignore","pipe","ignore"]}),r="";o.stdout.on("data",i=>{r+=i.toString("utf8")}),o.on("error",()=>t(null)),o.on("close",i=>{if(i!==0)return t(null);let a=r.trim().split(`
44
+ `)[0]??"";t(a?{bin:n,version:a}:null)})})}var Es=new Set(["","default","best"]);function In(e){let n=e.filter(i=>i.text.trim());if(n.length===0)return"";let t=n[n.length-1],o=n.slice(0,-1);return o.length===0?t.text:`<conversation-history>
45
45
  ${o.map(i=>`${i.role==="assistant"?"Assistant":"User"}: ${i.text}`).join(`
46
46
 
47
47
  `)}
48
48
  </conversation-history>
49
49
 
50
- ${e.text}`}function bn(t,n){return n?t.messages.filter(o=>o.text.trim()).at(-1)?.text??"":yn(t.messages)}function Ya({abortController:t,input:n,resumeSessionId:e,workspace:o}){let r=(n.modelId??"").trim(),i=n.thinking??null,a={abortController:t,allowedTools:["WebSearch","WebFetch"],cwd:o,env:{...process.env,PATH:Tt()},includePartialMessages:!0,maxTurns:16,permissionMode:"dontAsk"};return Xa.has(r)||(a.model=r),n.effort&&(a.effort=n.effort),i&&i!=="disabled"&&(a.thinking={display:"summarized",type:i==="enabled"?"enabled":"adaptive"}),e?a.resume=e:n.system?.trim()&&(a.systemPrompt=n.system),a}async function gr(t){let n=bn(t.input,t.resumeSessionId);if(!n)throw new Error("Chat turn has no user text to send.");let e=new AbortController,o=()=>e.abort();t.signal?.addEventListener("abort",o,{once:!0});let r=null,i=null,a=null,s=null,l=null,d=0,f=new Set;try{let g=Ja({prompt:n,options:Ya({abortController:e,input:t.input,resumeSessionId:t.resumeSessionId,workspace:t.workspace})});for await(let T of g){let b=T;if(b.type==="system"&&b.subtype==="init"){typeof b.session_id=="string"&&(i=b.session_id,t.onEvent({eventType:"chat.session",payload:{sessionId:i,sessionPath:mr(t.workspace,i)}})),typeof b.model=="string"&&(r=b.model,t.onEvent({eventType:"chat.model",payload:{modelId:b.model}}));continue}if(b.type==="stream_event"){let y=b.event;if(y?.type!=="content_block_delta")continue;let x=y.delta;if(!x)continue;x.type==="text_delta"&&typeof x.text=="string"?(d+=x.text.length,t.onEvent({eventType:"chat.text.delta",payload:{text:x.text}})):x.type==="thinking_delta"&&typeof x.thinking=="string"&&t.onEvent({eventType:"chat.reasoning.delta",payload:{text:x.thinking}});continue}if(b.type==="assistant"){let y=re(b.message),x=Array.isArray(y.content)?y.content:[];for(let E of x){let A=re(E);if(A.type!=="tool_use")continue;let P=D(A.id),w=D(A.name);!P||!w||f.has(P)||(f.add(P),t.onEvent({eventType:"chat.tool.started",payload:{input:oe(A.input),toolCallId:P,toolName:w}}))}continue}if(b.type==="user"){let y=re(b.message),x=Array.isArray(y.content)?y.content:[];for(let E of x){let A=re(E);if(A.type!=="tool_result")continue;let P=D(A.tool_use_id);P&&t.onEvent({eventType:"chat.tool.completed",payload:{...A.is_error===!0?{errorText:typeof A.content=="string"?It(A.content):"Claude tool call failed."}:{},output:oe(A.content),toolCallId:P}})}continue}b.type==="result"&&(typeof b.result=="string"&&(s=b.result),b.usage&&typeof b.usage=="object"&&(a=b.usage),typeof b.session_id=="string"&&(i=b.session_id),(b.is_error===!0||b.subtype!=="success")&&(l=typeof b.result=="string"&&b.result||`Claude turn failed (${String(b.subtype)}).`,t.onEvent({eventType:"chat.error",message:l,payload:{message:l}})))}}finally{t.signal?.removeEventListener("abort",o)}if(t.signal?.aborted)throw new Error("Chat turn cancelled.");if(l)throw new Error(l);let v=s??"";d===0&&v&&t.onEvent({eventType:"chat.text.delta",payload:{text:v}});let I=i?mr(t.workspace,i):null;return{modelId:r,sessionId:i,sessionPath:I&&Wa(I)?I:null,text:v,usage:a}}import{spawn as Ka}from"child_process";import{closeSync as Qa,fstatSync as Za,openSync as es,readdirSync as ts,readSync as ns}from"fs";import{homedir as os}from"os";import{join as fr}from"path";import{Codex as rs}from"@openai/codex-sdk";var is=["/Applications/Codex.app/Contents/Resources/codex"];async function Rt(t){let n=t?[t]:["codex",...is];for(let e of n){let o=await as(e);if(o)return{bin:e,version:o}}return null}function as(t){return new Promise(n=>{let e=Ka(t,["--version"],{env:{...process.env,PATH:Tt()},stdio:["ignore","pipe","ignore"]}),o="";e.stdout.on("data",r=>{o+=r.toString("utf8")}),e.on("error",()=>n(null)),e.on("close",r=>{if(r!==0)return n(null);let i=o.trim().split(`
51
- `)[0]??"";n(i||null)})})}var ss=24,cs=4*1024*1024,br=new Set(["custom_tool_call","custom_tool_call_output","dynamic_tool_call","function_call"]);function ls(t){let n;try{n=ds(t).split(`
52
- `)}catch{return[]}let e=new Set,o=new Map,r=null;for(let i of n){if(!i.trim())continue;let a;try{a=JSON.parse(i)}catch{continue}let s=re(a.payload);if(a.type==="response_item"&&s.type==="custom_tool_call"){let l=D(s.call_id),d=D(s.input);l&&s.name==="exec"&&/\btools\.web__run\s*\(/.test(d)&&(e.add(l),r=l);continue}if(a.type==="event_msg"&&s.type==="web_search_end"){let l=D(s.call_id);if(!l||!r)continue;let d=D(s.query),f=re(s.action),I={action:{...f,...d&&!D(f.query)?{query:d}:{}},query:d,sources:hr(s.results),toolCallId:l},g=o.get(r)??[];g.push(I),o.set(r,g);continue}if(a.type==="response_item"&&s.type==="custom_tool_call_output"){let l=D(s.call_id);if(!l||!e.has(l))continue;let d=hr(s.output);for(let f of o.get(l)??[])f.sources.length===0&&(f.sources=d);r===l&&(r=null)}}return Array.from(o.values()).flat()}function ds(t){let n=es(t,"r");try{let e=Za(n).size,o=Math.max(0,e-cs),r=Buffer.alloc(e-o);ns(n,r,0,r.length,o);let i=r.toString("utf8");if(o===0)return i;let a=i.indexOf(`
53
- `);return a===-1?"":i.slice(a+1)}finally{Qa(n)}}function hr(t){let e=wn(t).match(/https?:\/\/[^\s<>"'()[\]{}\\]+/g)??[],o=new Set,r=[];for(let i of e){let a=i.replace(/[.,;:!?]+$/,"");try{let s=new URL(a);if(s.protocol!=="http:"&&s.protocol!=="https:"||o.has(s.href))continue;if(o.add(s.href),r.push({type:"url",url:s.href}),r.length>=ss)break}catch{}}return r}function wn(t){return typeof t=="string"?t:Array.isArray(t)?t.map(wn).join(`
54
- `):t&&typeof t=="object"?Object.values(t).map(wn).join(`
55
- `):""}function xn(t,n){let e=re(t),o=D(e.type),r=D(e.id),i=D(e.call_id)||D(e.tool_call_id),a=br.has(o)?i||r:r||i;if(!a)return null;if(o==="command_execution"){let s=D(e.command),l=D(e.status),d={exitCode:typeof e.exit_code=="number"?e.exit_code:null,output:oe(e.aggregated_output)};return{...n&&l==="failed"?{errorText:It(e.aggregated_output)||"Command failed."}:{},input:{command:s},...n?{output:d}:{},toolCallId:a,toolName:"Bash"}}if(o==="mcp_tool_call"){let s=re(e.error);return{...n&&D(s.message)?{errorText:D(s.message)}:{},input:oe(e.arguments),...n?{output:oe(e.result??{status:e.status??"completed"})}:{},toolCallId:a,toolName:D(e.tool)||D(e.name)||"Codex tool"}}if(o==="web_search"){let s=D(e.query);return{input:{query:s},...n?{output:{query:s}}:{},toolCallId:a,toolName:"web_search"}}if(o==="file_change"){let s=D(e.status);return{...n&&s==="failed"?{errorText:"Codex could not apply the file changes."}:{},input:{changes:oe(e.changes)},...n?{output:{changes:oe(e.changes),status:s}}:{},toolCallId:a,toolName:"ApplyPatch"}}if(o==="custom_tool_call_output")return{input:{},...n?{output:oe(e.output)}:{},toolCallId:a,toolName:"Codex tool"};if(o==="custom_tool_call"||o==="dynamic_tool_call"||o==="function_call"){let s=D(e.name)||D(e.tool)||"Codex tool",l=e.input??e.arguments??{};return{input:s==="exec"&&typeof l=="string"?{command:l}:oe(l),...n?{output:oe(e.output??e.result??{status:e.status??"completed"})}:{},toolCallId:a,toolName:s}}return null}function vn(t,n=fr(os(),".codex","sessions")){try{let o=ts(n,{recursive:!0}).find(r=>typeof r=="string"&&r.endsWith(`${t}.jsonl`));return o?fr(n,o):null}catch{return null}}function us(t,n){return n?bn(t,n):yn(t.messages)}function ms(t,n,e=p.codexSelfConnectorAppId){let o=n.system?.trim(),r={...o?{developer_instructions:o}:{},...e?{apps:{[e]:{enabled:!1}}}:{}};return{codexPathOverride:t,...Object.keys(r).length>0?{config:r}:{}}}var ps=new Set(["minimal","low","medium","high","xhigh"]);function gs(t,n){let e={networkAccessEnabled:!0,sandboxMode:"workspace-write",skipGitRepoCheck:!0,webSearchEnabled:!0,workingDirectory:n},o=(t.modelId??"").trim();return o&&o!=="default"&&(e.model=o),t.effort&&ps.has(t.effort)&&(e.modelReasoningEffort=t.effort),e}async function xr(t){let n=us(t.input,t.resumeSessionId);if(!n)throw new Error("Chat turn has no user text to send.");let e=new rs(ms(t.bin,t.input)),o=gs(t.input,t.workspace),r=t.resumeSessionId?e.resumeThread(t.resumeSessionId,o):e.startThread(o),i=t.resumeSessionId??null,a=null,s=null,l=[],d=new Set,f=new Set,v=null,I=b=>{v??=vn(b,t.sessionsRoot),t.onEvent({eventType:"chat.session",payload:{sessionId:b,sessionPath:v}})},g=b=>{i&&(v??=vn(i,t.sessionsRoot));let y=v?ls(v):[],x=D(re(b.input).query),E=yr(x),A=y.find(P=>!d.has(P.toolCallId)&&yr(P.query)===E)??y.find(P=>!d.has(P.toolCallId));A&&d.add(A.toolCallId),t.onEvent({eventType:"chat.tool.completed",payload:{...b,output:A?{action:A.action,query:A.query,sources:A.sources}:{action:{query:x,type:"search"},sourceListUnavailable:!0,sources:[]}}})},{events:T}=await r.runStreamed(n);i&&I(i);for await(let b of T){if(t.signal?.aborted)throw await T.return?.(void 0),new Error("Chat turn cancelled.");let y=b;if(y.type==="thread.started"){typeof y.thread_id=="string"&&(i=y.thread_id,I(y.thread_id));continue}if(y.type==="item.started"){let x=xn(y.item,!1);if(x){t.onEvent({eventType:"chat.tool.started",payload:x});let E=re(y.item);if(br.has(D(E.type))&&D(E.status)==="completed"){let A=xn(E,!0);A&&(f.add(A.toolCallId),t.onEvent({eventType:"chat.tool.completed",payload:A}))}}continue}if(y.type==="item.completed"){let x=y.item;if(!x)continue;if(x.type==="agent_message"&&typeof x.text=="string")l.push(x.text),t.onEvent({eventType:"chat.text.delta",payload:{text:x.text}});else if(x.type==="reasoning"&&typeof x.text=="string")t.onEvent({eventType:"chat.reasoning.delta",payload:{text:x.text}});else{let E=xn(x,!0);E&&(x.type==="web_search"?g(E):x.type==="custom_tool_call"&&f.has(E.toolCallId)||t.onEvent({eventType:"chat.tool.completed",payload:E}))}continue}if(y.type==="turn.completed"){y.usage&&typeof y.usage=="object"&&(a=y.usage);continue}if(y.type==="turn.failed"){let x=y.error;s=typeof x?.message=="string"&&x.message||"Codex turn failed.",t.onEvent({eventType:"chat.error",message:s,payload:{message:s}})}}if(s)throw new Error(s);return i=r.id??i,i&&(v??=vn(i,t.sessionsRoot)),{modelId:t.input.modelId??null,sessionId:i,sessionPath:v,text:l.join(`
56
-
57
- `),usage:a}}function yr(t){return t.trim().replace(/\s+/g," ").toLocaleLowerCase()}import{randomUUID as xs}from"crypto";import{mkdir as vs}from"fs/promises";import{hostname as $t,platform as ws}from"os";import{join as Ss}from"path";var De=class extends Error{constructor(e,o,r=!1){super(e);this.statusCode=o;this.reRegister=r;this.name="RunnerApiError"}statusCode;reRegister};async function Le(t,n={}){let e=await de();n.body!==void 0&&(e["Content-Type"]="application/json");let o=new AbortController,r=setTimeout(()=>o.abort(),n.timeoutMs??3e4),i=()=>o.abort();n.signal?.addEventListener("abort",i,{once:!0});try{let a=await fetch(`${j()}${t}`,{body:n.body!==void 0?JSON.stringify(n.body):void 0,headers:e,method:n.method??"GET",signal:o.signal}),s=await a.text(),l={};try{l=s?JSON.parse(s):{}}catch{l={error:s.slice(0,300)}}if(!a.ok)throw new De(typeof l.error=="string"?l.error:`Runner API returned ${a.status}`,a.status,l.reRegister===!0);return l}finally{clearTimeout(r),n.signal?.removeEventListener("abort",i)}}async function vr(t){await Le("/api/runner/register",{body:t,method:"POST",timeoutMs:15e3})}async function wr(t,n){return(await Le(`/api/runner/work?runnerId=${encodeURIComponent(t)}`,{signal:n,timeoutMs:28e3})).job??null}async function Sr(t){await Le("/api/runner/heartbeat",{body:{runnerId:t},method:"POST",timeoutMs:1e4})}async function Cr(t,n){return{cancelRequested:(await Le(`/api/runner/jobs/${encodeURIComponent(t)}/events`,{body:{events:n},method:"POST",timeoutMs:15e3})).cancelRequested===!0}}async function Sn(t,n,e){await Le(`/api/runner/jobs/${encodeURIComponent(t)}/complete`,{body:{result:e,runnerId:n},method:"POST",timeoutMs:15e3})}async function At(t,n,e,o=!0){await Le(`/api/runner/jobs/${encodeURIComponent(t)}/fail`,{body:{message:e,retryable:o,runnerId:n},method:"POST",timeoutMs:15e3})}import{mkdirSync as fs,readFileSync as hs,writeFileSync as Ir}from"fs";import{dirname as ys,join as bs}from"path";function Cn(t){return bs(t,"sessions.json")}function In(t){try{let n=hs(Cn(t),"utf8"),e=JSON.parse(n);if(e&&typeof e=="object"&&!Array.isArray(e))return e}catch{}return{}}function Tr(t,n,e){return n?In(t)[n]?.[e]??null:null}function kr(t,n,e,o){if(!(!n||!o))try{let r=Cn(t);fs(ys(r),{recursive:!0});let i=In(t);i[n]={...i[n],[e]:o},Ir(r,`${JSON.stringify(i,null," ")}
58
- `,"utf8")}catch{}}function Rr(t,n,e){if(n)try{let o=In(t);if(!o[n])return;delete o[n][e],Ir(Cn(t),`${JSON.stringify(o,null," ")}
59
- `,"utf8")}catch{}}var Cs=300,Is=3e4;async function Ar(t){let[n,e]=await Promise.all([kt(t.claudeBin),Rt(t.codexBin)]);if(!n&&!e)throw new Error("Neither Claude Code nor Codex was found on this machine. Install one and log in, then retry.");n?t.log(`Claude Code detected: ${n.version} (${n.bin})`):t.log("Claude Code not found \u2014 Claude turns will be declined."),e?t.log(`Codex detected: ${e.version} (${e.bin})`):t.log("Codex not found \u2014 Codex turns will be declined.");let o=[...n?["claude-code"]:[],...e?["codex"]:[]],r=`${$t().split(".")[0]}-${xs().slice(0,8)}`,i=()=>vr({capabilities:["chat_turn","proof"],claudeCodeVersion:n?.version??null,cliVersion:t.version,codexVersion:e?.version??null,hostname:$t(),platform:ws(),runnerId:r,runtimes:o});for(await i(),t.log(`Registered as ${r} (runtimes: ${o.join(", ")}). Waiting for work\u2026`);!t.signal?.aborted;){let a=null;try{a=await wr(r,t.signal)}catch(s){if(t.signal?.aborted)break;if(s instanceof De&&s.reRegister){t.log("Server asked for re-registration."),await i().catch(()=>{});continue}t.log(`Work poll failed (${s instanceof Error?s.message:"unknown"}); retrying\u2026`),await Rs(t.pollBackoffMs??5e3,t.signal);continue}if(!a){if(t.once)continue;continue}if(t.log(`Claimed ${a.jobType} job ${a.runId}.`),await Ts({claude:n,codex:e,job:a,options:t,runnerId:r}),t.once)break}}async function Ts({claude:t,codex:n,job:e,options:o,runnerId:r}){let i=new AbortController,a=()=>i.abort();o.signal?.addEventListener("abort",a,{once:!0});let s=setInterval(()=>{Sr(r).catch(()=>{})},Is),l=[],d=!1,f=async()=>{if(d||l.length===0)return;d=!0;let g=l.splice(0,100);try{let{cancelRequested:T}=await Cr(e.runId,g);T&&i.abort()}catch(T){T instanceof De&&T.statusCode===409&&i.abort()}finally{d=!1}},v=setInterval(()=>{f()},Cs),I=g=>{l.push(g)};try{if(e.jobType==="runner.proof"){let g=typeof e.input.message=="string"?e.input.message:"proof";I({eventType:"proof.echo",payload:{message:g}}),await Tn(f,l),await Sn(e.runId,r,{echo:g}),o.log(`Proof job ${e.runId} completed.`);return}if(e.jobType==="runner.chat_turn"){let g=e.input.runtime==="codex"?"codex":"claude-code",T=g==="codex"?n&&{detection:n,run:xr}:t&&{detection:t,run:gr};if(!T){await At(e.runId,r,g==="codex"?"Codex is not available on this machine. Install the Codex app or CLI and log in, then retry.":"Claude Code is not available on this machine. Install it and log in, then retry.",!1);return}let b=typeof e.input.chatId=="string"&&e.input.chatId?e.input.chatId:null,y=Ss(o.workspaceRoot,"chats",b??e.runId);await vs(y,{recursive:!0});let x=ks(e.input),E=w=>I({eventType:w.eventType,message:w.message??null,payload:w.eventType==="chat.session"?{host:$t(),runtime:g,runtimeVersion:T.detection.version,...w.payload??{}}:w.payload??{}}),A=Tr(o.workspaceRoot,b,g),P;try{P=await T.run({bin:T.detection.bin,input:x,onEvent:E,resumeSessionId:A,signal:i.signal,workspace:y})}catch(w){if(!A||i.signal.aborted)throw w;o.log(`Resume of ${g} session failed (${w instanceof Error?w.message:"unknown"}); retrying fresh.`),Rr(o.workspaceRoot,b,g),P=await T.run({bin:T.detection.bin,input:x,onEvent:E,resumeSessionId:null,signal:i.signal,workspace:y})}kr(o.workspaceRoot,b,g,P.sessionId),I({eventType:"chat.session",payload:{host:$t(),runtime:g,runtimeVersion:T.detection.version,sessionId:P.sessionId,sessionPath:P.sessionPath}}),await Tn(f,l),await Sn(e.runId,r,{modelId:P.modelId,runtime:g,runtimeVersion:T.detection.version,sessionId:P.sessionId,sessionPath:P.sessionPath,text:P.text,usage:P.usage??{}}),o.log(`Chat turn ${e.runId} (${g}) completed.`);return}await At(e.runId,r,`This runner does not support ${e.jobType} jobs. Update the desktop app / CLI.`,!1)}catch(g){let T=g instanceof Error?g.message:"Local runner job crashed.";o.log(`Job ${e.runId} failed: ${T}`),await Tn(f,l).catch(()=>{}),await At(e.runId,r,T).catch(()=>{})}finally{clearInterval(v),clearInterval(s),o.signal?.removeEventListener("abort",a)}}function ks(t){let n=Array.isArray(t.messages)?t.messages.map(e=>{if(!e||typeof e!="object")return null;let o=e;return{role:typeof o.role=="string"?o.role:"user",text:typeof o.text=="string"?o.text:""}}).filter(e=>!!e):[];return{effort:typeof t.effort=="string"?t.effort:null,messages:n,modelId:typeof t.modelId=="string"?t.modelId:null,system:typeof t.system=="string"?t.system:null,thinking:typeof t.thinking=="string"?t.thinking:null}}async function Tn(t,n){for(;n.length>0;)await t(),n.length>0&&await new Promise(e=>setTimeout(e,25))}function Rs(t,n){return t<=0||n?.aborted?Promise.resolve():new Promise(e=>{let o=setTimeout(r,t);function r(){clearTimeout(o),n?.removeEventListener("abort",r),e()}n?.addEventListener("abort",r,{once:!0})})}function Os(){return $s(As(),`.${p.commands[0]}-runner`,"runs")}var Et=new Es("runner").description("Run agent work locally with your own Claude Code / Codex login (desktop lane)");Et.command("status").description("Check local Claude Code / Codex detection and account auth").action(async()=>{let[t,n]=await Promise.all([kt(),Rt()]);if(console.log(t?se.green(`\u2713 Claude Code ${t.version}`):se.red("\u2717 Claude Code not found on PATH")),console.log(n?se.green(`\u2713 Codex ${n.version} (${n.bin})`):se.red("\u2717 Codex not found (PATH or Codex.app)")),!ae()){console.log(se.red(`\u2717 Not logged in. Run '${p.commands[0]} login' first.`)),process.exitCode=2;return}try{let e=await he();console.log(se.green(`\u2713 Logged in as ${e.user.email}`))}catch(e){console.log(se.red(`\u2717 Auth check failed: ${e instanceof Error?e.message:"unknown"}`)),process.exitCode=2}});Et.command("start").description("Start the local runner (register + wait for work)").option("--once","Execute a single job, then exit").option("--workspace <dir>","Workspace root for job scratch directories").option("--claude-bin <path>","Path to the claude binary").option("--codex-bin <path>","Path to the codex binary").action(async t=>{ae()||(console.error(se.red(`Not authenticated. Run '${p.commands[0]} login' first.`)),process.exit(2));let n=new AbortController,e=()=>{console.log(se.gray(`
60
- Stopping runner\u2026`)),n.abort()};process.on("SIGINT",e),process.on("SIGTERM",e);try{await Ar({claudeBin:t.claudeBin,codexBin:t.codexBin,log:o=>console.log(se.gray(`[runner] ${o}`)),once:t.once,signal:n.signal,version:"0.3.11",workspaceRoot:t.workspace??Os()})}catch(o){console.error(se.red(o instanceof Error?o.message:String(o))),process.exit(1)}});import{Command as Us}from"commander";import M from"chalk";function Ot(t){let{name:n,cmd:e}=t,o=n.toUpperCase().replace(/[^A-Z0-9]/g,"_");return`---
50
+ ${t.text}`}function Tn(e,n){return n?e.messages.filter(o=>o.text.trim()).at(-1)?.text??"":In(e.messages)}function Os({abortController:e,input:n,resumeSessionId:t,workspace:o}){let r=(n.modelId??"").trim(),i=n.thinking??null,a={abortController:e,allowedTools:["WebSearch","WebFetch"],cwd:o,env:{...process.env,PATH:Et()},includePartialMessages:!0,maxTurns:16,permissionMode:"dontAsk"};return Es.has(r)||(a.model=r),n.effort&&(a.effort=n.effort),i&&i!=="disabled"&&(a.thinking={display:"summarized",type:i==="enabled"?"enabled":"adaptive"}),t?a.resume=t:n.system?.trim()&&(a.systemPrompt=n.system),a}async function $r(e){let n=Tn(e.input,e.resumeSessionId);if(!n)throw new Error("Chat turn has no user text to send.");let t=new AbortController,o=()=>t.abort();e.signal?.addEventListener("abort",o,{once:!0});let r=null,i=null,a=null,s=null,d=null,u=0,p=new Set;try{let f=As({prompt:n,options:Os({abortController:t,input:e.input,resumeSessionId:e.resumeSessionId,workspace:e.workspace})});for await(let T of f){let b=T;if(b.type==="system"&&b.subtype==="init"){typeof b.session_id=="string"&&(i=b.session_id,e.onEvent({eventType:"chat.session",payload:{sessionId:i,sessionPath:kr(e.workspace,i)}})),typeof b.model=="string"&&(r=b.model,e.onEvent({eventType:"chat.model",payload:{modelId:b.model}}));continue}if(b.type==="stream_event"){let y=b.event;if(y?.type!=="content_block_delta")continue;let v=y.delta;if(!v)continue;v.type==="text_delta"&&typeof v.text=="string"?(u+=v.text.length,e.onEvent({eventType:"chat.text.delta",payload:{text:v.text}})):v.type==="thinking_delta"&&typeof v.thinking=="string"&&e.onEvent({eventType:"chat.reasoning.delta",payload:{text:v.thinking}});continue}if(b.type==="assistant"){let y=ae(b.message),v=Array.isArray(y.content)?y.content:[];for(let E of v){let A=ae(E);if(A.type!=="tool_use")continue;let N=U(A.id),C=U(A.name);!N||!C||p.has(N)||(p.add(N),e.onEvent({eventType:"chat.tool.started",payload:{input:ie(A.input),toolCallId:N,toolName:C}}))}continue}if(b.type==="user"){let y=ae(b.message),v=Array.isArray(y.content)?y.content:[];for(let E of v){let A=ae(E);if(A.type!=="tool_result")continue;let N=U(A.tool_use_id);N&&e.onEvent({eventType:"chat.tool.completed",payload:{...A.is_error===!0?{errorText:typeof A.content=="string"?$t(A.content):"Claude tool call failed."}:{},output:ie(A.content),toolCallId:N}})}continue}b.type==="result"&&(typeof b.result=="string"&&(s=b.result),b.usage&&typeof b.usage=="object"&&(a=b.usage),typeof b.session_id=="string"&&(i=b.session_id),(b.is_error===!0||b.subtype!=="success")&&(d=typeof b.result=="string"&&b.result||`Claude turn failed (${String(b.subtype)}).`,e.onEvent({eventType:"chat.error",message:d,payload:{message:d}})))}}finally{e.signal?.removeEventListener("abort",o)}if(e.signal?.aborted)throw new Error("Chat turn cancelled.");if(d)throw new Error(d);let w=s??"";u===0&&w&&e.onEvent({eventType:"chat.text.delta",payload:{text:w}});let I=i?kr(e.workspace,i):null;return{modelId:r,sessionId:i,sessionPath:I&&Rs(I)?I:null,text:w,usage:a}}import{spawn as Ps}from"child_process";import{closeSync as Ns,fstatSync as Ds,openSync as Ls,readdirSync as Us,readSync as Fs}from"fs";import{homedir as _s}from"os";import{join as Er}from"path";import{Codex as Vs}from"@openai/codex-sdk";var Ms=["/Applications/Codex.app/Contents/Resources/codex"];async function Pt(e){let n=e?[e]:["codex",...Ms];for(let t of n){let o=await js(t);if(o)return{bin:t,version:o}}return null}function js(e){return new Promise(n=>{let t=Ps(e,["--version"],{env:{...process.env,PATH:Et()},stdio:["ignore","pipe","ignore"]}),o="";t.stdout.on("data",r=>{o+=r.toString("utf8")}),t.on("error",()=>n(null)),t.on("close",r=>{if(r!==0)return n(null);let i=o.trim().split(`
51
+ `)[0]??"";n(i||null)})})}var qs=24,Bs=4*1024*1024,Nr=new Set(["custom_tool_call","custom_tool_call_output","dynamic_tool_call","function_call"]);function Gs(e){let n;try{n=Ws(e).split(`
52
+ `)}catch{return[]}let t=new Set,o=new Map,r=null;for(let i of n){if(!i.trim())continue;let a;try{a=JSON.parse(i)}catch{continue}let s=ae(a.payload);if(a.type==="response_item"&&s.type==="custom_tool_call"){let d=U(s.call_id),u=U(s.input);d&&s.name==="exec"&&/\btools\.web__run\s*\(/.test(u)&&(t.add(d),r=d);continue}if(a.type==="event_msg"&&s.type==="web_search_end"){let d=U(s.call_id);if(!d||!r)continue;let u=U(s.query),p=ae(s.action),I={action:{...p,...u&&!U(p.query)?{query:u}:{}},query:u,sources:Or(s.results),toolCallId:d},f=o.get(r)??[];f.push(I),o.set(r,f);continue}if(a.type==="response_item"&&s.type==="custom_tool_call_output"){let d=U(s.call_id);if(!d||!t.has(d))continue;let u=Or(s.output);for(let p of o.get(d)??[])p.sources.length===0&&(p.sources=u);r===d&&(r=null)}}return Array.from(o.values()).flat()}function Ws(e){let n=Ls(e,"r");try{let t=Ds(n).size,o=Math.max(0,t-Bs),r=Buffer.alloc(t-o);Fs(n,r,0,r.length,o);let i=r.toString("utf8");if(o===0)return i;let a=i.indexOf(`
53
+ `);return a===-1?"":i.slice(a+1)}finally{Ns(n)}}function Or(e){let t=An(e).match(/https?:\/\/[^\s<>"'()[\]{}\\]+/g)??[],o=new Set,r=[];for(let i of t){let a=i.replace(/[.,;:!?]+$/,"");try{let s=new URL(a);if(s.protocol!=="http:"&&s.protocol!=="https:"||o.has(s.href))continue;if(o.add(s.href),r.push({type:"url",url:s.href}),r.length>=qs)break}catch{}}return r}function An(e){return typeof e=="string"?e:Array.isArray(e)?e.map(An).join(`
54
+ `):e&&typeof e=="object"?Object.values(e).map(An).join(`
55
+ `):""}function Rn(e,n){let t=ae(e),o=U(t.type),r=U(t.id),i=U(t.call_id)||U(t.tool_call_id),a=Nr.has(o)?i||r:r||i;if(!a)return null;if(o==="command_execution"){let s=U(t.command),d=U(t.status),u={exitCode:typeof t.exit_code=="number"?t.exit_code:null,output:ie(t.aggregated_output)};return{...n&&d==="failed"?{errorText:$t(t.aggregated_output)||"Command failed."}:{},input:{command:s},...n?{output:u}:{},toolCallId:a,toolName:"Bash"}}if(o==="mcp_tool_call"){let s=ae(t.error);return{...n&&U(s.message)?{errorText:U(s.message)}:{},input:ie(t.arguments),...n?{output:ie(t.result??{status:t.status??"completed"})}:{},toolCallId:a,toolName:U(t.tool)||U(t.name)||"Codex tool"}}if(o==="web_search"){let s=U(t.query);return{input:{query:s},...n?{output:{query:s}}:{},toolCallId:a,toolName:"web_search"}}if(o==="file_change"){let s=U(t.status);return{...n&&s==="failed"?{errorText:"Codex could not apply the file changes."}:{},input:{changes:ie(t.changes)},...n?{output:{changes:ie(t.changes),status:s}}:{},toolCallId:a,toolName:"ApplyPatch"}}if(o==="custom_tool_call_output")return{input:{},...n?{output:ie(t.output)}:{},toolCallId:a,toolName:"Codex tool"};if(o==="custom_tool_call"||o==="dynamic_tool_call"||o==="function_call"){let s=U(t.name)||U(t.tool)||"Codex tool",d=t.input??t.arguments??{};return{input:s==="exec"&&typeof d=="string"?{command:d}:ie(d),...n?{output:ie(t.output??t.result??{status:t.status??"completed"})}:{},toolCallId:a,toolName:s}}return null}function kn(e,n=Er(_s(),".codex","sessions")){try{let o=Us(n,{recursive:!0}).find(r=>typeof r=="string"&&r.endsWith(`${e}.jsonl`));return o?Er(n,o):null}catch{return null}}function Hs(e,n){return n?Tn(e,n):In(e.messages)}function Js(e,n,t=g.codexSelfConnectorAppId){let o=n.system?.trim(),r={...o?{developer_instructions:o}:{},...t?{apps:{[t]:{enabled:!1}}}:{}};return{codexPathOverride:e,...Object.keys(r).length>0?{config:r}:{}}}var zs=new Set(["minimal","low","medium","high","xhigh"]);function Xs(e,n){let t={networkAccessEnabled:!0,sandboxMode:"workspace-write",skipGitRepoCheck:!0,webSearchEnabled:!0,workingDirectory:n},o=(e.modelId??"").trim();return o&&o!=="default"&&(t.model=o),e.effort&&zs.has(e.effort)&&(t.modelReasoningEffort=e.effort),t}async function Dr(e){let n=Hs(e.input,e.resumeSessionId);if(!n)throw new Error("Chat turn has no user text to send.");let t=new Vs(Js(e.bin,e.input)),o=Xs(e.input,e.workspace),r=e.resumeSessionId?t.resumeThread(e.resumeSessionId,o):t.startThread(o),i=e.resumeSessionId??null,a=null,s=null,d=[],u=new Set,p=new Set,w=null,I=b=>{w??=kn(b,e.sessionsRoot),e.onEvent({eventType:"chat.session",payload:{sessionId:b,sessionPath:w}})},f=b=>{i&&(w??=kn(i,e.sessionsRoot));let y=w?Gs(w):[],v=U(ae(b.input).query),E=Pr(v),A=y.find(N=>!u.has(N.toolCallId)&&Pr(N.query)===E)??y.find(N=>!u.has(N.toolCallId));A&&u.add(A.toolCallId),e.onEvent({eventType:"chat.tool.completed",payload:{...b,output:A?{action:A.action,query:A.query,sources:A.sources}:{action:{query:v,type:"search"},sourceListUnavailable:!0,sources:[]}}})},{events:T}=await r.runStreamed(n);i&&I(i);for await(let b of T){if(e.signal?.aborted)throw await T.return?.(void 0),new Error("Chat turn cancelled.");let y=b;if(y.type==="thread.started"){typeof y.thread_id=="string"&&(i=y.thread_id,I(y.thread_id));continue}if(y.type==="item.started"){let v=Rn(y.item,!1);if(v){e.onEvent({eventType:"chat.tool.started",payload:v});let E=ae(y.item);if(Nr.has(U(E.type))&&U(E.status)==="completed"){let A=Rn(E,!0);A&&(p.add(A.toolCallId),e.onEvent({eventType:"chat.tool.completed",payload:A}))}}continue}if(y.type==="item.completed"){let v=y.item;if(!v)continue;if(v.type==="agent_message"&&typeof v.text=="string")d.push(v.text),e.onEvent({eventType:"chat.text.delta",payload:{text:v.text}});else if(v.type==="reasoning"&&typeof v.text=="string")e.onEvent({eventType:"chat.reasoning.delta",payload:{text:v.text}});else{let E=Rn(v,!0);E&&(v.type==="web_search"?f(E):v.type==="custom_tool_call"&&p.has(E.toolCallId)||e.onEvent({eventType:"chat.tool.completed",payload:E}))}continue}if(y.type==="turn.completed"){y.usage&&typeof y.usage=="object"&&(a=y.usage);continue}if(y.type==="turn.failed"){let v=y.error;s=typeof v?.message=="string"&&v.message||"Codex turn failed.",e.onEvent({eventType:"chat.error",message:s,payload:{message:s}})}}if(s)throw new Error(s);return i=r.id??i,i&&(w??=kn(i,e.sessionsRoot)),{modelId:e.input.modelId??null,sessionId:i,sessionPath:w,text:d.join(`
56
+
57
+ `),usage:a}}function Pr(e){return e.trim().replace(/\s+/g," ").toLocaleLowerCase()}import{randomUUID as ec}from"crypto";import{mkdir as tc}from"fs/promises";import{hostname as Dt,platform as nc}from"os";import{join as oc}from"path";var Ue=class extends Error{constructor(t,o,r=!1){super(t);this.statusCode=o;this.reRegister=r;this.name="RunnerApiError"}statusCode;reRegister};async function Fe(e,n={}){let t=await ge();n.body!==void 0&&(t["Content-Type"]="application/json");let o=new AbortController,r=setTimeout(()=>o.abort(),n.timeoutMs??3e4),i=()=>o.abort();n.signal?.addEventListener("abort",i,{once:!0});try{let a=await fetch(`${j()}${e}`,{body:n.body!==void 0?JSON.stringify(n.body):void 0,headers:t,method:n.method??"GET",signal:o.signal}),s=await a.text(),d={};try{d=s?JSON.parse(s):{}}catch{d={error:s.slice(0,300)}}if(!a.ok)throw new Ue(typeof d.error=="string"?d.error:`Runner API returned ${a.status}`,a.status,d.reRegister===!0);return d}finally{clearTimeout(r),n.signal?.removeEventListener("abort",i)}}async function Lr(e){await Fe("/api/runner/register",{body:e,method:"POST",timeoutMs:15e3})}async function Ur(e,n){return(await Fe(`/api/runner/work?runnerId=${encodeURIComponent(e)}`,{signal:n,timeoutMs:28e3})).job??null}async function Fr(e){await Fe("/api/runner/heartbeat",{body:{runnerId:e},method:"POST",timeoutMs:1e4})}async function _r(e,n){return{cancelRequested:(await Fe(`/api/runner/jobs/${encodeURIComponent(e)}/events`,{body:{events:n},method:"POST",timeoutMs:15e3})).cancelRequested===!0}}async function $n(e,n,t){await Fe(`/api/runner/jobs/${encodeURIComponent(e)}/complete`,{body:{result:t,runnerId:n},method:"POST",timeoutMs:15e3})}async function Nt(e,n,t,o=!0){await Fe(`/api/runner/jobs/${encodeURIComponent(e)}/fail`,{body:{message:t,retryable:o,runnerId:n},method:"POST",timeoutMs:15e3})}import{mkdirSync as Ys,readFileSync as Ks,writeFileSync as Vr}from"fs";import{dirname as Qs,join as Zs}from"path";function En(e){return Zs(e,"sessions.json")}function On(e){try{let n=Ks(En(e),"utf8"),t=JSON.parse(n);if(t&&typeof t=="object"&&!Array.isArray(t))return t}catch{}return{}}function Mr(e,n,t){return n?On(e)[n]?.[t]??null:null}function jr(e,n,t,o){if(!(!n||!o))try{let r=En(e);Ys(Qs(r),{recursive:!0});let i=On(e);i[n]={...i[n],[t]:o},Vr(r,`${JSON.stringify(i,null," ")}
58
+ `,"utf8")}catch{}}function qr(e,n,t){if(n)try{let o=On(e);if(!o[n])return;delete o[n][t],Vr(En(e),`${JSON.stringify(o,null," ")}
59
+ `,"utf8")}catch{}}var rc=300,ic=3e4;async function Br(e){let[n,t]=await Promise.all([Ot(e.claudeBin),Pt(e.codexBin)]);if(!n&&!t)throw new Error("Neither Claude Code nor Codex was found on this machine. Install one and log in, then retry.");n?e.log(`Claude Code detected: ${n.version} (${n.bin})`):e.log("Claude Code not found \u2014 Claude turns will be declined."),t?e.log(`Codex detected: ${t.version} (${t.bin})`):e.log("Codex not found \u2014 Codex turns will be declined.");let o=[...n?["claude-code"]:[],...t?["codex"]:[]],r=`${Dt().split(".")[0]}-${ec().slice(0,8)}`,i=()=>Lr({capabilities:["chat_turn","proof"],claudeCodeVersion:n?.version??null,cliVersion:e.version,codexVersion:t?.version??null,hostname:Dt(),platform:nc(),runnerId:r,runtimes:o});for(await i(),e.log(`Registered as ${r} (runtimes: ${o.join(", ")}). Waiting for work\u2026`);!e.signal?.aborted;){let a=null;try{a=await Ur(r,e.signal)}catch(s){if(e.signal?.aborted)break;if(s instanceof Ue&&s.reRegister){e.log("Server asked for re-registration."),await i().catch(()=>{});continue}e.log(`Work poll failed (${s instanceof Error?s.message:"unknown"}); retrying\u2026`),await cc(e.pollBackoffMs??5e3,e.signal);continue}if(!a){if(e.once)continue;continue}if(e.log(`Claimed ${a.jobType} job ${a.runId}.`),await ac({claude:n,codex:t,job:a,options:e,runnerId:r}),e.once)break}}async function ac({claude:e,codex:n,job:t,options:o,runnerId:r}){let i=new AbortController,a=()=>i.abort();o.signal?.addEventListener("abort",a,{once:!0});let s=setInterval(()=>{Fr(r).catch(()=>{})},ic),d=[],u=!1,p=async()=>{if(u||d.length===0)return;u=!0;let f=d.splice(0,100);try{let{cancelRequested:T}=await _r(t.runId,f);T&&i.abort()}catch(T){T instanceof Ue&&T.statusCode===409&&i.abort()}finally{u=!1}},w=setInterval(()=>{p()},rc),I=f=>{d.push(f)};try{if(t.jobType==="runner.proof"){let f=typeof t.input.message=="string"?t.input.message:"proof";I({eventType:"proof.echo",payload:{message:f}}),await Pn(p,d),await $n(t.runId,r,{echo:f}),o.log(`Proof job ${t.runId} completed.`);return}if(t.jobType==="runner.chat_turn"){let f=t.input.runtime==="codex"?"codex":"claude-code",T=f==="codex"?n&&{detection:n,run:Dr}:e&&{detection:e,run:$r};if(!T){await Nt(t.runId,r,f==="codex"?"Codex is not available on this machine. Install the Codex app or CLI and log in, then retry.":"Claude Code is not available on this machine. Install it and log in, then retry.",!1);return}let b=typeof t.input.chatId=="string"&&t.input.chatId?t.input.chatId:null,y=oc(o.workspaceRoot,"chats",b??t.runId);await tc(y,{recursive:!0});let v=sc(t.input),E=C=>I({eventType:C.eventType,message:C.message??null,payload:C.eventType==="chat.session"?{host:Dt(),runtime:f,runtimeVersion:T.detection.version,...C.payload??{}}:C.payload??{}}),A=Mr(o.workspaceRoot,b,f),N;try{N=await T.run({bin:T.detection.bin,input:v,onEvent:E,resumeSessionId:A,signal:i.signal,workspace:y})}catch(C){if(!A||i.signal.aborted)throw C;o.log(`Resume of ${f} session failed (${C instanceof Error?C.message:"unknown"}); retrying fresh.`),qr(o.workspaceRoot,b,f),N=await T.run({bin:T.detection.bin,input:v,onEvent:E,resumeSessionId:null,signal:i.signal,workspace:y})}jr(o.workspaceRoot,b,f,N.sessionId),I({eventType:"chat.session",payload:{host:Dt(),runtime:f,runtimeVersion:T.detection.version,sessionId:N.sessionId,sessionPath:N.sessionPath}}),await Pn(p,d),await $n(t.runId,r,{modelId:N.modelId,runtime:f,runtimeVersion:T.detection.version,sessionId:N.sessionId,sessionPath:N.sessionPath,text:N.text,usage:N.usage??{}}),o.log(`Chat turn ${t.runId} (${f}) completed.`);return}await Nt(t.runId,r,`This runner does not support ${t.jobType} jobs. Update the desktop app / CLI.`,!1)}catch(f){let T=f instanceof Error?f.message:"Local runner job crashed.";o.log(`Job ${t.runId} failed: ${T}`),await Pn(p,d).catch(()=>{}),await Nt(t.runId,r,T).catch(()=>{})}finally{clearInterval(w),clearInterval(s),o.signal?.removeEventListener("abort",a)}}function sc(e){let n=Array.isArray(e.messages)?e.messages.map(t=>{if(!t||typeof t!="object")return null;let o=t;return{role:typeof o.role=="string"?o.role:"user",text:typeof o.text=="string"?o.text:""}}).filter(t=>!!t):[];return{effort:typeof e.effort=="string"?e.effort:null,messages:n,modelId:typeof e.modelId=="string"?e.modelId:null,system:typeof e.system=="string"?e.system:null,thinking:typeof e.thinking=="string"?e.thinking:null}}async function Pn(e,n){for(;n.length>0;)await e(),n.length>0&&await new Promise(t=>setTimeout(t,25))}function cc(e,n){return e<=0||n?.aborted?Promise.resolve():new Promise(t=>{let o=setTimeout(r,e);function r(){clearTimeout(o),n?.removeEventListener("abort",r),t()}n?.addEventListener("abort",r,{once:!0})})}function mc(){return lc(dc(),`.${g.commands[0]}-runner`,"runs")}var Lt=new uc("runner").description("Run agent work locally with your own Claude Code / Codex login (desktop lane)");Lt.command("status").description("Check local Claude Code / Codex detection and account auth").action(async()=>{let[e,n]=await Promise.all([Ot(),Pt()]);if(console.log(e?de.green(`\u2713 Claude Code ${e.version}`):de.red("\u2717 Claude Code not found on PATH")),console.log(n?de.green(`\u2713 Codex ${n.version} (${n.bin})`):de.red("\u2717 Codex not found (PATH or Codex.app)")),!ce()){console.log(de.red(`\u2717 Not logged in. Run '${g.commands[0]} login' first.`)),process.exitCode=2;return}try{let t=await we();console.log(de.green(`\u2713 Logged in as ${t.user.email}`))}catch(t){console.log(de.red(`\u2717 Auth check failed: ${t instanceof Error?t.message:"unknown"}`)),process.exitCode=2}});Lt.command("start").description("Start the local runner (register + wait for work)").option("--once","Execute a single job, then exit").option("--workspace <dir>","Workspace root for job scratch directories").option("--claude-bin <path>","Path to the claude binary").option("--codex-bin <path>","Path to the codex binary").action(async e=>{ce()||(console.error(de.red(`Not authenticated. Run '${g.commands[0]} login' first.`)),process.exit(2));let n=new AbortController,t=()=>{console.log(de.gray(`
60
+ Stopping runner\u2026`)),n.abort()};process.on("SIGINT",t),process.on("SIGTERM",t);try{await Br({claudeBin:e.claudeBin,codexBin:e.codexBin,log:o=>console.log(de.gray(`[runner] ${o}`)),once:e.once,signal:n.signal,version:"0.3.13",workspaceRoot:e.workspace??mc()})}catch(o){console.error(de.red(o instanceof Error?o.message:String(o))),process.exit(1)}});import{Command as bc}from"commander";import V from"chalk";function Ut(e){let{name:n,cmd:t}=e,o=n.toUpperCase().replace(/[^A-Z0-9]/g,"_");return`---
61
61
  name: ${n}
62
62
  description: CLI with TTS (text-to-speech), AI music generation, sound effects, stock image/video search, audio mixing, URL scraping, and branding. Use when user asks for voiceover, narration, background music, sound effects, stock footage, or needs to scrape a website.
63
63
  ---
@@ -75,7 +75,7 @@ A comprehensive CLI for AI-powered content creation. Generate presentations, vid
75
75
  **IMPORTANT:** Most commands require authentication. If a command fails with "Not authenticated", run:
76
76
 
77
77
  \`\`\`bash
78
- ${e} login
78
+ ${t} login
79
79
  \`\`\`
80
80
 
81
81
  This opens a browser for OAuth login. Alternatively, set an API key:
@@ -85,12 +85,12 @@ export ${o}_API_KEY="your-key-here"
85
85
  \`\`\`
86
86
 
87
87
  **For AI Assistants (Claude Code, Cursor, etc.):**
88
- When running \`${e} login\` via Bash tool, use the default behavior (opens browser).
89
- Do NOT use \`--no-browser\` flag. Correct: \`Bash(${e} login)\` \u2713
88
+ When running \`${t} login\` via Bash tool, use the default behavior (opens browser).
89
+ Do NOT use \`--no-browser\` flag. Correct: \`Bash(${t} login)\` \u2713
90
90
 
91
91
  **Verify authentication:**
92
92
  \`\`\`bash
93
- ${e} whoami
93
+ ${t} whoami
94
94
  \`\`\`
95
95
 
96
96
  ---
@@ -98,39 +98,39 @@ ${e} whoami
98
98
  ## Commands
99
99
 
100
100
  ### Presentations
101
- \`${e} create "Topic"\` \u2192 Load \`${n}-presentation\` skill
101
+ \`${t} create "Topic"\` \u2192 Load \`${n}-presentation\` skill
102
102
 
103
103
  ### Video
104
- \`${e} video generate new my-video\` \u2192 Load \`${n}-video\` skill
104
+ \`${t} video generate new my-video\` \u2192 Load \`${n}-video\` skill
105
105
 
106
106
  ### TTS
107
- \`${e} tts generate -t "Text" -o out.mp3\` \u2192 [references/tts.md](references/tts.md)
107
+ \`${t} tts generate -t "Text" -o out.mp3\` \u2192 [references/tts.md](references/tts.md)
108
108
 
109
109
  ### Music
110
- \`${e} music generate -p "upbeat corporate" -d 30\` \u2192 [references/music.md](references/music.md)
110
+ \`${t} music generate -p "upbeat corporate" -d 30\` \u2192 [references/music.md](references/music.md)
111
111
 
112
112
  ### SFX
113
- \`${e} sfx generate -t "thunder"\` \u2192 [references/sfx.md](references/sfx.md)
113
+ \`${t} sfx generate -t "thunder"\` \u2192 [references/sfx.md](references/sfx.md)
114
114
 
115
115
  ### Image
116
- \`${e} image search -q "landscape"\` \u2192 [references/image.md](references/image.md)
116
+ \`${t} image search -q "landscape"\` \u2192 [references/image.md](references/image.md)
117
117
 
118
118
  ### Video Search
119
- \`${e} video find "ocean waves"\` \u2192 [references/video-search.md](references/video-search.md)
119
+ \`${t} video find "ocean waves"\` \u2192 [references/video-search.md](references/video-search.md)
120
120
 
121
121
  ### Mix
122
- \`${e} mix create --video v.mp4 --music m.mp3 -o out.mp4\` \u2192 [references/mix.md](references/mix.md)
122
+ \`${t} mix create --video v.mp4 --music m.mp3 -o out.mp4\` \u2192 [references/mix.md](references/mix.md)
123
123
 
124
124
  ### Scrape
125
- \`${e} scrape https://example.com\` \u2192 [references/scrape.md](references/scrape.md)
125
+ \`${t} scrape https://example.com\` \u2192 [references/scrape.md](references/scrape.md)
126
126
 
127
127
  ### Branding
128
- \`${e} branding list\` \u2192 [references/branding.md](references/branding.md)
128
+ \`${t} branding list\` \u2192 [references/branding.md](references/branding.md)
129
129
 
130
130
  ### Config
131
- \`${e} config show\` \u2192 [references/config.md](references/config.md)
131
+ \`${t} config show\` \u2192 [references/config.md](references/config.md)
132
132
 
133
- `}function Pt(t){let{name:n,cmd:e,mode:o="standalone"}=t,r=o==="studio";return`---
133
+ `}function Ft(e){let{name:n,cmd:t,mode:o="standalone"}=e,r=o==="studio";return`---
134
134
  name: ${n}-video
135
135
  description: Orchestrates video creation by coordinating specialized agents for branding, audio, and scene building. Gathers context, writes briefs, generates plans, and assembles Remotion videos. Use when user says "create a video", "make a promo", "product demo", "explainer video", "marketing video", "gather video assets", "video for my project", or "TikTok/Reels content".
136
136
  ---
@@ -142,13 +142,13 @@ Follow the steps in order. Some steps delegate work to specialized agents (brand
142
142
  **Before starting ANY work, verify authentication:**
143
143
 
144
144
  \`\`\`bash
145
- ${e} whoami
145
+ ${t} whoami
146
146
  \`\`\`
147
147
 
148
148
  **If authentication fails:**
149
149
  - **STOP IMMEDIATELY** - Do NOT proceed to any other steps
150
150
  - **Do NOT build Remotion scenes** without audio assets
151
- - Tell user to run: \`${e} login\`
151
+ - Tell user to run: \`${t} login\`
152
152
  - Wait for user to authenticate before continuing
153
153
 
154
154
  **Why this matters:** Audio assets (voiceovers, music) cannot be "added later" in practice. Without authentication, the video workflow cannot be completed. Building scenes without audio is wasted effort.
@@ -163,10 +163,10 @@ ${e} whoami
163
163
 
164
164
  | Command | Purpose |
165
165
  |---------|---------|
166
- | \`${e} scrape <url>\` | Extract content from URLs (websites, YouTube, Twitter) |
167
- | \`${e} image search\` | Search stock images |
168
- | \`${e} video find\` | Search stock video clips |
169
- | \`${e} video analyze <file>\` | Analyze video: scene detection, transcription, frame descriptions |
166
+ | \`${t} scrape <url>\` | Extract content from URLs (websites, YouTube, Twitter) |
167
+ | \`${t} image search\` | Search stock images |
168
+ | \`${t} video find\` | Search stock video clips |
169
+ | \`${t} video analyze <file>\` | Analyze video: scene detection, transcription, frame descriptions |
170
170
 
171
171
  Branding commands (\`branding find/extract/get\`) are used by the \`video-branding-director\` \u2014 see Step 3.
172
172
  Audio commands (\`tts generate\`, \`music generate\`, \`sfx generate\`) are used by the \`video-audio-director\` \u2014 see Step 8.
@@ -174,12 +174,12 @@ Audio commands (\`tts generate\`, \`music generate\`, \`sfx generate\`) are used
174
174
  ## Step 1: Initialize Project
175
175
 
176
176
  \`\`\`bash
177
- ${e} video generate new my-video # Run in BACKGROUND, continue to Step 2 immediately
177
+ ${t} video generate new my-video # Run in BACKGROUND, continue to Step 2 immediately
178
178
  \`\`\`
179
179
 
180
180
  **MANDATORY:** Run project creation in background and proceed to Step 2 while dependencies install.
181
181
 
182
- Projects are stored in \`~/.conceptcraft/projects/\`. Use \`${e} video projects\` to list all.
182
+ Projects are stored in \`~/.conceptcraft/projects/\`. Use \`${t} video projects\` to list all.
183
183
 
184
184
  **Revisions:** If user requests changes (new music, different voice, etc.), render a new output file (e.g., \`out/video_v2.mp4\`) \u2014 do not overwrite the original.
185
185
 
@@ -187,7 +187,7 @@ Projects are stored in \`~/.conceptcraft/projects/\`. Use \`${e} video projects\
187
187
 
188
188
  Understand user's request and identify source type. Gather all relevant information for the video.
189
189
 
190
- **For URLs/websites:** \`${e} scrape <url>\` - extracts content and page structure.
190
+ **For URLs/websites:** \`${t} scrape <url>\` - extracts content and page structure.
191
191
  **For codebases:** Explore repo, find UI components, README, docs.
192
192
  **For topics:** Research via web search, gather key points.
193
193
 
@@ -287,10 +287,10 @@ Once brief is approved, generate the video plan. The \`--branding\` flag sends b
287
287
 
288
288
  \`\`\`bash
289
289
  # Without branding
290
- cat video-brief.md | ${e} video generate plan -o video-plan.md
290
+ cat video-brief.md | ${t} video generate plan -o video-plan.md
291
291
 
292
292
  # With branding (always use when branding.json exists)
293
- cat video-brief.md | ${e} video generate plan -o video-plan.md --branding branding.json
293
+ cat video-brief.md | ${t} video generate plan -o video-plan.md --branding branding.json
294
294
  \`\`\`
295
295
 
296
296
  This sends the brief to the server and returns a detailed scene-by-scene plan.
@@ -312,7 +312,7 @@ Spawn the \`video-audio-director\` agent to handle all audio generation and timi
312
312
  \`\`\`
313
313
  ## Audio Director Task
314
314
 
315
- **CLI command:** ${e}
315
+ **CLI command:** ${t}
316
316
  **Video plan:** video-plan.md
317
317
  **Output directory:** ./public/audio/
318
318
  **Voice:** [chosen voice, default: Puck]
@@ -321,18 +321,18 @@ Spawn the \`video-audio-director\` agent to handle all audio generation and timi
321
321
  Generate all audio assets and produce timing-manifest.md.
322
322
  \`\`\`
323
323
 
324
- **Available voices:** \`${e} tts voices -p <provider>\`
324
+ **Available voices:** \`${t} tts voices -p <provider>\`
325
325
  - **Gemini (default):** Puck, Kore, Charon, Zephyr, Fenrir, Aoede, Enceladus...
326
326
  - **OpenAI:** alloy, coral, nova, onyx, sage, shimmer, ash, ballad...
327
- - **ElevenLabs:** Use \`--voice-id\` with ID from \`${e} tts voices -p elevenlabs\`
327
+ - **ElevenLabs:** Use \`--voice-id\` with ID from \`${t} tts voices -p elevenlabs\`
328
328
 
329
329
  ### Stock Media (only if plan requires it)
330
330
 
331
331
  While the audio director works, search for stock media if the plan references real photos/footage. CSS-built visuals do NOT need stock media.
332
332
 
333
333
  \`\`\`bash
334
- ${e} image search -q "exact description from plan" --max-results 3
335
- ${e} video find "exact description from plan" --max-results 3
334
+ ${t} image search -q "exact description from plan" --max-results 3
335
+ ${t} video find "exact description from plan" --max-results 3
336
336
  \`\`\`
337
337
 
338
338
  ### After Audio Director Completes
@@ -593,12 +593,12 @@ npx remotion render Main out/video.mp4 --gl=angle
593
593
  \`\`\`
594
594
 
595
595
  After render:
596
- - [ ] Thumbnail injected via \`${e} video thumbnail inject\`
596
+ - [ ] Thumbnail injected via \`${t} video thumbnail inject\`
597
597
 
598
598
  ## Step 10: Inject Thumbnail
599
599
 
600
600
  \`\`\`bash
601
- ${e} video thumbnail inject -i out/video.mp4 -t ./public/thumbnail.jpg
601
+ ${t} video thumbnail inject -i out/video.mp4 -t ./public/thumbnail.jpg
602
602
  \`\`\`
603
603
 
604
604
  Injects thumbnail as first frame (QuickLook preview) + attached_pic (file icons).
@@ -612,7 +612,7 @@ Injects thumbnail as first frame (QuickLook preview) + attached_pic (file icons)
612
612
  **CRITICAL:** If you see "Unauthorized" or authentication errors:
613
613
  - **STOP the entire workflow immediately**
614
614
  - **Do NOT proceed to build scenes or implement code**
615
- - Tell user: "Authentication is required. Please run: \`${e} login\`"
615
+ - Tell user: "Authentication is required. Please run: \`${t} login\`"
616
616
  - Wait for user to authenticate before restarting from Step 1
617
617
 
618
618
  **Why:** Audio assets cannot be generated without authentication. Building Remotion scenes without audio is wasted work that cannot be completed later.
@@ -632,19 +632,19 @@ Add \`--concurrency=2\` to reduce memory usage, or render scenes separately.
632
632
 
633
633
  ## CLI Quick Reference
634
634
 
635
- The \`${e}\` CLI has tools for working with individual assets directly. This is useful for quick fixes \u2014 re-generating a single voiceover, trying a different music style, or searching for stock footage. Run \`${e} --help\` for the full list.
635
+ The \`${t}\` CLI has tools for working with individual assets directly. This is useful for quick fixes \u2014 re-generating a single voiceover, trying a different music style, or searching for stock footage. Run \`${t} --help\` for the full list.
636
636
 
637
- - **Voiceover:** \`${e} tts generate --text "..." --voice Puck --output file.wav\` \u2014 generate speech from text. \`${e} tts voices\` lists available voices.
638
- - **Music:** \`${e} music generate --prompt "..." --duration 30 --output file.mp3\` \u2014 generate background music from a text prompt.
639
- - **Sound effects:** \`${e} sfx generate --prompt "..." --output file.wav\` \u2014 generate SFX from a description.
640
- - **Stock images:** \`${e} image search "query"\` \u2014 search stock photo libraries.
641
- - **Stock video:** \`${e} video find "query"\` \u2014 search stock video clips.
642
- - **Scraping:** \`${e} scrape <url>\` \u2014 extract text content from a URL.
643
- - **Branding:** \`${e} branding find <name>\`, \`${e} branding extract <url>\`, \`${e} branding get <id>\` \u2014 search, extract, or export brand profiles.
644
- - **Audio mixing:** \`${e} mix\` \u2014 combine voice, music, and video tracks.
637
+ - **Voiceover:** \`${t} tts generate --text "..." --voice Puck --output file.wav\` \u2014 generate speech from text. \`${t} tts voices\` lists available voices.
638
+ - **Music:** \`${t} music generate --prompt "..." --duration 30 --output file.mp3\` \u2014 generate background music from a text prompt.
639
+ - **Sound effects:** \`${t} sfx generate --prompt "..." --output file.wav\` \u2014 generate SFX from a description.
640
+ - **Stock images:** \`${t} image search "query"\` \u2014 search stock photo libraries.
641
+ - **Stock video:** \`${t} video find "query"\` \u2014 search stock video clips.
642
+ - **Scraping:** \`${t} scrape <url>\` \u2014 extract text content from a URL.
643
+ - **Branding:** \`${t} branding find <name>\`, \`${t} branding extract <url>\`, \`${t} branding get <id>\` \u2014 search, extract, or export brand profiles.
644
+ - **Audio mixing:** \`${t} mix\` \u2014 combine voice, music, and video tracks.
645
645
 
646
646
  During the main workflow, branding and audio are handled by their dedicated agents. But for one-off fixes or user requests outside the workflow, use these commands directly.
647
- `}function Nt(t){let{name:n,cmd:e}=t;return`---
647
+ `}function _t(e){let{name:n,cmd:t}=e;return`---
648
648
  name: ${n}-presentation
649
649
  description: Use when user asks to create presentations, slides, decks, pitch decks.
650
650
  Researches the topic, gathers context, and generates AI-powered presentations via CLI.
@@ -659,10 +659,10 @@ description: Use when user asks to create presentations, slides, decks, pitch de
659
659
  Always verify auth before doing anything else:
660
660
 
661
661
  \`\`\`bash
662
- ${e} whoami
662
+ ${t} whoami
663
663
  \`\`\`
664
664
 
665
- If this fails \u2192 **STOP**. Tell the user: \`${e} login\`. Do NOT proceed without auth.
665
+ If this fails \u2192 **STOP**. Tell the user: \`${t} login\`. Do NOT proceed without auth.
666
666
 
667
667
  ---
668
668
 
@@ -670,16 +670,16 @@ If this fails \u2192 **STOP**. Tell the user: \`${e} login\`. Do NOT proceed wit
670
670
 
671
671
  | Command | Purpose |
672
672
  |---------|---------|
673
- | \`${e} create <topic>\` | Create presentation |
674
- | \`${e} create <topic> --studio\` | Create and link to Studio preview |
675
- | \`${e} scrape <url>\` | Scrape URL content |
676
- | \`${e} list\` | List presentations |
677
- | \`${e} get <id>\` | Get details |
678
- | \`${e} export <id> -o file.zip\` | Export |
679
- | \`${e} branding find <name-or-url>\` | Search existing brands (returns IDs) |
680
- | \`${e} branding extract <url>\` | Extract NEW brand identity |
681
- | \`${e} branding list\` | List saved brands |
682
- | \`${e} images search "query"\` | Stock images |
673
+ | \`${t} create <topic>\` | Create presentation |
674
+ | \`${t} create <topic> --studio\` | Create and link to Studio preview |
675
+ | \`${t} scrape <url>\` | Scrape URL content |
676
+ | \`${t} list\` | List presentations |
677
+ | \`${t} get <id-or-slug>\` | Get details and canonical Studio/view URLs |
678
+ | \`${t} export <id> -o file.zip\` | Export |
679
+ | \`${t} branding find <name-or-url>\` | Search existing brands (returns IDs) |
680
+ | \`${t} branding extract <url>\` | Extract NEW brand identity |
681
+ | \`${t} branding list\` | List saved brands |
682
+ | \`${t} images search "query"\` | Stock images |
683
683
 
684
684
  ---
685
685
 
@@ -689,15 +689,15 @@ If this fails \u2192 **STOP**. Tell the user: \`${e} login\`. Do NOT proceed wit
689
689
 
690
690
  **For a company/product/URL:**
691
691
  \`\`\`bash
692
- ${e} scrape https://company.com > /tmp/context.txt
693
- ${e} create "Company Overview" --studio --context-file /tmp/context.txt -n 10 --mode best
692
+ ${t} scrape https://company.com > /tmp/context.txt
693
+ ${t} create "Company Overview" --studio --context-file /tmp/context.txt -n 10 --mode best
694
694
  \`\`\`
695
695
 
696
696
  **For a topic (no URL):**
697
697
  - Use web search to gather current facts, stats, key points
698
698
  - Synthesize into text, pass via \`--context\`:
699
699
  \`\`\`bash
700
- ${e} create "AI in Healthcare" \\
700
+ ${t} create "AI in Healthcare" \\
701
701
  --studio \\
702
702
  --context "Key findings: Market size \\$45B in 2024, growing 37% CAGR. Top: diagnostics, drug discovery..." \\
703
703
  -n 12 --mode best
@@ -705,7 +705,7 @@ ${e} create "AI in Healthcare" \\
705
705
 
706
706
  **For user-provided files:**
707
707
  \`\`\`bash
708
- ${e} create "Q4 Review" --studio --file ./report.pdf --file ./data.xlsx -n 10
708
+ ${t} create "Q4 Review" --studio --file ./report.pdf --file ./data.xlsx -n 10
709
709
  \`\`\`
710
710
 
711
711
  ---
@@ -716,8 +716,8 @@ ${e} create "Q4 Review" --studio --file ./report.pdf --file ./data.xlsx -n 10
716
716
 
717
717
  1. **Search existing brands first** (always before extracting):
718
718
  \`\`\`bash
719
- ${e} branding find "Company Name"
720
- ${e} branding find company.com
719
+ ${t} branding find "Company Name"
720
+ ${t} branding find company.com
721
721
  \`\`\`
722
722
 
723
723
  2. **If found** \u2014 use AskUserQuestion: "Found existing brand for [name]. Apply it?"
@@ -725,7 +725,7 @@ ${e} branding find company.com
725
725
  - If yes: get the brand ID from the find results
726
726
 
727
727
  3. **If not found** \u2014 extract immediately (no need to ask):
728
- \`${e} branding extract https://company.com\`
728
+ \`${t} branding extract https://company.com\`
729
729
 
730
730
  4. **If extraction FAILS** (rate limit, plan limit, server error):
731
731
  - **STOP immediately** \u2014 do NOT retry or manually create brand assets
@@ -734,12 +734,12 @@ ${e} branding find company.com
734
734
 
735
735
  5. **If user confirms** \u2192 use brand ID in create:
736
736
  \`\`\`bash
737
- ${e} create "Topic" --branding-id <id> --styling brand-plus-style ...
737
+ ${t} create "Topic" --branding-id <id> --styling brand-plus-style ...
738
738
  \`\`\`
739
739
 
740
740
  **\`--reference-url\`** \u2014 only when user explicitly provides an image/URL as visual design reference:
741
741
  \`\`\`bash
742
- ${e} create "Product Demo" --reference-url https://example.com/style-screenshot.png
742
+ ${t} create "Product Demo" --reference-url https://example.com/style-screenshot.png
743
743
  \`\`\`
744
744
 
745
745
  ---
@@ -773,7 +773,7 @@ ${e} create "Product Demo" --reference-url https://example.com/style-screenshot.
773
773
 
774
774
  | Flag | Values | Notes |
775
775
  |------|--------|-------|
776
- | \`--branding-id\` | branding ID | DB ID from \`${e} branding list\` or returned by \`${e} branding extract\`. NOT a URL. |
776
+ | \`--branding-id\` | branding ID | DB ID from \`${t} branding list\` or returned by \`${t} branding extract\`. NOT a URL. |
777
777
  | \`--styling\` | **freeform**/brand-only/brand-plus-style/style-only/no-styling | if brand \u2192 \`brand-only\` (enforces brand fonts+colors) |
778
778
  | \`--reference-url\` | image url | only when user explicitly provides an image as design reference |
779
779
  | \`--theme\` | blue/violet/rose/orange/green | **instant mode only** \u2014 quick color preset |
@@ -788,7 +788,7 @@ ${e} create "Product Demo" --reference-url https://example.com/style-screenshot.
788
788
 
789
789
  Full example \u2014 research-driven:
790
790
  \`\`\`bash
791
- ${e} create "AI in Healthcare 2025" \\
791
+ ${t} create "AI in Healthcare 2025" \\
792
792
  --studio \\
793
793
  --context-file /tmp/research.txt \\
794
794
  --slides 12 \\
@@ -800,7 +800,7 @@ ${e} create "AI in Healthcare 2025" \\
800
800
 
801
801
  Full example \u2014 company pitch deck:
802
802
  \`\`\`bash
803
- ${e} create "Acme Corp Investor Pitch" \\
803
+ ${t} create "Acme Corp Investor Pitch" \\
804
804
  --studio \\
805
805
  --context "Acme Corp: B2B SaaS, \\$5M ARR, 200 customers, founded 2021..." \\
806
806
  --branding-id <id-from-branding-extract> \\
@@ -818,35 +818,53 @@ ${e} create "Acme Corp Investor Pitch" \\
818
818
 
819
819
  \`\`\`bash
820
820
  # Export to ZIP (HTML + all assets)
821
- ${e} export <slug> -o ./presentation.zip
821
+ ${t} export <slug> -o ./presentation.zip
822
822
 
823
823
  # Export and unzip to folder
824
- ${e} export <slug> -o ./presentation.zip && unzip -o ./presentation.zip -d ./presentation/
824
+ ${t} export <slug> -o ./presentation.zip && unzip -o ./presentation.zip -d ./presentation/
825
825
 
826
826
  # Get slug from a just-created presentation
827
- ${e} get <id-or-slug> --format json
827
+ ${t} get <id-or-slug> --format json
828
828
  \`\`\`
829
829
 
830
+ ## Completion handoff (required)
831
+
832
+ After a background presentation reaches 100%, do not finish with only a title
833
+ or slug. Resolve the created row and include its canonical Studio URL as a
834
+ clickable Markdown link:
835
+
836
+ \`\`\`bash
837
+ # Find the newly created row, then use its full UUID (most reliable while a
838
+ # deployment containing slug lookup fixes may still be rolling out).
839
+ ${t} list --format json
840
+ ${t} get <presentation-uuid> --format json
841
+ \`\`\`
842
+
843
+ Use the returned \`editUrl\` in the final response: \`[Open deck](<editUrl>)\`.
844
+ Use \`viewUrl\` only when the user asked for the viewer. If you created local
845
+ research notes, link their absolute path; the Mindframes desktop app can open
846
+ files inside its own local-runner workspace.
847
+
830
848
  ---
831
849
 
832
850
  ## Managing Presentations
833
851
 
834
852
  \`\`\`bash
835
- ${e} list
836
- ${e} get <id-or-slug>
837
- ${e} export <id-or-slug> -o presentation.zip
838
- ${e} delete <id-or-slug>
839
- ${e} import ./presentation.zip
853
+ ${t} list
854
+ ${t} get <id-or-slug>
855
+ ${t} export <id-or-slug> -o presentation.zip
856
+ ${t} delete <id-or-slug>
857
+ ${t} import ./presentation.zip
840
858
  \`\`\`
841
859
 
842
860
  ---
843
861
 
844
862
  ## Troubleshooting
845
863
 
846
- - **Auth fails** \u2192 \`${e} logout && ${e} login\` (browser required)
864
+ - **Auth fails** \u2192 \`${t} logout && ${t} login\` (browser required)
847
865
  - **"Context required"** \u2192 add \`--context\`, \`--file\`, or \`--context-file\`
848
- - **Rate limit (429)** \u2192 check plan with \`${e} whoami\`
849
- `}function Dt(t){let{name:n,cmd:e}=t;return`---
866
+ - **Rate limit (429)** \u2192 check plan with \`${t} whoami\`
867
+ `}function Vt(e){let{name:n,cmd:t}=e;return`---
850
868
  name: ${n}-presentation-edit
851
869
  description: >
852
870
  Use ONLY when editing an already-created presentation that has real slides:
@@ -871,12 +889,12 @@ A new version is created automatically after each AI-assisted save.
871
889
 
872
890
  \`\`\`bash
873
891
  # Quick creation
874
- ${e} create "Topic" --slides 10 --mode best
892
+ ${t} create "Topic" --slides 10 --mode best
875
893
 
876
894
  # With branding (always search before extracting)
877
- ${e} branding find "Company Name" # check if brand already saved
878
- ${e} branding extract https://company.com # extract if not found \u2192 get ID
879
- ${e} create "Company Pitch Deck" \\
895
+ ${t} branding find "Company Name" # check if brand already saved
896
+ ${t} branding extract https://company.com # extract if not found \u2192 get ID
897
+ ${t} create "Company Pitch Deck" \\
880
898
  --branding-id <id> \\
881
899
  --styling brand-plus-style \\
882
900
  --slides 10 --mode best \\
@@ -1028,13 +1046,13 @@ Edit only the \`data\` / \`labels\` / \`options\` values \u2014 do not change th
1028
1046
 
1029
1047
  \`\`\`bash
1030
1048
  # Basic search \u2014 returns URLs from Unsplash / Pexels
1031
- ${e} image search -q "modern office workspace"
1049
+ ${t} image search -q "modern office workspace"
1032
1050
 
1033
1051
  # Get more results, large size only
1034
- ${e} image search -q "team collaboration" -n 20 --size large
1052
+ ${t} image search -q "team collaboration" -n 20 --size large
1035
1053
 
1036
1054
  # JSON output for scripting
1037
- ${e} image search -q "abstract tech" -f json
1055
+ ${t} image search -q "abstract tech" -f json
1038
1056
  \`\`\`
1039
1057
 
1040
1058
 
@@ -1049,10 +1067,10 @@ When no stock photo fits, generate a custom one:
1049
1067
 
1050
1068
  \`\`\`bash
1051
1069
  # Generate and save to a temp path
1052
- ${e} image generate -p "futuristic data center, blue lighting, cinematic" -o /tmp/slide-hero.png
1070
+ ${t} image generate -p "futuristic data center, blue lighting, cinematic" -o /tmp/slide-hero.png
1053
1071
 
1054
1072
  # Custom dimensions for a 16:9 slide background
1055
- ${e} image generate -p "abstract gradient technology" --width 1920 --height 1080 -o /tmp/bg.png
1073
+ ${t} image generate -p "abstract gradient technology" --width 1920 --height 1080 -o /tmp/bg.png
1056
1074
  \`\`\`
1057
1075
 
1058
1076
 
@@ -1080,10 +1098,10 @@ Do NOT render or export the presentation \u2014 that's handled by the app.
1080
1098
  |-----------|--------|
1081
1099
  | Edit text / color / image in open slides | Edit \`current.html\` directly |
1082
1100
  | Add 1\u20132 slides to existing deck | Add \`<div class="slide">\` to \`current.html\` |
1083
- | Create brand-new presentation (5+ slides, new topic) | \`${e} create ...\` via CLI |
1084
- | Redesign the whole deck | \`${e} create ...\` via CLI, then sync |
1085
- | User provides a URL to base the presentation on | \`${e} scrape <url>\` \u2192 \`${e} create ...\` |
1086
- `}function Fe(t){let{name:n,cmd:e}=t;return`---
1101
+ | Create brand-new presentation (5+ slides, new topic) | \`${t} create ...\` via CLI |
1102
+ | Redesign the whole deck | \`${t} create ...\` via CLI, then sync |
1103
+ | User provides a URL to base the presentation on | \`${t} scrape <url>\` \u2192 \`${t} create ...\` |
1104
+ `}function _e(e){let{name:n,cmd:t}=e;return`---
1087
1105
  name: ${n}-tts
1088
1106
  description: Text-to-speech generation. Convert text to natural speech with multiple providers (Gemini, ElevenLabs, OpenAI) and voices. Use for voiceovers, narration, accessibility.
1089
1107
  ---
@@ -1095,9 +1113,9 @@ Convert text to natural speech with multiple providers and voices.
1095
1113
  ## Quick Start
1096
1114
 
1097
1115
  \`\`\`bash
1098
- ${e} tts generate -t "Hello world" --voice Puck -o output.wav
1099
- ${e} tts voices -p gemini # List Gemini voices
1100
- ${e} tts voices # List all providers
1116
+ ${t} tts generate -t "Hello world" --voice Puck -o output.wav
1117
+ ${t} tts voices -p gemini # List Gemini voices
1118
+ ${t} tts voices # List all providers
1101
1119
  \`\`\`
1102
1120
 
1103
1121
  ---
@@ -1107,7 +1125,7 @@ ${e} tts voices # List all providers
1107
1125
  ### \`tts generate\`
1108
1126
 
1109
1127
  \`\`\`bash
1110
- ${e} tts generate -t "Text" -o output.wav [options]
1128
+ ${t} tts generate -t "Text" -o output.wav [options]
1111
1129
  \`\`\`
1112
1130
 
1113
1131
  | Option | Description | Default |
@@ -1126,11 +1144,11 @@ ${e} tts generate -t "Text" -o output.wav [options]
1126
1144
  ### \`tts voices\`
1127
1145
 
1128
1146
  \`\`\`bash
1129
- ${e} tts voices # All providers
1130
- ${e} tts voices -p gemini # Gemini only
1131
- ${e} tts voices -p elevenlabs # ElevenLabs only
1132
- ${e} tts voices -p openai # OpenAI only
1133
- ${e} tts voices -f json # JSON format
1147
+ ${t} tts voices # All providers
1148
+ ${t} tts voices -p gemini # Gemini only
1149
+ ${t} tts voices -p elevenlabs # ElevenLabs only
1150
+ ${t} tts voices -p openai # OpenAI only
1151
+ ${t} tts voices -f json # JSON format
1134
1152
  \`\`\`
1135
1153
 
1136
1154
  ---
@@ -1163,10 +1181,10 @@ Control delivery with natural language in the text:
1163
1181
 
1164
1182
  \`\`\`bash
1165
1183
  # Cheerful delivery
1166
- ${e} tts generate -t "Say cheerfully: Have a wonderful day!" --voice Puck -o cheerful.wav
1184
+ ${t} tts generate -t "Say cheerfully: Have a wonderful day!" --voice Puck -o cheerful.wav
1167
1185
 
1168
1186
  # Whisper
1169
- ${e} tts generate -t "Say in a spooky whisper: Something wicked this way comes" --voice Enceladus -o whisper.wav
1187
+ ${t} tts generate -t "Say in a spooky whisper: Something wicked this way comes" --voice Enceladus -o whisper.wav
1170
1188
  \`\`\`
1171
1189
 
1172
1190
  ### Multi-Speaker TTS (Gemini)
@@ -1175,7 +1193,7 @@ Generate dialogue with up to 2 speakers using \`--speakers\`:
1175
1193
 
1176
1194
  \`\`\`bash
1177
1195
  # Basic dialogue
1178
- ${e} tts generate \\
1196
+ ${t} tts generate \\
1179
1197
  -t "Joe: How's it going? Jane: Not too bad!" \\
1180
1198
  --speakers '[{"name":"Joe","voice":"Kore"},{"name":"Jane","voice":"Puck"}]' \\
1181
1199
  -p gemini -o dialogue.wav
@@ -1189,7 +1207,7 @@ Jane: Not too bad, how about you?
1189
1207
 
1190
1208
  With style directions:
1191
1209
  \`\`\`bash
1192
- ${e} tts generate \\
1210
+ ${t} tts generate \\
1193
1211
  -t "Make Joe sound tired and Jane excited:
1194
1212
  Joe: So... what's on the agenda?
1195
1213
  Jane: You're never going to guess!" \\
@@ -1211,7 +1229,7 @@ Use \`--voice-id\` with ElevenLabs provider:
1211
1229
  | \`pNInz6obpgDQGcFmaJgB\` | Adam | Deep male |
1212
1230
 
1213
1231
  \`\`\`bash
1214
- ${e} tts generate -t "Text" --voice-id 21m00Tcm4TlvDq8ikWAM -p elevenlabs -o out.mp3
1232
+ ${t} tts generate -t "Text" --voice-id 21m00Tcm4TlvDq8ikWAM -p elevenlabs -o out.mp3
1215
1233
  \`\`\`
1216
1234
 
1217
1235
  ---
@@ -1233,7 +1251,7 @@ Models: \`gpt-4o-mini-tts\` (newest, supports instructions), \`tts-1\`, \`tts-1-
1233
1251
  ### Basic Usage
1234
1252
 
1235
1253
  \`\`\`bash
1236
- ${e} tts generate -t "Text" --voice coral -p openai -o out.mp3
1254
+ ${t} tts generate -t "Text" --voice coral -p openai -o out.mp3
1237
1255
  \`\`\`
1238
1256
 
1239
1257
  ### Style Prompting (gpt-4o-mini-tts)
@@ -1242,21 +1260,21 @@ Use \`--instructions\` to control tone, accent, speed, emotion:
1242
1260
 
1243
1261
  \`\`\`bash
1244
1262
  # Cheerful tone
1245
- ${e} tts generate \\
1263
+ ${t} tts generate \\
1246
1264
  -t "Today is a wonderful day to build something people love!" \\
1247
1265
  --voice coral -p openai -m gpt-4o-mini-tts \\
1248
1266
  -i "Speak in a cheerful and positive tone." \\
1249
1267
  -o cheerful.mp3
1250
1268
 
1251
1269
  # Whispering
1252
- ${e} tts generate \\
1270
+ ${t} tts generate \\
1253
1271
  -t "This is a secret message." \\
1254
1272
  --voice sage -p openai -m gpt-4o-mini-tts \\
1255
1273
  -i "Speak in a soft whisper." \\
1256
1274
  -o whisper.mp3
1257
1275
 
1258
1276
  # Fast-paced excitement
1259
- ${e} tts generate \\
1277
+ ${t} tts generate \\
1260
1278
  -t "Breaking news: incredible discovery!" \\
1261
1279
  --voice ash -p openai -m gpt-4o-mini-tts \\
1262
1280
  -i "Speak rapidly with excitement and urgency." \\
@@ -1283,7 +1301,7 @@ ${e} tts generate \\
1283
1301
  2. **Voice matching** - Match voice style to content: Puck for upbeat, Charon for serious
1284
1302
  3. **Speed adjustment** - Use 0.9-0.95 for narration, 1.0-1.1 for casual
1285
1303
  4. **Batch processing** - Use \`video generate assets\` for multiple voiceovers
1286
- `}function Ue(t){let{name:n,cmd:e}=t;return`---
1304
+ `}function Ve(e){let{name:n,cmd:t}=e;return`---
1287
1305
  name: ${n}-music
1288
1306
  description: AI music generation from text prompts. Create background music, soundtracks, jingles for videos, presentations, podcasts. Supports ElevenLabs and Suno providers.
1289
1307
  ---
@@ -1296,10 +1314,10 @@ Generate AI music from text descriptions.
1296
1314
 
1297
1315
  \`\`\`bash
1298
1316
  # Generate 30s background music
1299
- ${e} music generate -p "upbeat corporate, modern synth" -d 30
1317
+ ${t} music generate -p "upbeat corporate, modern synth" -d 30
1300
1318
 
1301
1319
  # Save to file
1302
- ${e} music generate -p "calm ambient" -d 60 -o music.mp3
1320
+ ${t} music generate -p "calm ambient" -d 60 -o music.mp3
1303
1321
  \`\`\`
1304
1322
 
1305
1323
  ---
@@ -1311,7 +1329,7 @@ ${e} music generate -p "calm ambient" -d 60 -o music.mp3
1311
1329
  Generate music from a text prompt.
1312
1330
 
1313
1331
  \`\`\`bash
1314
- ${e} music generate [options]
1332
+ ${t} music generate [options]
1315
1333
  \`\`\`
1316
1334
 
1317
1335
  **Required:**
@@ -1332,7 +1350,7 @@ ${e} music generate [options]
1332
1350
  Check status of a generation request.
1333
1351
 
1334
1352
  \`\`\`bash
1335
- ${e} music status <request-id>
1353
+ ${t} music status <request-id>
1336
1354
  \`\`\`
1337
1355
 
1338
1356
  ---
@@ -1374,21 +1392,21 @@ ${e} music status <request-id>
1374
1392
 
1375
1393
  \`\`\`bash
1376
1394
  # Background music for video (2 minutes)
1377
- ${e} music generate \\
1395
+ ${t} music generate \\
1378
1396
  -p "upbeat corporate background, positive, modern" \\
1379
1397
  -d 120 \\
1380
1398
  -o background.mp3
1381
1399
 
1382
1400
  # Short jingle
1383
- ${e} music generate -p "tech startup intro jingle" -d 10 -o jingle.mp3
1401
+ ${t} music generate -p "tech startup intro jingle" -d 10 -o jingle.mp3
1384
1402
 
1385
1403
  # Async generation (get ID, check later)
1386
- ${e} music generate -p "ambient soundscape" -d 300 --no-wait
1404
+ ${t} music generate -p "ambient soundscape" -d 300 --no-wait
1387
1405
  # Returns request ID
1388
- ${e} music status <request-id>
1406
+ ${t} music status <request-id>
1389
1407
 
1390
1408
  # JSON output
1391
- ${e} music generate -p "calm piano" -d 30 -f json
1409
+ ${t} music generate -p "calm piano" -d 30 -f json
1392
1410
  \`\`\`
1393
1411
 
1394
1412
  ---
@@ -1423,7 +1441,7 @@ ${e} music generate -p "calm piano" -d 30 -f json
1423
1441
  2. **Looping** - For seamless loops, mention "loopable" in prompt.
1424
1442
  3. **Video sync** - Use \`video generate assets\` to auto-generate music for video projects.
1425
1443
  4. **Volume mixing** - Background music should be 20-30% volume when mixed with voiceover.
1426
- `}function _e(t){let{name:n,cmd:e}=t;return`---
1444
+ `}function Me(e){let{name:n,cmd:t}=e;return`---
1427
1445
  name: ${n}-sfx
1428
1446
  description: AI sound effects generation from text descriptions. Create foley, ambient, UI sounds, impacts, whooshes for videos, games, apps. Uses ElevenLabs SFX.
1429
1447
  ---
@@ -1436,13 +1454,13 @@ Generate AI sound effects from text descriptions.
1436
1454
 
1437
1455
  \`\`\`bash
1438
1456
  # Basic sound effect
1439
- ${e} sfx generate -t "door knock" -o knock.mp3
1457
+ ${t} sfx generate -t "door knock" -o knock.mp3
1440
1458
 
1441
1459
  # With duration
1442
- ${e} sfx generate -t "thunder rumbling" -d 5 -o thunder.mp3
1460
+ ${t} sfx generate -t "thunder rumbling" -d 5 -o thunder.mp3
1443
1461
 
1444
1462
  # Looping ambient
1445
- ${e} sfx generate -t "rain on window" -d 10 --loop -o rain.mp3
1463
+ ${t} sfx generate -t "rain on window" -d 10 --loop -o rain.mp3
1446
1464
  \`\`\`
1447
1465
 
1448
1466
  ---
@@ -1454,7 +1472,7 @@ ${e} sfx generate -t "rain on window" -d 10 --loop -o rain.mp3
1454
1472
  Generate sound effects from a text prompt.
1455
1473
 
1456
1474
  \`\`\`bash
1457
- ${e} sfx generate [options]
1475
+ ${t} sfx generate [options]
1458
1476
  \`\`\`
1459
1477
 
1460
1478
  **Required:**
@@ -1477,7 +1495,7 @@ ${e} sfx generate [options]
1477
1495
  Check status of a generation request.
1478
1496
 
1479
1497
  \`\`\`bash
1480
- ${e} sfx status <request-id>
1498
+ ${t} sfx status <request-id>
1481
1499
  \`\`\`
1482
1500
 
1483
1501
  ---
@@ -1488,92 +1506,92 @@ ${e} sfx status <request-id>
1488
1506
  Background sounds, environments.
1489
1507
 
1490
1508
  \`\`\`bash
1491
- ${e} sfx generate -t "rain on window, gentle storm" -d 10 --loop
1492
- ${e} sfx generate -t "busy coffee shop background" -d 15 --loop
1493
- ${e} sfx generate -t "wind through trees, forest" -d 10 --loop
1494
- ${e} sfx generate -t "city traffic, distant cars" -d 10 --loop
1509
+ ${t} sfx generate -t "rain on window, gentle storm" -d 10 --loop
1510
+ ${t} sfx generate -t "busy coffee shop background" -d 15 --loop
1511
+ ${t} sfx generate -t "wind through trees, forest" -d 10 --loop
1512
+ ${t} sfx generate -t "city traffic, distant cars" -d 10 --loop
1495
1513
  \`\`\`
1496
1514
 
1497
1515
  ### Foley
1498
1516
  Everyday sounds, object interactions.
1499
1517
 
1500
1518
  \`\`\`bash
1501
- ${e} sfx generate -t "footsteps on wood floor" -d 3
1502
- ${e} sfx generate -t "door slam, heavy wooden door" -d 2
1503
- ${e} sfx generate -t "glass breaking, shatter" -d 2
1504
- ${e} sfx generate -t "keys jingling" -d 1
1505
- ${e} sfx generate -t "paper rustling" -d 2
1519
+ ${t} sfx generate -t "footsteps on wood floor" -d 3
1520
+ ${t} sfx generate -t "door slam, heavy wooden door" -d 2
1521
+ ${t} sfx generate -t "glass breaking, shatter" -d 2
1522
+ ${t} sfx generate -t "keys jingling" -d 1
1523
+ ${t} sfx generate -t "paper rustling" -d 2
1506
1524
  \`\`\`
1507
1525
 
1508
1526
  ### UI/Interface
1509
1527
  App sounds, notifications.
1510
1528
 
1511
1529
  \`\`\`bash
1512
- ${e} sfx generate -t "notification chime, pleasant" -d 1
1513
- ${e} sfx generate -t "button click, soft" -d 0.5
1514
- ${e} sfx generate -t "success sound, achievement" -d 1
1515
- ${e} sfx generate -t "error beep, gentle" -d 0.5
1516
- ${e} sfx generate -t "swoosh transition" -d 0.5
1530
+ ${t} sfx generate -t "notification chime, pleasant" -d 1
1531
+ ${t} sfx generate -t "button click, soft" -d 0.5
1532
+ ${t} sfx generate -t "success sound, achievement" -d 1
1533
+ ${t} sfx generate -t "error beep, gentle" -d 0.5
1534
+ ${t} sfx generate -t "swoosh transition" -d 0.5
1517
1535
  \`\`\`
1518
1536
 
1519
1537
  ### Nature
1520
1538
  Natural environmental sounds.
1521
1539
 
1522
1540
  \`\`\`bash
1523
- ${e} sfx generate -t "birds chirping, morning" -d 5
1524
- ${e} sfx generate -t "thunder, distant rumble" -d 4
1525
- ${e} sfx generate -t "ocean waves crashing" -d 8 --loop
1526
- ${e} sfx generate -t "fire crackling" -d 5 --loop
1541
+ ${t} sfx generate -t "birds chirping, morning" -d 5
1542
+ ${t} sfx generate -t "thunder, distant rumble" -d 4
1543
+ ${t} sfx generate -t "ocean waves crashing" -d 8 --loop
1544
+ ${t} sfx generate -t "fire crackling" -d 5 --loop
1527
1545
  \`\`\`
1528
1546
 
1529
1547
  ### Impact
1530
1548
  Hits, explosions, crashes.
1531
1549
 
1532
1550
  \`\`\`bash
1533
- ${e} sfx generate -t "explosion, distant" -d 3
1534
- ${e} sfx generate -t "punch hit, impact" -d 1
1535
- ${e} sfx generate -t "car crash, metal" -d 3
1536
- ${e} sfx generate -t "sword clash, metal on metal" -d 1
1551
+ ${t} sfx generate -t "explosion, distant" -d 3
1552
+ ${t} sfx generate -t "punch hit, impact" -d 1
1553
+ ${t} sfx generate -t "car crash, metal" -d 3
1554
+ ${t} sfx generate -t "sword clash, metal on metal" -d 1
1537
1555
  \`\`\`
1538
1556
 
1539
1557
  ### Whoosh/Transitions
1540
1558
  Motion sounds, swooshes.
1541
1559
 
1542
1560
  \`\`\`bash
1543
- ${e} sfx generate -t "fast whoosh, swoosh" -d 1
1544
- ${e} sfx generate -t "sword swing through air" -d 1
1545
- ${e} sfx generate -t "wind gust" -d 2
1546
- ${e} sfx generate -t "camera shutter click" -d 0.5
1561
+ ${t} sfx generate -t "fast whoosh, swoosh" -d 1
1562
+ ${t} sfx generate -t "sword swing through air" -d 1
1563
+ ${t} sfx generate -t "wind gust" -d 2
1564
+ ${t} sfx generate -t "camera shutter click" -d 0.5
1547
1565
  \`\`\`
1548
1566
 
1549
1567
  ### Mechanical
1550
1568
  Machines, technology.
1551
1569
 
1552
1570
  \`\`\`bash
1553
- ${e} sfx generate -t "engine starting, car" -d 3
1554
- ${e} sfx generate -t "robot servo movement" -d 1
1555
- ${e} sfx generate -t "gear grinding, mechanical" -d 2
1556
- ${e} sfx generate -t "typing on keyboard, fast" -d 3
1571
+ ${t} sfx generate -t "engine starting, car" -d 3
1572
+ ${t} sfx generate -t "robot servo movement" -d 1
1573
+ ${t} sfx generate -t "gear grinding, mechanical" -d 2
1574
+ ${t} sfx generate -t "typing on keyboard, fast" -d 3
1557
1575
  \`\`\`
1558
1576
 
1559
1577
  ### Voice/Human
1560
1578
  Non-speech human sounds.
1561
1579
 
1562
1580
  \`\`\`bash
1563
- ${e} sfx generate -t "crowd cheering" -d 4
1564
- ${e} sfx generate -t "gasp, surprised" -d 1
1565
- ${e} sfx generate -t "laughter, genuine" -d 2
1566
- ${e} sfx generate -t "applause" -d 3
1581
+ ${t} sfx generate -t "crowd cheering" -d 4
1582
+ ${t} sfx generate -t "gasp, surprised" -d 1
1583
+ ${t} sfx generate -t "laughter, genuine" -d 2
1584
+ ${t} sfx generate -t "applause" -d 3
1567
1585
  \`\`\`
1568
1586
 
1569
1587
  ### Musical Stingers
1570
1588
  Short musical accents.
1571
1589
 
1572
1590
  \`\`\`bash
1573
- ${e} sfx generate -t "dramatic stinger, reveal" -d 2
1574
- ${e} sfx generate -t "tension riser, building" -d 3
1575
- ${e} sfx generate -t "cinematic drone, ominous" -d 5
1576
- ${e} sfx generate -t "success fanfare, short" -d 2
1591
+ ${t} sfx generate -t "dramatic stinger, reveal" -d 2
1592
+ ${t} sfx generate -t "tension riser, building" -d 3
1593
+ ${t} sfx generate -t "cinematic drone, ominous" -d 5
1594
+ ${t} sfx generate -t "success fanfare, short" -d 2
1577
1595
  \`\`\`
1578
1596
 
1579
1597
  ---
@@ -1582,19 +1600,19 @@ ${e} sfx generate -t "success fanfare, short" -d 2
1582
1600
 
1583
1601
  \`\`\`bash
1584
1602
  # Video transition sound
1585
- ${e} sfx generate -t "whoosh transition, fast" -d 0.5 -o transition.mp3
1603
+ ${t} sfx generate -t "whoosh transition, fast" -d 0.5 -o transition.mp3
1586
1604
 
1587
1605
  # Looping rain for video background
1588
- ${e} sfx generate -t "rain on window, cozy" -d 10 --loop -o rain-loop.mp3
1606
+ ${t} sfx generate -t "rain on window, cozy" -d 10 --loop -o rain-loop.mp3
1589
1607
 
1590
1608
  # High prompt influence (more literal)
1591
- ${e} sfx generate -t "sci-fi laser blast" --prompt-influence 0.8 -o laser.mp3
1609
+ ${t} sfx generate -t "sci-fi laser blast" --prompt-influence 0.8 -o laser.mp3
1592
1610
 
1593
1611
  # WAV format for editing
1594
- ${e} sfx generate -t "footsteps gravel" --format wav -o steps.wav
1612
+ ${t} sfx generate -t "footsteps gravel" --format wav -o steps.wav
1595
1613
 
1596
1614
  # JSON output for automation
1597
- ${e} sfx generate -t "click" -d 0.5 -f json
1615
+ ${t} sfx generate -t "click" -d 0.5 -f json
1598
1616
  \`\`\`
1599
1617
 
1600
1618
  ---
@@ -1632,7 +1650,7 @@ ${e} sfx generate -t "click" -d 0.5 -f json
1632
1650
  3. **Prompt influence** - Higher (0.7-1.0) = more literal, lower (0.1-0.3) = more creative.
1633
1651
  4. **Descriptive prompts** - Add context: "door slam, heavy wooden door" > "door slam".
1634
1652
  5. **Format** - Use WAV for editing, MP3 for final output.
1635
- `}function Me(t){let{name:n,cmd:e}=t;return`---
1653
+ `}function je(e){let{name:n,cmd:t}=e;return`---
1636
1654
  name: ${n}-mix
1637
1655
  description: Audio mixing for video production. Combine video with voiceover and background music. Supports volume control, fade effects, and multiple audio tracks.
1638
1656
  ---
@@ -1645,7 +1663,7 @@ Mix video with voiceover and background music.
1645
1663
 
1646
1664
  \`\`\`bash
1647
1665
  # Mix video + voice + music
1648
- ${e} mix create \\
1666
+ ${t} mix create \\
1649
1667
  --video input.mp4 \\
1650
1668
  --voice voiceover.mp3 \\
1651
1669
  --music background.mp3 \\
@@ -1661,7 +1679,7 @@ ${e} mix create \\
1661
1679
  Mix audio tracks with video.
1662
1680
 
1663
1681
  \`\`\`bash
1664
- ${e} mix create [options]
1682
+ ${t} mix create [options]
1665
1683
  \`\`\`
1666
1684
 
1667
1685
  **Options:**
@@ -1681,7 +1699,7 @@ ${e} mix create [options]
1681
1699
  Check status of a mix request.
1682
1700
 
1683
1701
  \`\`\`bash
1684
- ${e} mix status <request-id>
1702
+ ${t} mix status <request-id>
1685
1703
  \`\`\`
1686
1704
 
1687
1705
  ---
@@ -1708,7 +1726,7 @@ ${e} mix status <request-id>
1708
1726
 
1709
1727
  \`\`\`bash
1710
1728
  # Standard video with voiceover and music
1711
- ${e} mix create \\
1729
+ ${t} mix create \\
1712
1730
  --video video.mp4 \\
1713
1731
  --voice narration.mp3 \\
1714
1732
  --music background.mp3 \\
@@ -1717,29 +1735,29 @@ ${e} mix create \\
1717
1735
  -o final.mp4
1718
1736
 
1719
1737
  # Music only (no voiceover)
1720
- ${e} mix create \\
1738
+ ${t} mix create \\
1721
1739
  --video video.mp4 \\
1722
1740
  --music soundtrack.mp3 \\
1723
1741
  --music-volume 80 \\
1724
1742
  -o with-music.mp4
1725
1743
 
1726
1744
  # Voice only (no music)
1727
- ${e} mix create \\
1745
+ ${t} mix create \\
1728
1746
  --video video.mp4 \\
1729
1747
  --voice voiceover.mp3 \\
1730
1748
  -o with-voice.mp4
1731
1749
 
1732
1750
  # From URLs
1733
- ${e} mix create \\
1751
+ ${t} mix create \\
1734
1752
  --video https://storage.example.com/video.mp4 \\
1735
1753
  --voice https://storage.example.com/voice.mp3 \\
1736
1754
  --music https://storage.example.com/music.mp3 \\
1737
1755
  -o final.mp4
1738
1756
 
1739
1757
  # Async (large files)
1740
- ${e} mix create --video v.mp4 --music m.mp3 --no-wait
1758
+ ${t} mix create --video v.mp4 --music m.mp3 --no-wait
1741
1759
  # Returns request ID
1742
- ${e} mix status <request-id>
1760
+ ${t} mix status <request-id>
1743
1761
  \`\`\`
1744
1762
 
1745
1763
  ---
@@ -1782,7 +1800,7 @@ ${e} mix status <request-id>
1782
1800
  2. **Music selection** - Choose music that doesn't compete with voice frequency.
1783
1801
  3. **Consistent levels** - Keep voice at 100%, adjust music only.
1784
1802
  4. **File sizes** - Use \`--no-wait\` for large files to avoid timeout.
1785
- `}function Ve(t){let{name:n,cmd:e}=t;return`---
1803
+ `}function qe(e){let{name:n,cmd:t}=e;return`---
1786
1804
  name: ${n}-image
1787
1805
  description: Stock image search and AI image generation. Find royalty-free images from multiple providers or generate custom images with AI. For videos, presentations, marketing.
1788
1806
  ---
@@ -1795,10 +1813,10 @@ Search stock images and generate AI images.
1795
1813
 
1796
1814
  \`\`\`bash
1797
1815
  # Search stock images
1798
- ${e} image search -q "mountain landscape"
1816
+ ${t} image search -q "mountain landscape"
1799
1817
 
1800
1818
  # Generate AI image
1801
- ${e} image generate -p "futuristic city at sunset" -o city.png
1819
+ ${t} image generate -p "futuristic city at sunset" -o city.png --yes
1802
1820
  \`\`\`
1803
1821
 
1804
1822
  ---
@@ -1810,7 +1828,7 @@ ${e} image generate -p "futuristic city at sunset" -o city.png
1810
1828
  Search for stock images from multiple providers.
1811
1829
 
1812
1830
  \`\`\`bash
1813
- ${e} image search [options]
1831
+ ${t} image search [options]
1814
1832
  \`\`\`
1815
1833
 
1816
1834
  **Required:**
@@ -1830,18 +1848,20 @@ ${e} image search [options]
1830
1848
  Generate an AI image from a text prompt.
1831
1849
 
1832
1850
  \`\`\`bash
1833
- ${e} image generate [options]
1851
+ ${t} image generate <prompt> [options]
1834
1852
  \`\`\`
1835
1853
 
1836
1854
  **Required:**
1837
- - \`-p, --prompt <text>\` - Image description
1855
+ - image description as \`<prompt>\` or \`-p, --prompt <text>\`
1838
1856
 
1839
1857
  **Options:**
1840
1858
  | Option | Description | Default |
1841
1859
  |--------|-------------|---------|
1842
1860
  | \`-o, --output <path>\` | Output file path | - |
1843
- | \`--width <pixels>\` | Image width | \`1024\` |
1844
- | \`--height <pixels>\` | Image height | \`1024\` |
1861
+ | \`--width <pixels>\` | Image width | host default |
1862
+ | \`--height <pixels>\` | Image height | host default |
1863
+ | \`--no-wait\` | Return the request id without downloading; cannot be combined with \`--output\` | - |
1864
+ | \`--yes\` | Approve generation | required |
1845
1865
  | \`-f, --format <format>\` | Output: human, json, quiet | \`human\` |
1846
1866
 
1847
1867
  ---
@@ -1873,31 +1893,32 @@ ${e} image generate [options]
1873
1893
 
1874
1894
  \`\`\`bash
1875
1895
  # Basic search
1876
- ${e} image search -q "mountain landscape"
1896
+ ${t} image search -q "mountain landscape"
1877
1897
 
1878
1898
  # More results, large size
1879
- ${e} image search -q "business team" -n 20 --size large
1899
+ ${t} image search -q "business team" -n 20 --size large
1880
1900
 
1881
1901
  # JSON for scripting
1882
- ${e} image search -q "tech abstract" -f json > images.json
1902
+ ${t} image search -q "tech abstract" -f json > images.json
1883
1903
 
1884
1904
  # Specific style
1885
- ${e} image search -q "minimal workspace desk laptop white"
1905
+ ${t} image search -q "minimal workspace desk laptop white"
1886
1906
  \`\`\`
1887
1907
 
1888
1908
  ### AI Image Generation
1889
1909
 
1890
1910
  \`\`\`bash
1891
1911
  # Basic generation
1892
- ${e} image generate -p "futuristic city skyline at sunset" -o city.png
1912
+ ${t} image generate -p "futuristic city skyline at sunset" -o city.png --yes
1893
1913
 
1894
1914
  # Custom dimensions
1895
- ${e} image generate -p "abstract art" --width 1920 --height 1080 -o hero.png
1915
+ ${t} image generate -p "abstract art" --width 1920 --height 1080 -o hero.png --yes
1896
1916
 
1897
1917
  # Detailed prompt
1898
- ${e} image generate \\
1918
+ ${t} image generate \\
1899
1919
  -p "professional headshot, business woman, neutral background, studio lighting" \\
1900
- -o headshot.png
1920
+ -o headshot.png \\
1921
+ --yes
1901
1922
  \`\`\`
1902
1923
 
1903
1924
  ---
@@ -1966,7 +1987,7 @@ Found 10 images for "mountain landscape"
1966
1987
  3. **Size matters** - Use \`--size large\` for hero images
1967
1988
  4. **JSON for automation** - Parse results programmatically
1968
1989
  5. **Generation prompts** - Be detailed, describe style, lighting, composition
1969
- `}function je(t){let{name:n,cmd:e}=t;return`---
1990
+ `}function Be(e){let{name:n,cmd:t}=e;return`---
1970
1991
  name: ${n}-video-search
1971
1992
  description: Stock video search. Find royalty-free video clips from multiple providers (Pexels, Pixabay). For b-roll, backgrounds, transitions in video production.
1972
1993
  ---
@@ -1979,10 +2000,10 @@ Search for stock video clips.
1979
2000
 
1980
2001
  \`\`\`bash
1981
2002
  # Basic search
1982
- ${e} video find "ocean waves"
2003
+ ${t} video find "ocean waves"
1983
2004
 
1984
2005
  # With filters
1985
- ${e} video find "city timelapse" --orientation landscape --max-results 5
2006
+ ${t} video find "city timelapse" --orientation landscape --max-results 5
1986
2007
  \`\`\`
1987
2008
 
1988
2009
  ---
@@ -1994,7 +2015,7 @@ ${e} video find "city timelapse" --orientation landscape --max-results 5
1994
2015
  Search for stock video clips.
1995
2016
 
1996
2017
  \`\`\`bash
1997
- ${e} video find <query> [options]
2018
+ ${t} video find <query> [options]
1998
2019
  \`\`\`
1999
2020
 
2000
2021
  **Required:**
@@ -2035,22 +2056,22 @@ ${e} video find <query> [options]
2035
2056
 
2036
2057
  \`\`\`bash
2037
2058
  # B-roll for tech video
2038
- ${e} video find "typing on laptop" --orientation landscape -n 5
2059
+ ${t} video find "typing on laptop" --orientation landscape -n 5
2039
2060
 
2040
2061
  # Background for presentation
2041
- ${e} video find "abstract particles dark" --orientation landscape
2062
+ ${t} video find "abstract particles dark" --orientation landscape
2042
2063
 
2043
2064
  # Aerial footage
2044
- ${e} video find "drone city skyline sunset" -n 10
2065
+ ${t} video find "drone city skyline sunset" -n 10
2045
2066
 
2046
2067
  # Vertical for social media
2047
- ${e} video find "coffee pouring" --orientation portrait
2068
+ ${t} video find "coffee pouring" --orientation portrait
2048
2069
 
2049
2070
  # JSON for automation
2050
- ${e} video find "ocean waves" -f json > videos.json
2071
+ ${t} video find "ocean waves" -f json > videos.json
2051
2072
 
2052
2073
  # Free license only
2053
- ${e} video find "business meeting" --license free
2074
+ ${t} video find "business meeting" --license free
2054
2075
  \`\`\`
2055
2076
 
2056
2077
  ---
@@ -2114,10 +2135,10 @@ Found 5 videos for "ocean waves"
2114
2135
 
2115
2136
  \`\`\`bash
2116
2137
  # 1. Search for b-roll
2117
- ${e} video find "tech startup office" -f json > broll.json
2138
+ ${t} video find "tech startup office" -f json > broll.json
2118
2139
 
2119
2140
  # 2. Use with video generate assets
2120
- cat scenes.json | ${e} video generate assets --output ./public
2141
+ cat scenes.json | ${t} video generate assets --output ./public
2121
2142
 
2122
2143
  # 3. Or download manually and use in Remotion
2123
2144
  \`\`\`
@@ -2126,10 +2147,10 @@ cat scenes.json | ${e} video generate assets --output ./public
2126
2147
 
2127
2148
  \`\`\`bash
2128
2149
  # TikTok/Reels (vertical)
2129
- ${e} video find "coffee making" --orientation portrait -n 5
2150
+ ${t} video find "coffee making" --orientation portrait -n 5
2130
2151
 
2131
2152
  # YouTube (landscape)
2132
- ${e} video find "city timelapse" --orientation landscape -n 10
2153
+ ${t} video find "city timelapse" --orientation landscape -n 10
2133
2154
  \`\`\`
2134
2155
 
2135
2156
  ---
@@ -2141,7 +2162,7 @@ ${e} video find "city timelapse" --orientation landscape -n 10
2141
2162
  3. **Preview first** - Use preview URLs to check quality
2142
2163
  4. **License** - Verify license for commercial use
2143
2164
  5. **JSON export** - Save searches for batch processing
2144
- `}function qe(t){let{name:n,cmd:e}=t;return`---
2165
+ `}function Ge(e){let{name:n,cmd:t}=e;return`---
2145
2166
  name: ${n}-scrape
2146
2167
  description: Scrape any URL the user provides. Use when user says "check this site", "look at this URL", "use this website", "here's the link", or shares any URL for context. Supports websites, YouTube, Twitter/X.
2147
2168
  ---
@@ -2154,13 +2175,13 @@ Extract content from URLs for analysis and context.
2154
2175
 
2155
2176
  \`\`\`bash
2156
2177
  # Scrape website
2157
- ${e} scrape https://example.com
2178
+ ${t} scrape https://example.com
2158
2179
 
2159
2180
  # Scrape YouTube video (transcript)
2160
- ${e} scrape https://youtube.com/watch?v=abc123
2181
+ ${t} scrape https://youtube.com/watch?v=abc123
2161
2182
 
2162
2183
  # Scrape Twitter/X post
2163
- ${e} scrape https://x.com/user/status/123456
2184
+ ${t} scrape https://x.com/user/status/123456
2164
2185
  \`\`\`
2165
2186
 
2166
2187
  ---
@@ -2172,7 +2193,7 @@ ${e} scrape https://x.com/user/status/123456
2172
2193
  Extract content from a URL.
2173
2194
 
2174
2195
  \`\`\`bash
2175
- ${e} scrape <url> [options]
2196
+ ${t} scrape <url> [options]
2176
2197
  \`\`\`
2177
2198
 
2178
2199
  **Required:**
@@ -2192,25 +2213,25 @@ ${e} scrape <url> [options]
2192
2213
  Extracts main content, headings, metadata.
2193
2214
 
2194
2215
  \`\`\`bash
2195
- ${e} scrape https://company.com/about
2196
- ${e} scrape https://docs.example.com/guide
2197
- ${e} scrape https://blog.example.com/post
2216
+ ${t} scrape https://company.com/about
2217
+ ${t} scrape https://docs.example.com/guide
2218
+ ${t} scrape https://blog.example.com/post
2198
2219
  \`\`\`
2199
2220
 
2200
2221
  ### YouTube Videos
2201
2222
  Extracts transcript, title, description, channel info.
2202
2223
 
2203
2224
  \`\`\`bash
2204
- ${e} scrape https://youtube.com/watch?v=abc123
2205
- ${e} scrape https://youtu.be/abc123
2225
+ ${t} scrape https://youtube.com/watch?v=abc123
2226
+ ${t} scrape https://youtu.be/abc123
2206
2227
  \`\`\`
2207
2228
 
2208
2229
  ### Twitter/X Posts
2209
2230
  Extracts tweet text, author info, media URLs.
2210
2231
 
2211
2232
  \`\`\`bash
2212
- ${e} scrape https://twitter.com/user/status/123456
2213
- ${e} scrape https://x.com/user/status/123456
2233
+ ${t} scrape https://twitter.com/user/status/123456
2234
+ ${t} scrape https://x.com/user/status/123456
2214
2235
  \`\`\`
2215
2236
 
2216
2237
  ---
@@ -2219,22 +2240,22 @@ ${e} scrape https://x.com/user/status/123456
2219
2240
 
2220
2241
  \`\`\`bash
2221
2242
  # Basic scrape
2222
- ${e} scrape https://example.com
2243
+ ${t} scrape https://example.com
2223
2244
 
2224
2245
  # Save to file
2225
- ${e} scrape https://company.com/about -o about.md
2246
+ ${t} scrape https://company.com/about -o about.md
2226
2247
 
2227
2248
  # JSON output (for programmatic use)
2228
- ${e} scrape https://docs.example.com -f json > doc.json
2249
+ ${t} scrape https://docs.example.com -f json > doc.json
2229
2250
 
2230
2251
  # Quiet mode (content only, no metadata)
2231
- ${e} scrape https://blog.example.com -f quiet > content.txt
2252
+ ${t} scrape https://blog.example.com -f quiet > content.txt
2232
2253
 
2233
2254
  # YouTube transcript
2234
- ${e} scrape https://youtube.com/watch?v=abc123 -o transcript.md
2255
+ ${t} scrape https://youtube.com/watch?v=abc123 -o transcript.md
2235
2256
 
2236
2257
  # Twitter thread
2237
- ${e} scrape https://x.com/user/status/123456
2258
+ ${t} scrape https://x.com/user/status/123456
2238
2259
  \`\`\`
2239
2260
 
2240
2261
  ---
@@ -2288,38 +2309,38 @@ Outputs only the content (markdown), no metadata. Ideal for piping.
2288
2309
 
2289
2310
  \`\`\`bash
2290
2311
  # Gather context from multiple sources
2291
- ${e} scrape https://company.com/product -o product.md
2292
- ${e} scrape https://company.com/about -o about.md
2312
+ ${t} scrape https://company.com/product -o product.md
2313
+ ${t} scrape https://company.com/about -o about.md
2293
2314
 
2294
2315
  # Use in presentation
2295
- ${e} create "Product Overview" --file product.md --file about.md
2316
+ ${t} create "Product Overview" --file product.md --file about.md
2296
2317
  \`\`\`
2297
2318
 
2298
2319
  ### Research & Analysis
2299
2320
 
2300
2321
  \`\`\`bash
2301
2322
  # Scrape competitor
2302
- ${e} scrape https://competitor.com/features -f json > competitor.json
2323
+ ${t} scrape https://competitor.com/features -f json > competitor.json
2303
2324
 
2304
2325
  # Scrape documentation
2305
- ${e} scrape https://docs.example.com/api -o api-docs.md
2326
+ ${t} scrape https://docs.example.com/api -o api-docs.md
2306
2327
  \`\`\`
2307
2328
 
2308
2329
  ### Video Script from YouTube
2309
2330
 
2310
2331
  \`\`\`bash
2311
2332
  # Get transcript
2312
- ${e} scrape https://youtube.com/watch?v=abc123 -o transcript.md
2333
+ ${t} scrape https://youtube.com/watch?v=abc123 -o transcript.md
2313
2334
 
2314
2335
  # Use for presentation
2315
- ${e} create "Video Summary" --file transcript.md
2336
+ ${t} create "Video Summary" --file transcript.md
2316
2337
  \`\`\`
2317
2338
 
2318
2339
  ### Content Pipeline
2319
2340
 
2320
2341
  \`\`\`bash
2321
2342
  # Scrape and pipe directly
2322
- ${e} scrape https://blog.example.com -f quiet | ${e} create "Blog Summary"
2343
+ ${t} scrape https://blog.example.com -f quiet | ${t} create "Blog Summary"
2323
2344
  \`\`\`
2324
2345
 
2325
2346
  ---
@@ -2331,7 +2352,7 @@ ${e} scrape https://blog.example.com -f quiet | ${e} create "Blog Summary"
2331
2352
  3. **Use JSON** - For programmatic processing of results
2332
2353
  4. **Combine sources** - Scrape multiple URLs for comprehensive context
2333
2354
  5. **Token count** - Check token usage for large documents
2334
- `}function Be(t){let{name:n,cmd:e}=t;return`---
2355
+ `}function We(e){let{name:n,cmd:t}=e;return`---
2335
2356
  name: ${n}-branding
2336
2357
  description: Brand profile management. Extract branding from websites, manage saved brands, apply consistent styling to presentations.
2337
2358
  ---
@@ -2343,9 +2364,9 @@ Manage brand profiles for consistent styling across presentations.
2343
2364
  ## Quick Start
2344
2365
 
2345
2366
  \`\`\`bash
2346
- ${e} branding list # List saved brands
2347
- ${e} branding extract https://company.com # Extract from website
2348
- ${e} create "Topic" --brand my-company # Use in presentation
2367
+ ${t} branding list # List saved brands
2368
+ ${t} branding extract https://company.com # Extract from website
2369
+ ${t} create "Topic" --brand my-company # Use in presentation
2349
2370
  \`\`\`
2350
2371
 
2351
2372
  ---
@@ -2357,8 +2378,8 @@ ${e} create "Topic" --brand my-company # Use in presentation
2357
2378
  List all saved brand profiles.
2358
2379
 
2359
2380
  \`\`\`bash
2360
- ${e} branding list
2361
- ${e} branding list -f json
2381
+ ${t} branding list
2382
+ ${t} branding list -f json
2362
2383
  \`\`\`
2363
2384
 
2364
2385
  ### \`branding find\`
@@ -2366,17 +2387,17 @@ ${e} branding list -f json
2366
2387
  Search existing brand profiles by name or website URL. **Always try this before extracting.**
2367
2388
 
2368
2389
  \`\`\`bash
2369
- ${e} branding find <query>
2390
+ ${t} branding find <query>
2370
2391
  \`\`\`
2371
2392
 
2372
- Prints matching brands with IDs, colors, and source URLs. Use \`${e} branding get <id> -o branding.json\` to export a match.
2393
+ Prints matching brands with IDs, colors, and source URLs. Use \`${t} branding get <id> -o branding.json\` to export a match.
2373
2394
 
2374
2395
  ### \`branding extract\`
2375
2396
 
2376
2397
  Extract branding (colors, logos, fonts) from a website. **Only use if \`branding find\` returns no results.**
2377
2398
 
2378
2399
  \`\`\`bash
2379
- ${e} branding extract <url>
2400
+ ${t} branding extract <url>
2380
2401
  \`\`\`
2381
2402
 
2382
2403
  **Extracts:**
@@ -2392,8 +2413,8 @@ ${e} branding extract <url>
2392
2413
  Get details of a specific brand.
2393
2414
 
2394
2415
  \`\`\`bash
2395
- ${e} branding get <brand-id>
2396
- ${e} branding get <brand-id> -f json
2416
+ ${t} branding get <brand-id>
2417
+ ${t} branding get <brand-id> -f json
2397
2418
  \`\`\`
2398
2419
 
2399
2420
  ### \`branding set-default\`
@@ -2401,7 +2422,7 @@ ${e} branding get <brand-id> -f json
2401
2422
  Set a brand as default for new presentations.
2402
2423
 
2403
2424
  \`\`\`bash
2404
- ${e} branding set-default <brand-id>
2425
+ ${t} branding set-default <brand-id>
2405
2426
  \`\`\`
2406
2427
 
2407
2428
  ---
@@ -2410,27 +2431,27 @@ ${e} branding set-default <brand-id>
2410
2431
 
2411
2432
  \`\`\`bash
2412
2433
  # Search for existing brand first (ALWAYS do this before extracting)
2413
- ${e} branding find Acme
2414
- ${e} branding find acme.com
2434
+ ${t} branding find Acme
2435
+ ${t} branding find acme.com
2415
2436
 
2416
2437
  # Export a found brand to file by ID
2417
- ${e} branding get <id> -o branding.json
2438
+ ${t} branding get <id> -o branding.json
2418
2439
 
2419
2440
  # Only extract if find returns nothing
2420
- ${e} branding extract https://company.com
2441
+ ${t} branding extract https://company.com
2421
2442
  # Returns brand ID
2422
2443
 
2423
2444
  # List all brands
2424
- ${e} branding list
2445
+ ${t} branding list
2425
2446
 
2426
2447
  # Get brand details
2427
- ${e} branding get abc123
2448
+ ${t} branding get abc123
2428
2449
 
2429
2450
  # Use brand in presentation
2430
- ${e} create "Quarterly Report" --brand abc123
2451
+ ${t} create "Quarterly Report" --brand abc123
2431
2452
 
2432
2453
  # Set as default
2433
- ${e} branding set-default abc123
2454
+ ${t} branding set-default abc123
2434
2455
  \`\`\`
2435
2456
 
2436
2457
  ---
@@ -2441,7 +2462,7 @@ ${e} branding set-default abc123
2441
2462
  2. **If extraction fails** \u2014 Proceed without branding. Do not manually create brand assets.
2442
2463
  3. **Set default** \u2014 If you mostly work with one brand, set it as default.
2443
2464
  4. **Override** \u2014 Use \`--brand\` flag to override default for specific presentations.
2444
- `}function Ge(t){let{name:n,cmd:e}=t,o=n.toUpperCase().replace(/[^A-Z0-9]/g,"_");return`---
2465
+ `}function He(e){let{name:n,cmd:t}=e,o=n.toUpperCase().replace(/[^A-Z0-9]/g,"_");return`---
2445
2466
  name: ${n}-config
2446
2467
  description: CLI configuration management. Set API keys, team IDs, custom API URLs. Verify authentication status.
2447
2468
  ---
@@ -2453,9 +2474,9 @@ Manage CLI settings and authentication.
2453
2474
  ## Quick Start
2454
2475
 
2455
2476
  \`\`\`bash
2456
- ${e} config init # Interactive setup
2457
- ${e} config show # Show current config
2458
- ${e} config show --verify # Verify API key works
2477
+ ${t} config init # Interactive setup
2478
+ ${t} config show # Show current config
2479
+ ${t} config show --verify # Verify API key works
2459
2480
  \`\`\`
2460
2481
 
2461
2482
  ---
@@ -2467,7 +2488,7 @@ ${e} config show --verify # Verify API key works
2467
2488
  Interactive configuration wizard.
2468
2489
 
2469
2490
  \`\`\`bash
2470
- ${e} config init
2491
+ ${t} config init
2471
2492
  \`\`\`
2472
2493
 
2473
2494
  Guides you through setting up API key and preferences.
@@ -2477,9 +2498,9 @@ Guides you through setting up API key and preferences.
2477
2498
  Display current configuration.
2478
2499
 
2479
2500
  \`\`\`bash
2480
- ${e} config show
2481
- ${e} config show --verify # Also verify API key
2482
- ${e} config show -f json
2501
+ ${t} config show
2502
+ ${t} config show --verify # Also verify API key
2503
+ ${t} config show -f json
2483
2504
  \`\`\`
2484
2505
 
2485
2506
  ### \`config set\`
@@ -2487,7 +2508,7 @@ ${e} config show -f json
2487
2508
  Set a configuration value.
2488
2509
 
2489
2510
  \`\`\`bash
2490
- ${e} config set <key> <value>
2511
+ ${t} config set <key> <value>
2491
2512
  \`\`\`
2492
2513
 
2493
2514
  **Available keys:**
@@ -2502,7 +2523,7 @@ ${e} config set <key> <value>
2502
2523
  Clear all configuration.
2503
2524
 
2504
2525
  \`\`\`bash
2505
- ${e} config clear
2526
+ ${t} config clear
2506
2527
  \`\`\`
2507
2528
 
2508
2529
  ### \`config path\`
@@ -2510,7 +2531,7 @@ ${e} config clear
2510
2531
  Show config file location.
2511
2532
 
2512
2533
  \`\`\`bash
2513
- ${e} config path
2534
+ ${t} config path
2514
2535
  \`\`\`
2515
2536
 
2516
2537
  ---
@@ -2532,23 +2553,23 @@ export ${o}_API_URL="https://custom-api.example.com"
2532
2553
 
2533
2554
  \`\`\`bash
2534
2555
  # Initial setup
2535
- ${e} config init
2556
+ ${t} config init
2536
2557
 
2537
2558
  # Set API key manually
2538
- ${e} config set api-key sk-abc123
2559
+ ${t} config set api-key sk-abc123
2539
2560
 
2540
2561
  # Set team for multi-team accounts
2541
- ${e} config set team-id team_xyz
2562
+ ${t} config set team-id team_xyz
2542
2563
 
2543
2564
  # Verify everything works
2544
- ${e} config show --verify
2565
+ ${t} config show --verify
2545
2566
 
2546
2567
  # Check who you're logged in as
2547
- ${e} whoami
2568
+ ${t} whoami
2548
2569
 
2549
2570
  # Clear and start fresh
2550
- ${e} config clear
2551
- ${e} login
2571
+ ${t} config clear
2572
+ ${t} login
2552
2573
  \`\`\`
2553
2574
 
2554
2575
  ---
@@ -2557,9 +2578,9 @@ ${e} login
2557
2578
 
2558
2579
  | OS | Path |
2559
2580
  |----|------|
2560
- | macOS | \`~/.config/${e}/config.json\` |
2561
- | Linux | \`~/.config/${e}/config.json\` |
2562
- | Windows | \`%APPDATA%\\${e}\\config.json\` |
2581
+ | macOS | \`~/.config/${t}/config.json\` |
2582
+ | Linux | \`~/.config/${t}/config.json\` |
2583
+ | Windows | \`%APPDATA%\\${t}\\config.json\` |
2563
2584
 
2564
2585
  ---
2565
2586
 
@@ -2568,7 +2589,7 @@ ${e} login
2568
2589
  ### 1. OAuth Login (Recommended)
2569
2590
 
2570
2591
  \`\`\`bash
2571
- ${e} login
2592
+ ${t} login
2572
2593
  \`\`\`
2573
2594
 
2574
2595
  Opens browser for secure OAuth flow. Tokens are stored securely.
@@ -2576,7 +2597,7 @@ Opens browser for secure OAuth flow. Tokens are stored securely.
2576
2597
  ### 2. API Key
2577
2598
 
2578
2599
  \`\`\`bash
2579
- ${e} config set api-key <your-key>
2600
+ ${t} config set api-key <your-key>
2580
2601
  # or
2581
2602
  export ${o}_API_KEY="your-key"
2582
2603
  \`\`\`
@@ -2589,21 +2610,21 @@ Get API key from your account settings.
2589
2610
 
2590
2611
  **"Not authenticated" error:**
2591
2612
  \`\`\`bash
2592
- ${e} whoami # Check if logged in
2593
- ${e} login # Re-authenticate
2613
+ ${t} whoami # Check if logged in
2614
+ ${t} login # Re-authenticate
2594
2615
  \`\`\`
2595
2616
 
2596
2617
  **API key not working:**
2597
2618
  \`\`\`bash
2598
- ${e} config show --verify # Test API key
2619
+ ${t} config show --verify # Test API key
2599
2620
  \`\`\`
2600
2621
 
2601
2622
  **Wrong team:**
2602
2623
  \`\`\`bash
2603
- ${e} config set team-id <correct-team-id>
2624
+ ${t} config set team-id <correct-team-id>
2604
2625
  \`\`\`
2605
- `}var kn={name:"video-ref-website-assets",description:"Extract maximum assets from websites for video production.",render:t=>`---
2606
- name: ${t.name}-video-ref-website-assets
2626
+ `}var Nn={name:"video-ref-website-assets",description:"Extract maximum assets from websites for video production.",render:e=>`---
2627
+ name: ${e.name}-video-ref-website-assets
2607
2628
  description: Extract maximum assets from websites for video production.
2608
2629
  ---
2609
2630
 
@@ -2618,7 +2639,7 @@ Branding is handled by the \`video-branding-director\` agent (Step 4). Do not ex
2618
2639
  ## Content
2619
2640
 
2620
2641
  \`\`\`bash
2621
- ${t.cmd} scrape <url> -o page.md
2642
+ ${e.cmd} scrape <url> -o page.md
2622
2643
  \`\`\`
2623
2644
 
2624
2645
  Scrape multiple pages:
@@ -2673,8 +2694,8 @@ agent-browser screenshot --path ./screenshots/hero.png
2673
2694
  **Images 403/404** - may need referrer header: \`curl -e <site-url> -O <image-url>\`
2674
2695
 
2675
2696
  **Lazy-loaded images** - use agent-browser to scroll and capture, or inspect network tab for actual URLs.
2676
- `};var Rn={name:"video-ref-brief-guide",description:"How to write video brief for server-side plan generation.",render:t=>`---
2677
- name: ${t.name}-video-ref-brief-guide
2697
+ `};var Dn={name:"video-ref-brief-guide",description:"How to write video brief for server-side plan generation.",render:e=>`---
2698
+ name: ${e.name}-video-ref-brief-guide
2678
2699
  description: How to write video brief for server-side plan generation.
2679
2700
  ---
2680
2701
 
@@ -2734,19 +2755,19 @@ These will be rebuilt as lightweight animated versions for Remotion. Focus on vi
2734
2755
  ---
2735
2756
 
2736
2757
  **IMPORTANT:** The brief contains ONLY the 6 sections above. Do NOT add "Suggested Scenes", "Scene Breakdown", or any other sections \u2014 scene planning happens server-side via \`video generate plan\`.
2737
- `};var An={name:"video-ref-source-scraping",description:"Extract content from various sources (YouTube, websites, Twitter).",render:t=>`---
2738
- name: ${t.name}-video-ref-source-scraping
2758
+ `};var Ln={name:"video-ref-source-scraping",description:"Extract content from various sources (YouTube, websites, Twitter).",render:e=>`---
2759
+ name: ${e.name}-video-ref-source-scraping
2739
2760
  description: Extract content from various sources (YouTube, websites, Twitter).
2740
2761
  ---
2741
2762
 
2742
2763
  # Source Scraping
2743
2764
 
2744
- The \`${t.cmd} scrape\` command automatically detects source type and extracts content.
2765
+ The \`${e.cmd} scrape\` command automatically detects source type and extracts content.
2745
2766
 
2746
2767
  ## YouTube Videos
2747
2768
 
2748
2769
  \`\`\`bash
2749
- ${t.cmd} scrape <youtube-url>
2770
+ ${e.cmd} scrape <youtube-url>
2750
2771
  \`\`\`
2751
2772
 
2752
2773
  Extracts: transcript, title, description, channel info
@@ -2754,7 +2775,7 @@ Extracts: transcript, title, description, channel info
2754
2775
  ## Websites
2755
2776
 
2756
2777
  \`\`\`bash
2757
- ${t.cmd} scrape <website-url>
2778
+ ${e.cmd} scrape <website-url>
2758
2779
  \`\`\`
2759
2780
 
2760
2781
  Extracts: content, headings, metadata
@@ -2762,7 +2783,7 @@ Extracts: content, headings, metadata
2762
2783
  ## Twitter/X Posts
2763
2784
 
2764
2785
  \`\`\`bash
2765
- ${t.cmd} scrape <twitter-url>
2786
+ ${e.cmd} scrape <twitter-url>
2766
2787
  \`\`\`
2767
2788
 
2768
2789
  Extracts: tweet text, author info, media URLs
@@ -2770,19 +2791,19 @@ Extracts: tweet text, author info, media URLs
2770
2791
  ---
2771
2792
 
2772
2793
  All scraped content is returned in markdown format.
2773
- `};import{existsSync as We,mkdirSync as Lt,rmSync as Pr,writeFileSync as Ft}from"fs";import{homedir as Ut}from"os";import{basename as Nr,join as Q,relative as Ps,resolve as ke}from"path";var pe=[{name:"Claude Code",dir:".claude",provider:"claude"},{name:"GitHub Copilot",dir:".github",agentSuffix:".agent.md",provider:"copilot"},{name:"Cursor",dir:".cursor"},{name:"Codex",dir:".codex",agentSuffix:".toml",provider:"codex"},{name:"OpenCode",dir:".opencode"},{name:"Windsurf",dir:".windsurf"},{name:"Agent",dir:".agent"}];var Ns={sonnet:"claude-sonnet-4.6",haiku:"claude-haiku-4.5",opus:"claude-opus-4.6"},Ds=["permissionMode","skills","subagentType"];function Ls(t){let n=t.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(!n)return`developer_instructions = """
2774
- ${t.replace(/"""/g,'\\"\\"\\"').trim()}
2794
+ `};import{existsSync as Je,mkdirSync as Mt,rmSync as Jr,writeFileSync as jt}from"fs";import{homedir as qt}from"os";import{basename as zr,join as ee,relative as pc,resolve as Ae}from"path";var he=[{name:"Claude Code",dir:".claude",provider:"claude"},{name:"GitHub Copilot",dir:".github",agentSuffix:".agent.md",provider:"copilot"},{name:"Cursor",dir:".cursor"},{name:"Codex",dir:".codex",agentSuffix:".toml",provider:"codex"},{name:"OpenCode",dir:".opencode"},{name:"Windsurf",dir:".windsurf"},{name:"Agent",dir:".agent"}];var gc={sonnet:"claude-sonnet-4.6",haiku:"claude-haiku-4.5",opus:"claude-opus-4.6"},fc=["permissionMode","skills","subagentType"];function hc(e){let n=e.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(!n)return`developer_instructions = """
2795
+ ${e.replace(/"""/g,'\\"\\"\\"').trim()}
2775
2796
  """
2776
- `;let e=n[1],o=n[2].trim(),r=d=>e.match(new RegExp(`^${d}:\\s*(.+)$`,"m"))?.[1]?.trim().replace(/^["']|["']$/g,""),i=r("name")??"",a=r("description")??"",s=o.replace(/"""/g,'\\"\\"\\"');return`${[`name = ${JSON.stringify(i)}`,`description = ${JSON.stringify(a)}`,`developer_instructions = """
2797
+ `;let t=n[1],o=n[2].trim(),r=u=>t.match(new RegExp(`^${u}:\\s*(.+)$`,"m"))?.[1]?.trim().replace(/^["']|["']$/g,""),i=r("name")??"",a=r("description")??"",s=o.replace(/"""/g,'\\"\\"\\"');return`${[`name = ${JSON.stringify(i)}`,`description = ${JSON.stringify(a)}`,`developer_instructions = """
2777
2798
  ${s}
2778
2799
  """`].join(`
2779
2800
  `)}
2780
- `}function Dr(t,n){if(n!=="copilot")return t;let e=t.match(/^---\n([\s\S]*?)\n---\n/);if(!e)return Er(t);let o=e[1],r=t.slice((e.index??0)+e[0].length);o=o.replace(/^(model:\s*)(\S+)([ \t]*)$/m,(a,s,l,d)=>`${s}${Ns[l]??l}${d}`);for(let a of Ds)o=o.replace(new RegExp(`^${a}:[^
2801
+ `}function Xr(e,n){if(n!=="copilot")return e;let t=e.match(/^---\n([\s\S]*?)\n---\n/);if(!t)return Wr(e);let o=t[1],r=e.slice((t.index??0)+t[0].length);o=o.replace(/^(model:\s*)(\S+)([ \t]*)$/m,(a,s,d,u)=>`${s}${gc[d]??d}${u}`);for(let a of fc)o=o.replace(new RegExp(`^${a}:[^
2781
2802
  ]*
2782
- ?`,"m"),"");o=o.replace(/\n+$/,"");let i=Er(r);return`---
2803
+ ?`,"m"),"");o=o.replace(/\n+$/,"");let i=Wr(r);return`---
2783
2804
  ${o}
2784
2805
  ---
2785
- ${i}`}function $r(t,n){return n==="codex"?Ls(t):Dr(t,n)}function Er(t){return t.replace(/\bAskUserQuestion\b/g,"ask the user directly in your response").replace(/\*\*Construct the Task prompt:\*\*/g,"**Construct the Task prompt (must be fully self-contained \u2014 sub-agents cannot read this conversation's history):**").replace(/\*\*Wait for all agents to complete\*\*/g,"**Wait for all agents to complete** (monitor with `/tasks` in Copilot CLI)").replace("**Launch ALL scene agents in parallel**","**Launch ALL scene agents in parallel** \u2014 each agent must write to its own `Scene[NN][Name].tsx` file. Two agents writing to the same file will silently overwrite each other (no error). Verify unique filenames before spawning.")}function Fs(t,n){let e=ke(t),o=ke(t,n);if(Ps(e,o).startsWith("..")||ke(o)!==o.replace(/\.\./g,""))throw new Error(`Invalid path: "${n}" would escape base directory`);return o}function Or(t,n,e,o){let r=Q(t,"SKILL.md");if(Lt(t,{recursive:!0}),Ft(r,Dr(n,o),"utf-8"),e&&e.length>0){let i=Q(t,"references");Lt(i,{recursive:!0});for(let a of e){let s=Q(i,`${a.name}.md`);Ft(s,a.content,"utf-8")}}}function _t(t,n,e={},o){let r={installed:[],skipped:[],errors:[]},i=e.local?process.cwd():Ut();if(e.dir){let a=Nr(ke(e.dir)),s=pe.find(l=>l.dir===a)?.provider;try{let l=ke(e.dir),d=Fs(l,Q("skills",t));Or(d,n,o,s),r.installed.push(e.dir)}catch(l){r.errors.push(`${e.dir}: ${l instanceof Error?l.message:String(l)}`)}}else for(let a of pe){let s=Q(i,a.dir),l=Q(s,"skills",t),d=Q(l,"SKILL.md");if(We(s)){if(We(d)&&!e.force){r.skipped.push(a.name);continue}try{Or(l,n,o,a.provider),r.installed.push(a.name)}catch(f){r.errors.push(`${a.name}: ${f instanceof Error?f.message:String(f)}`)}}}return r}function Mt(t,n={}){let e={removed:[],errors:[]},o=n.local?process.cwd():Ut();for(let r of pe){let i=Q(o,r.dir,"skills",t);if(We(i))try{Pr(i,{recursive:!0}),e.removed.push(r.name)}catch(a){e.errors.push(`${r.name}: ${a instanceof Error?a.message:String(a)}`)}}return e}function Lr(){return pe.map(t=>t.name)}function Fr(t,n,e={}){let o={installed:[],skipped:[],errors:[]};if(e.dir){let a=Nr(ke(e.dir)),s=pe.find(v=>v.dir===a),l=s?.agentSuffix??".md",d=Q(ke(e.dir),"agents"),f=Q(d,`${t}${l}`);if(We(f)&&!e.force)o.skipped.push(e.dir);else try{Lt(d,{recursive:!0}),Ft(f,$r(n,s?.provider),"utf-8"),o.installed.push(e.dir)}catch(v){o.errors.push(`${e.dir}: ${v instanceof Error?v.message:String(v)}`)}return o}let r=Ut(),i=pe.filter(a=>a.dir===".claude"||a.dir===".github"||a.dir===".codex");for(let a of i){let s=a.agentSuffix??".md",l=Q(r,a.dir,"agents"),d=Q(l,`${t}${s}`);if(We(d)&&!e.force){o.skipped.push(a.name);continue}try{Lt(l,{recursive:!0}),Ft(d,$r(n,a.provider),"utf-8"),o.installed.push(a.name)}catch(f){o.errors.push(`${a.name}: ${f instanceof Error?f.message:String(f)}`)}}return o}function Ur(t){let n={removed:[],errors:[]},e=Ut(),o=pe.filter(r=>r.dir===".claude"||r.dir===".github"||r.dir===".codex");for(let r of o){let i=r.agentSuffix??".md",a=Q(e,r.dir,"agents",`${t}${i}`);if(We(a))try{Pr(a),n.removed.push(r.name)}catch(s){n.errors.push(`${r.name}: ${s instanceof Error?s.message:String(s)}`)}}return n}function $n(){return`---
2806
+ ${i}`}function Gr(e,n){return n==="codex"?hc(e):Xr(e,n)}function Wr(e){return e.replace(/\bAskUserQuestion\b/g,"ask the user directly in your response").replace(/\*\*Construct the Task prompt:\*\*/g,"**Construct the Task prompt (must be fully self-contained \u2014 sub-agents cannot read this conversation's history):**").replace(/\*\*Wait for all agents to complete\*\*/g,"**Wait for all agents to complete** (monitor with `/tasks` in Copilot CLI)").replace("**Launch ALL scene agents in parallel**","**Launch ALL scene agents in parallel** \u2014 each agent must write to its own `Scene[NN][Name].tsx` file. Two agents writing to the same file will silently overwrite each other (no error). Verify unique filenames before spawning.")}function yc(e,n){let t=Ae(e),o=Ae(e,n);if(pc(t,o).startsWith("..")||Ae(o)!==o.replace(/\.\./g,""))throw new Error(`Invalid path: "${n}" would escape base directory`);return o}function Hr(e,n,t,o){let r=ee(e,"SKILL.md");if(Mt(e,{recursive:!0}),jt(r,Xr(n,o),"utf-8"),t&&t.length>0){let i=ee(e,"references");Mt(i,{recursive:!0});for(let a of t){let s=ee(i,`${a.name}.md`);jt(s,a.content,"utf-8")}}}function Bt(e,n,t={},o){let r={installed:[],skipped:[],errors:[]},i=t.local?process.cwd():qt();if(t.dir){let a=zr(Ae(t.dir)),s=he.find(d=>d.dir===a)?.provider;try{let d=Ae(t.dir),u=yc(d,ee("skills",e));Hr(u,n,o,s),r.installed.push(t.dir)}catch(d){r.errors.push(`${t.dir}: ${d instanceof Error?d.message:String(d)}`)}}else for(let a of he){let s=ee(i,a.dir),d=ee(s,"skills",e),u=ee(d,"SKILL.md");if(Je(s)){if(Je(u)&&!t.force){r.skipped.push(a.name);continue}try{Hr(d,n,o,a.provider),r.installed.push(a.name)}catch(p){r.errors.push(`${a.name}: ${p instanceof Error?p.message:String(p)}`)}}}return r}function Gt(e,n={}){let t={removed:[],errors:[]},o=n.local?process.cwd():qt();for(let r of he){let i=ee(o,r.dir,"skills",e);if(Je(i))try{Jr(i,{recursive:!0}),t.removed.push(r.name)}catch(a){t.errors.push(`${r.name}: ${a instanceof Error?a.message:String(a)}`)}}return t}function Yr(){return he.map(e=>e.name)}function Kr(e,n,t={}){let o={installed:[],skipped:[],errors:[]};if(t.dir){let a=zr(Ae(t.dir)),s=he.find(w=>w.dir===a),d=s?.agentSuffix??".md",u=ee(Ae(t.dir),"agents"),p=ee(u,`${e}${d}`);if(Je(p)&&!t.force)o.skipped.push(t.dir);else try{Mt(u,{recursive:!0}),jt(p,Gr(n,s?.provider),"utf-8"),o.installed.push(t.dir)}catch(w){o.errors.push(`${t.dir}: ${w instanceof Error?w.message:String(w)}`)}return o}let r=qt(),i=he.filter(a=>a.dir===".claude"||a.dir===".github"||a.dir===".codex");for(let a of i){let s=a.agentSuffix??".md",d=ee(r,a.dir,"agents"),u=ee(d,`${e}${s}`);if(Je(u)&&!t.force){o.skipped.push(a.name);continue}try{Mt(d,{recursive:!0}),jt(u,Gr(n,a.provider),"utf-8"),o.installed.push(a.name)}catch(p){o.errors.push(`${a.name}: ${p instanceof Error?p.message:String(p)}`)}}return o}function Qr(e){let n={removed:[],errors:[]},t=qt(),o=he.filter(r=>r.dir===".claude"||r.dir===".github"||r.dir===".codex");for(let r of o){let i=r.agentSuffix??".md",a=ee(t,r.dir,"agents",`${e}${i}`);if(Je(a))try{Jr(a),n.removed.push(r.name)}catch(s){n.errors.push(`${r.name}: ${s instanceof Error?s.message:String(s)}`)}}return n}function Un(){return`---
2786
2807
  name: video-scene-reviewer
2787
2808
  description: Strict QA reviewer for a single Remotion scene. Compares code against the video plan checking ColorGrading, transitions, icons, logos, spring physics, idle states, VO-sync, and phase structure. Returns a pass/fail checklist.
2788
2809
  tools: Read, Glob
@@ -2879,7 +2900,7 @@ Priority fixes:
2879
2900
  - Scene under 80 lines with 5+ seconds duration = flag as too simple
2880
2901
  - Be specific in fixes: exact icon name, exact component, exact file
2881
2902
  - 85% pass rate minimum. Below = not ready for render
2882
- `}function En(){return`---
2903
+ `}function Fn(){return`---
2883
2904
  name: video-scene-builder
2884
2905
  description: Builds a single Remotion video scene (.tsx) from a video plan section. Receives global context, scene spec, audio timing, and rhythm cues. Writes the scene file, spawns a reviewer, and iterates until 85%+ quality. One agent per scene.
2885
2906
  tools: Read, Write, Edit, Glob, Grep, Task, Bash
@@ -3062,7 +3083,7 @@ function AnimatedCamera() {
3062
3083
  - Don't download assets \u2014 the main AI already did that
3063
3084
  - Don't run render commands \u2014 the main AI handles that
3064
3085
  - Don't modify video-plan.md \u2014 it's read-only to you
3065
- `}function On(t){return`---
3086
+ `}function _n(e){return`---
3066
3087
  name: video-audio-director
3067
3088
  description: Generates all audio assets (voiceover TTS, background music, sound effects) and builds the timing manifest that reconciles planned vs actual durations. One agent per video, runs before scene building.
3068
3089
  tools: Read, Bash, Write
@@ -3074,7 +3095,7 @@ You are the **Audio Director** for a video production. You receive the video pla
3074
3095
 
3075
3096
  ## Your Input (provided in the Task prompt)
3076
3097
 
3077
- 1. **CLI command** \u2014 \\\`${t?.cmd??"mf"}\\\`
3098
+ 1. **CLI command** \u2014 \\\`${e?.cmd??"mf"}\\\`
3078
3099
  2. **Video plan path** \u2014 path to video-plan.md
3079
3100
  3. **Output directory** \u2014 where to write audio files (e.g., ./public/audio/)
3080
3101
  4. **Voice** \u2014 TTS voice (default: Puck)
@@ -3222,7 +3243,7 @@ This saves money and time \u2014 generation is expensive, downloading is free.
3222
3243
  - Don't choose voices \u2014 use the voice from your input
3223
3244
  - Don't skip the timing manifest \u2014 it's the critical handoff to scene builders
3224
3245
  - Don't re-generate audio if it was already generated successfully (see Error Handling above)
3225
- `}function Pn(){return`---
3246
+ `}function Vn(){return`---
3226
3247
  name: video-continuity-editor
3227
3248
  description: Post-build cross-scene QA. Checks transition continuity, color grade flow, timing alignment between Main.tsx and manifest, import consistency, brand coherence, rhythm flow, and music cue alignment. Runs after all scenes are built.
3228
3249
  tools: Read, Glob, Grep
@@ -3333,7 +3354,7 @@ FIXES:
3333
3354
  - Focus on CROSS-SCENE issues. Per-scene quality is the reviewer's job.
3334
3355
  - Be specific in fixes: exact file, exact line, exact component.
3335
3356
  - 85% pass rate minimum.
3336
- `}function Nn(t){let n=t?.cmd??"mf";return`---
3357
+ `}function Mn(e){let n=e?.cmd??"mf";return`---
3337
3358
  name: video-branding-director
3338
3359
  description: Extracts brand identity (logos, colors, fonts) from a URL or existing profiles. Searches saved brands, extracts new ones via CLI, downloads assets locally, and writes branding.json. Returns success or failure. One agent per video, runs before brief/plan generation.
3339
3360
  tools: Read, Bash, Write
@@ -3436,7 +3457,7 @@ Query: <what was searched/extracted>
3436
3457
  - Download logos or images from websites directly (only from branding.json URLs after successful extraction)
3437
3458
  - Create or edit branding.json by hand
3438
3459
  - Ask the user questions \u2014 return failure to the orchestrator instead
3439
- `}function _r(t){return`---
3460
+ `}function Zr(e){return`---
3440
3461
  name: remotion-scene-craft
3441
3462
  description: Remotion scene coding reference for scene builder agents. DO NOT load this directly \u2014 it is preloaded into video-scene-builder agents via frontmatter. Contains plan vocabulary decoder, 4-phase architecture, VO-sync, animation recipes.
3442
3463
  ---
@@ -3711,87 +3732,87 @@ const glow = interpolate(Math.sin(frame / fps * Math.PI * 2 / 2), [-1, 1], [0.1,
3711
3732
  - Static scenes with no visual change for 2+ seconds -> Every 2s needs a visual event.
3712
3733
  - Generic component substitution -> Plan says WhipPan, use WhipPan. Not slide() or wipe().
3713
3734
  - Unused variables or imports -> Every \`const\`, \`import\`, and \`interpolate()\` call must be used in JSX/return. Remove what you don't use. Do NOT prefix with \`_\` \u2014 delete entirely.
3714
- `}var it=["main","video","presentation","presentation-edit","tts","music","sfx","mix","image","video-search","scrape","branding","config"],Vt=["standalone","studio"],Mr={cmd:p.commands[0],pkg:p.packageName,url:p.apiUrl,name:p.name},He=new Us("skill").description(`Manage ${p.displayName} skills for AI coding assistants`).addHelpText("after",`
3715
- ${M.bold("Skill Types:")}
3716
- ${M.cyan("main")} Main CLI skill with all capabilities overview
3717
- ${M.cyan("video")} Detailed video creation workflow with Remotion/R3F patterns
3718
- ${M.cyan("presentation")} Detailed presentation creation workflow
3719
- ${M.cyan("presentation-edit")} In-app presentation editing (Studio)
3720
-
3721
- ${M.bold("Reference Skills:")}
3722
- ${M.cyan("tts")} Text-to-speech generation (voices, providers, options)
3723
- ${M.cyan("music")} AI music generation (prompts, styles, duration)
3724
- ${M.cyan("sfx")} Sound effects generation (categories, looping, formats)
3725
- ${M.cyan("mix")} Audio mixing (video + voice + music)
3726
- ${M.cyan("image")} Image search and AI generation
3727
- ${M.cyan("video-search")} Stock video search
3728
- ${M.cyan("scrape")} URL content extraction
3729
- ${M.cyan("branding")} Brand profile management
3730
- ${M.cyan("config")} CLI configuration management
3731
-
3732
- ${M.bold("Examples:")}
3733
- ${M.gray("# Install main CLI skill (comprehensive overview)")}
3734
- $ ${p.commands[0]} skill install main
3735
-
3736
- ${M.gray("# Install video skill")}
3737
- $ ${p.commands[0]} skill install video
3738
-
3739
- ${M.gray("# Install presentation skill")}
3740
- $ ${p.commands[0]} skill install presentation
3741
-
3742
- ${M.gray("# Install all skills")}
3743
- $ ${p.commands[0]} skill install
3744
-
3745
- ${M.gray("# Install to specific directory")}
3746
- $ ${p.commands[0]} skill install main --dir ~/.claude
3747
-
3748
- ${M.gray("# Show skill content")}
3749
- $ ${p.commands[0]} skill show main
3750
- `);He.command("install").description(`Install ${p.displayName} skills for AI coding assistants`).argument("[type]","Skill type: main, video, presentation, or omit for all").option("-d, --dir <path>","Install to specific directory").option("-g, --global","Install globally (to home directory)",!0).option("-l, --local","Install locally (to current directory)").option("-f, --force","Overwrite existing skill files").option("-m, --mode <mode>","Skill mode: standalone (render to file) or studio (Studio Preview)","standalone").action(async(t,n)=>{n.mode&&!Vt.includes(n.mode)&&(c(`Invalid mode: ${n.mode}. Must be one of: ${Vt.join(", ")}`),process.exit(1));let e={...Mr,mode:n.mode},o=[];t&&!it.includes(t)&&(c(`Invalid skill type: ${t}. Must be one of: ${it.join(", ")}`),process.exit(1));let r=[{name:"tts",content:Fe(e)},{name:"music",content:Ue(e)},{name:"sfx",content:_e(e)},{name:"mix",content:Me(e)},{name:"image",content:Ve(e)},{name:"video-search",content:je(e)},{name:"scrape",content:qe(e)},{name:"branding",content:Be(e)},{name:"config",content:Ge(e)}];(!t||t==="main")&&o.push({name:p.name,content:Ot(e),references:r});let i=[{name:"brief-guide",content:Rn.render(e)},{name:"website-assets",content:kn.render(e)},{name:"source-scraping",content:An.render(e)}];(!t||t==="video")&&(o.push({name:`${p.name}-video`,content:Pt(e),references:i}),o.push({name:"remotion-scene-craft",content:_r(e)})),(!t||t==="presentation")&&o.push({name:`${p.name}-presentation`,content:Nt(e)}),(!t||t==="presentation-edit")&&o.push({name:`${p.name}-presentation-edit`,content:Dt(e)}),t==="tts"&&o.push({name:`${p.name}-tts`,content:Fe(e)}),t==="music"&&o.push({name:`${p.name}-music`,content:Ue(e)}),t==="sfx"&&o.push({name:`${p.name}-sfx`,content:_e(e)}),t==="mix"&&o.push({name:`${p.name}-mix`,content:Me(e)}),t==="image"&&o.push({name:`${p.name}-image`,content:Ve(e)}),t==="video-search"&&o.push({name:`${p.name}-video-search`,content:je(e)}),t==="scrape"&&o.push({name:`${p.name}-scrape`,content:qe(e)}),t==="branding"&&o.push({name:`${p.name}-branding`,content:Be(e)}),t==="config"&&o.push({name:`${p.name}-config`,content:Ge(e)}),console.log();for(let a of o){m(`Installing ${a.name}...`);let s=_t(a.name,a.content,{dir:n.dir,local:n.local,force:n.force},a.references);if(s.installed.length>0&&(C(`${a.name} installed successfully`),k(" Installed to",s.installed.join(", "))),s.skipped.length>0&&(m(` Skipped (already exists): ${s.skipped.join(", ")}`),console.log(M.gray(" Use --force to overwrite"))),s.errors.length>0)for(let l of s.errors)c(` ${l}`);s.installed.length===0&&s.skipped.length===0&&s.errors.length===0&&(m(" No supported AI coding assistants detected"),console.log(M.gray(" Supported editors: "+Lr().join(", "))),console.log(M.gray(" Use --dir <path> to install to a specific directory"))),console.log()}if(!t||t==="video"){for(let a of[{name:"video-branding-director",generate:()=>Nn(e)},{name:"video-scene-builder",generate:En},{name:"video-scene-reviewer",generate:$n},{name:"video-audio-director",generate:()=>On(e)},{name:"video-continuity-editor",generate:Pn}]){m(`Installing ${a.name} agent...`);let s=Fr(a.name,a.generate(),{force:n.force,dir:n.dir});if(s.installed.length>0){C(`${a.name} agent installed`);let l={"Claude Code":"~/.claude/agents/","GitHub Copilot":"~/.github/agents/"};k(" Installed to",s.installed.map(d=>n.dir?d:`${d} (${l[d]??"~/.<editor>/agents/"})`).join(", "))}s.skipped.length>0&&m(` Agent skipped (already exists): ${s.skipped.join(", ")}`)}console.log()}});He.command("show").description("Display skill content").argument("[type]","Skill type (default: main)").option("-m, --mode <mode>","Skill mode: standalone or studio","standalone").action((t="main",n)=>{n.mode&&!Vt.includes(n.mode)&&(c(`Invalid mode: ${n.mode}. Must be one of: ${Vt.join(", ")}`),process.exit(1));let e={...Mr,mode:n.mode},r={main:()=>Ot(e),video:()=>Pt(e),presentation:()=>Nt(e),"presentation-edit":()=>Dt(e),tts:()=>Fe(e),music:()=>Ue(e),sfx:()=>_e(e),mix:()=>Me(e),image:()=>Ve(e),"video-search":()=>je(e),scrape:()=>qe(e),branding:()=>Be(e),config:()=>Ge(e),"video-branding-director":()=>Nn(e),"video-scene-builder":()=>En(),"video-scene-reviewer":()=>$n(),"video-audio-director":()=>On(e),"video-continuity-editor":()=>Pn()}[t];if(r)console.log(r());else{let i=[...it,"video-branding-director","video-scene-builder","video-scene-reviewer","video-audio-director","video-continuity-editor"];c(`Invalid skill type: ${t}. Must be one of: ${i.join(", ")}`),process.exit(1)}});He.command("uninstall").description(`Remove ${p.displayName} skills from AI coding assistants`).argument("[type]","Skill type: main, video, presentation, or omit for all").option("-g, --global","Uninstall globally (from home directory)",!0).option("-l, --local","Uninstall locally (from current directory)").action(async(t,n)=>{let e=[];t&&!it.includes(t)&&(c(`Invalid skill type: ${t}. Must be one of: ${it.join(", ")}`),process.exit(1)),(!t||t==="main")&&e.push(p.name),(!t||t==="video")&&(e.push(`${p.name}-video`),e.push("remotion-scene-craft")),(!t||t==="presentation")&&e.push(`${p.name}-presentation`),(!t||t==="presentation-edit")&&e.push(`${p.name}-presentation-edit`),(!t||t==="tts")&&e.push(`${p.name}-tts`),(!t||t==="music")&&e.push(`${p.name}-music`),(!t||t==="sfx")&&e.push(`${p.name}-sfx`),(!t||t==="mix")&&e.push(`${p.name}-mix`),(!t||t==="image")&&e.push(`${p.name}-image`),(!t||t==="video-search")&&e.push(`${p.name}-video-search`),(!t||t==="scrape")&&e.push(`${p.name}-scrape`),(!t||t==="branding")&&e.push(`${p.name}-branding`),(!t||t==="config")&&e.push(`${p.name}-config`),console.log();for(let o of e){let r=Mt(o,{local:n.local});if(r.removed.length>0?(C(`${o} uninstalled`),k(" Removed from",r.removed.join(", "))):m(` ${o} not found`),r.errors.length>0)for(let i of r.errors)_(` Failed to remove: ${i}`)}if(!t||t==="video")for(let o of["video-branding-director","video-scene-builder","video-scene-reviewer","video-audio-director","video-continuity-editor"])Ur(o).removed.length>0&&C(`${o} agent uninstalled`);console.log()});import{Command as _s}from"commander";import at from"chalk";var Vr=new _s("templates").description("List slide design templates (use with `create --template <id>`)").argument("[search]","Filter templates by name, description, or category").option("-f, --format <format>","Output format (table, json)","table").option("--limit <n>","Maximum templates to list","25").action(async(t,n)=>{await O();try{let e=Number.parseInt(n.limit??"25",10),{templates:o}=await So(t,Number.isFinite(e)?e:25);if(o.length===0){n.format==="json"?console.log(JSON.stringify([])):m("No templates found");return}if(n.format==="json"){console.log(JSON.stringify(o,null,2));return}for(let r of o){let i=[r.isDefault?at.green("default"):null,r.category??null,r.recommendedModes?.length?`modes: ${r.recommendedModes.join("/")}`:null].filter(Boolean).join(" \xB7 ");console.log(`${at.bold(r.name)} ${at.gray(r.id)}${i?`
3751
- ${at.gray(i)}`:""}`)}console.log(),console.log(at.gray(`Use one with: ${p.commands[0]} create "<topic>" --template <id>`))}catch(e){c(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}});import{Command as Ms}from"commander";import Dn from"chalk";var jr=new Ms("whoami").description("Show current user and team information").option("-f, --format <format>","Output format (human, json)","human").action(async t=>{await O();try{let n=await he();if(fn(),t.format==="json"){console.log(JSON.stringify(n,null,2));return}me("User"),console.log(),k("Email",n.user.email),n.user.username&&k("Username",n.user.username),(n.user.firstName||n.user.lastName)&&k("Name",[n.user.firstName,n.user.lastName].filter(Boolean).join(" "));let e=n.authType==="apiKey"?"API Key":n.authType==="oauth"?"OAuth":"Session";if(k("Auth Type",e),n.currentTeam&&(console.log(),me("Current Team"),console.log(),k("ID",n.currentTeam.id),k("Name",n.currentTeam.name),k("Plan",n.currentTeam.planName),k("Role",n.currentTeam.isOwner?"Owner":"Member")),n.teams.length>1){console.log(),me("All Teams"),console.log();for(let o of n.teams){let r=o.isCurrent?Dn.green(" (current)"):"";console.log(` ${Dn.bold(o.name)}${r}`),console.log(Dn.gray(` ID: ${o.id} | Plan: ${o.planName} | Role: ${o.role}`))}}console.log()}catch(n){c(n instanceof Error?n.message:String(n)),process.exit(n.exitCode??1)}});function qr(t){return t[0]==="--"?t.slice(1):t}import{Command as Ln}from"commander";function Vs(t,n){return[...n,t]}var js=new Ln("create").description("Start durable ad-set generation").argument("<title>","Ad-set title").requiredOption("--brief <brief>","Campaign brief").option("--hook <text>","Opening hook (repeat)",Vs,[]).option("--style <style>","ugc, clean, cinematic, or testimonial","ugc").option("--branding-id <id>","Branding ID").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(t,n)=>{if(!n.yes)return c("Pass --yes to approve generation");try{S(await $("createAdSet",{approvalReceipt:"cli:--yes",brandingId:n.brandingId,brief:n.brief,hooks:n.hook.length?n.hook:[n.brief],style:n.style,teamId:n.teamId,title:t}))}catch(e){c(e instanceof Error?e.message:"Generation failed"),process.exit(u.GENERAL_ERROR)}}),qs=new Ln("status").description("Read ad-set generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(t,n)=>{try{S(await U("createAdSet",t,n.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(u.GENERAL_ERROR)}}),Br=new Ln("ad-set").description("Ad set commands").addCommand(js).addCommand(qs);import{Command as Wr}from"commander";function Gr(t){return new Wr(t).description(t==="create"?"Create and activate a scheduled agent":"Create a reviewable agent recommendation").argument("<name>","Agent name").requiredOption("--instructions <markdown>","Agent instructions").option("--description <text>","Agent description","").option("--schedule <frequency>","manual, daily, weekdays, weekly, or monthly","weekly").option("--time <hh:mm>","Local run time","09:00").option("--timezone <zone>","IANA timezone","UTC").option("--output <adapter>","Output adapter","digest").option("--team-id <id>","Workspace ID").option("--yes","Approve saving the agent").action(async(n,e)=>{if(!e.yes)return c("Pass --yes to approve this operation");try{S(await $(t==="create"?"createAgent":"recommendAgent",{approvalReceipt:"cli:--yes",description:e.description,instructionsMarkdown:e.instructions,name:n,output:e.output,schedule:e.schedule,scheduleTime:e.time,teamId:e.teamId,timezone:e.timezone}))}catch(o){c(o instanceof Error?o.message:"Agent operation failed"),process.exit(u.GENERAL_ERROR)}})}var Hr=new Wr("agent").description("Scheduled agent commands").addCommand(Gr("create")).addCommand(Gr("recommend"));import{Command as jt}from"commander";import Ws from"ora";import{mkdir as Bs,writeFile as Jr}from"fs/promises";import{dirname as Gs}from"path";async function we(t,n){if(await Bs(Gs(n),{recursive:!0}),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");if(i.length===0)throw new Error("Downloaded media was empty");await Jr(n,i);return}let e=await fetch(t);if(!e.ok)throw new Error(`Failed to download media: ${e.status}`);let o=Buffer.from(await e.arrayBuffer());if(o.length===0)throw new Error("Downloaded media was empty");await Jr(n,o)}var Hs=15e3,Js=40;function Fn(t,n){if(n==="json"){S(t);return}if(n==="quiet"){console.log(t.videoUrl??t.requestId);return}m(`Request ID: ${t.requestId}`),m(`Status: ${t.status}`),t.durationSec!=null&&m(`Duration: ${t.durationSec}s`),t.videoUrl&&C(`Video URL: ${t.videoUrl}`),t.error&&c(`Error: ${t.error}`)}var zs=new jt("options").description("List available presenter avatars and voices").option("--language <language>","Filter voices by language").option("-f, --format <format>","Output format: human, json, quiet","human").action(async t=>{try{let n=await Lo(t.language);if(t.format==="json"){S(n);return}let e=n.personal??[];if(t.format==="quiet"){for(let o of e)console.log(o.id);for(let o of n.avatars)console.log(o.id);for(let o of n.voices)console.log(o.id);return}if(e.length>0){m("Your presenters:");for(let o of e)console.log(` ${o.id} ${o.name}`)}m("Avatars:");for(let o of n.avatars){let r=o.renderTiers?.length?` [${o.renderTiers.join(", ")}]`:"";console.log(` ${o.id} ${o.name}${r}`)}m("Voices:");for(let o of n.voices)console.log(` ${o.id} ${o.name}${o.language?` (${o.language})`:""}`)}catch(n){c(n instanceof Error?n.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),Xs=new jt("generate").description("Generate a reusable presenter clip").option("--avatar-id <id>","Avatar id from 'avatar options'; sandbox runs use the host presenter policy").option("--audio-url <url>","Public narration audio URL for avatar lip sync").option("--voice-id <id>","Voice id from 'avatar options'").option("--script <text>","Exact words for the presenter to speak").requiredOption("-o, --output <path>","Local output path").option("--aspect <aspect>","Aspect: 1:1, 9:16, 16:9","9:16").option("--duration <seconds>","Maximum requested duration (1-300)").option("--transparent","Render a transparent-background WebM presenter clip").option("--background-color <hex>","Solid presenter background color, for example #0F172A").option("--background-image-url <url>","Public image URL used as the presenter background").option("--fit <mode>","Background image fit: contain or cover").option("--output-format <container>","Container: mp4 (default) or webm \u2014 webm renders a transparent-background clip (single scene) for compositing").option("--render-tier <tier>","Render cost/quality: basic, standard, premium","basic").option("--title <title>","Clip title","Presenter clip").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async t=>{let n=t.transparent?"webm":t.outputFormat;!!t.audioUrl==!!t.script&&(c("Provide exactly one avatar speech input: --audio-url or --script"),process.exit(u.INVALID_INPUT)),["1:1","9:16","16:9"].includes(t.aspect)||(c("Aspect must be one of 1:1, 9:16, or 16:9"),process.exit(u.INVALID_INPUT)),t.outputFormat!==void 0&&!["mp4","webm"].includes(t.outputFormat)&&(c("Output format must be mp4 or webm"),process.exit(u.INVALID_INPUT)),t.backgroundColor!==void 0&&!/^#[0-9a-fA-F]{6}$/.test(t.backgroundColor)&&(c("Background color must be a six-digit hex value"),process.exit(u.INVALID_INPUT)),t.backgroundColor&&t.backgroundImageUrl&&(c("Provide only one presenter background"),process.exit(u.INVALID_INPUT)),t.fit!==void 0&&!["contain","cover"].includes(t.fit)&&(c("Fit must be contain or cover"),process.exit(u.INVALID_INPUT)),t.fit&&!t.backgroundImageUrl&&(c("Fit requires --background-image-url"),process.exit(u.INVALID_INPUT)),t.transparent&&t.outputFormat==="mp4"&&(c("--transparent cannot be combined with --output-format mp4"),process.exit(u.INVALID_INPUT)),n==="webm"&&(t.backgroundColor||t.backgroundImageUrl)&&(c("Transparent WebM output cannot be combined with a background"),process.exit(u.INVALID_INPUT)),["basic","standard","premium"].includes(t.renderTier)||(c("Render tier must be basic, standard, or premium"),process.exit(u.INVALID_INPUT));let e=t.duration?Number.parseInt(t.duration,10):void 0;e!==void 0&&(!Number.isFinite(e)||e<1||e>300)&&(c("Duration must be between 1 and 300 seconds"),process.exit(u.INVALID_INPUT));let o=t.format==="human"?Ws("Generating presenter clip...").start():null;try{let r=t.audioUrl?{audioUrl:t.audioUrl}:{script:t.script??"",...t.voiceId?{voiceId:t.voiceId}:{}},i=await Fo({...r,aspect:t.aspect,...t.avatarId?{avatarId:t.avatarId}:{},...t.backgroundColor?{backgroundHex:t.backgroundColor}:{},...t.backgroundImageUrl?{backgroundImageUrl:t.backgroundImageUrl}:{},...e!==void 0?{durationSec:e}:{},...t.fit?{fit:t.fit}:{},...n?{outputFormat:n}:{},renderTier:t.renderTier,title:t.title});if(!t.wait){o?.stop(),Fn(i,t.format);return}let a=await ue(()=>un(i.requestId),Js,Hs);if(a.status==="failed")throw new Error(a.error||"Presenter generation failed");if(!a.videoUrl)throw new Error("Presenter generation completed without a video URL");o&&(o.text="Downloading presenter clip..."),await we(a.videoUrl,t.output),o?.stop(),Fn(a,t.format),t.format==="human"&&C(`Saved to: ${t.output}`)}catch(r){o?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),Ys=new jt("status").description("Check a presenter clip generation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{try{Fn(await un(t),n.format)}catch(e){c(e instanceof Error?e.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),zr=new jt("avatar").description("Avatar/presenter media commands").addCommand(zs).addCommand(Xs).addCommand(Ys);import{writeFile as Xr}from"fs/promises";import H from"chalk";import{Command as ie}from"commander";import Ks from"ora";var Yr=new ie("branding").description("Manage brand profiles").addCommand(new ie("list").description("List brand profiles").option("-f, --format <format>","Output format (table, json)","table").action(async t=>{await O();try{let n=await sn();if(n.brandings.length===0){t.format==="json"?console.log(JSON.stringify([])):(m("No brand profiles found"),console.log(),console.log(H.gray(`Create one with: ${p.commands[0]} branding extract <url>`)));return}t.format==="json"?console.log(JSON.stringify(n.brandings,null,2)):console.log(jo(n.brandings))}catch(n){c(n instanceof Error?n.message:String(n)),process.exit(n.exitCode??1)}})).addCommand(new ie("get").description("Get brand profile details").argument("<id>","Brand profile ID").option("-f, --format <format>","Output format (summary, json)","summary").option("-o, --output <path>","Save JSON to file").action(async(t,n)=>{await O();try{let e=await Co(t);if(n.output){await Xr(n.output,JSON.stringify(e,null,2)),C(`Brand profile saved to ${n.output}`);return}if(n.format==="json")console.log(JSON.stringify(e,null,2));else{if(me("Brand Profile"),console.log(),k("ID",e.id),k("Name",e.name),k("Source URL",e.sourceUrl??H.gray("None")),k("Default",e.isDefault?H.green("Yes"):"No"),e.createdAt&&k("Created",new Date(e.createdAt).toLocaleString()),console.log(),e.primaryColor||e.colors.length>0){if(console.log(H.bold(" Colors")),e.primaryColor){let r=H.bgHex(e.primaryColor)(" ");console.log(` Primary: ${r} ${e.primaryColor}`)}if(e.colors.length>0){console.log(" Palette:");for(let r of e.colors.slice(0,10)){let i=H.bgHex(r.hex)(" "),a=r.role?H.gray(` (${r.role})`):"";console.log(` ${i} ${r.hex}${a}`)}}console.log()}e.logoUrl&&(console.log(H.bold(" Logo")),console.log(` ${e.logoUrl}`),console.log());let o=e.typography;o&&Object.keys(o).length>0&&(console.log(H.bold(" Typography")),(o.primary||o.headings)&&console.log(` Headings: ${o.primary||o.headings||"-"}`),(o.secondary||o.body)&&console.log(` Body: ${o.secondary||o.body||"-"}`),console.log()),(e.confidence||e.extractionMethod)&&(console.log(H.bold(" Extraction")),e.confidence&&console.log(` Confidence: ${Math.round(e.confidence*100)}%`),e.extractionMethod&&console.log(` Method: ${e.extractionMethod}`),console.log()),console.log(H.gray(" Use --format json for full details")),console.log()}}catch(e){c(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}})).addCommand(new ie("find").description("Find existing brand profile by name or URL").argument("<query>","Brand name or website URL to search for").action(async t=>{await O();try{let n=await sn(),e=t.toLowerCase().replace(/^https?:\/\//,"").replace(/\/$/,""),o=n.brandings.filter(r=>{let i=(r.name||"").toLowerCase(),a=(r.sourceUrl||"").toLowerCase().replace(/^https?:\/\//,"").replace(/\/$/,"");return i.includes(e)||a.includes(e)||i.length>0&&e.includes(i)||a.length>0&&e.includes(a)});if(o.length===0){m(`No brand profiles matching "${t}"`),console.log(H.gray(` Extract one with: ${p.commands[0]} branding extract <url>`));return}console.log(`Found ${o.length} brand${o.length>1?"s":""}:
3752
- `);for(let r of o){let i=r.primaryColor?`${H.bgHex(r.primaryColor)(" ")} ${r.primaryColor}`:"";console.log(` ${H.bold(r.name)} ${H.gray(r.id)}`),r.sourceUrl&&console.log(` ${H.gray(r.sourceUrl)}`),i&&console.log(` ${i}`),console.log()}console.log(H.gray(` Export with: ${p.commands[0]} branding get <id> -o branding.json`))}catch(n){c(n instanceof Error?n.message:String(n)),process.exit(n.exitCode??1)}})).addCommand(new ie("extract").description("Extract brand profile from a website").argument("<url>","Website URL to extract branding from").option("--team-id <id>","Team ID").option("--yes","Confirm starting a paid/external extraction").option("--no-save","Extract without saving").option("-o, --output <path>","Save JSON to file").action(async(t,n)=>{await O(),n.yes||(c("Pass --yes to confirm brand extraction."),process.exit(u.INVALID_INPUT));try{new URL(t.startsWith("http")?t:`https://${t}`)}catch{c("Invalid URL format"),process.exit(6)}let e=t.startsWith("http")?t:`https://${t}`,o=n.teamId??ut(),r=Ks({text:`Extracting branding from ${e}...`,stream:process.stdout}).start();try{let i=await Io(e,o,"cli:--yes");r.succeed("Brand extraction started");let a=JSON.stringify(i,null,2);n.output?(await Xr(n.output,a),C(`Brand profile saved to ${n.output}`)):console.log(a),m(`Check progress with: ${p.commands[0]} branding status ${i.runId}`),console.log()}catch(i){r.fail("Extraction failed"),c(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}})).addCommand(new ie("status").description("Check a brand extraction run").argument("<run-id>","Run ID returned by branding extract").option("--team-id <id>","Workspace ID").action(async(t,n)=>{try{S(await U("extractBranding",t,n.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(u.GENERAL_ERROR)}})).addCommand(new ie("set-default").description("Set a brand profile as default").argument("<id>","Brand profile ID").action(async t=>{await O(),m(`To set brand ${t} as default, use the web dashboard.`),console.log(),console.log(H.gray("API support for setting default brand is coming soon."))})).addCommand(new ie("competitor").description("Brand competitor commands").addCommand(new ie("list").description("List competitors for a brand").option("--branding-id <id>","Brand ID").option("--team-id <id>","Workspace ID").action(async t=>{try{console.log(JSON.stringify(await $("getBrandCompetitors",{brandingId:t.brandingId,teamId:t.teamId}),null,2))}catch(n){c(n instanceof Error?n.message:"Lookup failed"),process.exit(1)}})).addCommand(new ie("add").description("Add or update a brand competitor").argument("<name>","Competitor name").option("--branding-id <id>","Brand ID").option("--team-id <id>","Workspace ID").option("--website <url>","Competitor website").option("--x-handle <handle>","Competitor X handle").option("--yes","Confirm writing brand data").action(async(t,n)=>{n.yes||(c("Pass --yes to confirm adding a competitor."),process.exit(u.INVALID_INPUT));try{S(await $("addCompetitor",{approvalReceipt:"cli:--yes",brandingId:n.brandingId,name:t,teamId:n.teamId,website:n.website,xHandle:n.xHandle}))}catch(e){c(e instanceof Error?e.message:"Write failed"),process.exit(u.GENERAL_ERROR)}}))).addCommand(new ie("social").description("Brand social handle commands").addCommand(new ie("add").description("Add or update a brand social handle").argument("<platform>","Social platform").argument("<handle>","Account handle").option("--branding-id <id>","Brand ID").option("--team-id <id>","Workspace ID").option("--yes","Confirm writing brand data").action(async(t,n,e)=>{e.yes||(c("Pass --yes to confirm adding a social handle."),process.exit(u.INVALID_INPUT));try{S(await $("addBrandSocialHandle",{approvalReceipt:"cli:--yes",brandingId:e.brandingId,handle:n,platform:t,teamId:e.teamId}))}catch(o){c(o instanceof Error?o.message:"Write failed"),process.exit(u.GENERAL_ERROR)}})));import{readFile as Qs}from"fs/promises";import{Command as Kr}from"commander";var Zs=new Kr("extract").description("Extract normalized text from a URL or local file").argument("<source>","URL, encoded source, or local file path").option("--team-id <id>","Workspace ID").option("--mime-type <type>","Source MIME type").option("--max-length <count>","Maximum output characters","30000").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{try{let e=t,o;t.includes("://")||(e=await Qs(t,"utf8"),o=t);let r=await $("extractContent",{filename:o,maxLength:Number.parseInt(n.maxLength,10),mimeType:n.mimeType,source:e,teamId:n.teamId});n.format!=="quiet"&&S(r)}catch(e){c(e instanceof Error?e.message:"Extraction failed"),process.exit(u.GENERAL_ERROR)}}),Qr=new Kr("content").description("Content extraction commands").addCommand(Zs);import Y from"chalk";import{Command as ec}from"commander";import{existsSync as tc,readFileSync as nc}from"fs";import oc,{resolve as Zr}from"path";var ei=new ec("create").description("Create a new presentation").argument("<topic>","The topic or title for the presentation").option("-n, --slides <count>","Number of slides (1-20)").option("-m, --mode <mode>","Generation quality (best, balanced, fast, ultrafast, instant, image-min, image, image-max) \u2014 default: fast. image-min/image/image-max render each slide as a full-bleed AI image (text not editable); slower + pricier, require image-mode access, and cap at 25 slides. image-min is cheapest (brand colors only, no exact fonts).").option("--image-tier <tier>","Embedded-image quality for HTML modes: smart (default, auto-routes per image), fast (cheapest, no extra credits), balanced (+50 credits/slide), best (premium, +200 credits/slide, slow). Ignored for image-*/instant modes.").option("-t, --tone <tone>","Tone (creative, professional, educational, formal, casual)").option("--amount <amount>","Content density (minimal, concise, detailed, extensive)").option("--audience <text>","Target audience description").option("-l, --language <lang>","Output language").option("--branding-id <id>","Branding ID (from `ccr branding list` or `ccr branding extract`)").option("--brand-domain <url>","Brand the deck by website/domain (e.g. https://www.pfizer.com). Errors if no matching saved brand exists.").option("--template <id>","Slide template ID to style the deck after (from `ccr templates`). A default template is applied automatically when omitted.").option("-c, --context <text>","Inline text context (research notes, key facts)").option("--context-file <path>","Path to a context file (text, markdown, JSON)").option("--stdin","Read context from stdin").option("-f, --file <paths...>","Files to upload (PDF, PPTX, DOCX, images)").option("-g, --goal <type>","Goal (inform, persuade, train, learn, entertain, report)").option("--styling <mode>","Styling mode (freeform, brand-only, brand-plus-style, style-only, no-styling)").option("--reference-url <url>","Image URL to use as visual style reference").option("--thinking-depth <depth>","AI thinking depth (quick, moderate, deep, profound)").option("--theme <preset>","[instant mode only] Color theme preset (blue, violet, rose, orange, green)").option("--primary-color <hex>","[instant mode only] Primary color (e.g., #0066CC)").option("--secondary-color <hex>","[instant mode only] Secondary color").option("--accent-color <hex>","[instant mode only] Accent color").option("--background-color <hex>","[instant mode only] Background color").option("--foreground-color <hex>","[instant mode only] Foreground/text color").option("--decorations <style>","[instant mode only] Background decoration (none, waves-bottom-left, waves-top-right, blob-corners, minimal)").option("--team-id <id>","Team ID (switch teams)").option("-o, --output <format>","Output format (human, json, quiet)").option("--no-stream","Wait for completion without streaming progress").option("--wait","Poll until generation completes").option("--debug","Enable debug logging").option("--open","Open in browser after creation").option("--id <uuid>","Use a specific UUID for the presentation").option("--studio","Studio mode: use current directory name as presentation ID (auto-links to Studio preview)").action(async(t,n)=>{await O();let e;n.slides!==void 0&&(e=parseInt(n.slides,10),(Number.isNaN(e)||e<1||e>20)&&(c("Slide count must be between 1 and 20"),process.exit(6)));let o=["best","balanced","fast","ultrafast","instant","image-min","image","image-max"];n.mode&&!o.includes(n.mode)&&(c(`Invalid mode: ${n.mode}. Valid: ${o.join(", ")}`),process.exit(6));let r=["smart","fast","balanced","best"];n.imageTier&&!r.includes(n.imageTier)&&(c(`Invalid image tier: ${n.imageTier}. Valid: ${r.join(", ")}`),process.exit(6));let i=["creative","professional","educational","formal","casual"];n.tone&&!i.includes(n.tone)&&(c(`Invalid tone: ${n.tone}. Valid: ${i.join(", ")}`),process.exit(6));let a=["minimal","concise","detailed","extensive"];n.amount&&!a.includes(n.amount)&&(c(`Invalid amount: ${n.amount}. Valid: ${a.join(", ")}`),process.exit(6));let s=["freeform","brand-only","brand-plus-style","style-only","no-styling"];n.styling&&!s.includes(n.styling)&&(c(`Invalid styling: ${n.styling}. Valid: ${s.join(", ")}`),process.exit(6));let l=["quick","moderate","deep","profound"];n.thinkingDepth&&!l.includes(n.thinkingDepth)&&(c(`Invalid thinking-depth: ${n.thinkingDepth}. Valid: ${l.join(", ")}`),process.exit(6));let d=["inform","persuade","train","learn","entertain","report"];n.goal&&!d.includes(n.goal)&&(c(`Invalid goal: ${n.goal}. Valid: ${d.join(", ")}`),process.exit(6));let f=["blue","violet","rose","orange","green"];n.theme&&!f.includes(n.theme)&&(c(`Invalid theme: ${n.theme}. Valid: ${f.join(", ")}`),process.exit(6));let v=["none","waves-bottom-left","waves-top-right","blob-corners","minimal"];n.decorations&&!v.includes(n.decorations)&&(c(`Invalid decorations: ${n.decorations}. Valid: ${v.join(", ")}`),process.exit(6));let I=n.theme||n.primaryColor||n.secondaryColor||n.accentColor||n.backgroundColor||n.foregroundColor||n.decorations;I&&n.mode&&n.mode!=="instant"&&(c("--theme, --primary-color, --decorations and other color options are only supported with --mode instant"),process.exit(6));let g=n.mode??(I?"instant":"fast"),T=/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;for(let[w,V]of[["primary-color",n.primaryColor],["secondary-color",n.secondaryColor],["accent-color",n.accentColor],["background-color",n.backgroundColor],["foreground-color",n.foregroundColor]])V&&!T.test(V)&&(c(`Invalid ${w}: ${V}. Must be hex (e.g., #0066CC)`),process.exit(6));try{n.output!=="json"&&n.output!=="quiet"&&process.stdout.write(Y.gray("Checking generation limits... "));let w=await Ro(g,e??10,n.teamId);if(n.output!=="json"&&n.output!=="quiet"){console.log(Y.green("\u2713"));let V=w.remaining[g],q=w.limits[g],ee=V===void 0||q===void 0?"":` | ${g}: ${V}/${q} remaining`;console.log(Y.gray(` Plan: ${w.planName}${ee}`))}}catch(w){n.output==="json"?console.log(JSON.stringify({success:!1,error:w instanceof Error?w.message:String(w)})):(console.log(Y.red("\u2717")),c(w instanceof Error?w.message:String(w))),process.exit(w.exitCode??1)}let b=[];if(n.file&&n.file.length>0){for(let w of n.file)tc(Zr(w))||(c(`File not found: ${w}`),process.exit(6));n.output!=="json"&&n.output!=="quiet"&&console.log(Y.gray(`
3753
- Uploading ${n.file.length} file(s)...`));try{b=await ho(n.file.map(w=>Zr(w)),(w,V,q)=>{n.output!=="json"&&n.output!=="quiet"&&q&&process.stdout.write(`\r ${Y.cyan("\u2B06")} Uploading: ${q} (${w+1}/${V})`)}),n.output!=="json"&&n.output!=="quiet"&&console.log(`\r ${Y.green("\u2713")} Uploaded ${b.length} file(s) `)}catch(w){c(`Failed to upload files: ${w instanceof Error?w.message:String(w)}`),process.exit(1)}}let y;(n.stdin||!process.stdin.isTTY)&&(y=await rc(),n.stdin&&!y&&(c("No content received from stdin"),process.exit(6)));let x=n.context;if(n.contextFile)try{x=nc(n.contextFile,"utf-8"),x.trim()||(c(`Context file is empty: ${n.contextFile}`),process.exit(6))}catch{c(`Failed to read context file: ${n.contextFile}`),process.exit(6)}!y&&!x&&b.length===0&&(c("Context is required to create a presentation."),console.log(),console.log(Y.gray(" -f, --file <paths...> Upload files (PDF, PPTX, images)")),console.log(Y.gray(" -c, --context <text> Inline text context")),console.log(Y.gray(" --context-file <path> Read from a file")),console.log(Y.gray(` cat file | ${p.commands[0]} Pipe content`)),process.exit(6));let E=[...b];y&&E.push({id:`stdin-${Date.now()}`,content:y,title:"Piped Content",mime:"text/plain",selected:!0}),x&&E.push({id:`context-${Date.now()}`,content:x,title:"Context",mime:"text/plain",selected:!0});let A,P=n.primaryColor||n.secondaryColor||n.accentColor||n.backgroundColor||n.foregroundColor;(n.theme||P||n.decorations)&&(A={},n.theme&&(A.preset=n.theme),P&&(A.custom={},n.primaryColor&&(A.custom.primary=n.primaryColor),n.secondaryColor&&(A.custom.secondary=n.secondaryColor),n.accentColor&&(A.custom.accent=n.accentColor),n.backgroundColor&&(A.custom.background=n.backgroundColor),n.foregroundColor&&(A.custom.foreground=n.foregroundColor)),n.decorations&&(A.decorations=n.decorations));try{let w=await yo({topic:t,...e!==void 0&&{slideCount:e},mode:g,...n.imageTier&&{imageTier:n.imageTier},...n.tone&&{tone:n.tone},...n.amount&&{amount:n.amount},...n.audience&&{audience:n.audience},...n.language&&{language:n.language},...n.brandingId&&{brandingId:n.brandingId},...n.brandDomain&&{brandDomain:n.brandDomain},...n.template&&{templateId:n.template},...n.styling&&{stylingMode:n.styling},...n.referenceUrl&&{referenceUrl:n.referenceUrl},...n.thinkingDepth&&{thinkingDepth:n.thinkingDepth},...n.goal&&{goal:n.goal},...n.teamId&&{teamId:n.teamId},...A&&{theme:A},...n.studio?{documentId:oc.basename(process.cwd())}:n.id?{documentId:n.id}:{},...E.length>0&&{contentSources:{uploadedFiles:E,contextFiles:[]}}});if(!n.wait){n.output==="json"?console.log(JSON.stringify({success:!0,run:w},null,2)):n.output!=="quiet"&&(C("Presentation generation queued"),k("Run ID",w.runId),k("Status",w.status),console.log(Y.gray(` Check later with presentation status ${w.runId}`)));return}let V=await U("createSlides",w.runId,n.teamId);for(;!V.done;)n.output!=="json"&&n.output!=="quiet"&&console.log(Y.gray(` ${V.message}`)),await new Promise(ee=>setTimeout(ee,(V.nextPollAfterSeconds??5)*1e3)),V=await U("createSlides",w.runId,n.teamId);if(V.error)throw new Error(V.error.message);let q=V.entity?await xe(V.entity.id):void 0;if(n.output==="json")console.log(JSON.stringify({success:!0,presentation:q,run:V,viewUrl:q?Pe(q.slug,n.language??"en"):void 0},null,2));else{console.log(),C("Presentation created successfully"),console.log(),k("Title",q?.title??t),k("Slides",String(q?.numberOfSlides??e??"\u2014")),console.log();let ee=q?Pe(q.slug,n.language??"en"):"N/A";ee!=="N/A"&&(console.log(Y.bold(" Open: ")+Y.cyan.underline(ee)),n.open&&await(await import("open")).default(ee)),console.log()}}catch(w){n.output==="json"?console.log(JSON.stringify({success:!1,error:w instanceof Error?w.message:String(w)})):c(w instanceof Error?w.message:String(w)),process.exit(w.exitCode??1)}});async function rc(){return new Promise(t=>{let n="";if(process.stdin.setEncoding("utf8"),process.stdin.isTTY){t("");return}process.stdin.on("data",e=>{n+=e}),process.stdin.on("end",()=>{t(n.trim())}),setTimeout(()=>{t(n.trim())},100)})}import{Command as ic}from"commander";import qt from"chalk";var ti=new ic("get").description("Get presentation details").argument("<slug>","Presentation slug (e.g., my-presentation-v1-abc123)").option("-f, --format <format>","Output format (summary, full, json)","summary").option("--include <fields>","Fields to include (comma-separated: slides,styling)").option("-l, --language <lang>","Language for view URL","en").action(async(t,n)=>{await O();try{let e=await xe(t);if(n.format==="json"){console.log(JSON.stringify(e,null,2));return}let o=Pe(e.slug,n.language);me("Presentation Details"),console.log(),k("Slug",e.slug),k("Title",e.title||"Untitled"),k("Description",e.description||qt.gray("None")),k("Slides",String(e.numberOfSlides||"-")),k("Mode",e.mode||"-"),k("Created",gn(e.createdAt)),e.updatedAt&&k("Updated",gn(e.updatedAt)),console.log(),o!=="N/A"&&console.log(qt.bold(" Open: ")+qt.cyan.underline(o)),console.log(),n.format==="full"&&n.include?.includes("slides")&&(console.log(qt.gray("(Full slide content available in JSON format)")),console.log())}catch(e){c(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}});import{Command as Bt}from"commander";import ac from"ora";var sc=new Bt("search").description("Search for images").requiredOption("-q, --query <query>","Search query").option("-n, --max-results <number>","Maximum number of results (default: 10)").option("-s, --size <size>","Image size: small, medium, large, any","large").option("--safe-search","Enable safe search (default: true)",!0).option("--no-safe-search","Disable safe search").option("-f, --format <format>","Output format: human, json, quiet","human").action(async t=>{let n=t.format,e=n==="human"?ac("Searching for images...").start():null,o;t.maxResults&&(o=parseInt(t.maxResults,10),(Number.isNaN(o)||o<1)&&(e?.stop(),c("Max results must be a positive number"),process.exit(u.INVALID_INPUT)));try{let r=await wt({query:t.query,options:{maxResults:o||10,size:t.size,safeSearch:t.safeSearch}});e?.stop(),r.success||(c("Search failed"),process.exit(u.GENERAL_ERROR));let i=r.data.results.flatMap(a=>a.results.map(s=>({...s,provider:a.providerName})));if(n==="json"){S({success:!0,query:t.query,totalResults:i.length,images:i});return}if(n==="quiet"){for(let a of i)console.log(a.url);return}if(i.length===0){m("No images found");return}C(`Found ${i.length} images for "${t.query}"`),console.log();for(let a=0;a<i.length;a++){let s=i[a];console.log(`[${a+1}] ${s.title||"Untitled"}`),console.log(` URL: ${s.url}`),console.log(` Size: ${s.width}x${s.height}`),s.author&&console.log(` Author: ${s.author}`),console.log(` Provider: ${s.provider}`),console.log()}m(`Total cost: $${r.data.totalCost.toFixed(4)}`)}catch(r){e?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),cc=new Bt("generate").description("Start background image generation").argument("<prompt>","Image prompt").option("--provider <provider>","Provider override").option("--model <model>","Model override").option("--width <pixels>","Width").option("--height <pixels>","Height").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(t,n)=>{if(!n.yes)return c("Pass --yes to approve image generation");try{S(await $("createImage",{approvalReceipt:"cli:--yes",height:n.height?Number.parseInt(n.height,10):void 0,model:n.model,prompt:t,provider:n.provider,teamId:n.teamId,width:n.width?Number.parseInt(n.width,10):void 0}))}catch(e){c(e instanceof Error?e.message:"Generation failed"),process.exit(u.GENERAL_ERROR)}}),lc=new Bt("status").description("Read image generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(t,n)=>{try{S(await U("createImage",t,n.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(u.GENERAL_ERROR)}}),ni=new Bt("image").description("Image search and generation commands").addCommand(sc).addCommand(cc).addCommand(lc);import{Command as Un}from"commander";var dc=new Un("search").description("Search the workspace Knowledge Hub").argument("[query]","Optional search query").option("--team-id <id>","Workspace ID").option("--kind <kind>","Knowledge kind").option("--limit <count>","Maximum results","10").action(async(t,n)=>{try{S(await $("searchKnowledge",{kind:n.kind,limit:Number.parseInt(n.limit,10),query:t,teamId:n.teamId}))}catch(e){c(e instanceof Error?e.message:"Knowledge search failed"),process.exit(u.GENERAL_ERROR)}}),uc=new Un("bundle").description("Read a bounded Open Knowledge Format bundle").option("--team-id <id>","Workspace ID").option("--kind <kind>","Knowledge kind").action(async t=>{try{S(await $("getKnowledgeBundle",{kind:t.kind,teamId:t.teamId}))}catch(n){c(n instanceof Error?n.message:"Knowledge bundle failed"),process.exit(u.GENERAL_ERROR)}}),oi=new Un("knowledge").description("Knowledge Hub commands").addCommand(dc).addCommand(uc);import{Command as _n}from"commander";var mc=new _n("create").description("Start background microsite generation").argument("<title>","Microsite title").requiredOption("--description <brief>","Microsite brief").option("--audience <audience>","Target audience").option("--tone <tone>","Tone").option("--language <language>","Content language","en").option("--branding-id <id>","Branding ID").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(t,n)=>{if(!n.yes)return c("Pass --yes to approve generation");try{S(await $("createMicrosite",{approvalReceipt:"cli:--yes",audience:n.audience,brandingId:n.brandingId,description:n.description,language:n.language,teamId:n.teamId,title:t,tone:n.tone}))}catch(e){c(e instanceof Error?e.message:"Generation failed"),process.exit(u.GENERAL_ERROR)}}),pc=new _n("status").description("Read microsite generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(t,n)=>{try{S(await U("createMicrosite",t,n.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(u.GENERAL_ERROR)}}),ri=new _n("microsite").description("Microsite commands").addCommand(mc).addCommand(pc);import{Command as jn}from"commander";import Mn from"ora";function Vn(t,n){if(n==="json"){let{cost:e,...o}=t;S(o);return}if(n==="quiet"){t.outputUrl?console.log(t.outputUrl):console.log(t.requestId);return}m(`Request ID: ${t.requestId}`),m(`Status: ${t.status}`),t.duration&&m(`Duration: ${t.duration}s`),t.outputUrl&&C(`Output URL: ${t.outputUrl}`),t.cost!==void 0&&m(`Cost: $${t.cost.toFixed(4)}`),t.error&&c(`Error: ${t.error}`)}var gc=new jn("create").description("Mix audio tracks into a video (music will loop to match video duration)").requiredOption("--video <url>","Input video file/URL").option("--music <url>","Background music file/URL (will loop if shorter than video)").option("--voice <url>","Voiceover file/URL").option("--music-volume <percent>","Music volume 0-100 (default: 30, recommended for mix with voice)","30").option("--voice-volume <percent>","Voice volume 0-100","100").option("-o, --output <path>","Output file path").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async t=>{!t.music&&!t.voice&&(c("At least one of --music or --voice must be provided"),process.exit(u.INVALID_INPUT));let n=parseInt(t.musicVolume,10)/100,e=parseInt(t.voiceVolume,10)/100;(Number.isNaN(n)||n<0||n>1)&&(c("Music volume must be between 0 and 100"),process.exit(u.INVALID_INPUT)),(Number.isNaN(e)||e<0||e>2)&&(c("Voice volume must be between 0 and 200"),process.exit(u.INVALID_INPUT));let o=t.format,r=o==="human"?Mn("Mixing audio...").start():null,i=[{url:t.video,role:"video"}];t.music&&i.push({url:t.music,role:"background",volume:n*5}),t.voice&&i.push({url:t.voice,role:"voice",volume:e*2});try{let a=await Oo({operation:"add-to-video",inputs:i,options:{musicVolume:n,voiceVolume:e}});if(!t.wait){r?.stop(),Vn(a,o);return}r&&(r.text=`Processing (ID: ${a.requestId})...`);let s=await ue(()=>cn(a.requestId),120,3e3);if(r?.stop(),s.status==="failed"&&(c(s.error||"Audio mixing failed"),process.exit(u.GENERAL_ERROR)),Vn(s,o),t.output){if(!s.outputUrl)throw new Error("Audio mix completed without an output URL");let l=o==="human"?Mn("Downloading...").start():null;await we(s.outputUrl,t.output),l?.stop(),o==="human"&&C(`Saved to: ${t.output}`)}}catch(a){r?.stop(),c(a instanceof Error?a.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),fc=new jn("status").description("Check status of an audio mix request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{let e=n.format==="human"?Mn("Checking status...").start():null;try{let o=await cn(t);e?.stop(),Vn(o,n.format)}catch(o){e?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),ii=new jn("mix").description("Audio mixing commands").addCommand(gc).addCommand(fc);import{Command as Gn}from"commander";import qn from"ora";function Bn(t,n){if(n==="json"){let{cost:e,...o}=t;S(o);return}if(n==="quiet"){t.audioUrl?console.log(t.audioUrl):console.log(t.requestId);return}m(`Request ID: ${t.requestId}`),m(`Status: ${t.status}`),t.duration&&m(`Duration: ${t.duration}s`),t.audioUrl&&C(`Audio URL: ${t.audioUrl}`),t.cost!==void 0&&m(`Cost: $${t.cost.toFixed(4)}`),t.error&&c(`Error: ${t.error}`)}var hc=new Gn("generate").description("Generate music from a text prompt").requiredOption("-p, --prompt <text>","Music description").option("-d, --duration <seconds>","Duration in seconds (3-600)","30").option("-s, --style <style>","Style preset").option("--provider <provider>","Provider (elevenlabs, suno)").option("-o, --output <path>","Output file path").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async t=>{let n=parseInt(t.duration,10);(Number.isNaN(n)||n<3||n>600)&&(c("Duration must be between 3 and 600 seconds (10 minutes)"),process.exit(u.INVALID_INPUT));let e=t.format,o=e==="human"?qn("Generating music...").start():null;try{let r=await vt({prompt:t.prompt,duration:n,options:{provider:t.provider,style:t.style}});if(!t.wait){o?.stop(),Bn(r,e);return}let i=r;if(r.status!=="completed"&&r.status!=="failed"&&(o&&(o.text=`Processing (ID: ${r.requestId})...`),i=await ue(()=>ot(r.requestId),60,2e3)),o?.stop(),i.status==="failed"&&(c(i.error||"Music generation failed"),process.exit(u.GENERAL_ERROR)),Bn(i,e),t.output){if(!i.audioUrl)throw new Error("Music completed without an audio URL");let a=e==="human"?qn("Downloading...").start():null;await we(i.audioUrl,t.output),a?.stop(),e==="human"&&C(`Saved to: ${t.output}`)}}catch(r){o?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),yc=new Gn("status").description("Check status of a music 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"?qn("Checking status...").start():null;try{let o=await ot(t);e?.stop(),Bn(o,n.format)}catch(o){e?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),ai=new Gn("music").description("Music generation commands").addCommand(hc).addCommand(yc);import{Command as Wn}from"commander";function si(t,n){return[...n,t]}var bc=new Wn("create").description("Create a standalone poll").argument("<question>","Poll question").option("--option <text>","Choice (repeat 2-10 times)",si,[]).option("--type <type>","single, multiple, or word-cloud","single").option("--title <title>","Poll title").option("--team-id <id>","Workspace ID").option("--yes","Approve creation").action(async(t,n)=>{if(!n.yes)return c("Pass --yes to approve poll creation");try{S(await $("createPoll",{approvalReceipt:"cli:--yes",options:n.option.map(e=>({text:e})),pollType:n.type,question:t,teamId:n.teamId,title:n.title}))}catch(e){c(e instanceof Error?e.message:"Poll creation failed"),process.exit(u.GENERAL_ERROR)}}),xc=new Wn("edit").description("Edit a standalone poll").argument("<poll-id>","Poll UUID").option("--question <question>","New question").option("--option <text>","Replacement choice (repeat)",si).option("--type <type>","single, multiple, or word-cloud").option("--title <title>","Poll title").option("--team-id <id>","Workspace ID").option("--yes","Approve update").action(async(t,n)=>{if(!n.yes)return c("Pass --yes to approve poll update");try{S(await $("editPoll",{approvalReceipt:"cli:--yes",options:n.option?.map(e=>({text:e})),pollId:t,pollType:n.type,question:n.question,teamId:n.teamId,title:n.title}))}catch(e){c(e instanceof Error?e.message:"Poll update failed"),process.exit(u.GENERAL_ERROR)}}),ci=new Wn("poll").description("Standalone poll commands").addCommand(bc).addCommand(xc);import{Command as li}from"commander";var vc=new li("status").description("Check a presentation generation run").argument("<run-id>","Run ID returned by presentation generation").option("--team-id <id>","Workspace ID override").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{try{let e=await U("createSlides",t,n.teamId);if(n.format==="json"){S(e);return}if(n.format==="quiet"){console.log(e.status);return}m(`Status: ${e.status}`),m(e.message),e.progress!==null&&m(`Progress: ${e.progress}%`),e.error&&c(e.error.message)}catch(e){c(e instanceof Error?e.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),di=new li("presentation").description("Presentation background-run commands").addCommand(vc);import{writeFile as wc}from"fs/promises";import{Command as Sc}from"commander";import Cc from"ora";var ui=new Sc("scrape").description("Extract content from a URL").argument("<url>","URL to scrape").option("--team-id <id>","Workspace ID").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"?Cc("Scraping URL...").start():null;try{let r=await No(t,n.teamId);o?.stop(),(!r.success||!r.data)&&(c(r.error||"Failed to scrape URL"),process.exit(u.GENERAL_ERROR));let i=r.data;if(n.output&&(await wc(n.output,i.content,"utf-8"),e==="human"&&C(`Content saved to: ${n.output}`)),e==="json"){let{cost:a,...s}=i;S(s);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&&_(i.warning),n.output||(console.log(),console.log("--- Content ---"),console.log(i.content)),i.cost&&i.cost>0&&m(`Cost: $${i.cost.toFixed(6)}`)}catch(r){o?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}});import{Command as st}from"commander";function Gt(t,n){n!=="quiet"&&S(t)}var Ic=new st("web").description("Search current public web sources").argument("<query>","Search query").option("--team-id <id>","Workspace ID").option("--max-results <count>","Maximum results","5").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{try{let e=await $("searchInternet",{maxResults:Number.parseInt(n.maxResults,10),query:t,teamId:n.teamId});Gt(e,n.format)}catch(e){c(e instanceof Error?e.message:"Search failed"),process.exit(u.GENERAL_ERROR)}}),Tc=new st("news").description("Search recent news").argument("<topic>","News topic").option("--team-id <id>","Workspace ID").option("--timeframe <value>","Timeframe hint").option("--max-results <count>","Maximum results","6").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{try{let e=await $("getNews",{maxResults:Number.parseInt(n.maxResults,10),teamId:n.teamId,timeframe:n.timeframe,topic:t});Gt(e,n.format)}catch(e){c(e instanceof Error?e.message:"News search failed"),process.exit(u.GENERAL_ERROR)}}),kc=new st("images").description("Search licensed image providers").argument("<query>","Image search query").option("--team-id <id>","Workspace ID").option("--max-results <count>","Maximum results","10").option("--aspect <aspect>","Aspect: any, square, wide, tall","any").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{try{let e=await $("searchImages",{aspect:n.aspect,maxResults:Number.parseInt(n.maxResults,10),query:t,teamId:n.teamId});Gt(e,n.format)}catch(e){c(e instanceof Error?e.message:"Image search failed"),process.exit(u.GENERAL_ERROR)}}),Rc=new st("video").description("Search licensed stock-video providers").argument("<query>","Stock-video search query").option("--team-id <id>","Workspace ID").option("--max-results <count>","Maximum results","10").option("--orientation <value>","Orientation: landscape, portrait, square, any","any").option("--license <value>","License: free, premium, any","any").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(t,n)=>{try{let e=await $("searchStockVideo",{license:n.license,maxResults:Number.parseInt(n.maxResults,10),orientation:n.orientation,query:t,teamId:n.teamId});Gt(e,n.format)}catch(e){c(e instanceof Error?e.message:"Video search failed"),process.exit(u.GENERAL_ERROR)}}),mi=new st("search").description("Web, news, image, and stock-video search").addCommand(Ic).addCommand(Tc).addCommand(kc).addCommand(Rc);import{Command as zn}from"commander";import Hn from"ora";function Jn(t,n){if(n==="json"){let{cost:e,...o}=t;S(o);return}if(n==="quiet"){t.audioUrl?console.log(t.audioUrl):t.requestId?console.log(t.requestId):console.log(t.id);return}m(`Request ID: ${t.requestId||t.id}`),m(`Status: ${t.status}`),t.duration&&m(`Duration: ${t.duration}s`),t.audioUrl&&C(`Audio URL: ${t.audioUrl}`),t.cost!==void 0&&m(`Cost: $${t.cost.toFixed(4)}`),t.error&&c(`Error: ${t.error}`)}var Ac=new zn("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(u.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(u.INVALID_INPUT)));let o=t.outputFormat,r=o==="human"?Hn("Generating sound effects...").start():null;try{let i=await Do({text:t.text,duration:n,options:{provider:t.provider,promptInfluence:e,loop:t.loop,format:t.format}});if(!t.wait){r?.stop(),Jn(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 ue(()=>dn(s),60,2e3)}if(r?.stop(),a.status==="failed"&&(c(a.error||"Sound effects generation failed"),process.exit(u.GENERAL_ERROR)),Jn(a,o),t.output){if(!a.audioUrl)throw new Error("Sound effect completed without an audio URL");let s=o==="human"?Hn("Downloading...").start():null;await we(a.audioUrl,t.output),s?.stop(),o==="human"&&C(`Saved to: ${t.output}`)}}catch(i){r?.stop(),c(i instanceof Error?i.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),$c=new zn("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"?Hn("Checking status...").start():null;try{let o=await dn(t);e?.stop(),Jn(o,n.format)}catch(o){e?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),pi=new zn("sfx").description("Sound effects generation commands").addCommand(Ac).addCommand($c);import{Command as Wt}from"commander";import{mkdir as Ec,writeFile as gi}from"fs/promises";import yi from"ora";import{dirname as Oc}from"path";var fi="en-US-Neural2-C",hi="gemini",Pc=new Wt("generate").description("Generate speech from text").requiredOption("-t, --text <text>","Text to convert to speech").requiredOption("-o, --output <path>","Output file path").option("--voice-id <voiceId>","Voice ID (e.g., ElevenLabs: 21m00Tcm4TlvDq8ikWAM)").option("--voice <voice>",`Voice name (default: ${fi})`).option("-p, --provider <provider>",`Provider: gemini, elevenlabs, openai (default: ${hi})`).option("-m, --model <model>","Model (provider-specific)").option("-s, --speed <speed>","Speech speed 0.25-4.0 (default: 1.0)").option("--speakers <json>",`Multi-speaker (Gemini, max 2): '[{"name":"Joe","voice":"Kore"},{"name":"Jane","voice":"Puck"}]'`).option("-i, --instructions <text>","Style prompt (OpenAI gpt-4o-mini-tts): tone, accent, speed, emotion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async t=>{let n=t.format,e=n==="human"?yi("Generating speech...").start():null,o;t.speed&&(o=parseFloat(t.speed),(isNaN(o)||o<.25||o>4)&&(e?.stop(),c("Speed must be between 0.25 and 4.0"),process.exit(u.INVALID_INPUT)));let r;if(t.speakers)try{r=JSON.parse(t.speakers),(!Array.isArray(r)||r.length>2)&&(e?.stop(),c("Speakers must be an array with max 2 items"),process.exit(u.INVALID_INPUT))}catch{e?.stop(),c(`Invalid --speakers JSON. Example: '[{"name":"Joe","voice":"Kore"}]'`),process.exit(u.INVALID_INPUT)}try{let i=t.voiceId,a=t.voice||fi,s=t.provider||hi,l={};r&&(l.gemini={speakers:r}),t.instructions&&(l.openai={instructions:t.instructions});let d=await xt({text:t.text,options:{provider:s,voiceId:i,voice:a,model:t.model,speed:o,providerOptions:Object.keys(l).length>0?l:void 0}});e?.stop();let f=t.output.endsWith(`.${d.format}`)?t.output:`${t.output}.${d.format}`;await Ec(Oc(f),{recursive:!0}),await gi(f,d.audioData);let v=f.replace(/\.[^.]+$/,".txt");if(await gi(v,t.text,"utf-8"),n==="json"){S({status:"completed",output:f,audioUrl:d.audioUrl,duration:d.duration,provider:d.provider,format:d.format});return}if(n==="quiet"){console.log(f);return}C(`Saved to: ${f}`),m(`Duration: ${d.duration.toFixed(2)}s`),m(`Provider: ${d.provider}`),m(`Cost: $${d.cost.toFixed(6)}`)}catch(i){e?.stop(),c(i instanceof Error?i.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),Nc=new Wt("voices").description("List available voices").option("-p, --provider <provider>","Filter by provider: gemini, elevenlabs, openai").option("-f, --format <format>","Output format: human, json","human").action(async t=>{let n=t.format==="human"?yi("Fetching voices...").start():null;try{let e=await Eo(t.provider);if(n?.stop(),t.format==="json"){S(e.voices);return}if(Array.isArray(e.voices)){let o=t.provider?.toUpperCase()||"VOICES";console.log(),console.log(`${o} Voices:`),console.log("-".repeat(50));for(let r of e.voices)console.log(` ${r.name} (${r.id})`),console.log(` ${r.description}`)}else for(let[o,r]of Object.entries(e.voices))if(!(!r||r.length===0)){console.log(),console.log(`${o.toUpperCase()} Voices:`),console.log("-".repeat(50));for(let i of r)console.log(` ${i.name} (${i.id})`),console.log(` ${i.description}`)}}catch(e){n?.stop(),c(e instanceof Error?e.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),Dc=new Wt("status").description("Read speech generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").option("-f, --format <format>","Output format: json","json").action(async(t,n)=>{try{S(await U("generateSpeech",t,n.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(u.GENERAL_ERROR)}}),bi=new Wt("tts").description("Text-to-speech commands").addCommand(Pc).addCommand(Nc).addCommand(Dc);import{execSync as Ye,spawn as zc,spawnSync as Xc}from"child_process";import{access as Yn,mkdir as Ke,readFile as lt,rm as Kn,writeFile as ye}from"fs/promises";import{join as G,resolve as ct}from"path";import{Command as Z}from"commander";import Yc from"ffmpeg-static";import dt from"ora";import{homedir as Lc}from"os";import{join as xi}from"path";import{readdir as Fc}from"fs/promises";var Uc="conceptcraft";function Je(){return xi(Lc(),`.${Uc}`,"projects")}function Ht(t){return xi(Je(),t)}async function Xn(){try{let t=Je();return(await Fc(t,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>e.name)}catch{return[]}}function vi(t,n){let e=2,o=`${t}-${e}`;for(;n.includes(o);)e++,o=`${t}-${e}`;return o}import{Command as _c}from"commander";import Mc from"ora";import{execSync as Vc,spawnSync as ze}from"child_process";import{mkdirSync as wi,existsSync as zt,readFileSync as Ci,writeFileSync as Si}from"fs";import{join as Re,basename as jc}from"path";import{tmpdir as qc}from"os";function Xt(t,n){try{return Vc(n,{stdio:"ignore"}),!0}catch{return!1}}function Jt(t){let n=Math.floor(t/60),e=Math.floor(t%60),o=Math.round(t%1*10);return`${n}:${String(e).padStart(2,"0")}.${o}`}function Bc(t){let n=ze("ffprobe",["-v","error","-show_entries","format=duration","-of","default=noprint_wrappers=1:nokey=1",t],{encoding:"utf-8"});return parseFloat(n.stdout.trim())}function Gc(t,n){let e=ze("ffmpeg",["-i",t,"-vf",`select='gt(scene,${n})',showinfo`,"-vsync","vfr","-f","null","-"],{encoding:"utf-8",timeout:12e4}),o=[0],r=(e.stderr||"").split(`
3754
- `);for(let i of r){let a=i.match(/pts_time:([\d.]+)/);if(a){let s=parseFloat(a[1]);s-o[o.length-1]>=1.5&&o.push(s)}}return o}function Wc(t,n,e){let o=[];for(let r=0;r<n.length;r++){let i=n[r]+.5,a=Re(e,`scene_${String(r+1).padStart(2,"0")}.jpg`);ze("ffmpeg",["-ss",String(i),"-i",t,"-vframes","1","-q:v","2","-y",a],{stdio:"ignore",timeout:3e4}),o.push(a)}return o}function Hc(t,n){let e=Re(n,"audio.wav");if(ze("ffmpeg",["-i",t,"-vn","-acodec","pcm_s16le","-ar","16000","-ac","1","-y",e],{stdio:"ignore",timeout:6e4}),!zt(e)||!Xt("whisper","which whisper")&&!Xt("whisper-cpp","which whisper-cpp"))return null;let r=ze("whisper",[e,"--model","base","--output_format","json","--output_dir",n,"--language","en"],{encoding:"utf-8",timeout:3e5}),i=Re(n,"audio.json");if(!zt(i))return null;try{let a=JSON.parse(Ci(i,"utf-8"));return{text:a.text||"",segments:(a.segments||[]).map(s=>({start:s.start,end:s.end,text:s.text?.trim()||""}))}}catch{return null}}function Jc(t,n){let e=Ci(t).toString("base64"),o=JSON.stringify({model:n,prompt:"Describe this image in one short sentence (max 15 words). Focus on: what is shown, the setting, key objects or people.",images:[e],stream:!1}),r=ze("curl",["-s","-X","POST","http://localhost:11434/api/generate","-H","Content-Type: application/json","-d",o],{encoding:"utf-8",timeout:6e4});try{return(JSON.parse(r.stdout).response||"").replace(/!!!IMAGE!!!/gi,"").replace(/\[image[^\]]*\]/gi,"").trim()||"Unable to describe frame"}catch{return"Unable to describe frame"}}var Ii=new _c("analyze").description("Analyze a video file: detect scenes, transcribe audio, describe frames").argument("<file>","Path to video file").option("-o, --output <path>","Output directory for analysis results").option("-t, --threshold <number>","Scene detection threshold (0-1, lower = more scenes)","0.3").option("-m, --model <name>","Ollama vision model","moondream").option("--no-vision","Skip frame description (faster)").option("--no-transcribe","Skip audio transcription").option("-f, --output-format <format>","Output format: human, json","human").action(async(t,n)=>{let e=Mc();zt(t)||(console.error(`File not found: ${t}`),process.exit(1)),Xt("ffmpeg","which ffmpeg")||(console.error("ffmpeg is required. Install: brew install ffmpeg"),process.exit(1)),n.vision!==!1&&!Xt("ollama","which ollama")&&(console.error("ollama is required for vision. Install: brew install ollama"),process.exit(1));let o=n.output||Re(qc(),`video-analyze-${Date.now()}`);wi(o,{recursive:!0});let r=Re(o,"frames");wi(r,{recursive:!0});let i=parseFloat(n.threshold),a=n.model;e.start("Reading video metadata...");let s=Bc(t);e.succeed(`Video: ${Jt(s)} (${s.toFixed(1)}s)`),e.start("Detecting scenes...");let l=Gc(t,i);e.succeed(`Detected ${l.length} scenes`),e.start("Extracting key frames...");let d=Wc(t,l,r);e.succeed(`Extracted ${d.length} key frames`);let f=null;n.transcribe!==!1&&(e.start("Transcribing audio..."),f=Hc(t,o),f?e.succeed(`Transcribed: ${f.segments.length} segments`):e.warn("Transcription skipped (whisper not installed: pip install openai-whisper)"));let v=[];for(let g=0;g<l.length;g++){let T=l[g],b=g<l.length-1?l[g+1]:s,y="";n.vision!==!1&&zt(d[g])&&(e.start(`Describing scene ${g+1}/${l.length}...`),y=Jc(d[g],a),e.succeed(`Scene ${g+1}: ${y}`)),v.push({id:g+1,startTime:T,endTime:b,duration:b-T,framePath:d[g],description:y})}let I={source:t,duration:s,scenes:v,transcript:f};if(n.outputFormat==="json"){let g=JSON.stringify(I,null,2),T=Re(o,"analysis.json");Si(T,g),console.log(g)}else{let g=["# Video Analysis","",`**Source:** ${jc(t)}`,`**Duration:** ${Jt(s)} (${s.toFixed(1)}s)`,`**Scenes:** ${v.length}`,"","## Scenes",""];for(let y of v){if(g.push(`### Scene ${y.id} (${Jt(y.startTime)} - ${Jt(y.endTime)}) [${y.duration.toFixed(1)}s]`),y.description&&g.push(`**Visual:** ${y.description}`),f?.segments){let x=f.segments.filter(E=>E.end>y.startTime&&E.start<y.endTime);x.length>0&&g.push(`**Audio:** ${x.map(E=>E.text).join(" ").trim()}`)}g.push(`**Frame:** ${y.framePath}`),g.push("")}f?.text&&(g.push("## Full Transcript"),g.push(""),g.push(f.text.trim()),g.push(""));let T=g.join(`
3755
- `),b=Re(o,"analysis.md");Si(b,T),console.log(T),console.log(`
3756
- Results saved to: ${o}`)}});var Kc="inizio-inc/remotion-video-template#main",Xe=30;async function Qc(t){let n=await lt(t,"utf-8");return JSON.parse(n)}async function Zc(t){let n=G(t,"template.manifest.json");try{return await Qc(n)}catch{return{entry:"src/Root.tsx",compositions:[{id:"Main",type:"youtube",aspect:"16:9",default:!0}]}}}function Ti(){try{return Ye("bun --version",{stdio:"ignore"}),!0}catch{return!1}}function el(t){if(t.includes("---")||t.includes("[Section")){let r=t.split(/---|\[Section \d+\]/i).filter(i=>i.trim());if(r.length>1)return r.map(i=>i.trim())}let n=t.split(/(?<=[.!?])\s+/).map(r=>r.trim()).filter(r=>r.length>0),e=[],o="";for(let r of n){let i=r.split(/\s+/).length;o?(e.push(`${o} ${r}`),o=""):i<5&&e.length<n.length-1?o=r:e.push(r)}return o&&(e.length>0?e[e.length-1]+=` ${o}`:e.push(o)),e}function tl(t,n,e=Xe,o){if(o&&o.characters.length>0)return nl(t,o,e);let r=t.reduce((a,s)=>a+s.split(/\s+/).length,0),i=0;return t.map((a,s)=>{let l=a.split(/\s+/).length,d=l/r,f=n*d,v=Math.round(f*e),I=a.split(""),g=f/I.length,T={characters:I,characterStartTimesSeconds:I.map((y,x)=>x*g),characterEndTimesSeconds:I.map((y,x)=>(x+1)*g)},b={id:s+1,text:a,wordCount:l,startTime:i,endTime:i+f,durationInSeconds:f,durationInFrames:v,timestamps:T};return i+=f,b})}function nl(t,n,e){let{characters:o,characterStartTimesSeconds:r,characterEndTimesSeconds:i}=n,a=o.join(""),s=[],l=0;for(let d=0;d<t.length;d++){let f=t[d],v=f.length;for(;l<o.length&&o[l].match(/^\s*$/);)l++;let I=l,g=r[I]||0;l+=v;let T=l-1;for(;T>I&&o[T]?.match(/^\s*$/);)T--;let b=i[Math.min(T,i.length-1)]||g+1,y=b-g,x=Math.round(y*e),E={characters:o.slice(I,T+1),characterStartTimesSeconds:r.slice(I,T+1).map(A=>A-g),characterEndTimesSeconds:i.slice(I,T+1).map(A=>A-g)};s.push({id:d+1,text:f,wordCount:f.split(/\s+/).length,startTime:g,endTime:b,durationInSeconds:y,durationInFrames:x,timestamps:E})}return s}function ol(t){let n=t==="tiktok"?"vertical":t==="audiogram"?"square":"widescreen";return{scenes:[{name:"Hook",script:"Replace this with a bold opening line that grabs attention.",imageQuery:`cinematic ${n} intro visual, dramatic lighting`,videoQuery:`abstract ${n} motion background`},{name:"Proof",script:"Share the core insight, benefit, or product moment you want viewers to remember.",imageQuery:`people collaborating ${n} office, warm lighting`,videoQuery:`close-up hands using technology ${n}`},{name:"Close",script:"End with a crisp call to action and a confident closing line.",imageQuery:`bold typography ${n} background, high contrast`,videoQuery:`sunrise skyline ${n} timelapse`}],voice:"en-US-Neural2-C",voiceSettings:{speed:1,stability:.4,style:.6},musicPrompt:"uplifting cinematic background, modern and confident"}}async function rl(t,n,e){let o=G(t,"public"),r=G(t,"scripts");await Ke(o,{recursive:!0}),await Ke(r,{recursive:!0});let i=G(o,"scenes.json");await ye(i,JSON.stringify(ol(n),null,2),"utf-8");let a=`import { execSync } from "node:child_process";
3757
-
3758
- execSync("${e} video generate plan --project .", { stdio: "inherit" });
3735
+ `}var dt=["main","video","presentation","presentation-edit","tts","music","sfx","mix","image","video-search","scrape","branding","config"],Wt=["standalone","studio"],ei={cmd:g.commands[0],pkg:g.packageName,url:g.apiUrl,name:g.name},ze=new bc("skill").description(`Manage ${g.displayName} skills for AI coding assistants`).addHelpText("after",`
3736
+ ${V.bold("Skill Types:")}
3737
+ ${V.cyan("main")} Main CLI skill with all capabilities overview
3738
+ ${V.cyan("video")} Detailed video creation workflow with Remotion/R3F patterns
3739
+ ${V.cyan("presentation")} Detailed presentation creation workflow
3740
+ ${V.cyan("presentation-edit")} In-app presentation editing (Studio)
3741
+
3742
+ ${V.bold("Reference Skills:")}
3743
+ ${V.cyan("tts")} Text-to-speech generation (voices, providers, options)
3744
+ ${V.cyan("music")} AI music generation (prompts, styles, duration)
3745
+ ${V.cyan("sfx")} Sound effects generation (categories, looping, formats)
3746
+ ${V.cyan("mix")} Audio mixing (video + voice + music)
3747
+ ${V.cyan("image")} Image search and AI generation
3748
+ ${V.cyan("video-search")} Stock video search
3749
+ ${V.cyan("scrape")} URL content extraction
3750
+ ${V.cyan("branding")} Brand profile management
3751
+ ${V.cyan("config")} CLI configuration management
3752
+
3753
+ ${V.bold("Examples:")}
3754
+ ${V.gray("# Install main CLI skill (comprehensive overview)")}
3755
+ $ ${g.commands[0]} skill install main
3756
+
3757
+ ${V.gray("# Install video skill")}
3758
+ $ ${g.commands[0]} skill install video
3759
+
3760
+ ${V.gray("# Install presentation skill")}
3761
+ $ ${g.commands[0]} skill install presentation
3762
+
3763
+ ${V.gray("# Install all skills")}
3764
+ $ ${g.commands[0]} skill install
3765
+
3766
+ ${V.gray("# Install to specific directory")}
3767
+ $ ${g.commands[0]} skill install main --dir ~/.claude
3768
+
3769
+ ${V.gray("# Show skill content")}
3770
+ $ ${g.commands[0]} skill show main
3771
+ `);ze.command("install").description(`Install ${g.displayName} skills for AI coding assistants`).argument("[type]","Skill type: main, video, presentation, or omit for all").option("-d, --dir <path>","Install to specific directory").option("-g, --global","Install globally (to home directory)",!0).option("-l, --local","Install locally (to current directory)").option("-f, --force","Overwrite existing skill files").option("-m, --mode <mode>","Skill mode: standalone (render to file) or studio (Studio Preview)","standalone").action(async(e,n)=>{n.mode&&!Wt.includes(n.mode)&&(c(`Invalid mode: ${n.mode}. Must be one of: ${Wt.join(", ")}`),process.exit(1));let t={...ei,mode:n.mode},o=[];e&&!dt.includes(e)&&(c(`Invalid skill type: ${e}. Must be one of: ${dt.join(", ")}`),process.exit(1));let r=[{name:"tts",content:_e(t)},{name:"music",content:Ve(t)},{name:"sfx",content:Me(t)},{name:"mix",content:je(t)},{name:"image",content:qe(t)},{name:"video-search",content:Be(t)},{name:"scrape",content:Ge(t)},{name:"branding",content:We(t)},{name:"config",content:He(t)}];(!e||e==="main")&&o.push({name:g.name,content:Ut(t),references:r});let i=[{name:"brief-guide",content:Dn.render(t)},{name:"website-assets",content:Nn.render(t)},{name:"source-scraping",content:Ln.render(t)}];(!e||e==="video")&&(o.push({name:`${g.name}-video`,content:Ft(t),references:i}),o.push({name:"remotion-scene-craft",content:Zr(t)})),(!e||e==="presentation")&&o.push({name:`${g.name}-presentation`,content:_t(t)}),(!e||e==="presentation-edit")&&o.push({name:`${g.name}-presentation-edit`,content:Vt(t)}),e==="tts"&&o.push({name:`${g.name}-tts`,content:_e(t)}),e==="music"&&o.push({name:`${g.name}-music`,content:Ve(t)}),e==="sfx"&&o.push({name:`${g.name}-sfx`,content:Me(t)}),e==="mix"&&o.push({name:`${g.name}-mix`,content:je(t)}),e==="image"&&o.push({name:`${g.name}-image`,content:qe(t)}),e==="video-search"&&o.push({name:`${g.name}-video-search`,content:Be(t)}),e==="scrape"&&o.push({name:`${g.name}-scrape`,content:Ge(t)}),e==="branding"&&o.push({name:`${g.name}-branding`,content:We(t)}),e==="config"&&o.push({name:`${g.name}-config`,content:He(t)}),console.log();for(let a of o){m(`Installing ${a.name}...`);let s=Bt(a.name,a.content,{dir:n.dir,local:n.local,force:n.force},a.references);if(s.installed.length>0&&(S(`${a.name} installed successfully`),R(" Installed to",s.installed.join(", "))),s.skipped.length>0&&(m(` Skipped (already exists): ${s.skipped.join(", ")}`),console.log(V.gray(" Use --force to overwrite"))),s.errors.length>0)for(let d of s.errors)c(` ${d}`);s.installed.length===0&&s.skipped.length===0&&s.errors.length===0&&(m(" No supported AI coding assistants detected"),console.log(V.gray(" Supported editors: "+Yr().join(", "))),console.log(V.gray(" Use --dir <path> to install to a specific directory"))),console.log()}if(!e||e==="video"){for(let a of[{name:"video-branding-director",generate:()=>Mn(t)},{name:"video-scene-builder",generate:Fn},{name:"video-scene-reviewer",generate:Un},{name:"video-audio-director",generate:()=>_n(t)},{name:"video-continuity-editor",generate:Vn}]){m(`Installing ${a.name} agent...`);let s=Kr(a.name,a.generate(),{force:n.force,dir:n.dir});if(s.installed.length>0){S(`${a.name} agent installed`);let d={"Claude Code":"~/.claude/agents/","GitHub Copilot":"~/.github/agents/"};R(" Installed to",s.installed.map(u=>n.dir?u:`${u} (${d[u]??"~/.<editor>/agents/"})`).join(", "))}s.skipped.length>0&&m(` Agent skipped (already exists): ${s.skipped.join(", ")}`)}console.log()}});ze.command("show").description("Display skill content").argument("[type]","Skill type (default: main)").option("-m, --mode <mode>","Skill mode: standalone or studio","standalone").action((e="main",n)=>{n.mode&&!Wt.includes(n.mode)&&(c(`Invalid mode: ${n.mode}. Must be one of: ${Wt.join(", ")}`),process.exit(1));let t={...ei,mode:n.mode},r={main:()=>Ut(t),video:()=>Ft(t),presentation:()=>_t(t),"presentation-edit":()=>Vt(t),tts:()=>_e(t),music:()=>Ve(t),sfx:()=>Me(t),mix:()=>je(t),image:()=>qe(t),"video-search":()=>Be(t),scrape:()=>Ge(t),branding:()=>We(t),config:()=>He(t),"video-branding-director":()=>Mn(t),"video-scene-builder":()=>Fn(),"video-scene-reviewer":()=>Un(),"video-audio-director":()=>_n(t),"video-continuity-editor":()=>Vn()}[e];if(r)console.log(r());else{let i=[...dt,"video-branding-director","video-scene-builder","video-scene-reviewer","video-audio-director","video-continuity-editor"];c(`Invalid skill type: ${e}. Must be one of: ${i.join(", ")}`),process.exit(1)}});ze.command("uninstall").description(`Remove ${g.displayName} skills from AI coding assistants`).argument("[type]","Skill type: main, video, presentation, or omit for all").option("-g, --global","Uninstall globally (from home directory)",!0).option("-l, --local","Uninstall locally (from current directory)").action(async(e,n)=>{let t=[];e&&!dt.includes(e)&&(c(`Invalid skill type: ${e}. Must be one of: ${dt.join(", ")}`),process.exit(1)),(!e||e==="main")&&t.push(g.name),(!e||e==="video")&&(t.push(`${g.name}-video`),t.push("remotion-scene-craft")),(!e||e==="presentation")&&t.push(`${g.name}-presentation`),(!e||e==="presentation-edit")&&t.push(`${g.name}-presentation-edit`),(!e||e==="tts")&&t.push(`${g.name}-tts`),(!e||e==="music")&&t.push(`${g.name}-music`),(!e||e==="sfx")&&t.push(`${g.name}-sfx`),(!e||e==="mix")&&t.push(`${g.name}-mix`),(!e||e==="image")&&t.push(`${g.name}-image`),(!e||e==="video-search")&&t.push(`${g.name}-video-search`),(!e||e==="scrape")&&t.push(`${g.name}-scrape`),(!e||e==="branding")&&t.push(`${g.name}-branding`),(!e||e==="config")&&t.push(`${g.name}-config`),console.log();for(let o of t){let r=Gt(o,{local:n.local});if(r.removed.length>0?(S(`${o} uninstalled`),R(" Removed from",r.removed.join(", "))):m(` ${o} not found`),r.errors.length>0)for(let i of r.errors)_(` Failed to remove: ${i}`)}if(!e||e==="video")for(let o of["video-branding-director","video-scene-builder","video-scene-reviewer","video-audio-director","video-continuity-editor"])Qr(o).removed.length>0&&S(`${o} agent uninstalled`);console.log()});import{Command as wc}from"commander";import lt from"chalk";var ti=new wc("templates").description("List slide design templates (use with `create --template <id>`)").argument("[search]","Filter templates by name, description, or category").option("-f, --format <format>","Output format (table, json)","table").option("--limit <n>","Maximum templates to list","25").action(async(e,n)=>{await P();try{let t=Number.parseInt(n.limit??"25",10),{templates:o}=await Do(e,Number.isFinite(t)?t:25);if(o.length===0){n.format==="json"?console.log(JSON.stringify([])):m("No templates found");return}if(n.format==="json"){console.log(JSON.stringify(o,null,2));return}for(let r of o){let i=[r.isDefault?lt.green("default"):null,r.category??null,r.recommendedModes?.length?`modes: ${r.recommendedModes.join("/")}`:null].filter(Boolean).join(" \xB7 ");console.log(`${lt.bold(r.name)} ${lt.gray(r.id)}${i?`
3772
+ ${lt.gray(i)}`:""}`)}console.log(),console.log(lt.gray(`Use one with: ${g.commands[0]} create "<topic>" --template <id>`))}catch(t){c(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}});import{Command as vc}from"commander";import jn from"chalk";var ni=new vc("whoami").description("Show current user and team information").option("-f, --format <format>","Output format (human, json)","human").action(async e=>{await P();try{let n=await we();if(Sn(),e.format==="json"){console.log(JSON.stringify(n,null,2));return}fe("User"),console.log(),R("Email",n.user.email),n.user.username&&R("Username",n.user.username),(n.user.firstName||n.user.lastName)&&R("Name",[n.user.firstName,n.user.lastName].filter(Boolean).join(" "));let t=n.authType==="apiKey"?"API Key":n.authType==="oauth"?"OAuth":"Session";if(R("Auth Type",t),n.currentTeam&&(console.log(),fe("Current Team"),console.log(),R("ID",n.currentTeam.id),R("Name",n.currentTeam.name),R("Plan",n.currentTeam.planName),R("Role",n.currentTeam.isOwner?"Owner":"Member")),n.teams.length>1){console.log(),fe("All Teams"),console.log();for(let o of n.teams){let r=o.isCurrent?jn.green(" (current)"):"";console.log(` ${jn.bold(o.name)}${r}`),console.log(jn.gray(` ID: ${o.id} | Plan: ${o.planName} | Role: ${o.role}`))}}console.log()}catch(n){c(n instanceof Error?n.message:String(n)),process.exit(n.exitCode??1)}});function oi(e){return e[0]==="--"?e.slice(1):e}import{Command as qn}from"commander";function xc(e,n){return[...n,e]}var Sc=new qn("create").description("Start durable ad-set generation").argument("<title>","Ad-set title").requiredOption("--brief <brief>","Campaign brief").option("--hook <text>","Opening hook (repeat)",xc,[]).option("--style <style>","ugc, clean, cinematic, or testimonial","ugc").option("--branding-id <id>","Branding ID").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(e,n)=>{if(!n.yes)return c("Pass --yes to approve generation");try{x(await $("createAdSet",{approvalReceipt:"cli:--yes",brandingId:n.brandingId,brief:n.brief,hooks:n.hook.length?n.hook:[n.brief],style:n.style,teamId:n.teamId,title:e}))}catch(t){c(t instanceof Error?t.message:"Generation failed"),process.exit(l.GENERAL_ERROR)}}),Cc=new qn("status").description("Read ad-set generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(e,n)=>{try{x(await L("createAdSet",e,n.teamId))}catch(t){c(t instanceof Error?t.message:"Status failed"),process.exit(l.GENERAL_ERROR)}}),ri=new qn("ad-set").description("Ad set commands").addCommand(Sc).addCommand(Cc);import{Command as ai}from"commander";function ii(e){return new ai(e).description(e==="create"?"Create and activate a scheduled agent":"Create a reviewable agent recommendation").argument("<name>","Agent name").requiredOption("--instructions <markdown>","Agent instructions").option("--description <text>","Agent description","").option("--schedule <frequency>","manual, daily, weekdays, weekly, or monthly","weekly").option("--time <hh:mm>","Local run time","09:00").option("--timezone <zone>","IANA timezone","UTC").option("--output <adapter>","Output adapter","digest").option("--team-id <id>","Workspace ID").option("--yes","Approve saving the agent").action(async(n,t)=>{if(!t.yes)return c("Pass --yes to approve this operation");try{x(await $(e==="create"?"createAgent":"recommendAgent",{approvalReceipt:"cli:--yes",description:t.description,instructionsMarkdown:t.instructions,name:n,output:t.output,schedule:t.schedule,scheduleTime:t.time,teamId:t.teamId,timezone:t.timezone}))}catch(o){c(o instanceof Error?o.message:"Agent operation failed"),process.exit(l.GENERAL_ERROR)}})}var si=new ai("agent").description("Scheduled agent commands").addCommand(ii("create")).addCommand(ii("recommend"));import{Command as Ht}from"commander";import Rc from"ora";import{mkdir as Ic,writeFile as ci}from"fs/promises";import{dirname as Tc}from"path";async function Q(e,n){if(await Ic(Tc(n),{recursive:!0}),e.startsWith("data:")){let r=e.match(/^data:[^;]+;base64,(.+)$/);if(!r)throw new Error("Invalid data URL format");let i=Buffer.from(r[1],"base64");if(i.length===0)throw new Error("Downloaded media was empty");await ci(n,i);return}let t=await fetch(e);if(!t.ok)throw new Error(`Failed to download media: ${t.status}`);let o=Buffer.from(await t.arrayBuffer());if(o.length===0)throw new Error("Downloaded media was empty");await ci(n,o)}var kc=15e3,Ac=40;function Bn(e,n){if(n==="json"){x(e);return}if(n==="quiet"){console.log(e.videoUrl??e.requestId);return}m(`Request ID: ${e.requestId}`),m(`Status: ${e.status}`),e.durationSec!=null&&m(`Duration: ${e.durationSec}s`),e.videoUrl&&S(`Video URL: ${e.videoUrl}`),e.error&&c(`Error: ${e.error}`)}var $c=new Ht("options").description("List available presenter avatars and voices").option("--language <language>","Filter voices by language").option("-f, --format <format>","Output format: human, json, quiet","human").action(async e=>{try{let n=await Jo(e.language);if(e.format==="json"){x(n);return}let t=n.personal??[];if(e.format==="quiet"){for(let o of t)console.log(o.id);for(let o of n.avatars)console.log(o.id);for(let o of n.voices)console.log(o.id);return}if(t.length>0){m("Your presenters:");for(let o of t)console.log(` ${o.id} ${o.name}`)}m("Avatars:");for(let o of n.avatars){let r=o.renderTiers?.length?` [${o.renderTiers.join(", ")}]`:"";console.log(` ${o.id} ${o.name}${r}`)}m("Voices:");for(let o of n.voices)console.log(` ${o.id} ${o.name}${o.language?` (${o.language})`:""}`)}catch(n){c(n instanceof Error?n.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),Ec=new Ht("generate").description("Generate a reusable presenter clip").option("--avatar-id <id>","Avatar id from 'avatar options'; sandbox runs use the host presenter policy").option("--audio-url <url>","Public narration audio URL for avatar lip sync").option("--voice-id <id>","Voice id from 'avatar options'").option("--script <text>","Exact words for the presenter to speak").requiredOption("-o, --output <path>","Local output path").option("--aspect <aspect>","Aspect: 1:1, 9:16, 16:9","9:16").option("--duration <seconds>","Maximum requested duration (1-300)").option("--transparent","Render a transparent-background WebM presenter clip").option("--background-color <hex>","Solid presenter background color, for example #0F172A").option("--background-image-url <url>","Public image URL used as the presenter background").option("--fit <mode>","Background image fit: contain or cover").option("--output-format <container>","Container: mp4 (default) or webm \u2014 webm renders a transparent-background clip (single scene) for compositing").option("--render-tier <tier>","Render cost/quality: basic, standard, premium","basic").option("--title <title>","Clip title","Presenter clip").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async e=>{let n=e.transparent?"webm":e.outputFormat;!!e.audioUrl==!!e.script&&(c("Provide exactly one avatar speech input: --audio-url or --script"),process.exit(l.INVALID_INPUT)),["1:1","9:16","16:9"].includes(e.aspect)||(c("Aspect must be one of 1:1, 9:16, or 16:9"),process.exit(l.INVALID_INPUT)),e.outputFormat!==void 0&&!["mp4","webm"].includes(e.outputFormat)&&(c("Output format must be mp4 or webm"),process.exit(l.INVALID_INPUT)),e.backgroundColor!==void 0&&!/^#[0-9a-fA-F]{6}$/.test(e.backgroundColor)&&(c("Background color must be a six-digit hex value"),process.exit(l.INVALID_INPUT)),e.backgroundColor&&e.backgroundImageUrl&&(c("Provide only one presenter background"),process.exit(l.INVALID_INPUT)),e.fit!==void 0&&!["contain","cover"].includes(e.fit)&&(c("Fit must be contain or cover"),process.exit(l.INVALID_INPUT)),e.fit&&!e.backgroundImageUrl&&(c("Fit requires --background-image-url"),process.exit(l.INVALID_INPUT)),e.transparent&&e.outputFormat==="mp4"&&(c("--transparent cannot be combined with --output-format mp4"),process.exit(l.INVALID_INPUT)),n==="webm"&&(e.backgroundColor||e.backgroundImageUrl)&&(c("Transparent WebM output cannot be combined with a background"),process.exit(l.INVALID_INPUT)),["basic","standard","premium"].includes(e.renderTier)||(c("Render tier must be basic, standard, or premium"),process.exit(l.INVALID_INPUT));let t=e.duration?Number.parseInt(e.duration,10):void 0;t!==void 0&&(!Number.isFinite(t)||t<1||t>300)&&(c("Duration must be between 1 and 300 seconds"),process.exit(l.INVALID_INPUT));let o=e.format==="human"?Rc("Generating presenter clip...").start():null;try{let r=e.audioUrl?{audioUrl:e.audioUrl}:{script:e.script??"",...e.voiceId?{voiceId:e.voiceId}:{}},i=await zo({...r,aspect:e.aspect,...e.avatarId?{avatarId:e.avatarId}:{},...e.backgroundColor?{backgroundHex:e.backgroundColor}:{},...e.backgroundImageUrl?{backgroundImageUrl:e.backgroundImageUrl}:{},...t!==void 0?{durationSec:t}:{},...e.fit?{fit:e.fit}:{},...n?{outputFormat:n}:{},renderTier:e.renderTier,title:e.title});if(!e.wait){o?.stop(),Bn(i,e.format);return}let a=await K(()=>bn(i.requestId),Ac,kc);if(a.status==="failed")throw new Error(a.error||"Presenter generation failed");if(!a.videoUrl)throw new Error("Presenter generation completed without a video URL");o&&(o.text="Downloading presenter clip..."),await Q(a.videoUrl,e.output),o?.stop(),Bn(a,e.format),e.format==="human"&&S(`Saved to: ${e.output}`)}catch(r){o?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),Oc=new Ht("status").description("Check a presenter clip generation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(e,n)=>{try{Bn(await bn(e),n.format)}catch(t){c(t instanceof Error?t.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),di=new Ht("avatar").description("Avatar/presenter media commands").addCommand($c).addCommand(Ec).addCommand(Oc);import{writeFile as li}from"fs/promises";import H from"chalk";import{Command as se}from"commander";import Pc from"ora";var ui=new se("branding").description("Manage brand profiles").addCommand(new se("list").description("List brand profiles").option("-f, --format <format>","Output format (table, json)","table").action(async e=>{await P();try{let n=await gn();if(n.brandings.length===0){e.format==="json"?console.log(JSON.stringify([])):(m("No brand profiles found"),console.log(),console.log(H.gray(`Create one with: ${g.commands[0]} branding extract <url>`)));return}e.format==="json"?console.log(JSON.stringify(n.brandings,null,2)):console.log(nr(n.brandings))}catch(n){c(n instanceof Error?n.message:String(n)),process.exit(n.exitCode??1)}})).addCommand(new se("get").description("Get brand profile details").argument("<id>","Brand profile ID").option("-f, --format <format>","Output format (summary, json)","summary").option("-o, --output <path>","Save JSON to file").action(async(e,n)=>{await P();try{let t=await Lo(e);if(n.output){await li(n.output,JSON.stringify(t,null,2)),S(`Brand profile saved to ${n.output}`);return}if(n.format==="json")console.log(JSON.stringify(t,null,2));else{if(fe("Brand Profile"),console.log(),R("ID",t.id),R("Name",t.name),R("Source URL",t.sourceUrl??H.gray("None")),R("Default",t.isDefault?H.green("Yes"):"No"),t.createdAt&&R("Created",new Date(t.createdAt).toLocaleString()),console.log(),t.primaryColor||t.colors.length>0){if(console.log(H.bold(" Colors")),t.primaryColor){let r=H.bgHex(t.primaryColor)(" ");console.log(` Primary: ${r} ${t.primaryColor}`)}if(t.colors.length>0){console.log(" Palette:");for(let r of t.colors.slice(0,10)){let i=H.bgHex(r.hex)(" "),a=r.role?H.gray(` (${r.role})`):"";console.log(` ${i} ${r.hex}${a}`)}}console.log()}t.logoUrl&&(console.log(H.bold(" Logo")),console.log(` ${t.logoUrl}`),console.log());let o=t.typography;o&&Object.keys(o).length>0&&(console.log(H.bold(" Typography")),(o.primary||o.headings)&&console.log(` Headings: ${o.primary||o.headings||"-"}`),(o.secondary||o.body)&&console.log(` Body: ${o.secondary||o.body||"-"}`),console.log()),(t.confidence||t.extractionMethod)&&(console.log(H.bold(" Extraction")),t.confidence&&console.log(` Confidence: ${Math.round(t.confidence*100)}%`),t.extractionMethod&&console.log(` Method: ${t.extractionMethod}`),console.log()),console.log(H.gray(" Use --format json for full details")),console.log()}}catch(t){c(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}})).addCommand(new se("find").description("Find existing brand profile by name or URL").argument("<query>","Brand name or website URL to search for").action(async e=>{await P();try{let n=await gn(),t=e.toLowerCase().replace(/^https?:\/\//,"").replace(/\/$/,""),o=n.brandings.filter(r=>{let i=(r.name||"").toLowerCase(),a=(r.sourceUrl||"").toLowerCase().replace(/^https?:\/\//,"").replace(/\/$/,"");return i.includes(t)||a.includes(t)||i.length>0&&t.includes(i)||a.length>0&&t.includes(a)});if(o.length===0){m(`No brand profiles matching "${e}"`),console.log(H.gray(` Extract one with: ${g.commands[0]} branding extract <url>`));return}console.log(`Found ${o.length} brand${o.length>1?"s":""}:
3773
+ `);for(let r of o){let i=r.primaryColor?`${H.bgHex(r.primaryColor)(" ")} ${r.primaryColor}`:"";console.log(` ${H.bold(r.name)} ${H.gray(r.id)}`),r.sourceUrl&&console.log(` ${H.gray(r.sourceUrl)}`),i&&console.log(` ${i}`),console.log()}console.log(H.gray(` Export with: ${g.commands[0]} branding get <id> -o branding.json`))}catch(n){c(n instanceof Error?n.message:String(n)),process.exit(n.exitCode??1)}})).addCommand(new se("extract").description("Extract brand profile from a website").argument("<url>","Website URL to extract branding from").option("--team-id <id>","Team ID").option("--yes","Confirm starting a paid/external extraction").option("--no-save","Extract without saving").option("-o, --output <path>","Save JSON to file").action(async(e,n)=>{await P(),n.yes||(c("Pass --yes to confirm brand extraction."),process.exit(l.INVALID_INPUT));try{new URL(e.startsWith("http")?e:`https://${e}`)}catch{c("Invalid URL format"),process.exit(6)}let t=e.startsWith("http")?e:`https://${e}`,o=n.teamId??ht(),r=Pc({text:`Extracting branding from ${t}...`,stream:process.stdout}).start();try{let i=await Uo(t,o,"cli:--yes");r.succeed("Brand extraction started");let a=JSON.stringify(i,null,2);n.output?(await li(n.output,a),S(`Brand profile saved to ${n.output}`)):console.log(a),m(`Check progress with: ${g.commands[0]} branding status ${i.runId}`),console.log()}catch(i){r.fail("Extraction failed"),c(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}})).addCommand(new se("status").description("Check a brand extraction run").argument("<run-id>","Run ID returned by branding extract").option("--team-id <id>","Workspace ID").action(async(e,n)=>{try{x(await L("extractBranding",e,n.teamId))}catch(t){c(t instanceof Error?t.message:"Status failed"),process.exit(l.GENERAL_ERROR)}})).addCommand(new se("set-default").description("Set a brand profile as default").argument("<id>","Brand profile ID").action(async e=>{await P(),m(`To set brand ${e} as default, use the web dashboard.`),console.log(),console.log(H.gray("API support for setting default brand is coming soon."))})).addCommand(new se("competitor").description("Brand competitor commands").addCommand(new se("list").description("List competitors for a brand").option("--branding-id <id>","Brand ID").option("--team-id <id>","Workspace ID").action(async e=>{try{console.log(JSON.stringify(await $("getBrandCompetitors",{brandingId:e.brandingId,teamId:e.teamId}),null,2))}catch(n){c(n instanceof Error?n.message:"Lookup failed"),process.exit(1)}})).addCommand(new se("add").description("Add or update a brand competitor").argument("<name>","Competitor name").option("--branding-id <id>","Brand ID").option("--team-id <id>","Workspace ID").option("--website <url>","Competitor website").option("--x-handle <handle>","Competitor X handle").option("--yes","Confirm writing brand data").action(async(e,n)=>{n.yes||(c("Pass --yes to confirm adding a competitor."),process.exit(l.INVALID_INPUT));try{x(await $("addCompetitor",{approvalReceipt:"cli:--yes",brandingId:n.brandingId,name:e,teamId:n.teamId,website:n.website,xHandle:n.xHandle}))}catch(t){c(t instanceof Error?t.message:"Write failed"),process.exit(l.GENERAL_ERROR)}}))).addCommand(new se("social").description("Brand social handle commands").addCommand(new se("add").description("Add or update a brand social handle").argument("<platform>","Social platform").argument("<handle>","Account handle").option("--branding-id <id>","Brand ID").option("--team-id <id>","Workspace ID").option("--yes","Confirm writing brand data").action(async(e,n,t)=>{t.yes||(c("Pass --yes to confirm adding a social handle."),process.exit(l.INVALID_INPUT));try{x(await $("addBrandSocialHandle",{approvalReceipt:"cli:--yes",brandingId:t.brandingId,handle:n,platform:e,teamId:t.teamId}))}catch(o){c(o instanceof Error?o.message:"Write failed"),process.exit(l.GENERAL_ERROR)}})));import{readFile as Nc}from"fs/promises";import{Command as mi}from"commander";var Dc=new mi("extract").description("Extract normalized text from a URL or local file").argument("<source>","URL, encoded source, or local file path").option("--team-id <id>","Workspace ID").option("--mime-type <type>","Source MIME type").option("--max-length <count>","Maximum output characters","30000").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(e,n)=>{try{let t=e,o;e.includes("://")||(t=await Nc(e,"utf8"),o=e);let r=await $("extractContent",{filename:o,maxLength:Number.parseInt(n.maxLength,10),mimeType:n.mimeType,source:t,teamId:n.teamId});n.format!=="quiet"&&x(r)}catch(t){c(t instanceof Error?t.message:"Extraction failed"),process.exit(l.GENERAL_ERROR)}}),pi=new mi("content").description("Content extraction commands").addCommand(Dc);import Y from"chalk";import{Command as Lc}from"commander";import{existsSync as Uc,readFileSync as Fc}from"fs";import _c,{resolve as gi}from"path";var fi=new Lc("create").description("Create a new presentation").argument("<topic>","The topic or title for the presentation").option("-n, --slides <count>","Number of slides (1-20)").option("-m, --mode <mode>","Generation quality (best, balanced, fast, ultrafast, instant, image-min, image, image-max) \u2014 default: fast. image-min/image/image-max render each slide as a full-bleed AI image (text not editable); slower + pricier, require image-mode access, and cap at 25 slides. image-min is cheapest (brand colors only, no exact fonts).").option("--image-tier <tier>","Embedded-image quality for HTML modes: smart (default, auto-routes per image), fast (cheapest, no extra credits), balanced (+50 credits/slide), best (premium, +200 credits/slide, slow). Ignored for image-*/instant modes.").option("-t, --tone <tone>","Tone (creative, professional, educational, formal, casual)").option("--amount <amount>","Content density (minimal, concise, detailed, extensive)").option("--audience <text>","Target audience description").option("-l, --language <lang>","Output language").option("--branding-id <id>","Branding ID (from `ccr branding list` or `ccr branding extract`)").option("--brand-domain <url>","Brand the deck by website/domain (e.g. https://www.pfizer.com). Errors if no matching saved brand exists.").option("--template <id>","Slide template ID to style the deck after (from `ccr templates`). A default template is applied automatically when omitted.").option("-c, --context <text>","Inline text context (research notes, key facts)").option("--context-file <path>","Path to a context file (text, markdown, JSON)").option("--stdin","Read context from stdin").option("-f, --file <paths...>","Files to upload (PDF, PPTX, DOCX, images)").option("-g, --goal <type>","Goal (inform, persuade, train, learn, entertain, report)").option("--styling <mode>","Styling mode (freeform, brand-only, brand-plus-style, style-only, no-styling)").option("--reference-url <url>","Image URL to use as visual style reference").option("--thinking-depth <depth>","AI thinking depth (quick, moderate, deep, profound)").option("--theme <preset>","[instant mode only] Color theme preset (blue, violet, rose, orange, green)").option("--primary-color <hex>","[instant mode only] Primary color (e.g., #0066CC)").option("--secondary-color <hex>","[instant mode only] Secondary color").option("--accent-color <hex>","[instant mode only] Accent color").option("--background-color <hex>","[instant mode only] Background color").option("--foreground-color <hex>","[instant mode only] Foreground/text color").option("--decorations <style>","[instant mode only] Background decoration (none, waves-bottom-left, waves-top-right, blob-corners, minimal)").option("--team-id <id>","Team ID (switch teams)").option("-o, --output <format>","Output format (human, json, quiet)").option("--no-stream","Wait for completion without streaming progress").option("--wait","Poll until generation completes").option("--debug","Enable debug logging").option("--open","Open in browser after creation").option("--id <uuid>","Use a specific UUID for the presentation").option("--studio","Studio mode: use current directory name as presentation ID (auto-links to Studio preview)").action(async(e,n)=>{await P();let t;n.slides!==void 0&&(t=parseInt(n.slides,10),(Number.isNaN(t)||t<1||t>20)&&(c("Slide count must be between 1 and 20"),process.exit(6)));let o=["best","balanced","fast","ultrafast","instant","image-min","image","image-max"];n.mode&&!o.includes(n.mode)&&(c(`Invalid mode: ${n.mode}. Valid: ${o.join(", ")}`),process.exit(6));let r=["smart","fast","balanced","best"];n.imageTier&&!r.includes(n.imageTier)&&(c(`Invalid image tier: ${n.imageTier}. Valid: ${r.join(", ")}`),process.exit(6));let i=["creative","professional","educational","formal","casual"];n.tone&&!i.includes(n.tone)&&(c(`Invalid tone: ${n.tone}. Valid: ${i.join(", ")}`),process.exit(6));let a=["minimal","concise","detailed","extensive"];n.amount&&!a.includes(n.amount)&&(c(`Invalid amount: ${n.amount}. Valid: ${a.join(", ")}`),process.exit(6));let s=["freeform","brand-only","brand-plus-style","style-only","no-styling"];n.styling&&!s.includes(n.styling)&&(c(`Invalid styling: ${n.styling}. Valid: ${s.join(", ")}`),process.exit(6));let d=["quick","moderate","deep","profound"];n.thinkingDepth&&!d.includes(n.thinkingDepth)&&(c(`Invalid thinking-depth: ${n.thinkingDepth}. Valid: ${d.join(", ")}`),process.exit(6));let u=["inform","persuade","train","learn","entertain","report"];n.goal&&!u.includes(n.goal)&&(c(`Invalid goal: ${n.goal}. Valid: ${u.join(", ")}`),process.exit(6));let p=["blue","violet","rose","orange","green"];n.theme&&!p.includes(n.theme)&&(c(`Invalid theme: ${n.theme}. Valid: ${p.join(", ")}`),process.exit(6));let w=["none","waves-bottom-left","waves-top-right","blob-corners","minimal"];n.decorations&&!w.includes(n.decorations)&&(c(`Invalid decorations: ${n.decorations}. Valid: ${w.join(", ")}`),process.exit(6));let I=n.theme||n.primaryColor||n.secondaryColor||n.accentColor||n.backgroundColor||n.foregroundColor||n.decorations;I&&n.mode&&n.mode!=="instant"&&(c("--theme, --primary-color, --decorations and other color options are only supported with --mode instant"),process.exit(6));let f=n.mode??(I?"instant":"fast"),T=/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;for(let[C,M]of[["primary-color",n.primaryColor],["secondary-color",n.secondaryColor],["accent-color",n.accentColor],["background-color",n.backgroundColor],["foreground-color",n.foregroundColor]])M&&!T.test(M)&&(c(`Invalid ${C}: ${M}. Must be hex (e.g., #0066CC)`),process.exit(6));try{n.output!=="json"&&n.output!=="quiet"&&process.stdout.write(Y.gray("Checking generation limits... "));let C=await Vo(f,t??10,n.teamId);if(n.output!=="json"&&n.output!=="quiet"){console.log(Y.green("\u2713"));let M=C.remaining[f],q=C.limits[f],ne=M===void 0||q===void 0?"":` | ${f}: ${M}/${q} remaining`;console.log(Y.gray(` Plan: ${C.planName}${ne}`))}}catch(C){n.output==="json"?console.log(JSON.stringify({success:!1,error:C instanceof Error?C.message:String(C)})):(console.log(Y.red("\u2717")),c(C instanceof Error?C.message:String(C))),process.exit(C.exitCode??1)}let b=[];if(n.file&&n.file.length>0){for(let C of n.file)Uc(gi(C))||(c(`File not found: ${C}`),process.exit(6));n.output!=="json"&&n.output!=="quiet"&&console.log(Y.gray(`
3774
+ Uploading ${n.file.length} file(s)...`));try{b=await Ao(n.file.map(C=>gi(C)),(C,M,q)=>{n.output!=="json"&&n.output!=="quiet"&&q&&process.stdout.write(`\r ${Y.cyan("\u2B06")} Uploading: ${q} (${C+1}/${M})`)}),n.output!=="json"&&n.output!=="quiet"&&console.log(`\r ${Y.green("\u2713")} Uploaded ${b.length} file(s) `)}catch(C){c(`Failed to upload files: ${C instanceof Error?C.message:String(C)}`),process.exit(1)}}let y;(n.stdin||!process.stdin.isTTY)&&(y=await Vc(),n.stdin&&!y&&(c("No content received from stdin"),process.exit(6)));let v=n.context;if(n.contextFile)try{v=Fc(n.contextFile,"utf-8"),v.trim()||(c(`Context file is empty: ${n.contextFile}`),process.exit(6))}catch{c(`Failed to read context file: ${n.contextFile}`),process.exit(6)}!y&&!v&&b.length===0&&(c("Context is required to create a presentation."),console.log(),console.log(Y.gray(" -f, --file <paths...> Upload files (PDF, PPTX, images)")),console.log(Y.gray(" -c, --context <text> Inline text context")),console.log(Y.gray(" --context-file <path> Read from a file")),console.log(Y.gray(` cat file | ${g.commands[0]} Pipe content`)),process.exit(6));let E=[...b];y&&E.push({id:`stdin-${Date.now()}`,content:y,title:"Piped Content",mime:"text/plain",selected:!0}),v&&E.push({id:`context-${Date.now()}`,content:v,title:"Context",mime:"text/plain",selected:!0});let A,N=n.primaryColor||n.secondaryColor||n.accentColor||n.backgroundColor||n.foregroundColor;(n.theme||N||n.decorations)&&(A={},n.theme&&(A.preset=n.theme),N&&(A.custom={},n.primaryColor&&(A.custom.primary=n.primaryColor),n.secondaryColor&&(A.custom.secondary=n.secondaryColor),n.accentColor&&(A.custom.accent=n.accentColor),n.backgroundColor&&(A.custom.background=n.backgroundColor),n.foregroundColor&&(A.custom.foreground=n.foregroundColor)),n.decorations&&(A.decorations=n.decorations));try{let C=await $o({topic:e,...t!==void 0&&{slideCount:t},mode:f,...n.imageTier&&{imageTier:n.imageTier},...n.tone&&{tone:n.tone},...n.amount&&{amount:n.amount},...n.audience&&{audience:n.audience},...n.language&&{language:n.language},...n.brandingId&&{brandingId:n.brandingId},...n.brandDomain&&{brandDomain:n.brandDomain},...n.template&&{templateId:n.template},...n.styling&&{stylingMode:n.styling},...n.referenceUrl&&{referenceUrl:n.referenceUrl},...n.thinkingDepth&&{thinkingDepth:n.thinkingDepth},...n.goal&&{goal:n.goal},...n.teamId&&{teamId:n.teamId},...A&&{theme:A},...n.studio?{documentId:_c.basename(process.cwd())}:n.id?{documentId:n.id}:{},...E.length>0&&{contentSources:{uploadedFiles:E,contextFiles:[]}}});if(!n.wait){n.output==="json"?console.log(JSON.stringify({success:!0,run:C},null,2)):n.output!=="quiet"&&(S("Presentation generation queued"),R("Run ID",C.runId),R("Status",C.status),console.log(Y.gray(` Check later with presentation status ${C.runId}`)));return}let M=await L("createSlides",C.runId,n.teamId);for(;!M.done;)n.output!=="json"&&n.output!=="quiet"&&console.log(Y.gray(` ${M.message}`)),await new Promise(ne=>setTimeout(ne,(M.nextPollAfterSeconds??5)*1e3)),M=await L("createSlides",C.runId,n.teamId);if(M.error)throw new Error(M.error.message);let q=M.entity?await Se(M.entity.id):void 0;if(n.output==="json")console.log(JSON.stringify({success:!0,presentation:q,run:M,viewUrl:q?De(q.slug,n.language??"en"):void 0},null,2));else{console.log(),S("Presentation created successfully"),console.log(),R("Title",q?.title??e),R("Slides",String(q?.numberOfSlides??t??"\u2014")),console.log();let ne=q?De(q.slug,n.language??"en"):"N/A";ne!=="N/A"&&(console.log(Y.bold(" Open: ")+Y.cyan.underline(ne)),n.open&&await(await import("open")).default(ne)),console.log()}}catch(C){n.output==="json"?console.log(JSON.stringify({success:!1,error:C instanceof Error?C.message:String(C)})):c(C instanceof Error?C.message:String(C)),process.exit(C.exitCode??1)}});async function Vc(){return new Promise(e=>{let n="";if(process.stdin.setEncoding("utf8"),process.stdin.isTTY){e("");return}process.stdin.on("data",t=>{n+=t}),process.stdin.on("end",()=>{e(n.trim())}),setTimeout(()=>{e(n.trim())},100)})}import{Command as Mc}from"commander";import Jt from"chalk";var hi=new Mc("get").description("Get presentation details").argument("<slug>","Presentation slug (e.g., my-presentation-v1-abc123)").option("-f, --format <format>","Output format (summary, full, json)","summary").option("--include <fields>","Fields to include (comma-separated: slides,styling)").option("-l, --language <lang>","Language for view URL","en").action(async(e,n)=>{await P();try{let t=await Se(e);if(n.format==="json"){console.log(JSON.stringify(t,null,2));return}let o=De(t.slug,n.language);fe("Presentation Details"),console.log(),R("Slug",t.slug),R("Title",t.title||"Untitled"),R("Description",t.description||Jt.gray("None")),R("Slides",String(t.numberOfSlides||"-")),R("Mode",t.mode||"-"),R("Created",xn(t.createdAt)),t.updatedAt&&R("Updated",xn(t.updatedAt)),console.log(),o!=="N/A"&&console.log(Jt.bold(" Open: ")+Jt.cyan.underline(o)),console.log(),n.format==="full"&&n.include?.includes("slides")&&(console.log(Jt.gray("(Full slide content available in JSON format)")),console.log())}catch(t){c(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}});import{Command as Xt}from"commander";import jc from"ora";function le(e,n){let t=e instanceof Error?e.message:"Unknown error";return!n||t.includes(n)?t:`${t} Request ID: ${n}. Resume with the matching status command; do not start a duplicate run.`}function qc(e){let n=e.assetType??"image";if(n!=="image"&&n!=="icon")throw new Error("Asset type must be image or icon");let t;if(e.maxResults&&(t=Number.parseInt(e.maxResults,10),Number.isNaN(t)||t<1))throw new Error("Max results must be a positive number");return{query:n==="icon"?`${e.query.trim()} transparent icon isolated symbol`:e.query.trim(),options:{maxResults:t||10,size:e.size,safeSearch:e.safeSearch,assetType:n,transparentBackground:n==="icon"}}}function Bc(e){let n=e.url||e.imageUrl;if(!n)throw new Error("Image search returned a result without a URL");return n}function Gc(e){return e.transparent??e.isTransparent??e.metadata?.transparent??e.metadata?.isTransparent}function Wc(e,n){return e.data.results.flatMap(t=>t.results.map(o=>{let r=o,i=Gc(r);if(n==="icon"&&i!==!0)throw new Error("Icon search returned a result without a verified transparent background");return{...r,url:Bc(r),provider:t.providerName,assetType:n,...i!==void 0?{transparent:i}:{}}}))}function Hc(e){return e.error||e.status==="failed"||e.status==="errored"||e.status==="cancelled"?"failed":e.done||e.status==="completed"?"completed":e.status==="in_progress"?"processing":"pending"}function zt(e){return typeof e=="number"&&Number.isFinite(e)?e:void 0}function Jc(e){return{requestId:e.runId,status:Hc(e),...e.entity?.url?{url:e.entity.url}:{},...e.error?.message?{error:e.error.message}:{},...zt(e.output?.width)!==void 0?{width:zt(e.output?.width)}:{},...zt(e.output?.height)!==void 0?{height:zt(e.output?.height)}:{}}}async function yi(e,n){return Jc(await L("createImage",e,n))}function Gn(e,n){if(n==="json"){x(e);return}if(n==="quiet"){console.log(e.output??e.url??e.requestId);return}m(`Request ID: ${e.requestId}`),m(`Status: ${e.status}`),e.url&&S(`Image URL: ${e.url}`),e.output&&S(`Saved to: ${e.output}`),e.error&&c(`Error: ${e.error}`)}var zc=new Xt("search").description("Search for images").requiredOption("-q, --query <query>","Search query").option("-n, --max-results <number>","Maximum number of results (default: 10)").option("-s, --size <size>","Image size: small, medium, large, any","large").option("--asset-type <type>","Asset intent: image or transparent icon","image").option("--safe-search","Enable safe search (default: true)",!0).option("--no-safe-search","Disable safe search").option("-f, --format <format>","Output format: human, json, quiet","human").action(async e=>{let n=e.format,t=n==="human"?jc("Searching for images...").start():null,o;try{o=qc(e)}catch(r){t?.stop(),c(r instanceof Error?r.message:"Invalid image search request"),process.exit(l.INVALID_INPUT);return}try{let r=await Rt(o);t?.stop(),r.success||(c("Search failed"),process.exit(l.GENERAL_ERROR));let i=o.options?.assetType??"image",a=Wc(r,i);if(n==="json"){x({success:!0,query:e.query,assetType:i,totalResults:a.length,images:a});return}if(n==="quiet"){for(let s of a)console.log(s.url);return}if(a.length===0){m("No images found");return}S(`Found ${a.length} images for "${e.query}"`),console.log();for(let s=0;s<a.length;s++){let d=a[s];console.log(`[${s+1}] ${d.title||"Untitled"}`),console.log(` URL: ${d.url}`),console.log(` Size: ${d.width}x${d.height}`),d.author&&console.log(` Author: ${d.author}`),console.log(` Provider: ${d.provider}`),console.log()}m(`Total cost: $${r.data.totalCost.toFixed(4)}`)}catch(r){t?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),Xc=new Xt("generate").description("Generate an image and optionally save it locally").argument("[prompt]","Image prompt").option("-p, --prompt <text>","Image prompt (named compatibility form)").option("--provider <provider>","Provider override").option("--model <model>","Model override").option("--width <pixels>","Width").option("--height <pixels>","Height").option("--team-id <id>","Workspace ID").option("-o, --output <path>","Local output path").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet","human").option("--yes","Approve generation").action(async(e,n)=>{let t,o=e??n.prompt;o?.trim()||(c("Provide an image prompt as an argument or with --prompt"),process.exit(l.INVALID_INPUT)),n.yes||(c("Pass --yes to approve image generation"),process.exit(l.INVALID_INPUT)),!n.wait&&n.output&&(c("--output requires waiting for completion; remove --no-wait"),process.exit(l.INVALID_INPUT));try{let r=await $("createImage",{approvalReceipt:"cli:--yes",height:n.height?Number.parseInt(n.height,10):void 0,model:n.model,prompt:o.trim(),provider:n.provider,teamId:n.teamId,width:n.width?Number.parseInt(n.width,10):void 0});if(t=r.runId,!n.wait){Gn({requestId:r.runId,status:"pending"},n.format);return}let i=await K(()=>yi(r.runId,n.teamId),180,2e3);if(i.status==="failed")throw new Error(i.error||"Image generation failed");if(!i.url)throw new Error("Image generation completed without an image URL");let a=n.output?{...i,output:n.output}:i;n.output&&await Q(i.url,n.output),Gn(a,n.format)}catch(r){c(le(r,t),n.format),process.exit(l.GENERAL_ERROR)}}),Yc=new Xt("status").description("Read image generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").option("-o, --output <path>","Download a completed image").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(e,n)=>{try{let t=await yi(e,n.teamId);if(n.output){if(t.status!=="completed"||!t.url)throw new Error("Image generation is not complete");await Q(t.url,n.output),t.output=n.output}Gn(t,n.format)}catch(t){c(t instanceof Error?t.message:"Status failed"),process.exit(l.GENERAL_ERROR)}}),bi=new Xt("image").description("Image search and generation commands").addCommand(zc).addCommand(Xc).addCommand(Yc);import{Command as Wn}from"commander";var Kc=new Wn("search").description("Search the workspace Knowledge Hub").argument("[query]","Optional search query").option("--team-id <id>","Workspace ID").option("--kind <kind>","Knowledge kind").option("--limit <count>","Maximum results","10").action(async(e,n)=>{try{x(await $("searchKnowledge",{kind:n.kind,limit:Number.parseInt(n.limit,10),query:e,teamId:n.teamId}))}catch(t){c(t instanceof Error?t.message:"Knowledge search failed"),process.exit(l.GENERAL_ERROR)}}),Qc=new Wn("bundle").description("Read a bounded Open Knowledge Format bundle").option("--team-id <id>","Workspace ID").option("--kind <kind>","Knowledge kind").action(async e=>{try{x(await $("getKnowledgeBundle",{kind:e.kind,teamId:e.teamId}))}catch(n){c(n instanceof Error?n.message:"Knowledge bundle failed"),process.exit(l.GENERAL_ERROR)}}),wi=new Wn("knowledge").description("Knowledge Hub commands").addCommand(Kc).addCommand(Qc);import{Command as Hn}from"commander";var Zc=new Hn("create").description("Start background microsite generation").argument("<title>","Microsite title").requiredOption("--description <brief>","Microsite brief").option("--audience <audience>","Target audience").option("--tone <tone>","Tone").option("--language <language>","Content language","en").option("--branding-id <id>","Branding ID").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(e,n)=>{if(!n.yes)return c("Pass --yes to approve generation");try{x(await $("createMicrosite",{approvalReceipt:"cli:--yes",audience:n.audience,brandingId:n.brandingId,description:n.description,language:n.language,teamId:n.teamId,title:e,tone:n.tone}))}catch(t){c(t instanceof Error?t.message:"Generation failed"),process.exit(l.GENERAL_ERROR)}}),ed=new Hn("status").description("Read microsite generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(e,n)=>{try{x(await L("createMicrosite",e,n.teamId))}catch(t){c(t instanceof Error?t.message:"Status failed"),process.exit(l.GENERAL_ERROR)}}),vi=new Hn("microsite").description("Microsite commands").addCommand(Zc).addCommand(ed);import{Command as Xn}from"commander";import Jn from"ora";function zn(e,n){if(n==="json"){let{cost:t,...o}=e;x(o);return}if(n==="quiet"){e.outputUrl?console.log(e.outputUrl):console.log(e.requestId);return}m(`Request ID: ${e.requestId}`),m(`Status: ${e.status}`),e.duration&&m(`Duration: ${e.duration}s`),e.outputUrl&&S(`Output URL: ${e.outputUrl}`),e.cost!==void 0&&m(`Cost: $${e.cost.toFixed(4)}`),e.error&&c(`Error: ${e.error}`)}var td=new Xn("create").description("Mix audio tracks into a video (music will loop to match video duration)").requiredOption("--video <url>","Input video file/URL").option("--music <url>","Background music file/URL (will loop if shorter than video)").option("--voice <url>","Voiceover file/URL").option("--music-volume <percent>","Music volume 0-100 (default: 30, recommended for mix with voice)","30").option("--voice-volume <percent>","Voice volume 0-100","100").option("-o, --output <path>","Output file path").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async e=>{!e.music&&!e.voice&&(c("At least one of --music or --voice must be provided"),process.exit(l.INVALID_INPUT));let n=parseInt(e.musicVolume,10)/100,t=parseInt(e.voiceVolume,10)/100;(Number.isNaN(n)||n<0||n>1)&&(c("Music volume must be between 0 and 100"),process.exit(l.INVALID_INPUT)),(Number.isNaN(t)||t<0||t>2)&&(c("Voice volume must be between 0 and 200"),process.exit(l.INVALID_INPUT));let o=e.format,r=o==="human"?Jn("Mixing audio...").start():null,i=[{url:e.video,role:"video"}];e.music&&i.push({url:e.music,role:"background",volume:n*5}),e.voice&&i.push({url:e.voice,role:"voice",volume:t*2});try{let a=await Bo({operation:"add-to-video",inputs:i,options:{musicVolume:n,voiceVolume:t}});if(!e.wait){r?.stop(),zn(a,o);return}r&&(r.text=`Processing (ID: ${a.requestId})...`);let s=await K(()=>fn(a.requestId),120,3e3);if(r?.stop(),s.status==="failed"&&(c(s.error||"Audio mixing failed"),process.exit(l.GENERAL_ERROR)),zn(s,o),e.output){if(!s.outputUrl)throw new Error("Audio mix completed without an output URL");let d=o==="human"?Jn("Downloading...").start():null;await Q(s.outputUrl,e.output),d?.stop(),o==="human"&&S(`Saved to: ${e.output}`)}}catch(a){r?.stop(),c(a instanceof Error?a.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),nd=new Xn("status").description("Check status of an audio mix request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(e,n)=>{let t=n.format==="human"?Jn("Checking status...").start():null;try{let o=await fn(e);t?.stop(),zn(o,n.format)}catch(o){t?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),xi=new Xn("mix").description("Audio mixing commands").addCommand(td).addCommand(nd);import{Command as Qn}from"commander";import Yn from"ora";function Kn(e,n){if(n==="json"){let{cost:t,...o}=e;x(o);return}if(n==="quiet"){e.audioUrl?console.log(e.audioUrl):console.log(e.requestId);return}m(`Request ID: ${e.requestId}`),m(`Status: ${e.status}`),e.duration&&m(`Duration: ${e.duration}s`),e.audioUrl&&S(`Audio URL: ${e.audioUrl}`),e.cost!==void 0&&m(`Cost: $${e.cost.toFixed(4)}`),e.error&&c(`Error: ${e.error}`)}var od=new Qn("generate").description("Generate music from a text prompt").requiredOption("-p, --prompt <text>","Music description").option("-d, --duration <seconds>","Duration in seconds (3-600)","30").option("-s, --style <style>","Style preset").option("--provider <provider>","Untrusted provider hint (host policy is authoritative)").option("--mode <mode>","Intent: auto, retrieve, or generate","auto").option("--no-instrumental","Allow vocals (background music is instrumental by default)").option("--tempo <bpm>","Tempo hint in BPM (60-180)").option("--audio-format <format>","Audio format: mp3, wav, flac, ogg","mp3").option("-o, --output <path>","Output file path").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async e=>{let n=Number(e.duration);(!Number.isInteger(n)||n<3||n>600)&&(c("Duration must be between 3 and 600 seconds (10 minutes)"),process.exit(l.INVALID_INPUT)),!e.wait&&e.output&&(c("--output requires waiting for completion; remove --no-wait"),process.exit(l.INVALID_INPUT)),["auto","retrieve","generate"].includes(e.mode)||(c("Mode must be auto, retrieve, or generate"),process.exit(l.INVALID_INPUT)),["mp3","wav","flac","ogg"].includes(e.audioFormat)||(c("Audio format must be mp3, wav, flac, or ogg"),process.exit(l.INVALID_INPUT));let t=e.tempo?Number(e.tempo):void 0;t!==void 0&&(!Number.isInteger(t)||t<60||t>180)&&(c("Tempo must be between 60 and 180 BPM"),process.exit(l.INVALID_INPUT));let o=e.format,r=o==="human"?Yn("Generating music...").start():null,i;try{let a=await Tt({prompt:e.prompt,duration:n,options:{provider:e.provider,mode:e.mode,instrumental:e.instrumental,style:e.style,tempo:t,format:e.audioFormat}});if(i=a.requestId,!e.wait){r?.stop(),Kn(a,o);return}let s=a;if(a.status!=="completed"&&a.status!=="failed"&&(r&&(r.text=`Processing (ID: ${a.requestId})...`),s=await K(()=>st(a.requestId),180,2e3)),r?.stop(),s.status==="failed"&&(c(s.error||"Music generation failed"),process.exit(l.GENERAL_ERROR)),e.output){if(!s.audioUrl)throw new Error("Music completed without an audio URL");let d=o==="human"?Yn("Downloading...").start():null;await Q(s.audioUrl,e.output),d?.stop(),o==="human"&&S(`Saved to: ${e.output}`),s={...s,output:e.output}}Kn(s,o)}catch(a){r?.stop(),c(le(a,i),o),process.exit(l.GENERAL_ERROR)}}),rd=new Qn("status").description("Check status of a music generation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(e,n)=>{let t=n.format==="human"?Yn("Checking status...").start():null;try{let o=await st(e);t?.stop(),Kn(o,n.format)}catch(o){t?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),Si=new Qn("music").description("Music generation commands").addCommand(od).addCommand(rd);import{Command as Zn}from"commander";function Ci(e,n){return[...n,e]}var id=new Zn("create").description("Create a standalone poll").argument("<question>","Poll question").option("--option <text>","Choice (repeat 2-10 times)",Ci,[]).option("--type <type>","single, multiple, or word-cloud","single").option("--title <title>","Poll title").option("--team-id <id>","Workspace ID").option("--yes","Approve creation").action(async(e,n)=>{if(!n.yes)return c("Pass --yes to approve poll creation");try{x(await $("createPoll",{approvalReceipt:"cli:--yes",options:n.option.map(t=>({text:t})),pollType:n.type,question:e,teamId:n.teamId,title:n.title}))}catch(t){c(t instanceof Error?t.message:"Poll creation failed"),process.exit(l.GENERAL_ERROR)}}),ad=new Zn("edit").description("Edit a standalone poll").argument("<poll-id>","Poll UUID").option("--question <question>","New question").option("--option <text>","Replacement choice (repeat)",Ci).option("--type <type>","single, multiple, or word-cloud").option("--title <title>","Poll title").option("--team-id <id>","Workspace ID").option("--yes","Approve update").action(async(e,n)=>{if(!n.yes)return c("Pass --yes to approve poll update");try{x(await $("editPoll",{approvalReceipt:"cli:--yes",options:n.option?.map(t=>({text:t})),pollId:e,pollType:n.type,question:n.question,teamId:n.teamId,title:n.title}))}catch(t){c(t instanceof Error?t.message:"Poll update failed"),process.exit(l.GENERAL_ERROR)}}),Ii=new Zn("poll").description("Standalone poll commands").addCommand(id).addCommand(ad);import{Command as Ti}from"commander";var sd=new Ti("status").description("Check a presentation generation run").argument("<run-id>","Run ID returned by presentation generation").option("--team-id <id>","Workspace ID override").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(e,n)=>{try{let t=await L("createSlides",e,n.teamId);if(n.format==="json"){x(t);return}if(n.format==="quiet"){console.log(t.status);return}m(`Status: ${t.status}`),m(t.message),t.progress!==null&&m(`Progress: ${t.progress}%`),t.error&&c(t.error.message)}catch(t){c(t instanceof Error?t.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),Ri=new Ti("presentation").description("Presentation background-run commands").addCommand(sd);import{writeFile as cd}from"fs/promises";import{Command as dd}from"commander";import ld from"ora";var ki=new dd("scrape").description("Extract content from a URL").argument("<url>","URL to scrape").option("--team-id <id>","Workspace ID").option("-o, --output <path>","Save content to file").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(e,n)=>{let t=n.format,o=t==="human"?ld("Scraping URL...").start():null;try{let r=await Wo(e,n.teamId);o?.stop(),(!r.success||!r.data)&&(c(r.error||"Failed to scrape URL"),process.exit(l.GENERAL_ERROR));let i=r.data;if(n.output&&(await cd(n.output,i.content,"utf-8"),t==="human"&&S(`Content saved to: ${n.output}`)),t==="json"){let{cost:a,...s}=i;x(s);return}if(t==="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&&_(i.warning),n.output||(console.log(),console.log("--- Content ---"),console.log(i.content)),i.cost&&i.cost>0&&m(`Cost: $${i.cost.toFixed(6)}`)}catch(r){o?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}});import{Command as ut}from"commander";function Yt(e,n){n!=="quiet"&&x(e)}var ud=new ut("web").description("Search current public web sources").argument("<query>","Search query").option("--team-id <id>","Workspace ID").option("--max-results <count>","Maximum results","5").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(e,n)=>{try{let t=await $("searchInternet",{maxResults:Number.parseInt(n.maxResults,10),query:e,teamId:n.teamId});Yt(t,n.format)}catch(t){c(t instanceof Error?t.message:"Search failed"),process.exit(l.GENERAL_ERROR)}}),md=new ut("news").description("Search recent news").argument("<topic>","News topic").option("--team-id <id>","Workspace ID").option("--timeframe <value>","Timeframe hint").option("--max-results <count>","Maximum results","6").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(e,n)=>{try{let t=await $("getNews",{maxResults:Number.parseInt(n.maxResults,10),teamId:n.teamId,timeframe:n.timeframe,topic:e});Yt(t,n.format)}catch(t){c(t instanceof Error?t.message:"News search failed"),process.exit(l.GENERAL_ERROR)}}),pd=new ut("images").description("Search licensed image providers").argument("<query>","Image search query").option("--team-id <id>","Workspace ID").option("--max-results <count>","Maximum results","10").option("--aspect <aspect>","Aspect: any, square, wide, tall","any").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(e,n)=>{try{let t=await $("searchImages",{aspect:n.aspect,maxResults:Number.parseInt(n.maxResults,10),query:e,teamId:n.teamId});Yt(t,n.format)}catch(t){c(t instanceof Error?t.message:"Image search failed"),process.exit(l.GENERAL_ERROR)}}),gd=new ut("video").description("Search licensed stock-video providers").argument("<query>","Stock-video search query").option("--team-id <id>","Workspace ID").option("--max-results <count>","Maximum results","10").option("--orientation <value>","Orientation: landscape, portrait, square, any","any").option("--license <value>","License: free, premium, any","any").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(e,n)=>{try{let t=await $("searchStockVideo",{license:n.license,maxResults:Number.parseInt(n.maxResults,10),orientation:n.orientation,query:e,teamId:n.teamId});Yt(t,n.format)}catch(t){c(t instanceof Error?t.message:"Video search failed"),process.exit(l.GENERAL_ERROR)}}),Ai=new ut("search").description("Web, news, image, and stock-video search").addCommand(ud).addCommand(md).addCommand(pd).addCommand(gd);import{Command as no}from"commander";import eo from"ora";function to(e,n){if(n==="json"){let{cost:t,...o}=e;x(o);return}if(n==="quiet"){e.audioUrl?console.log(e.audioUrl):e.requestId?console.log(e.requestId):console.log(e.id);return}m(`Request ID: ${e.requestId||e.id}`),m(`Status: ${e.status}`),e.duration&&m(`Duration: ${e.duration}s`),e.audioUrl&&S(`Audio URL: ${e.audioUrl}`),e.cost!==void 0&&m(`Cost: $${e.cost.toFixed(4)}`),e.error&&c(`Error: ${e.error}`)}var fd=new no("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>","Untrusted provider hint (host policy is authoritative)").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 e=>{let n;e.duration&&(n=parseFloat(e.duration),(isNaN(n)||n<.5||n>30)&&(c("Duration must be between 0.5 and 30 seconds"),process.exit(l.INVALID_INPUT)));let t;e.promptInfluence&&(t=parseFloat(e.promptInfluence),(isNaN(t)||t<0||t>1)&&(c("Prompt influence must be between 0 and 1"),process.exit(l.INVALID_INPUT)));let o=e.outputFormat,r=o==="human"?eo("Generating sound effects...").start():null,i;try{let a=await Ho({text:e.text,duration:n,options:{provider:e.provider,promptInfluence:t,loop:e.loop,format:e.format}});if(i=a.requestId||a.id,!e.wait){r?.stop(),to(a,o);return}let s=a;if(a.status!=="completed"&&a.status!=="failed"){let d=a.requestId||a.id;r&&(r.text=`Processing (ID: ${d})...`),s=await K(()=>yn(d),60,2e3)}if(r?.stop(),s.status==="failed"&&(c(s.error||"Sound effects generation failed"),process.exit(l.GENERAL_ERROR)),to(s,o),e.output){if(!s.audioUrl)throw new Error("Sound effect completed without an audio URL");let d=o==="human"?eo("Downloading...").start():null;await Q(s.audioUrl,e.output),d?.stop(),o==="human"&&S(`Saved to: ${e.output}`)}}catch(a){r?.stop(),c(le(a,i),o),process.exit(l.GENERAL_ERROR)}}),hd=new no("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(e,n)=>{let t=n.format==="human"?eo("Checking status...").start():null;try{let o=await yn(e);t?.stop(),to(o,n.format)}catch(o){t?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),$i=new no("sfx").description("Sound effects generation commands").addCommand(fd).addCommand(hd);import{mkdir as yd,writeFile as Ei}from"fs/promises";import{dirname as bd}from"path";import{Command as Kt}from"commander";import Ni from"ora";var Oi="en-US-Neural2-C",Pi="gemini",wd=new Kt("generate").description("Generate speech from text").requiredOption("-t, --text <text>","Text to convert to speech").requiredOption("-o, --output <path>","Output file path").option("--voice-id <voiceId>","Voice ID (e.g., ElevenLabs: 21m00Tcm4TlvDq8ikWAM)").option("--voice <voice>",`Voice name (default: ${Oi})`).option("-p, --provider <provider>",`Provider: gemini, elevenlabs, openai (default: ${Pi})`).option("-m, --model <model>","Model (provider-specific)").option("-s, --speed <speed>","Speech speed 0.1-4.0 (default: 1.0)").option("-l, --lang <lang>","Language or locale hint (for example en-US)").option("--speakers <json>",`Multi-speaker (Gemini, max 2): '[{"name":"Joe","voice":"Kore"},{"name":"Jane","voice":"Puck"}]'`).option("-i, --instructions <text>","Style prompt (OpenAI gpt-4o-mini-tts): tone, accent, speed, emotion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async e=>{let n=e.format,t=n==="human"?Ni("Generating speech...").start():null,o;e.speed&&(o=parseFloat(e.speed),(Number.isNaN(o)||o<.1||o>4)&&(t?.stop(),c("Speed must be between 0.1 and 4.0"),process.exit(l.INVALID_INPUT)));let r;if(e.speakers)try{r=JSON.parse(e.speakers),(!Array.isArray(r)||r.length===0||r.length>2||r.some(a=>!a||typeof a!="object"||typeof a.name!="string"||!a.name.trim()||typeof a.voice!="string"||!a.voice.trim()))&&(t?.stop(),c("Speakers must be an array with 1-2 name/voice items"),process.exit(l.INVALID_INPUT))}catch{t?.stop(),c(`Invalid --speakers JSON. Example: '[{"name":"Joe","voice":"Kore"}]'`),process.exit(l.INVALID_INPUT)}let i;try{let a=e.voiceId,s=e.voice||Oi,d=e.provider||Pi,u={};r&&(u.gemini={speakers:r}),e.instructions&&(u.openai={instructions:e.instructions});let p=await It({text:e.text,options:{language:e.lang,provider:d,voiceId:a,voice:s,model:e.model,speed:o,providerOptions:Object.keys(u).length>0?u:void 0}});i=p.requestId,t?.stop();let w=e.output.endsWith(`.${p.format}`)?e.output:`${e.output}.${p.format}`;await yd(bd(w),{recursive:!0}),await Ei(w,p.audioData);let I=w.replace(/\.[^.]+$/,".txt");if(await Ei(I,e.text,"utf-8"),n==="json"){x({status:"completed",output:w,audioUrl:p.audioUrl,duration:p.duration,provider:p.provider,format:p.format,voice_id:p.voiceId??null,voice:p.voice??s,model:p.model??e.model??null,speed:p.speed??o??1,lang:p.language??e.lang??null,langApplied:p.langApplied??!1,timestamps:p.timestamps??null,words:p.wordTimings??null});return}if(n==="quiet"){console.log(w);return}S(`Saved to: ${w}`),m(`Duration: ${p.duration.toFixed(2)}s`),m(`Provider: ${p.provider}`),m(`Cost: $${p.cost.toFixed(6)}`)}catch(a){t?.stop(),c(le(a,i),n),process.exit(l.GENERAL_ERROR)}}),vd=new Kt("voices").description("List available voices").option("-p, --provider <provider>","Filter by provider: gemini, elevenlabs, openai").option("-f, --format <format>","Output format: human, json","human").action(async e=>{let n=e.format==="human"?Ni("Fetching voices...").start():null;try{let t=await qo(e.provider);if(n?.stop(),e.format==="json"){x(t.voices);return}if(Array.isArray(t.voices)){let o=e.provider?.toUpperCase()||"VOICES";console.log(),console.log(`${o} Voices:`),console.log("-".repeat(50));for(let r of t.voices)console.log(` ${r.name} (${r.id})`),console.log(` ${r.description}`)}else for(let[o,r]of Object.entries(t.voices))if(!(!r||r.length===0)){console.log(),console.log(`${o.toUpperCase()} Voices:`),console.log("-".repeat(50));for(let i of r)console.log(` ${i.name} (${i.id})`),console.log(` ${i.description}`)}}catch(t){n?.stop(),c(t instanceof Error?t.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),xd=new Kt("status").description("Read speech generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").option("-f, --format <format>","Output format: json","json").action(async(e,n)=>{try{x(await L("generateSpeech",e,n.teamId))}catch(t){c(t instanceof Error?t.message:"Status failed"),process.exit(l.GENERAL_ERROR)}}),Di=new Kt("tts").description("Text-to-speech commands").addCommand(wd).addCommand(vd).addCommand(xd);import{execSync as Ze,spawn as Yd,spawnSync as Kd}from"child_process";import{access as io,mkdir as et,readFile as gt,rm as ao,writeFile as ve}from"fs/promises";import{join as G,resolve as pt}from"path";import{Command as te}from"commander";import Qd from"ffmpeg-static";import ft from"ora";import{homedir as Sd}from"os";import{join as Li}from"path";import{readdir as Cd}from"fs/promises";var Id="conceptcraft";function Xe(){return Li(Sd(),`.${Id}`,"projects")}function Qt(e){return Li(Xe(),e)}async function oo(){try{let e=Xe();return(await Cd(e,{withFileTypes:!0})).filter(t=>t.isDirectory()).map(t=>t.name)}catch{return[]}}function Ui(e,n){let t=2,o=`${e}-${t}`;for(;n.includes(o);)t++,o=`${e}-${t}`;return o}import{Command as Td}from"commander";import Rd from"ora";import{execSync as kd,spawnSync as Ye}from"child_process";import{mkdirSync as Fi,existsSync as en,readFileSync as Vi,writeFileSync as _i}from"fs";import{join as $e,basename as Ad}from"path";import{tmpdir as $d}from"os";function tn(e,n){try{return kd(n,{stdio:"ignore"}),!0}catch{return!1}}function Zt(e){let n=Math.floor(e/60),t=Math.floor(e%60),o=Math.round(e%1*10);return`${n}:${String(t).padStart(2,"0")}.${o}`}function Ed(e){let n=Ye("ffprobe",["-v","error","-show_entries","format=duration","-of","default=noprint_wrappers=1:nokey=1",e],{encoding:"utf-8"});return parseFloat(n.stdout.trim())}function Od(e,n){let t=Ye("ffmpeg",["-i",e,"-vf",`select='gt(scene,${n})',showinfo`,"-vsync","vfr","-f","null","-"],{encoding:"utf-8",timeout:12e4}),o=[0],r=(t.stderr||"").split(`
3775
+ `);for(let i of r){let a=i.match(/pts_time:([\d.]+)/);if(a){let s=parseFloat(a[1]);s-o[o.length-1]>=1.5&&o.push(s)}}return o}function Pd(e,n,t){let o=[];for(let r=0;r<n.length;r++){let i=n[r]+.5,a=$e(t,`scene_${String(r+1).padStart(2,"0")}.jpg`);Ye("ffmpeg",["-ss",String(i),"-i",e,"-vframes","1","-q:v","2","-y",a],{stdio:"ignore",timeout:3e4}),o.push(a)}return o}function Nd(e,n){let t=$e(n,"audio.wav");if(Ye("ffmpeg",["-i",e,"-vn","-acodec","pcm_s16le","-ar","16000","-ac","1","-y",t],{stdio:"ignore",timeout:6e4}),!en(t)||!tn("whisper","which whisper")&&!tn("whisper-cpp","which whisper-cpp"))return null;let r=Ye("whisper",[t,"--model","base","--output_format","json","--output_dir",n,"--language","en"],{encoding:"utf-8",timeout:3e5}),i=$e(n,"audio.json");if(!en(i))return null;try{let a=JSON.parse(Vi(i,"utf-8"));return{text:a.text||"",segments:(a.segments||[]).map(s=>({start:s.start,end:s.end,text:s.text?.trim()||""}))}}catch{return null}}function Dd(e,n){let t=Vi(e).toString("base64"),o=JSON.stringify({model:n,prompt:"Describe this image in one short sentence (max 15 words). Focus on: what is shown, the setting, key objects or people.",images:[t],stream:!1}),r=Ye("curl",["-s","-X","POST","http://localhost:11434/api/generate","-H","Content-Type: application/json","-d",o],{encoding:"utf-8",timeout:6e4});try{return(JSON.parse(r.stdout).response||"").replace(/!!!IMAGE!!!/gi,"").replace(/\[image[^\]]*\]/gi,"").trim()||"Unable to describe frame"}catch{return"Unable to describe frame"}}var Mi=new Td("analyze").description("Analyze a video file: detect scenes, transcribe audio, describe frames").argument("<file>","Path to video file").option("-o, --output <path>","Output directory for analysis results").option("-t, --threshold <number>","Scene detection threshold (0-1, lower = more scenes)","0.3").option("-m, --model <name>","Ollama vision model","moondream").option("--no-vision","Skip frame description (faster)").option("--no-transcribe","Skip audio transcription").option("-f, --output-format <format>","Output format: human, json","human").action(async(e,n)=>{let t=Rd();en(e)||(console.error(`File not found: ${e}`),process.exit(1)),tn("ffmpeg","which ffmpeg")||(console.error("ffmpeg is required. Install: brew install ffmpeg"),process.exit(1)),n.vision!==!1&&!tn("ollama","which ollama")&&(console.error("ollama is required for vision. Install: brew install ollama"),process.exit(1));let o=n.output||$e($d(),`video-analyze-${Date.now()}`);Fi(o,{recursive:!0});let r=$e(o,"frames");Fi(r,{recursive:!0});let i=parseFloat(n.threshold),a=n.model;t.start("Reading video metadata...");let s=Ed(e);t.succeed(`Video: ${Zt(s)} (${s.toFixed(1)}s)`),t.start("Detecting scenes...");let d=Od(e,i);t.succeed(`Detected ${d.length} scenes`),t.start("Extracting key frames...");let u=Pd(e,d,r);t.succeed(`Extracted ${u.length} key frames`);let p=null;n.transcribe!==!1&&(t.start("Transcribing audio..."),p=Nd(e,o),p?t.succeed(`Transcribed: ${p.segments.length} segments`):t.warn("Transcription skipped (whisper not installed: pip install openai-whisper)"));let w=[];for(let f=0;f<d.length;f++){let T=d[f],b=f<d.length-1?d[f+1]:s,y="";n.vision!==!1&&en(u[f])&&(t.start(`Describing scene ${f+1}/${d.length}...`),y=Dd(u[f],a),t.succeed(`Scene ${f+1}: ${y}`)),w.push({id:f+1,startTime:T,endTime:b,duration:b-T,framePath:u[f],description:y})}let I={source:e,duration:s,scenes:w,transcript:p};if(n.outputFormat==="json"){let f=JSON.stringify(I,null,2),T=$e(o,"analysis.json");_i(T,f),console.log(f)}else{let f=["# Video Analysis","",`**Source:** ${Ad(e)}`,`**Duration:** ${Zt(s)} (${s.toFixed(1)}s)`,`**Scenes:** ${w.length}`,"","## Scenes",""];for(let y of w){if(f.push(`### Scene ${y.id} (${Zt(y.startTime)} - ${Zt(y.endTime)}) [${y.duration.toFixed(1)}s]`),y.description&&f.push(`**Visual:** ${y.description}`),p?.segments){let v=p.segments.filter(E=>E.end>y.startTime&&E.start<y.endTime);v.length>0&&f.push(`**Audio:** ${v.map(E=>E.text).join(" ").trim()}`)}f.push(`**Frame:** ${y.framePath}`),f.push("")}p?.text&&(f.push("## Full Transcript"),f.push(""),f.push(p.text.trim()),f.push(""));let T=f.join(`
3776
+ `),b=$e(o,"analysis.md");_i(b,T),console.log(T),console.log(`
3777
+ Results saved to: ${o}`)}});import{mkdir as Ld}from"fs/promises";import{join as Ud}from"path";import{Command as mt}from"commander";import qi from"ora";var Fd=5e3,_d=120,ji=5;function Vd(e,n){return[...n,e]}function Md(e,n){try{let t=new URL(e);if(t.protocol!=="https:"&&t.protocol!=="http:")throw new Error;return t.toString()}catch{throw new Error(`${n} must be a public HTTP(S) URL`)}}function Bi(e){if(!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(e))throw new Error("Source video id must be a UUID");return e}function jd(e){if(e.mode&&!["speed","precision"].includes(e.mode))throw new Error("Lip-sync mode must be speed or precision");return{audioUrl:Md(e.audioUrl,"Audio URL"),...e.mode?{mode:e.mode}:{},sourceVideoId:Bi(e.sourceVideoId)}}function qd(e){let n=[],t=new Set;for(let r of e.targetLanguage){let i=r.trim(),a=i.toLocaleLowerCase("en-US");!i||t.has(a)||(t.add(a),n.push(i))}if(n.length===0)throw new Error("Provide at least one target language");if(n.length>ji)throw new Error(`Provide at most ${ji} target languages`);if(n.find(r=>r.length<2||r.length>40))throw new Error("Target languages must be between 2 and 40 characters");return{...e.captions?{captions:!0}:{},sourceVideoId:Bi(e.sourceVideoId),targetLanguages:n}}function Bd(e){return e.error||e.status==="failed"||e.status==="cancelled"?"failed":e.done||e.status==="completed"?"completed":e.status==="in_progress"||e.status==="processing"?"processing":"pending"}function ro(e){return{requestId:e.runId,status:Bd(e),...e.entity?.url?{videoUrl:e.entity.url}:{},...e.output?{output:e.output}:{},...e.error?.message?{error:e.error.message}:{}}}function Gi(e){return{requestId:e.runId,status:"pending"}}async function Wi(e,n){return K(async()=>ro(await L(e,n)),_d,Fd)}function Ke(e,n){if(n==="json"){x(e);return}if(n==="quiet"){console.log(e.videoUrl??e.requestId);return}m(`Request ID: ${e.requestId}`),m(`Status: ${e.status}`),e.videoUrl&&S(`Video URL: ${e.videoUrl}`),e.error&&c(`Error: ${e.error}`)}function Gd(e){return Array.isArray(e?.languages)?e.languages.filter(n=>{if(!n||typeof n!="object"||Array.isArray(n))return!1;let t=n;return typeof t.language=="string"&&(t.status==="completed"||t.status==="failed")&&typeof t.videoId=="string"&&(t.videoUrl===null||typeof t.videoUrl=="string")}):[]}function Wd(e){return`${e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")||"translation"}.mp4`}function Hd(e,n){let t=Wd(e);if(!n.has(t))return n.add(t),t;let o=t.slice(0,-4),r=2;for(;n.has(`${o}-${r}.mp4`);)r+=1;let i=`${o}-${r}.mp4`;return n.add(i),i}async function Jd(e,n){let t=Gd(e.output).filter(i=>i.status==="completed"&&!!i.videoUrl);if(t.length===0)throw new Error("Video translation completed without downloadable results");await Ld(n,{recursive:!0});let o=[],r=new Set;for(let i of t){let a=Ud(n,Hd(i.language,r));await Q(i.videoUrl,a),o.push({language:i.language,path:a})}return o}var zd=new mt("status").description("Check a video lip-sync request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(e,n)=>{try{Ke(ro(await L("lipsyncVideo",e)),n.format)}catch(t){c(t instanceof Error?t.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),Hi=new mt("lipsync").description("Re-voice a ready workspace video with a public audio URL").requiredOption("--source-video-id <uuid>","READY workspace video UUID").requiredOption("--audio-url <url>","Public replacement voice audio URL").option("--mode <mode>","Quality mode: speed or precision","speed").requiredOption("-o, --output <path>","Local output video path").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async e=>{let n=e.format==="human"?qi("Starting video lip-sync...").start():null,t;try{let o=await Xo(jd(e));if(t=o.runId,!e.wait){n?.stop(),Ke(Gi(o),e.format);return}n&&(n.text="Waiting for video lip-sync...");let r=await Wi("lipsyncVideo",o.runId);if(r.status==="failed")throw new Error(r.error??"Video lip-sync failed");if(!r.videoUrl)throw new Error("Video lip-sync completed without a video URL");n&&(n.text="Downloading lip-synced video..."),await Q(r.videoUrl,e.output),n?.stop(),Ke(r,e.format),e.format==="human"&&S(`Saved to: ${e.output}`)}catch(o){n?.stop(),c(le(o,t),e.format),process.exit(l.GENERAL_ERROR)}}).addCommand(zd),Ji=new mt("translate-languages").description("List supported video translation target languages").option("-f, --format <format>","Output format: human, json, quiet","human").action(async e=>{try{let n=await Yo();if(e.format==="json")x({languages:n});else for(let t of n)console.log(t)}catch(n){c(n instanceof Error?n.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),Xd=new mt("status").description("Check a video translation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(e,n)=>{try{Ke(ro(await L("translateVideo",e)),n.format)}catch(t){c(t instanceof Error?t.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),zi=new mt("translate").description("Translate a ready workspace video into one or more languages").requiredOption("--source-video-id <uuid>","READY workspace video UUID").option("--target-language <language>","Target language (repeatable)",Vd,[]).option("--captions","Burn provider-generated captions into translated videos").requiredOption("--output-dir <path>","Directory for translated videos").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async e=>{let n=e.format==="human"?qi("Starting video translation...").start():null,t;try{let o=await Ko(qd(e));if(t=o.runId,!e.wait){n?.stop(),Ke(Gi(o),e.format);return}n&&(n.text="Waiting for video translations...");let r=await Wi("translateVideo",o.runId);if(r.status==="failed")throw new Error(r.error??"Video translation failed");n&&(n.text="Downloading translated videos...");let i=await Jd(r,e.outputDir);if(n?.stop(),e.format==="json")x({...r,downloads:i});else if(e.format==="quiet")for(let a of i)console.log(a.path);else{Ke(r,e.format);for(let a of i)S(`${a.language}: ${a.path}`)}}catch(o){n?.stop(),c(le(o,t),e.format),process.exit(l.GENERAL_ERROR)}}).addCommand(Xd);var Zd="inizio-inc/remotion-video-template#main",Qe=30;async function el(e){let n=await gt(e,"utf-8");return JSON.parse(n)}async function tl(e){let n=G(e,"template.manifest.json");try{return await el(n)}catch{return{entry:"src/Root.tsx",compositions:[{id:"Main",type:"youtube",aspect:"16:9",default:!0}]}}}function Xi(){try{return Ze("bun --version",{stdio:"ignore"}),!0}catch{return!1}}function nl(e){if(e.includes("---")||e.includes("[Section")){let r=e.split(/---|\[Section \d+\]/i).filter(i=>i.trim());if(r.length>1)return r.map(i=>i.trim())}let n=e.split(/(?<=[.!?])\s+/).map(r=>r.trim()).filter(r=>r.length>0),t=[],o="";for(let r of n){let i=r.split(/\s+/).length;o?(t.push(`${o} ${r}`),o=""):i<5&&t.length<n.length-1?o=r:t.push(r)}return o&&(t.length>0?t[t.length-1]+=` ${o}`:t.push(o)),t}function ol(e,n,t=Qe,o){if(o&&o.characters.length>0)return rl(e,o,t);let r=e.reduce((a,s)=>a+s.split(/\s+/).length,0),i=0;return e.map((a,s)=>{let d=a.split(/\s+/).length,u=d/r,p=n*u,w=Math.round(p*t),I=a.split(""),f=p/I.length,T={characters:I,characterStartTimesSeconds:I.map((y,v)=>v*f),characterEndTimesSeconds:I.map((y,v)=>(v+1)*f)},b={id:s+1,text:a,wordCount:d,startTime:i,endTime:i+p,durationInSeconds:p,durationInFrames:w,timestamps:T};return i+=p,b})}function rl(e,n,t){let{characters:o,characterStartTimesSeconds:r,characterEndTimesSeconds:i}=n,a=o.join(""),s=[],d=0;for(let u=0;u<e.length;u++){let p=e[u],w=p.length;for(;d<o.length&&o[d].match(/^\s*$/);)d++;let I=d,f=r[I]||0;d+=w;let T=d-1;for(;T>I&&o[T]?.match(/^\s*$/);)T--;let b=i[Math.min(T,i.length-1)]||f+1,y=b-f,v=Math.round(y*t),E={characters:o.slice(I,T+1),characterStartTimesSeconds:r.slice(I,T+1).map(A=>A-f),characterEndTimesSeconds:i.slice(I,T+1).map(A=>A-f)};s.push({id:u+1,text:p,wordCount:p.split(/\s+/).length,startTime:f,endTime:b,durationInSeconds:y,durationInFrames:v,timestamps:E})}return s}function il(e){let n=e==="tiktok"?"vertical":e==="audiogram"?"square":"widescreen";return{scenes:[{name:"Hook",script:"Replace this with a bold opening line that grabs attention.",imageQuery:`cinematic ${n} intro visual, dramatic lighting`,videoQuery:`abstract ${n} motion background`},{name:"Proof",script:"Share the core insight, benefit, or product moment you want viewers to remember.",imageQuery:`people collaborating ${n} office, warm lighting`,videoQuery:`close-up hands using technology ${n}`},{name:"Close",script:"End with a crisp call to action and a confident closing line.",imageQuery:`bold typography ${n} background, high contrast`,videoQuery:`sunrise skyline ${n} timelapse`}],voice:"en-US-Neural2-C",voiceSettings:{speed:1,stability:.4,style:.6},musicPrompt:"uplifting cinematic background, modern and confident"}}async function al(e,n,t){let o=G(e,"public"),r=G(e,"scripts");await et(o,{recursive:!0}),await et(r,{recursive:!0});let i=G(o,"scenes.json");await ve(i,JSON.stringify(il(n),null,2),"utf-8");let a=`import { execSync } from "node:child_process";
3778
+
3779
+ execSync("${t} video generate plan --project .", { stdio: "inherit" });
3759
3780
  `,s=`import { execSync } from "node:child_process";
3760
3781
 
3761
3782
  const args = process.argv.slice(2).join(" ");
3762
- execSync("${e} video export --project . " + args, { stdio: "inherit" });
3763
- `;await ye(G(r,"plan.ts"),a,"utf-8"),await ye(G(r,"export.ts"),s,"utf-8")}async function ki(){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 il(t){return t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function al(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 Yt(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 ye(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 ye(n,Buffer.from(o))}function sl(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 cl=new Z("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"?dt("Initializing...").start():null,o=t.project?ct(process.cwd(),t.project):null;try{let r=await ki(),i=null;if(t.scenes&&!t.scriptFile&&(t.scriptFile=t.scenes),o&&(t.output=G(o,"public"),t.scriptFile?t.scriptFile=ct(o,t.scriptFile):!t.script&&!r&&(t.scriptFile=G(o,"public","scenes.json"))),r)try{let R=JSON.parse(r);R.scenes&&Array.isArray(R.scenes)&&(i=R)}catch{}if(!i&&t.scriptFile)try{let R=await lt(t.scriptFile,"utf-8"),J=JSON.parse(R);J.scenes&&Array.isArray(J.scenes)&&(i=J)}catch{}let a=i?.voice||t.voice,s=i?.voiceId,l=i?.provider,d=i?.model,f=i?.voiceInstructions,v=i?.musicPrompt||t.musicPrompt||"uplifting background music, positive energy",I=i?.musicDuration,g=G(t.output,"audio"),T=G(t.output,"images"),b=G(t.output,"videos");e&&(e.text="Creating directories..."),await Ke(g,{recursive:!0}),await Ke(T,{recursive:!0}),await Ke(b,{recursive:!0});let y=0,x=[],E=0,A=[],P=[];if(i&&i.scenes.length>0){n==="human"&&(e?.stop(),m(`Processing ${i.scenes.length} scenes...`),e?.start());let R=i.scenes.map((ne,B)=>{let ge=ne.script;return ne.voiceStyle&&(ge=`${ne.voiceStyle} ${ge}`),{text:ge,id:`scene-${B}`}});e&&(e.text="Generating speech for all scenes...");let J=await $o({texts:R,options:{provider:l,voice:a,voiceId:s,model:d,voiceSettings:i.voiceSettings,instructions:f}});y+=J.totalCost;let te=0;for(let ne=0;ne<i.scenes.length;ne++){let B=i.scenes[ne],ge=il(B.name),le=J.results[ne];e&&(e.text=`[${B.name}] Saving audio...`);let en=G(g,`${ge}.${le.format}`);await ye(en,le.audioData);let $e=le.duration,Di=Math.round($e*Xe),Ze={id:ne+1,name:B.name,text:B.script,wordCount:B.script.split(/\s+/).length,startTime:te,endTime:te+$e,durationInSeconds:$e,durationInFrames:Di,audioPath:`audio/${ge}.${le.format}`,timestamps:le.timestamps};if(B.imageQuery){e&&(e.text=`[${B.name}] Searching image...`);try{let K=await wt({query:B.imageQuery,options:{maxResults:1,size:"large",safeSearch:!0}}),et=K.data.results.flatMap(X=>X.results);if(y+=K.data.totalCost,et.length>0){let X=et[0],tt=sl(X.url),Se=`${ge}.${tt}`,tn=G(T,Se);await Yt(X.url,tn),Ze.imagePath=`images/${Se}`,A.push({path:`images/${Se}`,url:X.url,width:X.width,height:X.height,query:B.imageQuery})}}catch(K){n==="human"&&(e?.stop(),_(`[${B.name}] Image search failed: ${K instanceof Error?K.message:"Unknown"}`),e?.start())}}if(B.videoQuery){e&&(e.text=`[${B.name}] Searching video...`);try{let K=await ln({query:B.videoQuery,options:{maxResults:1,license:"free"}}),et=K.data.results.flatMap(X=>X.results);if(y+=K.data.totalCost,et.length>0){let X=et[0],tt=X.previewUrl||X.downloadUrl;if(tt){let Se=`${ge}.mp4`,tn=G(b,Se);await Yt(tt,tn),Ze.videoPath=`videos/${Se}`,P.push({path:`videos/${Se}`,url:tt,width:X.width,height:X.height,duration:X.duration,query:B.videoQuery})}}}catch(K){n==="human"&&(e?.stop(),_(`[${B.name}] Video search failed: ${K instanceof Error?K.message:"Unknown"}`),e?.start())}}if(x.push(Ze),te+=$e,E+=$e,n==="human"){e?.stop();let K=[`audio: ${$e.toFixed(1)}s`,Ze.imagePath?"image":null,Ze.videoPath?"video":null].filter(Boolean).join(", ");C(` ${B.name}: ${K}`),e?.start()}}}else{let R=t.script;if(t.scriptFile)try{R=await lt(t.scriptFile,"utf-8")}catch(le){e?.stop(),c(`Failed to read script file: ${le instanceof Error?le.message:"Unknown error"}`),process.exit(u.INVALID_INPUT)}(!R||R.trim().length===0)&&(e?.stop(),c("Provide scenes via stdin JSON, --scenes/--script-file with scenes JSON, or --script for legacy mode"),process.exit(u.INVALID_INPUT)),R=R.trim();let J=t.topic||R.split(".")[0].slice(0,50);e&&(e.text="Generating voiceover...");let te=await xt({text:R,options:{voice:a}}),ne=G(g,`voiceover.${te.format}`);await ye(ne,te.audioData),y+=te.cost,E=te.duration;let B=el(R);x=tl(B,te.duration,Xe,te.timestamps).map((le,en)=>({...le,name:`Section${en+1}`,audioPath:`audio/voiceover.${te.format}`})),n==="human"&&(e?.stop(),C(`Voiceover: ${ne} (${te.duration.toFixed(1)}s)`),e?.start())}e&&(e.text="Creating timeline...");let w=al(x),V=Math.max(w.audio.length>0?Math.max(...w.audio.map(R=>R.endMs)):0,w.text.length>0?Math.max(...w.text.map(R=>R.endMs)):0,w.elements.length>0?Math.max(...w.elements.map(R=>R.endMs)):0),q=V/1e3,ee=I?Math.min(300,Math.max(3,I)):Math.min(300,Math.ceil(q));console.log("[Music Generation] Requesting music:",{prompt:v,requestedDuration:ee,totalAudioDuration:E,actualVideoDuration:q,timelineDurationMs:V});let Qe,Kt;e&&(e.text="Generating music and thumbnail...");let Oi=`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: ${x.map(R=>R.text).join(" ")}`,Qt=[],Pi=(async()=>{if(ee<3)return n==="human"&&(e?.stop(),_(`Video duration (${q.toFixed(1)}s) is too short for music generation (minimum 3s).`),e?.start()),null;try{let R=await vt({prompt:v,duration:ee});if(R.status!=="completed"&&R.status!=="failed"&&(R=await ue(()=>ot(R.requestId),60,2e3)),R.status==="failed")throw new Error(R.error||"Unknown error");let J=G(g,"music.mp3");return R.audioUrl&&await Yt(R.audioUrl,J),{path:"audio/music.mp3",duration:R.duration||ee,prompt:v,cost:R.cost||0}}catch(R){return n==="human"&&(e?.stop(),_(`Music generation failed: ${R.message}`),e?.start()),null}})();Qt.push(Pi);let Ni=(async()=>{try{let R=await Po({prompt:Oi,options:{width:1280,height:720}});if(R.success&&R.data.url){let J=G(t.output,"thumbnail.jpg");return await Yt(R.data.url,J),y+=R.data.cost||0,J}return null}catch(R){return n==="human"&&(e?.stop(),_(`Thumbnail generation failed: ${R.message}`),e?.start()),null}})();Qt.push(Ni);let[Ae,eo]=await Promise.all(Qt);Ae&&(Qe=Ae,y+=Ae.cost||0,n==="human"&&(e?.stop(),C(`Music: ${G(g,"music.mp3")} (${Ae.duration}s)`),Ae.duration<q&&_(`Music duration (${Ae.duration.toFixed(1)}s) is shorter than video duration (${q.toFixed(1)}s).`),e?.start())),eo&&(Kt=eo,n==="human"&&(e?.stop(),C(`Thumbnail: ${Kt}`),e?.start())),e&&(e.text="Writing manifest...");let to=Math.round(q*Xe),no={music:Qe,thumbnail:Kt?"thumbnail.jpg":void 0,images:A,videos:P,scenes:x,timeline:w,totalDurationInFrames:to,fps:Xe,totalCost:y,createdAt:new Date().toISOString()},Zt=G(t.output,"video-manifest.json");if(await ye(Zt,JSON.stringify(no,null,2)),e?.stop(),n==="json"){let{totalCost:R,...J}=no;S(J);return}if(n==="quiet"){console.log(Zt);return}console.log(),C("Video assets created successfully!"),console.log(),m(`Scenes: ${x.length} (${to} frames at ${Xe}fps)`);for(let R of x){let J=[R.audioPath?"audio":null,R.imagePath?"image":null,R.videoPath?"video":null].filter(Boolean).join(", ");m(` - ${R.name}: ${R.durationInSeconds.toFixed(1)}s [${J}]`)}m(`Music: ${Qe?.path} (${Qe?.duration}s)`),m(`Manifest: ${Zt}`),console.log(),m(`Total cost: $${y.toFixed(4)}`)}catch(r){e?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),ll=new Z("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"?dt("Finding videos...").start():null;try{let s=await ln({query:t,options:{maxResults:parseInt(e,10),orientation:o,license:r}});a?.stop();let l=s.data.results.flatMap(d=>d.results);if(i==="json"){let{totalCost:d,...f}=s.data;S({...s,data:f});return}if(i==="quiet"){l.forEach(d=>{console.log(d.previewUrl||d.thumbnailUrl)});return}if(l.length===0){m("No videos found");return}C(`Found ${l.length} videos for "${t}"`),console.log(),l.forEach((d,f)=>{console.log(`[${f+1}] ${d.title}`),console.log(` URL: ${d.previewUrl||d.thumbnailUrl}`),console.log(` Duration: ${d.duration}s | Size: ${d.width}x${d.height}`),console.log(` Provider: ${d.provider}`),console.log()}),m(`Total cost: $${s.data.totalCost.toFixed(4)}`)}catch(s){a?.stop(),c(s instanceof Error?s.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),dl=new Z("new").description("Create a new video project from a template").argument("<name>","Project directory name").option("-t, --template <repo>","GitHub repo (user/repo#commit)",Kc).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"?dt("Initializing video project...").start():null;try{let r=Je();await Ke(r,{recursive:!0});let i=Ht(t),a=n.type,s=await Xn();if(s.includes(t)){let g=vi(t,s);o?.stop(),c(`Project "${t}" already exists at: ${i}`),m(`Try: ${p.commands[0]} video generate new ${g}`),process.exit(u.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(u.INVALID_INPUT)),["youtube","tiktok","audiogram"].includes(a)||(o?.stop(),c(`Invalid type "${a}". Use youtube, tiktok, or audiogram.`),process.exit(u.INVALID_INPUT)),o&&(o.text=`Cloning template from ${n.template}...`);let[d,f]=n.template.split("#"),v=f?`-b ${f}`:"";try{Ye(`git clone ${v} --depth 1 https://github.com/${d}.git "${i}"`,{stdio:"pipe"}),await Kn(G(i,".git"),{recursive:!0,force:!0})}catch(g){o?.stop(),c(`Failed to clone template: ${g instanceof Error?g.message:"Unknown error"}`),process.exit(u.GENERAL_ERROR)}e==="human"&&(o?.stop(),C(`Template downloaded to ${t}/`),o?.start());let I;try{I=await Zc(i)}catch{o?.stop(),c("template.manifest.json not found or invalid in template repo"),process.exit(u.INVALID_INPUT)}if(I.propsSchema&&I.propsSchema!=="video-plan.v1"&&(o?.stop(),c(`Template propsSchema must be video-plan.v1 (found ${I.propsSchema})`),process.exit(u.INVALID_INPUT)),o&&(o.text="Writing scaffold files..."),await rl(i,a,p.commands[0]),n.install){let g=Ti()?"bun":"npm";o&&(o.text=`Installing dependencies with ${g}...`),await new Promise((T,b)=>{let y=zc(g,["install"],{cwd:i,stdio:"pipe",shell:!0});y.on("close",x=>{x===0?T():b(new Error(`${g} install failed with code ${x}`))}),y.on("error",b)}),e==="human"&&(o?.stop(),C("Dependencies installed"),o?.start())}if(o?.stop(),e==="json"){S({name:t,path:i,template:n.template,type:a,installed:n.install});return}if(e==="quiet"){console.log(i);return}console.log(),C(`Video project "${t}" created successfully!`),m(`Location: ${i}`),a==="tiktok"?m("Format: TikTok/Reels/Shorts (1080x1920 @ 30fps)"):a==="audiogram"?m("Format: Audiogram (1080x1080 @ 30fps)"):m("Format: YouTube (1920x1080 @ 30fps)"),console.log(),m("Next steps:"),m(` cd ${i}`),n.install||m(` ${Ti()?"bun":"npm"} install`),m(" bun run dev # Preview in Remotion Studio"),m(` ${p.commands[0]} video generate assets --scenes public/scenes.json`),m(` ${p.commands[0]} video generate plan`)}catch(r){o?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),ul=new Z("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").option("--render-target <target>","Plan target: hyperframes or remotion","hyperframes").option("--no-wait","Return the background run ID immediately").action(async t=>{let n=dt("Generating video plan...").start();try{let e=t.context;if(!e){let l=await ki();l&&(e=l)}e||(n.stop(),c("Provide context via stdin or --context flag"),process.exit(u.INVALID_INPUT));let o;if(t.branding)try{o=await lt(t.branding,"utf-8")}catch{n.stop(),c(`Could not read branding file: ${t.branding}`),process.exit(u.INVALID_INPUT)}let r=t.renderTarget==="remotion"?"remotion":"hyperframes",i={context:e,branding:o,renderTarget:r};if(t.wait===!1){n.stop(),S(await mn(i));return}let a=await _o(i);n.stop(),a.success||(c(a.error||"Failed to generate plan"),process.exit(u.GENERAL_ERROR));let s=a.data;t.output?(await ye(t.output,s),C(`Plan saved to ${t.output}`)):console.log(s)}catch(e){n.stop(),c(e instanceof Error?e.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),ml=new Z("generate").description("Generate parts of a video project").addCommand(dl).addCommand(cl).addCommand(ul),pl=new Z("create").description("Start background standalone video generation").argument("<title>","Video title").requiredOption("--brief <brief>","Video brief").option("--topic <topic>","Video topic").option("--duration <seconds>","Duration in seconds","30").option("--format <format>","tiktok, instagram_reel, or youtube_short","tiktok").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(t,n)=>{if(!n.yes)return c("Pass --yes to approve video generation");try{S(await Uo({brief:n.brief,durationSec:Number(n.duration),format:n.format,title:t,topic:n.topic}))}catch(e){c(e instanceof Error?e.message:"Generation failed"),process.exit(u.GENERAL_ERROR)}}),Ri=new Z("plan").description("Start background video-plan generation").requiredOption("--context <brief>","Video brief (minimum 100 characters)").option("--branding <path>","Branding JSON file").option("--render-target <target>","hyperframes or remotion","hyperframes").option("--yes","Approve generation").action(async t=>{if(!t.yes)return c("Pass --yes to approve plan generation");try{let n=t.branding?await lt(t.branding,"utf-8"):void 0;S(await mn({branding:n,context:t.context,renderTarget:t.renderTarget==="remotion"?"remotion":"hyperframes"}))}catch(n){c(n instanceof Error?n.message:"Plan generation failed"),process.exit(u.GENERAL_ERROR)}}),gl=new Z("status").description("Read video or video-plan background status").argument("<run-id>","Run ID").option("--plan","Read a video-plan run").option("--team-id <id>","Workspace ID").action(async(t,n)=>{try{S(await U(n.plan?"generateVideoPlan":"createVideo",t,n.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(u.GENERAL_ERROR)}}),fl=new Z("status").description("Read video-plan background status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(t,n)=>{try{S(await U("generateVideoPlan",t,n.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(u.GENERAL_ERROR)}});Ri.addCommand(fl);var hl=new Z("projects").description("List all video projects").option("-f, --format <format>","Output format: human, json","human").action(async t=>{let n=await Xn();if(t.format==="json"){S({projectsDir:Je(),projects:n.map(e=>({name:e,path:Ht(e)}))});return}if(n.length===0){m("No video projects found"),m(`Projects are stored in: ${Je()}`);return}console.log(`
3764
- Video Projects:`),console.log("-".repeat(50));for(let e of n)console.log(` ${e}`),console.log(` ${Ht(e)}`);console.log()}),yl=new Z("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"?dt("Injecting thumbnail...").start():null;try{let o=ct(t.video),r=ct(t.thumbnail),i=t.output?ct(t.output):o.replace(/\.mp4$/,"-with-thumb.mp4");await Yn(o),await Yn(r);let a=Yc;if(a)try{await Yn(a)}catch{a=null}if(!a)try{a=Ye("which ffmpeg",{encoding:"utf8"}).trim()}catch{throw new Error("ffmpeg not found. Install ffmpeg or ffmpeg-static.")}let s=Xc(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[,d,f]=l;e&&(e.text="Creating thumbnail frame...");let v="/tmp/cc-thumb-frame.mp4";Ye(`${a} -y -loop 1 -i "${r}" -vf "scale=${d}:${f}:force_original_aspect_ratio=decrease,pad=${d}:${f}:(ow-iw)/2:(oh-ih)/2,setsar=1" -t 0.033 -r 30 -c:v libx264 -pix_fmt yuv420p "${v}"`,{stdio:"pipe"}),e&&(e.text="Concatenating with video...");let I="/tmp/cc-concat-video.mp4";if(Ye(`${a} -y -i "${v}" -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 "${I}"`,{stdio:"pipe"}),e&&(e.text="Adding file icon thumbnail..."),Ye(`${a} -y -i "${I}" -i "${r}" -map 0 -map 1 -c copy -c:v:1 png -disposition:v:1 attached_pic "${i}"`,{stdio:"pipe"}),await Kn(v,{force:!0}),await Kn(I,{force:!0}),e?.stop(),n==="json"){S({success:!0,output:i});return}if(n==="quiet"){console.log(i);return}C(`Thumbnail injected: ${i}`)}catch(o){e?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(u.GENERAL_ERROR)}}),bl=new Z("thumbnail").description("Thumbnail operations").addCommand(yl),Qn=new Z("video").description("Video generation commands").addCommand(ml).addCommand(ll).addCommand(hl).addCommand(bl).addCommand(Ii);Qn.addCommand(pl).addCommand(Ri).addCommand(gl);import{Command as Zn}from"commander";var xl=new Zn("create").description("Start background visual-abstract generation").argument("<brief>","Dense source brief").option("--title <title>","Artifact title").option("--aspect <ratio>","1:1, 16:9, 9:16, 4:3, or 3:4","1:1").option("--quality <tier>","fast, balanced, or best","best").option("--preset <preset>","Output preset","executive-one-pager").option("--branding-id <id>","Branding ID").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(t,n)=>{if(!n.yes)return c("Pass --yes to approve visual-abstract generation");try{S(await $("createVisualAbstract",{approvalReceipt:"cli:--yes",aspectRatio:n.aspect,brandingId:n.brandingId,brief:t,outputPreset:n.preset,qualityTier:n.quality,teamId:n.teamId,title:n.title}))}catch(e){c(e instanceof Error?e.message:"Generation failed"),process.exit(u.GENERAL_ERROR)}}),vl=new Zn("status").description("Read visual-abstract generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(t,n)=>{try{S(await U("createVisualAbstract",t,n.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(u.GENERAL_ERROR)}}),Ai=new Zn("visual-abstract").description("Visual abstract commands").addCommand(xl).addCommand(vl);var wl=[ei,ti,Yr,bi,ai,ii,ni,Qn,ui,pi,di,mi,Qr,oi,ci,Hr,Ai,ri,Br,zr];function $i(t){for(let n of wl)t.addCommand(n)}var Cl="0.3.11",W=new Sl,be=p.commands[0];W.name(be).description(p.description).version(Cl,"-v, --version","Show version number").option("--debug","Enable debug logging").option("--no-color","Disable colored output").configureOutput({outputError:(t,n)=>{n(ce.red(t))}});W.addCommand(lr);W.addCommand(dr);W.addCommand(zo);W.addCommand(rr);W.addCommand(Xo);W.addCommand(er);W.addCommand(or);W.addCommand(Vr);W.addCommand(tr);W.addCommand(jr);W.addCommand(He);W.addCommand(Et);W.addCommand(qo);$i(W);var Ei=Qo();Ei.commands.length>0&&W.addCommand(Ei);W.on("command:*",t=>{console.error(ce.red(`Error: Unknown command '${t[0]}'`)),console.error(),console.error(`Run '${be} --help' to see available commands.`),process.exit(1)});W.addHelpText("after",`
3765
- ${ce.bold("Examples:")}
3766
- ${ce.gray("# Log in (opens browser)")}
3767
- $ ${be} login
3768
-
3769
- ${ce.gray("# Create a presentation (recommended pattern)")}
3770
- $ ${be} create "Q4 Business Review" \\
3783
+ execSync("${t} video export --project . " + args, { stdio: "inherit" });
3784
+ `;await ve(G(r,"plan.ts"),a,"utf-8"),await ve(G(r,"export.ts"),s,"utf-8")}async function Yi(){return process.stdin.isTTY?null:new Promise(e=>{let n="",t=!1;process.stdin.setEncoding("utf-8"),process.stdin.on("data",o=>{n+=o}),process.stdin.on("end",()=>{t||(t=!0,e(n.trim()||null))}),process.stdin.on("error",()=>{t||(t=!0,e(null))}),setTimeout(()=>{!t&&!n&&(t=!0,e(null))},500)})}function sl(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function cl(e){let n={shortTitle:"Video",elements:[],audio:[],text:[],scenes:[]},t=!0;return e.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:t?1.3:1,to:t?1:1.3,startMs:0,endMs:a}]}),t=!t):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 nn(e,n){if(e.startsWith("data:")){let r=e.match(/^data:[^;]+;base64,(.+)$/);if(!r)throw new Error("Invalid data URL format");let i=Buffer.from(r[1],"base64");await ve(n,i);return}let t=await fetch(e);if(!t.ok)throw new Error(`Failed to download: ${t.status}`);let o=await t.arrayBuffer();await ve(n,Buffer.from(o))}function dl(e){try{let o=new URL(e).pathname.split(".").pop()?.toLowerCase();if(o&&["jpg","jpeg","png","gif","webp"].includes(o))return o}catch{}return"jpg"}var ll=new te("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 e=>{let n=e.format,t=n==="human"?ft("Initializing...").start():null,o=e.project?pt(process.cwd(),e.project):null;try{let r=await Yi(),i=null;if(e.scenes&&!e.scriptFile&&(e.scriptFile=e.scenes),o&&(e.output=G(o,"public"),e.scriptFile?e.scriptFile=pt(o,e.scriptFile):!e.script&&!r&&(e.scriptFile=G(o,"public","scenes.json"))),r)try{let k=JSON.parse(r);k.scenes&&Array.isArray(k.scenes)&&(i=k)}catch{}if(!i&&e.scriptFile)try{let k=await gt(e.scriptFile,"utf-8"),J=JSON.parse(k);J.scenes&&Array.isArray(J.scenes)&&(i=J)}catch{}let a=i?.voice||e.voice,s=i?.voiceId,d=i?.provider,u=i?.model,p=i?.voiceInstructions,w=i?.musicPrompt||e.musicPrompt||"uplifting background music, positive energy",I=i?.musicDuration,f=G(e.output,"audio"),T=G(e.output,"images"),b=G(e.output,"videos");t&&(t.text="Creating directories..."),await et(f,{recursive:!0}),await et(T,{recursive:!0}),await et(b,{recursive:!0});let y=0,v=[],E=0,A=[],N=[];if(i&&i.scenes.length>0){n==="human"&&(t?.stop(),m(`Processing ${i.scenes.length} scenes...`),t?.start());let k=i.scenes.map((re,B)=>{let ye=re.script;return re.voiceStyle&&(ye=`${re.voiceStyle} ${ye}`),{text:ye,id:`scene-${B}`}});t&&(t.text="Generating speech for all scenes...");let J=await jo({texts:k,options:{provider:d,voice:a,voiceId:s,model:u,voiceSettings:i.voiceSettings,instructions:p}});y+=J.totalCost;let oe=0;for(let re=0;re<i.scenes.length;re++){let B=i.scenes[re],ye=sl(B.name),me=J.results[re];t&&(t.text=`[${B.name}] Saving audio...`);let sn=G(f,`${ye}.${me.format}`);await ve(sn,me.audioData);let Oe=me.duration,ra=Math.round(Oe*Qe),nt={id:re+1,name:B.name,text:B.script,wordCount:B.script.split(/\s+/).length,startTime:oe,endTime:oe+Oe,durationInSeconds:Oe,durationInFrames:ra,audioPath:`audio/${ye}.${me.format}`,timestamps:me.timestamps};if(B.imageQuery){t&&(t.text=`[${B.name}] Searching image...`);try{let Z=await Rt({query:B.imageQuery,options:{maxResults:1,size:"large",safeSearch:!0}}),ot=Z.data.results.flatMap(X=>X.results);if(y+=Z.data.totalCost,ot.length>0){let X=ot[0],rt=dl(X.url),Ie=`${ye}.${rt}`,cn=G(T,Ie);await nn(X.url,cn),nt.imagePath=`images/${Ie}`,A.push({path:`images/${Ie}`,url:X.url,width:X.width,height:X.height,query:B.imageQuery})}}catch(Z){n==="human"&&(t?.stop(),_(`[${B.name}] Image search failed: ${Z instanceof Error?Z.message:"Unknown"}`),t?.start())}}if(B.videoQuery){t&&(t.text=`[${B.name}] Searching video...`);try{let Z=await hn({query:B.videoQuery,options:{maxResults:1,license:"free"}}),ot=Z.data.results.flatMap(X=>X.results);if(y+=Z.data.totalCost,ot.length>0){let X=ot[0],rt=X.previewUrl||X.downloadUrl;if(rt){let Ie=`${ye}.mp4`,cn=G(b,Ie);await nn(rt,cn),nt.videoPath=`videos/${Ie}`,N.push({path:`videos/${Ie}`,url:rt,width:X.width,height:X.height,duration:X.duration,query:B.videoQuery})}}}catch(Z){n==="human"&&(t?.stop(),_(`[${B.name}] Video search failed: ${Z instanceof Error?Z.message:"Unknown"}`),t?.start())}}if(v.push(nt),oe+=Oe,E+=Oe,n==="human"){t?.stop();let Z=[`audio: ${Oe.toFixed(1)}s`,nt.imagePath?"image":null,nt.videoPath?"video":null].filter(Boolean).join(", ");S(` ${B.name}: ${Z}`),t?.start()}}}else{let k=e.script;if(e.scriptFile)try{k=await gt(e.scriptFile,"utf-8")}catch(me){t?.stop(),c(`Failed to read script file: ${me instanceof Error?me.message:"Unknown error"}`),process.exit(l.INVALID_INPUT)}(!k||k.trim().length===0)&&(t?.stop(),c("Provide scenes via stdin JSON, --scenes/--script-file with scenes JSON, or --script for legacy mode"),process.exit(l.INVALID_INPUT)),k=k.trim();let J=e.topic||k.split(".")[0].slice(0,50);t&&(t.text="Generating voiceover...");let oe=await It({text:k,options:{voice:a}}),re=G(f,`voiceover.${oe.format}`);await ve(re,oe.audioData),y+=oe.cost,E=oe.duration;let B=nl(k);v=ol(B,oe.duration,Qe,oe.timestamps).map((me,sn)=>({...me,name:`Section${sn+1}`,audioPath:`audio/voiceover.${oe.format}`})),n==="human"&&(t?.stop(),S(`Voiceover: ${re} (${oe.duration.toFixed(1)}s)`),t?.start())}t&&(t.text="Creating timeline...");let C=cl(v),M=Math.max(C.audio.length>0?Math.max(...C.audio.map(k=>k.endMs)):0,C.text.length>0?Math.max(...C.text.map(k=>k.endMs)):0,C.elements.length>0?Math.max(...C.elements.map(k=>k.endMs)):0),q=M/1e3,ne=I?Math.min(300,Math.max(3,I)):Math.min(300,Math.ceil(q));console.log("[Music Generation] Requesting music:",{prompt:w,requestedDuration:ne,totalAudioDuration:E,actualVideoDuration:q,timelineDurationMs:M});let tt,on;t&&(t.text="Generating music and thumbnail...");let ta=`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: ${v.map(k=>k.text).join(" ")}`,rn=[],na=(async()=>{if(ne<3)return n==="human"&&(t?.stop(),_(`Video duration (${q.toFixed(1)}s) is too short for music generation (minimum 3s).`),t?.start()),null;try{let k=await Tt({prompt:w,duration:ne});if(k.status!=="completed"&&k.status!=="failed"&&(k=await K(()=>st(k.requestId),60,2e3)),k.status==="failed")throw new Error(k.error||"Unknown error");let J=G(f,"music.mp3");return k.audioUrl&&await nn(k.audioUrl,J),{path:"audio/music.mp3",duration:k.duration||ne,prompt:w,cost:k.cost||0}}catch(k){return n==="human"&&(t?.stop(),_(`Music generation failed: ${k.message}`),t?.start()),null}})();rn.push(na);let oa=(async()=>{try{let k=await Go({prompt:ta,options:{width:1280,height:720}});if(k.success&&k.data.url){let J=G(e.output,"thumbnail.jpg");return await nn(k.data.url,J),y+=k.data.cost||0,J}return null}catch(k){return n==="human"&&(t?.stop(),_(`Thumbnail generation failed: ${k.message}`),t?.start()),null}})();rn.push(oa);let[Ee,lo]=await Promise.all(rn);Ee&&(tt=Ee,y+=Ee.cost||0,n==="human"&&(t?.stop(),S(`Music: ${G(f,"music.mp3")} (${Ee.duration}s)`),Ee.duration<q&&_(`Music duration (${Ee.duration.toFixed(1)}s) is shorter than video duration (${q.toFixed(1)}s).`),t?.start())),lo&&(on=lo,n==="human"&&(t?.stop(),S(`Thumbnail: ${on}`),t?.start())),t&&(t.text="Writing manifest...");let uo=Math.round(q*Qe),mo={music:tt,thumbnail:on?"thumbnail.jpg":void 0,images:A,videos:N,scenes:v,timeline:C,totalDurationInFrames:uo,fps:Qe,totalCost:y,createdAt:new Date().toISOString()},an=G(e.output,"video-manifest.json");if(await ve(an,JSON.stringify(mo,null,2)),t?.stop(),n==="json"){let{totalCost:k,...J}=mo;x(J);return}if(n==="quiet"){console.log(an);return}console.log(),S("Video assets created successfully!"),console.log(),m(`Scenes: ${v.length} (${uo} frames at ${Qe}fps)`);for(let k of v){let J=[k.audioPath?"audio":null,k.imagePath?"image":null,k.videoPath?"video":null].filter(Boolean).join(", ");m(` - ${k.name}: ${k.durationInSeconds.toFixed(1)}s [${J}]`)}m(`Music: ${tt?.path} (${tt?.duration}s)`),m(`Manifest: ${an}`),console.log(),m(`Total cost: $${y.toFixed(4)}`)}catch(r){t?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),ul=new te("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(e,n)=>{let{maxResults:t,orientation:o,license:r,format:i}=n,a=i==="human"?ft("Finding videos...").start():null;try{let s=await hn({query:e,options:{maxResults:parseInt(t,10),orientation:o,license:r}});a?.stop();let d=s.data.results.flatMap(u=>u.results);if(i==="json"){let{totalCost:u,...p}=s.data;x({...s,data:p});return}if(i==="quiet"){d.forEach(u=>{console.log(u.previewUrl||u.thumbnailUrl)});return}if(d.length===0){m("No videos found");return}S(`Found ${d.length} videos for "${e}"`),console.log(),d.forEach((u,p)=>{console.log(`[${p+1}] ${u.title}`),console.log(` URL: ${u.previewUrl||u.thumbnailUrl}`),console.log(` Duration: ${u.duration}s | Size: ${u.width}x${u.height}`),console.log(` Provider: ${u.provider}`),console.log()}),m(`Total cost: $${s.data.totalCost.toFixed(4)}`)}catch(s){a?.stop(),c(s instanceof Error?s.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),ml=new te("new").description("Create a new video project from a template").argument("<name>","Project directory name").option("-t, --template <repo>","GitHub repo (user/repo#commit)",Zd).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(e,n)=>{let t=n.format,o=t==="human"?ft("Initializing video project...").start():null;try{let r=Xe();await et(r,{recursive:!0});let i=Qt(e),a=n.type,s=await oo();if(s.includes(e)){let f=Ui(e,s);o?.stop(),c(`Project "${e}" already exists at: ${i}`),m(`Try: ${g.commands[0]} video generate new ${f}`),process.exit(l.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(l.INVALID_INPUT)),["youtube","tiktok","audiogram"].includes(a)||(o?.stop(),c(`Invalid type "${a}". Use youtube, tiktok, or audiogram.`),process.exit(l.INVALID_INPUT)),o&&(o.text=`Cloning template from ${n.template}...`);let[u,p]=n.template.split("#"),w=p?`-b ${p}`:"";try{Ze(`git clone ${w} --depth 1 https://github.com/${u}.git "${i}"`,{stdio:"pipe"}),await ao(G(i,".git"),{recursive:!0,force:!0})}catch(f){o?.stop(),c(`Failed to clone template: ${f instanceof Error?f.message:"Unknown error"}`),process.exit(l.GENERAL_ERROR)}t==="human"&&(o?.stop(),S(`Template downloaded to ${e}/`),o?.start());let I;try{I=await tl(i)}catch{o?.stop(),c("template.manifest.json not found or invalid in template repo"),process.exit(l.INVALID_INPUT)}if(I.propsSchema&&I.propsSchema!=="video-plan.v1"&&(o?.stop(),c(`Template propsSchema must be video-plan.v1 (found ${I.propsSchema})`),process.exit(l.INVALID_INPUT)),o&&(o.text="Writing scaffold files..."),await al(i,a,g.commands[0]),n.install){let f=Xi()?"bun":"npm";o&&(o.text=`Installing dependencies with ${f}...`),await new Promise((T,b)=>{let y=Yd(f,["install"],{cwd:i,stdio:"pipe",shell:!0});y.on("close",v=>{v===0?T():b(new Error(`${f} install failed with code ${v}`))}),y.on("error",b)}),t==="human"&&(o?.stop(),S("Dependencies installed"),o?.start())}if(o?.stop(),t==="json"){x({name:e,path:i,template:n.template,type:a,installed:n.install});return}if(t==="quiet"){console.log(i);return}console.log(),S(`Video project "${e}" created successfully!`),m(`Location: ${i}`),a==="tiktok"?m("Format: TikTok/Reels/Shorts (1080x1920 @ 30fps)"):a==="audiogram"?m("Format: Audiogram (1080x1080 @ 30fps)"):m("Format: YouTube (1920x1080 @ 30fps)"),console.log(),m("Next steps:"),m(` cd ${i}`),n.install||m(` ${Xi()?"bun":"npm"} install`),m(" bun run dev # Preview in Remotion Studio"),m(` ${g.commands[0]} video generate assets --scenes public/scenes.json`),m(` ${g.commands[0]} video generate plan`)}catch(r){o?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),pl=new te("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").option("--render-target <target>","Plan target: hyperframes or remotion","hyperframes").option("--no-wait","Return the background run ID immediately").action(async e=>{let n=ft("Generating video plan...").start();try{let t=e.context;if(!t){let d=await Yi();d&&(t=d)}t||(n.stop(),c("Provide context via stdin or --context flag"),process.exit(l.INVALID_INPUT));let o;if(e.branding)try{o=await gt(e.branding,"utf-8")}catch{n.stop(),c(`Could not read branding file: ${e.branding}`),process.exit(l.INVALID_INPUT)}let r=e.renderTarget==="remotion"?"remotion":"hyperframes",i={context:t,branding:o,renderTarget:r};if(e.wait===!1){n.stop(),x(await wn(i));return}let a=await Zo(i);n.stop(),a.success||(c(a.error||"Failed to generate plan"),process.exit(l.GENERAL_ERROR));let s=a.data;e.output?(await ve(e.output,s),S(`Plan saved to ${e.output}`)):console.log(s)}catch(t){n.stop(),c(t instanceof Error?t.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),gl=new te("generate").description("Generate parts of a video project").addCommand(ml).addCommand(ll).addCommand(pl),fl=new te("create").description("Start background standalone video generation").argument("<title>","Video title").requiredOption("--brief <brief>","Video brief").option("--topic <topic>","Video topic").option("--duration <seconds>","Duration in seconds","30").option("--format <format>","tiktok, instagram_reel, or youtube_short","tiktok").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(e,n)=>{if(!n.yes)return c("Pass --yes to approve video generation");try{x(await Qo({brief:n.brief,durationSec:Number(n.duration),format:n.format,title:e,topic:n.topic}))}catch(t){c(t instanceof Error?t.message:"Generation failed"),process.exit(l.GENERAL_ERROR)}}),Ki=new te("plan").description("Start background video-plan generation").requiredOption("--context <brief>","Video brief (minimum 100 characters)").option("--branding <path>","Branding JSON file").option("--render-target <target>","hyperframes or remotion","hyperframes").option("--yes","Approve generation").action(async e=>{if(!e.yes)return c("Pass --yes to approve plan generation");try{let n=e.branding?await gt(e.branding,"utf-8"):void 0;x(await wn({branding:n,context:e.context,renderTarget:e.renderTarget==="remotion"?"remotion":"hyperframes"}))}catch(n){c(n instanceof Error?n.message:"Plan generation failed"),process.exit(l.GENERAL_ERROR)}}),hl=new te("status").description("Read video or video-plan background status").argument("<run-id>","Run ID").option("--plan","Read a video-plan run").option("--team-id <id>","Workspace ID").action(async(e,n)=>{try{x(await L(n.plan?"generateVideoPlan":"createVideo",e,n.teamId))}catch(t){c(t instanceof Error?t.message:"Status failed"),process.exit(l.GENERAL_ERROR)}}),yl=new te("status").description("Read video-plan background status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(e,n)=>{try{x(await L("generateVideoPlan",e,n.teamId))}catch(t){c(t instanceof Error?t.message:"Status failed"),process.exit(l.GENERAL_ERROR)}});Ki.addCommand(yl);var bl=new te("projects").description("List all video projects").option("-f, --format <format>","Output format: human, json","human").action(async e=>{let n=await oo();if(e.format==="json"){x({projectsDir:Xe(),projects:n.map(t=>({name:t,path:Qt(t)}))});return}if(n.length===0){m("No video projects found"),m(`Projects are stored in: ${Xe()}`);return}console.log(`
3785
+ Video Projects:`),console.log("-".repeat(50));for(let t of n)console.log(` ${t}`),console.log(` ${Qt(t)}`);console.log()}),wl=new te("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 e=>{let n=e.format,t=n==="human"?ft("Injecting thumbnail...").start():null;try{let o=pt(e.video),r=pt(e.thumbnail),i=e.output?pt(e.output):o.replace(/\.mp4$/,"-with-thumb.mp4");await io(o),await io(r);let a=Qd;if(a)try{await io(a)}catch{a=null}if(!a)try{a=Ze("which ffmpeg",{encoding:"utf8"}).trim()}catch{throw new Error("ffmpeg not found. Install ffmpeg or ffmpeg-static.")}let s=Kd(a,["-i",o],{encoding:"utf8"});if(s.error)throw new Error(`Failed to probe video: ${s.error.message}`);let d=(s.stderr??"").match(/(\d{2,5})x(\d{2,5})/);if(!d)throw new Error("Could not detect video dimensions");let[,u,p]=d;t&&(t.text="Creating thumbnail frame...");let w="/tmp/cc-thumb-frame.mp4";Ze(`${a} -y -loop 1 -i "${r}" -vf "scale=${u}:${p}:force_original_aspect_ratio=decrease,pad=${u}:${p}:(ow-iw)/2:(oh-ih)/2,setsar=1" -t 0.033 -r 30 -c:v libx264 -pix_fmt yuv420p "${w}"`,{stdio:"pipe"}),t&&(t.text="Concatenating with video...");let I="/tmp/cc-concat-video.mp4";if(Ze(`${a} -y -i "${w}" -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 "${I}"`,{stdio:"pipe"}),t&&(t.text="Adding file icon thumbnail..."),Ze(`${a} -y -i "${I}" -i "${r}" -map 0 -map 1 -c copy -c:v:1 png -disposition:v:1 attached_pic "${i}"`,{stdio:"pipe"}),await ao(w,{force:!0}),await ao(I,{force:!0}),t?.stop(),n==="json"){x({success:!0,output:i});return}if(n==="quiet"){console.log(i);return}S(`Thumbnail injected: ${i}`)}catch(o){t?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(l.GENERAL_ERROR)}}),vl=new te("thumbnail").description("Thumbnail operations").addCommand(wl),so=new te("video").description("Video generation commands").addCommand(gl).addCommand(ul).addCommand(bl).addCommand(vl).addCommand(Hi).addCommand(Ji).addCommand(zi).addCommand(Mi);so.addCommand(fl).addCommand(Ki).addCommand(hl);import{Command as co}from"commander";var xl=new co("create").description("Start background visual-abstract generation").argument("<brief>","Dense source brief").option("--title <title>","Artifact title").option("--aspect <ratio>","1:1, 16:9, 9:16, 4:3, or 3:4","1:1").option("--quality <tier>","fast, balanced, or best","best").option("--preset <preset>","Output preset","executive-one-pager").option("--branding-id <id>","Branding ID").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(e,n)=>{if(!n.yes)return c("Pass --yes to approve visual-abstract generation");try{x(await $("createVisualAbstract",{approvalReceipt:"cli:--yes",aspectRatio:n.aspect,brandingId:n.brandingId,brief:e,outputPreset:n.preset,qualityTier:n.quality,teamId:n.teamId,title:n.title}))}catch(t){c(t instanceof Error?t.message:"Generation failed"),process.exit(l.GENERAL_ERROR)}}),Sl=new co("status").description("Read visual-abstract generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(e,n)=>{try{x(await L("createVisualAbstract",e,n.teamId))}catch(t){c(t instanceof Error?t.message:"Status failed"),process.exit(l.GENERAL_ERROR)}}),Qi=new co("visual-abstract").description("Visual abstract commands").addCommand(xl).addCommand(Sl);var Cl=[fi,hi,ui,Di,Si,xi,bi,so,ki,$i,Ri,Ai,pi,wi,Ii,si,Qi,vi,ri,di];function Zi(e){for(let n of Cl)e.addCommand(n)}var Tl="0.3.13",W=new Il,xe=g.commands[0];W.name(xe).description(g.description).version(Tl,"-v, --version","Show version number").option("--debug","Enable debug logging").option("--no-color","Disable colored output").configureOutput({outputError:(e,n)=>{n(ue.red(e))}});W.addCommand(Ir);W.addCommand(Tr);W.addCommand(dr);W.addCommand(wr);W.addCommand(lr);W.addCommand(fr);W.addCommand(br);W.addCommand(ti);W.addCommand(hr);W.addCommand(ni);W.addCommand(ze);W.addCommand(Lt);W.addCommand(or);Zi(W);var ea=pr();ea.commands.length>0&&W.addCommand(ea);W.on("command:*",e=>{console.error(ue.red(`Error: Unknown command '${e[0]}'`)),console.error(),console.error(`Run '${xe} --help' to see available commands.`),process.exit(1)});W.addHelpText("after",`
3786
+ ${ue.bold("Examples:")}
3787
+ ${ue.gray("# Log in (opens browser)")}
3788
+ $ ${xe} login
3789
+
3790
+ ${ue.gray("# Create a presentation (recommended pattern)")}
3791
+ $ ${xe} create "Q4 Business Review" \\
3771
3792
  -n 12 -m best \\
3772
3793
  --audience "Executive leadership team" \\
3773
3794
  --context "Revenue: $50M (+25% YoY), New customers: 150"
3774
3795
 
3775
- ${ce.gray("# Create from a file")}
3776
- $ ${be} create "Product Launch" \\
3796
+ ${ue.gray("# Create from a file")}
3797
+ $ ${xe} create "Product Launch" \\
3777
3798
  -n 10 -m fast \\
3778
3799
  --audience "Sales team and partners" \\
3779
3800
  --context-file ./launch-brief.md
3780
3801
 
3781
- ${ce.gray("# Create from URLs")}
3782
- $ ${be} create "Market Analysis" \\
3802
+ ${ue.gray("# Create from URLs")}
3803
+ $ ${xe} create "Market Analysis" \\
3783
3804
  -n 15 -m best \\
3784
3805
  --audience "Strategy team" \\
3785
3806
  --sources https://example.com/report.pdf
3786
3807
 
3787
- ${ce.gray("# List and export")}
3788
- $ ${be} list --format table
3789
- $ ${be} export <slug> -o backup.zip
3808
+ ${ue.gray("# List and export")}
3809
+ $ ${xe} list --format table
3810
+ $ ${xe} export <slug> -o backup.zip
3790
3811
 
3791
- ${ce.bold("Authentication:")}
3792
- Run '${be} login' to authenticate (recommended).
3812
+ ${ue.bold("Authentication:")}
3813
+ Run '${xe} login' to authenticate (recommended).
3793
3814
  Or set CC_SLIDES_API_KEY environment variable for API key auth.
3794
3815
 
3795
- ${ce.bold("More Info:")}
3796
- ${ce.blue(p.docsUrl)}
3797
- `);W.parse(qr(process.argv.slice(2)),{from:"user"});
3816
+ ${ue.bold("More Info:")}
3817
+ ${ue.blue(g.docsUrl)}
3818
+ `);W.parse(oi(process.argv.slice(2)),{from:"user"});