@conceptcraft/mindframes 0.3.21 → 0.3.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/index.js +40 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -308,7 +308,8 @@ mindframes video create --storyboard-revision <rev-id> --idempotency-key run-1 -
|
|
|
308
308
|
mindframes video status <run-id>
|
|
309
309
|
```
|
|
310
310
|
|
|
311
|
-
`video create` also accepts `--source-video <id>`, `--
|
|
311
|
+
`video create` also accepts `--source-video <id>`, `--release` (720p; the
|
|
312
|
+
default render is 480p),
|
|
312
313
|
`--team-id` and `--approval-receipt`. Omit `--approval-receipt` on the first
|
|
313
314
|
call to get the browser confirmation URL back.
|
|
314
315
|
|
package/dist/index.js
CHANGED
|
@@ -58,7 +58,7 @@ ${n.text}`}function Tn(e,t){return t?e.messages.filter(r=>r.text.trim()).at(-1)?
|
|
|
58
58
|
`),usage:a}}function pi(e){return e.trim().replace(/\s+/g," ").toLocaleLowerCase()}import{randomUUID as Ec}from"crypto";import{mkdir as Ac}from"fs/promises";import{hostname as jt,platform as Oc}from"os";import{join as Pc}from"path";var Me=class extends Error{constructor(n,r,o=!1){super(n);this.statusCode=r;this.reRegister=o;this.name="RunnerApiError"}statusCode;reRegister};async function Fe(e,t={}){let n=await he();t.body!==void 0&&(n["Content-Type"]="application/json");let r=new AbortController,o=setTimeout(()=>r.abort(),t.timeoutMs??3e4),i=()=>r.abort();t.signal?.addEventListener("abort",i,{once:!0});try{let a=await fetch(`${B()}${e}`,{body:t.body!==void 0?JSON.stringify(t.body):void 0,headers:n,method:t.method??"GET",signal:r.signal}),d=await a.text(),l={};try{l=d?JSON.parse(d):{}}catch{l={error:d.slice(0,300)}}if(!a.ok)throw new Me(typeof l.error=="string"?l.error:`Runner API returned ${a.status}`,a.status,l.reRegister===!0);return l}finally{clearTimeout(o),t.signal?.removeEventListener("abort",i)}}async function hi(e){await Fe("/api/runner/register",{body:e,method:"POST",timeoutMs:15e3})}async function yi(e,t){return(await Fe(`/api/runner/work?runnerId=${encodeURIComponent(e)}`,{signal:t,timeoutMs:28e3})).job??null}async function bi(e){await Fe("/api/runner/heartbeat",{body:{runnerId:e},method:"POST",timeoutMs:1e4})}async function wi(e,t){return{cancelRequested:(await Fe(`/api/runner/jobs/${encodeURIComponent(e)}/events`,{body:{events:t},method:"POST",timeoutMs:15e3})).cancelRequested===!0}}async function Pn(e,t,n){await Fe(`/api/runner/jobs/${encodeURIComponent(e)}/complete`,{body:{result:n,runnerId:t},method:"POST",timeoutMs:15e3})}async function Ut(e,t,n,r=!0){await Fe(`/api/runner/jobs/${encodeURIComponent(e)}/fail`,{body:{message:n,retryable:r,runnerId:t},method:"POST",timeoutMs:15e3})}import{mkdirSync as Rc,readFileSync as Sc,writeFileSync as vi}from"fs";import{dirname as $c,join as Tc}from"path";function _n(e){return Tc(e,"sessions.json")}function Ln(e){try{let t=Sc(_n(e),"utf8"),n=JSON.parse(t);if(n&&typeof n=="object"&&!Array.isArray(n))return n}catch{}return{}}function xi(e,t,n){return t?Ln(e)[t]?.[n]??null:null}function ki(e,t,n,r){if(!(!t||!r))try{let o=_n(e);Rc($c(o),{recursive:!0});let i=Ln(e);i[t]={...i[t],[n]:r},vi(o,`${JSON.stringify(i,null," ")}
|
|
59
59
|
`,"utf8")}catch{}}function Ci(e,t,n){if(t)try{let r=Ln(e);if(!r[t])return;delete r[t][n],vi(_n(e),`${JSON.stringify(r,null," ")}
|
|
60
60
|
`,"utf8")}catch{}}var _c=300,Lc=3e4;async function Ii(e){let[t,n]=await Promise.all([Nt(e.claudeBin),qt(e.codexBin)]);if(!t&&!n)throw new Error("Neither Claude Code nor Codex was found on this machine. Install one and log in, then retry.");t?e.log(`Claude Code detected: ${t.version} (${t.bin})`):e.log("Claude Code not found \u2014 Claude turns will be declined."),n?e.log(`Codex detected: ${n.version} (${n.bin})`):e.log("Codex not found \u2014 Codex turns will be declined.");let r=[...t?["claude-code"]:[],...n?["codex"]:[]],o=`${jt().split(".")[0]}-${Ec().slice(0,8)}`,i=()=>hi({capabilities:["chat_turn","proof"],claudeCodeVersion:t?.version??null,cliVersion:e.version,codexVersion:n?.version??null,hostname:jt(),platform:Oc(),runnerId:o,runtimes:r});for(await i(),e.log(`Registered as ${o} (runtimes: ${r.join(", ")}). Waiting for work\u2026`);!e.signal?.aborted;){let a=null;try{a=await yi(o,e.signal)}catch(d){if(e.signal?.aborted)break;if(d instanceof Me&&d.reRegister){e.log("Server asked for re-registration."),await i().catch(()=>{});continue}e.log(`Work poll failed (${d instanceof Error?d.message:"unknown"}); retrying\u2026`),await qc(e.pollBackoffMs??5e3,e.signal);continue}if(!a){if(e.once)continue;continue}if(e.log(`Claimed ${a.jobType} job ${a.runId}.`),await Dc({claude:t,codex:n,job:a,options:e,runnerId:o}),e.once)break}}async function Dc({claude:e,codex:t,job:n,options:r,runnerId:o}){let i=new AbortController,a=()=>i.abort();r.signal?.addEventListener("abort",a,{once:!0});let d=setInterval(()=>{bi(o).catch(()=>{})},Lc),l=[],y=!1,p=async()=>{if(y||l.length===0)return;y=!0;let C=l.splice(0,100);try{let{cancelRequested:E}=await wi(n.runId,C);E&&i.abort()}catch(E){E instanceof Me&&E.statusCode===409&&i.abort()}finally{y=!1}},w=setInterval(()=>{p()},_c),v=C=>{l.push(C)};try{if(n.jobType==="runner.proof"){let C=typeof n.input.message=="string"?n.input.message:"proof";v({eventType:"proof.echo",payload:{message:C}}),await Dn(p,l),await Pn(n.runId,o,{echo:C}),r.log(`Proof job ${n.runId} completed.`);return}if(n.jobType==="runner.chat_turn"){let C=n.input.runtime==="codex"?"codex":"claude-code",E=C==="codex"?t&&{detection:t,run:fi}:e&&{detection:e,run:li};if(!E){await Ut(n.runId,o,C==="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 k=typeof n.input.chatId=="string"&&n.input.chatId?n.input.chatId:null,$=Pc(r.workspaceRoot,"chats",k??n.runId);await Ac($,{recursive:!0});let S=Nc(n.input),V=I=>v({eventType:I.eventType,message:I.message??null,payload:I.eventType==="chat.session"?{host:jt(),runtime:C,runtimeVersion:E.detection.version,...I.payload??{}}:I.payload??{}}),A=xi(r.workspaceRoot,k,C),q;try{q=await E.run({bin:E.detection.bin,input:S,onEvent:V,resumeSessionId:A,signal:i.signal,workspace:$})}catch(I){if(!A||i.signal.aborted)throw I;r.log(`Resume of ${C} session failed (${I instanceof Error?I.message:"unknown"}); retrying fresh.`),Ci(r.workspaceRoot,k,C),q=await E.run({bin:E.detection.bin,input:S,onEvent:V,resumeSessionId:null,signal:i.signal,workspace:$})}ki(r.workspaceRoot,k,C,q.sessionId),v({eventType:"chat.session",payload:{host:jt(),runtime:C,runtimeVersion:E.detection.version,sessionId:q.sessionId,sessionPath:q.sessionPath}}),await Dn(p,l),await Pn(n.runId,o,{modelId:q.modelId,runtime:C,runtimeVersion:E.detection.version,sessionId:q.sessionId,sessionPath:q.sessionPath,text:q.text,usage:q.usage??{}}),r.log(`Chat turn ${n.runId} (${C}) completed.`);return}await Ut(n.runId,o,`This runner does not support ${n.jobType} jobs. Update the desktop app / CLI.`,!1)}catch(C){let E=C instanceof Error?C.message:"Local runner job crashed.";r.log(`Job ${n.runId} failed: ${E}`),await Dn(p,l).catch(()=>{}),await Ut(n.runId,o,E).catch(()=>{})}finally{clearInterval(w),clearInterval(d),r.signal?.removeEventListener("abort",a)}}function Nc(e){let t=Array.isArray(e.messages)?e.messages.map(n=>{if(!n||typeof n!="object")return null;let r=n;return{role:typeof r.role=="string"?r.role:"user",text:typeof r.text=="string"?r.text:""}}).filter(n=>!!n):[];return{effort:typeof e.effort=="string"?e.effort:null,messages:t,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 Dn(e,t){for(;t.length>0;)await e(),t.length>0&&await new Promise(n=>setTimeout(n,25))}function qc(e,t){return e<=0||t?.aborted?Promise.resolve():new Promise(n=>{let r=setTimeout(o,e);function o(){clearTimeout(r),t?.removeEventListener("abort",o),n()}t?.addEventListener("abort",o,{once:!0})})}function Fc(){return jc(Uc(),`.${m.commands[0]}-runner`,"runs")}var Mt=new Mc("runner").description("Run agent work locally with your own Claude Code / Codex login (desktop lane)");Mt.command("status").description("Check local Claude Code / Codex detection and account auth").action(async()=>{let[e,t]=await Promise.all([Nt(),qt()]);if(console.log(e?de.green(`\u2713 Claude Code ${e.version}`):de.red("\u2717 Claude Code not found on PATH")),console.log(t?de.green(`\u2713 Codex ${t.version} (${t.bin})`):de.red("\u2717 Codex not found (PATH or Codex.app)")),!fe()){console.log(de.red(`\u2717 Not logged in. Run '${m.commands[0]} login' first.`)),process.exitCode=2;return}try{let n=await ye();console.log(de.green(`\u2713 Logged in as ${n.user.email}`))}catch(n){console.log(de.red(`\u2717 Auth check failed: ${n instanceof Error?n.message:"unknown"}`)),process.exitCode=2}});Mt.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=>{fe()||(console.error(de.red(`Not authenticated. Run '${m.commands[0]} login' first.`)),process.exit(2));let t=new AbortController,n=()=>{console.log(de.gray(`
|
|
61
|
-
Stopping runner\u2026`)),t.abort()};process.on("SIGINT",n),process.on("SIGTERM",n);try{await Ii({claudeBin:e.claudeBin,codexBin:e.codexBin,log:r=>console.log(de.gray(`[runner] ${r}`)),once:e.once,signal:t.signal,version:"0.3.21",workspaceRoot:e.workspace??Fc()})}catch(r){console.error(de.red(r instanceof Error?r.message:String(r))),process.exit(1)}});import j from"chalk";import{Command as Vp}from"commander";import{Command as Nn}from"commander";function Vc(e,t){return[...t,e]}var Gc=new Nn("create").description("Start durable ad-set generation").argument("<title>","Ad-set title").requiredOption("--brief <brief>","Campaign brief").option("--hook <text>","Opening hook (repeat)",Vc,[]).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,t)=>{if(!t.yes)return s("Pass --yes to approve generation");try{u(await h("createAdSet",{approvalReceipt:"cli:--yes",brandingId:t.brandingId,brief:t.brief,hooks:t.hook.length?t.hook:[t.brief],style:t.style,teamId:t.teamId,title:e}))}catch(n){s(n instanceof Error?n.message:"Generation failed"),process.exit(c.GENERAL_ERROR)}}),Bc=new Nn("status").description("Read ad-set generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(e,t)=>{try{u(await T("createAdSet",e,t.teamId))}catch(n){s(n instanceof Error?n.message:"Status failed"),process.exit(c.GENERAL_ERROR)}}),Ri=new Nn("ad-set").description("Generate a set of ad creatives (hooks, copy, visuals) from a campaign brief").addCommand(Gc).addCommand(Bc);import{randomUUID as Wc}from"crypto";import{Command as Ve}from"commander";function Si(e){return new Ve(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(t,n)=>{if(!n.yes)return s("Pass --yes to approve this operation");try{u(await h(e==="create"?"createAgent":"recommendAgent",{approvalReceipt:"cli:--yes",description:n.description,instructionsMarkdown:n.instructions,name:t,output:n.output,schedule:n.schedule,scheduleTime:n.time,teamId:n.teamId,timezone:n.timezone}))}catch(r){s(r instanceof Error?r.message:"Agent operation failed"),process.exit(c.GENERAL_ERROR)}})}function Un(e,t){s(e instanceof Error?e.message:t),process.exit(c.GENERAL_ERROR)}function $i(e){return`cli:agent-memory:${e}:${Wc()}`}function Kc(e,t){let n=e.indexOf("="),r=n===-1?e:e.slice(0,n),o=n===-1?"":e.slice(n+1);return[...t,{name:r.trim(),note:o.trim()}]}function qn(e,t){return[...t,e]}var Jc=new Ve("show").description("Show what a scheduled agent remembers").argument("<agent-id>","Agent ID").option("--team-id <id>","Workspace ID").action(async(e,t)=>{try{u(await h("getAgentMemory",{agentId:e,teamId:t.teamId}))}catch(n){Un(n,"Could not read the agent's memory")}}),zc=new Ve("set").description("Add to or remove from what an agent remembers. Owner or workspace admin only.").argument("<agent-id>","Agent ID").option("--learned <text>","Durable fact to add (repeatable)",qn,[]).option("--always <text>","Standing instruction to add (repeatable)",qn,[]).option("--never <text>","Thing it must not do, to add (repeatable)",qn,[]).option("--track <name=note>","Entity to track, as name=note (repeatable)",Kc,[]).option("--notes <text>","Replace the freeform notes").option("--remove <field>","Remove instead of add: learned, recurringInstructions, negativePreferences, entities, or notes").option("--value <text>","Item to remove; not needed when removing notes").option("--expected-version <n>","Refuse the write unless the stored memory is still at this version").option("--team-id <id>","Workspace ID").action(async(e,t)=>{let n=typeof t.remove=="string";try{u(await h("updateAgentMemory",{agentId:e,entities:t.track.length?t.track:void 0,expectedVersion:t.expectedVersion===void 0?void 0:Number.parseInt(t.expectedVersion,10),learned:t.learned.length?t.learned:void 0,negativePreferences:t.never.length?t.never:void 0,notes:t.notes,operation:n?"remove":"add",recurringInstructions:t.always.length?t.always:void 0,removeField:t.remove,removeValue:t.value,teamId:t.teamId},$i(n?"remove":"add")))}catch(r){Un(r,"Could not update the agent's memory")}}),Xc=new Ve("forget").description("Erase every stored version of an agent's memory. This cannot be undone.").argument("<agent-id>","Agent ID").option("--team-id <id>","Workspace ID").option("--yes","Confirm the erase").action(async(e,t)=>{if(!t.yes)return s("Pass --yes to erase this agent's memory");try{u(await h("forgetAgentMemory",{agentId:e,teamId:t.teamId},$i("forget")))}catch(n){Un(n,"Could not erase the agent's memory")}}),Hc=new Ve("memory").description("Read, edit, and erase what a scheduled agent remembers").addCommand(Jc).addCommand(zc).addCommand(Xc),Ti=new Ve("agent").description("Create scheduled agents and read, edit, or erase what they remember").addCommand(Si("create")).addCommand(Si("recommend")).addCommand(Hc);import{randomUUID as Oi}from"crypto";import{existsSync as Zc}from"fs";import{resolve as el}from"path";import ct from"chalk";import{Command as be}from"commander";import tl from"ora";import{mkdir as Yc,writeFile as Ei}from"fs/promises";import{dirname as Qc}from"path";async function Y(e,t){if(await Yc(Qc(t),{recursive:!0}),e.startsWith("data:")){let o=e.match(/^data:[^;]+;base64,(.+)$/);if(!o)throw new Error("Invalid data URL format");let i=Buffer.from(o[1],"base64");if(i.length===0)throw new Error("Downloaded media was empty");await Ei(t,i);return}let n=await fetch(e);if(!n.ok)throw new Error(`Failed to download media: ${n.status}`);let r=Buffer.from(await n.arrayBuffer());if(r.length===0)throw new Error("Downloaded media was empty");await Ei(t,r)}var nl=15e3,rl=40,Ai=3;async function Pi(e,t){if(e?.length){if(e.length>Ai)throw new Error(`A presenter Look accepts at most ${Ai} reference images`);return Promise.all(e.map(async(n,r)=>{if(Zc(n))return{url:(await me(el(n),{idempotencyKey:`${t}:reference:${r+1}`})).url};let o;try{o=new URL(n)}catch(i){throw new Error(`Reference image ${r+1} must be an existing local file or an HTTP(S) URL.`,{cause:i})}if(o.protocol!=="http:"&&o.protocol!=="https:")throw new Error(`Reference image ${r+1} must use an HTTP(S) URL.`);return{url:o.toString()}}))}}function jn(e,t){if(t==="json"){u(e);return}if(t==="quiet"){console.log(e.videoUrl??e.requestId);return}g(`Request ID: ${e.requestId}`),g(`Status: ${e.status}`),e.durationSec!=null&&g(`Duration: ${e.durationSec}s`),e.videoUrl&&x(`Video URL: ${e.videoUrl}`),e.error&&s(`Error: ${e.error}`)}var ol=new be("options").description("List available presenter avatars and voices").option("--language <language>","Filter voices by language").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async e=>{try{let t=await Ro(e.language);if(e.format==="json"){u(t);return}let n=t.personal??[];if(e.format==="quiet"){for(let r of n)console.log(r.id);for(let r of t.avatars)console.log(r.id);for(let r of t.voices)console.log(r.id);return}if(n.length>0){g("Your presenters:");for(let r of n)console.log(` ${r.id} ${r.name}`)}g("Avatars:");for(let r of t.avatars){let o=r.renderTiers?.length?` [${r.renderTiers.join(", ")}]`:"";console.log(` ${r.id} ${r.name}${o}`)}g("Voices:");for(let r of t.voices)console.log(` ${r.id} ${r.name}${r.language?` (${r.language})`:""}`)}catch(t){s(t instanceof Error?t.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),il=new be("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",b("--format",["human","json","quiet"]),"human").action(async e=>{let t=e.transparent?"webm":e.outputFormat;!!e.audioUrl==!!e.script&&(s("Provide exactly one avatar speech input: --audio-url or --script"),process.exit(c.INVALID_INPUT)),["1:1","9:16","16:9"].includes(e.aspect)||(s("Aspect must be one of 1:1, 9:16, or 16:9"),process.exit(c.INVALID_INPUT)),e.outputFormat!==void 0&&!["mp4","webm"].includes(e.outputFormat)&&(s("Output format must be mp4 or webm"),process.exit(c.INVALID_INPUT)),e.backgroundColor!==void 0&&!/^#[0-9a-fA-F]{6}$/.test(e.backgroundColor)&&(s("Background color must be a six-digit hex value"),process.exit(c.INVALID_INPUT)),e.backgroundColor&&e.backgroundImageUrl&&(s("Provide only one presenter background"),process.exit(c.INVALID_INPUT)),e.fit!==void 0&&!["contain","cover"].includes(e.fit)&&(s("Fit must be contain or cover"),process.exit(c.INVALID_INPUT)),e.fit&&!e.backgroundImageUrl&&(s("Fit requires --background-image-url"),process.exit(c.INVALID_INPUT)),e.transparent&&e.outputFormat==="mp4"&&(s("--transparent cannot be combined with --output-format mp4"),process.exit(c.INVALID_INPUT)),t==="webm"&&(e.backgroundColor||e.backgroundImageUrl)&&(s("Transparent WebM output cannot be combined with a background"),process.exit(c.INVALID_INPUT)),["basic","standard","premium"].includes(e.renderTier)||(s("Render tier must be basic, standard, or premium"),process.exit(c.INVALID_INPUT));let n=e.duration?Number.parseInt(e.duration,10):void 0;n!==void 0&&(!Number.isFinite(n)||n<1||n>300)&&(s("Duration must be between 1 and 300 seconds"),process.exit(c.INVALID_INPUT));let r=e.format==="human"?tl("Generating presenter clip...").start():null;try{let o=e.audioUrl?{audioUrl:e.audioUrl}:{script:e.script??"",...e.voiceId?{voiceId:e.voiceId}:{}},i=await So({...o,aspect:e.aspect,...e.avatarId?{avatarId:e.avatarId}:{},...e.backgroundColor?{backgroundHex:e.backgroundColor}:{},...e.backgroundImageUrl?{backgroundImageUrl:e.backgroundImageUrl}:{},...n!==void 0?{durationSec:n}:{},...e.fit?{fit:e.fit}:{},...t?{outputFormat:t}:{},renderTier:e.renderTier,title:e.title});if(!e.wait){r?.stop(),jn(i,e.format);return}let a=await te(()=>In(i.requestId),rl,nl);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");r&&(r.text="Downloading presenter clip..."),await Y(a.videoUrl,e.output),r?.stop(),jn(a,e.format),e.format==="human"&&x(`Saved to: ${e.output}`)}catch(o){r?.stop(),s(o instanceof Error?o.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),al=new be("status").description("Check a presenter clip generation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async(e,t)=>{try{jn(await In(e),t.format)}catch(n){s(n instanceof Error?n.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),sl=new be("generate").description("Generate another look for an existing personal presenter").argument("<base-profile-id>","Base personal presenter id (pp_*)").requiredOption("--name <name>","Look name").requiredOption("--description <description>","Short look description").requiredOption("--prompt <prompt>","Exact appearance generation prompt").requiredOption("--look-id <id>","Stable template/look id").option("--reference-image <path-or-url...>","Up to three local images or URLs for location, outfit, or style guidance").option("--idempotency-key <key>","Stable retry key for this look request").action(async(e,t)=>{try{let n=t.idempotencyKey??Oi(),r=await Pi(t.referenceImage,n),o=await h("generatePresenterLook",{baseProfileId:e,description:t.description,id:t.lookId,prompt:t.prompt,...r?{referenceImages:r}:{},title:t.name},n);u(o)}catch(n){s(n instanceof Error?n.message:"Look generation failed"),process.exit(c.GENERAL_ERROR)}}),dl=new be("status").description("Read presenter look generation status").argument("<run-id>","Durable run ID").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async(e,t)=>{try{let n=await T("generatePresenterLook",e);if(t.format==="json")return u(n);if(t.format==="quiet")return console.log(n.status);g(`Run ID: ${e}`),g(`Status: ${n.status}`),n.error?.message&&s(n.error.message)}catch(n){s(n instanceof Error?n.message:"Status failed"),process.exit(c.GENERAL_ERROR)}}),cl=new be("revise").description("Create a new Look by editing an existing presenter Look").argument("<look-id>","Ready presenter Look id (pp_*)").requiredOption("--instruction <instruction>","What to add, remove, or change").option("--reference-image <path-or-url...>","Up to three local images or URLs for location, outfit, or style guidance").option("--idempotency-key <key>","Stable retry key for this revision").action(async(e,t)=>{try{let n=t.idempotencyKey??Oi(),r=await Pi(t.referenceImage,n),o=await h("revisePresenterLook",{instruction:t.instruction,...r?{referenceImages:r}:{},sourceLookId:e},n);u(o)}catch(n){s(n instanceof Error?n.message:"Look revision failed"),process.exit(c.GENERAL_ERROR)}}),ll=new be("revision-status").description("Read presenter Look revision status").argument("<run-id>","Durable run ID").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async(e,t)=>{try{let n=await T("revisePresenterLook",e);if(t.format==="json")return u(n);if(t.format==="quiet")return console.log(n.status);g(`Run ID: ${e}`),g(`Status: ${n.status}`),n.error?.message&&s(n.error.message)}catch(n){s(n instanceof Error?n.message:"Revision status failed"),process.exit(c.GENERAL_ERROR)}}),ml=new be("look").description("Manage looks under an existing personal presenter").addCommand(sl).addCommand(cl).addCommand(ll).addCommand(dl),Mn=new be("avatar").description("Generate presenter clips and looks; avatar options lists the voices and looks used by presentation video presenter and cast preset").addCommand(ol).addCommand(il).addCommand(ml).addCommand(al);Mn.addHelpText("after",`
|
|
61
|
+
Stopping runner\u2026`)),t.abort()};process.on("SIGINT",n),process.on("SIGTERM",n);try{await Ii({claudeBin:e.claudeBin,codexBin:e.codexBin,log:r=>console.log(de.gray(`[runner] ${r}`)),once:e.once,signal:t.signal,version:"0.3.22",workspaceRoot:e.workspace??Fc()})}catch(r){console.error(de.red(r instanceof Error?r.message:String(r))),process.exit(1)}});import j from"chalk";import{Command as Vp}from"commander";import{Command as Nn}from"commander";function Vc(e,t){return[...t,e]}var Gc=new Nn("create").description("Start durable ad-set generation").argument("<title>","Ad-set title").requiredOption("--brief <brief>","Campaign brief").option("--hook <text>","Opening hook (repeat)",Vc,[]).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,t)=>{if(!t.yes)return s("Pass --yes to approve generation");try{u(await h("createAdSet",{approvalReceipt:"cli:--yes",brandingId:t.brandingId,brief:t.brief,hooks:t.hook.length?t.hook:[t.brief],style:t.style,teamId:t.teamId,title:e}))}catch(n){s(n instanceof Error?n.message:"Generation failed"),process.exit(c.GENERAL_ERROR)}}),Bc=new Nn("status").description("Read ad-set generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(e,t)=>{try{u(await T("createAdSet",e,t.teamId))}catch(n){s(n instanceof Error?n.message:"Status failed"),process.exit(c.GENERAL_ERROR)}}),Ri=new Nn("ad-set").description("Generate a set of ad creatives (hooks, copy, visuals) from a campaign brief").addCommand(Gc).addCommand(Bc);import{randomUUID as Wc}from"crypto";import{Command as Ve}from"commander";function Si(e){return new Ve(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(t,n)=>{if(!n.yes)return s("Pass --yes to approve this operation");try{u(await h(e==="create"?"createAgent":"recommendAgent",{approvalReceipt:"cli:--yes",description:n.description,instructionsMarkdown:n.instructions,name:t,output:n.output,schedule:n.schedule,scheduleTime:n.time,teamId:n.teamId,timezone:n.timezone}))}catch(r){s(r instanceof Error?r.message:"Agent operation failed"),process.exit(c.GENERAL_ERROR)}})}function Un(e,t){s(e instanceof Error?e.message:t),process.exit(c.GENERAL_ERROR)}function $i(e){return`cli:agent-memory:${e}:${Wc()}`}function Kc(e,t){let n=e.indexOf("="),r=n===-1?e:e.slice(0,n),o=n===-1?"":e.slice(n+1);return[...t,{name:r.trim(),note:o.trim()}]}function qn(e,t){return[...t,e]}var Jc=new Ve("show").description("Show what a scheduled agent remembers").argument("<agent-id>","Agent ID").option("--team-id <id>","Workspace ID").action(async(e,t)=>{try{u(await h("getAgentMemory",{agentId:e,teamId:t.teamId}))}catch(n){Un(n,"Could not read the agent's memory")}}),zc=new Ve("set").description("Add to or remove from what an agent remembers. Owner or workspace admin only.").argument("<agent-id>","Agent ID").option("--learned <text>","Durable fact to add (repeatable)",qn,[]).option("--always <text>","Standing instruction to add (repeatable)",qn,[]).option("--never <text>","Thing it must not do, to add (repeatable)",qn,[]).option("--track <name=note>","Entity to track, as name=note (repeatable)",Kc,[]).option("--notes <text>","Replace the freeform notes").option("--remove <field>","Remove instead of add: learned, recurringInstructions, negativePreferences, entities, or notes").option("--value <text>","Item to remove; not needed when removing notes").option("--expected-version <n>","Refuse the write unless the stored memory is still at this version").option("--team-id <id>","Workspace ID").action(async(e,t)=>{let n=typeof t.remove=="string";try{u(await h("updateAgentMemory",{agentId:e,entities:t.track.length?t.track:void 0,expectedVersion:t.expectedVersion===void 0?void 0:Number.parseInt(t.expectedVersion,10),learned:t.learned.length?t.learned:void 0,negativePreferences:t.never.length?t.never:void 0,notes:t.notes,operation:n?"remove":"add",recurringInstructions:t.always.length?t.always:void 0,removeField:t.remove,removeValue:t.value,teamId:t.teamId},$i(n?"remove":"add")))}catch(r){Un(r,"Could not update the agent's memory")}}),Xc=new Ve("forget").description("Erase every stored version of an agent's memory. This cannot be undone.").argument("<agent-id>","Agent ID").option("--team-id <id>","Workspace ID").option("--yes","Confirm the erase").action(async(e,t)=>{if(!t.yes)return s("Pass --yes to erase this agent's memory");try{u(await h("forgetAgentMemory",{agentId:e,teamId:t.teamId},$i("forget")))}catch(n){Un(n,"Could not erase the agent's memory")}}),Hc=new Ve("memory").description("Read, edit, and erase what a scheduled agent remembers").addCommand(Jc).addCommand(zc).addCommand(Xc),Ti=new Ve("agent").description("Create scheduled agents and read, edit, or erase what they remember").addCommand(Si("create")).addCommand(Si("recommend")).addCommand(Hc);import{randomUUID as Oi}from"crypto";import{existsSync as Zc}from"fs";import{resolve as el}from"path";import ct from"chalk";import{Command as be}from"commander";import tl from"ora";import{mkdir as Yc,writeFile as Ei}from"fs/promises";import{dirname as Qc}from"path";async function Y(e,t){if(await Yc(Qc(t),{recursive:!0}),e.startsWith("data:")){let o=e.match(/^data:[^;]+;base64,(.+)$/);if(!o)throw new Error("Invalid data URL format");let i=Buffer.from(o[1],"base64");if(i.length===0)throw new Error("Downloaded media was empty");await Ei(t,i);return}let n=await fetch(e);if(!n.ok)throw new Error(`Failed to download media: ${n.status}`);let r=Buffer.from(await n.arrayBuffer());if(r.length===0)throw new Error("Downloaded media was empty");await Ei(t,r)}var nl=15e3,rl=40,Ai=3;async function Pi(e,t){if(e?.length){if(e.length>Ai)throw new Error(`A presenter Look accepts at most ${Ai} reference images`);return Promise.all(e.map(async(n,r)=>{if(Zc(n))return{url:(await me(el(n),{idempotencyKey:`${t}:reference:${r+1}`})).url};let o;try{o=new URL(n)}catch(i){throw new Error(`Reference image ${r+1} must be an existing local file or an HTTP(S) URL.`,{cause:i})}if(o.protocol!=="http:"&&o.protocol!=="https:")throw new Error(`Reference image ${r+1} must use an HTTP(S) URL.`);return{url:o.toString()}}))}}function jn(e,t){if(t==="json"){u(e);return}if(t==="quiet"){console.log(e.videoUrl??e.requestId);return}g(`Request ID: ${e.requestId}`),g(`Status: ${e.status}`),e.durationSec!=null&&g(`Duration: ${e.durationSec}s`),e.videoUrl&&x(`Video URL: ${e.videoUrl}`),e.error&&s(`Error: ${e.error}`)}var ol=new be("options").description("List available presenter avatars and voices").option("--language <language>","Filter voices by language").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async e=>{try{let t=await Ro(e.language);if(e.format==="json"){u(t);return}let n=t.personal??[];if(e.format==="quiet"){for(let r of n)console.log(r.id);for(let r of t.avatars)console.log(r.id);for(let r of t.voices)console.log(r.id);return}if(n.length>0){g("Your presenters:");for(let r of n)console.log(` ${r.id} ${r.name}`)}g("Avatars:");for(let r of t.avatars){let o=r.renderTiers?.length?` [${r.renderTiers.join(", ")}]`:"";console.log(` ${r.id} ${r.name}${o}`)}g("Voices:");for(let r of t.voices)console.log(` ${r.id} ${r.name}${r.language?` (${r.language})`:""}`)}catch(t){s(t instanceof Error?t.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),il=new be("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",b("--format",["human","json","quiet"]),"human").action(async e=>{let t=e.transparent?"webm":e.outputFormat;!!e.audioUrl==!!e.script&&(s("Provide exactly one avatar speech input: --audio-url or --script"),process.exit(c.INVALID_INPUT)),["1:1","9:16","16:9"].includes(e.aspect)||(s("Aspect must be one of 1:1, 9:16, or 16:9"),process.exit(c.INVALID_INPUT)),e.outputFormat!==void 0&&!["mp4","webm"].includes(e.outputFormat)&&(s("Output format must be mp4 or webm"),process.exit(c.INVALID_INPUT)),e.backgroundColor!==void 0&&!/^#[0-9a-fA-F]{6}$/.test(e.backgroundColor)&&(s("Background color must be a six-digit hex value"),process.exit(c.INVALID_INPUT)),e.backgroundColor&&e.backgroundImageUrl&&(s("Provide only one presenter background"),process.exit(c.INVALID_INPUT)),e.fit!==void 0&&!["contain","cover"].includes(e.fit)&&(s("Fit must be contain or cover"),process.exit(c.INVALID_INPUT)),e.fit&&!e.backgroundImageUrl&&(s("Fit requires --background-image-url"),process.exit(c.INVALID_INPUT)),e.transparent&&e.outputFormat==="mp4"&&(s("--transparent cannot be combined with --output-format mp4"),process.exit(c.INVALID_INPUT)),t==="webm"&&(e.backgroundColor||e.backgroundImageUrl)&&(s("Transparent WebM output cannot be combined with a background"),process.exit(c.INVALID_INPUT)),["basic","standard","premium"].includes(e.renderTier)||(s("Render tier must be basic, standard, or premium"),process.exit(c.INVALID_INPUT));let n=e.duration?Number.parseInt(e.duration,10):void 0;n!==void 0&&(!Number.isFinite(n)||n<1||n>300)&&(s("Duration must be between 1 and 300 seconds"),process.exit(c.INVALID_INPUT));let r=e.format==="human"?tl("Generating presenter clip...").start():null;try{let o=e.audioUrl?{audioUrl:e.audioUrl}:{script:e.script??"",...e.voiceId?{voiceId:e.voiceId}:{}},i=await So({...o,aspect:e.aspect,...e.avatarId?{avatarId:e.avatarId}:{},...e.backgroundColor?{backgroundHex:e.backgroundColor}:{},...e.backgroundImageUrl?{backgroundImageUrl:e.backgroundImageUrl}:{},...n!==void 0?{durationSec:n}:{},...e.fit?{fit:e.fit}:{},...t?{outputFormat:t}:{},renderTier:e.renderTier,title:e.title});if(!e.wait){r?.stop(),jn(i,e.format);return}let a=await te(()=>In(i.requestId),rl,nl);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");r&&(r.text="Downloading presenter clip..."),await Y(a.videoUrl,e.output),r?.stop(),jn(a,e.format),e.format==="human"&&x(`Saved to: ${e.output}`)}catch(o){r?.stop(),s(o instanceof Error?o.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),al=new be("status").description("Check a presenter clip generation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async(e,t)=>{try{jn(await In(e),t.format)}catch(n){s(n instanceof Error?n.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),sl=new be("generate").description("Generate another look for an existing personal presenter").argument("<base-profile-id>","Base personal presenter id (pp_*)").requiredOption("--name <name>","Look name").requiredOption("--description <description>","Short look description").requiredOption("--prompt <prompt>","Exact appearance generation prompt").requiredOption("--look-id <id>","Stable template/look id").option("--reference-image <path-or-url...>","Up to three local images or URLs for location, outfit, or style guidance").option("--idempotency-key <key>","Stable retry key for this look request").action(async(e,t)=>{try{let n=t.idempotencyKey??Oi(),r=await Pi(t.referenceImage,n),o=await h("generatePresenterLook",{baseProfileId:e,description:t.description,id:t.lookId,prompt:t.prompt,...r?{referenceImages:r}:{},title:t.name},n);u(o)}catch(n){s(n instanceof Error?n.message:"Look generation failed"),process.exit(c.GENERAL_ERROR)}}),dl=new be("status").description("Read presenter look generation status").argument("<run-id>","Durable run ID").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async(e,t)=>{try{let n=await T("generatePresenterLook",e);if(t.format==="json")return u(n);if(t.format==="quiet")return console.log(n.status);g(`Run ID: ${e}`),g(`Status: ${n.status}`),n.error?.message&&s(n.error.message)}catch(n){s(n instanceof Error?n.message:"Status failed"),process.exit(c.GENERAL_ERROR)}}),cl=new be("revise").description("Create a new Look by editing an existing presenter Look").argument("<look-id>","Ready presenter Look id (pp_*)").requiredOption("--instruction <instruction>","What to add, remove, or change").option("--reference-image <path-or-url...>","Up to three local images or URLs for location, outfit, or style guidance").option("--idempotency-key <key>","Stable retry key for this revision").action(async(e,t)=>{try{let n=t.idempotencyKey??Oi(),r=await Pi(t.referenceImage,n),o=await h("revisePresenterLook",{instruction:t.instruction,...r?{referenceImages:r}:{},sourceLookId:e},n);u(o)}catch(n){s(n instanceof Error?n.message:"Look revision failed"),process.exit(c.GENERAL_ERROR)}}),ll=new be("revision-status").description("Read presenter Look revision status").argument("<run-id>","Durable run ID").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async(e,t)=>{try{let n=await T("revisePresenterLook",e);if(t.format==="json")return u(n);if(t.format==="quiet")return console.log(n.status);g(`Run ID: ${e}`),g(`Status: ${n.status}`),n.error?.message&&s(n.error.message)}catch(n){s(n instanceof Error?n.message:"Revision status failed"),process.exit(c.GENERAL_ERROR)}}),ml=new be("look").description("Manage looks under an existing personal presenter").addCommand(sl).addCommand(cl).addCommand(ll).addCommand(dl),Mn=new be("avatar").description("Generate presenter clips and looks; avatar options lists the voices and looks used by presentation video presenter and cast preset").addCommand(ol).addCommand(il).addCommand(ml).addCommand(al);Mn.addHelpText("after",`
|
|
62
62
|
${ct.bold("Examples:")}
|
|
63
63
|
${ct.gray("# Discover the presenter avatars and voices you can use")}
|
|
64
64
|
$ ${m.commands[0]} avatar options
|
|
@@ -176,7 +176,7 @@ ${cr.bold("See also:")}
|
|
|
176
176
|
$ ${m.commands[0]} video find --help
|
|
177
177
|
`);import{Command as ur}from"commander";import Ou from"ora";function mr(e,t){if(t==="json"){let{cost:n,...r}=e;u(r);return}if(t==="quiet"){console.log(e.audioUrl??e.requestId??e.id);return}g(`Request ID: ${e.requestId||e.id}`),g(`Status: ${e.status}`),e.duration&&g(`Duration: ${e.duration}s`),e.audioUrl&&x(`Audio URL: ${e.audioUrl}`),e.cost!==void 0&&g(`Cost: $${e.cost.toFixed(4)}`),e.error&&s(`Error: ${e.error}`)}var Pu=new ur("generate").description("Generate one SFX cue from a video's final facts and visual event").requiredOption("--request <path>","JSON file with video description, narration timings, and visual_event").option("-o, --output <path>","Output file path").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async e=>{!e.wait&&e.output&&(s("--output requires waiting for completion; remove --no-wait"),process.exit(c.INVALID_INPUT));let t;try{t=ga(e.request)}catch(i){s(i instanceof Error?i.message:String(i)),process.exit(c.INVALID_INPUT)}let n=e.format,r=n==="human"?Ou("Generating sound effect for video...").start():null,o;try{let i=await Io(t);if(o=i.requestId||i.id,!e.wait){r?.stop(),mr(i,n);return}let a=i.requestId||i.id;r&&(r.text=`Processing (ID: ${a})...`);let d=i.status==="completed"||i.status==="failed"?i:await te(()=>Cn(a),60,2e3);if(r?.stop(),d.status==="failed"&&(s(d.error||"Sound effects generation failed"),process.exit(c.GENERAL_ERROR)),e.output){if(!d.audioUrl)throw new Error("Sound effect completed without an audio URL");await Y(d.audioUrl,e.output),n==="human"&&x(`Saved to: ${e.output}`)}mr(d,n)}catch(i){r?.stop(),s(ae(i,o),n),process.exit(c.GENERAL_ERROR)}}),_u=new ur("status").description("Check status of a sound effects generation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async(e,t)=>{try{mr(await Cn(e),t.format)}catch(n){s(n instanceof Error?n.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),Aa=new ur("sfx").description("Video-aware sound effects generation commands").addCommand(Pu).addCommand(_u);import{writeFile as Lu}from"fs/promises";import{Command as Du}from"commander";import Nu from"ora";var Oa=new Du("transcript").description("Fetch a YouTube video's transcript").argument("<url>","YouTube URL or 11-character video id").option("--team-id <id>","Workspace ID").option("--language <codes>","Comma-separated language priority list, e.g. 'en,de' or 'asr-en'").option("--no-timestamps","Print plain text without [m:ss] prefixes").option("-o, --output <path>","Save the transcript to a file").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async(e,t)=>{let n=t.format,r=n==="human"?Nu("Fetching transcript...").start():null;try{let o=await ko(e,t.teamId,t.language);r?.stop();let i=t.timestamps?o.cues.map(a=>`[${a.timestamp}] ${a.text}`).join(`
|
|
178
178
|
`):o.cues.map(a=>a.text).join(`
|
|
179
|
-
`);if(t.output&&(await Lu(t.output,i,"utf-8"),n==="human"&&x(`Transcript saved to: ${t.output}`)),n==="json"){u(o);return}if(n==="quiet"){console.log(i);return}console.log(),console.log(`Title: ${o.title}`),o.channelName&&console.log(`Channel: ${o.channelName}`),o.durationFormatted&&console.log(`Duration: ${o.durationFormatted}`),console.log(`Language: ${o.language??"unknown"}${o.isAutoGenerated?" (auto-generated)":""}`),console.log(`Words: ${o.wordCount.toLocaleString()}`),console.log(`URL: ${o.url}`),o.truncated&&M("Transcript was truncated to fit the response budget."),t.output||(console.log(),console.log("--- Transcript ---"),console.log(i)),o.totalCost&&o.totalCost>0&&g(`Cost: $${o.totalCost.toFixed(6)}`)}catch(o){r?.stop(),s(o instanceof Error?o.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}});import{mkdir as qu,writeFile as Pa}from"fs/promises";import{dirname as Uu}from"path";import{Command as Qt}from"commander";import Da from"ora";var _a="en-US-Neural2-C",La="gemini",ju=new Qt("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: ${_a})`).option("-p, --provider <provider>",`Provider: gemini, elevenlabs, openai (default: ${La})`).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",b("--format",["human","json","quiet"]),"human").action(async e=>{let t=e.format,n=t==="human"?Da("Generating speech...").start():null,r;e.speed&&(r=parseFloat(e.speed),(Number.isNaN(r)||r<.1||r>4)&&(n?.stop(),s("Speed must be between 0.1 and 4.0"),process.exit(c.INVALID_INPUT)));let o;if(e.speakers)try{o=JSON.parse(e.speakers),(!Array.isArray(o)||o.length===0||o.length>2||o.some(a=>!a||typeof a!="object"||typeof a.name!="string"||!a.name.trim()||typeof a.voice!="string"||!a.voice.trim()))&&(n?.stop(),s("Speakers must be an array with 1-2 name/voice items"),process.exit(c.INVALID_INPUT))}catch{n?.stop(),s(`Invalid --speakers JSON. Example: '[{"name":"Joe","voice":"Kore"}]'`),process.exit(c.INVALID_INPUT)}let i;try{let a=e.voiceId,d=e.voice||_a,l=e.provider||La,y={};o&&(y.gemini={speakers:o}),e.instructions&&(y.openai={instructions:e.instructions});let p=await fo({text:e.text,options:{language:e.lang,provider:l,voiceId:a,voice:d,model:e.model,speed:r,providerOptions:Object.keys(y).length>0?y:void 0}});i=p.requestId,n?.stop();let w=e.output.endsWith(`.${p.format}`)?e.output:`${e.output}.${p.format}`;await qu(Uu(w),{recursive:!0}),await Pa(w,p.audioData);let v=w.replace(/\.[^.]+$/,".txt");if(await Pa(v,e.text,"utf-8"),t==="json"){u({status:"completed",output:w,audioUrl:p.audioUrl,duration:p.duration,provider:p.provider,format:p.format,voice_id:p.voiceId??null,voice:p.voice??d,model:p.model??e.model??null,speed:p.speed??r??1,lang:p.language??e.lang??null,langApplied:p.langApplied??!1,timestamps:p.timestamps??null,words:p.wordTimings??null});return}if(t==="quiet"){console.log(w);return}x(`Saved to: ${w}`),g(`Duration: ${p.duration.toFixed(2)}s`),g(`Provider: ${p.provider}`),g(`Cost: $${p.cost.toFixed(6)}`)}catch(a){n?.stop(),s(ae(a,i),t),process.exit(c.GENERAL_ERROR)}}),Mu=new Qt("voices").description("List available voices").option("-p, --provider <provider>","Filter by provider: gemini, elevenlabs, openai").option("-f, --format <format>","Output format: human, json",b("--format",["human","json"]),"human").action(async e=>{let t=e.format==="human"?Da("Fetching voices...").start():null;try{let n=await yo(e.provider);if(t?.stop(),e.format==="json"){u(n.voices);return}if(Array.isArray(n.voices)){let r=e.provider?.toUpperCase()||"VOICES";console.log(),console.log(`${r} Voices:`),console.log("-".repeat(50));for(let o of n.voices)console.log(` ${o.name} (${o.id})`),console.log(` ${o.description}`)}else for(let[r,o]of Object.entries(n.voices))if(!(!o||o.length===0)){console.log(),console.log(`${r.toUpperCase()} Voices:`),console.log("-".repeat(50));for(let i of o)console.log(` ${i.name} (${i.id})`),console.log(` ${i.description}`)}}catch(n){t?.stop(),s(n instanceof Error?n.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),Fu=new Qt("status").description("Read speech generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").option("-f, --format <format>","Output format: json",b("--format",["json"]),"json").action(async(e,t)=>{try{u(await T("generateSpeech",e,t.teamId))}catch(n){s(n instanceof Error?n.message:"Status failed"),process.exit(c.GENERAL_ERROR)}}),Na=new Qt("tts").description("Text-to-speech commands").addCommand(ju).addCommand(Mu).addCommand(Fu);import{execSync as Zt,spawnSync as rp}from"child_process";import{access as gr,readFile as op,rm as Wa}from"fs/promises";import{resolve as wt}from"path";import Q from"chalk";import{Command as ee}from"commander";import ip from"ffmpeg-static";import Ka from"ora";import{mkdir as Vu}from"fs/promises";import{join as Gu}from"path";import{Command as bt}from"commander";import Ua from"ora";var Bu=5e3,Wu=120,qa=5;function Ku(e,t){return[...t,e]}function Ju(e,t){try{let n=new URL(e);if(n.protocol!=="https:"&&n.protocol!=="http:")throw new Error;return n.toString()}catch{throw new Error(`${t} must be a public HTTP(S) URL`)}}function ja(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 zu(e){if(e.mode&&!["speed","precision"].includes(e.mode))throw new Error("Lip-sync mode must be speed or precision");return{audioUrl:Ju(e.audioUrl,"Audio URL"),...e.mode?{mode:e.mode}:{},sourceVideoId:ja(e.sourceVideoId)}}function Xu(e){let t=[],n=new Set;for(let o of e.targetLanguage){let i=o.trim(),a=i.toLocaleLowerCase("en-US");!i||n.has(a)||(n.add(a),t.push(i))}if(t.length===0)throw new Error("Provide at least one target language");if(t.length>qa)throw new Error(`Provide at most ${qa} target languages`);if(t.find(o=>o.length<2||o.length>40))throw new Error("Target languages must be between 2 and 40 characters");return{...e.captions?{captions:!0}:{},sourceVideoId:ja(e.sourceVideoId),targetLanguages:t}}function Hu(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 pr(e){return{requestId:e.runId,status:Hu(e),...e.entity?.url?{videoUrl:e.entity.url}:{},...e.output?{output:e.output}:{},...e.error?{error:se(e.error)}:{}}}function Ma(e){return{requestId:e.runId,status:"pending"}}async function Fa(e,t){return te(async()=>pr(await T(e,t)),Wu,Bu)}function We(e,t){if(t==="json"){u(e);return}if(t==="quiet"){console.log(e.videoUrl??e.requestId);return}g(`Request ID: ${e.requestId}`),g(`Status: ${e.status}`),e.videoUrl&&x(`Video URL: ${e.videoUrl}`),e.error&&s(`Error: ${e.error}`)}function Yu(e){return Array.isArray(e?.languages)?e.languages.filter(t=>{if(!t||typeof t!="object"||Array.isArray(t))return!1;let n=t;return typeof n.language=="string"&&(n.status==="completed"||n.status==="failed")&&typeof n.videoId=="string"&&(n.videoUrl===null||typeof n.videoUrl=="string")}):[]}function Qu(e){return`${e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")||"translation"}.mp4`}function Zu(e,t){let n=Qu(e);if(!t.has(n))return t.add(n),n;let r=n.slice(0,-4),o=2;for(;t.has(`${r}-${o}.mp4`);)o+=1;let i=`${r}-${o}.mp4`;return t.add(i),i}async function ep(e,t){let n=Yu(e.output).filter(i=>i.status==="completed"&&!!i.videoUrl);if(n.length===0)throw new Error("Video translation completed without downloadable results");await Vu(t,{recursive:!0});let r=[],o=new Set;for(let i of n){let a=Gu(t,Zu(i.language,o));await Y(i.videoUrl,a),r.push({language:i.language,path:a})}return r}var tp=new bt("status").description("Check a video lip-sync request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"])).action(async function(e,t){let r=F(this,t).format??"human";try{We(pr(await T("lipsyncVideo",e)),r)}catch(o){s(o instanceof Error?o.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),Va=new bt("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",b("--format",["human","json","quiet"]),"human").action(async e=>{let t=e.format==="human"?Ua("Starting video lip-sync...").start():null,n;try{let r=await $o(zu(e));if(n=r.runId,!e.wait){t?.stop(),We(Ma(r),e.format);return}t&&(t.text="Waiting for video lip-sync...");let o=await Fa("lipsyncVideo",r.runId);if(o.status==="failed")throw new Error(o.error??"Video lip-sync failed");if(!o.videoUrl)throw new Error("Video lip-sync completed without a video URL");t&&(t.text="Downloading lip-synced video..."),await Y(o.videoUrl,e.output),t?.stop(),We(o,e.format),e.format==="human"&&x(`Saved to: ${e.output}`)}catch(r){t?.stop(),s(ae(r,n),e.format),process.exit(c.GENERAL_ERROR)}}).addCommand(tp),Ga=new bt("translate-languages").description("List supported video translation target languages").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async e=>{try{let t=await To();if(e.format==="json")u({languages:t});else for(let n of t)console.log(n)}catch(t){s(t instanceof Error?t.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),np=new bt("status").description("Check a video translation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"])).action(async function(e,t){let r=F(this,t).format??"human";try{We(pr(await T("translateVideo",e)),r)}catch(o){s(o instanceof Error?o.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),Ba=new bt("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)",Ku,[]).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",b("--format",["human","json","quiet"]),"human").action(async e=>{let t=e.format==="human"?Ua("Starting video translation...").start():null,n;try{let r=await Eo(Xu(e));if(n=r.runId,!e.wait){t?.stop(),We(Ma(r),e.format);return}t&&(t.text="Waiting for video translations...");let o=await Fa("translateVideo",r.runId);if(o.status==="failed")throw new Error(o.error??"Video translation failed");t&&(t.text="Downloading translated videos...");let i=await ep(o,e.outputDir);if(t?.stop(),e.format==="json")u({...o,downloads:i});else if(e.format==="quiet")for(let a of i)console.log(a.path);else{We(o,e.format);for(let a of i)x(`${a.language}: ${a.path}`)}}catch(r){t?.stop(),s(ae(r,n),e.format),process.exit(c.GENERAL_ERROR)}}).addCommand(np);async function ap(){return process.stdin.isTTY?null:new Promise(e=>{let t="",n=!1;process.stdin.setEncoding("utf-8"),process.stdin.on("data",r=>{t+=r}),process.stdin.on("end",()=>{n||(n=!0,e(t.trim()||null))}),process.stdin.on("error",()=>{n||(n=!0,e(null))}),setTimeout(()=>{!n&&!t&&(n=!0,e(null))},500)})}function sp(e){let t=e?.trim().toLowerCase();if(!(!t||t==="any"||t==="all"))return t==="web"||t==="stock"?[t]:void 0}var dp=new ee("find").description("Find video clips across the web and licensed stock").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("--source <source>","Catalog: web, stock, or any (default: any)","any").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async(e,t)=>{let{maxResults:n,orientation:r,license:o,format:i}=t,a=i==="human"?Ka("Finding videos...").start():null;try{let d=await xo({query:e,options:{maxResults:parseInt(n,10),orientation:r,license:o,sources:sp(t.source)}});a?.stop();let l=d.data.results.flatMap(y=>y.results);if(i==="json"){let{totalCost:y,...p}=d.data;u({...d,data:p});return}if(i==="quiet"){l.forEach(y=>{console.log(y.embedUrl||y.previewUrl||y.thumbnailUrl)});return}if(l.length===0){g("No videos found");return}x(`Found ${l.length} videos for "${e}"`),console.log(),l.forEach((y,p)=>{let w=y.kind==="embed";console.log(`[${p+1}] ${y.title}`),console.log(` ${w?"Embed":"URL"}: ${y.embedUrl||y.previewUrl||y.thumbnailUrl}`),console.log(w?` Duration: ${y.duration}s | Embed only \u2014 plays in the host player, do not download`:` Duration: ${y.duration}s | Size: ${y.width}x${y.height}`),console.log(` Provider: ${y.provider}`),console.log()}),g(`Total cost: $${d.data.totalCost.toFixed(4)}`)}catch(d){a?.stop(),s(d instanceof Error?d.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),cp=new ee("create").description("Generate one video from a pinned storyboard revision").requiredOption("--storyboard-revision <id>","Immutable storyboard revision UUID").option("--source-video <id>","Ready video from an earlier create call to use as base footage").option("--draft","Generate at 480p for a faster draft").option("--team-id <id>","Workspace ID").option("--approval-receipt <receipt>","Receipt returned by the browser confirmation URL; omit on the first call to get that URL").requiredOption("--idempotency-key <key>","Stable invocation key bound into the approval receipt").option("--yes","Approve paid video generation").action(async e=>{if(!e.yes)return s("Pass --yes to approve video generation");try{u(await Ao({quality:e.draft?"draft":void 0,sourceVideoId:e.sourceVideo,storyboardRevisionId:e.storyboardRevision,teamId:e.teamId},e.approvalReceipt,e.idempotencyKey))}catch(t){s(t instanceof Error?t.message:"Generation failed"),process.exit(c.GENERAL_ERROR)}});async function Ja(e){let t=e==="-"?await ap():await op(e,"utf-8");if(!t?.trim())throw new Error(e==="-"?"No storyboard Markdown was received on stdin":`Storyboard file is empty: ${e}`);return t}async function za(e,t={}){if(e)return e.length===1&&e[0]==="none"?[]:Promise.all(e.map(async n=>{let r;try{let v=JSON.parse(n);if(!v||typeof v!="object"||Array.isArray(v))throw new Error("Media binding must be a JSON object");r=v}catch(v){throw new Error(`Invalid --media binding. Pass one JSON object per binding, for example '{"handle":"actress-photo","path":"./actress.jpg","purpose":"identity"}'.`,{cause:v})}let o=ue(r.handle),i=ue(r.path),a=ue(r.fileUrl)??ue(r.url),d=ue(r.purpose),l=ue(r.videoRole),y=ue(r.analysisId)??ue(r.analysis);if(!o||!i&&!a||!d)throw new Error("Invalid --media binding. handle, purpose, and either path or url are required strings.");if(i&&a)throw new Error("A media binding cannot contain both path and url.");if(i&&d==="source"&&y)throw new Error("A source analysis is bound to the original uploaded URL. Reuse the url/name/mime/size binding printed by 'video reference analyze' instead of uploading path again.");if(i&&!t.uploadIdempotencyKey)throw new Error("Local storyboard media requires the command idempotency key.");let p=i?await me(wt(i),{idempotencyKey:`${t.uploadIdempotencyKey}:media:${o}`}):{name:ue(r.name),size:Number(r.size),type:ue(r.mime),url:a};if(!p.name||!p.type||!p.url||!Number.isSafeInteger(p.size)||p.size<=0)throw new Error(`URL media binding "${n}" requires name, mime, and positive integer size.`);let w=p.type.startsWith("video/")?"video":p.type.startsWith("audio/")?"audio":p.type.startsWith("image/")?"image":null;if(!w)throw new Error(`Unsupported media type for ${i??a}: ${p.type}`);if(!["source","style","identity","required"].includes(d))throw new Error(`Invalid media purpose: ${d}`);if(l&&!["reference","first-frame","last-frame"].includes(l))throw new Error(`Invalid videoRole: ${l}`);if(l&&w!=="image")throw new Error("videoRole is supported only for image bindings.");return{...y?{analysisId:y}:{},fileUrl:p.url,handle:o,kind:w,mime:p.type,name:p.name,purpose:d,size:p.size,...l?{videoRole:l}:{}}}))}function ue(e){return typeof e=="string"&&e.length>0?e:void 0}var lp=new ee("create").description("Create a versioned Markdown video storyboard").requiredOption("--file <path>","Markdown file path, or - for stdin").requiredOption("--duration <seconds>","Exact total duration in seconds").requiredOption("--aspect <ratio>","Output aspect: 9:16, 16:9, or 1:1").option("--title <text>","Artifact label").requiredOption("--idempotency-key <key>","Stable key to reuse when retrying this exact create").option("--media <binding...>",'One JSON binding per asset: {"handle":"actress-photo","path":"./actress.jpg","purpose":"identity"}').option("--team-id <id>","Workspace ID").action(async e=>{try{u(await h("createVideoStoryboard",{aspectRatio:e.aspect,durationSec:Number(e.duration),mediaBindings:await za(e.media,{uploadIdempotencyKey:e.idempotencyKey}),storyboardMarkdown:await Ja(e.file),teamId:e.teamId,title:e.title},e.idempotencyKey))}catch(t){s(t instanceof Error?t.message:"Storyboard creation failed"),process.exit(c.GENERAL_ERROR)}}),mp=new ee("revise").description("Append an immutable revision to a video storyboard").argument("<storyboard-id>","Storyboard UUID").requiredOption("--base-revision <id>","Revision UUID that was edited").requiredOption("--file <path>","Complete Markdown file path, or - for stdin").requiredOption("--duration <seconds>","Exact total duration in seconds").requiredOption("--aspect <ratio>","Output aspect: 9:16, 16:9, or 1:1").option("--title <text>","Replacement artifact label").requiredOption("--idempotency-key <key>","Stable key to reuse when retrying this exact revision").option("--change-summary <text>","Short description of this revision").option("--media <binding...>",'Replace media bindings with one JSON object per asset; use the JSON printed by "video reference analyze" for analyzed source video').option("--team-id <id>","Workspace ID").action(async(e,t)=>{try{u(await h("reviseVideoStoryboard",{aspectRatio:t.aspect,baseRevisionId:t.baseRevision,changeSummary:t.changeSummary,durationSec:Number(t.duration),mediaBindings:await za(t.media,{uploadIdempotencyKey:t.idempotencyKey}),storyboardId:e,storyboardMarkdown:await Ja(t.file),teamId:t.teamId,title:t.title},t.idempotencyKey))}catch(n){s(n instanceof Error?n.message:"Storyboard revision failed"),process.exit(c.GENERAL_ERROR)}}),up=new ee("show").description("Read a storyboard; print Markdown unless --json is used").argument("<storyboard-id>","Storyboard UUID").option("--revision <id>","Read one immutable revision UUID").option("--team-id <id>","Workspace ID").option("--json","Print the complete structured response").action(async(e,t)=>{try{let n=await h("readVideoStoryboard",{revisionId:t.revision,storyboardId:e,teamId:t.teamId});if(t.json){u(n);return}console.error(`${n.storyboard.title} \xB7 revision ${n.storyboard.revision.versionNumber} (${n.storyboard.revision.id})`),console.log(n.storyboard.revision.storyboardMarkdown)}catch(n){s(n instanceof Error?n.message:"Storyboard read failed"),process.exit(c.GENERAL_ERROR)}}),pp=new ee("storyboard").description("Create, revise, and read Markdown video storyboards").addCommand(lp).addCommand(mp).addCommand(up),Xa=new ee("analyze").description("Upload and analyze a reference video; its analysisId is the only analysis video generation consumes").requiredOption("--file <path>","Local reference video").requiredOption("--idempotency-key <key>","Stable key to reuse when retrying this exact analysis").option("--user-request <text>","What the analysis should focus on").option("--team-id <id>","Workspace ID").option("--no-wait","Return the durable run immediately").option("--json","Print the complete structured result").action(async e=>{try{let t=await me(wt(e.file),{idempotencyKey:`video-reference-analysis:${e.idempotencyKey}:source`});if(!t.type.startsWith("video/"))throw new Error(`Reference analysis requires a video, got ${t.type}`);let n=await Oo({idempotencyKey:e.idempotencyKey,sourceUrl:t.url,teamId:e.teamId,userRequest:e.userRequest}),r={analysisId:n.runId,fileUrl:t.url,handle:"source-video",kind:"video",mime:t.type,name:t.name,purpose:"source",size:t.size};if(e.wait===!1){u({...n,binding:r,source:t});return}let o=await Po(n.runId,e.teamId);if(e.json){u({...o,binding:r,source:t});return}let i=o.output?.analysis??{};console.log(typeof i.promptContext=="string"?i.promptContext:JSON.stringify(o.output,null,2)),console.error(`Analysis run: ${n.runId}`),console.error(`Storyboard media JSON: ${JSON.stringify(r)}`)}catch(t){s(t instanceof Error?t.message:"Reference analysis failed"),process.exit(c.GENERAL_ERROR)}});Xa.addHelpText("after",`
|
|
179
|
+
`);if(t.output&&(await Lu(t.output,i,"utf-8"),n==="human"&&x(`Transcript saved to: ${t.output}`)),n==="json"){u(o);return}if(n==="quiet"){console.log(i);return}console.log(),console.log(`Title: ${o.title}`),o.channelName&&console.log(`Channel: ${o.channelName}`),o.durationFormatted&&console.log(`Duration: ${o.durationFormatted}`),console.log(`Language: ${o.language??"unknown"}${o.isAutoGenerated?" (auto-generated)":""}`),console.log(`Words: ${o.wordCount.toLocaleString()}`),console.log(`URL: ${o.url}`),o.truncated&&M("Transcript was truncated to fit the response budget."),t.output||(console.log(),console.log("--- Transcript ---"),console.log(i)),o.totalCost&&o.totalCost>0&&g(`Cost: $${o.totalCost.toFixed(6)}`)}catch(o){r?.stop(),s(o instanceof Error?o.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}});import{mkdir as qu,writeFile as Pa}from"fs/promises";import{dirname as Uu}from"path";import{Command as Qt}from"commander";import Da from"ora";var _a="en-US-Neural2-C",La="gemini",ju=new Qt("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: ${_a})`).option("-p, --provider <provider>",`Provider: gemini, elevenlabs, openai (default: ${La})`).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",b("--format",["human","json","quiet"]),"human").action(async e=>{let t=e.format,n=t==="human"?Da("Generating speech...").start():null,r;e.speed&&(r=parseFloat(e.speed),(Number.isNaN(r)||r<.1||r>4)&&(n?.stop(),s("Speed must be between 0.1 and 4.0"),process.exit(c.INVALID_INPUT)));let o;if(e.speakers)try{o=JSON.parse(e.speakers),(!Array.isArray(o)||o.length===0||o.length>2||o.some(a=>!a||typeof a!="object"||typeof a.name!="string"||!a.name.trim()||typeof a.voice!="string"||!a.voice.trim()))&&(n?.stop(),s("Speakers must be an array with 1-2 name/voice items"),process.exit(c.INVALID_INPUT))}catch{n?.stop(),s(`Invalid --speakers JSON. Example: '[{"name":"Joe","voice":"Kore"}]'`),process.exit(c.INVALID_INPUT)}let i;try{let a=e.voiceId,d=e.voice||_a,l=e.provider||La,y={};o&&(y.gemini={speakers:o}),e.instructions&&(y.openai={instructions:e.instructions});let p=await fo({text:e.text,options:{language:e.lang,provider:l,voiceId:a,voice:d,model:e.model,speed:r,providerOptions:Object.keys(y).length>0?y:void 0}});i=p.requestId,n?.stop();let w=e.output.endsWith(`.${p.format}`)?e.output:`${e.output}.${p.format}`;await qu(Uu(w),{recursive:!0}),await Pa(w,p.audioData);let v=w.replace(/\.[^.]+$/,".txt");if(await Pa(v,e.text,"utf-8"),t==="json"){u({status:"completed",output:w,audioUrl:p.audioUrl,duration:p.duration,provider:p.provider,format:p.format,voice_id:p.voiceId??null,voice:p.voice??d,model:p.model??e.model??null,speed:p.speed??r??1,lang:p.language??e.lang??null,langApplied:p.langApplied??!1,timestamps:p.timestamps??null,words:p.wordTimings??null});return}if(t==="quiet"){console.log(w);return}x(`Saved to: ${w}`),g(`Duration: ${p.duration.toFixed(2)}s`),g(`Provider: ${p.provider}`),g(`Cost: $${p.cost.toFixed(6)}`)}catch(a){n?.stop(),s(ae(a,i),t),process.exit(c.GENERAL_ERROR)}}),Mu=new Qt("voices").description("List available voices").option("-p, --provider <provider>","Filter by provider: gemini, elevenlabs, openai").option("-f, --format <format>","Output format: human, json",b("--format",["human","json"]),"human").action(async e=>{let t=e.format==="human"?Da("Fetching voices...").start():null;try{let n=await yo(e.provider);if(t?.stop(),e.format==="json"){u(n.voices);return}if(Array.isArray(n.voices)){let r=e.provider?.toUpperCase()||"VOICES";console.log(),console.log(`${r} Voices:`),console.log("-".repeat(50));for(let o of n.voices)console.log(` ${o.name} (${o.id})`),console.log(` ${o.description}`)}else for(let[r,o]of Object.entries(n.voices))if(!(!o||o.length===0)){console.log(),console.log(`${r.toUpperCase()} Voices:`),console.log("-".repeat(50));for(let i of o)console.log(` ${i.name} (${i.id})`),console.log(` ${i.description}`)}}catch(n){t?.stop(),s(n instanceof Error?n.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),Fu=new Qt("status").description("Read speech generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").option("-f, --format <format>","Output format: json",b("--format",["json"]),"json").action(async(e,t)=>{try{u(await T("generateSpeech",e,t.teamId))}catch(n){s(n instanceof Error?n.message:"Status failed"),process.exit(c.GENERAL_ERROR)}}),Na=new Qt("tts").description("Text-to-speech commands").addCommand(ju).addCommand(Mu).addCommand(Fu);import{execSync as Zt,spawnSync as rp}from"child_process";import{access as gr,readFile as op,rm as Wa}from"fs/promises";import{resolve as wt}from"path";import Q from"chalk";import{Command as ee}from"commander";import ip from"ffmpeg-static";import Ka from"ora";import{mkdir as Vu}from"fs/promises";import{join as Gu}from"path";import{Command as bt}from"commander";import Ua from"ora";var Bu=5e3,Wu=120,qa=5;function Ku(e,t){return[...t,e]}function Ju(e,t){try{let n=new URL(e);if(n.protocol!=="https:"&&n.protocol!=="http:")throw new Error;return n.toString()}catch{throw new Error(`${t} must be a public HTTP(S) URL`)}}function ja(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 zu(e){if(e.mode&&!["speed","precision"].includes(e.mode))throw new Error("Lip-sync mode must be speed or precision");return{audioUrl:Ju(e.audioUrl,"Audio URL"),...e.mode?{mode:e.mode}:{},sourceVideoId:ja(e.sourceVideoId)}}function Xu(e){let t=[],n=new Set;for(let o of e.targetLanguage){let i=o.trim(),a=i.toLocaleLowerCase("en-US");!i||n.has(a)||(n.add(a),t.push(i))}if(t.length===0)throw new Error("Provide at least one target language");if(t.length>qa)throw new Error(`Provide at most ${qa} target languages`);if(t.find(o=>o.length<2||o.length>40))throw new Error("Target languages must be between 2 and 40 characters");return{...e.captions?{captions:!0}:{},sourceVideoId:ja(e.sourceVideoId),targetLanguages:t}}function Hu(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 pr(e){return{requestId:e.runId,status:Hu(e),...e.entity?.url?{videoUrl:e.entity.url}:{},...e.output?{output:e.output}:{},...e.error?{error:se(e.error)}:{}}}function Ma(e){return{requestId:e.runId,status:"pending"}}async function Fa(e,t){return te(async()=>pr(await T(e,t)),Wu,Bu)}function We(e,t){if(t==="json"){u(e);return}if(t==="quiet"){console.log(e.videoUrl??e.requestId);return}g(`Request ID: ${e.requestId}`),g(`Status: ${e.status}`),e.videoUrl&&x(`Video URL: ${e.videoUrl}`),e.error&&s(`Error: ${e.error}`)}function Yu(e){return Array.isArray(e?.languages)?e.languages.filter(t=>{if(!t||typeof t!="object"||Array.isArray(t))return!1;let n=t;return typeof n.language=="string"&&(n.status==="completed"||n.status==="failed")&&typeof n.videoId=="string"&&(n.videoUrl===null||typeof n.videoUrl=="string")}):[]}function Qu(e){return`${e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")||"translation"}.mp4`}function Zu(e,t){let n=Qu(e);if(!t.has(n))return t.add(n),n;let r=n.slice(0,-4),o=2;for(;t.has(`${r}-${o}.mp4`);)o+=1;let i=`${r}-${o}.mp4`;return t.add(i),i}async function ep(e,t){let n=Yu(e.output).filter(i=>i.status==="completed"&&!!i.videoUrl);if(n.length===0)throw new Error("Video translation completed without downloadable results");await Vu(t,{recursive:!0});let r=[],o=new Set;for(let i of n){let a=Gu(t,Zu(i.language,o));await Y(i.videoUrl,a),r.push({language:i.language,path:a})}return r}var tp=new bt("status").description("Check a video lip-sync request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"])).action(async function(e,t){let r=F(this,t).format??"human";try{We(pr(await T("lipsyncVideo",e)),r)}catch(o){s(o instanceof Error?o.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),Va=new bt("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",b("--format",["human","json","quiet"]),"human").action(async e=>{let t=e.format==="human"?Ua("Starting video lip-sync...").start():null,n;try{let r=await $o(zu(e));if(n=r.runId,!e.wait){t?.stop(),We(Ma(r),e.format);return}t&&(t.text="Waiting for video lip-sync...");let o=await Fa("lipsyncVideo",r.runId);if(o.status==="failed")throw new Error(o.error??"Video lip-sync failed");if(!o.videoUrl)throw new Error("Video lip-sync completed without a video URL");t&&(t.text="Downloading lip-synced video..."),await Y(o.videoUrl,e.output),t?.stop(),We(o,e.format),e.format==="human"&&x(`Saved to: ${e.output}`)}catch(r){t?.stop(),s(ae(r,n),e.format),process.exit(c.GENERAL_ERROR)}}).addCommand(tp),Ga=new bt("translate-languages").description("List supported video translation target languages").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async e=>{try{let t=await To();if(e.format==="json")u({languages:t});else for(let n of t)console.log(n)}catch(t){s(t instanceof Error?t.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),np=new bt("status").description("Check a video translation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"])).action(async function(e,t){let r=F(this,t).format??"human";try{We(pr(await T("translateVideo",e)),r)}catch(o){s(o instanceof Error?o.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),Ba=new bt("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)",Ku,[]).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",b("--format",["human","json","quiet"]),"human").action(async e=>{let t=e.format==="human"?Ua("Starting video translation...").start():null,n;try{let r=await Eo(Xu(e));if(n=r.runId,!e.wait){t?.stop(),We(Ma(r),e.format);return}t&&(t.text="Waiting for video translations...");let o=await Fa("translateVideo",r.runId);if(o.status==="failed")throw new Error(o.error??"Video translation failed");t&&(t.text="Downloading translated videos...");let i=await ep(o,e.outputDir);if(t?.stop(),e.format==="json")u({...o,downloads:i});else if(e.format==="quiet")for(let a of i)console.log(a.path);else{We(o,e.format);for(let a of i)x(`${a.language}: ${a.path}`)}}catch(r){t?.stop(),s(ae(r,n),e.format),process.exit(c.GENERAL_ERROR)}}).addCommand(np);async function ap(){return process.stdin.isTTY?null:new Promise(e=>{let t="",n=!1;process.stdin.setEncoding("utf-8"),process.stdin.on("data",r=>{t+=r}),process.stdin.on("end",()=>{n||(n=!0,e(t.trim()||null))}),process.stdin.on("error",()=>{n||(n=!0,e(null))}),setTimeout(()=>{!n&&!t&&(n=!0,e(null))},500)})}function sp(e){let t=e?.trim().toLowerCase();if(!(!t||t==="any"||t==="all"))return t==="web"||t==="stock"?[t]:void 0}var dp=new ee("find").description("Find video clips across the web and licensed stock").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("--source <source>","Catalog: web, stock, or any (default: any)","any").option("-f, --format <format>","Output format: human, json, quiet",b("--format",["human","json","quiet"]),"human").action(async(e,t)=>{let{maxResults:n,orientation:r,license:o,format:i}=t,a=i==="human"?Ka("Finding videos...").start():null;try{let d=await xo({query:e,options:{maxResults:parseInt(n,10),orientation:r,license:o,sources:sp(t.source)}});a?.stop();let l=d.data.results.flatMap(y=>y.results);if(i==="json"){let{totalCost:y,...p}=d.data;u({...d,data:p});return}if(i==="quiet"){l.forEach(y=>{console.log(y.embedUrl||y.previewUrl||y.thumbnailUrl)});return}if(l.length===0){g("No videos found");return}x(`Found ${l.length} videos for "${e}"`),console.log(),l.forEach((y,p)=>{let w=y.kind==="embed";console.log(`[${p+1}] ${y.title}`),console.log(` ${w?"Embed":"URL"}: ${y.embedUrl||y.previewUrl||y.thumbnailUrl}`),console.log(w?` Duration: ${y.duration}s | Embed only \u2014 plays in the host player, do not download`:` Duration: ${y.duration}s | Size: ${y.width}x${y.height}`),console.log(` Provider: ${y.provider}`),console.log()}),g(`Total cost: $${d.data.totalCost.toFixed(4)}`)}catch(d){a?.stop(),s(d instanceof Error?d.message:"Unknown error"),process.exit(c.GENERAL_ERROR)}}),cp=new ee("create").description("Generate one video from a pinned storyboard revision").requiredOption("--storyboard-revision <id>","Immutable storyboard revision UUID").option("--source-video <id>","Ready video from an earlier create call to use as base footage").option("--release","Render at 720p for release. Costs more; drafts are 480p by default").option("--team-id <id>","Workspace ID").option("--approval-receipt <receipt>","Receipt returned by the browser confirmation URL; omit on the first call to get that URL").requiredOption("--idempotency-key <key>","Stable invocation key bound into the approval receipt").option("--yes","Approve paid video generation").action(async e=>{if(!e.yes)return s("Pass --yes to approve video generation");try{u(await Ao({quality:e.release?"release":void 0,sourceVideoId:e.sourceVideo,storyboardRevisionId:e.storyboardRevision,teamId:e.teamId},e.approvalReceipt,e.idempotencyKey))}catch(t){s(t instanceof Error?t.message:"Generation failed"),process.exit(c.GENERAL_ERROR)}});async function Ja(e){let t=e==="-"?await ap():await op(e,"utf-8");if(!t?.trim())throw new Error(e==="-"?"No storyboard Markdown was received on stdin":`Storyboard file is empty: ${e}`);return t}async function za(e,t={}){if(e)return e.length===1&&e[0]==="none"?[]:Promise.all(e.map(async n=>{let r;try{let v=JSON.parse(n);if(!v||typeof v!="object"||Array.isArray(v))throw new Error("Media binding must be a JSON object");r=v}catch(v){throw new Error(`Invalid --media binding. Pass one JSON object per binding, for example '{"handle":"actress-photo","path":"./actress.jpg","purpose":"identity"}'.`,{cause:v})}let o=ue(r.handle),i=ue(r.path),a=ue(r.fileUrl)??ue(r.url),d=ue(r.purpose),l=ue(r.videoRole),y=ue(r.analysisId)??ue(r.analysis);if(!o||!i&&!a||!d)throw new Error("Invalid --media binding. handle, purpose, and either path or url are required strings.");if(i&&a)throw new Error("A media binding cannot contain both path and url.");if(i&&d==="source"&&y)throw new Error("A source analysis is bound to the original uploaded URL. Reuse the url/name/mime/size binding printed by 'video reference analyze' instead of uploading path again.");if(i&&!t.uploadIdempotencyKey)throw new Error("Local storyboard media requires the command idempotency key.");let p=i?await me(wt(i),{idempotencyKey:`${t.uploadIdempotencyKey}:media:${o}`}):{name:ue(r.name),size:Number(r.size),type:ue(r.mime),url:a};if(!p.name||!p.type||!p.url||!Number.isSafeInteger(p.size)||p.size<=0)throw new Error(`URL media binding "${n}" requires name, mime, and positive integer size.`);let w=p.type.startsWith("video/")?"video":p.type.startsWith("audio/")?"audio":p.type.startsWith("image/")?"image":null;if(!w)throw new Error(`Unsupported media type for ${i??a}: ${p.type}`);if(!["source","style","identity","required"].includes(d))throw new Error(`Invalid media purpose: ${d}`);if(l&&!["reference","first-frame","last-frame"].includes(l))throw new Error(`Invalid videoRole: ${l}`);if(l&&w!=="image")throw new Error("videoRole is supported only for image bindings.");return{...y?{analysisId:y}:{},fileUrl:p.url,handle:o,kind:w,mime:p.type,name:p.name,purpose:d,size:p.size,...l?{videoRole:l}:{}}}))}function ue(e){return typeof e=="string"&&e.length>0?e:void 0}var lp=new ee("create").description("Create a versioned Markdown video storyboard").requiredOption("--file <path>","Markdown file path, or - for stdin").requiredOption("--duration <seconds>","Exact total duration in seconds").requiredOption("--aspect <ratio>","Output aspect: 9:16, 16:9, or 1:1").option("--title <text>","Artifact label").requiredOption("--idempotency-key <key>","Stable key to reuse when retrying this exact create").option("--media <binding...>",'One JSON binding per asset: {"handle":"actress-photo","path":"./actress.jpg","purpose":"identity"}').option("--team-id <id>","Workspace ID").action(async e=>{try{u(await h("createVideoStoryboard",{aspectRatio:e.aspect,durationSec:Number(e.duration),mediaBindings:await za(e.media,{uploadIdempotencyKey:e.idempotencyKey}),storyboardMarkdown:await Ja(e.file),teamId:e.teamId,title:e.title},e.idempotencyKey))}catch(t){s(t instanceof Error?t.message:"Storyboard creation failed"),process.exit(c.GENERAL_ERROR)}}),mp=new ee("revise").description("Append an immutable revision to a video storyboard").argument("<storyboard-id>","Storyboard UUID").requiredOption("--base-revision <id>","Revision UUID that was edited").requiredOption("--file <path>","Complete Markdown file path, or - for stdin").requiredOption("--duration <seconds>","Exact total duration in seconds").requiredOption("--aspect <ratio>","Output aspect: 9:16, 16:9, or 1:1").option("--title <text>","Replacement artifact label").requiredOption("--idempotency-key <key>","Stable key to reuse when retrying this exact revision").option("--change-summary <text>","Short description of this revision").option("--media <binding...>",'Replace media bindings with one JSON object per asset; use the JSON printed by "video reference analyze" for analyzed source video').option("--team-id <id>","Workspace ID").action(async(e,t)=>{try{u(await h("reviseVideoStoryboard",{aspectRatio:t.aspect,baseRevisionId:t.baseRevision,changeSummary:t.changeSummary,durationSec:Number(t.duration),mediaBindings:await za(t.media,{uploadIdempotencyKey:t.idempotencyKey}),storyboardId:e,storyboardMarkdown:await Ja(t.file),teamId:t.teamId,title:t.title},t.idempotencyKey))}catch(n){s(n instanceof Error?n.message:"Storyboard revision failed"),process.exit(c.GENERAL_ERROR)}}),up=new ee("show").description("Read a storyboard; print Markdown unless --json is used").argument("<storyboard-id>","Storyboard UUID").option("--revision <id>","Read one immutable revision UUID").option("--team-id <id>","Workspace ID").option("--json","Print the complete structured response").action(async(e,t)=>{try{let n=await h("readVideoStoryboard",{revisionId:t.revision,storyboardId:e,teamId:t.teamId});if(t.json){u(n);return}console.error(`${n.storyboard.title} \xB7 revision ${n.storyboard.revision.versionNumber} (${n.storyboard.revision.id})`),console.log(n.storyboard.revision.storyboardMarkdown)}catch(n){s(n instanceof Error?n.message:"Storyboard read failed"),process.exit(c.GENERAL_ERROR)}}),pp=new ee("storyboard").description("Create, revise, and read Markdown video storyboards").addCommand(lp).addCommand(mp).addCommand(up),Xa=new ee("analyze").description("Upload and analyze a reference video; its analysisId is the only analysis video generation consumes").requiredOption("--file <path>","Local reference video").requiredOption("--idempotency-key <key>","Stable key to reuse when retrying this exact analysis").option("--user-request <text>","What the analysis should focus on").option("--team-id <id>","Workspace ID").option("--no-wait","Return the durable run immediately").option("--json","Print the complete structured result").action(async e=>{try{let t=await me(wt(e.file),{idempotencyKey:`video-reference-analysis:${e.idempotencyKey}:source`});if(!t.type.startsWith("video/"))throw new Error(`Reference analysis requires a video, got ${t.type}`);let n=await Oo({idempotencyKey:e.idempotencyKey,sourceUrl:t.url,teamId:e.teamId,userRequest:e.userRequest}),r={analysisId:n.runId,fileUrl:t.url,handle:"source-video",kind:"video",mime:t.type,name:t.name,purpose:"source",size:t.size};if(e.wait===!1){u({...n,binding:r,source:t});return}let o=await Po(n.runId,e.teamId);if(e.json){u({...o,binding:r,source:t});return}let i=o.output?.analysis??{};console.log(typeof i.promptContext=="string"?i.promptContext:JSON.stringify(o.output,null,2)),console.error(`Analysis run: ${n.runId}`),console.error(`Storyboard media JSON: ${JSON.stringify(r)}`)}catch(t){s(t instanceof Error?t.message:"Reference analysis failed"),process.exit(c.GENERAL_ERROR)}});Xa.addHelpText("after",`
|
|
180
180
|
${Q.gray("# Prints an analysisId plus a ready storyboard media binding. Pass that")}
|
|
181
181
|
${Q.gray("# binding to video storyboard create/revise --media; generation reads the")}
|
|
182
182
|
${Q.gray("# analysis from the analysisId, never from local files.")}
|
|
@@ -488,8 +488,8 @@ ${n} video status <run-id>
|
|
|
488
488
|
into the approval receipt. Call it once without \`--approval-receipt\` to get a
|
|
489
489
|
browser confirmation URL, then repeat the **exact** invocation with
|
|
490
490
|
\`--approval-receipt <receipt>\`. \`--yes\` states intent; it is not a receipt and
|
|
491
|
-
never substitutes for one.
|
|
492
|
-
\`--source-video <id>\` reuses a finished video as base footage.
|
|
491
|
+
never substitutes for one. A render is 480p unless \`--release\` asks for 720p,
|
|
492
|
+
which costs more; \`--source-video <id>\` reuses a finished video as base footage.
|
|
493
493
|
|
|
494
494
|
## Before you generate
|
|
495
495
|
|
|
@@ -506,11 +506,44 @@ never overwritten, so iterating costs nothing and loses nothing; a revision is
|
|
|
506
506
|
immutable once \`video create\` pins it, which is why the reading happens now.
|
|
507
507
|
|
|
508
508
|
Offer the material choices instead of deciding them silently: the
|
|
509
|
-
\`--duration\` and \`--aspect\` the revision was created with, whether
|
|
510
|
-
|
|
509
|
+
\`--duration\` and \`--aspect\` the revision was created with, whether the 480p
|
|
510
|
+
default is enough or this is the \`--release\` run, and any \`--media\` binding with
|
|
511
511
|
\`purpose\` \`identity\` \u2014 who appears in the shot is not something to guess.
|
|
512
512
|
Say what you would pick and why.
|
|
513
513
|
|
|
514
|
+
### When a source is bound, write the change and nothing else
|
|
515
|
+
|
|
516
|
+
Composing is your job when the user brings an idea: a brief like "a 30-second
|
|
517
|
+
promo about X" needs you to plan the shots, and under-describing it wastes a
|
|
518
|
+
paid run just as surely as over-describing one.
|
|
519
|
+
|
|
520
|
+
A bound source video inverts that. Its frames already carry the shot, the angle,
|
|
521
|
+
the props, the lighting, the pacing and the graphics, so a storyboard that
|
|
522
|
+
describes those things does not reinforce them \u2014 it overwrites them. The model
|
|
523
|
+
obeys the text over the pictures, which means every sentence you add beyond the
|
|
524
|
+
user's actual request is an instruction to ignore the reference.
|
|
525
|
+
|
|
526
|
+
"Replace the man in this clip with me" became a thirty-five-line film treatment
|
|
527
|
+
once, and the three lines that read *walks straight toward the lens*,
|
|
528
|
+
*no props* and *no labels* silently deleted the profile framing, the treadmill,
|
|
529
|
+
the suitcase and the on-screen product card that made the reference what it was.
|
|
530
|
+
The bindings were correct; the prose was the bug.
|
|
531
|
+
|
|
532
|
+
So: with a bound source, write only the change the user asked for.
|
|
533
|
+
|
|
534
|
+
\`\`\`
|
|
535
|
+
Replace the man in the source clip with the man in the supplied photograph.
|
|
536
|
+
Keep everything else exactly as in the source.
|
|
537
|
+
\`\`\`
|
|
538
|
+
|
|
539
|
+
That is a complete storyboard. The prompt cannot be empty \u2014 the provider
|
|
540
|
+
requires text whenever reference images are attached \u2014 but two lines are enough,
|
|
541
|
+
and everything absent from them is inherited rather than invented.
|
|
542
|
+
|
|
543
|
+
If you believe the result needs something the user did not mention, put it in
|
|
544
|
+
your reply as a proposal and let them accept it. Never fold it into the
|
|
545
|
+
storyboard on their behalf.
|
|
546
|
+
|
|
514
547
|
**Then, the spend.** \`video create\` costs credits, runs for minutes and
|
|
515
548
|
produces the file the user will send to other people. The browser confirmation
|
|
516
549
|
its approval receipt requires asks a person about **cost and destination**; it
|
|
@@ -2700,7 +2733,7 @@ ${j.bold("Examples:")}
|
|
|
2700
2733
|
`);rt.command("install").description(`Install ${m.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,t)=>{t.mode&&!un.includes(t.mode)&&(s(`Invalid mode: ${t.mode}. Must be one of: ${un.join(", ")}`),process.exit(1));let n={...us,mode:t.mode},r=[];e&&!nt.includes(e)&&(s(`Invalid skill type: ${e}. Must be one of: ${nt.join(", ")}`),process.exit(1));let o=await at();o.source==="snapshot"&&(M(`Live capability catalog unavailable (${o.reason??"unknown reason"}) \u2014 generating from the snapshot baked into this CLI.`),console.log(j.gray(` Run \`${m.commands[0]} login\` then re-run with --force to regenerate from the live catalog.`)));let i=[...rs(n,o,{branding:et(n)}),{name:"tts",content:Je(n)},{name:"music",content:ze(n)},{name:"sfx",content:Xe(n)},{name:"mix",content:He(n)},{name:"image",content:Ye(n)},{name:"video-search",content:Qe(n)},{name:"scrape",content:Ze(n)},{name:"config",content:tt(n)}];(!e||e==="main")&&r.push({name:m.name,content:an(n,o),references:i}),(!e||e==="video")&&r.push({content:cn(n,o),name:`${m.name}-video`,references:is(n,o)}),(!e||e==="presentation")&&r.push({name:`${m.name}-presentation`,content:dn(n)}),(!e||e==="presentation-edit")&&r.push({name:`${m.name}-presentation-edit`,content:sn(n)}),e==="tts"&&r.push({name:`${m.name}-tts`,content:Je(n)}),e==="music"&&r.push({name:`${m.name}-music`,content:ze(n)}),e==="sfx"&&r.push({name:`${m.name}-sfx`,content:Xe(n)}),e==="mix"&&r.push({name:`${m.name}-mix`,content:He(n)}),e==="image"&&r.push({name:`${m.name}-image`,content:Ye(n)}),e==="video-search"&&r.push({name:`${m.name}-video-search`,content:Qe(n)}),e==="scrape"&&r.push({name:`${m.name}-scrape`,content:Ze(n)}),e==="branding"&&r.push({name:`${m.name}-branding`,content:et(n)}),e==="config"&&r.push({name:`${m.name}-config`,content:tt(n)}),console.log();for(let a of r){g(`Installing ${a.name}...`);let d=ln(a.name,a.content,{dir:t.dir,local:t.local,force:t.force},a.references);if(d.installed.length>0&&(x(`${a.name} installed successfully`),R(" Installed to",d.installed.join(", "))),d.skipped.length>0&&(g(` Skipped (already exists): ${d.skipped.join(", ")}`),console.log(j.gray(" Use --force to overwrite"))),d.errors.length>0)for(let l of d.errors)s(` ${l}`);d.installed.length===0&&d.skipped.length===0&&d.errors.length===0&&(g(" No supported AI coding assistants detected"),console.log(j.gray(` Supported editors: ${ms().join(", ")}`)),console.log(j.gray(" Use --dir <path> to install to a specific directory"))),console.log()}});rt.command("show").description("Display skill content").argument("[type]","Skill type (default: main)").option("-m, --mode <mode>","Skill mode: standalone or studio","standalone").action(async(e="main",t)=>{t.mode&&!un.includes(t.mode)&&(s(`Invalid mode: ${t.mode}. Must be one of: ${un.join(", ")}`),process.exit(1));let n={...us,mode:t.mode},r=await at(),i={main:()=>an(n,r),video:()=>cn(n,r),presentation:()=>dn(n),"presentation-edit":()=>sn(n),tts:()=>Je(n),music:()=>ze(n),sfx:()=>Xe(n),mix:()=>He(n),image:()=>Ye(n),"video-search":()=>Qe(n),scrape:()=>Ze(n),branding:()=>et(n),config:()=>tt(n)}[e];i?console.log(i()):(s(`Invalid skill type: ${e}. Must be one of: ${nt.join(", ")}`),process.exit(1))});rt.command("uninstall").description(`Remove ${m.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,t)=>{let n=[];e&&!nt.includes(e)&&(s(`Invalid skill type: ${e}. Must be one of: ${nt.join(", ")}`),process.exit(1)),(!e||e==="main")&&n.push(m.name),(!e||e==="video")&&n.push(`${m.name}-video`),(!e||e==="presentation")&&n.push(`${m.name}-presentation`),(!e||e==="presentation-edit")&&n.push(`${m.name}-presentation-edit`),(!e||e==="tts")&&n.push(`${m.name}-tts`),(!e||e==="music")&&n.push(`${m.name}-music`),(!e||e==="sfx")&&n.push(`${m.name}-sfx`),(!e||e==="mix")&&n.push(`${m.name}-mix`),(!e||e==="image")&&n.push(`${m.name}-image`),(!e||e==="video-search")&&n.push(`${m.name}-video-search`),(!e||e==="scrape")&&n.push(`${m.name}-scrape`),(!e||e==="branding")&&n.push(`${m.name}-branding`),(!e||e==="config")&&n.push(`${m.name}-config`),console.log();for(let r of n){let o=mn(r,{local:t.local});if(o.removed.length>0?(x(`${r} uninstalled`),R(" Removed from",o.removed.join(", "))):g(` ${r} not found`),o.errors.length>0)for(let i of o.errors)M(` Failed to remove: ${i}`)}console.log()});import{Command as Gp}from"commander";import kt from"chalk";var ps=new Gp("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)",b("--format",["table","json"]),"table").option("--limit <n>","Maximum templates to list","25").action(async(e,t)=>{await O();try{let n=Number.parseInt(t.limit??"25",10),{templates:r}=await co(e,Number.isFinite(n)?n:25);if(r.length===0){t.format==="json"?console.log(JSON.stringify([])):g("No templates found");return}if(t.format==="json"){console.log(JSON.stringify(r,null,2));return}for(let o of r){let i=[o.isDefault?kt.green("default"):null,o.category??null,o.recommendedModes?.length?`modes: ${o.recommendedModes.join("/")}`:null].filter(Boolean).join(" \xB7 ");console.log(`${kt.bold(o.name)} ${kt.gray(o.id)}${i?`
|
|
2701
2734
|
${kt.gray(i)}`:""}`)}console.log(),console.log(kt.gray(`Use one with: ${m.commands[0]} create "<topic>" --template <id>`))}catch(n){s(n instanceof Error?n.message:String(n)),process.exit(n.exitCode??1)}});import{Command as Bp}from"commander";import kr from"chalk";var gs=new Bp("whoami").description("Show current user and team information").option("-f, --format <format>","Output format (human, json)",b("--format",["human","json"]),"human").action(async e=>{await O();try{let t=await ye();if(Rn(),e.format==="json"){console.log(JSON.stringify(t,null,2));return}ie("User"),console.log(),R("Email",t.user.email),t.user.username&&R("Username",t.user.username),(t.user.firstName||t.user.lastName)&&R("Name",[t.user.firstName,t.user.lastName].filter(Boolean).join(" "));let n=t.authType==="apiKey"?"API Key":t.authType==="oauth"?"OAuth":"Session";if(R("Auth Type",n),t.currentTeam&&(console.log(),ie("Current Team"),console.log(),R("ID",t.currentTeam.id),R("Name",t.currentTeam.name),R("Plan",t.currentTeam.planName),R("Role",t.currentTeam.isOwner?"Owner":"Member")),t.teams.length>1){console.log(),ie("All Teams"),console.log();for(let r of t.teams){let o=r.isCurrent?kr.green(" (current)"):"";console.log(` ${kr.bold(r.name)}${o}`),console.log(kr.gray(` ID: ${r.id} | Plan: ${r.planName} | Role: ${r.role}`))}}console.log()}catch(t){s(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}});function fs(e){return e[0]==="--"?e.slice(1):e}import Cr from"chalk";function Ir(e){e.configureOutput({outputError:(t,n)=>{n(Cr.red(t));let r=/unknown option '(-{1,2}[^'\s=]+)/.exec(t);if(!r)return;let o=Kp(e,r[1]);o&&n(Cr.yellow(`Did you mean '${o}'?
|
|
2702
2735
|
`)),n(Cr.gray(`Run '${Wp(e)} --help' to see the accepted options.
|
|
2703
|
-
`))}});for(let t of e.commands)Ir(t)}function Wp(e){let t=[],n=e;for(;n;)t.unshift(n.name()),n=n.parent;return t.join(" ")}function Kp(e,t){let n,r=Number.POSITIVE_INFINITY;for(let i of e.options)if(!i.hidden)for(let a of[i.short,i.long]){if(!a)continue;let d=Rr(t,a);d<r&&(r=d,n=i.flags)}let o=t.startsWith("--")?2:1;return n!==void 0&&r<=o?n:void 0}function Rr(e,t){if(e===t)return 0;if(e.length===0)return t.length;if(t.length===0)return e.length;let n=Array.from({length:t.length+1},(r,o)=>o);for(let r=1;r<=e.length;r++){let o=[r];for(let i=1;i<=t.length;i++){let a=e[r-1]===t[i-1]?0:1;o[i]=Math.min(o[i-1]+1,n[i]+1,n[i-1]+a)}n=o}return n[t.length]}var zp="0.3.
|
|
2736
|
+
`))}});for(let t of e.commands)Ir(t)}function Wp(e){let t=[],n=e;for(;n;)t.unshift(n.name()),n=n.parent;return t.join(" ")}function Kp(e,t){let n,r=Number.POSITIVE_INFINITY;for(let i of e.options)if(!i.hidden)for(let a of[i.short,i.long]){if(!a)continue;let d=Rr(t,a);d<r&&(r=d,n=i.flags)}let o=t.startsWith("--")?2:1;return n!==void 0&&r<=o?n:void 0}function Rr(e,t){if(e===t)return 0;if(e.length===0)return t.length;if(t.length===0)return e.length;let n=Array.from({length:t.length+1},(r,o)=>o);for(let r=1;r<=e.length;r++){let o=[r];for(let i=1;i<=t.length;i++){let a=e[r-1]===t[i-1]?0:1;o[i]=Math.min(o[i-1]+1,n[i]+1,n[i-1]+a)}n=o}return n[t.length]}var zp="0.3.22",W=new Jp,N=m.commands[0];W.name(N).description(`${m.displayName} CLI \u2014 presentations, videos, avatars, audio, branding, media and research`).version(zp,"-v, --version","Show version number").option("--debug","Enable debug logging").option("--no-color","Disable colored output");W.addCommand(Mo);Ya(W);W.addCommand(ei);W.addCommand(Zo);W.addCommand(ps);W.addCommand(Yo);W.addCommand(Jo);W.addCommand(gs);W.addCommand(ii);W.addCommand(ai);W.addCommand(Ko);W.addCommand(rt);W.addCommand(Mt);var hs=Ho();hs.commands.length>0&&W.addCommand(hs);function Xp(e){let t=e.toLowerCase(),n=t.length<=4?1:2,r,o=Number.POSITIVE_INFINITY;for(let i of W.commands)for(let a of[i.name(),...i.aliases()]){let d=Rr(t,a.toLowerCase());d<o&&(o=d,r=i.name())}return r!==void 0&&o<=n?r:void 0}W.on("command:*",e=>{let t=String(e[0]);console.error(G.red(`Error: Unknown command '${t}'`)),console.error();let n=Xp(t);n&&console.error(`Did you mean '${n}'?`),console.error(`Run '${N} --help' to see available commands.`),console.error(`Run '${N} capabilities' for the full list of callable capabilities.`),process.exit(1)});W.addHelpText("after",`
|
|
2704
2737
|
${G.bold("Start here:")}
|
|
2705
2738
|
$ ${N} capabilities ${G.gray("# every capability + its exact command path")}
|
|
2706
2739
|
$ ${N} <group> --help ${G.gray("# drill into any command group above")}
|