#!/usr/bin/env node
function l(){let e=process.env.AUTOVIRAL_WORK_ID,t=Number(process.env.AUTOVIRAL_PORT??3271),r=process.env.AUTOVIRAL_CWD??process.cwd();return e||(process.stderr.write(`autoviral: AUTOVIRAL_WORK_ID env not set \u2014 are you running outside the Studio terminal?
`),process.exit(2)),{workId:e,port:t,cwd:r}}async function d(e,t,r,o){let s=`http://127.0.0.1:${e.port}/api/bridge/v1${r}`,n=await fetch(s,{method:t,headers:{"Content-Type":"application/json","X-AutoViral-Work-Id":e.workId},body:o==null?void 0:JSON.stringify(o)});if(!n.ok){let i=await n.text();process.stderr.write(`autoviral: bridge ${t} ${r} \u2192 ${n.status} ${i}
`);let c;try{let u=JSON.parse(i);typeof u.code=="number"&&(c=u.code)}catch{}process.exit(c??(n.status>=400&&n.status<500?4:3))}let a=await n.json();return a.ok||(process.stderr.write(`autoviral: ${a.error??"unknown error"}
`),process.exit(a.code??3)),a.result}async function O(e,t,r,o){let s=`http://127.0.0.1:${e.port}/api/works/${encodeURIComponent(e.workId)}${r}`,n=await fetch(s,{method:t,headers:o==null?void 0:{"Content-Type":"text/markdown; charset=utf-8"},body:o??void 0});if(!n.ok){let a=await n.text();process.stderr.write(`autoviral: api ${t} ${r} \u2192 ${n.status} ${a}
`),process.exit(n.status>=400&&n.status<500?4:3)}return n.text()}async function D(e,t,r,o){let s=`http://127.0.0.1:${e.port}/api/works/${encodeURIComponent(e.workId)}${r}`,n=await fetch(s,{method:t,headers:o==null?void 0:{"Content-Type":"application/json"},body:o==null?void 0:JSON.stringify(o)});if(!n.ok){let a=await n.text();process.stderr.write(`autoviral: api ${t} ${r} \u2192 ${n.status} ${a}
`),process.exit(n.status>=400&&n.status<500?4:3)}return await n.json()}import{stringify as U}from"yaml";function x(e){let t=e.indexOf("--format");if(t<0)return;let r=e[t+1];if(r==="json"||r==="yaml"||r==="table")return r}function h(e,t){let r=t??(process.stdout.isTTY?"yaml":"json");if(r==="json"){process.stdout.write(JSON.stringify(e)+`
`);return}if(r==="table"){process.stdout.write(_(e));return}if(typeof e=="string"||typeof e=="number"||typeof e=="boolean"){process.stdout.write(`${e}
`);return}process.stdout.write(U(e))}function _(e){if(!Array.isArray(e))return e&&typeof e=="object"?_([e]):U(e);if(e.length===0)return`(no rows)
`;let t=e.map(i=>i&&typeof i=="object"&&!Array.isArray(i)?i:{value:i}),r=[];for(let i of t)for(let c of Object.keys(i))r.includes(c)||r.push(c);let o=i=>i==null?"":typeof i=="object"?JSON.stringify(i):String(i),s=r.map(i=>Math.max(i.length,...t.map(c=>o(c[i]).length))),n=i=>i.map((c,u)=>c.padEnd(s[u])).join("  ").replace(/\s+$/,""),a=[];a.push(n(r)),a.push(n(s.map(i=>"-".repeat(i))));for(let i of t)a.push(n(r.map(c=>o(i[c]))));return a.join(`
`)+`
`}async function B(e){let t=l(),r=await d(t,"GET","/whoami");h(r)}import{readFile as Xe}from"fs/promises";import{parse as Ye}from"yaml";async function Qe(e){if(e==="-"){let t=[];for await(let r of process.stdin)t.push(Buffer.isBuffer(r)?r:Buffer.from(r));return Buffer.concat(t).toString("utf8")}return Xe(e,"utf8")}async function G(e){let t=e[0];if(t==="show"||t===void 0){let r=l(),o=await d(r,"GET","/comp");h(o,x(e));return}if(t==="diff"){let r=l(),o=await d(r,"GET","/comp/diff");if(!o.hasBaseline){process.stdout.write(`(no prior write to diff against \u2014 composition.yaml.previous has not been written yet)
`);return}if(o.diff===""){process.stdout.write(`(no changes since last write)
`);return}process.stdout.write(o.diff);return}if(t==="put"){let r=e[1],o=await V("put",r),s=l();await d(s,"PUT","/comp",o),process.stdout.write(`wrote composition from ${r==="-"?"stdin":r}
`);return}if(t==="validate"){let r=e[1],o=await V("validate",r),s=l(),n=await d(s,"POST","/comp/validate",o);e.includes("--json")?h(n):et(n),n.ok||(process.exitCode=4);return}if(t==="aspect"){let r=e[1];(!r||!M.includes(r))&&(process.stderr.write(`usage: autoviral comp aspect <${M.join("|")}>
`),process.exit(4));let o=l();await d(o,"POST","/comp/aspect",{ratio:r}),process.stdout.write(`switched aspect to ${r}
`);return}if(t==="set"){let r=Ze(e.slice(1),"--duration");r===void 0&&(process.stderr.write(`usage: autoviral comp set --duration <seconds|auto>
`),process.exit(4));let o;if(r==="auto")o={auto:!0};else{let a=Number(r);(!Number.isFinite(a)||a<0)&&(process.stderr.write(`autoviral comp set: --duration must be a finite, non-negative number or "auto" (got "${r}")
`),process.exit(4)),o={durationSec:a}}let s=l(),n=await d(s,"POST","/comp/duration",o);process.stdout.write(`set duration to ${n.duration}s
`),n.truncatesContent&&process.stderr.write(`\u26A0 duration ${n.duration}s is shorter than the content end ${n.contentEnd}s \u2014 clip content past ${n.duration}s will not render
`);return}process.stderr.write(`autoviral comp: unknown subcommand "${t}"
`),process.exit(127)}function Ze(e,t){let r=e.indexOf(t);if(r!==-1)return e[r+1]}var M=["9:16","1:1","16:9","4:5"];async function V(e,t){t||(process.stderr.write(`usage: autoviral comp ${e} <file|->
`),process.exit(4));let r;try{r=await Qe(t)}catch(s){process.stderr.write(`autoviral comp ${e}: cannot read ${t==="-"?"stdin":t}: ${s.message}
`),process.exit(4)}let o;try{o=Ye(r)}catch(s){process.stderr.write(`autoviral comp ${e}: ${t==="-"?"stdin":t} is not valid YAML/JSON: ${s.message}
`),process.exit(4)}return(o===null||typeof o!="object"||Array.isArray(o))&&(process.stderr.write(`autoviral comp ${e}: ${t==="-"?"stdin":t} did not parse to a composition object
`),process.exit(4)),o}function et(e){for(let t of e.errors)process.stderr.write(`\u2717 ${t}
`);for(let t of e.warnings)process.stdout.write(`\u26A0 ${t}
`);e.ok&&e.warnings.length===0?process.stdout.write(`ok \u2014 composition is valid (no errors, no warnings)
`):e.ok?process.stdout.write(`ok \u2014 composition is valid (${e.warnings.length} warning(s))
`):process.stderr.write(`invalid \u2014 ${e.errors.length} error(s), ${e.warnings.length} warning(s)
`)}async function H(e){let t=e[0],r=l(),o=x(e);if(t==="clips"){let s=e.indexOf("--track"),n=s>=0?e[s+1]:void 0,a=n?`?track=${encodeURIComponent(n)}`:"",i=await d(r,"GET",`/clips${a}`);h(i,o);return}if(t==="assets"){let s=e.indexOf("--kind"),n=s>=0?e[s+1]:void 0,a=n?`?kind=${encodeURIComponent(n)}`:"",i=await d(r,"GET",`/assets${a}`);h(i,o);return}process.stderr.write(`autoviral list: expected "clips" or "assets", got "${t??""}"
`),process.exit(127)}async function z(e){let t=l(),r=e[0],o=r?`?topic=${encodeURIComponent(r)}`:"",s=await fetch(`http://127.0.0.1:${t.port}/api/bridge/v1/docs${o}`,{headers:{"X-AutoViral-Work-Id":t.workId}});s.ok||(process.stderr.write(`autoviral docs: ${s.status}
`),process.exit(3)),process.stdout.write(await s.text())}async function J(e){let[t,r]=e;t||(process.stderr.write(`usage: autoviral select <clip|track|none> <id?>
`),process.exit(4));let o=l();if(t==="none"){await d(o,"POST","/select",{target:{kind:"none"}});return}t!=="clip"&&t!=="track"&&(process.stderr.write(`autoviral select: unknown kind "${t}"
`),process.exit(4)),r||(process.stderr.write(`autoviral select: missing id
`),process.exit(4)),await d(o,"POST","/select",{target:{kind:t,id:r}})}function I(e){if(/^[\d.]+$/.test(e))return parseFloat(e);let t=e.match(/^(?:(\d+)m)?(\d+(?:\.\d+)?)s$/);return t?Number(t[1]??0)*60+Number(t[2]):null}async function K(e){let t=e[0];t||(process.stderr.write(`usage: autoviral seek <seconds|'12.5s'|'1m30s'>
`),process.exit(4));let r=I(t);r===null&&(process.stderr.write(`autoviral seek: bad time format ${t}
`),process.exit(4));let o=l();await d(o,"POST","/seek",{seconds:r})}async function X(e){let t=l();await d(t,"POST","/play",{})}async function Y(e){let t=l();await d(t,"POST","/pause",{})}async function Q(e){let t=e[0];t||(process.stderr.write(`usage: autoviral toast <message> [--kind info|success|warn|error] [--duration 3000]
`),process.exit(4));let r=e.indexOf("--kind"),o=e.indexOf("--duration"),s=r>=0?e[r+1]:"info",n=o>=0?Number(e[o+1]):3e3,a=l();await d(a,"POST","/toast",{message:t,kind:s,durationMs:n})}async function Z(e){let[t,...r]=e,o=l();if(t==="start"){let s=r[0]??"";s||(process.stderr.write(`usage: autoviral progress start <label> [--steps N]
`),process.exit(4));let n=r.indexOf("--steps"),a=n>=0?Number(r[n+1]):void 0;await d(o,"POST","/progress",{phase:"start",label:s,steps:a});return}if(t==="step"){let s=Number(r[0]??"0");await d(o,"POST","/progress",{phase:"step",n:s});return}if(t==="done"){await d(o,"POST","/progress",{phase:"done"});return}process.stderr.write(`usage: autoviral progress start|step|done
`),process.exit(4)}async function ee(e){let[t,...r]=e,o=l();if(t==="add"){let s=k(r),n=s["--track"]??"video";n==="text"?s["--text"]||(process.stderr.write(`autoviral clip add --track text: --text required
`),process.exit(4)):s["--src"]||(process.stderr.write(`autoviral clip add: --src required
`),process.exit(4));let a={src:s["--src"],text:s["--text"],track:n,trackId:s["--track-id"]||void 0,offset:s["--offset"]?Number(s["--offset"]):0,duration:s["--duration"]?Number(s["--duration"]):void 0,in:s["--in"]?Number(s["--in"]):void 0,out:s["--out"]?Number(s["--out"]):void 0},i=await d(o,"POST","/clip",a);process.stdout.write(`${i.id}
`);return}if(t==="remove"){let s=r[0];s||(process.stderr.write(`usage: autoviral clip remove <id>
`),process.exit(4)),await d(o,"DELETE",`/clip/${encodeURIComponent(s)}`,void 0);return}if(t==="split"){let s=r[0];(!s||s.startsWith("--"))&&(process.stderr.write(`usage: autoviral clip split <id> --at <seconds>
`),process.exit(4));let a=k(r.slice(1))["--at"],i=a===void 0?NaN:Number(a);Number.isFinite(i)||(process.stderr.write(`autoviral clip split: --at <seconds> required
`),process.exit(4));let c=await d(o,"POST","/split",{clipId:s,at:i});process.stdout.write(`${c.id}
`);return}if(t==="trim"){let s=r[0];(!s||s.startsWith("--"))&&(process.stderr.write(`usage: autoviral clip trim <id> [--in <seconds>] [--out <seconds>]
`),process.exit(4));let n=k(r.slice(1)),a={};if(n["--in"]!==void 0){let i=Number(n["--in"]);Number.isFinite(i)||(process.stderr.write(`autoviral clip trim: --in <seconds> must be a number
`),process.exit(4)),a.in=i}if(n["--out"]!==void 0){let i=Number(n["--out"]);Number.isFinite(i)||(process.stderr.write(`autoviral clip trim: --out <seconds> must be a number
`),process.exit(4)),a.out=i}a.in===void 0&&a.out===void 0&&(process.stderr.write(`autoviral clip trim: at least one of --in / --out is required
`),process.exit(4)),await d(o,"POST",`/clip/${encodeURIComponent(s)}/trim`,a);return}if(t==="move"){let s=r[0];(!s||s.startsWith("--"))&&(process.stderr.write(`usage: autoviral clip move <id> --to-track <trackId>
`),process.exit(4));let a=k(r.slice(1))["--to-track"];a||(process.stderr.write(`autoviral clip move: --to-track <trackId> required
`),process.exit(4)),await d(o,"POST",`/clip/${encodeURIComponent(s)}/move`,{toTrackId:a});return}if(t==="keyframe"){let[s,n,...a]=r;s!=="add"&&s!=="set"&&(process.stderr.write(`usage: autoviral clip keyframe add|set <id> --property <p> --at <sec> --value <v> [--easing <e>]
`),process.exit(4)),(!n||n.startsWith("--"))&&(process.stderr.write(`usage: autoviral clip keyframe add|set <id> --property <p> --at <sec> --value <v> [--easing <e>]
`),process.exit(4));let i=k(a),c=i["--property"];c||(process.stderr.write(`autoviral clip keyframe: --property <name> required (opacity/scale/x/y/rotation/volume/speed)
`),process.exit(4));let u=i["--at"],f=u===void 0?NaN:Number(u);Number.isFinite(f)||(process.stderr.write(`autoviral clip keyframe: --at <seconds> required (number)
`),process.exit(4));let p=i["--value"],m=p===void 0?NaN:Number(p);Number.isFinite(m)||(process.stderr.write(`autoviral clip keyframe: --value <number> required
`),process.exit(4));let w={property:c,atSec:f,value:m};i["--easing"]!==void 0&&(w.easing=i["--easing"]),await d(o,"POST",`/clip/${encodeURIComponent(n)}/keyframe`,w);return}if(t==="set"){let s=r[0];s||(process.stderr.write(`usage: autoviral clip set <id> [--key value]...
`),process.exit(4));let n=k(r.slice(1)),a={};for(let[i,c]of Object.entries(n)){let u=i.replace(/^--/,""),f=tt[u]??u,p=rt.has(f)?c:st(c);if(f==="transforms.crop"){let m=p,w=["x","y","w","h"];m!=null&&typeof m=="object"&&!Array.isArray(m)&&w.every(Ke=>typeof m[Ke]=="number")||(process.stderr.write(`autoviral clip set --crop: crop \u9700\u540C\u65F6\u7ED9\u51FA x, y, w, h \u56DB\u4E2A\u6570\u503C (\u4F8B: --crop '{"x":0,"y":0,"w":0.5,"h":1}')
`),process.exit(4))}te(a,f,p)}await d(o,"PATCH",`/clip/${encodeURIComponent(s)}`,a);return}process.stderr.write(`autoviral clip: unknown subcommand "${t??""}"
`),process.exit(127)}var tt={scale:"transforms.scale",x:"transforms.x",y:"transforms.y",rotation:"transforms.rotation",crop:"transforms.crop","flip-h":"transforms.flipH","flip-v":"transforms.flipV","freeze-at":"freezeAtSec",reverse:"reverse",lut:"filters.lut",brightness:"filters.brightness",contrast:"filters.contrast",saturation:"filters.saturation","fit-mode":"fitMode","fade-in":"fadeIn","fade-out":"fadeOut",font:"style.font",size:"style.size",weight:"style.weight",italic:"style.italic",tracking:"style.tracking",color:"style.color",anchor:"position.anchor"},rt=new Set(["src","text","type","filters.lut","fitMode","style.font","style.color","style.stroke.color","position.anchor","animation"]);function st(e){if(e===void 0)return e;if(e==="true")return!0;if(e==="false")return!1;if(/^-?(?:\d+\.?\d*|\.\d+)$/.test(e))return Number(e);if(/^[[{]/.test(e))try{return JSON.parse(e)}catch{}return e}function te(e,t,r){if(nt(r)){for(let[o,s]of Object.entries(r))te(e,`${t}.${o}`,s);return}e[t]=r}function nt(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)&&Object.getPrototypeOf(e)===Object.prototype}function k(e){let t={};for(let r=0;r<e.length;r++){let o=e[r];o.startsWith("--")&&(t[o]=e[r+1],r++)}return t}var re=["video","audio","text","overlay"];async function se(e){let[t,...r]=e,o=l();if(t==="add"){let s=ot(r),n=s["--kind"];(!n||!re.includes(n))&&(process.stderr.write(`autoviral track add: --kind <${re.join("|")}> required
`),process.exit(4));let a={kind:n};s["--after"]&&(a.afterTrackId=s["--after"]),s["--label"]&&(a.label=s["--label"]),s["--language"]&&(a.language=s["--language"]);let i=await d(o,"POST","/track",a);process.stdout.write(`${i.trackId}
`);return}if(t==="remove"){let s=r[0];(!s||s.startsWith("--"))&&(process.stderr.write(`usage: autoviral track remove <trackId>
`),process.exit(4)),await d(o,"DELETE",`/track/${encodeURIComponent(s)}`,void 0);return}process.stderr.write(`autoviral track: unknown subcommand "${t??""}"
`),process.exit(127)}function ot(e){let t={};for(let r=0;r<e.length;r++){let o=e[r];o.startsWith("--")&&(t[o]=e[r+1],r++)}return t}var ne=["hook","build","payoff","cta"],oe=["long","full","medium","close","closeup"],ie=["push","pull","pan","track","follow","static"],it=["planned","generated","stale"];async function ae(e){let[t,...r]=e,o=l();if(t==="add"){let s=R(r),n=s["--title"];n||(process.stderr.write(`autoviral scene add: --title <text> required
`),process.exit(4));let a=y(s,"--intent",ne,"scene add"),i=y(s,"--shot-size",oe,"scene add"),c=y(s,"--camera",ie,"scene add"),u={title:n};if(a&&(u.intent=a),s["--prompt"]&&(u.prompt=s["--prompt"]),s["--narration"]&&(u.narration=s["--narration"]),s["--duration"]!==void 0){let p=Number(s["--duration"]);Number.isFinite(p)||(process.stderr.write(`autoviral scene add: --duration <seconds> must be a number
`),process.exit(4)),u.durationSec=p}i&&(u.shotSize=i),c&&(u.cameraMovement=c),s["--md-anchor"]&&(u.mdAnchor=s["--md-anchor"]);let f=await d(o,"POST","/scene",u);process.stdout.write(`${f.sceneId}
`);return}if(t==="list"){let n=[...(await d(o,"GET","/comp")).scenes??[]].sort((i,c)=>i.order-c.order),a=x(e);if(a){h(n.map(i=>({order:i.order,id:i.id,title:i.title,intent:i.intent??null,status:i.status??"planned"})),a);return}for(let i of n){let c=i.intent??"-",u=i.status??"planned";process.stdout.write(`${i.order}	${i.id}	${i.title}	${c}	${u}
`)}return}if(t==="set"){let s=r[0];(!s||s.startsWith("--"))&&(process.stderr.write(`usage: autoviral scene set <id> [--key value]...
`),process.exit(4));let n=R(r.slice(1)),a=y(n,"--intent",ne,"scene set"),i=y(n,"--shot-size",oe,"scene set"),c=y(n,"--camera",ie,"scene set"),u={};if(n["--title"]!==void 0&&(u.title=n["--title"]),a&&(u.intent=a),n["--prompt"]!==void 0&&(u.prompt=n["--prompt"]),n["--narration"]!==void 0&&(u.narration=n["--narration"]),n["--duration"]!==void 0){let f=Number(n["--duration"]);Number.isFinite(f)||(process.stderr.write(`autoviral scene set: --duration <seconds> must be a number
`),process.exit(4)),u.durationSec=f}i&&(u.shotSize=i),c&&(u.cameraMovement=c),n["--md-anchor"]!==void 0&&(u.mdAnchor=n["--md-anchor"]),await d(o,"PATCH",`/scene/${encodeURIComponent(s)}`,u);return}if(t==="reorder"){let s=r.filter(n=>!n.startsWith("--"));s.length===0&&(process.stderr.write(`usage: autoviral scene reorder <sceneId> [<sceneId>...]
`),process.exit(4)),await d(o,"POST","/scene/reorder",{orderedSceneIds:s});return}if(t==="link"){let s=r[0];(!s||s.startsWith("--"))&&(process.stderr.write(`usage: autoviral scene link <id> --asset <assetId> [--asset <id2>...] [--select <id>] [--status planned|generated|stale]
`),process.exit(4));let n=r.slice(1),a=at(n,"--asset");a.length===0&&(process.stderr.write(`autoviral scene link: at least one --asset <assetId> required
`),process.exit(4));let i=R(n),c=y(i,"--status",it,"scene link"),u={assetIds:a};i["--select"]&&(u.selectedAssetId=i["--select"]),c&&(u.status=c),await d(o,"POST",`/scene/${encodeURIComponent(s)}/link`,u);return}if(t==="generate"){let s=r[0];(!s||s.startsWith("--"))&&(process.stderr.write(`usage: autoviral scene generate <id> [--provider <name>]
`),process.exit(4));let n=R(r.slice(1)),a={};n["--provider"]&&(a.provider=n["--provider"]);let i=await d(o,"POST",`/scene/${encodeURIComponent(s)}/generate`,a);process.stdout.write(`${i.assetId}
`);return}if(t==="remove"){let s=r[0];(!s||s.startsWith("--"))&&(process.stderr.write(`usage: autoviral scene remove <id>
`),process.exit(4)),await d(o,"DELETE",`/scene/${encodeURIComponent(s)}`,void 0);return}process.stderr.write(`autoviral scene: unknown subcommand "${t??""}"
`),process.exit(127)}function y(e,t,r,o){let s=e[t];if(s!==void 0)return r.includes(s)||(process.stderr.write(`autoviral ${o}: ${t} must be one of <${r.join("|")}>
`),process.exit(4)),s}function at(e,t){let r=[];for(let o=0;o<e.length;o++)if(e[o]===t){let s=e[o+1];s!==void 0&&!s.startsWith("--")&&(r.push(s),o++)}return r}function R(e){let t={};for(let r=0;r<e.length;r++){let o=e[r];o.startsWith("--")&&(t[o]=e[r+1],r++)}return t}import{readFile as ct}from"fs/promises";var ce="/plan/script.md";async function dt(e){if(e)return ct(e,"utf8");let t=[];for await(let r of process.stdin)t.push(Buffer.isBuffer(r)?r:Buffer.from(r));return Buffer.concat(t).toString("utf8")}function ut(e){let t=e.indexOf("--file");if(t===-1)return;let r=e[t+1];return r||(process.stderr.write(`autoviral script edit: --file requires a path
`),process.exit(4)),r}async function de(e){let t=e[0];if(t==="show"||t===void 0){let r=l(),o=await O(r,"GET",ce);process.stdout.write(o);return}if(t==="edit"){let r=ut(e.slice(1)),o;try{o=await dt(r)}catch(n){process.stderr.write(`autoviral script edit: cannot read ${r??"stdin"}: ${n.message}
`),process.exit(4)}let s=l();await O(s,"PUT",ce,o),process.stdout.write(`wrote script from ${r??"stdin"}
`);return}process.stderr.write(`autoviral script: unknown subcommand "${t}"
`),process.exit(127)}async function ue(e){let[t,...r]=e,o=l();if(t==="add"){let s=lt(r),n=s["--track"],a=s["--after"],i=s["--preset"];n||(process.stderr.write(`autoviral transition add: --track <trackId> required
`),process.exit(4)),a||(process.stderr.write(`autoviral transition add: --after <clipId> required
`),process.exit(4)),i||(process.stderr.write(`autoviral transition add: --preset <name> required
`),process.exit(4));let c={trackId:n,afterClipId:a,preset:i};if(s["--duration"]!==void 0){let f=Number(s["--duration"]);Number.isFinite(f)||(process.stderr.write(`autoviral transition add: --duration <seconds> must be a number
`),process.exit(4)),c.durationSec=f}let u=await d(o,"POST","/transition",c);process.stdout.write(`${u.id}
`);return}if(t==="remove"){let s=r[0];(!s||s.startsWith("--"))&&(process.stderr.write(`usage: autoviral transition remove <id>
`),process.exit(4)),await d(o,"DELETE",`/transition/${encodeURIComponent(s)}`,void 0);return}process.stderr.write(`autoviral transition: unknown subcommand "${t??""}"
`),process.exit(127)}function lt(e){let t={};for(let r=0;r<e.length;r++){let o=e[r];o.startsWith("--")&&(t[o]=e[r+1],r++)}return t}async function le(e){let[t,...r]=e,o=l();if(t==="generate"){let s=pt(r),n={};s["--language"]&&(n.language=s["--language"]),s["--asset"]&&(n.assetPath=s["--asset"]),s["--track-id"]&&(n.trackId=s["--track-id"]);let a=await d(o,"POST","/captions/generate",n);a.written===0&&a.message&&process.stderr.write(`autoviral: ${a.message}
`),process.stdout.write(`${a.written}
`);return}process.stderr.write(`autoviral captions: unknown subcommand "${t??""}"
`),process.exit(127)}function pt(e){let t={};for(let r=0;r<e.length;r++){let o=e[r];o.startsWith("--")&&(t[o]=e[r+1],r++)}return t}async function fe(e){let[t,...r]=e,o=l();if(t==="add-slide"){let s=pe(r),n={};s["--at"]!==void 0&&(n.at=Number(s["--at"]));let a=s["--bg-type"];a!==void 0&&(s["--bg-value"]===void 0&&(process.stderr.write(`autoviral carousel add-slide: --bg-type requires --bg-value
`),process.exit(4)),n.bg={type:a,value:s["--bg-value"]});let i=await d(o,"POST","/carousel/slide",n);process.stdout.write(`${i.id}
`);return}if(t==="set-layer"){let s=r[0];s||(process.stderr.write(`usage: autoviral carousel set-layer <slideId> --kind <text|image|shape|sticker> [flags]
`),process.exit(4));let n=pe(r.slice(1)),a=n["--kind"];a||(process.stderr.write(`autoviral carousel set-layer: --kind required (text|image|shape|sticker)
`),process.exit(4));let i=n["--id"]!==void 0&&n["--id"]!=="",c={};n["--x"]!==void 0&&(c.x=Number(n["--x"])),n["--y"]!==void 0&&(c.y=Number(n["--y"])),n["--w"]!==void 0&&(c.w=Number(n["--w"])),n["--h"]!==void 0&&(c.h=Number(n["--h"])),n["--rotation"]!==void 0&&(c.rotation=Number(n["--rotation"])),i||(c.x===void 0&&(c.x=80),c.y===void 0&&(c.y=80),c.w===void 0&&(c.w=920),c.h===void 0&&(c.h=200));let u={kind:a};if(i&&(u.id=n["--id"]),Object.keys(c).length>0&&(u.box=c),a==="text"){n["--text"]===void 0&&!i&&(process.stderr.write(`autoviral carousel set-layer --kind text: --text required
`),process.exit(4)),n["--text"]!==void 0&&(u.text=n["--text"]);let p={};n["--font"]!==void 0&&(p.font=n["--font"]),n["--size"]!==void 0&&(p.size=Number(n["--size"])),n["--weight"]!==void 0&&(p.weight=Number(n["--weight"])),n["--italic"]!==void 0&&(p.italic=ft(n["--italic"])),n["--color"]!==void 0&&(p.color=n["--color"]),n["--align"]!==void 0&&(p.align=n["--align"]),n["--tracking"]!==void 0&&(p.tracking=Number(n["--tracking"])),Object.keys(p).length>0&&(u.style=p)}else a==="image"||a==="sticker"?(n["--src"]===void 0&&!i&&(process.stderr.write(`autoviral carousel set-layer --kind ${a}: --src required
`),process.exit(4)),n["--src"]!==void 0&&(u.src=n["--src"])):a==="shape"&&(n["--shape"]===void 0&&!i&&(process.stderr.write(`autoviral carousel set-layer --kind shape: --shape required (rect|circle|line)
`),process.exit(4)),n["--shape"]!==void 0&&(u.shape=n["--shape"]),n["--fill"]!==void 0&&(u.fill=n["--fill"]),n["--stroke"]!==void 0&&(u.stroke=n["--stroke"]),n["--stroke-width"]!==void 0&&(u.strokeWidth=Number(n["--stroke-width"])));let f=await d(o,"POST",`/carousel/slide/${encodeURIComponent(s)}/layer`,u);process.stdout.write(`${f.id}
`);return}process.stderr.write(`autoviral carousel: unknown subcommand "${t??""}"
`),process.exit(127)}function ft(e){return e===void 0?!0:!["false","0","no","off"].includes(e.toLowerCase())}function pe(e){let t={};for(let r=0;r<e.length;r++){let o=e[r];o.startsWith("--")&&(t[o]=e[r+1],r++)}return t}async function me(e){let t=e[0];t||(process.stderr.write(`usage: autoviral ask <message> [--yes-no|--ok-cancel] [--timeout seconds]
`),process.exit(4));let r=e.includes("--yes-no"),s=e.includes("--ok-cancel")?"ok-cancel":"yes-no",n=e.indexOf("--timeout"),i=(n>=0?Number(e[n+1]):1800)*1e3,c=l(),u=`http://127.0.0.1:${c.port}/api/bridge/v1/ask`,f=await fetch(u,{method:"POST",headers:{"Content-Type":"application/json","X-AutoViral-Work-Id":c.workId},body:JSON.stringify({message:t,kind:s,timeoutMs:i})});if(f.status===504&&(process.stderr.write(`autoviral ask: timeout
`),process.exit(124)),!f.ok){let m=await f.text();process.stderr.write(`autoviral ask: ${f.status} ${m}
`),process.exit(3)}let p=await f.json();(!p.ok||!p.result)&&(process.stderr.write(`autoviral ask: ${p.error??"unknown error"}
`),process.exit(3)),process.stdout.write(`${p.result.answer}
`),process.exit(p.result.answer==="yes"?0:p.result.answer==="no"?1:2)}import{readFile as mt,stat as we,readdir as gt}from"fs/promises";import{basename as ht,extname as wt,join as bt}from"path";function vt(e){let t={proxy:!1,strictVariables:!1,continueOnError:!1};for(let r=0;r<e.length;r++){let o=e[r];if(o==="--proxy")t.proxy=!0;else if(o==="--preset")t.preset=e[++r];else if(o==="--variables"){let s=e[++r];try{t.variables=JSON.parse(s)}catch(n){process.stderr.write(`autoviral: --variables must be a JSON object \u2014 ${n.message}
`),process.exit(4)}}else o==="--variables-file"?t.variablesFile=e[++r]:o==="--strict-variables"?t.strictVariables=!0:o==="--continue-on-error"?t.continueOnError=!0:o.startsWith("--")&&(process.stderr.write(`autoviral: unknown flag ${o}
`),process.exit(4))}return t}async function ge(e,t){return d(e,"POST","/export",t)}async function xt(e){try{return(await we(e)).isFile()}catch{return!1}}async function yt(e){try{return(await we(e)).isDirectory()}catch{return!1}}async function he(e){let t=await mt(e,"utf-8"),r=JSON.parse(t);if(!r||typeof r!="object"||Array.isArray(r))throw new Error("variables file must contain a JSON object");return r}async function F(e){let t=vt(e),r=l();if(t.variablesFile&&await yt(t.variablesFile)){let n=(await gt(t.variablesFile)).filter(c=>c.toLowerCase().endsWith(".json")).sort();n.length===0&&(process.stderr.write(`autoviral: no *.json files in ${t.variablesFile}
`),process.exit(4));let a=0,i=0;for(let c of n){let u=bt(t.variablesFile,c),f=ht(c,wt(c));try{let p=await he(u),m=await ge(r,{preset:t.preset,proxy:t.proxy,variables:p,strictVariables:t.strictVariables,variantStem:f});process.stdout.write(`${c}	${m.path}	ok
`),a+=1}catch(p){let m=p instanceof Error?p.message:String(p);if(process.stderr.write(`${c}	ERROR	${m}
`),i+=1,!t.continueOnError){process.exitCode=5;return}}}process.stdout.write(`
autoviral batch: ${a}/${n.length} succeeded
`),i>0&&(process.exitCode=5);return}let o=t.variables;t.variablesFile&&(await xt(t.variablesFile)||(process.stderr.write(`autoviral: --variables-file path not found: ${t.variablesFile}
`),process.exit(4)),o=await he(t.variablesFile));let s=await ge(r,{preset:t.preset,proxy:t.proxy,variables:o,strictVariables:t.strictVariables});process.stdout.write(`${s.path}
`)}async function be(e){return F([...e,"--proxy"])}function kt(e){let t={};for(let r=0;r<e.length;r++){let o=e[r];if(o==="--at"){let s=e[++r];s===void 0&&(process.stderr.write(`autoviral snapshot: --at needs a time value
`),process.exit(4));let n=I(s);n===null&&(process.stderr.write(`autoviral snapshot: bad --at time format ${s} (use seconds|'12.5s'|'1m30s')
`),process.exit(4)),t.at=n}else o==="--slide"?(t.slide=e[++r],t.slide===void 0&&(process.stderr.write(`autoviral snapshot: --slide needs a slide id
`),process.exit(4))):o.startsWith("--")&&(process.stderr.write(`autoviral: unknown flag ${o}
`),process.exit(4))}return t}async function ve(e){let t=kt(e),r=l(),o={};t.at!==void 0&&(o.at=t.at),t.slide!==void 0&&(o.slide=t.slide);let s=await d(r,"POST","/snapshot",o);process.stdout.write(`${s.path}
`),s.textLayersComposited===!1&&process.stderr.write(`\u26A0 carousel snapshot shows the slide background only; text/sticker layers are NOT composited (no headless carousel renderer yet) \u2014 do not infer text layout/overflow from this image.
`)}async function xe(e){let[t,...r]=e,o=l();if(t==="create"){let s=$t(r),i=(await D(o,"POST","/checkpoints",s===void 0?void 0:{label:s})).written??[];if(i.length===0){process.stderr.write(`checkpoint create: no change since the last snapshot \u2014 nothing written (the existing checkpoint stands).
`);return}for(let c of i)process.stdout.write(`${c.file}
`);s&&process.stderr.write(`\u21B3 labelled "${s}"
`);return}if(t==="list"){let s=await d(o,"GET","/checkpoints");h(s,x(e));return}if(t==="restore"){let s=r[0];s||(process.stderr.write("usage: autoviral checkpoint restore <id>  (id = a `file` from `checkpoint list`)\n"),process.exit(4));let n=await d(o,"POST","/restore",{file:s});process.stdout.write(`restored ${n.deliverable} from ${s}
`),n.preRestoreSnapshot&&process.stderr.write(`\u21A9 current state was checkpointed first (${n.preRestoreSnapshot.sha}) \u2014 this restore is reversible.
`);return}process.stderr.write(`autoviral checkpoint: expected "create", "list" or "restore", got "${t??""}"
`),process.exit(127)}function $t(e){let t=e.indexOf("--label");if(t<0)return;let r=e[t+1];return(r===void 0||r.startsWith("--"))&&(process.stderr.write(`usage: autoviral checkpoint create [--label <text>]
`),process.exit(4)),r}async function ye(e){let[t,...r]=e;t!=="youtube"&&(process.stderr.write(`autoviral: ingest subcommand must be 'youtube' (got ${t??"nothing"})
`),process.exit(127)),await Ct(r)}async function Ct(e){let t=Pt(e);t.url||(process.stderr.write(`autoviral: ingest youtube <url> [--lang zh-CN] [--model <openrouter-id>] [--start <s>] [--end <s>]
`),process.exit(4));let r=l(),o=await d(r,"POST","/ingest/youtube",{url:t.url,language:t.lang??"zh-CN",model:t.model,start:t.start,end:t.end});process.stdout.write(`${o.sourceClipPath}
duration ${o.durationSec.toFixed(2)}s \xB7 ${o.segmentCount} segments \xB7 ${o.language} \u2192 ${o.targetLanguage}
`)}function Pt(e){let t={};for(let r=0;r<e.length;r++){let o=e[r];o==="--lang"?t.lang=e[++r]:o==="--model"?t.model=e[++r]:o==="--start"?t.start=Number(e[++r]):o==="--end"?t.end=Number(e[++r]):o.startsWith("--")?(process.stderr.write(`autoviral: unknown flag ${o}
`),process.exit(4)):t.url||(t.url=o)}return t}function Rt(e){let t={};for(let r=0;r<e.length;r++){let o=e[r];o==="--voice"?t.voice=e[++r]:o==="--format"?t.format=e[++r]:o==="--model"?t.model=e[++r]:o==="--stem"||o==="--filename-stem"?t.stem=e[++r]:o.startsWith("--")?(process.stderr.write(`autoviral: unknown flag ${o}
`),process.exit(4)):t.text||(t.text=o)}return t}async function ke(e){let[t,...r]=e;if(t==="tts")return Tt(r);process.stderr.write(`autoviral: unknown preprocess subcommand ${t??"<none>"}
`),process.exit(127)}async function Tt(e){let t=Rt(e);t.text||(process.stderr.write(`autoviral: preprocess tts <text> [--voice alloy|echo|fable|onyx|nova|shimmer] [--format mp3|wav|opus|aac|flac] [--stem <name>]
`),process.exit(4));let r=l(),o=await d(r,"POST","/preprocess/tts",{text:t.text,voice:t.voice,format:t.format,model:t.model,filenameStem:t.stem});process.stdout.write(`${o.relativeUri}
voice ${o.voice} \xB7 ${o.format} \xB7 ${o.bytes} bytes
`)}function St(e){let t={watch:!1};for(let r=0;r<e.length;r++){let o=e[r];if(o==="--watch")t.watch=!0;else if(o==="--inject"){let s=e[++r];s!=="on"&&s!=="off"&&(process.stderr.write(`autoviral: --inject expects "on" or "off" (got ${s??"<none>"})
`),process.exit(4)),t.inject=s}else o.startsWith("--")&&(process.stderr.write(`autoviral: unknown flag ${o}
`),process.exit(4))}return t}async function $e(e){let t=St(e),r=l();if(t.inject){let s=t.inject==="on",n=await d(r,"POST","/context/inject",{enabled:s});process.stdout.write(`inject ${n.enabled?"on":"off"}
`);return}if(t.watch){await Ot(r);return}let o=await d(r,"GET","/context",null);process.stdout.write(`${JSON.stringify(o,null,2)}
`)}async function Ot(e){let t=`http://localhost:${e.port}/api/bridge/v1/context/stream`,r=new AbortController,o=()=>{r.abort()};process.on("SIGINT",o),process.on("SIGTERM",o);try{let s=await fetch(t,{headers:{"X-AutoViral-Work-Id":e.workId},signal:r.signal});(!s.ok||!s.body)&&(process.stderr.write(`autoviral: context stream returned ${s.status} ${s.statusText}
`),process.exit(3));let n=s.body.getReader(),a=new TextDecoder,i="";for(;;){let{value:c,done:u}=await n.read();if(u)break;i+=a.decode(c,{stream:!0});let f;for(;(f=i.indexOf(`

`))!==-1;){let p=i.slice(0,f);i=i.slice(f+2);let m=p.split(`
`).find(w=>w.startsWith("data: "));m&&process.stdout.write(`${m.slice(6)}
`)}}}catch(s){if(s.name==="AbortError")return;throw s}finally{process.off("SIGINT",o),process.off("SIGTERM",o)}}async function Ce(e){let t,r;for(let a=0;a<e.length;a++){let i=e[a];i==="--platform"?t=e[++a]:i==="--topic"?r=e[++a]:i.startsWith("--")&&(process.stderr.write(`autoviral: unknown flag ${i}
`),process.exit(4))}let o=l(),s=[];t&&s.push(`platform=${encodeURIComponent(t)}`),r&&s.push(`topic=${encodeURIComponent(r)}`);let n=await d(o,"GET",`/trends${s.length>0?`?${s.join("&")}`:""}`,null);process.stdout.write(`${JSON.stringify(n,null,2)}
`)}async function Pe(e){let t=l(),r=await d(t,"GET","/profile",null);process.stdout.write(`${JSON.stringify(r,null,2)}
`)}import{existsSync as v,readdirSync as Oe}from"fs";import{copyFile as It,mkdir as Ft,chmod as Nt}from"fs/promises";import{spawn as Et}from"child_process";import{createRequire as At}from"module";import{homedir as T}from"os";import{delimiter as Ie,dirname as Lt,join as g}from"path";import{fileURLToPath as jt}from"url";var N=At(import.meta.url);function E(){return process.env.AUTOVIRAL_DATA_DIR??g(T(),".autoviral")}function Fe(e){return process.platform==="win32"?`${e}.exe`:e}function Re(e){return g(E(),"bin",Fe(e))}function qt(e){let t=e==="ffmpeg"?process.env.FFMPEG_PATH:process.env.FFPROBE_PATH;return t&&t.trim()?t:void 0}function Ne(e){try{if(e==="ffmpeg"){let r=N("ffmpeg-static");return r&&typeof r=="string"?r:null}let t=N("@ffprobe-installer/ffprobe");return t&&typeof t.path=="string"?t.path:null}catch{return null}}function Wt(e){let t=process.env.PATH??"",r=process.platform==="win32"?(process.env.PATHEXT??".EXE;.CMD;.BAT").split(";"):[""];for(let o of t.split(Ie))if(o){for(let s of r)if(v(g(o,`${e}${s}`)))return!0}return!1}function Dt(e){let{name:t,override:r,managedPath:o,managedExists:s,vendoredPath:n}=e,a,i;r&&r.trim()?(a=r,i="env"):s?(a=o,i="managed"):n?(a=n,i="vendored"):(a=t,i="path");let c=i==="path"?e.onPath:!0;return{name:t,path:a,source:i,managedPath:o,managedExists:s,vendoredPath:n,onPath:c,ok:i!=="path"||c}}function Te(e){return Dt({name:e,override:qt(e),managedPath:Re(e),managedExists:v(Re(e)),vendoredPath:Ne(e),onPath:Wt(e)})}function Ee(){return{ffmpeg:Te("ffmpeg"),ffprobe:Te("ffprobe")}}function $(){return g(E(),"tts-venv")}function Ut(e){return process.platform==="win32"?g($(),"Scripts",`${e}.exe`):g($(),"bin",e)}function _t(){let e=$();if(process.platform==="win32")return v(g(e,"Lib","site-packages","stable_whisper"));let t=g(e,"lib"),r;try{r=Oe(t)}catch{return!1}for(let o of r)if(o.startsWith("python")&&v(g(t,o,"site-packages","stable_whisper")))return!0;return!1}function A(){let e=v(Ut("edge-tts")),t=_t();return{edgeTts:e,stableTs:t,ready:e&&t,venvDir:$()}}function Bt(){let e=process.env.PLAYWRIGHT_BROWSERS_PATH;if(e&&e.trim())return e;if(process.platform==="win32"){let r=process.env.LOCALAPPDATA??g(T(),"AppData","Local");return g(r,"ms-playwright")}if(process.platform==="darwin")return g(T(),"Library","Caches","ms-playwright");let t=process.env.XDG_CACHE_HOME;return g(t&&t.trim()?t:g(T(),".cache"),"ms-playwright")}function L(){let e=Bt(),t=!1;try{t=Oe(e).some(r=>r.startsWith("chromium"))}catch{t=!1}return{cached:t,cacheDir:e}}function Ae(){let e=process.env.PATH??"",t=process.platform==="win32"?(process.env.PATHEXT??".EXE;.CMD;.BAT").split(";"):[""];for(let r of e.split(Ie))if(r)for(let o of t){let s=g(r,`claude${o}`);if(v(s))return{path:s,present:!0}}return{path:null,present:!1}}function Le(e){let t=e?.bundleEnv!==void 0?e.bundleEnv:process.env.AUTOVIRAL_REMOTION_BUNDLE,r=e?.existsSyncFn??v,o=e?.repoRoot??g(Mt(),"..","..","..");if(t&&t.trim()&&r(t.trim()))return{ready:!0,via:"bundle",path:t.trim()};let s=g(o,"web","src","features","studio","composition","RemotionRoot.tsx");return r(s)?{ready:!0,via:"source",path:s}:{ready:!1,via:null,path:s}}function Mt(){return Lt(jt(import.meta.url))}var je=(e,t,r)=>new Promise((o,s)=>{let{onLine:n,...a}=r??{},i=Et(e,t,{...a}),c="",u="";i.stdout?.on("data",f=>{let p=f.toString();c+=p,n?.(p.trimEnd())}),i.stderr?.on("data",f=>{let p=f.toString();u+=p,n?.(p.trimEnd())}),i.on("error",s),i.on("close",f=>o({code:f,stdout:c,stderr:u}))});async function qe(e,t={}){let r=t.vendoredPathFor??Ne,o=t.copyFileFn??It,s=t.mkdirFn??Ft,n=t.chmodFn??Nt,a=t.existsSyncFn??v,i=g(E(),"bin");try{await s(i,{recursive:!0})}catch(p){return{status:"failed",detail:`could not create ${i}: ${Se(p)}`}}let c=0,u=0,f=0;for(let p of["ffmpeg","ffprobe"]){let m=g(i,Fe(p));if(a(m)){u++,e(`  ${p}: already managed (${m})`);continue}let w=r(p);if(!w||!a(w)){f++,e(`  ${p}: no vendored binary to copy (falls back to PATH at runtime)`);continue}try{e(`  ${p}: copying vendored binary \u2192 ${m} \u2026`),await o(w,m),process.platform!=="win32"&&await n(m,493),c++,e(`  ${p}: installed.`)}catch(W){e(`  ${p}: copy failed (${Se(W)}) \u2014 runtime falls back to vendored path`)}}return c>0?{status:"installed",detail:`${c} binary(ies) copied to ${i}`}:u===2?{status:"already",detail:`ffmpeg + ffprobe already managed in ${i}`}:f>0?{status:"skipped",detail:"no vendored ffmpeg/ffprobe available; runtime resolves via PATH"}:{status:"already",detail:`nothing to do (${i})`}}async function We(e,t=je){if(A().ready)return{status:"already",detail:"edge-tts + stable-ts already installed"};e("  probing python3 \u2026");let r=!1;try{r=(await t("python3",["--version"])).code===0}catch{r=!1}if(!r)return{status:"failed",detail:"python3 not found \u2014 install Python 3 (e.g. `brew install python` on macOS) then re-run `autoviral setup`"};let o=$(),s=process.platform==="win32"?g(o,"Scripts","python.exe"):g(o,"bin","python3");if(!v(s)){e(`  creating venv at ${o} \u2026`);let a=await t("python3",["-m","venv",o],{onLine:i=>e(`    ${i}`)});if(a.code!==0)return{status:"failed",detail:`python3 -m venv exited ${a.code}: ${a.stderr.slice(0,200)}`}}e("  pip install --upgrade edge-tts stable-ts (this can take a minute) \u2026");let n=await t(s,["-m","pip","install","--upgrade","edge-tts","stable-ts"],{onLine:a=>e(`    ${a}`)});return n.code!==0?{status:"failed",detail:`pip exited ${n.code}: ${n.stderr.slice(0,200)}`}:{status:"installed",detail:`edge-tts + stable-ts installed into ${o}`}}async function De(e,t=je){if(L().cached)return{status:"already",detail:"chromium already cached"};let r=Vt();e("  downloading chromium (~150MB) \u2026");let o=r?await t(process.execPath,[r,"install","chromium"],{onLine:s=>e(`    ${s}`)}):await t("npx",["playwright","install","chromium"],{onLine:s=>e(`    ${s}`)});return o.code!==0?{status:"failed",detail:`playwright install chromium exited ${o.code}: ${o.stderr.slice(0,200)}`}:{status:"installed",detail:"chromium installed"}}function Vt(){for(let e of["playwright/cli.js","@playwright/test/cli.js"])try{return N.resolve(e)}catch{}return null}function Se(e){return e instanceof Error?e.message:String(e)}var C="\u2713",Ue="\u2717",j="\u25CB";function Gt(e,t){switch(e){case"env":return"env override (FFMPEG_PATH/FFPROBE_PATH)";case"managed":return"managed (~/.autoviral/bin)";case"vendored":return"vendored (ffmpeg-static)";case"path":return t?"system PATH":"NOT FOUND on PATH"}}async function _e(e){let t=Ee(),r=A(),o=L(),s=Ae(),n=[],a=!1;for(let c of[t.ffmpeg,t.ffprobe]){let u=Gt(c.source,c.onPath);c.ok?(n.push(`${C} ${b(c.name)} ${u}`),n.push(`    \u2192 ${c.path}`)):(a=!0,n.push(`${Ue} ${b(c.name)} ${u}`),n.push("    fix: run `autoviral setup` (installs the vendored binary)"))}let i=Le();if(i.ready?(n.push(`${C} ${b("remotion")} render entry \u2014 ${i.via==="bundle"?"pre-built bundle (AUTOVIRAL_REMOTION_BUNDLE)":"web/src source checkout"}`),n.push(`    \u2192 ${i.path}`)):(a=!0,n.push(`${Ue} ${b("remotion")} render entry NOT FOUND \u2014 render/export/snapshot will fail`),n.push(`    looked for: ${i.path}`),n.push("    fix: set AUTOVIRAL_REMOTION_BUNDLE to a pre-built bundle dir, or run the daemon from a checkout containing web/src")),r.ready)n.push(`${C} ${b("tts venv")} edge-tts + stable-ts ready`),n.push(`    \u2192 ${r.venvDir}`);else{let c=[r.edgeTts?null:"edge-tts",r.stableTs?null:"stable-ts"].filter(Boolean).join(" + ");n.push(`${j} ${b("tts venv")} missing ${c}`),n.push("    fix: run `autoviral setup` (creates the venv & pip-installs them)")}o.cached?(n.push(`${C} ${b("playwright")} chromium cached`),n.push(`    \u2192 ${o.cacheDir}`)):(n.push(`${j} ${b("playwright")} chromium not installed`),n.push("    note: ~150MB, lazy-installs on first trends scrape (or `autoviral setup --heavy`)")),s.present?(n.push(`${C} ${b("claude CLI")} on PATH`),n.push(`    \u2192 ${s.path}`)):(n.push(`${j} ${b("claude CLI")} not found on PATH`),n.push("    note: required for the Chat panel; install from https://claude.ai/code (can't be bundled)")),process.stdout.write(`autoviral doctor \u2014 dependency readiness

${n.join(`
`)}

`),a?(process.stdout.write(`Core dependency missing (ffmpeg/ffprobe/remotion entry) \u2014 render/export/waveform will fail.
See the \u2717 rows above for the exact fix.
`),process.exitCode=1):(process.stdout.write(`Core dependencies OK.
`),process.exitCode=0)}function b(e){return(e+" ".repeat(12)).slice(0,12)}function Ht(e,t){return e.includes(t)}var zt=new Set(["--heavy"]);function Jt(e){for(let t of e)t.startsWith("--")&&(zt.has(t)||(t==="--check"?process.stderr.write("autoviral setup: unknown flag --check \u2014 `setup` always INSTALLS. For a read-only readiness probe (no install), run `autoviral doctor`.\n"):process.stderr.write(`autoviral setup: unknown flag ${t}
usage: autoviral setup [--heavy]
`),process.exit(4)))}var S={installed:"\u2713",already:"\u2713",skipped:"\u25CB",failed:"\u2717"};async function Be(e){Jt(e);let t=Ht(e,"--heavy"),r=i=>process.stdout.write(`${i}
`);r(`autoviral setup \u2014 installing dependencies
`),r("[1/3] ffmpeg + ffprobe (managed binaries)");let o=await qe(i=>r(i));r(`${S[o.status]} ffmpeg/ffprobe: ${o.detail}
`),r("[2/3] TTS venv (edge-tts + stable-ts)");let s=await We(i=>r(i));r(`${S[s.status]} tts venv: ${s.detail}
`);let n;if(t?(r("[3/3] playwright chromium (--heavy)"),n=await De(i=>r(i)),r(`${S[n.status]} chromium: ${n.detail}
`)):(n={status:"skipped",detail:"lazy-installs (~150MB) on first trends scrape \u2014 pass --heavy to install now"},r("[3/3] playwright chromium"),r(`${S[n.status]} chromium: ${n.detail}
`)),o.status==="failed")r("Setup finished with a CORE failure \u2014 render/export needs ffmpeg. See above."),r("Re-run `autoviral doctor` to re-check."),process.exitCode=1;else{let i=s.status==="failed"?" (TTS install failed \u2014 see above)":"";r(`Setup complete.${i} Run \`autoviral doctor\` to verify.`),process.exitCode=0}}function Kt(e){return e.error>0?6:e.warning>0?5:0}function Me(e){for(let t of e.findings){let r=t.severity==="error"?"\u2717 ERROR":t.severity==="warning"?"\u26A0 WARN":"\u2139 INFO",o=t.locator?` [${t.locator}]`:"";process.stdout.write(`${r} ${t.ruleId}${o}: ${t.message}
`)}}async function q(e,t,r){let o=e.includes("--json"),s=l(),n=await d(s,"POST",r,{});o?process.stdout.write(`${JSON.stringify(n,null,2)}
`):n.findings.length===0?process.stdout.write(`autoviral ${t}: clean \u2014 no findings
`):(Me(n),process.stdout.write(`
${n.counts.error} error(s), ${n.counts.warning} warning(s)
`)),process.exitCode=Kt(n.counts)}async function Ve(e){return q(e,"lint","/quality/lint")}async function Ge(e){return q(e,"inspect","/quality/inspect")}async function He(e){return q(e,"validate","/quality/validate")}async function ze(e){let t=e.includes("--json"),r=l(),o=await d(r,"POST","/quality/animation-map",{});process.stdout.write(`${JSON.stringify(o,null,2)}
`)}async function Je(e){let t=e.includes("--json"),r=l(),o=await d(r,"POST","/quality/check",{});if(t)process.stdout.write(`${JSON.stringify(o,null,2)}
`);else{for(let s of["lint","inspect","validate"]){let n=o[s];n.findings.length!==0&&(process.stdout.write(`
=== ${s} ===
`),Me(n))}process.stdout.write(`
autoviral check: ${o.summary.totalErrors} error(s), ${o.summary.totalWarnings} warning(s)
`)}process.exitCode=o.summary.exitCode}var[,,P,...Xt]=process.argv,Yt={whoami:B,comp:G,list:H,docs:z,select:J,seek:K,play:X,pause:Y,toast:Q,progress:Z,clip:ee,track:se,scene:ae,script:de,transition:ue,captions:le,carousel:fe,ask:me,export:F,render:be,snapshot:ve,checkpoint:xe,ingest:ye,preprocess:ke,context:$e,trends:Ce,profile:Pe,doctor:_e,setup:Be,lint:Ve,inspect:Ge,validate:He,"animation-map":ze,check:Je};(async()=>{(!P||P==="--help"||P==="-h")&&(process.stdout.write(Qt()),process.exit(0));let e=Yt[P];e||(process.stderr.write(`autoviral: unknown command "${P}"
`),process.exit(127)),await e(Xt)})().catch(e=>{process.stderr.write(`autoviral: ${e.message??String(e)}
`),process.exit(3)});function Qt(){return["autoviral \u2014 bridge between shell agents and the AutoViral Studio.","","Read commands:","  whoami                       Print current Studio context (workId, cwd, port)","  docs [topic]                 Print operator manual. Topic namespaces:","    _shared/\u2026 \xB7 video/\u2026 \xB7 carousel/\u2026 (manual chapters),","    contracts/\u2026 (error-codes \xB7 event-stream), recipes/\u2026 (task recipes).","  comp show                    Print composition.yaml","  list clips [--track K]       List clips, optionally filtered by track","  list assets [--kind K]       List assets","","UI commands:","  select <clip|track|none> <id>","  seek <seconds|'12.5s'|'1m30s'>","  play | pause","  toast <message> [--kind info|success|warn|error] [--duration ms]","  progress start <label> [--steps N] | step <n> | done","","Write + tasks:","  comp put <file|->            Write a WHOLE composition (from file or stdin).","    The universal write path: parses YAML/JSON, validates server-side, and","    atomically replaces composition.yaml. Use for rich edits no verb covers.","  comp validate <file|-> [--json]  Preflight a candidate composition WITHOUT","    writing it. Prints {ok,errors,warnings}; exit 4 on blocking errors. Run","    this before `comp put` to skip the write\u2192400\u2192guess loop.","  comp aspect <9:16|1:1|16:9|4:5>  Switch the canvas ratio in one shot. Flips","    width/height and rescales existing clip offsets so content stays in frame.","  comp set --duration <seconds|auto>  Set or SHORTEN the overall timeline","    length. The ONLY path to crop a tail \u2014 clip edits only ever GROW duration.","    `auto` derives it from the max clip end; an explicit value shorter than","    content warns (tail past it won't render).","  clip add --src <path> [--track video|audio|text|overlay] [--track-id <trackId>] [--offset s] [--duration s]","    --track is the KIND; --track-id targets an EXACT lane (e.g. A2) instead of","    the first same-kind lane. --track overlay adds a picture-in-picture clip.","  clip set <id> [--key value]...","  clip split <id> --at <seconds>","  clip trim <id> [--in <seconds>] [--out <seconds>]","  clip remove <id>","  track add --kind video|audio|text|overlay [--after <trackId>] [--label L] [--language L]","    Add a new lane; prints the minted trackId. Default placement is the end of","    the same-kind block; --after inserts directly below that anchor lane.","  track remove <trackId>          Remove a lane (its clips go with it).","  scene add --title X [--intent hook|build|payoff|cta] [--prompt ...] [--narration ...]","    [--duration N] [--shot-size long|full|medium|close|closeup]","    [--camera push|pull|pan|track|follow|static] [--md-anchor <heading>]","    Add one shot to the storyboard (\u5206\u955C\u8868). Prints the minted sceneId. Scenes","    are the planning layer (\u5267\u672C=PRD / \u5206\u955C=issue), decoupled from the timeline;","    they have no direct render effect until you hand a scene off to generation.","  scene list [--format json|yaml|table]   List the storyboard (order / id / title / intent / status).","  scene set <id> [--title ...] [--intent ...] [--prompt ...] [--narration ...] [--duration N]","    [--shot-size ...] [--camera ...] [--md-anchor ...]   Patch one scene card.","  scene reorder <id1> <id2> ...   Reorder the storyboard (a full permutation of scene ids).","  scene link <id> --asset <assetId> [--asset <id2>...] [--select <id>] [--status planned|generated|stale]","    Attach generated asset(s) to a scene (the plan\u2192execution handoff state).","  scene generate <id> [--provider <name>]   Generate one image from the scene's own","    fields (the plan\u2192execution handoff); registers it + links it + prints the assetId. Re-run to reshoot.","  scene remove <id>               Remove one shot from the storyboard.","  script show                     Print the \u5267\u672C (plan/script.md) \u2014 the narrative","    outline / 'PRD' of the plan. Empty if no script written yet (not an error).","  script edit [--file <path>]     Write the \u5267\u672C from a file (or stdin). Persists","    plan/script.md and refreshes the Studio script editor live.","  transition add --track <trackId> --after <clipId> --preset <name> [--duration <seconds>]","    Add a cut-point transition between two adjacent video clips. Presets come","    from the shared registry (cross-dissolve / wipe-* / push-* / \u2026).","  transition remove <id>          Remove a transition (restore a hard cut).","  captions generate [--language L] [--asset <relpath>] [--track-id <trackId>]","    Run ASR on the work's audio (first audio clip by default, or --asset) and","    write each timecoded segment as a text clip. Prints the # of clips written.","  carousel add-slide [--at N] [--bg-type gradient|image|solid --bg-value V]","  carousel set-layer <slideId> --kind <text|image|shape|sticker> [--id L] [--x N --y N --w N --h N] [...]","    Carousel (\u56FE\u6587) write surface. Full schema: `autoviral docs carousel/02-schema`.","  ask <message> [--yes-no|--ok-cancel] [--timeout seconds]","  export [--preset name] [--proxy]","  render                        Alias for `export --proxy`","  snapshot [--at <time>] [--slide <id>]","    Capture the CURRENT frame (video) or slide (carousel) as a PNG and","    print its path \u2014 Read it to visually self-check before delivering.","  checkpoint create [--label <text>]   Snapshot the live deliverable(s) NOW","    (manual trigger). A pure CLI agent gets NO auto-snapshot \u2014 only the","    ws-bridge chat agent does on each turn \u2014 so take one before a risky edit.","    Idempotent: an unchanged yaml writes nothing.","  checkpoint list                List rollback history (newest first).","  checkpoint restore <id>        Roll the deliverable back to checkpoint <id>","    (its `file` from `checkpoint list`). The CURRENT state is snapshotted","    FIRST, so a restore never loses your pending edits \u2014 it's reversible.","","Ingest:","  ingest youtube <url> [--lang zh-CN] [--model <openrouter-id>]","    Download YouTube \u2192 transcribe (Whisper) \u2192 translate via OpenRouter","    \u2192 bootstrap composition.yaml with overlay captions.","","Setup / diagnostics:","  doctor                        Print a dependency readiness table","    (ffmpeg/ffprobe, TTS venv, playwright, claude CLI). Non-zero exit if a","    CORE dep (ffmpeg/ffprobe) is missing. Runs locally \u2014 no daemon needed.","  setup [--heavy]               Install missing deps with progress","    (managed ffmpeg/ffprobe + TTS venv). --heavy also installs playwright","    chromium now (else it lazy-installs on first use). No npm postinstall.","","Run `autoviral docs` for the full manual.",""].join(`
`)}
