@conceptcraft/mindframes 0.1.38 → 0.2.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Mindframes CLI
2
2
 
3
- Command-line tool for creating AI-powered presentations with [Mindframes](https://www.mindframes.app).
3
+ Command-line tool for creating AI-powered presentations with [Mindframes](https://v2.mindframes.app).
4
4
 
5
5
  ## Installation
6
6
 
@@ -16,7 +16,7 @@ npx @conceptcraft/mindframes create "Topic" --context "your content"
16
16
 
17
17
  ## Setup
18
18
 
19
- Get your API key from [Mindframes Settings](https://www.mindframes.app/settings/api-keys), then configure:
19
+ Get your API key from [Mindframes Settings](https://v2.mindframes.app/settings/api-keys), then configure:
20
20
 
21
21
  ```bash
22
22
  # Interactive setup (recommended)
@@ -244,7 +244,7 @@ mindframes create "Report" --context-file data.md -o json | jq -r '.viewUrl' | x
244
244
  | Variable | Description |
245
245
  |----------|-------------|
246
246
  | `MINDFRAMES_API_KEY` | API key for authentication |
247
- | `MINDFRAMES_API_URL` | Custom API URL (default: https://www.mindframes.app) |
247
+ | `MINDFRAMES_API_URL` | Custom API URL (default: https://v2.mindframes.app) |
248
248
 
249
249
  ## Requirements
250
250
 
@@ -19,42 +19,52 @@ const cliPath = join(__dirname, "cli.js");
19
19
  * e.g. "ccr" → "conceptcraft", "mf" → "mindframes"
20
20
  */
21
21
  function detectBrandId() {
22
- const COMMAND_TO_BRAND = { cc: "conceptcraft", ccr: "conceptcraft", conceptcraft: "conceptcraft", mf: "mindframes", mindframes: "mindframes" };
23
- try {
24
- const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
25
- const firstBin = Object.keys(pkg.bin ?? {})[0] ?? "";
26
- return COMMAND_TO_BRAND[firstBin] ?? "conceptcraft";
27
- } catch {
28
- return "conceptcraft";
29
- }
22
+ const COMMAND_TO_BRAND = {
23
+ cc: "conceptcraft",
24
+ ccr: "conceptcraft",
25
+ conceptcraft: "conceptcraft",
26
+ mf: "mindframes",
27
+ mindframes: "mindframes",
28
+ };
29
+ try {
30
+ const pkg = JSON.parse(
31
+ readFileSync(join(__dirname, "..", "package.json"), "utf-8"),
32
+ );
33
+ const firstBin = Object.keys(pkg.bin ?? {})[0] ?? "";
34
+ return COMMAND_TO_BRAND[firstBin] ?? "conceptcraft";
35
+ } catch {
36
+ return "conceptcraft";
37
+ }
30
38
  }
31
39
 
32
40
  /**
33
41
  * External skills to install via npx skills add
34
42
  */
35
43
  const EXTERNAL_SKILLS = [
36
- // { repo: "https://github.com/remotion-dev/skills", skill: "remotion-best-practices" },
44
+ // { repo: "https://github.com/remotion-dev/skills", skill: "remotion-best-practices" },
37
45
  ];
38
46
 
39
47
  function silentRun(command, env) {
40
- try {
41
- execSync(command, { stdio: "pipe", env: { ...process.env, ...env } });
42
- return true;
43
- } catch {
44
- return false;
45
- }
48
+ try {
49
+ execSync(command, { stdio: "pipe", env: { ...process.env, ...env } });
50
+ return true;
51
+ } catch {
52
+ return false;
53
+ }
46
54
  }
47
55
 
48
56
  async function main() {
49
- const brandId = detectBrandId();
50
- silentRun(`node "${cliPath}" skill install --force`, { CC_BRAND_ID: brandId });
57
+ const brandId = detectBrandId();
58
+ silentRun(`node "${cliPath}" skill install --force`, {
59
+ CC_BRAND_ID: brandId,
60
+ });
51
61
 
52
- for (const { repo, skill } of EXTERNAL_SKILLS) {
53
- silentRun(`npx skills add ${repo} --skill ${skill} -y -g`);
54
- }
62
+ for (const { repo, skill } of EXTERNAL_SKILLS) {
63
+ silentRun(`npx skills add ${repo} --skill ${skill} -y -g`);
64
+ }
55
65
  }
56
66
 
57
67
  // Always exit successfully - postinstall failures should not block npm install
58
68
  main()
59
- .catch(() => {})
60
- .finally(() => process.exit(0));
69
+ .catch(() => {})
70
+ .finally(() => process.exit(0));
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'module'; const require = createRequire(import.meta.url);
3
- import{Command as Fa}from"commander";import Q from"chalk";import lr from"path";var Je={conceptcraft:{id:"conceptcraft",name:"conceptcraft",displayName:"ConceptCraft",description:"CLI tool for ConceptCraft presentation generation",commands:["ccr","conceptcraft"],apiUrl:"https://conceptcraft.ai",docsUrl:"https://docs.conceptcraft.ai",packageName:"@conceptcraft/cli",configDir:".conceptcraft",apiKeyEnvVar:"CONCEPTCRAFT_API_KEY",apiUrlEnvVar:"CONCEPTCRAFT_API_URL"},mindframes:{id:"mindframes",name:"mindframes",displayName:"Mindframes",description:"CLI tool for Mindframes presentation generation",commands:["mf","mindframes"],apiUrl:"https://mindframes.app",docsUrl:"https://docs.mindframes.app",packageName:"@conceptcraft/mindframes",configDir:".mindframes",apiKeyEnvVar:"MINDFRAMES_API_KEY",apiUrlEnvVar:"MINDFRAMES_API_URL"}},vn={cc:"conceptcraft",conceptcraft:"conceptcraft",mf:"mindframes",mindframes:"mindframes"};function dr(){let n=process.env.CC_BRAND_ID;if(n&&Je[n])return Je[n];let t=process.argv[1]||"",e=lr.basename(t).replace(/\.(js|ts)$/,""),o=vn[e];if(o)return Je[o];for(let[r,i]of Object.entries(vn))if(t.includes(`/${r}`)||t.includes(`\\${r}`))return Je[i];return Je.mindframes}var u=dr();import{Command as $r}from"commander";import to from"chalk";import no from"ora";import oo from"http";import{randomBytes as ro,createHash as Ir}from"crypto";import Rr from"open";import mr from"conf";var xn="https://www.mindframes.app",ur={apiKey:{type:"string"},apiUrl:{type:"string",default:xn},defaultTeamId:{type:"string"},accessToken:{type:"string"},refreshToken:{type:"string"},tokenExpiresAt:{type:"number"},clientId:{type:"string"},clientSecret:{type:"string"}},O=new mr({projectName:u.name,schema:ur});function wn(){return{apiKey:ie(),apiUrl:M(),defaultTeamId:O.get("defaultTeamId"),accessToken:O.get("accessToken"),refreshToken:O.get("refreshToken"),tokenExpiresAt:O.get("tokenExpiresAt"),clientId:O.get("clientId"),clientSecret:O.get("clientSecret")}}function ie(){let n=process.env[u.apiKeyEnvVar]??process.env.CC_SLIDES_API_KEY;return n||O.get("apiKey")}function Ft(n){O.set("apiKey",n)}function M(){let n=process.env[u.apiUrlEnvVar]??process.env.CC_SLIDES_API_URL;return n||(O.get("apiUrl")??xn)}function Dt(n){O.set("apiUrl",n)}function et(){return O.get("defaultTeamId")}function Se(n){O.set("defaultTeamId",n)}function tt(){O.clear()}function nt(){return O.path}function Ce(){return!!ie()}function Sn(){return O.get("accessToken")}function Cn(){return O.get("refreshToken")}function ot(n,t,e){O.set("accessToken",n),O.set("refreshToken",t),O.set("tokenExpiresAt",Date.now()+(e-60)*1e3)}function rt(){O.delete("accessToken"),O.delete("refreshToken"),O.delete("tokenExpiresAt")}function kn(){let n=O.get("tokenExpiresAt");return n?Date.now()>=n:!0}function ue(){return!!O.get("accessToken")&&!!O.get("refreshToken")}function it(){return O.get("clientId")}function at(){return O.get("clientSecret")}function Tn(n,t){O.set("clientId",n),O.set("clientSecret",t)}import E from"chalk";import Nt from"cli-table3";function $n(){return process.stdout.isTTY??!1}function v(n,t="human"){t!=="quiet"&&t!=="json"&&console.log(E.green("\u2713"),n)}function l(n,t="human"){if(t!=="quiet"){if(t==="json"){console.error(JSON.stringify({error:n}));return}console.error(E.red("\u2717"),n)}}function I(n,t="human"){t!=="quiet"&&t!=="json"&&console.warn(E.yellow("\u26A0"),n)}function p(n,t="human"){t!=="quiet"&&t!=="json"&&console.log(E.blue("\u2139"),n)}function ke(n,t="en"){return n?`${M()}/${t}/view/presentations/${n}`:"N/A"}function In(n,t={}){let{showLinks:e=!1,language:o="en"}=t,r=(s,c)=>s.length>c?s.slice(0,c-1)+"\u2026":s,i=s=>{try{return new Date(s).toLocaleString("en-US",{month:"short",day:"numeric",hour:"numeric",minute:"2-digit",hour12:!0}).replace(" at ",", ")}catch{return"-"}};if(e){let s=new Nt({head:[E.cyan("Slug"),E.cyan("Title"),E.cyan("Slides"),E.cyan("Created"),E.cyan("URL")]});for(let c of n)s.push([r(c.slug||c.id.slice(0,8),30),r(c.title||"Untitled",22),String(c.numberOfSlides||"-"),i(c.createdAt),ke(c.slug,o)]);return s.toString()}let a=new Nt({head:[E.cyan("Slug"),E.cyan("Title"),E.cyan("Slides"),E.cyan("Mode"),E.cyan("Created")],colWidths:[32,28,8,11,18]});for(let s of n)a.push([s.slug||s.id.slice(0,8),s.title||"Untitled",String(s.numberOfSlides||"-"),s.mode||"-",i(s.createdAt)]);return a.toString()}function Rn(n){return n.map(t=>t.slug||t.id).join(`
4
- `)}function An(n){let t=[...n].sort((r,i)=>{if(r.isDefault&&!i.isDefault)return-1;if(!r.isDefault&&i.isDefault)return 1;let a=r.createdAt?new Date(r.createdAt).getTime():0;return(i.createdAt?new Date(i.createdAt).getTime():0)-a}),e=r=>{if(!r)return"-";try{return new URL(r).href}catch{return r.startsWith("http")?r:`https://${r}`}},o=new Nt({head:[E.cyan("Name"),E.cyan("Source"),E.cyan("Color"),E.cyan("Logo"),E.cyan("Default"),E.cyan("ID")]});for(let r of t){let i=r.primaryColor?`${E.bgHex(r.primaryColor)(" ")} ${r.primaryColor}`:"-";o.push([r.name,e(r.sourceUrl),i,r.logoUrl?E.green("\u2713"):E.gray("\u2717"),r.isDefault?E.green("\u2605"):"",r.id])}return o.toString()}function Ut(n){try{return new Date(n).toLocaleString()}catch{return n}}function ee(n){console.log(),console.log(E.bold(n)),console.log(E.gray("\u2500".repeat(n.length)))}function x(n,t){console.log(` ${E.gray(n+":")} ${t??"-"}`)}function On(n,t,e=30,o=!0){let r=Math.min(100,Math.round(n/t*100)),i=Math.round(e*n/t),a=e-i,s=E.green("\u2588".repeat(i))+E.gray("\u2591".repeat(a));return o?`[${s}] ${r}%`:`[${s}]`}function pr(n){return JSON.stringify(n,null,2)}function V(n){console.log(pr(n))}import Cr from"conf";import st from"chalk";var S={SUCCESS:0,GENERAL_ERROR:1,AUTH_ERROR:2,NOT_FOUND:3,RATE_LIMIT:4,NETWORK_ERROR:5,INVALID_INPUT:6};async function fr(){let n=Cn(),t=it(),e=M();if(!n||!t)return null;try{let o=await fetch(`${e}/.well-known/oauth-authorization-server`);if(!o.ok)return null;let r=await o.json(),i=new URLSearchParams({grant_type:"refresh_token",refresh_token:n,client_id:t}),a=at();a&&i.set("client_secret",a);let s=await fetch(r.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()});if(!s.ok)return rt(),null;let c=await s.json();return ot(c.access_token,c.refresh_token,c.expires_in),c.access_token}catch{return null}}async function En(){return ue()?kn()?fr():Sn()||null:null}function te(){return ue()||Ce()}async function F(){if(!te()){let n=u.commands[0],t=u.apiKeyEnvVar;console.error(st.red("\u2717 Not authenticated.")),console.error(),console.error(st.bold("To authenticate, run:")),console.error(st.cyan(` ${n} login`)),console.error(),console.error(st.gray(`Or set ${t} environment variable.`)),process.exit(S.AUTH_ERROR)}}function gr(n){return n.length<=14?"****":`${n.slice(0,10)}...${n.slice(-4)}`}function Pn(){let n=ie();if(n)return gr(n)}function Lt(n){return["cc_slides_","mcp_","cc_sk_","sk_"].some(e=>n.startsWith(e))}import{readFileSync as hr,statSync as yr}from"fs";import{basename as Fn}from"path";import{randomUUID as br}from"crypto";async function le(){let n=await En();if(n)return{Authorization:`Bearer ${n}`};let t=ie();return t?{"x-api-key":t}:{}}var P=class extends Error{constructor(e,o,r=1){super(e);this.statusCode=o;this.exitCode=r;this.name="ApiError"}};async function U(n,t={}){let e=M();if(!te())throw new P(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2);let o=await le(),r=`${e}${n}`,i={...o,...t.headers};t.body&&!t.stream&&(i["Content-Type"]="application/json");let a={method:t.method??"GET",headers:i};t.body&&(a.body=JSON.stringify(t.body));let s;try{s=await fetch(r,a)}catch(d){throw new P(`Network error: ${d instanceof Error?d.message:"Unknown error"}`,0,5)}if(!s.ok){let d=await s.text().catch(()=>""),m=1;switch(s.status){case 401:m=2;break;case 403:m=2;break;case 404:m=3;break;case 429:m=4;break;case 500:m=1;break}let C=d.trim()||`HTTP ${s.status}: ${s.statusText||"Server error"}`;throw new P(C,s.status,m)}return t.stream?s:s.headers.get("content-type")?.includes("application/json")?s.json():s.text()}async function vr(n,t){let e=M();if(!te())throw new P(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2);let o=await le(),r=`${e}${n}`,i;try{i=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",...o},body:JSON.stringify(t)})}catch(a){throw new P(`Network error: ${a instanceof Error?a.message:"Unknown error"}`,0,5)}if(!i.ok){let a=await i.text().catch(()=>"Unknown error"),s=1;switch(i.status){case 401:s=2;break;case 403:s=2;break;case 404:s=3;break;case 429:s=4;break}throw new P(a,i.status,s)}return i}function xr(n){let t=n.toLowerCase().split(".").pop();return{pdf:"application/pdf",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",txt:"text/plain",md:"text/markdown",csv:"text/csv",json:"application/json",html:"text/html",css:"text/css",js:"application/javascript",ts:"text/x-typescript",py:"text/x-python"}[t||""]||"application/octet-stream"}async function wr(n){let t=M();if(!te())throw new P(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2);let e=await le(),o=yr(n),r=Fn(n),i=xr(n),a=await fetch(`${t}/api/cli/files/upload`,{method:"POST",headers:{"Content-Type":"application/json",...e},body:JSON.stringify({fileMetadata:{name:r,type:i,size:o.size}})});if(!a.ok){let h=await a.text();throw new P(h||"Failed to get upload URL",a.status,1)}let s=await a.json(),c=hr(n),d=new FormData;for(let[h,f]of Object.entries(s.fields||{}))d.append(h,f);let m=new Blob([c],{type:i});d.append("file",m,r);let C=await fetch(s.url,{method:"POST",body:d});if(!C.ok)throw new P("Failed to upload file to storage",C.status,1);return{id:br(),name:r,url:s.fileUrl,size:o.size,type:i,selected:!0}}async function Dn(n,t){let e=[];for(let o=0;o<n.length;o++){let r=n[o],i=Fn(r);t?.(o,n.length,i);let a=await wr(r);e.push(a)}return t?.(n.length,n.length,""),e}async function Nn(n){let t={};for(let[e,o]of Object.entries(n))o!==void 0&&(t[e]=o);return vr("/api/slides/cli/create-presentation",t)}async function Un(n,t=20){let e=new URLSearchParams;return e.set("limit",String(t)),n&&e.set("teamId",n),(await U(`/api/cli/presentations?${e}`)).presentations}async function Te(n){return U(`/api/cli/presentation/${n}`)}async function Ln(n){await U(`/api/cli/presentation/${n}`,{method:"DELETE"})}async function Mn(n,t={}){let e=M();if(!te())throw new P(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2);let o=await le(),r=await fetch(`${e}/api/presentations/export`,{method:"POST",headers:{"Content-Type":"application/json",...o},body:JSON.stringify({presentationId:n,options:{includeImages:t.includeImages??!0,includeBranding:t.includeBranding??!0,downloadExternalImages:t.includeExternal??!0}})});if(!r.ok)throw new P(await r.text(),r.status,r.status===404?3:1);return r.arrayBuffer()}async function jn(n,t,e={}){let o=M();if(!te())throw new P(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2);let r=await le(),i=new FormData,a=new Blob([n],{type:"application/zip"});i.append("file",a,t),i.append("options",JSON.stringify({dryRun:e.dryRun??!1,remapIds:!0}));let s=await fetch(`${o}/api/presentations/import`,{method:"POST",headers:r,body:i}),c=await s.json();if(!s.ok)throw new P(c.errors?.[0]?.message??"Import failed",s.status,1);return c}async function Mt(){return U("/api/cli/branding")}async function jt(n){return U(`/api/branding/${n}`)}async function Vn(n,t){return U("/api/cli/branding/extract",{method:"POST",body:{url:n,teamId:t}})}async function pe(){return U("/api/cli/whoami")}async function _n(){return U("/api/cli/features")}async function qn(n,t,e={}){let o=M();if(!te())throw new P(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2);let r=await le(),i=await fetch(`${o}/api/presentations/${n}/generate-blog`,{method:"POST",headers:{"Content-Type":"application/json",...r},body:JSON.stringify({documentCreatedAt:t,targetWordCount:e.targetWordCount??300,tone:e.tone??"professional",language:e.language??"en",targetAudience:e.targetAudience??"General Audience",blogFormat:e.blogFormat??"narrative",customInstructions:e.customInstructions??"",includeImages:e.includeImages??!0,includeTableOfContents:e.includeTableOfContents??!1})});if(!i.ok)throw new P(await i.text(),i.status,i.status===404?3:1);return i}async function Sr(n){let t=new URLSearchParams;n&&t.set("teamId",n);let e=t.toString();return U(`/api/cli/limits${e?`?${e}`:""}`)}async function Bn(n,t,e){let o=await Sr(e);if(!o.canGenerate[n]){let r=o.remaining[n]??0,i=o.limits[n]??0;throw i===0?new P(`The "${n}" mode is not available on your ${o.planName} plan. Available modes: ${o.availableModes.join(", ")||"none"}`,403,2):new P(`You have reached your ${n} generation limit for this billing cycle (${o.usage[n]??0}/${i} used). Try a different mode: ${o.availableModes.join(", ")||"none available"}`,403,4)}if(o.maxSlidesPerPresentation!==-1&&t>o.maxSlidesPerPresentation)throw new P(`Maximum ${o.maxSlidesPerPresentation} slides allowed on your ${o.planName} plan (requested: ${t}). Try a different mode: ${o.availableModes.join(", ")||"none available"}`,403,6);return o}function Gn(n){return n.replace(/[\u2014\u2013]/g,"-").replace(/[\u201C\u201D]/g,'"').replace(/[\u2018\u2019]/g,"'").replace(/\u2026/g,"...").replace(/\u00A0/g," ").replace(/[\u2010-\u2015]/g,"-").replace(/[\u2032\u2033]/g,"'")}async function ct(n){let t=M();if(!te())throw new P(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2);let e=await le(),o={...n,text:Gn(n.text)},r;try{r=await fetch(`${t}/api/cli/tts`,{method:"POST",headers:{"Content-Type":"application/json",...e},body:JSON.stringify(o)})}catch(h){throw new P(`Network error: ${h instanceof Error?h.message:"Unknown error"}`,0,5)}if(!r.ok){let h=await r.text().catch(()=>"Unknown error"),f;try{let w=JSON.parse(h);f=w.error||w.message||h}catch{f=h}throw new P(f,r.status,r.status===401?2:1)}let i=Buffer.from(await r.arrayBuffer()),a=parseFloat(r.headers.get("X-Duration-Seconds")||"0"),s=parseFloat(r.headers.get("X-Cost-USD")||"0"),c=r.headers.get("X-Provider")||"unknown",d=r.headers.get("X-Audio-Format")||"mp3",m,C=r.headers.get("X-Timestamps");if(C)try{m=JSON.parse(C)}catch{}return{audioData:i,duration:a,cost:s,provider:c,format:d,timestamps:m}}async function Wn(n){let t=M();if(!te())throw new P(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2);let e=await le(),o={...n,texts:n.texts.map(a=>({...a,text:Gn(a.text)}))},r;try{r=await fetch(`${t}/api/cli/tts/batch`,{method:"POST",headers:{"Content-Type":"application/json",...e},body:JSON.stringify(o)})}catch(a){throw new P(`Network error: ${a instanceof Error?a.message:"Unknown error"}`,0,5)}if(!r.ok){let a=await r.text().catch(()=>"Unknown error"),s;try{let c=JSON.parse(a);s=c.error||c.message||a}catch{s=a}throw new P(s,r.status,r.status===401?2:1)}let i=await r.json();return i.results=i.results.map(a=>({...a,audioData:Buffer.from(a.audioData,"base64")})),i}async function Yn(n){let t=n?`/api/cli/tts?provider=${n}`:"/api/cli/tts";return U(t)}async function lt(n){let t=await U("/api/cli/music",{method:"POST",body:n});if(!t.data)throw new P(`Invalid API response: ${JSON.stringify(t)}`,500,1);return{requestId:t.data.id,status:t.data.status,audioUrl:t.data.audioUrl,duration:t.data.duration,cost:t.data.cost,error:t.data.error}}async function ze(n){let t=await U(`/api/cli/music?requestId=${encodeURIComponent(n)}`);return{requestId:t.data.id,status:t.data.status,audioUrl:t.data.audioUrl,duration:t.data.duration,cost:t.data.cost,error:t.data.error}}async function Hn(n){return U("/api/cli/mix",{method:"POST",body:n})}async function Vt(n){return U(`/api/cli/mix?requestId=${encodeURIComponent(n)}`)}async function dt(n){return U("/api/cli/images/search",{method:"POST",body:n})}async function Jn(n){return U("/api/cli/images/generate",{method:"POST",body:n})}async function _t(n){return U("/api/cli/videos/search",{method:"POST",body:n})}async function de(n,t=60,e=2e3){for(let o=0;o<t;o++){let r=await n();if(r.status==="completed"||r.status==="failed")return r;await new Promise(i=>setTimeout(i,e))}throw new P("Operation timed out",408,1)}async function zn(n){return U("/api/cli/scrape",{method:"POST",body:{url:n}})}async function Kn(n){let t=await U("/api/cli/sfx",{method:"POST",body:n});if(!t.data)throw new P(`Invalid API response: ${JSON.stringify(t)}`,500,1);return{id:t.data.id,status:t.data.status,audioUrl:t.data.audioUrl,duration:t.data.duration,format:t.data.format,cost:t.data.cost,error:t.data.error,requestId:t.data.requestId}}async function qt(n){let t=await U(`/api/cli/sfx?requestId=${encodeURIComponent(n)}`);return{id:t.data.id,status:t.data.status,audioUrl:t.data.audioUrl,duration:t.data.duration,format:t.data.format,cost:t.data.cost,error:t.data.error,requestId:t.data.requestId}}async function Xn(n){return U("/api/cli/video/plan",{method:"POST",body:n})}var mt=new Cr({projectName:"conceptcraft",configName:"feature-cache"}),kr=3600*1e3,Tr=1440*60*1e3;function Qn(n){let t=0;for(let e=0;e<n.length;e++){let o=n.charCodeAt(e);t=(t<<5)-t+o,t=t&t}return t.toString(16)}function Zn(){if(!Ce())return null;let n=mt.get("featureFlags");if(!n)return null;let t=Qn(ie());if(n.apiKeyHash&&n.apiKeyHash!==t)return ge(),null;let e=Date.now()-n.fetchedAt;return e>Tr?null:(e>kr&&Bt(),n.flags)}function Bt(){fe().catch(()=>{})}async function fe(){let n=await _n(),t=ie();return mt.set("featureFlags",{flags:n,fetchedAt:Date.now(),apiKeyHash:t?Qn(t):void 0}),n}function ge(){mt.delete("featureFlags")}function eo(){return mt.path}var Ar=`${u.displayName} CLI`,Or=8765,Er=8775;function Pr(){return ro(32).toString("base64url")}function Fr(n){return Ir("sha256").update(n).digest("base64url")}function Dr(){return ro(16).toString("hex")}async function Nr(n,t){for(let e=n;e<=t;e++)try{return await new Promise((o,r)=>{let i=oo.createServer();i.listen(e,()=>{i.close(()=>o())}),i.on("error",r)}),e}catch{continue}throw new Error(`No available port found between ${n} and ${t}`)}async function Ur(n){let t=await fetch(`${n}/.well-known/oauth-authorization-server`);if(!t.ok)throw new Error(`Failed to fetch OAuth metadata: ${t.status}`);return t.json()}async function Lr(n,t){let e=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_name:Ar,redirect_uris:[t],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"none",scope:"presentations:read presentations:write"})});if(!e.ok){let o=await e.text();throw new Error(`Client registration failed: ${o}`)}return e.json()}async function Mr(n,t,e,o,r){let i=new URLSearchParams({grant_type:"authorization_code",code:t,redirect_uri:o,client_id:r,code_verifier:e}),a=await fetch(n,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()});if(!a.ok){let s=await a.text();throw new Error(`Token exchange failed: ${s}`)}return a.json()}function jr(n,t){return new Promise((e,o)=>{let r,i=!1,a=()=>{i||(i=!0,clearTimeout(r),process.off("SIGINT",s),process.off("SIGTERM",s),c.close())},s=()=>{a(),o(new Error("Login cancelled"))},c=oo.createServer((d,m)=>{let C=new URL(d.url||"",`http://localhost:${n}`);if(C.pathname!=="/callback"){m.writeHead(404),m.end("Not found");return}let h=C.searchParams.get("code"),f=C.searchParams.get("state"),w=C.searchParams.get("error"),$=C.searchParams.get("error_description");if(m.writeHead(200,{"Content-Type":"text/html"}),w){m.end(`
3
+ var g={id:"mindframes",name:"mindframes",displayName:"Mindframes",description:"CLI tool for Mindframes presentation generation",commands:["mf","mindframes"],apiUrl:"https://v2.mindframes.app",docsUrl:"https://docs.mindframes.ai",packageName:"@conceptcraft/mindframes",configDir:".mindframes",apiKeyEnvVar:"MINDFRAMES_API_KEY",apiUrlEnvVar:"MINDFRAMES_API_URL"};import{Command as Fs}from"commander";import Z from"chalk";function vn(n={}){let t=(a,c)=>{let d=n[a];return d&&d.trim().length>0?d.trim():c},e=t("NEXT_PUBLIC_PRODUCT_SHORT_NAME","ConceptCraft"),o=t("NEXT_PUBLIC_CLI_COMMAND","ccr"),r=t("NEXT_PUBLIC_CLI_COMMAND_FULL","conceptcraft"),i=t("NEXT_PUBLIC_CLI_CONFIG_DIR",`.${r}`),s=e.toUpperCase().replace(/[^A-Z0-9]/g,"_");return{id:r,name:i.replace(/^\./,""),displayName:e,description:`CLI tool for ${e} presentation generation`,commands:[o,r],apiUrl:t("NEXT_PUBLIC_API_URL","http://localhost:3000"),docsUrl:t("NEXT_PUBLIC_DOCS_URL",`https://docs.${e.toLowerCase()}.ai`),packageName:t("NEXT_PUBLIC_CLI_PACKAGE_NAME","@conceptcraft/cli"),configDir:i,apiKeyEnvVar:`${s}_API_KEY`,apiUrlEnvVar:`${s}_API_URL`}}var m=typeof g<"u"&&g?g:vn(process.env);function xn(n){return n[0]==="--"?n.slice(1):n}import{Command as $r}from"commander";import no from"chalk";import oo from"ora";import ro from"http";import{randomBytes as io,createHash as Ir}from"crypto";import Rr from"open";import ur from"conf";var wn=m.apiUrl,mr={apiKey:{type:"string"},apiUrl:{type:"string",default:wn},defaultTeamId:{type:"string"},accessToken:{type:"string"},refreshToken:{type:"string"},tokenExpiresAt:{type:"number"},clientId:{type:"string"},clientSecret:{type:"string"}},E=new ur({projectName:m.name,schema:mr});function Sn(){return{apiKey:se(),apiUrl:j(),defaultTeamId:E.get("defaultTeamId"),accessToken:E.get("accessToken"),refreshToken:E.get("refreshToken"),tokenExpiresAt:E.get("tokenExpiresAt"),clientId:E.get("clientId"),clientSecret:E.get("clientSecret")}}function se(){let n=process.env[m.apiKeyEnvVar]??process.env.CC_SLIDES_API_KEY;return n||E.get("apiKey")}function Ft(n){E.set("apiKey",n)}function j(){let n=process.env[m.apiUrlEnvVar]??process.env.CC_SLIDES_API_URL;return n||(E.get("apiUrl")??wn)}function Dt(n){E.set("apiUrl",n)}function et(){return E.get("defaultTeamId")}function Te(n){E.set("defaultTeamId",n)}function tt(){E.clear()}function nt(){return E.path}function Ce(){return!!se()}function Tn(){return E.get("accessToken")}function Cn(){return E.get("refreshToken")}function ot(n,t,e){E.set("accessToken",n),E.set("refreshToken",t),E.set("tokenExpiresAt",Date.now()+(e-60)*1e3)}function rt(){E.delete("accessToken"),E.delete("refreshToken"),E.delete("tokenExpiresAt")}function kn(){let n=E.get("tokenExpiresAt");return n?Date.now()>=n:!0}function pe(){return!!E.get("accessToken")&&!!E.get("refreshToken")}function it(){return E.get("clientId")}function st(){return E.get("clientSecret")}function $n(n,t){E.set("clientId",n),E.set("clientSecret",t)}import P from"chalk";import Nt from"cli-table3";function In(){return process.stdout.isTTY??!1}function v(n,t="human"){t!=="quiet"&&t!=="json"&&console.log(P.green("\u2713"),n)}function l(n,t="human"){if(t!=="quiet"){if(t==="json"){console.error(JSON.stringify({error:n}));return}console.error(P.red("\u2717"),n)}}function A(n,t="human"){t!=="quiet"&&t!=="json"&&console.warn(P.yellow("\u26A0"),n)}function p(n,t="human"){t!=="quiet"&&t!=="json"&&console.log(P.blue("\u2139"),n)}function ke(n,t="en"){return n?`${j()}/${t}/view/presentations/${n}`:"N/A"}function Rn(n,t={}){let{showLinks:e=!1,language:o="en"}=t,r=(a,c)=>a.length>c?a.slice(0,c-1)+"\u2026":a,i=a=>{try{return new Date(a).toLocaleString("en-US",{month:"short",day:"numeric",hour:"numeric",minute:"2-digit",hour12:!0}).replace(" at ",", ")}catch{return"-"}};if(e){let a=new Nt({head:[P.cyan("Slug"),P.cyan("Title"),P.cyan("Slides"),P.cyan("Created"),P.cyan("URL")]});for(let c of n)a.push([r(c.slug||c.id.slice(0,8),30),r(c.title||"Untitled",22),String(c.numberOfSlides||"-"),i(c.createdAt),ke(c.slug,o)]);return a.toString()}let s=new Nt({head:[P.cyan("Slug"),P.cyan("Title"),P.cyan("Slides"),P.cyan("Mode"),P.cyan("Created")],colWidths:[32,28,8,11,18]});for(let a of n)s.push([a.slug||a.id.slice(0,8),a.title||"Untitled",String(a.numberOfSlides||"-"),a.mode||"-",i(a.createdAt)]);return s.toString()}function An(n){return n.map(t=>t.slug||t.id).join(`
4
+ `)}function On(n){let t=[...n].sort((r,i)=>{if(r.isDefault&&!i.isDefault)return-1;if(!r.isDefault&&i.isDefault)return 1;let s=r.createdAt?new Date(r.createdAt).getTime():0;return(i.createdAt?new Date(i.createdAt).getTime():0)-s}),e=r=>{if(!r)return"-";try{return new URL(r).href}catch{return r.startsWith("http")?r:`https://${r}`}},o=new Nt({head:[P.cyan("Name"),P.cyan("Source"),P.cyan("Color"),P.cyan("Logo"),P.cyan("Default"),P.cyan("ID")]});for(let r of t){let i=r.primaryColor?`${P.bgHex(r.primaryColor)(" ")} ${r.primaryColor}`:"-";o.push([r.name,e(r.sourceUrl),i,r.logoUrl?P.green("\u2713"):P.gray("\u2717"),r.isDefault?P.green("\u2605"):"",r.id])}return o.toString()}function Ut(n){try{return new Date(n).toLocaleString()}catch{return n}}function te(n){console.log(),console.log(P.bold(n)),console.log(P.gray("\u2500".repeat(n.length)))}function x(n,t){console.log(` ${P.gray(n+":")} ${t??"-"}`)}function En(n,t,e=30,o=!0){let r=Math.min(100,Math.round(n/t*100)),i=Math.round(e*n/t),s=e-i,a=P.green("\u2588".repeat(i))+P.gray("\u2591".repeat(s));return o?`[${a}] ${r}%`:`[${a}]`}function pr(n){return JSON.stringify(n,null,2)}function _(n){console.log(pr(n))}import Tr from"conf";import at from"chalk";var T={SUCCESS:0,GENERAL_ERROR:1,AUTH_ERROR:2,NOT_FOUND:3,RATE_LIMIT:4,NETWORK_ERROR:5,INVALID_INPUT:6};async function fr(){let n=Cn(),t=it(),e=j();if(!n||!t)return null;try{let o=await fetch(`${e}/.well-known/oauth-authorization-server`);if(!o.ok)return null;let r=await o.json(),i=new URLSearchParams({grant_type:"refresh_token",refresh_token:n,client_id:t}),s=st();s&&i.set("client_secret",s);let a=await fetch(r.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()});if(!a.ok)return rt(),null;let c=await a.json();return ot(c.access_token,c.refresh_token,c.expires_in),c.access_token}catch{return null}}async function Pn(){return pe()?kn()?fr():Tn()||null:null}function ne(){return pe()||Ce()}async function D(){if(!ne()){let n=m.commands[0],t=m.apiKeyEnvVar;console.error(at.red("\u2717 Not authenticated.")),console.error(),console.error(at.bold("To authenticate, run:")),console.error(at.cyan(` ${n} login`)),console.error(),console.error(at.gray(`Or set ${t} environment variable.`)),process.exit(T.AUTH_ERROR)}}function gr(n){return n.length<=14?"****":`${n.slice(0,10)}...${n.slice(-4)}`}function Fn(){let n=se();if(n)return gr(n)}function Lt(n){return["cc_slides_","mcp_","cc_sk_","sk_"].some(e=>n.startsWith(e))}import{readFileSync as hr,statSync as yr}from"fs";import{basename as Dn}from"path";import{randomUUID as br}from"crypto";async function de(){let n=await Pn();if(n)return{Authorization:`Bearer ${n}`};let t=se();return t?{"x-api-key":t}:{}}var F=class extends Error{constructor(e,o,r=1){super(e);this.statusCode=o;this.exitCode=r;this.name="ApiError"}statusCode;exitCode};async function L(n,t={}){let e=j();if(!ne())throw new F(`Not authenticated. Run '${m.commands[0]} login' or set ${m.apiKeyEnvVar} environment variable.`,401,2);let o=await de(),r=`${e}${n}`,i={...o,...t.headers};t.body&&!t.stream&&(i["Content-Type"]="application/json");let s={method:t.method??"GET",headers:i};t.body&&(s.body=JSON.stringify(t.body));let a;try{a=await fetch(r,s)}catch(d){throw new F(`Network error: ${d instanceof Error?d.message:"Unknown error"}`,0,5)}if(!a.ok){let d=await a.text().catch(()=>""),u=1;switch(a.status){case 401:u=2;break;case 403:u=2;break;case 404:u=3;break;case 429:u=4;break;case 500:u=1;break}let C=d.trim()||`HTTP ${a.status}: ${a.statusText||"Server error"}`;throw new F(C,a.status,u)}return t.stream?a:a.headers.get("content-type")?.includes("application/json")?a.json():a.text()}async function vr(n,t){let e=j();if(!ne())throw new F(`Not authenticated. Run '${m.commands[0]} login' or set ${m.apiKeyEnvVar} environment variable.`,401,2);let o=await de(),r=`${e}${n}`,i;try{i=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",...o},body:JSON.stringify(t)})}catch(s){throw new F(`Network error: ${s instanceof Error?s.message:"Unknown error"}`,0,5)}if(!i.ok){let s=await i.text().catch(()=>"Unknown error"),a=1;switch(i.status){case 401:a=2;break;case 403:a=2;break;case 404:a=3;break;case 429:a=4;break}throw new F(s,i.status,a)}return i}function xr(n){let t=n.toLowerCase().split(".").pop();return{pdf:"application/pdf",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",txt:"text/plain",md:"text/markdown",csv:"text/csv",json:"application/json",html:"text/html",css:"text/css",js:"application/javascript",ts:"text/x-typescript",py:"text/x-python"}[t||""]||"application/octet-stream"}async function wr(n){let t=j();if(!ne())throw new F(`Not authenticated. Run '${m.commands[0]} login' or set ${m.apiKeyEnvVar} environment variable.`,401,2);let e=await de(),o=yr(n),r=Dn(n),i=xr(n),s=await fetch(`${t}/api/cli/files/upload`,{method:"POST",headers:{"Content-Type":"application/json",...e},body:JSON.stringify({fileMetadata:{name:r,type:i,size:o.size}})});if(!s.ok){let y=await s.text();throw new F(y||"Failed to get upload URL",s.status,1)}let a=await s.json(),c=hr(n),d=new FormData;for(let[y,f]of Object.entries(a.fields||{}))d.append(y,f);let u=new Blob([c],{type:i});d.append("file",u,r);let C=await fetch(a.url,{method:"POST",body:d});if(!C.ok)throw new F("Failed to upload file to storage",C.status,1);return{id:br(),name:r,url:a.fileUrl,size:o.size,type:i,selected:!0}}async function Nn(n,t){let e=[];for(let o=0;o<n.length;o++){let r=n[o],i=Dn(r);t?.(o,n.length,i);let s=await wr(r);e.push(s)}return t?.(n.length,n.length,""),e}async function Un(n){let t={};for(let[o,r]of Object.entries(n))r!==void 0&&(t[o]=r);let e=t.designBrandReference??t.brandId??t.brandingId;return e!==void 0&&(t.designBrandReference=e,delete t.brandId,delete t.brandingId),vr("/api/slides/cli/create-presentation",t)}async function Ln(n,t=20){let e=new URLSearchParams;return e.set("limit",String(t)),n&&e.set("teamId",n),(await L(`/api/cli/presentations?${e}`)).presentations}async function $e(n){return L(`/api/cli/presentation/${n}`)}async function Mn(n){await L(`/api/cli/presentation/${n}`,{method:"DELETE"})}async function jn(n,t={}){let e=j();if(!ne())throw new F(`Not authenticated. Run '${m.commands[0]} login' or set ${m.apiKeyEnvVar} environment variable.`,401,2);let o=await de(),r=await fetch(`${e}/api/presentations/export`,{method:"POST",headers:{"Content-Type":"application/json",...o},body:JSON.stringify({presentationId:n,options:{includeImages:t.includeImages??!0,includeBranding:t.includeBranding??!0,downloadExternalImages:t.includeExternal??!0}})});if(!r.ok)throw new F(await r.text(),r.status,r.status===404?3:1);return r.arrayBuffer()}async function Vn(n,t,e={}){let o=j();if(!ne())throw new F(`Not authenticated. Run '${m.commands[0]} login' or set ${m.apiKeyEnvVar} environment variable.`,401,2);let r=await de(),i=new FormData,s=new Blob([n],{type:"application/zip"});i.append("file",s,t),i.append("options",JSON.stringify({dryRun:e.dryRun??!1,remapIds:!0}));let a=await fetch(`${o}/api/presentations/import`,{method:"POST",headers:r,body:i}),c=await a.json();if(!a.ok)throw new F(c.errors?.[0]?.message??"Import failed",a.status,1);return c}async function Mt(){return L("/api/cli/branding")}async function jt(n){return L(`/api/branding/${n}`)}async function _n(n,t){return L("/api/cli/branding/extract",{method:"POST",body:{url:n,teamId:t}})}async function fe(){return L("/api/cli/whoami")}async function qn(){return L("/api/cli/features")}async function Bn(n,t,e={}){let o=j();if(!ne())throw new F(`Not authenticated. Run '${m.commands[0]} login' or set ${m.apiKeyEnvVar} environment variable.`,401,2);let r=await de(),i=await fetch(`${o}/api/presentations/${n}/generate-blog`,{method:"POST",headers:{"Content-Type":"application/json",...r},body:JSON.stringify({documentCreatedAt:t,targetWordCount:e.targetWordCount??300,tone:e.tone??"professional",language:e.language??"en",targetAudience:e.targetAudience??"General Audience",blogFormat:e.blogFormat??"narrative",customInstructions:e.customInstructions??"",includeImages:e.includeImages??!0,includeTableOfContents:e.includeTableOfContents??!1})});if(!i.ok)throw new F(await i.text(),i.status,i.status===404?3:1);return i}async function Sr(n){let t=new URLSearchParams;n&&t.set("teamId",n);let e=t.toString();return L(`/api/cli/limits${e?`?${e}`:""}`)}async function Gn(n,t,e){let o=await Sr(e);if(!o.canGenerate[n]){let r=o.remaining[n]??0,i=o.limits[n]??0;throw i===0?new F(`The "${n}" mode is not available on your ${o.planName} plan. Available modes: ${o.availableModes.join(", ")||"none"}`,403,2):new F(`You have reached your ${n} generation limit for this billing cycle (${o.usage[n]??0}/${i} used). Try a different mode: ${o.availableModes.join(", ")||"none available"}`,403,4)}if(o.maxSlidesPerPresentation!==-1&&t>o.maxSlidesPerPresentation)throw new F(`Maximum ${o.maxSlidesPerPresentation} slides allowed on your ${o.planName} plan (requested: ${t}). Try a different mode: ${o.availableModes.join(", ")||"none available"}`,403,6);return o}function Wn(n){return n.replace(/[\u2014\u2013]/g,"-").replace(/[\u201C\u201D]/g,'"').replace(/[\u2018\u2019]/g,"'").replace(/\u2026/g,"...").replace(/\u00A0/g," ").replace(/[\u2010-\u2015]/g,"-").replace(/[\u2032\u2033]/g,"'")}async function ct(n){let t=j();if(!ne())throw new F(`Not authenticated. Run '${m.commands[0]} login' or set ${m.apiKeyEnvVar} environment variable.`,401,2);let e=await de(),o={...n,text:Wn(n.text)},r;try{r=await fetch(`${t}/api/cli/tts`,{method:"POST",headers:{"Content-Type":"application/json",...e},body:JSON.stringify(o)})}catch(y){throw new F(`Network error: ${y instanceof Error?y.message:"Unknown error"}`,0,5)}if(!r.ok){let y=await r.text().catch(()=>"Unknown error"),f;try{let w=JSON.parse(y);f=w.error||w.message||y}catch{f=y}throw new F(f,r.status,r.status===401?2:1)}let i=Buffer.from(await r.arrayBuffer()),s=parseFloat(r.headers.get("X-Duration-Seconds")||"0"),a=parseFloat(r.headers.get("X-Cost-USD")||"0"),c=r.headers.get("X-Provider")||"unknown",d=r.headers.get("X-Audio-Format")||"mp3",u,C=r.headers.get("X-Timestamps");if(C)try{u=JSON.parse(C)}catch{}return{audioData:i,duration:s,cost:a,provider:c,format:d,timestamps:u}}async function Yn(n){let t=j();if(!ne())throw new F(`Not authenticated. Run '${m.commands[0]} login' or set ${m.apiKeyEnvVar} environment variable.`,401,2);let e=await de(),o={...n,texts:n.texts.map(s=>({...s,text:Wn(s.text)}))},r;try{r=await fetch(`${t}/api/cli/tts/batch`,{method:"POST",headers:{"Content-Type":"application/json",...e},body:JSON.stringify(o)})}catch(s){throw new F(`Network error: ${s instanceof Error?s.message:"Unknown error"}`,0,5)}if(!r.ok){let s=await r.text().catch(()=>"Unknown error"),a;try{let c=JSON.parse(s);a=c.error||c.message||s}catch{a=s}throw new F(a,r.status,r.status===401?2:1)}let i=await r.json();return i.results=i.results.map(s=>({...s,audioData:Buffer.from(s.audioData,"base64")})),i}async function Hn(n){let t=n?`/api/cli/tts?provider=${n}`:"/api/cli/tts";return L(t)}async function lt(n){let t=await L("/api/cli/music",{method:"POST",body:n});if(!t.data)throw new F(`Invalid API response: ${JSON.stringify(t)}`,500,1);return{requestId:t.data.id,status:t.data.status,audioUrl:t.data.audioUrl,duration:t.data.duration,cost:t.data.cost,error:t.data.error}}async function ze(n){let t=await L(`/api/cli/music?requestId=${encodeURIComponent(n)}`);return{requestId:t.data.id,status:t.data.status,audioUrl:t.data.audioUrl,duration:t.data.duration,cost:t.data.cost,error:t.data.error}}async function Jn(n){return L("/api/cli/mix",{method:"POST",body:n})}async function Vt(n){return L(`/api/cli/mix?requestId=${encodeURIComponent(n)}`)}async function dt(n){return L("/api/cli/images/search",{method:"POST",body:n})}async function zn(n){return L("/api/cli/images/generate",{method:"POST",body:n})}async function _t(n){return L("/api/cli/videos/search",{method:"POST",body:n})}async function ue(n,t=60,e=2e3){for(let o=0;o<t;o++){let r=await n();if(r.status==="completed"||r.status==="failed")return r;await new Promise(i=>setTimeout(i,e))}throw new F("Operation timed out",408,1)}async function Xn(n){return L("/api/cli/scrape",{method:"POST",body:{url:n}})}async function Kn(n){let t=await L("/api/cli/sfx",{method:"POST",body:n});if(!t.data)throw new F(`Invalid API response: ${JSON.stringify(t)}`,500,1);return{id:t.data.id,status:t.data.status,audioUrl:t.data.audioUrl,duration:t.data.duration,format:t.data.format,cost:t.data.cost,error:t.data.error,requestId:t.data.requestId}}async function qt(n){let t=await L(`/api/cli/sfx?requestId=${encodeURIComponent(n)}`);return{id:t.data.id,status:t.data.status,audioUrl:t.data.audioUrl,duration:t.data.duration,format:t.data.format,cost:t.data.cost,error:t.data.error,requestId:t.data.requestId}}async function Qn(n){return L("/api/cli/video/plan",{method:"POST",body:n})}var ut=new Tr({projectName:"conceptcraft",configName:"feature-cache"}),Cr=3600*1e3,kr=1440*60*1e3;function Zn(n){let t=0;for(let e=0;e<n.length;e++){let o=n.charCodeAt(e);t=(t<<5)-t+o,t=t&t}return t.toString(16)}function eo(){if(!Ce())return null;let n=ut.get("featureFlags");if(!n)return null;let t=Zn(se());if(n.apiKeyHash&&n.apiKeyHash!==t)return he(),null;let e=Date.now()-n.fetchedAt;return e>kr?null:(e>Cr&&Bt(),n.flags)}function Bt(){ge().catch(()=>{})}async function ge(){let n=await qn(),t=se();return ut.set("featureFlags",{flags:n,fetchedAt:Date.now(),apiKeyHash:t?Zn(t):void 0}),n}function he(){ut.delete("featureFlags")}function to(){return ut.path}var Ar=`${m.displayName} CLI`,Or=8765,Er=8775;function Pr(){return io(32).toString("base64url")}function Fr(n){return Ir("sha256").update(n).digest("base64url")}function Dr(){return io(16).toString("hex")}async function Nr(n,t){for(let e=n;e<=t;e++)try{return await new Promise((o,r)=>{let i=ro.createServer();i.listen(e,()=>{i.close(()=>o())}),i.on("error",r)}),e}catch{continue}throw new Error(`No available port found between ${n} and ${t}`)}async function Ur(n){let t=await fetch(`${n}/.well-known/oauth-authorization-server`);if(!t.ok)throw new Error(`Failed to fetch OAuth metadata: ${t.status}`);return t.json()}async function Lr(n,t){let e=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_name:Ar,redirect_uris:[t],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"none",scope:"presentations:read presentations:write"})});if(!e.ok){let o=await e.text();throw new Error(`Client registration failed: ${o}`)}return e.json()}async function Mr(n,t,e,o,r){let i=new URLSearchParams({grant_type:"authorization_code",code:t,redirect_uri:o,client_id:r,code_verifier:e}),s=await fetch(n,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()});if(!s.ok){let a=await s.text();throw new Error(`Token exchange failed: ${a}`)}return s.json()}function jr(n,t){return new Promise((e,o)=>{let r,i=!1,s=()=>{i||(i=!0,clearTimeout(r),process.off("SIGINT",a),process.off("SIGTERM",a),c.close())},a=()=>{s(),o(new Error("Login cancelled"))},c=ro.createServer((d,u)=>{let C=new URL(d.url||"",`http://localhost:${n}`);if(C.pathname!=="/callback"){u.writeHead(404),u.end("Not found");return}let y=C.searchParams.get("code"),f=C.searchParams.get("state"),w=C.searchParams.get("error"),I=C.searchParams.get("error_description");if(u.writeHead(200,{"Content-Type":"text/html"}),w){u.end(`
5
5
  <!DOCTYPE html>
6
6
  <html>
7
7
  <head><title>Login Failed</title></head>
8
8
  <body style="font-family: system-ui; text-align: center; padding: 50px;">
9
9
  <h1 style="color: #dc2626;">Login Failed</h1>
10
- <p>${$||w}</p>
10
+ <p>${I||w}</p>
11
11
  <p>You can close this window.</p>
12
12
  </body>
13
13
  </html>
14
- `),a(),o(new Error($||w));return}if(!h||!f){m.end(`
14
+ `),s(),o(new Error(I||w));return}if(!y||!f){u.end(`
15
15
  <!DOCTYPE html>
16
16
  <html>
17
17
  <head><title>Login Failed</title></head>
@@ -21,7 +21,7 @@ import{Command as Fa}from"commander";import Q from"chalk";import lr from"path";v
21
21
  <p>You can close this window.</p>
22
22
  </body>
23
23
  </html>
24
- `),a(),o(new Error("Missing authorization code or state"));return}if(f!==t){m.end(`
24
+ `),s(),o(new Error("Missing authorization code or state"));return}if(f!==t){u.end(`
25
25
  <!DOCTYPE html>
26
26
  <html>
27
27
  <head><title>Login Failed</title></head>
@@ -31,7 +31,7 @@ import{Command as Fa}from"commander";import Q from"chalk";import lr from"path";v
31
31
  <p>You can close this window.</p>
32
32
  </body>
33
33
  </html>
34
- `),a(),o(new Error("State mismatch"));return}m.end(`
34
+ `),s(),o(new Error("State mismatch"));return}u.end(`
35
35
  <!DOCTYPE html>
36
36
  <html>
37
37
  <head><title>Login Successful</title></head>
@@ -40,9 +40,9 @@ import{Command as Fa}from"commander";import Q from"chalk";import lr from"path";v
40
40
  <p>You can close this window and return to the terminal.</p>
41
41
  </body>
42
42
  </html>
43
- `),a(),e({code:h,state:f})});c.listen(n),process.once("SIGINT",s),process.once("SIGTERM",s),r=setTimeout(()=>{a(),o(new Error("Login timed out - no callback received within 5 minutes"))},300*1e3)})}async function Vr(n,t){let e=await fetch(`${n}/api/cli/whoami`,{headers:{Authorization:`Bearer ${t}`}});if(!e.ok)throw new Error(`Failed to fetch user info: ${e.status}`);return e.json()}async function _r(n){let t=M(),e=no("Discovering OAuth server...").start();try{let o=await Ur(t);e.succeed("Connecting to "+t);let r=await Nr(Or,Er),i=`http://localhost:${r}/callback`;console.log("Redirect URI: "+i),console.log("Authorization endpoint: "+o.authorization_endpoint),console.log("Token endpoint: "+o.token_endpoint),console.log("Registration endpoint: "+o.registration_endpoint);let a=it(),s=at();if(!a){let y=await Lr(o.registration_endpoint,i);a=y.client_id,s=y.client_secret,Tn(a,s)}let c=Pr(),d=Fr(c),m=Dr(),C=new URLSearchParams({client_id:a,redirect_uri:i,response_type:"code",scope:"presentations:read presentations:write",state:m,code_challenge:d,code_challenge_method:"S256"}),h=`${o.authorization_endpoint}?${C}`;console.log("Authorization URL: "+h),n.browser?(p("Opening browser..."),await Rr(h)):(console.log(to.bold("Open this URL in your browser:")),console.log(to.cyan(h)));let f=jr(r,m),{code:w}=await f;e=no("Completing login...").start();let $=await Mr(o.token_endpoint,w,c,i,a);ot($.access_token,$.refresh_token,$.expires_in);let k=await Vr(t,$.access_token);e.succeed("Logged in!"),console.log(),x("Logged in as",k.user.email),k.currentTeam&&(Se(k.currentTeam.id),x("Team",`${k.currentTeam.name} (${k.currentTeam.planName})`));try{await fe()}catch{}console.log(),v("You're all set!"),console.log()}catch(o){throw e.fail("Login failed"),l(o instanceof Error?o.message:String(o)),o}}var io=new $r("login").description(`Authenticate with ${u.displayName} (opens browser)`).option("--no-browser","Print URL instead of opening browser").action(async n=>{console.log(),ue()&&(I("You are already logged in."),p(`Run '${u.commands[0]} logout' to log out first, or continue to re-authenticate.`),console.log());try{await _r(n),process.exit(0)}catch{process.exit(1)}});import{Command as qr}from"commander";import{confirm as Br}from"@inquirer/prompts";var ao=new qr("logout").description("Log out and clear authentication").option("--all","Clear all config including API key").action(async n=>{console.log();let t=ue(),e=Ce();if(!t&&!e){I("You are not logged in."),console.log();return}if(n.all)try{await Br({message:"Clear all configuration including API key?",default:!1})?(tt(),ge(),v("All configuration cleared.")):p("Cancelled.")}catch{p("Cancelled.")}else rt(),ge(),v("Logged out successfully."),e&&p("Note: Your API key is still configured. Use --all to clear everything.");console.log()});import{Command as he}from"commander";import Ke from"chalk";import{input as Gr,password as Wr,confirm as so,select as Yr}from"@inquirer/prompts";import Gt from"ora";var co=new he("config").description("Manage CLI configuration").addCommand(new he("init").description("Initialize configuration interactively").action(async()=>{console.log(),console.log(Ke.bold(`${u.displayName} CLI Configuration`)),console.log(Ke.gray("\u2500".repeat(35))),console.log();try{let n=await Wr({message:"Enter your API key:",mask:"*",validate:o=>!o||o.trim().length===0?"API key is required":Lt(o.trim())?!0:"Invalid API key format. Keys should start with 'cc_slides_' or 'mcp_'"});if(Ft(n.trim()),await so({message:`Use a custom API URL? (default: ${u.apiUrl.replace("https://","")})`,default:!1})){let o=await Gr({message:"Enter API URL:",default:M(),validate:r=>{try{return new URL(r),!0}catch{return"Invalid URL format"}}});Dt(o)}console.log();let e=Gt("Verifying API key...").start();try{let o=await pe();if(e.succeed("API key verified!"),console.log(),p(`Logged in as: ${o.user.email}`),o.teams.length===0)I("No teams found for this user.");else if(o.teams.length===1){let r=o.teams[0];Se(r.id),p(`Team: ${r.name} (${r.planName})`)}else{console.log(),p(`You have access to ${o.teams.length} teams.`);let r=await Yr({message:"Select your default team:",choices:o.teams.map(a=>({name:`${a.name} (${a.planName}) - ${a.role}${a.isCurrent?" [current]":""}`,value:a.id})),default:o.currentTeam?.id});Se(r);let i=o.teams.find(a=>a.id===r);v(`Selected team: ${i?.name}`)}try{await fe()}catch{}}catch(o){e.fail("Failed to verify API key"),I(`Could not verify API key: ${o instanceof Error?o.message:String(o)}`),I(`You may need to set the team ID manually: ${u.commands[0]} config set team-id <id>`)}console.log(),v("Configuration saved!"),p(`Config file: ${nt()}`),console.log()}catch(n){if(n.name==="ExitPromptError"){console.log(),p("Configuration cancelled.");return}throw n}})).addCommand(new he("show").description("Show current configuration").option("--verify","Verify API key and show team details").action(async n=>{let t=wn();if(ee("Current Configuration"),console.log(),x("API Key",Pn()??Ke.red("Not set")),x("API URL",t.apiUrl),x("Default Team ID",t.defaultTeamId??Ke.gray("Not set")),console.log(),x("Config file",nt()),n.verify&&t.apiKey){console.log();let e=Gt("Verifying...").start();try{let o=await pe();e.succeed("Verified"),console.log(),x("User",o.user.email),o.currentTeam&&x("Current Team",`${o.currentTeam.name} (${o.currentTeam.planName})`),o.teams.length>1&&x("Total Teams",String(o.teams.length))}catch(o){e.fail("Verification failed"),I(o instanceof Error?o.message:String(o))}}console.log()})).addCommand(new he("set").description("Set a configuration value").argument("<key>","Configuration key (api-key, api-url, team-id)").argument("<value>","Value to set").action(async(n,t)=>{switch(n){case"api-key":Lt(t)||(l("Invalid API key format. Keys should start with 'cc_slides_' or 'mcp_'"),process.exit(6)),Ft(t),ge(),v("API key updated"),fe().catch(()=>{});break;case"api-url":try{new URL(t),Dt(t),v(`API URL set to: ${t}`)}catch{l("Invalid URL format"),process.exit(6)}break;case"team-id":Se(t),v(`Default team ID set to: ${t}`);break;default:l(`Unknown config key: ${n}`),console.log(Ke.gray("Valid keys: api-key, api-url, team-id")),process.exit(6)}})).addCommand(new he("clear").description("Clear all configuration").action(async()=>{try{await so({message:"Are you sure you want to clear all configuration?",default:!1})?(tt(),ge(),v("Configuration cleared")):p("Cancelled")}catch{p("Cancelled")}})).addCommand(new he("refresh").description("Refresh cached feature flags").action(async()=>{let n=Gt("Refreshing feature flags...").start();try{await fe(),n.succeed("Feature flags refreshed"),p(`Run '${u.commands[0]} --help' to see updated commands`)}catch(t){n.fail("Failed to refresh"),l(t instanceof Error?t.message:String(t)),process.exit(1)}})).addCommand(new he("path").description("Show configuration file path").option("--cache","Show feature cache file path").action(n=>{n.cache?console.log(eo()):console.log(nt())}));import{Command as Kr}from"commander";import H from"chalk";import Xr from"path";import{createParser as Hr}from"eventsource-parser";import Y from"chalk";import Jr from"ora";async function zr(n,t,e={}){let o=n.body?.getReader();if(!o)throw new Error("Response body is not readable");let r=new TextDecoder,i,a,s,c=0,d=0,m=0,C={},h=Hr({onEvent:w=>{if(w.data!=="[DONE]")try{let $=JSON.parse(w.data),{type:k,data:y}=$;switch(e.debug&&console.log(Y.gray(`[SSE] ${k}:`),y),t.onData?.(k,y),k){case"data-id":i=y;break;case"data-slug":a=y;break;case"data-title":s=y;break;case"data-slides-number-of-slides":c=y;break;case"data-slide-progress":{let R=y;d=R.current,c=R.total,t.onProgress?.(d,c),t.onSlide?.(d,c);break}case"data-overall-progress":{let R=y;t.onPhase?.(R.phase,R.percentage),R.details?.slides&&(d=R.details.slides.complete,c=R.details.slides.total,t.onProgress?.(d,c),t.onSlide?.(d,c));break}case"data-structure-tokens":{m=y,t.onTokens?.(m);break}case"data-slide-meta-tokens":{let[R,T]=y.split(":");if(R&&T){C[R]=parseInt(T,10);let g=Object.values(C).reduce((A,B)=>A+B,0);m=Math.max(m,g),t.onTokens?.(m+g)}break}case"data-generation-meta-estimated-time":{t.onEstimatedTime?.(y);break}case"data-finish":t.onComplete?.({id:i,slug:a,title:s,slidesCount:c});break;case"error":y&&t.onError?.(y);break}}catch{e.debug&&console.log(Y.gray("[SSE Raw]"),w.data)}}}),f=!1;for(;!f;){let w=await o.read();if(f=w.done,w.value){let $=r.decode(w.value,{stream:!0});h.feed($)}}return{id:i,slug:a,title:s,slidesCount:c}}async function lo(n,t,e){let o=$n()&&!e.noStream&&!e.quiet&&!e.json;e.json||(console.log(),console.log(Y.bold(`Creating presentation: "${t}"`)),console.log(Y.gray(`Quality: ${e.mode} | Tone: ${e.tone??"professional"} | Slides: ${e.slideCount} | Language: ${e.language}`)),console.log());let r,i="",a="Preparing",s=0,c={done:0,total:e.slideCount},d=0,m=0,C=Date.now(),h,f=g=>{let A=Math.floor(g/60),B=g%60;return`${A}:${B.toString().padStart(2,"0")}`},w=()=>Math.floor((Date.now()-C)/1e3),$=()=>{if(!m)return" \u2014:\u2014\u2014";let g=Math.max(0,m-w());return g===0&&s<100?"soon!":f(g)},k=g=>g>=1e3?`${(g/1e3).toFixed(1)}k`.padStart(5," "):`${g}tk`.padStart(5," "),y=g=>({"structure-generation":"Planning ","slide-generation":"Writing ","image-generation":"Images ",assembling:"Finishing",completed:"Done "})[g]||"Working ",R=()=>{let g=On(s,100,20,!1),A=String(s).padStart(3," "),B=y(a),z=`${String(c.done).padStart(2," ")}/${String(c.total).padEnd(2," ")}`,oe=k(d),ve=f(w()).padStart(5," "),Ge=$().padStart(5," ");return`${g} ${Y.bold(A)}${Y.gray("%")} ${Y.cyan(B)} ${Y.gray(z)} ${Y.yellow(oe)} ${Y.gray(ve)} ${Y.green(Ge+" left")}`};return o&&(r=Jr({text:R(),spinner:"dots"}).start(),h=setInterval(()=>{r&&r.isSpinning&&(r.text=R())},100)),{...await zr(n,{onProgress:(g,A)=>{if(c={done:g,total:A},!o&&!e.quiet&&!e.json){let B=`${a.trim()}: slide ${g}/${A}`;B!==i&&(console.log(B),i=B)}},onPhase:(g,A)=>{a=y(g),s=A},onTokens:g=>{d=g},onEstimatedTime:g=>{m=g},onError:g=>{h&&clearInterval(h),r?r.fail(Y.red(`Error: ${g}`)):e.json||console.error(Y.red(`Error: ${g}`))},onComplete:g=>{if(h&&clearInterval(h),r)s=100,a="Done",r.succeed(R());else if(!e.json){let A=d>0?` | ${d.toLocaleString()} tokens`:"";console.log(`Done! [${f(w())}${A}]`)}}},{debug:e.debug}),elapsedSeconds:w(),totalTokens:d}}async function mo(n,t={}){let e=n.body?.getReader();if(!e)throw new Error("Response body is not readable");let o=new TextDecoder,r="",i=!1;for(;!i;){let a=await e.read();if(i=a.done,a.value){let s=o.decode(a.value,{stream:!0});r+=s,t.quiet||process.stdout.write(s)}}return t.quiet||console.log(),r}import{readFileSync as Qr,existsSync as Zr}from"fs";import{resolve as uo}from"path";var po=new Kr("create").description("Create a new presentation").argument("<topic>","The topic or title for the presentation").option("-n, --slides <count>","Number of slides (1-20)").option("-m, --mode <mode>","Generation quality (best, balanced, fast, ultrafast, instant)").option("-t, --tone <tone>","Tone (creative, professional, educational, formal, casual)").option("--amount <amount>","Content density (minimal, concise, detailed, extensive)").option("--audience <text>","Target audience description").option("-l, --language <lang>","Output language").option("--branding-id <id>","Branding ID (from `ccr branding list` or `ccr branding extract`)").option("-c, --context <text>","Inline text context (research notes, key facts)").option("--context-file <path>","Path to a context file (text, markdown, JSON)").option("--stdin","Read context from stdin").option("-f, --file <paths...>","Files to upload (PDF, PPTX, DOCX, images)").option("-g, --goal <type>","Goal (inform, persuade, train, learn, entertain, report)").option("--styling <mode>","Styling mode (freeform, brand-only, brand-plus-style, style-only, no-styling)").option("--reference-url <url>","Image URL to use as visual style reference").option("--thinking-depth <depth>","AI thinking depth (quick, moderate, deep, profound)").option("--theme <preset>","[instant mode only] Color theme preset (blue, violet, rose, orange, green)").option("--primary-color <hex>","[instant mode only] Primary color (e.g., #0066CC)").option("--secondary-color <hex>","[instant mode only] Secondary color").option("--accent-color <hex>","[instant mode only] Accent color").option("--background-color <hex>","[instant mode only] Background color").option("--foreground-color <hex>","[instant mode only] Foreground/text color").option("--decorations <style>","[instant mode only] Background decoration (none, waves-bottom-left, waves-top-right, blob-corners, minimal)").option("--team-id <id>","Team ID (switch teams)").option("-o, --output <format>","Output format (human, json, quiet)").option("--no-stream","Wait for completion without streaming progress").option("--debug","Enable debug logging").option("--open","Open in browser after creation").option("--id <uuid>","Use a specific UUID for the presentation").option("--studio","Studio mode: use current directory name as presentation ID (auto-links to Studio preview)").action(async(n,t)=>{await F();let e;t.slides!==void 0&&(e=parseInt(t.slides,10),(isNaN(e)||e<1||e>20)&&(l("Slide count must be between 1 and 20"),process.exit(6)));let o=["best","balanced","fast","ultrafast","instant"];t.mode&&!o.includes(t.mode)&&(l(`Invalid mode: ${t.mode}. Valid: ${o.join(", ")}`),process.exit(6));let r=["creative","professional","educational","formal","casual"];t.tone&&!r.includes(t.tone)&&(l(`Invalid tone: ${t.tone}. Valid: ${r.join(", ")}`),process.exit(6));let i=["minimal","concise","detailed","extensive"];t.amount&&!i.includes(t.amount)&&(l(`Invalid amount: ${t.amount}. Valid: ${i.join(", ")}`),process.exit(6));let a=["freeform","brand-only","brand-plus-style","style-only","no-styling"];t.styling&&!a.includes(t.styling)&&(l(`Invalid styling: ${t.styling}. Valid: ${a.join(", ")}`),process.exit(6));let s=["quick","moderate","deep","profound"];t.thinkingDepth&&!s.includes(t.thinkingDepth)&&(l(`Invalid thinking-depth: ${t.thinkingDepth}. Valid: ${s.join(", ")}`),process.exit(6));let c=["inform","persuade","train","learn","entertain","report"];t.goal&&!c.includes(t.goal)&&(l(`Invalid goal: ${t.goal}. Valid: ${c.join(", ")}`),process.exit(6));let d=["blue","violet","rose","orange","green"];t.theme&&!d.includes(t.theme)&&(l(`Invalid theme: ${t.theme}. Valid: ${d.join(", ")}`),process.exit(6));let m=["none","waves-bottom-left","waves-top-right","blob-corners","minimal"];t.decorations&&!m.includes(t.decorations)&&(l(`Invalid decorations: ${t.decorations}. Valid: ${m.join(", ")}`),process.exit(6)),(t.theme||t.primaryColor||t.secondaryColor||t.accentColor||t.backgroundColor||t.foregroundColor||t.decorations)&&t.mode&&t.mode!=="instant"&&(l("--theme, --primary-color, --decorations and other color options are only supported with --mode instant"),process.exit(6));let h=/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;for(let[T,g]of[["primary-color",t.primaryColor],["secondary-color",t.secondaryColor],["accent-color",t.accentColor],["background-color",t.backgroundColor],["foreground-color",t.foregroundColor]])g&&!h.test(g)&&(l(`Invalid ${T}: ${g}. Must be hex (e.g., #0066CC)`),process.exit(6));try{t.output!=="json"&&t.output!=="quiet"&&process.stdout.write(H.gray("Checking generation limits... "));let T=await Bn(t.mode??"fast",e??10,t.teamId);t.output!=="json"&&t.output!=="quiet"&&(console.log(H.green("\u2713")),console.log(H.gray(` Plan: ${T.planName} | ${t.mode??"fast"}: ${T.remaining[t.mode??"fast"]}/${T.limits[t.mode??"fast"]} remaining`)))}catch(T){t.output==="json"?console.log(JSON.stringify({success:!1,error:T instanceof Error?T.message:String(T)})):(console.log(H.red("\u2717")),l(T instanceof Error?T.message:String(T))),process.exit(T.exitCode??1)}let f=[];if(t.file&&t.file.length>0){for(let T of t.file)Zr(uo(T))||(l(`File not found: ${T}`),process.exit(6));t.output!=="json"&&t.output!=="quiet"&&console.log(H.gray(`
44
- Uploading ${t.file.length} file(s)...`));try{f=await Dn(t.file.map(T=>uo(T)),(T,g,A)=>{t.output!=="json"&&t.output!=="quiet"&&A&&process.stdout.write(`\r ${H.cyan("\u2B06")} Uploading: ${A} (${T+1}/${g})`)}),t.output!=="json"&&t.output!=="quiet"&&console.log(`\r ${H.green("\u2713")} Uploaded ${f.length} file(s) `)}catch(T){l(`Failed to upload files: ${T instanceof Error?T.message:String(T)}`),process.exit(1)}}let w;(t.stdin||!process.stdin.isTTY)&&(w=await ei(),t.stdin&&!w&&(l("No content received from stdin"),process.exit(6)));let $=t.context;if(t.contextFile)try{$=Qr(t.contextFile,"utf-8"),$.trim()||(l(`Context file is empty: ${t.contextFile}`),process.exit(6))}catch{l(`Failed to read context file: ${t.contextFile}`),process.exit(6)}!w&&!$&&f.length===0&&(l("Context is required to create a presentation."),console.log(),console.log(H.gray(" -f, --file <paths...> Upload files (PDF, PPTX, images)")),console.log(H.gray(" -c, --context <text> Inline text context")),console.log(H.gray(" --context-file <path> Read from a file")),console.log(H.gray(` cat file | ${u.commands[0]} Pipe content`)),process.exit(6));let k=[...f];w&&k.push({id:`stdin-${Date.now()}`,content:w,title:"Piped Content",mime:"text/plain",selected:!0}),$&&k.push({id:`context-${Date.now()}`,content:$,title:"Context",mime:"text/plain",selected:!0});let y,R=t.primaryColor||t.secondaryColor||t.accentColor||t.backgroundColor||t.foregroundColor;(t.theme||R||t.decorations)&&(y={},t.theme&&(y.preset=t.theme),R&&(y.custom={},t.primaryColor&&(y.custom.primary=t.primaryColor),t.secondaryColor&&(y.custom.secondary=t.secondaryColor),t.accentColor&&(y.custom.accent=t.accentColor),t.backgroundColor&&(y.custom.background=t.backgroundColor),t.foregroundColor&&(y.custom.foreground=t.foregroundColor)),t.decorations&&(y.decorations=t.decorations));try{let T=await Nn({topic:n,...e!==void 0&&{slideCount:e},...t.mode&&{mode:t.mode},...t.tone&&{tone:t.tone},...t.amount&&{amount:t.amount},...t.audience&&{audience:t.audience},...t.language&&{language:t.language},...t.brandingId&&{brandingId:t.brandingId},...t.styling&&{stylingMode:t.styling},...t.referenceUrl&&{referenceUrl:t.referenceUrl},...t.thinkingDepth&&{thinkingDepth:t.thinkingDepth},...t.goal&&{goal:t.goal},...t.teamId&&{teamId:t.teamId},...y&&{theme:y},...t.studio?{documentId:Xr.basename(process.cwd())}:t.id?{documentId:t.id}:{},...k.length>0&&{contentSources:{uploadedFiles:k,contextFiles:[]}}}),g=await lo(T,n,{slideCount:e,mode:t.mode,tone:t.tone,language:t.language,noStream:t.noStream,debug:t.debug,quiet:t.output==="quiet",json:t.output==="json"});if(t.output==="json")console.log(JSON.stringify({success:!0,presentation:{id:g.id,slug:g.slug,title:g.title??n,slidesCount:g.slidesCount,elapsedSeconds:g.elapsedSeconds,totalTokens:g.totalTokens},viewUrl:ke(g.slug,t.language??"en")},null,2));else{console.log(),v("Presentation created successfully"),console.log(),x("Title",g.title??n),x("Slides",String(g.slidesCount??e??"\u2014"));let A=[];if(g.elapsedSeconds){let z=Math.floor(g.elapsedSeconds/60),oe=g.elapsedSeconds%60;A.push(z>0?`${z}m ${oe}s`:`${oe}s`)}g.totalTokens&&A.push(`${g.totalTokens.toLocaleString()} tokens`),A.length>0&&x("Generated in",A.join(" \xB7 ")),console.log();let B=ke(g.slug,t.language??"en");B!=="N/A"&&(console.log(H.bold(" Open: ")+H.cyan.underline(B)),t.open&&await(await import("open")).default(B)),console.log()}}catch(T){t.output==="json"?console.log(JSON.stringify({success:!1,error:T instanceof Error?T.message:String(T)})):l(T instanceof Error?T.message:String(T)),process.exit(T.exitCode??1)}});async function ei(){return new Promise(n=>{let t="";if(process.stdin.setEncoding("utf8"),process.stdin.isTTY){n("");return}process.stdin.on("data",e=>{t+=e}),process.stdin.on("end",()=>{n(t.trim())}),setTimeout(()=>{n(t.trim())},100)})}import{Command as ti}from"commander";var fo=new ti("list").description("List presentations").option("-n, --limit <count>","Number of results to return","20").option("-f, --format <format>","Output format (table, json, ids)","table").option("--sort <field>","Sort by field (created, updated, title)").option("--team-id <id>","Team ID (uses default if not specified)").option("-d, --detail","Show detailed output including URLs").option("-l, --language <lang>","Language for URLs","en").action(async n=>{await F();let t=parseInt(n.limit,10);(isNaN(t)||t<1)&&(l("Invalid limit value"),process.exit(6));let e=n.teamId??et();e||(l("`Team ID required. Set a default with '${brand.commands[0]} config set team-id <id>' or use --team-id`"),process.exit(6));try{let o=await Un(e,t);if(o.length===0){n.format==="json"?console.log(JSON.stringify([])):n.format!=="ids"&&p("No presentations found");return}switch(n.sort&&o.sort((r,i)=>{switch(n.sort){case"created":return new Date(i.createdAt).getTime()-new Date(r.createdAt).getTime();case"title":return(r.title||"").localeCompare(i.title||"");default:return 0}}),n.format){case"json":console.log(JSON.stringify(o,null,2));break;case"ids":console.log(Rn(o));break;default:console.log(In(o,{showLinks:n.detail,language:n.language}));break}}catch(o){l(o instanceof Error?o.message:String(o)),process.exit(o.exitCode??1)}});import{Command as ni}from"commander";import ut from"chalk";var go=new ni("get").description("Get presentation details").argument("<slug>","Presentation slug (e.g., my-presentation-v1-abc123)").option("-f, --format <format>","Output format (summary, full, json)","summary").option("--include <fields>","Fields to include (comma-separated: slides,styling)").option("-l, --language <lang>","Language for view URL","en").action(async(n,t)=>{await F();try{let e=await Te(n);if(t.format==="json"){console.log(JSON.stringify(e,null,2));return}let o=ke(e.slug,t.language);ee("Presentation Details"),console.log(),x("Slug",e.slug),x("Title",e.title||"Untitled"),x("Description",e.description||ut.gray("None")),x("Slides",String(e.numberOfSlides||"-")),x("Mode",e.mode||"-"),x("Created",Ut(e.createdAt)),e.updatedAt&&x("Updated",Ut(e.updatedAt)),console.log(),o!=="N/A"&&console.log(ut.bold(" Open: ")+ut.cyan.underline(o)),console.log(),t.format==="full"&&t.include?.includes("slides")&&(console.log(ut.gray("(Full slide content available in JSON format)")),console.log())}catch(e){l(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}});import{Command as oi}from"commander";import{confirm as ri}from"@inquirer/prompts";var ho=new oi("delete").description("Delete a presentation").argument("<slug>","Presentation slug (e.g., my-presentation-v1-abc123)").option("-f, --force","Skip confirmation prompt").option("-q, --quiet","Suppress output").action(async(n,t)=>{if(await F(),!t.force)try{if(!await ri({message:`Are you sure you want to delete presentation "${n}"?`,default:!1})){t.quiet||I("Deletion cancelled");return}}catch{t.quiet||I("Deletion cancelled");return}try{await Ln(n),t.quiet||v(`Presentation "${n}" deleted`)}catch(e){l(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}});import{Command as ii}from"commander";import{writeFile as ai}from"fs/promises";import{resolve as yo}from"path";import si from"ora";var bo=new ii("export").description("Export a presentation to ZIP").argument("<slug>","Presentation slug (e.g., my-presentation-v1-abc123)").option("-o, --output <path>","Output file path").option("--include-images","Include images (default: true)",!0).option("--include-branding","Include branding (default: true)",!0).option("--no-external","Skip external image downloads").action(async(n,t)=>{await F();let e=si("Fetching presentation...").start();try{let o=await Te(n),r=o.title||n,i=o.id,a=n.replace(/[^a-z0-9-]/gi,"_").toLowerCase().substring(0,50),s=new Date().toISOString().split("T")[0],c=`${a}_${s}.zip`,d=t.output?yo(t.output):yo(process.cwd(),c);e.text=`Exporting "${r}"...`;let m=await Mn(i,{includeImages:t.includeImages,includeBranding:t.includeBranding,includeExternal:!t.noExternal});e.text="Saving file...",await ai(d,Buffer.from(m)),e.succeed("Export complete!"),console.log(),p(`File saved: ${d}`),p(`Size: ${ci(m.byteLength)}`),console.log()}catch(o){e.fail("Export failed"),l(o instanceof Error?o.message:String(o)),process.exit(o.exitCode??1)}});function ci(n){return n<1024?`${n} B`:n<1024*1024?`${(n/1024).toFixed(1)} KB`:`${(n/(1024*1024)).toFixed(1)} MB`}import{Command as li}from"commander";import{readFile as di}from"fs/promises";import{resolve as mi,basename as ui}from"path";import pi from"ora";var vo=new li("import").description("Import a presentation from ZIP (admin only)").argument("<file>","Path to ZIP file");vo._hidden=!0;var xo=vo.option("--dry-run","Validate without importing").option("--overwrite","Overwrite existing presentations").option("--remap-ids","Generate new IDs (default: true)",!0).action(async(n,t)=>{await F();try{(await pe()).user.role!=="admin"&&(l("This command is only available to administrators"),process.exit(2))}catch{l("Failed to verify permissions"),process.exit(2)}let e=mi(n),o=ui(e);o.endsWith(".zip")||(l("File must be a ZIP archive"),process.exit(6));let r=pi("Reading file...").start();try{let i=await di(e);t.dryRun?r.text="Validating...":r.text="Importing presentation...";let a=await jn(i,o,{dryRun:t.dryRun});if(a.success){if(t.dryRun)r.succeed("Validation passed!"),console.log(),p("The file is valid and can be imported."),a.statistics&&(console.log(),x("Slides",String(a.statistics.slidesImported)),x("Images",String(a.statistics.imagesUploaded)));else if(r.succeed("Import complete!"),console.log(),x("Presentation ID",a.presentationId??"N/A"),x("Document ID",a.documentId??"N/A"),a.statistics&&(x("Slides imported",String(a.statistics.slidesImported)),x("Images uploaded",String(a.statistics.imagesUploaded)),x("Time",`${a.statistics.totalTimeMs}ms`)),a.presentationId){let s=M();x("View URL",`${s}/p/${a.presentationId}`)}if(a.warnings&&a.warnings.length>0){console.log();for(let s of a.warnings)I(s)}console.log()}else{if(r.fail("Import failed"),console.log(),a.errors)for(let s of a.errors)l(`${s.type}: ${s.message}`);process.exit(1)}}catch(i){r.fail("Import failed"),i.code==="ENOENT"&&(l(`File not found: ${e}`),process.exit(3)),l(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}});import{Command as $e}from"commander";import _ from"chalk";import fi from"ora";import{writeFile as wo}from"fs/promises";var So=new $e("branding").description("Manage brand profiles").addCommand(new $e("list").description("List brand profiles").option("-f, --format <format>","Output format (table, json)","table").action(async n=>{await F();try{let t=await Mt();if(t.brandings.length===0){n.format==="json"?console.log(JSON.stringify([])):(p("No brand profiles found"),console.log(),console.log(_.gray("`Create one with: ${brand.commands[0]} branding extract <url>`")));return}n.format==="json"?console.log(JSON.stringify(t.brandings,null,2)):console.log(An(t.brandings))}catch(t){l(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}})).addCommand(new $e("get").description("Get brand profile details").argument("<id>","Brand profile ID").option("-f, --format <format>","Output format (summary, json)","summary").option("-o, --output <path>","Save JSON to file").action(async(n,t)=>{await F();try{let e=await jt(n);if(t.output){await wo(t.output,JSON.stringify(e,null,2)),v(`Brand profile saved to ${t.output}`);return}if(t.format==="json")console.log(JSON.stringify(e,null,2));else{if(ee("Brand Profile"),console.log(),x("ID",e.id),x("Name",e.name),x("Source URL",e.sourceUrl??_.gray("None")),x("Default",e.isDefault?_.green("Yes"):"No"),e.createdAt&&x("Created",new Date(e.createdAt).toLocaleString()),console.log(),e.primaryColor||e.colors.length>0){if(console.log(_.bold(" Colors")),e.primaryColor){let r=_.bgHex(e.primaryColor)(" ");console.log(` Primary: ${r} ${e.primaryColor}`)}if(e.colors.length>0){console.log(" Palette:");for(let r of e.colors.slice(0,10)){let i=_.bgHex(r.hex)(" "),a=r.role?_.gray(` (${r.role})`):"";console.log(` ${i} ${r.hex}${a}`)}}console.log()}e.logoUrl&&(console.log(_.bold(" Logo")),console.log(` ${e.logoUrl}`),console.log());let o=e.typography;o&&Object.keys(o).length>0&&(console.log(_.bold(" Typography")),(o.primary||o.headings)&&console.log(` Headings: ${o.primary||o.headings||"-"}`),(o.secondary||o.body)&&console.log(` Body: ${o.secondary||o.body||"-"}`),console.log()),(e.confidence||e.extractionMethod)&&(console.log(_.bold(" Extraction")),e.confidence&&console.log(` Confidence: ${Math.round(e.confidence*100)}%`),e.extractionMethod&&console.log(` Method: ${e.extractionMethod}`),console.log()),console.log(_.gray(" Use --format json for full details")),console.log()}}catch(e){l(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}})).addCommand(new $e("find").description("Find existing brand profile by name or URL").argument("<query>","Brand name or website URL to search for").action(async n=>{await F();try{let t=await Mt(),e=n.toLowerCase().replace(/^https?:\/\//,"").replace(/\/$/,""),o=t.brandings.filter(r=>{let i=(r.name||"").toLowerCase(),a=(r.sourceUrl||"").toLowerCase().replace(/^https?:\/\//,"").replace(/\/$/,"");return i.includes(e)||a.includes(e)||i.length>0&&e.includes(i)||a.length>0&&e.includes(a)});if(o.length===0){p(`No brand profiles matching "${n}"`),console.log(_.gray(` Extract one with: ${u.commands[0]} branding extract <url>`));return}console.log(`Found ${o.length} brand${o.length>1?"s":""}:
45
- `);for(let r of o){let i=r.primaryColor?_.bgHex(r.primaryColor)(" ")+" "+r.primaryColor:"";console.log(` ${_.bold(r.name)} ${_.gray(r.id)}`),r.sourceUrl&&console.log(` ${_.gray(r.sourceUrl)}`),i&&console.log(` ${i}`),console.log()}console.log(_.gray(` Export with: ${u.commands[0]} branding get <id> -o branding.json`))}catch(t){l(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}})).addCommand(new $e("extract").description("Extract brand profile from a website").argument("<url>","Website URL to extract branding from").option("--team-id <id>","Team ID").option("--no-save","Extract without saving").option("-o, --output <path>","Save JSON to file").action(async(n,t)=>{await F();try{new URL(n.startsWith("http")?n:`https://${n}`)}catch{l("Invalid URL format"),process.exit(6)}let e=n.startsWith("http")?n:`https://${n}`,o=t.teamId??et(),r=fi({text:`Extracting branding from ${e}...`,stream:process.stdout}).start();try{let i=await Vn(e,o),a=await jt(i.id);r.succeed("Branding extracted!");let s=JSON.stringify(a,null,2);t.output?(await wo(t.output,s),v(`Brand profile saved to ${t.output}`)):console.log(s),console.log()}catch(i){r.fail("Extraction failed"),l(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}})).addCommand(new $e("set-default").description("Set a brand profile as default").argument("<id>","Brand profile ID").action(async n=>{await F(),p(`To set brand ${n} as default, use the web dashboard.`),console.log(),console.log(_.gray("API support for setting default brand is coming soon."))}));import{Command as Ie}from"commander";import Co from"chalk";import gi from"ora";function hi(){return new Ie("blog").description("Generate a blog post from a presentation").argument("<slug>","Presentation slug").option("--words <count>","Target word count (50-2000)","300").option("--tone <tone>","Writing tone (professional, casual, educational)","professional").option("--audience <text>","Target audience description").option("-f, --format <format>","Output format (human, json, markdown)","human").option("--instructions <text>","Custom instructions for the blog").option("--no-images","Exclude image references").option("--toc","Include table of contents").action(async(n,t)=>{await F();let e=parseInt(t.words,10);(isNaN(e)||e<50||e>2e3)&&(l("Word count must be between 50 and 2000"),process.exit(6));let o=["professional","casual","educational"];o.includes(t.tone)||(l(`Invalid tone. Valid options: ${o.join(", ")}`),process.exit(6));let r=gi("Fetching presentation...").start();try{let i=await Te(n);r.text="Generating blog post...";let a=await qn(i.id,i.documentCreatedAt||i.createdAt,{targetWordCount:e,tone:t.tone,targetAudience:t.audience??"General Audience",customInstructions:t.instructions??"",includeImages:!t.noImages,includeTableOfContents:t.toc??!1}),s=await mo(a,{quiet:!0});r.succeed("Blog generated"),t.format==="json"?console.log(JSON.stringify({presentationId:n,title:i.title,wordCount:e,tone:t.tone,content:s},null,2)):t.format==="markdown"?console.log(s):(console.log(),console.log(Co.bold(`Blog: ${i.title}`)),console.log(Co.gray("\u2500".repeat(40))),console.log(),console.log(s),console.log())}catch(i){r.fail("Generation failed"),l(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}})}function yi(){return new Ie("tweets").description("Generate tweets from a presentation").argument("<slug>","Presentation slug").option("--count <n>","Number of tweets to generate","5").option("-f, --format <format>","Output format (human, json)","human").action(async(n,t)=>{await F(),p("Tweet generation coming soon.")})}function bi(){return new Ie("linkedin").description("Generate a LinkedIn carousel from a presentation").argument("<slug>","Presentation slug").option("-f, --format <format>","Output format (human, json)","human").action(async n=>{await F(),p("LinkedIn carousel generation coming soon.")})}function vi(){return new Ie("questions").description("Generate questions for a presentation").argument("<slug>","Presentation slug").option("--count <n>","Number of questions","10").option("-f, --format <format>","Output format (human, json)","human").action(async(n,t)=>{await F(),p("Question generation coming soon.")})}function xi(){return new Ie("cheatsheet").description("Generate a presenter cheat sheet").argument("<slug>","Presentation slug").option("--mode <mode>","Cheat sheet mode (qa-prep, talking-points)","qa-prep").option("-f, --format <format>","Output format (human, json, markdown)","human").action(async(n,t)=>{await F(),p("Cheat sheet generation coming soon.")})}function ko(){let n=new Ie("derive").description("Generate derivative content from a presentation"),t=Zn();return t&&(t.deckToBlog&&n.addCommand(hi()),t.deckToTweets&&n.addCommand(yi()),t.linkedInCarousel&&n.addCommand(bi()),t.redTeamQuestions&&n.addCommand(vi()),t.presenterCheatSheet&&n.addCommand(xi())),n}import{Command as wi}from"commander";import Wt from"chalk";var To=new wi("ideas").description("Generate presentation topic ideas").option("--context <text>","Custom context for idea generation").option("--count <n>","Number of ideas to generate","5").option("-f, --format <format>","Output format (human, json)","human").action(async n=>{await F(),p("Idea generation is available in the web dashboard."),console.log(),console.log(Wt.gray("The CLI will support idea generation in a future release.")),console.log(),console.log("For now, try these approaches:"),console.log(Wt.gray("` 1. Visit the ${brand.displayName} dashboard and use the idea generator`")),console.log(Wt.gray(" 2. Create a presentation with a broad topic and refine it")),console.log()});import{Command as Si}from"commander";import Yt from"chalk";var $o=new Si("whoami").description("Show current user and team information").option("-f, --format <format>","Output format (human, json)","human").action(async n=>{await F();try{let t=await pe();if(Bt(),n.format==="json"){console.log(JSON.stringify(t,null,2));return}if(ee("User"),console.log(),x("Email",t.user.email),t.user.username&&x("Username",t.user.username),(t.user.firstName||t.user.lastName)&&x("Name",[t.user.firstName,t.user.lastName].filter(Boolean).join(" ")),x("Auth Type",t.authType==="apiKey"?"API Key":"Session"),t.currentTeam&&(console.log(),ee("Current Team"),console.log(),x("ID",t.currentTeam.id),x("Name",t.currentTeam.name),x("Plan",t.currentTeam.planName),x("Role",t.currentTeam.isOwner?"Owner":"Member")),t.teams.length>1){console.log(),ee("All Teams"),console.log();for(let e of t.teams){let o=e.isCurrent?Yt.green(" (current)"):"";console.log(` ${Yt.bold(e.name)}${o}`),console.log(Yt.gray(` ID: ${e.id} | Plan: ${e.planName} | Role: ${e.role}`))}}console.log()}catch(t){l(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}});import{Command as Ri}from"commander";import D from"chalk";function pt(n){let{name:t,cmd:e}=n,o=t.toUpperCase().replace(/[^A-Z0-9]/g,"_");return`---
43
+ `),s(),e({code:y,state:f})});c.listen(n),process.once("SIGINT",a),process.once("SIGTERM",a),r=setTimeout(()=>{s(),o(new Error("Login timed out - no callback received within 5 minutes"))},300*1e3)})}async function Vr(n,t){let e=await fetch(`${n}/api/cli/whoami`,{headers:{Authorization:`Bearer ${t}`}});if(!e.ok)throw new Error(`Failed to fetch user info: ${e.status}`);return e.json()}async function _r(n){let t=j(),e=oo("Discovering OAuth server...").start();try{let o=await Ur(t);e.succeed("Connecting to "+t);let r=await Nr(Or,Er),i=`http://localhost:${r}/callback`;console.log("Redirect URI: "+i),console.log("Authorization endpoint: "+o.authorization_endpoint),console.log("Token endpoint: "+o.token_endpoint),console.log("Registration endpoint: "+o.registration_endpoint);let s=it(),a=st();if(!s){let S=await Lr(o.registration_endpoint,i);s=S.client_id,a=S.client_secret,$n(s,a)}let c=Pr(),d=Fr(c),u=Dr(),C=new URLSearchParams({client_id:s,redirect_uri:i,response_type:"code",scope:"presentations:read presentations:write",state:u,code_challenge:d,code_challenge_method:"S256"}),y=`${o.authorization_endpoint}?${C}`;console.log("Authorization URL: "+y),n.browser?(p("Opening browser..."),await Rr(y)):(console.log(no.bold("Open this URL in your browser:")),console.log(no.cyan(y)));let f=jr(r,u),{code:w}=await f;e=oo("Completing login...").start();let I=await Mr(o.token_endpoint,w,c,i,s);ot(I.access_token,I.refresh_token,I.expires_in);let k=await Vr(t,I.access_token);e.succeed("Logged in!"),console.log(),x("Logged in as",k.user.email),k.currentTeam&&(Te(k.currentTeam.id),x("Team",`${k.currentTeam.name} (${k.currentTeam.planName})`));try{await ge()}catch{}console.log(),v("You're all set!"),console.log()}catch(o){throw e.fail("Login failed"),l(o instanceof Error?o.message:String(o)),o}}var so=new $r("login").description(`Authenticate with ${m.displayName} (opens browser)`).option("--no-browser","Print URL instead of opening browser").action(async n=>{console.log(),pe()&&(A("You are already logged in."),p(`Run '${m.commands[0]} logout' to log out first, or continue to re-authenticate.`),console.log());try{await _r(n),process.exit(0)}catch{process.exit(1)}});import{Command as qr}from"commander";import{confirm as Br}from"@inquirer/prompts";var ao=new qr("logout").description("Log out and clear authentication").option("--all","Clear all config including API key").action(async n=>{console.log();let t=pe(),e=Ce();if(!t&&!e){A("You are not logged in."),console.log();return}if(n.all)try{await Br({message:"Clear all configuration including API key?",default:!1})?(tt(),he(),v("All configuration cleared.")):p("Cancelled.")}catch{p("Cancelled.")}else rt(),he(),v("Logged out successfully."),e&&p("Note: Your API key is still configured. Use --all to clear everything.");console.log()});import{Command as ye}from"commander";import Xe from"chalk";import{input as Gr,password as Wr,confirm as co,select as Yr}from"@inquirer/prompts";import Gt from"ora";var lo=new ye("config").description("Manage CLI configuration").addCommand(new ye("init").description("Initialize configuration interactively").action(async()=>{console.log(),console.log(Xe.bold(`${m.displayName} CLI Configuration`)),console.log(Xe.gray("\u2500".repeat(35))),console.log();try{let n=await Wr({message:"Enter your API key:",mask:"*",validate:o=>!o||o.trim().length===0?"API key is required":Lt(o.trim())?!0:"Invalid API key format. Keys should start with 'cc_slides_' or 'mcp_'"});if(Ft(n.trim()),await co({message:`Use a custom API URL? (default: ${m.apiUrl.replace("https://","")})`,default:!1})){let o=await Gr({message:"Enter API URL:",default:j(),validate:r=>{try{return new URL(r),!0}catch{return"Invalid URL format"}}});Dt(o)}console.log();let e=Gt("Verifying API key...").start();try{let o=await fe();if(e.succeed("API key verified!"),console.log(),p(`Logged in as: ${o.user.email}`),o.teams.length===0)A("No teams found for this user.");else if(o.teams.length===1){let r=o.teams[0];Te(r.id),p(`Team: ${r.name} (${r.planName})`)}else{console.log(),p(`You have access to ${o.teams.length} teams.`);let r=await Yr({message:"Select your default team:",choices:o.teams.map(s=>({name:`${s.name} (${s.planName}) - ${s.role}${s.isCurrent?" [current]":""}`,value:s.id})),default:o.currentTeam?.id});Te(r);let i=o.teams.find(s=>s.id===r);v(`Selected team: ${i?.name}`)}try{await ge()}catch{}}catch(o){e.fail("Failed to verify API key"),A(`Could not verify API key: ${o instanceof Error?o.message:String(o)}`),A(`You may need to set the team ID manually: ${m.commands[0]} config set team-id <id>`)}console.log(),v("Configuration saved!"),p(`Config file: ${nt()}`),console.log()}catch(n){if(n.name==="ExitPromptError"){console.log(),p("Configuration cancelled.");return}throw n}})).addCommand(new ye("show").description("Show current configuration").option("--verify","Verify API key and show team details").action(async n=>{let t=Sn();if(te("Current Configuration"),console.log(),x("API Key",Fn()??Xe.red("Not set")),x("API URL",t.apiUrl),x("Default Team ID",t.defaultTeamId??Xe.gray("Not set")),console.log(),x("Config file",nt()),n.verify&&t.apiKey){console.log();let e=Gt("Verifying...").start();try{let o=await fe();e.succeed("Verified"),console.log(),x("User",o.user.email),o.currentTeam&&x("Current Team",`${o.currentTeam.name} (${o.currentTeam.planName})`),o.teams.length>1&&x("Total Teams",String(o.teams.length))}catch(o){e.fail("Verification failed"),A(o instanceof Error?o.message:String(o))}}console.log()})).addCommand(new ye("set").description("Set a configuration value").argument("<key>","Configuration key (api-key, api-url, team-id)").argument("<value>","Value to set").action(async(n,t)=>{switch(n){case"api-key":Lt(t)||(l("Invalid API key format. Keys should start with 'cc_slides_' or 'mcp_'"),process.exit(6)),Ft(t),he(),v("API key updated"),ge().catch(()=>{});break;case"api-url":try{new URL(t),Dt(t),v(`API URL set to: ${t}`)}catch{l("Invalid URL format"),process.exit(6)}break;case"team-id":Te(t),v(`Default team ID set to: ${t}`);break;default:l(`Unknown config key: ${n}`),console.log(Xe.gray("Valid keys: api-key, api-url, team-id")),process.exit(6)}})).addCommand(new ye("clear").description("Clear all configuration").action(async()=>{try{await co({message:"Are you sure you want to clear all configuration?",default:!1})?(tt(),he(),v("Configuration cleared")):p("Cancelled")}catch{p("Cancelled")}})).addCommand(new ye("refresh").description("Refresh cached feature flags").action(async()=>{let n=Gt("Refreshing feature flags...").start();try{await ge(),n.succeed("Feature flags refreshed"),p(`Run '${m.commands[0]} --help' to see updated commands`)}catch(t){n.fail("Failed to refresh"),l(t instanceof Error?t.message:String(t)),process.exit(1)}})).addCommand(new ye("path").description("Show configuration file path").option("--cache","Show feature cache file path").action(n=>{n.cache?console.log(to()):console.log(nt())}));import{Command as Xr}from"commander";import J from"chalk";import Kr from"path";import{createParser as Hr}from"eventsource-parser";import H from"chalk";import Jr from"ora";async function zr(n,t,e={}){let o=n.body?.getReader();if(!o)throw new Error("Response body is not readable");let r=new TextDecoder,i,s,a,c=0,d=0,u=0,C={},y=Hr({onEvent:w=>{if(w.data!=="[DONE]")try{let I=JSON.parse(w.data),{type:k,data:S}=I;switch(e.debug&&console.log(H.gray(`[SSE] ${k}:`),S),t.onData?.(k,S),k){case"data-id":i=S;break;case"data-slug":s=S;break;case"data-title":a=S;break;case"data-slides-number-of-slides":c=S;break;case"data-slide-progress":{let R=S;d=R.current,c=R.total,t.onProgress?.(d,c),t.onSlide?.(d,c);break}case"data-overall-progress":{let R=S;t.onPhase?.(R.phase,R.percentage),R.details?.slides&&(d=R.details.slides.complete,c=R.details.slides.total,t.onProgress?.(d,c),t.onSlide?.(d,c));break}case"data-structure-tokens":{u=S,t.onTokens?.(u);break}case"data-slide-meta-tokens":{let[R,$]=S.split(":");if(R&&$){C[R]=parseInt($,10);let h=Object.values(C).reduce((O,G)=>O+G,0);u=Math.max(u,h),t.onTokens?.(u+h)}break}case"data-generation-meta-estimated-time":{t.onEstimatedTime?.(S);break}case"data-finish":t.onComplete?.({id:i,slug:s,title:a,slidesCount:c});break;case"error":{let R=S??I.errorText;R&&t.onError?.(R);break}}}catch{e.debug&&console.log(H.gray("[SSE Raw]"),w.data)}}}),f=!1;for(;!f;){let w=await o.read();if(f=w.done,w.value){let I=r.decode(w.value,{stream:!0});y.feed(I)}}return{id:i,slug:s,title:a,slidesCount:c}}async function uo(n,t,e){let o=In()&&!e.noStream&&!e.quiet&&!e.json;e.json||(console.log(),console.log(H.bold(`Creating presentation: "${t}"`)),console.log(H.gray(`Quality: ${e.mode} | Tone: ${e.tone??"professional"} | Slides: ${e.slideCount} | Language: ${e.language}`)),console.log());let r,i="",s="Preparing",a=0,c={done:0,total:e.slideCount},d=0,u=0,C=Date.now(),y,f=h=>{let O=Math.floor(h/60),G=h%60;return`${O}:${G.toString().padStart(2,"0")}`},w=()=>Math.floor((Date.now()-C)/1e3),I=()=>{if(!u)return" \u2014:\u2014\u2014";let h=Math.max(0,u-w());return h===0&&a<100?"soon!":f(h)},k=h=>h>=1e3?`${(h/1e3).toFixed(1)}k`.padStart(5," "):`${h}tk`.padStart(5," "),S=h=>({"structure-generation":"Planning ","slide-generation":"Writing ","image-generation":"Images ",assembling:"Finishing",completed:"Done "})[h]||"Working ",R=()=>{let h=En(a,100,20,!1),O=String(a).padStart(3," "),G=S(s),X=`${String(c.done).padStart(2," ")}/${String(c.total).padEnd(2," ")}`,re=k(d),xe=f(w()).padStart(5," "),We=I().padStart(5," ");return`${h} ${H.bold(O)}${H.gray("%")} ${H.cyan(G)} ${H.gray(X)} ${H.yellow(re)} ${H.gray(xe)} ${H.green(We+" left")}`};return o&&(r=Jr({text:R(),spinner:"dots"}).start(),y=setInterval(()=>{r&&r.isSpinning&&(r.text=R())},100)),{...await zr(n,{onProgress:(h,O)=>{if(c={done:h,total:O},!o&&!e.quiet&&!e.json){let G=`${s.trim()}: slide ${h}/${O}`;G!==i&&(console.log(G),i=G)}},onPhase:(h,O)=>{s=S(h),a=O},onTokens:h=>{d=h},onEstimatedTime:h=>{u=h},onError:h=>{y&&clearInterval(y),r?r.fail(H.red(`Error: ${h}`)):e.json||console.error(H.red(`Error: ${h}`))},onComplete:h=>{if(y&&clearInterval(y),r)a=100,s="Done",r.succeed(R());else if(!e.json){let O=d>0?` | ${d.toLocaleString()} tokens`:"";console.log(`Done! [${f(w())}${O}]`)}}},{debug:e.debug}),elapsedSeconds:w(),totalTokens:d}}async function mo(n,t={}){let e=n.body?.getReader();if(!e)throw new Error("Response body is not readable");let o=new TextDecoder,r="",i=!1;for(;!i;){let s=await e.read();if(i=s.done,s.value){let a=o.decode(s.value,{stream:!0});r+=a,t.quiet||process.stdout.write(a)}}return t.quiet||console.log(),r}import{readFileSync as Qr,existsSync as Zr}from"fs";import{resolve as po}from"path";var fo=new Xr("create").description("Create a new presentation").argument("<topic>","The topic or title for the presentation").option("-n, --slides <count>","Number of slides (1-20)").option("-m, --mode <mode>","Generation quality (best, balanced, fast, ultrafast, instant)").option("-t, --tone <tone>","Tone (creative, professional, educational, formal, casual)").option("--amount <amount>","Content density (minimal, concise, detailed, extensive)").option("--audience <text>","Target audience description").option("-l, --language <lang>","Output language").option("--branding-id <id>","Branding ID (from `ccr branding list` or `ccr branding extract`)").option("-c, --context <text>","Inline text context (research notes, key facts)").option("--context-file <path>","Path to a context file (text, markdown, JSON)").option("--stdin","Read context from stdin").option("-f, --file <paths...>","Files to upload (PDF, PPTX, DOCX, images)").option("-g, --goal <type>","Goal (inform, persuade, train, learn, entertain, report)").option("--styling <mode>","Styling mode (freeform, brand-only, brand-plus-style, style-only, no-styling)").option("--reference-url <url>","Image URL to use as visual style reference").option("--thinking-depth <depth>","AI thinking depth (quick, moderate, deep, profound)").option("--theme <preset>","[instant mode only] Color theme preset (blue, violet, rose, orange, green)").option("--primary-color <hex>","[instant mode only] Primary color (e.g., #0066CC)").option("--secondary-color <hex>","[instant mode only] Secondary color").option("--accent-color <hex>","[instant mode only] Accent color").option("--background-color <hex>","[instant mode only] Background color").option("--foreground-color <hex>","[instant mode only] Foreground/text color").option("--decorations <style>","[instant mode only] Background decoration (none, waves-bottom-left, waves-top-right, blob-corners, minimal)").option("--team-id <id>","Team ID (switch teams)").option("-o, --output <format>","Output format (human, json, quiet)").option("--no-stream","Wait for completion without streaming progress").option("--debug","Enable debug logging").option("--open","Open in browser after creation").option("--id <uuid>","Use a specific UUID for the presentation").option("--studio","Studio mode: use current directory name as presentation ID (auto-links to Studio preview)").action(async(n,t)=>{await D();let e;t.slides!==void 0&&(e=parseInt(t.slides,10),(isNaN(e)||e<1||e>20)&&(l("Slide count must be between 1 and 20"),process.exit(6)));let o=["best","balanced","fast","ultrafast","instant"];t.mode&&!o.includes(t.mode)&&(l(`Invalid mode: ${t.mode}. Valid: ${o.join(", ")}`),process.exit(6));let r=["creative","professional","educational","formal","casual"];t.tone&&!r.includes(t.tone)&&(l(`Invalid tone: ${t.tone}. Valid: ${r.join(", ")}`),process.exit(6));let i=["minimal","concise","detailed","extensive"];t.amount&&!i.includes(t.amount)&&(l(`Invalid amount: ${t.amount}. Valid: ${i.join(", ")}`),process.exit(6));let s=["freeform","brand-only","brand-plus-style","style-only","no-styling"];t.styling&&!s.includes(t.styling)&&(l(`Invalid styling: ${t.styling}. Valid: ${s.join(", ")}`),process.exit(6));let a=["quick","moderate","deep","profound"];t.thinkingDepth&&!a.includes(t.thinkingDepth)&&(l(`Invalid thinking-depth: ${t.thinkingDepth}. Valid: ${a.join(", ")}`),process.exit(6));let c=["inform","persuade","train","learn","entertain","report"];t.goal&&!c.includes(t.goal)&&(l(`Invalid goal: ${t.goal}. Valid: ${c.join(", ")}`),process.exit(6));let d=["blue","violet","rose","orange","green"];t.theme&&!d.includes(t.theme)&&(l(`Invalid theme: ${t.theme}. Valid: ${d.join(", ")}`),process.exit(6));let u=["none","waves-bottom-left","waves-top-right","blob-corners","minimal"];t.decorations&&!u.includes(t.decorations)&&(l(`Invalid decorations: ${t.decorations}. Valid: ${u.join(", ")}`),process.exit(6)),(t.theme||t.primaryColor||t.secondaryColor||t.accentColor||t.backgroundColor||t.foregroundColor||t.decorations)&&t.mode&&t.mode!=="instant"&&(l("--theme, --primary-color, --decorations and other color options are only supported with --mode instant"),process.exit(6));let y=/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;for(let[$,h]of[["primary-color",t.primaryColor],["secondary-color",t.secondaryColor],["accent-color",t.accentColor],["background-color",t.backgroundColor],["foreground-color",t.foregroundColor]])h&&!y.test(h)&&(l(`Invalid ${$}: ${h}. Must be hex (e.g., #0066CC)`),process.exit(6));try{t.output!=="json"&&t.output!=="quiet"&&process.stdout.write(J.gray("Checking generation limits... "));let $=await Gn(t.mode??"fast",e??10,t.teamId);t.output!=="json"&&t.output!=="quiet"&&(console.log(J.green("\u2713")),console.log(J.gray(` Plan: ${$.planName} | ${t.mode??"fast"}: ${$.remaining[t.mode??"fast"]}/${$.limits[t.mode??"fast"]} remaining`)))}catch($){t.output==="json"?console.log(JSON.stringify({success:!1,error:$ instanceof Error?$.message:String($)})):(console.log(J.red("\u2717")),l($ instanceof Error?$.message:String($))),process.exit($.exitCode??1)}let f=[];if(t.file&&t.file.length>0){for(let $ of t.file)Zr(po($))||(l(`File not found: ${$}`),process.exit(6));t.output!=="json"&&t.output!=="quiet"&&console.log(J.gray(`
44
+ Uploading ${t.file.length} file(s)...`));try{f=await Nn(t.file.map($=>po($)),($,h,O)=>{t.output!=="json"&&t.output!=="quiet"&&O&&process.stdout.write(`\r ${J.cyan("\u2B06")} Uploading: ${O} (${$+1}/${h})`)}),t.output!=="json"&&t.output!=="quiet"&&console.log(`\r ${J.green("\u2713")} Uploaded ${f.length} file(s) `)}catch($){l(`Failed to upload files: ${$ instanceof Error?$.message:String($)}`),process.exit(1)}}let w;(t.stdin||!process.stdin.isTTY)&&(w=await ei(),t.stdin&&!w&&(l("No content received from stdin"),process.exit(6)));let I=t.context;if(t.contextFile)try{I=Qr(t.contextFile,"utf-8"),I.trim()||(l(`Context file is empty: ${t.contextFile}`),process.exit(6))}catch{l(`Failed to read context file: ${t.contextFile}`),process.exit(6)}!w&&!I&&f.length===0&&(l("Context is required to create a presentation."),console.log(),console.log(J.gray(" -f, --file <paths...> Upload files (PDF, PPTX, images)")),console.log(J.gray(" -c, --context <text> Inline text context")),console.log(J.gray(" --context-file <path> Read from a file")),console.log(J.gray(` cat file | ${m.commands[0]} Pipe content`)),process.exit(6));let k=[...f];w&&k.push({id:`stdin-${Date.now()}`,content:w,title:"Piped Content",mime:"text/plain",selected:!0}),I&&k.push({id:`context-${Date.now()}`,content:I,title:"Context",mime:"text/plain",selected:!0});let S,R=t.primaryColor||t.secondaryColor||t.accentColor||t.backgroundColor||t.foregroundColor;(t.theme||R||t.decorations)&&(S={},t.theme&&(S.preset=t.theme),R&&(S.custom={},t.primaryColor&&(S.custom.primary=t.primaryColor),t.secondaryColor&&(S.custom.secondary=t.secondaryColor),t.accentColor&&(S.custom.accent=t.accentColor),t.backgroundColor&&(S.custom.background=t.backgroundColor),t.foregroundColor&&(S.custom.foreground=t.foregroundColor)),t.decorations&&(S.decorations=t.decorations));try{let $=await Un({topic:n,...e!==void 0&&{slideCount:e},...t.mode&&{mode:t.mode},...t.tone&&{tone:t.tone},...t.amount&&{amount:t.amount},...t.audience&&{audience:t.audience},...t.language&&{language:t.language},...t.brandingId&&{brandingId:t.brandingId},...t.styling&&{stylingMode:t.styling},...t.referenceUrl&&{referenceUrl:t.referenceUrl},...t.thinkingDepth&&{thinkingDepth:t.thinkingDepth},...t.goal&&{goal:t.goal},...t.teamId&&{teamId:t.teamId},...S&&{theme:S},...t.studio?{documentId:Kr.basename(process.cwd())}:t.id?{documentId:t.id}:{},...k.length>0&&{contentSources:{uploadedFiles:k,contextFiles:[]}}}),h=await uo($,n,{slideCount:e,mode:t.mode,tone:t.tone,language:t.language,noStream:t.noStream,debug:t.debug,quiet:t.output==="quiet",json:t.output==="json"});if(t.output==="json")console.log(JSON.stringify({success:!0,presentation:{id:h.id,slug:h.slug,title:h.title??n,slidesCount:h.slidesCount,elapsedSeconds:h.elapsedSeconds,totalTokens:h.totalTokens},viewUrl:ke(h.slug,t.language??"en")},null,2));else{console.log(),v("Presentation created successfully"),console.log(),x("Title",h.title??n),x("Slides",String(h.slidesCount??e??"\u2014"));let O=[];if(h.elapsedSeconds){let X=Math.floor(h.elapsedSeconds/60),re=h.elapsedSeconds%60;O.push(X>0?`${X}m ${re}s`:`${re}s`)}h.totalTokens&&O.push(`${h.totalTokens.toLocaleString()} tokens`),O.length>0&&x("Generated in",O.join(" \xB7 ")),console.log();let G=ke(h.slug,t.language??"en");G!=="N/A"&&(console.log(J.bold(" Open: ")+J.cyan.underline(G)),t.open&&await(await import("open")).default(G)),console.log()}}catch($){t.output==="json"?console.log(JSON.stringify({success:!1,error:$ instanceof Error?$.message:String($)})):l($ instanceof Error?$.message:String($)),process.exit($.exitCode??1)}});async function ei(){return new Promise(n=>{let t="";if(process.stdin.setEncoding("utf8"),process.stdin.isTTY){n("");return}process.stdin.on("data",e=>{t+=e}),process.stdin.on("end",()=>{n(t.trim())}),setTimeout(()=>{n(t.trim())},100)})}import{Command as ti}from"commander";var go=new ti("list").description("List presentations").option("-n, --limit <count>","Number of results to return","20").option("-f, --format <format>","Output format (table, json, ids)","table").option("--sort <field>","Sort by field (created, updated, title)").option("--team-id <id>","Team ID (uses default if not specified)").option("-d, --detail","Show detailed output including URLs").option("-l, --language <lang>","Language for URLs","en").action(async n=>{await D();let t=parseInt(n.limit,10);(isNaN(t)||t<1)&&(l("Invalid limit value"),process.exit(6));let e=n.teamId??et();e||(l("`Team ID required. Set a default with '${brand.commands[0]} config set team-id <id>' or use --team-id`"),process.exit(6));try{let o=await Ln(e,t);if(o.length===0){n.format==="json"?console.log(JSON.stringify([])):n.format!=="ids"&&p("No presentations found");return}switch(n.sort&&o.sort((r,i)=>{switch(n.sort){case"created":return new Date(i.createdAt).getTime()-new Date(r.createdAt).getTime();case"title":return(r.title||"").localeCompare(i.title||"");default:return 0}}),n.format){case"json":console.log(JSON.stringify(o,null,2));break;case"ids":console.log(An(o));break;default:console.log(Rn(o,{showLinks:n.detail,language:n.language}));break}}catch(o){l(o instanceof Error?o.message:String(o)),process.exit(o.exitCode??1)}});import{Command as ni}from"commander";import mt from"chalk";var ho=new ni("get").description("Get presentation details").argument("<slug>","Presentation slug (e.g., my-presentation-v1-abc123)").option("-f, --format <format>","Output format (summary, full, json)","summary").option("--include <fields>","Fields to include (comma-separated: slides,styling)").option("-l, --language <lang>","Language for view URL","en").action(async(n,t)=>{await D();try{let e=await $e(n);if(t.format==="json"){console.log(JSON.stringify(e,null,2));return}let o=ke(e.slug,t.language);te("Presentation Details"),console.log(),x("Slug",e.slug),x("Title",e.title||"Untitled"),x("Description",e.description||mt.gray("None")),x("Slides",String(e.numberOfSlides||"-")),x("Mode",e.mode||"-"),x("Created",Ut(e.createdAt)),e.updatedAt&&x("Updated",Ut(e.updatedAt)),console.log(),o!=="N/A"&&console.log(mt.bold(" Open: ")+mt.cyan.underline(o)),console.log(),t.format==="full"&&t.include?.includes("slides")&&(console.log(mt.gray("(Full slide content available in JSON format)")),console.log())}catch(e){l(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}});import{Command as oi}from"commander";import{confirm as ri}from"@inquirer/prompts";var yo=new oi("delete").description("Delete a presentation").argument("<slug>","Presentation slug (e.g., my-presentation-v1-abc123)").option("-f, --force","Skip confirmation prompt").option("-q, --quiet","Suppress output").action(async(n,t)=>{if(await D(),!t.force)try{if(!await ri({message:`Are you sure you want to delete presentation "${n}"?`,default:!1})){t.quiet||A("Deletion cancelled");return}}catch{t.quiet||A("Deletion cancelled");return}try{await Mn(n),t.quiet||v(`Presentation "${n}" deleted`)}catch(e){l(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}});import{Command as ii}from"commander";import{writeFile as si}from"fs/promises";import{resolve as bo}from"path";import ai from"ora";var vo=new ii("export").description("Export a presentation to ZIP").argument("<slug>","Presentation slug (e.g., my-presentation-v1-abc123)").option("-o, --output <path>","Output file path").option("--include-images","Include images (default: true)",!0).option("--include-branding","Include branding (default: true)",!0).option("--no-external","Skip external image downloads").action(async(n,t)=>{await D();let e=ai("Fetching presentation...").start();try{let o=await $e(n),r=o.title||n,i=o.id,s=n.replace(/[^a-z0-9-]/gi,"_").toLowerCase().substring(0,50),a=new Date().toISOString().split("T")[0],c=`${s}_${a}.zip`,d=t.output?bo(t.output):bo(process.cwd(),c);e.text=`Exporting "${r}"...`;let u=await jn(i,{includeImages:t.includeImages,includeBranding:t.includeBranding,includeExternal:!t.noExternal});e.text="Saving file...",await si(d,Buffer.from(u)),e.succeed("Export complete!"),console.log(),p(`File saved: ${d}`),p(`Size: ${ci(u.byteLength)}`),console.log()}catch(o){e.fail("Export failed"),l(o instanceof Error?o.message:String(o)),process.exit(o.exitCode??1)}});function ci(n){return n<1024?`${n} B`:n<1024*1024?`${(n/1024).toFixed(1)} KB`:`${(n/(1024*1024)).toFixed(1)} MB`}import{Command as li}from"commander";import{readFile as di}from"fs/promises";import{resolve as ui,basename as mi}from"path";import pi from"ora";var xo=new li("import").description("Import a presentation from ZIP (admin only)").argument("<file>","Path to ZIP file");xo._hidden=!0;var wo=xo.option("--dry-run","Validate without importing").option("--overwrite","Overwrite existing presentations").option("--remap-ids","Generate new IDs (default: true)",!0).action(async(n,t)=>{await D();try{(await fe()).user.role!=="admin"&&(l("This command is only available to administrators"),process.exit(2))}catch{l("Failed to verify permissions"),process.exit(2)}let e=ui(n),o=mi(e);o.endsWith(".zip")||(l("File must be a ZIP archive"),process.exit(6));let r=pi("Reading file...").start();try{let i=await di(e);t.dryRun?r.text="Validating...":r.text="Importing presentation...";let s=await Vn(i,o,{dryRun:t.dryRun});if(s.success){if(t.dryRun)r.succeed("Validation passed!"),console.log(),p("The file is valid and can be imported."),s.statistics&&(console.log(),x("Slides",String(s.statistics.slidesImported)),x("Images",String(s.statistics.imagesUploaded)));else if(r.succeed("Import complete!"),console.log(),x("Presentation ID",s.presentationId??"N/A"),x("Document ID",s.documentId??"N/A"),s.statistics&&(x("Slides imported",String(s.statistics.slidesImported)),x("Images uploaded",String(s.statistics.imagesUploaded)),x("Time",`${s.statistics.totalTimeMs}ms`)),s.presentationId){let a=j();x("View URL",`${a}/p/${s.presentationId}`)}if(s.warnings&&s.warnings.length>0){console.log();for(let a of s.warnings)A(a)}console.log()}else{if(r.fail("Import failed"),console.log(),s.errors)for(let a of s.errors)l(`${a.type}: ${a.message}`);process.exit(1)}}catch(i){r.fail("Import failed"),i.code==="ENOENT"&&(l(`File not found: ${e}`),process.exit(3)),l(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}});import{Command as Ie}from"commander";import q from"chalk";import fi from"ora";import{writeFile as So}from"fs/promises";var To=new Ie("branding").description("Manage brand profiles").addCommand(new Ie("list").description("List brand profiles").option("-f, --format <format>","Output format (table, json)","table").action(async n=>{await D();try{let t=await Mt();if(t.brandings.length===0){n.format==="json"?console.log(JSON.stringify([])):(p("No brand profiles found"),console.log(),console.log(q.gray("`Create one with: ${brand.commands[0]} branding extract <url>`")));return}n.format==="json"?console.log(JSON.stringify(t.brandings,null,2)):console.log(On(t.brandings))}catch(t){l(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}})).addCommand(new Ie("get").description("Get brand profile details").argument("<id>","Brand profile ID").option("-f, --format <format>","Output format (summary, json)","summary").option("-o, --output <path>","Save JSON to file").action(async(n,t)=>{await D();try{let e=await jt(n);if(t.output){await So(t.output,JSON.stringify(e,null,2)),v(`Brand profile saved to ${t.output}`);return}if(t.format==="json")console.log(JSON.stringify(e,null,2));else{if(te("Brand Profile"),console.log(),x("ID",e.id),x("Name",e.name),x("Source URL",e.sourceUrl??q.gray("None")),x("Default",e.isDefault?q.green("Yes"):"No"),e.createdAt&&x("Created",new Date(e.createdAt).toLocaleString()),console.log(),e.primaryColor||e.colors.length>0){if(console.log(q.bold(" Colors")),e.primaryColor){let r=q.bgHex(e.primaryColor)(" ");console.log(` Primary: ${r} ${e.primaryColor}`)}if(e.colors.length>0){console.log(" Palette:");for(let r of e.colors.slice(0,10)){let i=q.bgHex(r.hex)(" "),s=r.role?q.gray(` (${r.role})`):"";console.log(` ${i} ${r.hex}${s}`)}}console.log()}e.logoUrl&&(console.log(q.bold(" Logo")),console.log(` ${e.logoUrl}`),console.log());let o=e.typography;o&&Object.keys(o).length>0&&(console.log(q.bold(" Typography")),(o.primary||o.headings)&&console.log(` Headings: ${o.primary||o.headings||"-"}`),(o.secondary||o.body)&&console.log(` Body: ${o.secondary||o.body||"-"}`),console.log()),(e.confidence||e.extractionMethod)&&(console.log(q.bold(" Extraction")),e.confidence&&console.log(` Confidence: ${Math.round(e.confidence*100)}%`),e.extractionMethod&&console.log(` Method: ${e.extractionMethod}`),console.log()),console.log(q.gray(" Use --format json for full details")),console.log()}}catch(e){l(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}})).addCommand(new Ie("find").description("Find existing brand profile by name or URL").argument("<query>","Brand name or website URL to search for").action(async n=>{await D();try{let t=await Mt(),e=n.toLowerCase().replace(/^https?:\/\//,"").replace(/\/$/,""),o=t.brandings.filter(r=>{let i=(r.name||"").toLowerCase(),s=(r.sourceUrl||"").toLowerCase().replace(/^https?:\/\//,"").replace(/\/$/,"");return i.includes(e)||s.includes(e)||i.length>0&&e.includes(i)||s.length>0&&e.includes(s)});if(o.length===0){p(`No brand profiles matching "${n}"`),console.log(q.gray(` Extract one with: ${m.commands[0]} branding extract <url>`));return}console.log(`Found ${o.length} brand${o.length>1?"s":""}:
45
+ `);for(let r of o){let i=r.primaryColor?q.bgHex(r.primaryColor)(" ")+" "+r.primaryColor:"";console.log(` ${q.bold(r.name)} ${q.gray(r.id)}`),r.sourceUrl&&console.log(` ${q.gray(r.sourceUrl)}`),i&&console.log(` ${i}`),console.log()}console.log(q.gray(` Export with: ${m.commands[0]} branding get <id> -o branding.json`))}catch(t){l(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}})).addCommand(new Ie("extract").description("Extract brand profile from a website").argument("<url>","Website URL to extract branding from").option("--team-id <id>","Team ID").option("--no-save","Extract without saving").option("-o, --output <path>","Save JSON to file").action(async(n,t)=>{await D();try{new URL(n.startsWith("http")?n:`https://${n}`)}catch{l("Invalid URL format"),process.exit(6)}let e=n.startsWith("http")?n:`https://${n}`,o=t.teamId??et(),r=fi({text:`Extracting branding from ${e}...`,stream:process.stdout}).start();try{let i=await _n(e,o),s=await jt(i.id);r.succeed("Branding extracted!");let a=JSON.stringify(s,null,2);t.output?(await So(t.output,a),v(`Brand profile saved to ${t.output}`)):console.log(a),console.log()}catch(i){r.fail("Extraction failed"),l(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}})).addCommand(new Ie("set-default").description("Set a brand profile as default").argument("<id>","Brand profile ID").action(async n=>{await D(),p(`To set brand ${n} as default, use the web dashboard.`),console.log(),console.log(q.gray("API support for setting default brand is coming soon."))}));import{Command as Re}from"commander";import Co from"chalk";import gi from"ora";function hi(){return new Re("blog").description("Generate a blog post from a presentation").argument("<slug>","Presentation slug").option("--words <count>","Target word count (50-2000)","300").option("--tone <tone>","Writing tone (professional, casual, educational)","professional").option("--audience <text>","Target audience description").option("-f, --format <format>","Output format (human, json, markdown)","human").option("--instructions <text>","Custom instructions for the blog").option("--no-images","Exclude image references").option("--toc","Include table of contents").action(async(n,t)=>{await D();let e=parseInt(t.words,10);(isNaN(e)||e<50||e>2e3)&&(l("Word count must be between 50 and 2000"),process.exit(6));let o=["professional","casual","educational"];o.includes(t.tone)||(l(`Invalid tone. Valid options: ${o.join(", ")}`),process.exit(6));let r=gi("Fetching presentation...").start();try{let i=await $e(n);r.text="Generating blog post...";let s=await Bn(i.id,i.documentCreatedAt||i.createdAt,{targetWordCount:e,tone:t.tone,targetAudience:t.audience??"General Audience",customInstructions:t.instructions??"",includeImages:!t.noImages,includeTableOfContents:t.toc??!1}),a=await mo(s,{quiet:!0});r.succeed("Blog generated"),t.format==="json"?console.log(JSON.stringify({presentationId:n,title:i.title,wordCount:e,tone:t.tone,content:a},null,2)):t.format==="markdown"?console.log(a):(console.log(),console.log(Co.bold(`Blog: ${i.title}`)),console.log(Co.gray("\u2500".repeat(40))),console.log(),console.log(a),console.log())}catch(i){r.fail("Generation failed"),l(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}})}function yi(){return new Re("tweets").description("Generate tweets from a presentation").argument("<slug>","Presentation slug").option("--count <n>","Number of tweets to generate","5").option("-f, --format <format>","Output format (human, json)","human").action(async(n,t)=>{await D(),p("Tweet generation coming soon.")})}function bi(){return new Re("linkedin").description("Generate a LinkedIn carousel from a presentation").argument("<slug>","Presentation slug").option("-f, --format <format>","Output format (human, json)","human").action(async n=>{await D(),p("LinkedIn carousel generation coming soon.")})}function vi(){return new Re("questions").description("Generate questions for a presentation").argument("<slug>","Presentation slug").option("--count <n>","Number of questions","10").option("-f, --format <format>","Output format (human, json)","human").action(async(n,t)=>{await D(),p("Question generation coming soon.")})}function xi(){return new Re("cheatsheet").description("Generate a presenter cheat sheet").argument("<slug>","Presentation slug").option("--mode <mode>","Cheat sheet mode (qa-prep, talking-points)","qa-prep").option("-f, --format <format>","Output format (human, json, markdown)","human").action(async(n,t)=>{await D(),p("Cheat sheet generation coming soon.")})}function ko(){let n=new Re("derive").description("Generate derivative content from a presentation"),t=eo();return t&&(t.deckToBlog&&n.addCommand(hi()),t.deckToTweets&&n.addCommand(yi()),t.linkedInCarousel&&n.addCommand(bi()),t.redTeamQuestions&&n.addCommand(vi()),t.presenterCheatSheet&&n.addCommand(xi())),n}import{Command as wi}from"commander";import Wt from"chalk";var $o=new wi("ideas").description("Generate presentation topic ideas").option("--context <text>","Custom context for idea generation").option("--count <n>","Number of ideas to generate","5").option("-f, --format <format>","Output format (human, json)","human").action(async n=>{await D(),p("Idea generation is available in the web dashboard."),console.log(),console.log(Wt.gray("The CLI will support idea generation in a future release.")),console.log(),console.log("For now, try these approaches:"),console.log(Wt.gray("` 1. Visit the ${brand.displayName} dashboard and use the idea generator`")),console.log(Wt.gray(" 2. Create a presentation with a broad topic and refine it")),console.log()});import{Command as Si}from"commander";import Yt from"chalk";var Io=new Si("whoami").description("Show current user and team information").option("-f, --format <format>","Output format (human, json)","human").action(async n=>{await D();try{let t=await fe();if(Bt(),n.format==="json"){console.log(JSON.stringify(t,null,2));return}te("User"),console.log(),x("Email",t.user.email),t.user.username&&x("Username",t.user.username),(t.user.firstName||t.user.lastName)&&x("Name",[t.user.firstName,t.user.lastName].filter(Boolean).join(" "));let e=t.authType==="apiKey"?"API Key":t.authType==="oauth"?"OAuth":"Session";if(x("Auth Type",e),t.currentTeam&&(console.log(),te("Current Team"),console.log(),x("ID",t.currentTeam.id),x("Name",t.currentTeam.name),x("Plan",t.currentTeam.planName),x("Role",t.currentTeam.isOwner?"Owner":"Member")),t.teams.length>1){console.log(),te("All Teams"),console.log();for(let o of t.teams){let r=o.isCurrent?Yt.green(" (current)"):"";console.log(` ${Yt.bold(o.name)}${r}`),console.log(Yt.gray(` ID: ${o.id} | Plan: ${o.planName} | Role: ${o.role}`))}}console.log()}catch(t){l(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}});import{Command as Ri}from"commander";import N from"chalk";function pt(n){let{name:t,cmd:e}=n,o=t.toUpperCase().replace(/[^A-Z0-9]/g,"_");return`---
46
46
  name: ${t}
47
47
  description: CLI with TTS (text-to-speech), AI music generation, sound effects, stock image/video search, audio mixing, URL scraping, and branding. Use when user asks for voiceover, narration, background music, sound effects, stock footage, or needs to scrape a website.
48
48
  ---
@@ -469,7 +469,7 @@ import { DEFAULT_FPS } from './audio/constants';
469
469
 
470
470
  ### 9c. Spawn Per-Scene Builder Agents
471
471
 
472
- **For EACH scene** from the parsed plan, spawn a \`video-scene-builder\` agent using the Task tool (model: sonnet).
472
+ **For EACH scene** from the parsed plan, spawn a \`video-scene-builder\` agent using the Task tool (model: opus).
473
473
 
474
474
  **Construct the Task prompt for each scene with these sections:**
475
475
 
@@ -1068,7 +1068,7 @@ Do NOT render or export the presentation \u2014 that's handled by the app.
1068
1068
  | Create brand-new presentation (5+ slides, new topic) | \`${e} create ...\` via CLI |
1069
1069
  | Redesign the whole deck | \`${e} create ...\` via CLI, then sync |
1070
1070
  | User provides a URL to base the presentation on | \`${e} scrape <url>\` \u2192 \`${e} create ...\` |
1071
- `}function Re(n){let{name:t,cmd:e}=n;return`---
1071
+ `}function Ae(n){let{name:t,cmd:e}=n;return`---
1072
1072
  name: ${t}-tts
1073
1073
  description: Text-to-speech generation. Convert text to natural speech with multiple providers (Gemini, ElevenLabs, OpenAI) and voices. Use for voiceovers, narration, accessibility.
1074
1074
  ---
@@ -1267,7 +1267,7 @@ ${e} tts generate \\
1267
1267
  2. **Voice matching** - Match voice style to content: Puck for upbeat, Charon for serious
1268
1268
  3. **Speed adjustment** - Use 0.9-0.95 for narration, 1.0-1.1 for casual
1269
1269
  4. **Batch processing** - Use \`video generate assets\` for multiple voiceovers
1270
- `}function Ae(n){let{name:t,cmd:e}=n;return`---
1270
+ `}function Oe(n){let{name:t,cmd:e}=n;return`---
1271
1271
  name: ${t}-music
1272
1272
  description: AI music generation from text prompts. Create background music, soundtracks, jingles for videos, presentations, podcasts. Supports ElevenLabs and Suno providers.
1273
1273
  ---
@@ -1407,7 +1407,7 @@ ${e} music generate -p "calm piano" -d 30 -f json
1407
1407
  2. **Looping** - For seamless loops, mention "loopable" in prompt.
1408
1408
  3. **Video sync** - Use \`video generate assets\` to auto-generate music for video projects.
1409
1409
  4. **Volume mixing** - Background music should be 20-30% volume when mixed with voiceover.
1410
- `}function Oe(n){let{name:t,cmd:e}=n;return`---
1410
+ `}function Ee(n){let{name:t,cmd:e}=n;return`---
1411
1411
  name: ${t}-sfx
1412
1412
  description: AI sound effects generation from text descriptions. Create foley, ambient, UI sounds, impacts, whooshes for videos, games, apps. Uses ElevenLabs SFX.
1413
1413
  ---
@@ -1616,7 +1616,7 @@ ${e} sfx generate -t "click" -d 0.5 -f json
1616
1616
  3. **Prompt influence** - Higher (0.7-1.0) = more literal, lower (0.1-0.3) = more creative.
1617
1617
  4. **Descriptive prompts** - Add context: "door slam, heavy wooden door" > "door slam".
1618
1618
  5. **Format** - Use WAV for editing, MP3 for final output.
1619
- `}function Ee(n){let{name:t,cmd:e}=n;return`---
1619
+ `}function Pe(n){let{name:t,cmd:e}=n;return`---
1620
1620
  name: ${t}-mix
1621
1621
  description: Audio mixing for video production. Combine video with voiceover and background music. Supports volume control, fade effects, and multiple audio tracks.
1622
1622
  ---
@@ -1766,7 +1766,7 @@ ${e} mix status <request-id>
1766
1766
  2. **Music selection** - Choose music that doesn't compete with voice frequency.
1767
1767
  3. **Consistent levels** - Keep voice at 100%, adjust music only.
1768
1768
  4. **File sizes** - Use \`--no-wait\` for large files to avoid timeout.
1769
- `}function Pe(n){let{name:t,cmd:e}=n;return`---
1769
+ `}function Fe(n){let{name:t,cmd:e}=n;return`---
1770
1770
  name: ${t}-image
1771
1771
  description: Stock image search and AI image generation. Find royalty-free images from multiple providers or generate custom images with AI. For videos, presentations, marketing.
1772
1772
  ---
@@ -1950,7 +1950,7 @@ Found 10 images for "mountain landscape"
1950
1950
  3. **Size matters** - Use \`--size large\` for hero images
1951
1951
  4. **JSON for automation** - Parse results programmatically
1952
1952
  5. **Generation prompts** - Be detailed, describe style, lighting, composition
1953
- `}function Fe(n){let{name:t,cmd:e}=n;return`---
1953
+ `}function De(n){let{name:t,cmd:e}=n;return`---
1954
1954
  name: ${t}-video-search
1955
1955
  description: Stock video search. Find royalty-free video clips from multiple providers (Pexels, Pixabay). For b-roll, backgrounds, transitions in video production.
1956
1956
  ---
@@ -2125,7 +2125,7 @@ ${e} video find "city timelapse" --orientation landscape -n 10
2125
2125
  3. **Preview first** - Use preview URLs to check quality
2126
2126
  4. **License** - Verify license for commercial use
2127
2127
  5. **JSON export** - Save searches for batch processing
2128
- `}function De(n){let{name:t,cmd:e}=n;return`---
2128
+ `}function Ne(n){let{name:t,cmd:e}=n;return`---
2129
2129
  name: ${t}-scrape
2130
2130
  description: Scrape any URL the user provides. Use when user says "check this site", "look at this URL", "use this website", "here's the link", or shares any URL for context. Supports websites, YouTube, Twitter/X.
2131
2131
  ---
@@ -2315,7 +2315,7 @@ ${e} scrape https://blog.example.com -f quiet | ${e} create "Blog Summary"
2315
2315
  3. **Use JSON** - For programmatic processing of results
2316
2316
  4. **Combine sources** - Scrape multiple URLs for comprehensive context
2317
2317
  5. **Token count** - Check token usage for large documents
2318
- `}function Ne(n){let{name:t,cmd:e}=n;return`---
2318
+ `}function Ue(n){let{name:t,cmd:e}=n;return`---
2319
2319
  name: ${t}-branding
2320
2320
  description: Brand profile management. Extract branding from websites, manage saved brands, apply consistent styling to presentations.
2321
2321
  ---
@@ -2425,7 +2425,7 @@ ${e} branding set-default abc123
2425
2425
  2. **If extraction fails** \u2014 Proceed without branding. Do not manually create brand assets.
2426
2426
  3. **Set default** \u2014 If you mostly work with one brand, set it as default.
2427
2427
  4. **Override** \u2014 Use \`--brand\` flag to override default for specific presentations.
2428
- `}function Ue(n){let{name:t,cmd:e}=n,o=t.toUpperCase().replace(/[^A-Z0-9]/g,"_");return`---
2428
+ `}function Le(n){let{name:t,cmd:e}=n,o=t.toUpperCase().replace(/[^A-Z0-9]/g,"_");return`---
2429
2429
  name: ${t}-config
2430
2430
  description: CLI configuration management. Set API keys, team IDs, custom API URLs. Verify authentication status.
2431
2431
  ---
@@ -2754,23 +2754,23 @@ Extracts: tweet text, author info, media URLs
2754
2754
  ---
2755
2755
 
2756
2756
  All scraped content is returned in markdown format.
2757
- `};import{mkdirSync as yt,writeFileSync as bt,existsSync as Le,rmSync as Ao}from"fs";import{join as J,resolve as ye,relative as Ci,basename as Oo}from"path";import{homedir as vt}from"os";var ne=[{name:"Claude Code",dir:".claude",provider:"claude"},{name:"GitHub Copilot",dir:".github",agentSuffix:".agent.md",provider:"copilot"},{name:"Cursor",dir:".cursor"},{name:"Codex",dir:".codex",agentSuffix:".toml",provider:"codex"},{name:"OpenCode",dir:".opencode"},{name:"Windsurf",dir:".windsurf"},{name:"Agent",dir:".agent"}];var ki={sonnet:"claude-sonnet-4.6",haiku:"claude-haiku-4.5",opus:"claude-opus-4.6"},Ti=["permissionMode","skills","subagentType"];function $i(n){let t=n.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(!t)return`developer_instructions = """
2757
+ `};import{mkdirSync as yt,writeFileSync as bt,existsSync as Me,rmSync as Oo}from"fs";import{join as z,resolve as be,relative as Ti,basename as Eo}from"path";import{homedir as vt}from"os";var oe=[{name:"Claude Code",dir:".claude",provider:"claude"},{name:"GitHub Copilot",dir:".github",agentSuffix:".agent.md",provider:"copilot"},{name:"Cursor",dir:".cursor"},{name:"Codex",dir:".codex",agentSuffix:".toml",provider:"codex"},{name:"OpenCode",dir:".opencode"},{name:"Windsurf",dir:".windsurf"},{name:"Agent",dir:".agent"}];var Ci={sonnet:"claude-sonnet-4.6",haiku:"claude-haiku-4.5",opus:"claude-opus-4.6"},ki=["permissionMode","skills","subagentType"];function $i(n){let t=n.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(!t)return`developer_instructions = """
2758
2758
  ${n.replace(/"""/g,'\\"\\"\\"').trim()}
2759
2759
  """
2760
- `;let e=t[1],o=t[2].trim(),r=d=>e.match(new RegExp(`^${d}:\\s*(.+)$`,"m"))?.[1]?.trim().replace(/^["']|["']$/g,""),i=r("name")??"",a=r("description")??"",s=o.replace(/"""/g,'\\"\\"\\"');return[`name = ${JSON.stringify(i)}`,`description = ${JSON.stringify(a)}`,`developer_instructions = """
2761
- ${s}
2760
+ `;let e=t[1],o=t[2].trim(),r=d=>e.match(new RegExp(`^${d}:\\s*(.+)$`,"m"))?.[1]?.trim().replace(/^["']|["']$/g,""),i=r("name")??"",s=r("description")??"",a=o.replace(/"""/g,'\\"\\"\\"');return[`name = ${JSON.stringify(i)}`,`description = ${JSON.stringify(s)}`,`developer_instructions = """
2761
+ ${a}
2762
2762
  """`].join(`
2763
2763
  `)+`
2764
- `}function Kt(n,t){if(t==="codex")return $i(n);if(t!=="copilot")return n;let e=n.match(/^---\n([\s\S]*?)\n---\n/);if(!e)return Io(n);let o=e[1],r=n.slice(e.index+e[0].length);o=o.replace(/^(model:\s*)(\S+)([ \t]*)$/m,(a,s,c,d)=>`${s}${ki[c]??c}${d}`);for(let a of Ti)o=o.replace(new RegExp(`^${a}:[^
2764
+ `}function Xt(n,t){if(t==="codex")return $i(n);if(t!=="copilot")return n;let e=n.match(/^---\n([\s\S]*?)\n---\n/);if(!e)return Ro(n);let o=e[1],r=n.slice(e.index+e[0].length);o=o.replace(/^(model:\s*)(\S+)([ \t]*)$/m,(s,a,c,d)=>`${a}${Ci[c]??c}${d}`);for(let s of ki)o=o.replace(new RegExp(`^${s}:[^
2765
2765
  ]*
2766
- ?`,"m"),"");o=o.replace(/\n+$/,"");let i=Io(r);return`---
2766
+ ?`,"m"),"");o=o.replace(/\n+$/,"");let i=Ro(r);return`---
2767
2767
  ${o}
2768
2768
  ---
2769
- ${i}`}function Io(n){return n.replace(/\bAskUserQuestion\b/g,"ask the user directly in your response").replace(/\*\*Construct the Task prompt:\*\*/g,"**Construct the Task prompt (must be fully self-contained \u2014 sub-agents cannot read this conversation's history):**").replace(/\*\*Wait for all agents to complete\*\*/g,"**Wait for all agents to complete** (monitor with `/tasks` in Copilot CLI)").replace("**Launch ALL scene agents in parallel**","**Launch ALL scene agents in parallel** \u2014 each agent must write to its own `Scene[NN][Name].tsx` file. Two agents writing to the same file will silently overwrite each other (no error). Verify unique filenames before spawning.")}function Ii(n,t){let e=ye(n),o=ye(n,t);if(Ci(e,o).startsWith("..")||ye(o)!==o.replace(/\.\./g,""))throw new Error(`Invalid path: "${t}" would escape base directory`);return o}function Ro(n,t,e,o){let r=J(n,"SKILL.md");if(yt(n,{recursive:!0}),bt(r,Kt(t,o),"utf-8"),e&&e.length>0){let i=J(n,"references");yt(i,{recursive:!0});for(let a of e){let s=J(i,`${a.name}.md`);bt(s,a.content,"utf-8")}}}function xt(n,t,e={},o){let r={installed:[],skipped:[],errors:[]},i=e.local?process.cwd():vt();if(e.dir){let a=Oo(ye(e.dir)),s=ne.find(c=>c.dir===a)?.provider;try{let c=ye(e.dir),d=Ii(c,J("skills",n));Ro(d,t,o,s),r.installed.push(e.dir)}catch(c){r.errors.push(`${e.dir}: ${c instanceof Error?c.message:String(c)}`)}}else for(let a of ne){let s=J(i,a.dir),c=J(s,"skills",n),d=J(c,"SKILL.md");if(Le(s)){if(Le(d)&&!e.force){r.skipped.push(a.name);continue}try{Ro(c,t,o,a.provider),r.installed.push(a.name)}catch(m){r.errors.push(`${a.name}: ${m instanceof Error?m.message:String(m)}`)}}}return r}function wt(n,t={}){let e={removed:[],errors:[]},o=t.local?process.cwd():vt();for(let r of ne){let i=J(o,r.dir,"skills",n);if(Le(i))try{Ao(i,{recursive:!0}),e.removed.push(r.name)}catch(a){e.errors.push(`${r.name}: ${a instanceof Error?a.message:String(a)}`)}}return e}function Eo(){return ne.map(n=>n.name)}function Po(n,t,e={}){let o={installed:[],skipped:[],errors:[]};if(e.dir){let a=Oo(ye(e.dir)),s=ne.find(C=>C.dir===a),c=s?.agentSuffix??".md",d=J(ye(e.dir),"agents"),m=J(d,`${n}${c}`);if(Le(m)&&!e.force)o.skipped.push(e.dir);else try{yt(d,{recursive:!0}),bt(m,Kt(t,s?.provider),"utf-8"),o.installed.push(e.dir)}catch(C){o.errors.push(`${e.dir}: ${C instanceof Error?C.message:String(C)}`)}return o}let r=vt(),i=ne.filter(a=>a.dir===".claude"||a.dir===".github"||a.dir===".codex");for(let a of i){let s=a.agentSuffix??".md",c=J(r,a.dir,"agents"),d=J(c,`${n}${s}`);if(Le(d)&&!e.force){o.skipped.push(a.name);continue}try{yt(c,{recursive:!0}),bt(d,Kt(t,a.provider),"utf-8"),o.installed.push(a.name)}catch(m){o.errors.push(`${a.name}: ${m instanceof Error?m.message:String(m)}`)}}return o}function Fo(n){let t={removed:[],errors:[]},e=vt(),o=ne.filter(r=>r.dir===".claude"||r.dir===".github"||r.dir===".codex");for(let r of o){let i=r.agentSuffix??".md",a=J(e,r.dir,"agents",`${n}${i}`);if(Le(a))try{Ao(a),t.removed.push(r.name)}catch(s){t.errors.push(`${r.name}: ${s instanceof Error?s.message:String(s)}`)}}return t}function Xt(){return`---
2769
+ ${i}`}function Ro(n){return n.replace(/\bAskUserQuestion\b/g,"ask the user directly in your response").replace(/\*\*Construct the Task prompt:\*\*/g,"**Construct the Task prompt (must be fully self-contained \u2014 sub-agents cannot read this conversation's history):**").replace(/\*\*Wait for all agents to complete\*\*/g,"**Wait for all agents to complete** (monitor with `/tasks` in Copilot CLI)").replace("**Launch ALL scene agents in parallel**","**Launch ALL scene agents in parallel** \u2014 each agent must write to its own `Scene[NN][Name].tsx` file. Two agents writing to the same file will silently overwrite each other (no error). Verify unique filenames before spawning.")}function Ii(n,t){let e=be(n),o=be(n,t);if(Ti(e,o).startsWith("..")||be(o)!==o.replace(/\.\./g,""))throw new Error(`Invalid path: "${t}" would escape base directory`);return o}function Ao(n,t,e,o){let r=z(n,"SKILL.md");if(yt(n,{recursive:!0}),bt(r,Xt(t,o),"utf-8"),e&&e.length>0){let i=z(n,"references");yt(i,{recursive:!0});for(let s of e){let a=z(i,`${s.name}.md`);bt(a,s.content,"utf-8")}}}function xt(n,t,e={},o){let r={installed:[],skipped:[],errors:[]},i=e.local?process.cwd():vt();if(e.dir){let s=Eo(be(e.dir)),a=oe.find(c=>c.dir===s)?.provider;try{let c=be(e.dir),d=Ii(c,z("skills",n));Ao(d,t,o,a),r.installed.push(e.dir)}catch(c){r.errors.push(`${e.dir}: ${c instanceof Error?c.message:String(c)}`)}}else for(let s of oe){let a=z(i,s.dir),c=z(a,"skills",n),d=z(c,"SKILL.md");if(Me(a)){if(Me(d)&&!e.force){r.skipped.push(s.name);continue}try{Ao(c,t,o,s.provider),r.installed.push(s.name)}catch(u){r.errors.push(`${s.name}: ${u instanceof Error?u.message:String(u)}`)}}}return r}function wt(n,t={}){let e={removed:[],errors:[]},o=t.local?process.cwd():vt();for(let r of oe){let i=z(o,r.dir,"skills",n);if(Me(i))try{Oo(i,{recursive:!0}),e.removed.push(r.name)}catch(s){e.errors.push(`${r.name}: ${s instanceof Error?s.message:String(s)}`)}}return e}function Po(){return oe.map(n=>n.name)}function Fo(n,t,e={}){let o={installed:[],skipped:[],errors:[]};if(e.dir){let s=Eo(be(e.dir)),a=oe.find(C=>C.dir===s),c=a?.agentSuffix??".md",d=z(be(e.dir),"agents"),u=z(d,`${n}${c}`);if(Me(u)&&!e.force)o.skipped.push(e.dir);else try{yt(d,{recursive:!0}),bt(u,Xt(t,a?.provider),"utf-8"),o.installed.push(e.dir)}catch(C){o.errors.push(`${e.dir}: ${C instanceof Error?C.message:String(C)}`)}return o}let r=vt(),i=oe.filter(s=>s.dir===".claude"||s.dir===".github"||s.dir===".codex");for(let s of i){let a=s.agentSuffix??".md",c=z(r,s.dir,"agents"),d=z(c,`${n}${a}`);if(Me(d)&&!e.force){o.skipped.push(s.name);continue}try{yt(c,{recursive:!0}),bt(d,Xt(t,s.provider),"utf-8"),o.installed.push(s.name)}catch(u){o.errors.push(`${s.name}: ${u instanceof Error?u.message:String(u)}`)}}return o}function Do(n){let t={removed:[],errors:[]},e=vt(),o=oe.filter(r=>r.dir===".claude"||r.dir===".github"||r.dir===".codex");for(let r of o){let i=r.agentSuffix??".md",s=z(e,r.dir,"agents",`${n}${i}`);if(Me(s))try{Oo(s),t.removed.push(r.name)}catch(a){t.errors.push(`${r.name}: ${a instanceof Error?a.message:String(a)}`)}}return t}function Kt(){return`---
2770
2770
  name: video-scene-reviewer
2771
2771
  description: Strict QA reviewer for a single Remotion scene. Compares code against the video plan checking ColorGrading, transitions, icons, logos, spring physics, idle states, VO-sync, and phase structure. Returns a pass/fail checklist.
2772
2772
  tools: Read, Glob
2773
- model: haiku
2773
+ model: sonnet
2774
2774
  permissionMode: plan
2775
2775
  ---
2776
2776
 
@@ -2867,7 +2867,7 @@ Priority fixes:
2867
2867
  name: video-scene-builder
2868
2868
  description: Builds a single Remotion video scene (.tsx) from a video plan section. Receives global context, scene spec, audio timing, and rhythm cues. Writes the scene file, spawns a reviewer, and iterates until 85%+ quality. One agent per scene.
2869
2869
  tools: Read, Write, Edit, Glob, Grep, Task, Bash
2870
- model: sonnet
2870
+ model: opus
2871
2871
  skills:
2872
2872
  - frontend-design
2873
2873
  - remotion-best-practices
@@ -3050,7 +3050,7 @@ function AnimatedCamera() {
3050
3050
  name: video-audio-director
3051
3051
  description: Generates all audio assets (voiceover TTS, background music, sound effects) and builds the timing manifest that reconciles planned vs actual durations. One agent per video, runs before scene building.
3052
3052
  tools: Read, Bash, Write
3053
- model: sonnet
3053
+ model: opus
3054
3054
  permissionMode: acceptEdits
3055
3055
  ---
3056
3056
 
@@ -3210,7 +3210,7 @@ This saves money and time \u2014 generation is expensive, downloading is free.
3210
3210
  name: video-continuity-editor
3211
3211
  description: Post-build cross-scene QA. Checks transition continuity, color grade flow, timing alignment between Main.tsx and manifest, import consistency, brand coherence, rhythm flow, and music cue alignment. Runs after all scenes are built.
3212
3212
  tools: Read, Glob, Grep
3213
- model: haiku
3213
+ model: sonnet
3214
3214
  permissionMode: plan
3215
3215
  ---
3216
3216
 
@@ -3321,7 +3321,7 @@ FIXES:
3321
3321
  name: video-branding-director
3322
3322
  description: Extracts brand identity (logos, colors, fonts) from a URL or existing profiles. Searches saved brands, extracts new ones via CLI, downloads assets locally, and writes branding.json. Returns success or failure. One agent per video, runs before brief/plan generation.
3323
3323
  tools: Read, Bash, Write
3324
- model: sonnet
3324
+ model: opus
3325
3325
  permissionMode: acceptEdits
3326
3326
  ---
3327
3327
 
@@ -3420,7 +3420,7 @@ Query: <what was searched/extracted>
3420
3420
  - Download logos or images from websites directly (only from branding.json URLs after successful extraction)
3421
3421
  - Create or edit branding.json by hand
3422
3422
  - Ask the user questions \u2014 return failure to the orchestrator instead
3423
- `}function Do(n){return`---
3423
+ `}function No(n){return`---
3424
3424
  name: remotion-scene-craft
3425
3425
  description: Remotion scene coding reference for scene builder agents. DO NOT load this directly \u2014 it is preloaded into video-scene-builder agents via frontmatter. Contains plan vocabulary decoder, 4-phase architecture, VO-sync, animation recipes.
3426
3426
  ---
@@ -3695,84 +3695,84 @@ const glow = interpolate(Math.sin(frame / fps * Math.PI * 2 / 2), [-1, 1], [0.1,
3695
3695
  - Static scenes with no visual change for 2+ seconds -> Every 2s needs a visual event.
3696
3696
  - Generic component substitution -> Plan says WhipPan, use WhipPan. Not slide() or wipe().
3697
3697
  - Unused variables or imports -> Every \`const\`, \`import\`, and \`interpolate()\` call must be used in JSX/return. Remove what you don't use. Do NOT prefix with \`_\` \u2014 delete entirely.
3698
- `}var Xe=["main","video","presentation","presentation-edit","tts","music","sfx","mix","image","video-search","scrape","branding","config"],St=["standalone","studio"],No={cmd:u.commands[0],pkg:u.packageName,url:u.apiUrl,name:u.name},Me=new Ri("skill").description(`Manage ${u.displayName} skills for AI coding assistants`).addHelpText("after",`
3699
- ${D.bold("Skill Types:")}
3700
- ${D.cyan("main")} Main CLI skill with all capabilities overview
3701
- ${D.cyan("video")} Detailed video creation workflow with Remotion/R3F patterns
3702
- ${D.cyan("presentation")} Detailed presentation creation workflow
3703
- ${D.cyan("presentation-edit")} In-app presentation editing (Studio)
3704
-
3705
- ${D.bold("Reference Skills:")}
3706
- ${D.cyan("tts")} Text-to-speech generation (voices, providers, options)
3707
- ${D.cyan("music")} AI music generation (prompts, styles, duration)
3708
- ${D.cyan("sfx")} Sound effects generation (categories, looping, formats)
3709
- ${D.cyan("mix")} Audio mixing (video + voice + music)
3710
- ${D.cyan("image")} Image search and AI generation
3711
- ${D.cyan("video-search")} Stock video search
3712
- ${D.cyan("scrape")} URL content extraction
3713
- ${D.cyan("branding")} Brand profile management
3714
- ${D.cyan("config")} CLI configuration management
3715
-
3716
- ${D.bold("Examples:")}
3717
- ${D.gray("# Install main CLI skill (comprehensive overview)")}
3718
- $ ${u.commands[0]} skill install main
3719
-
3720
- ${D.gray("# Install video skill")}
3721
- $ ${u.commands[0]} skill install video
3722
-
3723
- ${D.gray("# Install presentation skill")}
3724
- $ ${u.commands[0]} skill install presentation
3725
-
3726
- ${D.gray("# Install all skills")}
3727
- $ ${u.commands[0]} skill install
3728
-
3729
- ${D.gray("# Install to specific directory")}
3730
- $ ${u.commands[0]} skill install main --dir ~/.claude
3731
-
3732
- ${D.gray("# Show skill content")}
3733
- $ ${u.commands[0]} skill show main
3734
- `);Me.command("install").description(`Install ${u.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(n,t)=>{t.mode&&!St.includes(t.mode)&&(l(`Invalid mode: ${t.mode}. Must be one of: ${St.join(", ")}`),process.exit(1));let e={...No,mode:t.mode},o=[];n&&!Xe.includes(n)&&(l(`Invalid skill type: ${n}. Must be one of: ${Xe.join(", ")}`),process.exit(1));let r=[{name:"tts",content:Re(e)},{name:"music",content:Ae(e)},{name:"sfx",content:Oe(e)},{name:"mix",content:Ee(e)},{name:"image",content:Pe(e)},{name:"video-search",content:Fe(e)},{name:"scrape",content:De(e)},{name:"branding",content:Ne(e)},{name:"config",content:Ue(e)}];(!n||n==="main")&&o.push({name:u.name,content:pt(e),references:r});let i=[{name:"brief-guide",content:Jt.render(e)},{name:"website-assets",content:Ht.render(e)},{name:"source-scraping",content:zt.render(e)}];(!n||n==="video")&&(o.push({name:`${u.name}-video`,content:ft(e),references:i}),o.push({name:"remotion-scene-craft",content:Do(e)})),(!n||n==="presentation")&&o.push({name:`${u.name}-presentation`,content:gt(e)}),(!n||n==="presentation-edit")&&o.push({name:`${u.name}-presentation-edit`,content:ht(e)}),n==="tts"&&o.push({name:`${u.name}-tts`,content:Re(e)}),n==="music"&&o.push({name:`${u.name}-music`,content:Ae(e)}),n==="sfx"&&o.push({name:`${u.name}-sfx`,content:Oe(e)}),n==="mix"&&o.push({name:`${u.name}-mix`,content:Ee(e)}),n==="image"&&o.push({name:`${u.name}-image`,content:Pe(e)}),n==="video-search"&&o.push({name:`${u.name}-video-search`,content:Fe(e)}),n==="scrape"&&o.push({name:`${u.name}-scrape`,content:De(e)}),n==="branding"&&o.push({name:`${u.name}-branding`,content:Ne(e)}),n==="config"&&o.push({name:`${u.name}-config`,content:Ue(e)}),console.log();for(let a of o){p(`Installing ${a.name}...`);let s=xt(a.name,a.content,{dir:t.dir,local:t.local,force:t.force},a.references);if(s.installed.length>0&&(v(`${a.name} installed successfully`),x(" Installed to",s.installed.join(", "))),s.skipped.length>0&&(p(` Skipped (already exists): ${s.skipped.join(", ")}`),console.log(D.gray(" Use --force to overwrite"))),s.errors.length>0)for(let c of s.errors)l(` ${c}`);s.installed.length===0&&s.skipped.length===0&&s.errors.length===0&&(p(" No supported AI coding assistants detected"),console.log(D.gray(" Supported editors: "+Eo().join(", "))),console.log(D.gray(" Use --dir <path> to install to a specific directory"))),console.log()}if(!n||n==="video"){for(let a of[{name:"video-branding-director",generate:()=>tn(e)},{name:"video-scene-builder",generate:Qt},{name:"video-scene-reviewer",generate:Xt},{name:"video-audio-director",generate:()=>Zt(e)},{name:"video-continuity-editor",generate:en}]){p(`Installing ${a.name} agent...`);let s=Po(a.name,a.generate(),{force:t.force,dir:t.dir});if(s.installed.length>0){v(`${a.name} agent installed`);let c={"Claude Code":"~/.claude/agents/","GitHub Copilot":"~/.github/agents/"};x(" Installed to",s.installed.map(d=>t.dir?d:`${d} (${c[d]??"~/.<editor>/agents/"})`).join(", "))}s.skipped.length>0&&p(` Agent skipped (already exists): ${s.skipped.join(", ")}`)}console.log()}});Me.command("show").description("Display skill content").argument("[type]","Skill type (default: main)").option("-m, --mode <mode>","Skill mode: standalone or studio","standalone").action((n="main",t)=>{t.mode&&!St.includes(t.mode)&&(l(`Invalid mode: ${t.mode}. Must be one of: ${St.join(", ")}`),process.exit(1));let e={...No,mode:t.mode},r={main:()=>pt(e),video:()=>ft(e),presentation:()=>gt(e),"presentation-edit":()=>ht(e),tts:()=>Re(e),music:()=>Ae(e),sfx:()=>Oe(e),mix:()=>Ee(e),image:()=>Pe(e),"video-search":()=>Fe(e),scrape:()=>De(e),branding:()=>Ne(e),config:()=>Ue(e),"video-branding-director":()=>tn(e),"video-scene-builder":()=>Qt(),"video-scene-reviewer":()=>Xt(),"video-audio-director":()=>Zt(e),"video-continuity-editor":()=>en()}[n];if(r)console.log(r());else{let i=[...Xe,"video-branding-director","video-scene-builder","video-scene-reviewer","video-audio-director","video-continuity-editor"];l(`Invalid skill type: ${n}. Must be one of: ${i.join(", ")}`),process.exit(1)}});Me.command("uninstall").description(`Remove ${u.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(n,t)=>{let e=[];n&&!Xe.includes(n)&&(l(`Invalid skill type: ${n}. Must be one of: ${Xe.join(", ")}`),process.exit(1)),(!n||n==="main")&&e.push(u.name),(!n||n==="video")&&(e.push(`${u.name}-video`),e.push("remotion-scene-craft")),(!n||n==="presentation")&&e.push(`${u.name}-presentation`),(!n||n==="presentation-edit")&&e.push(`${u.name}-presentation-edit`),(!n||n==="tts")&&e.push(`${u.name}-tts`),(!n||n==="music")&&e.push(`${u.name}-music`),(!n||n==="sfx")&&e.push(`${u.name}-sfx`),(!n||n==="mix")&&e.push(`${u.name}-mix`),(!n||n==="image")&&e.push(`${u.name}-image`),(!n||n==="video-search")&&e.push(`${u.name}-video-search`),(!n||n==="scrape")&&e.push(`${u.name}-scrape`),(!n||n==="branding")&&e.push(`${u.name}-branding`),(!n||n==="config")&&e.push(`${u.name}-config`),console.log();for(let o of e){let r=wt(o,{local:t.local});if(r.removed.length>0?(v(`${o} uninstalled`),x(" Removed from",r.removed.join(", "))):p(` ${o} not found`),r.errors.length>0)for(let i of r.errors)I(` Failed to remove: ${i}`)}if(!n||n==="video")for(let o of["video-branding-director","video-scene-builder","video-scene-reviewer","video-audio-director","video-continuity-editor"])Fo(o).removed.length>0&&v(`${o} agent uninstalled`);console.log()});import{Command as nn}from"commander";import jo from"ora";import{writeFile as Uo,mkdir as Ai}from"fs/promises";import{dirname as Oi}from"path";var Lo="en-US-Neural2-C",Mo="gemini",Ei=new nn("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: ${Lo})`).option("-p, --provider <provider>",`Provider: gemini, elevenlabs, openai (default: ${Mo})`).option("-m, --model <model>","Model (provider-specific)").option("-s, --speed <speed>","Speech speed 0.25-4.0 (default: 1.0)").option("--speakers <json>",`Multi-speaker (Gemini, max 2): '[{"name":"Joe","voice":"Kore"},{"name":"Jane","voice":"Puck"}]'`).option("-i, --instructions <text>","Style prompt (OpenAI gpt-4o-mini-tts): tone, accent, speed, emotion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async n=>{let t=n.format,e=t==="human"?jo("Generating speech...").start():null,o;n.speed&&(o=parseFloat(n.speed),(isNaN(o)||o<.25||o>4)&&(e?.stop(),l("Speed must be between 0.25 and 4.0"),process.exit(S.INVALID_INPUT)));let r;if(n.speakers)try{r=JSON.parse(n.speakers),(!Array.isArray(r)||r.length>2)&&(e?.stop(),l("Speakers must be an array with max 2 items"),process.exit(S.INVALID_INPUT))}catch{e?.stop(),l(`Invalid --speakers JSON. Example: '[{"name":"Joe","voice":"Kore"}]'`),process.exit(S.INVALID_INPUT)}try{let i=n.voiceId,a=n.voice||Lo,s=n.provider||Mo,c={};r&&(c.gemini={speakers:r}),n.instructions&&(c.openai={instructions:n.instructions});let d=await ct({text:n.text,options:{provider:s,voiceId:i,voice:a,model:n.model,speed:o,providerOptions:Object.keys(c).length>0?c:void 0}});e?.stop();let m=n.output.endsWith(`.${d.format}`)?n.output:`${n.output}.${d.format}`;await Ai(Oi(m),{recursive:!0}),await Uo(m,d.audioData);let C=m.replace(/\.[^.]+$/,".txt");if(await Uo(C,n.text,"utf-8"),t==="json"){V({status:"completed",output:m,duration:d.duration,provider:d.provider,format:d.format});return}if(t==="quiet"){console.log(m);return}v(`Saved to: ${m}`),p(`Duration: ${d.duration.toFixed(2)}s`),p(`Provider: ${d.provider}`),p(`Cost: $${d.cost.toFixed(6)}`)}catch(i){e?.stop(),l(i instanceof Error?i.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),Pi=new nn("voices").description("List available voices").option("-p, --provider <provider>","Filter by provider: gemini, elevenlabs, openai").option("-f, --format <format>","Output format: human, json","human").action(async n=>{let t=n.format==="human"?jo("Fetching voices...").start():null;try{let e=await Yn(n.provider);if(t?.stop(),n.format==="json"){V(e.voices);return}if(Array.isArray(e.voices)){let o=n.provider?.toUpperCase()||"VOICES";console.log(),console.log(`${o} Voices:`),console.log("-".repeat(50));for(let r of e.voices)console.log(` ${r.name} (${r.id})`),console.log(` ${r.description}`)}else for(let[o,r]of Object.entries(e.voices))if(!(!r||r.length===0)){console.log(),console.log(`${o.toUpperCase()} Voices:`),console.log("-".repeat(50));for(let i of r)console.log(` ${i.name} (${i.id})`),console.log(` ${i.description}`)}}catch(e){t?.stop(),l(e instanceof Error?e.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),Vo=new nn("tts").description("Text-to-speech commands").addCommand(Ei).addCommand(Pi);import{Command as an}from"commander";import on from"ora";import{writeFile as _o,mkdir as Fi}from"fs/promises";import{dirname as Di}from"path";function rn(n,t){if(t==="json"){let{cost:e,...o}=n;V(o);return}if(t==="quiet"){n.audioUrl?console.log(n.audioUrl):console.log(n.requestId);return}p(`Request ID: ${n.requestId}`),p(`Status: ${n.status}`),n.duration&&p(`Duration: ${n.duration}s`),n.audioUrl&&v(`Audio URL: ${n.audioUrl}`),n.cost!==void 0&&p(`Cost: $${n.cost.toFixed(4)}`),n.error&&l(`Error: ${n.error}`)}async function Ni(n,t){if(await Fi(Di(t),{recursive:!0}),n.startsWith("data:")){let r=n.match(/^data:[^;]+;base64,(.+)$/);if(!r)throw new Error("Invalid data URL format");let i=Buffer.from(r[1],"base64");await _o(t,i);return}let e=await fetch(n);if(!e.ok)throw new Error(`Failed to download: ${e.status}`);let o=await e.arrayBuffer();await _o(t,Buffer.from(o))}var Ui=new an("generate").description("Generate music from a text prompt").requiredOption("-p, --prompt <text>","Music description").option("-d, --duration <seconds>","Duration in seconds (3-600)","30").option("-s, --style <style>","Style preset").option("--provider <provider>","Provider (elevenlabs, suno)").option("-o, --output <path>","Output file path").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async n=>{let t=parseInt(n.duration,10);(isNaN(t)||t<3||t>600)&&(l("Duration must be between 3 and 600 seconds (10 minutes)"),process.exit(S.INVALID_INPUT));let e=n.format,o=e==="human"?on("Generating music...").start():null;try{let r=await lt({prompt:n.prompt,duration:t,options:{provider:n.provider,style:n.style}});if(!n.wait){o?.stop(),rn(r,e);return}let i=r;if(r.status!=="completed"&&r.status!=="failed"&&(o&&(o.text=`Processing (ID: ${r.requestId})...`),i=await de(()=>ze(r.requestId),60,2e3)),o?.stop(),i.status==="failed"&&(l(i.error||"Music generation failed"),process.exit(S.GENERAL_ERROR)),rn(i,e),n.output&&i.audioUrl){let a=e==="human"?on("Downloading...").start():null;try{await Ni(i.audioUrl,n.output),a?.stop(),e==="human"&&v(`Saved to: ${n.output}`)}catch(s){a?.stop(),I(`Failed to download: ${s instanceof Error?s.message:"Unknown error"}`)}}}catch(r){o?.stop(),l(r instanceof Error?r.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),Li=new an("status").description("Check status of a music generation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{let e=t.format==="human"?on("Checking status...").start():null;try{let o=await ze(n);e?.stop(),rn(o,t.format)}catch(o){e?.stop(),l(o instanceof Error?o.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),qo=new an("music").description("Music generation commands").addCommand(Ui).addCommand(Li);import{Command as ln}from"commander";import sn from"ora";import{writeFile as Mi}from"fs/promises";function cn(n,t){if(t==="json"){let{cost:e,...o}=n;V(o);return}if(t==="quiet"){n.outputUrl?console.log(n.outputUrl):console.log(n.requestId);return}p(`Request ID: ${n.requestId}`),p(`Status: ${n.status}`),n.duration&&p(`Duration: ${n.duration}s`),n.outputUrl&&v(`Output URL: ${n.outputUrl}`),n.cost!==void 0&&p(`Cost: $${n.cost.toFixed(4)}`),n.error&&l(`Error: ${n.error}`)}async function ji(n,t){let e=await fetch(n);if(!e.ok)throw new Error(`Failed to download: ${e.status}`);let o=await e.arrayBuffer();await Mi(t,Buffer.from(o))}var Vi=new ln("create").description("Mix audio tracks into a video (music will loop to match video duration)").requiredOption("--video <url>","Input video file/URL").option("--music <url>","Background music file/URL (will loop if shorter than video)").option("--voice <url>","Voiceover file/URL").option("--music-volume <percent>","Music volume 0-100 (default: 30, recommended for mix with voice)","30").option("--voice-volume <percent>","Voice volume 0-100","100").option("-o, --output <path>","Output file path").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async n=>{!n.music&&!n.voice&&(l("At least one of --music or --voice must be provided"),process.exit(S.INVALID_INPUT));let t=parseInt(n.musicVolume,10)/100,e=parseInt(n.voiceVolume,10)/100;(isNaN(t)||t<0||t>1)&&(l("Music volume must be between 0 and 100"),process.exit(S.INVALID_INPUT)),(isNaN(e)||e<0||e>2)&&(l("Voice volume must be between 0 and 200"),process.exit(S.INVALID_INPUT));let o=n.format,r=o==="human"?sn("Mixing audio...").start():null,i=[{url:n.video,role:"video"}];n.music&&i.push({url:n.music,role:"background",volume:t*5}),n.voice&&i.push({url:n.voice,role:"voice",volume:e*2});try{let a=await Hn({operation:"add-to-video",inputs:i,options:{musicVolume:t,voiceVolume:e}});if(!n.wait){r?.stop(),cn(a,o);return}r&&(r.text=`Processing (ID: ${a.requestId})...`);let s=await de(()=>Vt(a.requestId),120,3e3);if(r?.stop(),s.status==="failed"&&(l(s.error||"Audio mixing failed"),process.exit(S.GENERAL_ERROR)),cn(s,o),n.output&&s.outputUrl){let c=o==="human"?sn("Downloading...").start():null;try{await ji(s.outputUrl,n.output),c?.stop(),o==="human"&&v(`Saved to: ${n.output}`)}catch(d){c?.stop(),I(`Failed to download: ${d instanceof Error?d.message:"Unknown error"}`)}}}catch(a){r?.stop(),l(a instanceof Error?a.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),_i=new ln("status").description("Check status of an audio mix request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{let e=t.format==="human"?sn("Checking status...").start():null;try{let o=await Vt(n);e?.stop(),cn(o,t.format)}catch(o){e?.stop(),l(o instanceof Error?o.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),Bo=new ln("mix").description("Audio mixing commands").addCommand(Vi).addCommand(_i);import{Command as Go}from"commander";import qi from"ora";var Bi=new Go("search").description("Search for images").requiredOption("-q, --query <query>","Search query").option("-n, --max-results <number>","Maximum number of results (default: 10)").option("-s, --size <size>","Image size: small, medium, large, any","large").option("--safe-search","Enable safe search (default: true)",!0).option("--no-safe-search","Disable safe search").option("-f, --format <format>","Output format: human, json, quiet","human").action(async n=>{let t=n.format,e=t==="human"?qi("Searching for images...").start():null,o;n.maxResults&&(o=parseInt(n.maxResults,10),(isNaN(o)||o<1)&&(e?.stop(),l("Max results must be a positive number"),process.exit(S.INVALID_INPUT)));try{let r=await dt({query:n.query,options:{maxResults:o||10,size:n.size,safeSearch:n.safeSearch}});e?.stop(),r.success||(l("Search failed"),process.exit(S.GENERAL_ERROR));let i=r.data.results.flatMap(a=>a.results.map(s=>({...s,provider:a.providerName})));if(t==="json"){V({success:!0,query:n.query,totalResults:i.length,images:i});return}if(t==="quiet"){for(let a of i)console.log(a.url);return}if(i.length===0){p("No images found");return}v(`Found ${i.length} images for "${n.query}"`),console.log();for(let a=0;a<i.length;a++){let s=i[a];console.log(`[${a+1}] ${s.title||"Untitled"}`),console.log(` URL: ${s.url}`),console.log(` Size: ${s.width}x${s.height}`),s.author&&console.log(` Author: ${s.author}`),console.log(` Provider: ${s.provider}`),console.log()}p(`Total cost: $${r.data.totalCost.toFixed(4)}`)}catch(r){e?.stop(),l(r instanceof Error?r.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),Wo=new Go("image").description("Image search commands").addCommand(Bi);import{Command as se}from"commander";import Ze from"ora";import{mkdir as Be,writeFile as ae,readFile as Rt,access as mn,rm as un}from"fs/promises";import{join as j,resolve as Qe}from"path";import{execSync as qe,spawn as oa,spawnSync as ra}from"child_process";import ia from"ffmpeg-static";import{homedir as Gi}from"os";import{join as Yo}from"path";import{readdir as Wi}from"fs/promises";var Yi="conceptcraft";function je(){return Yo(Gi(),`.${Yi}`,"projects")}function Ct(n){return Yo(je(),n)}async function dn(){try{let n=je();return(await Wi(n,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>e.name)}catch{return[]}}function Ho(n,t){let e=2,o=`${n}-${e}`;for(;t.includes(o);)e++,o=`${n}-${e}`;return o}import{Command as Hi}from"commander";import Ji from"ora";import{execSync as zi,spawnSync as Ve}from"child_process";import{mkdirSync as Jo,existsSync as Tt,readFileSync as Ko,writeFileSync as zo}from"fs";import{join as be,basename as Ki}from"path";import{tmpdir as Xi}from"os";function $t(n,t){try{return zi(t,{stdio:"ignore"}),!0}catch{return!1}}function kt(n){let t=Math.floor(n/60),e=Math.floor(n%60),o=Math.round(n%1*10);return`${t}:${String(e).padStart(2,"0")}.${o}`}function Qi(n){let t=Ve("ffprobe",["-v","error","-show_entries","format=duration","-of","default=noprint_wrappers=1:nokey=1",n],{encoding:"utf-8"});return parseFloat(t.stdout.trim())}function Zi(n,t){let e=Ve("ffmpeg",["-i",n,"-vf",`select='gt(scene,${t})',showinfo`,"-vsync","vfr","-f","null","-"],{encoding:"utf-8",timeout:12e4}),o=[0],r=(e.stderr||"").split(`
3735
- `);for(let i of r){let a=i.match(/pts_time:([\d.]+)/);if(a){let s=parseFloat(a[1]);s-o[o.length-1]>=1.5&&o.push(s)}}return o}function ea(n,t,e){let o=[];for(let r=0;r<t.length;r++){let i=t[r]+.5,a=be(e,`scene_${String(r+1).padStart(2,"0")}.jpg`);Ve("ffmpeg",["-ss",String(i),"-i",n,"-vframes","1","-q:v","2","-y",a],{stdio:"ignore",timeout:3e4}),o.push(a)}return o}function ta(n,t){let e=be(t,"audio.wav");if(Ve("ffmpeg",["-i",n,"-vn","-acodec","pcm_s16le","-ar","16000","-ac","1","-y",e],{stdio:"ignore",timeout:6e4}),!Tt(e)||!$t("whisper","which whisper")&&!$t("whisper-cpp","which whisper-cpp"))return null;let r=Ve("whisper",[e,"--model","base","--output_format","json","--output_dir",t,"--language","en"],{encoding:"utf-8",timeout:3e5}),i=be(t,"audio.json");if(!Tt(i))return null;try{let a=JSON.parse(Ko(i,"utf-8"));return{text:a.text||"",segments:(a.segments||[]).map(s=>({start:s.start,end:s.end,text:s.text?.trim()||""}))}}catch{return null}}function na(n,t){let e=Ko(n).toString("base64"),o=JSON.stringify({model:t,prompt:"Describe this image in one short sentence (max 15 words). Focus on: what is shown, the setting, key objects or people.",images:[e],stream:!1}),r=Ve("curl",["-s","-X","POST","http://localhost:11434/api/generate","-H","Content-Type: application/json","-d",o],{encoding:"utf-8",timeout:6e4});try{return(JSON.parse(r.stdout).response||"").replace(/!!!IMAGE!!!/gi,"").replace(/\[image[^\]]*\]/gi,"").trim()||"Unable to describe frame"}catch{return"Unable to describe frame"}}var Xo=new Hi("analyze").description("Analyze a video file: detect scenes, transcribe audio, describe frames").argument("<file>","Path to video file").option("-o, --output <path>","Output directory for analysis results").option("-t, --threshold <number>","Scene detection threshold (0-1, lower = more scenes)","0.3").option("-m, --model <name>","Ollama vision model","moondream").option("--no-vision","Skip frame description (faster)").option("--no-transcribe","Skip audio transcription").option("-f, --output-format <format>","Output format: human, json","human").action(async(n,t)=>{let e=Ji();Tt(n)||(console.error(`File not found: ${n}`),process.exit(1)),$t("ffmpeg","which ffmpeg")||(console.error("ffmpeg is required. Install: brew install ffmpeg"),process.exit(1)),t.vision!==!1&&!$t("ollama","which ollama")&&(console.error("ollama is required for vision. Install: brew install ollama"),process.exit(1));let o=t.output||be(Xi(),`video-analyze-${Date.now()}`);Jo(o,{recursive:!0});let r=be(o,"frames");Jo(r,{recursive:!0});let i=parseFloat(t.threshold),a=t.model;e.start("Reading video metadata...");let s=Qi(n);e.succeed(`Video: ${kt(s)} (${s.toFixed(1)}s)`),e.start("Detecting scenes...");let c=Zi(n,i);e.succeed(`Detected ${c.length} scenes`),e.start("Extracting key frames...");let d=ea(n,c,r);e.succeed(`Extracted ${d.length} key frames`);let m=null;t.transcribe!==!1&&(e.start("Transcribing audio..."),m=ta(n,o),m?e.succeed(`Transcribed: ${m.segments.length} segments`):e.warn("Transcription skipped (whisper not installed: pip install openai-whisper)"));let C=[];for(let f=0;f<c.length;f++){let w=c[f],$=f<c.length-1?c[f+1]:s,k="";t.vision!==!1&&Tt(d[f])&&(e.start(`Describing scene ${f+1}/${c.length}...`),k=na(d[f],a),e.succeed(`Scene ${f+1}: ${k}`)),C.push({id:f+1,startTime:w,endTime:$,duration:$-w,framePath:d[f],description:k})}let h={source:n,duration:s,scenes:C,transcript:m};if(t.outputFormat==="json"){let f=JSON.stringify(h,null,2),w=be(o,"analysis.json");zo(w,f),console.log(f)}else{let f=["# Video Analysis","",`**Source:** ${Ki(n)}`,`**Duration:** ${kt(s)} (${s.toFixed(1)}s)`,`**Scenes:** ${C.length}`,"","## Scenes",""];for(let k of C){if(f.push(`### Scene ${k.id} (${kt(k.startTime)} - ${kt(k.endTime)}) [${k.duration.toFixed(1)}s]`),k.description&&f.push(`**Visual:** ${k.description}`),m?.segments){let y=m.segments.filter(R=>R.end>k.startTime&&R.start<k.endTime);y.length>0&&f.push(`**Audio:** ${y.map(R=>R.text).join(" ").trim()}`)}f.push(`**Frame:** ${k.framePath}`),f.push("")}m?.text&&(f.push("## Full Transcript"),f.push(""),f.push(m.text.trim()),f.push(""));let w=f.join(`
3736
- `),$=be(o,"analysis.md");zo($,w),console.log(w),console.log(`
3737
- Results saved to: ${o}`)}});var aa="inizio-inc/remotion-video-template#main",_e=30;async function sa(n){let t=await Rt(n,"utf-8");return JSON.parse(t)}async function ca(n){let t=j(n,"template.manifest.json");try{return await sa(t)}catch{return{entry:"src/Root.tsx",compositions:[{id:"Main",type:"youtube",aspect:"16:9",default:!0}]}}}function Qo(){try{return qe("bun --version",{stdio:"ignore"}),!0}catch{return!1}}function la(n){if(n.includes("---")||n.includes("[Section")){let r=n.split(/---|\[Section \d+\]/i).filter(i=>i.trim());if(r.length>1)return r.map(i=>i.trim())}let t=n.split(/(?<=[.!?])\s+/).map(r=>r.trim()).filter(r=>r.length>0),e=[],o="";for(let r of t){let i=r.split(/\s+/).length;o?(e.push(`${o} ${r}`),o=""):i<5&&e.length<t.length-1?o=r:e.push(r)}return o&&(e.length>0?e[e.length-1]+=` ${o}`:e.push(o)),e}function da(n,t,e=_e,o){if(o&&o.characters.length>0)return ma(n,o,e);let r=n.reduce((a,s)=>a+s.split(/\s+/).length,0),i=0;return n.map((a,s)=>{let c=a.split(/\s+/).length,d=c/r,m=t*d,C=Math.round(m*e),h=a.split(""),f=m/h.length,w={characters:h,characterStartTimesSeconds:h.map((k,y)=>y*f),characterEndTimesSeconds:h.map((k,y)=>(y+1)*f)},$={id:s+1,text:a,wordCount:c,startTime:i,endTime:i+m,durationInSeconds:m,durationInFrames:C,timestamps:w};return i+=m,$})}function ma(n,t,e){let{characters:o,characterStartTimesSeconds:r,characterEndTimesSeconds:i}=t,a=o.join(""),s=[],c=0;for(let d=0;d<n.length;d++){let m=n[d],C=m.length;for(;c<o.length&&o[c].match(/^\s*$/);)c++;let h=c,f=r[h]||0;c+=C;let w=c-1;for(;w>h&&o[w]?.match(/^\s*$/);)w--;let $=i[Math.min(w,i.length-1)]||f+1,k=$-f,y=Math.round(k*e),R={characters:o.slice(h,w+1),characterStartTimesSeconds:r.slice(h,w+1).map(T=>T-f),characterEndTimesSeconds:i.slice(h,w+1).map(T=>T-f)};s.push({id:d+1,text:m,wordCount:m.split(/\s+/).length,startTime:f,endTime:$,durationInSeconds:k,durationInFrames:y,timestamps:R})}return s}function ua(n){let t=n==="tiktok"?"vertical":n==="audiogram"?"square":"widescreen";return{scenes:[{name:"Hook",script:"Replace this with a bold opening line that grabs attention.",imageQuery:`cinematic ${t} intro visual, dramatic lighting`,videoQuery:`abstract ${t} motion background`},{name:"Proof",script:"Share the core insight, benefit, or product moment you want viewers to remember.",imageQuery:`people collaborating ${t} office, warm lighting`,videoQuery:`close-up hands using technology ${t}`},{name:"Close",script:"End with a crisp call to action and a confident closing line.",imageQuery:`bold typography ${t} background, high contrast`,videoQuery:`sunrise skyline ${t} timelapse`}],voice:"en-US-Neural2-C",voiceSettings:{speed:1,stability:.4,style:.6},musicPrompt:"uplifting cinematic background, modern and confident"}}async function pa(n,t,e){let o=j(n,"public"),r=j(n,"scripts");await Be(o,{recursive:!0}),await Be(r,{recursive:!0});let i=j(o,"scenes.json");await ae(i,JSON.stringify(ua(t),null,2),"utf-8");let a=`import { execSync } from "node:child_process";
3698
+ `}var Ke=["main","video","presentation","presentation-edit","tts","music","sfx","mix","image","video-search","scrape","branding","config"],St=["standalone","studio"],Uo={cmd:m.commands[0],pkg:m.packageName,url:m.apiUrl,name:m.name},je=new Ri("skill").description(`Manage ${m.displayName} skills for AI coding assistants`).addHelpText("after",`
3699
+ ${N.bold("Skill Types:")}
3700
+ ${N.cyan("main")} Main CLI skill with all capabilities overview
3701
+ ${N.cyan("video")} Detailed video creation workflow with Remotion/R3F patterns
3702
+ ${N.cyan("presentation")} Detailed presentation creation workflow
3703
+ ${N.cyan("presentation-edit")} In-app presentation editing (Studio)
3704
+
3705
+ ${N.bold("Reference Skills:")}
3706
+ ${N.cyan("tts")} Text-to-speech generation (voices, providers, options)
3707
+ ${N.cyan("music")} AI music generation (prompts, styles, duration)
3708
+ ${N.cyan("sfx")} Sound effects generation (categories, looping, formats)
3709
+ ${N.cyan("mix")} Audio mixing (video + voice + music)
3710
+ ${N.cyan("image")} Image search and AI generation
3711
+ ${N.cyan("video-search")} Stock video search
3712
+ ${N.cyan("scrape")} URL content extraction
3713
+ ${N.cyan("branding")} Brand profile management
3714
+ ${N.cyan("config")} CLI configuration management
3715
+
3716
+ ${N.bold("Examples:")}
3717
+ ${N.gray("# Install main CLI skill (comprehensive overview)")}
3718
+ $ ${m.commands[0]} skill install main
3719
+
3720
+ ${N.gray("# Install video skill")}
3721
+ $ ${m.commands[0]} skill install video
3722
+
3723
+ ${N.gray("# Install presentation skill")}
3724
+ $ ${m.commands[0]} skill install presentation
3725
+
3726
+ ${N.gray("# Install all skills")}
3727
+ $ ${m.commands[0]} skill install
3728
+
3729
+ ${N.gray("# Install to specific directory")}
3730
+ $ ${m.commands[0]} skill install main --dir ~/.claude
3731
+
3732
+ ${N.gray("# Show skill content")}
3733
+ $ ${m.commands[0]} skill show main
3734
+ `);je.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(n,t)=>{t.mode&&!St.includes(t.mode)&&(l(`Invalid mode: ${t.mode}. Must be one of: ${St.join(", ")}`),process.exit(1));let e={...Uo,mode:t.mode},o=[];n&&!Ke.includes(n)&&(l(`Invalid skill type: ${n}. Must be one of: ${Ke.join(", ")}`),process.exit(1));let r=[{name:"tts",content:Ae(e)},{name:"music",content:Oe(e)},{name:"sfx",content:Ee(e)},{name:"mix",content:Pe(e)},{name:"image",content:Fe(e)},{name:"video-search",content:De(e)},{name:"scrape",content:Ne(e)},{name:"branding",content:Ue(e)},{name:"config",content:Le(e)}];(!n||n==="main")&&o.push({name:m.name,content:pt(e),references:r});let i=[{name:"brief-guide",content:Jt.render(e)},{name:"website-assets",content:Ht.render(e)},{name:"source-scraping",content:zt.render(e)}];(!n||n==="video")&&(o.push({name:`${m.name}-video`,content:ft(e),references:i}),o.push({name:"remotion-scene-craft",content:No(e)})),(!n||n==="presentation")&&o.push({name:`${m.name}-presentation`,content:gt(e)}),(!n||n==="presentation-edit")&&o.push({name:`${m.name}-presentation-edit`,content:ht(e)}),n==="tts"&&o.push({name:`${m.name}-tts`,content:Ae(e)}),n==="music"&&o.push({name:`${m.name}-music`,content:Oe(e)}),n==="sfx"&&o.push({name:`${m.name}-sfx`,content:Ee(e)}),n==="mix"&&o.push({name:`${m.name}-mix`,content:Pe(e)}),n==="image"&&o.push({name:`${m.name}-image`,content:Fe(e)}),n==="video-search"&&o.push({name:`${m.name}-video-search`,content:De(e)}),n==="scrape"&&o.push({name:`${m.name}-scrape`,content:Ne(e)}),n==="branding"&&o.push({name:`${m.name}-branding`,content:Ue(e)}),n==="config"&&o.push({name:`${m.name}-config`,content:Le(e)}),console.log();for(let s of o){p(`Installing ${s.name}...`);let a=xt(s.name,s.content,{dir:t.dir,local:t.local,force:t.force},s.references);if(a.installed.length>0&&(v(`${s.name} installed successfully`),x(" Installed to",a.installed.join(", "))),a.skipped.length>0&&(p(` Skipped (already exists): ${a.skipped.join(", ")}`),console.log(N.gray(" Use --force to overwrite"))),a.errors.length>0)for(let c of a.errors)l(` ${c}`);a.installed.length===0&&a.skipped.length===0&&a.errors.length===0&&(p(" No supported AI coding assistants detected"),console.log(N.gray(" Supported editors: "+Po().join(", "))),console.log(N.gray(" Use --dir <path> to install to a specific directory"))),console.log()}if(!n||n==="video"){for(let s of[{name:"video-branding-director",generate:()=>tn(e)},{name:"video-scene-builder",generate:Qt},{name:"video-scene-reviewer",generate:Kt},{name:"video-audio-director",generate:()=>Zt(e)},{name:"video-continuity-editor",generate:en}]){p(`Installing ${s.name} agent...`);let a=Fo(s.name,s.generate(),{force:t.force,dir:t.dir});if(a.installed.length>0){v(`${s.name} agent installed`);let c={"Claude Code":"~/.claude/agents/","GitHub Copilot":"~/.github/agents/"};x(" Installed to",a.installed.map(d=>t.dir?d:`${d} (${c[d]??"~/.<editor>/agents/"})`).join(", "))}a.skipped.length>0&&p(` Agent skipped (already exists): ${a.skipped.join(", ")}`)}console.log()}});je.command("show").description("Display skill content").argument("[type]","Skill type (default: main)").option("-m, --mode <mode>","Skill mode: standalone or studio","standalone").action((n="main",t)=>{t.mode&&!St.includes(t.mode)&&(l(`Invalid mode: ${t.mode}. Must be one of: ${St.join(", ")}`),process.exit(1));let e={...Uo,mode:t.mode},r={main:()=>pt(e),video:()=>ft(e),presentation:()=>gt(e),"presentation-edit":()=>ht(e),tts:()=>Ae(e),music:()=>Oe(e),sfx:()=>Ee(e),mix:()=>Pe(e),image:()=>Fe(e),"video-search":()=>De(e),scrape:()=>Ne(e),branding:()=>Ue(e),config:()=>Le(e),"video-branding-director":()=>tn(e),"video-scene-builder":()=>Qt(),"video-scene-reviewer":()=>Kt(),"video-audio-director":()=>Zt(e),"video-continuity-editor":()=>en()}[n];if(r)console.log(r());else{let i=[...Ke,"video-branding-director","video-scene-builder","video-scene-reviewer","video-audio-director","video-continuity-editor"];l(`Invalid skill type: ${n}. Must be one of: ${i.join(", ")}`),process.exit(1)}});je.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(n,t)=>{let e=[];n&&!Ke.includes(n)&&(l(`Invalid skill type: ${n}. Must be one of: ${Ke.join(", ")}`),process.exit(1)),(!n||n==="main")&&e.push(m.name),(!n||n==="video")&&(e.push(`${m.name}-video`),e.push("remotion-scene-craft")),(!n||n==="presentation")&&e.push(`${m.name}-presentation`),(!n||n==="presentation-edit")&&e.push(`${m.name}-presentation-edit`),(!n||n==="tts")&&e.push(`${m.name}-tts`),(!n||n==="music")&&e.push(`${m.name}-music`),(!n||n==="sfx")&&e.push(`${m.name}-sfx`),(!n||n==="mix")&&e.push(`${m.name}-mix`),(!n||n==="image")&&e.push(`${m.name}-image`),(!n||n==="video-search")&&e.push(`${m.name}-video-search`),(!n||n==="scrape")&&e.push(`${m.name}-scrape`),(!n||n==="branding")&&e.push(`${m.name}-branding`),(!n||n==="config")&&e.push(`${m.name}-config`),console.log();for(let o of e){let r=wt(o,{local:t.local});if(r.removed.length>0?(v(`${o} uninstalled`),x(" Removed from",r.removed.join(", "))):p(` ${o} not found`),r.errors.length>0)for(let i of r.errors)A(` Failed to remove: ${i}`)}if(!n||n==="video")for(let o of["video-branding-director","video-scene-builder","video-scene-reviewer","video-audio-director","video-continuity-editor"])Do(o).removed.length>0&&v(`${o} agent uninstalled`);console.log()});import{Command as nn}from"commander";import Vo from"ora";import{writeFile as Lo,mkdir as Ai}from"fs/promises";import{dirname as Oi}from"path";var Mo="en-US-Neural2-C",jo="gemini",Ei=new nn("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: ${Mo})`).option("-p, --provider <provider>",`Provider: gemini, elevenlabs, openai (default: ${jo})`).option("-m, --model <model>","Model (provider-specific)").option("-s, --speed <speed>","Speech speed 0.25-4.0 (default: 1.0)").option("--speakers <json>",`Multi-speaker (Gemini, max 2): '[{"name":"Joe","voice":"Kore"},{"name":"Jane","voice":"Puck"}]'`).option("-i, --instructions <text>","Style prompt (OpenAI gpt-4o-mini-tts): tone, accent, speed, emotion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async n=>{let t=n.format,e=t==="human"?Vo("Generating speech...").start():null,o;n.speed&&(o=parseFloat(n.speed),(isNaN(o)||o<.25||o>4)&&(e?.stop(),l("Speed must be between 0.25 and 4.0"),process.exit(T.INVALID_INPUT)));let r;if(n.speakers)try{r=JSON.parse(n.speakers),(!Array.isArray(r)||r.length>2)&&(e?.stop(),l("Speakers must be an array with max 2 items"),process.exit(T.INVALID_INPUT))}catch{e?.stop(),l(`Invalid --speakers JSON. Example: '[{"name":"Joe","voice":"Kore"}]'`),process.exit(T.INVALID_INPUT)}try{let i=n.voiceId,s=n.voice||Mo,a=n.provider||jo,c={};r&&(c.gemini={speakers:r}),n.instructions&&(c.openai={instructions:n.instructions});let d=await ct({text:n.text,options:{provider:a,voiceId:i,voice:s,model:n.model,speed:o,providerOptions:Object.keys(c).length>0?c:void 0}});e?.stop();let u=n.output.endsWith(`.${d.format}`)?n.output:`${n.output}.${d.format}`;await Ai(Oi(u),{recursive:!0}),await Lo(u,d.audioData);let C=u.replace(/\.[^.]+$/,".txt");if(await Lo(C,n.text,"utf-8"),t==="json"){_({status:"completed",output:u,duration:d.duration,provider:d.provider,format:d.format});return}if(t==="quiet"){console.log(u);return}v(`Saved to: ${u}`),p(`Duration: ${d.duration.toFixed(2)}s`),p(`Provider: ${d.provider}`),p(`Cost: $${d.cost.toFixed(6)}`)}catch(i){e?.stop(),l(i instanceof Error?i.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),Pi=new nn("voices").description("List available voices").option("-p, --provider <provider>","Filter by provider: gemini, elevenlabs, openai").option("-f, --format <format>","Output format: human, json","human").action(async n=>{let t=n.format==="human"?Vo("Fetching voices...").start():null;try{let e=await Hn(n.provider);if(t?.stop(),n.format==="json"){_(e.voices);return}if(Array.isArray(e.voices)){let o=n.provider?.toUpperCase()||"VOICES";console.log(),console.log(`${o} Voices:`),console.log("-".repeat(50));for(let r of e.voices)console.log(` ${r.name} (${r.id})`),console.log(` ${r.description}`)}else for(let[o,r]of Object.entries(e.voices))if(!(!r||r.length===0)){console.log(),console.log(`${o.toUpperCase()} Voices:`),console.log("-".repeat(50));for(let i of r)console.log(` ${i.name} (${i.id})`),console.log(` ${i.description}`)}}catch(e){t?.stop(),l(e instanceof Error?e.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),_o=new nn("tts").description("Text-to-speech commands").addCommand(Ei).addCommand(Pi);import{Command as sn}from"commander";import on from"ora";import{writeFile as qo,mkdir as Fi}from"fs/promises";import{dirname as Di}from"path";function rn(n,t){if(t==="json"){let{cost:e,...o}=n;_(o);return}if(t==="quiet"){n.audioUrl?console.log(n.audioUrl):console.log(n.requestId);return}p(`Request ID: ${n.requestId}`),p(`Status: ${n.status}`),n.duration&&p(`Duration: ${n.duration}s`),n.audioUrl&&v(`Audio URL: ${n.audioUrl}`),n.cost!==void 0&&p(`Cost: $${n.cost.toFixed(4)}`),n.error&&l(`Error: ${n.error}`)}async function Ni(n,t){if(await Fi(Di(t),{recursive:!0}),n.startsWith("data:")){let r=n.match(/^data:[^;]+;base64,(.+)$/);if(!r)throw new Error("Invalid data URL format");let i=Buffer.from(r[1],"base64");await qo(t,i);return}let e=await fetch(n);if(!e.ok)throw new Error(`Failed to download: ${e.status}`);let o=await e.arrayBuffer();await qo(t,Buffer.from(o))}var Ui=new sn("generate").description("Generate music from a text prompt").requiredOption("-p, --prompt <text>","Music description").option("-d, --duration <seconds>","Duration in seconds (3-600)","30").option("-s, --style <style>","Style preset").option("--provider <provider>","Provider (elevenlabs, suno)").option("-o, --output <path>","Output file path").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async n=>{let t=parseInt(n.duration,10);(isNaN(t)||t<3||t>600)&&(l("Duration must be between 3 and 600 seconds (10 minutes)"),process.exit(T.INVALID_INPUT));let e=n.format,o=e==="human"?on("Generating music...").start():null;try{let r=await lt({prompt:n.prompt,duration:t,options:{provider:n.provider,style:n.style}});if(!n.wait){o?.stop(),rn(r,e);return}let i=r;if(r.status!=="completed"&&r.status!=="failed"&&(o&&(o.text=`Processing (ID: ${r.requestId})...`),i=await ue(()=>ze(r.requestId),60,2e3)),o?.stop(),i.status==="failed"&&(l(i.error||"Music generation failed"),process.exit(T.GENERAL_ERROR)),rn(i,e),n.output&&i.audioUrl){let s=e==="human"?on("Downloading...").start():null;try{await Ni(i.audioUrl,n.output),s?.stop(),e==="human"&&v(`Saved to: ${n.output}`)}catch(a){s?.stop(),A(`Failed to download: ${a instanceof Error?a.message:"Unknown error"}`)}}}catch(r){o?.stop(),l(r instanceof Error?r.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),Li=new sn("status").description("Check status of a music generation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{let e=t.format==="human"?on("Checking status...").start():null;try{let o=await ze(n);e?.stop(),rn(o,t.format)}catch(o){e?.stop(),l(o instanceof Error?o.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),Bo=new sn("music").description("Music generation commands").addCommand(Ui).addCommand(Li);import{Command as ln}from"commander";import an from"ora";import{writeFile as Mi}from"fs/promises";function cn(n,t){if(t==="json"){let{cost:e,...o}=n;_(o);return}if(t==="quiet"){n.outputUrl?console.log(n.outputUrl):console.log(n.requestId);return}p(`Request ID: ${n.requestId}`),p(`Status: ${n.status}`),n.duration&&p(`Duration: ${n.duration}s`),n.outputUrl&&v(`Output URL: ${n.outputUrl}`),n.cost!==void 0&&p(`Cost: $${n.cost.toFixed(4)}`),n.error&&l(`Error: ${n.error}`)}async function ji(n,t){let e=await fetch(n);if(!e.ok)throw new Error(`Failed to download: ${e.status}`);let o=await e.arrayBuffer();await Mi(t,Buffer.from(o))}var Vi=new ln("create").description("Mix audio tracks into a video (music will loop to match video duration)").requiredOption("--video <url>","Input video file/URL").option("--music <url>","Background music file/URL (will loop if shorter than video)").option("--voice <url>","Voiceover file/URL").option("--music-volume <percent>","Music volume 0-100 (default: 30, recommended for mix with voice)","30").option("--voice-volume <percent>","Voice volume 0-100","100").option("-o, --output <path>","Output file path").option("--no-wait","Do not wait for completion").option("-f, --format <format>","Output format: human, json, quiet","human").action(async n=>{!n.music&&!n.voice&&(l("At least one of --music or --voice must be provided"),process.exit(T.INVALID_INPUT));let t=parseInt(n.musicVolume,10)/100,e=parseInt(n.voiceVolume,10)/100;(isNaN(t)||t<0||t>1)&&(l("Music volume must be between 0 and 100"),process.exit(T.INVALID_INPUT)),(isNaN(e)||e<0||e>2)&&(l("Voice volume must be between 0 and 200"),process.exit(T.INVALID_INPUT));let o=n.format,r=o==="human"?an("Mixing audio...").start():null,i=[{url:n.video,role:"video"}];n.music&&i.push({url:n.music,role:"background",volume:t*5}),n.voice&&i.push({url:n.voice,role:"voice",volume:e*2});try{let s=await Jn({operation:"add-to-video",inputs:i,options:{musicVolume:t,voiceVolume:e}});if(!n.wait){r?.stop(),cn(s,o);return}r&&(r.text=`Processing (ID: ${s.requestId})...`);let a=await ue(()=>Vt(s.requestId),120,3e3);if(r?.stop(),a.status==="failed"&&(l(a.error||"Audio mixing failed"),process.exit(T.GENERAL_ERROR)),cn(a,o),n.output&&a.outputUrl){let c=o==="human"?an("Downloading...").start():null;try{await ji(a.outputUrl,n.output),c?.stop(),o==="human"&&v(`Saved to: ${n.output}`)}catch(d){c?.stop(),A(`Failed to download: ${d instanceof Error?d.message:"Unknown error"}`)}}}catch(s){r?.stop(),l(s instanceof Error?s.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),_i=new ln("status").description("Check status of an audio mix request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{let e=t.format==="human"?an("Checking status...").start():null;try{let o=await Vt(n);e?.stop(),cn(o,t.format)}catch(o){e?.stop(),l(o instanceof Error?o.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),Go=new ln("mix").description("Audio mixing commands").addCommand(Vi).addCommand(_i);import{Command as Wo}from"commander";import qi from"ora";var Bi=new Wo("search").description("Search for images").requiredOption("-q, --query <query>","Search query").option("-n, --max-results <number>","Maximum number of results (default: 10)").option("-s, --size <size>","Image size: small, medium, large, any","large").option("--safe-search","Enable safe search (default: true)",!0).option("--no-safe-search","Disable safe search").option("-f, --format <format>","Output format: human, json, quiet","human").action(async n=>{let t=n.format,e=t==="human"?qi("Searching for images...").start():null,o;n.maxResults&&(o=parseInt(n.maxResults,10),(isNaN(o)||o<1)&&(e?.stop(),l("Max results must be a positive number"),process.exit(T.INVALID_INPUT)));try{let r=await dt({query:n.query,options:{maxResults:o||10,size:n.size,safeSearch:n.safeSearch}});e?.stop(),r.success||(l("Search failed"),process.exit(T.GENERAL_ERROR));let i=r.data.results.flatMap(s=>s.results.map(a=>({...a,provider:s.providerName})));if(t==="json"){_({success:!0,query:n.query,totalResults:i.length,images:i});return}if(t==="quiet"){for(let s of i)console.log(s.url);return}if(i.length===0){p("No images found");return}v(`Found ${i.length} images for "${n.query}"`),console.log();for(let s=0;s<i.length;s++){let a=i[s];console.log(`[${s+1}] ${a.title||"Untitled"}`),console.log(` URL: ${a.url}`),console.log(` Size: ${a.width}x${a.height}`),a.author&&console.log(` Author: ${a.author}`),console.log(` Provider: ${a.provider}`),console.log()}p(`Total cost: $${r.data.totalCost.toFixed(4)}`)}catch(r){e?.stop(),l(r instanceof Error?r.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),Yo=new Wo("image").description("Image search commands").addCommand(Bi);import{Command as ce}from"commander";import Ze from"ora";import{mkdir as Ge,writeFile as ae,readFile as Rt,access as un,rm as mn}from"fs/promises";import{join as V,resolve as Qe}from"path";import{execSync as Be,spawn as os,spawnSync as rs}from"child_process";import is from"ffmpeg-static";import{homedir as Gi}from"os";import{join as Ho}from"path";import{readdir as Wi}from"fs/promises";var Yi="conceptcraft";function Ve(){return Ho(Gi(),`.${Yi}`,"projects")}function Tt(n){return Ho(Ve(),n)}async function dn(){try{let n=Ve();return(await Wi(n,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>e.name)}catch{return[]}}function Jo(n,t){let e=2,o=`${n}-${e}`;for(;t.includes(o);)e++,o=`${n}-${e}`;return o}import{Command as Hi}from"commander";import Ji from"ora";import{execSync as zi,spawnSync as _e}from"child_process";import{mkdirSync as zo,existsSync as kt,readFileSync as Ko,writeFileSync as Xo}from"fs";import{join as ve,basename as Xi}from"path";import{tmpdir as Ki}from"os";function $t(n,t){try{return zi(t,{stdio:"ignore"}),!0}catch{return!1}}function Ct(n){let t=Math.floor(n/60),e=Math.floor(n%60),o=Math.round(n%1*10);return`${t}:${String(e).padStart(2,"0")}.${o}`}function Qi(n){let t=_e("ffprobe",["-v","error","-show_entries","format=duration","-of","default=noprint_wrappers=1:nokey=1",n],{encoding:"utf-8"});return parseFloat(t.stdout.trim())}function Zi(n,t){let e=_e("ffmpeg",["-i",n,"-vf",`select='gt(scene,${t})',showinfo`,"-vsync","vfr","-f","null","-"],{encoding:"utf-8",timeout:12e4}),o=[0],r=(e.stderr||"").split(`
3735
+ `);for(let i of r){let s=i.match(/pts_time:([\d.]+)/);if(s){let a=parseFloat(s[1]);a-o[o.length-1]>=1.5&&o.push(a)}}return o}function es(n,t,e){let o=[];for(let r=0;r<t.length;r++){let i=t[r]+.5,s=ve(e,`scene_${String(r+1).padStart(2,"0")}.jpg`);_e("ffmpeg",["-ss",String(i),"-i",n,"-vframes","1","-q:v","2","-y",s],{stdio:"ignore",timeout:3e4}),o.push(s)}return o}function ts(n,t){let e=ve(t,"audio.wav");if(_e("ffmpeg",["-i",n,"-vn","-acodec","pcm_s16le","-ar","16000","-ac","1","-y",e],{stdio:"ignore",timeout:6e4}),!kt(e)||!$t("whisper","which whisper")&&!$t("whisper-cpp","which whisper-cpp"))return null;let r=_e("whisper",[e,"--model","base","--output_format","json","--output_dir",t,"--language","en"],{encoding:"utf-8",timeout:3e5}),i=ve(t,"audio.json");if(!kt(i))return null;try{let s=JSON.parse(Ko(i,"utf-8"));return{text:s.text||"",segments:(s.segments||[]).map(a=>({start:a.start,end:a.end,text:a.text?.trim()||""}))}}catch{return null}}function ns(n,t){let e=Ko(n).toString("base64"),o=JSON.stringify({model:t,prompt:"Describe this image in one short sentence (max 15 words). Focus on: what is shown, the setting, key objects or people.",images:[e],stream:!1}),r=_e("curl",["-s","-X","POST","http://localhost:11434/api/generate","-H","Content-Type: application/json","-d",o],{encoding:"utf-8",timeout:6e4});try{return(JSON.parse(r.stdout).response||"").replace(/!!!IMAGE!!!/gi,"").replace(/\[image[^\]]*\]/gi,"").trim()||"Unable to describe frame"}catch{return"Unable to describe frame"}}var Qo=new Hi("analyze").description("Analyze a video file: detect scenes, transcribe audio, describe frames").argument("<file>","Path to video file").option("-o, --output <path>","Output directory for analysis results").option("-t, --threshold <number>","Scene detection threshold (0-1, lower = more scenes)","0.3").option("-m, --model <name>","Ollama vision model","moondream").option("--no-vision","Skip frame description (faster)").option("--no-transcribe","Skip audio transcription").option("-f, --output-format <format>","Output format: human, json","human").action(async(n,t)=>{let e=Ji();kt(n)||(console.error(`File not found: ${n}`),process.exit(1)),$t("ffmpeg","which ffmpeg")||(console.error("ffmpeg is required. Install: brew install ffmpeg"),process.exit(1)),t.vision!==!1&&!$t("ollama","which ollama")&&(console.error("ollama is required for vision. Install: brew install ollama"),process.exit(1));let o=t.output||ve(Ki(),`video-analyze-${Date.now()}`);zo(o,{recursive:!0});let r=ve(o,"frames");zo(r,{recursive:!0});let i=parseFloat(t.threshold),s=t.model;e.start("Reading video metadata...");let a=Qi(n);e.succeed(`Video: ${Ct(a)} (${a.toFixed(1)}s)`),e.start("Detecting scenes...");let c=Zi(n,i);e.succeed(`Detected ${c.length} scenes`),e.start("Extracting key frames...");let d=es(n,c,r);e.succeed(`Extracted ${d.length} key frames`);let u=null;t.transcribe!==!1&&(e.start("Transcribing audio..."),u=ts(n,o),u?e.succeed(`Transcribed: ${u.segments.length} segments`):e.warn("Transcription skipped (whisper not installed: pip install openai-whisper)"));let C=[];for(let f=0;f<c.length;f++){let w=c[f],I=f<c.length-1?c[f+1]:a,k="";t.vision!==!1&&kt(d[f])&&(e.start(`Describing scene ${f+1}/${c.length}...`),k=ns(d[f],s),e.succeed(`Scene ${f+1}: ${k}`)),C.push({id:f+1,startTime:w,endTime:I,duration:I-w,framePath:d[f],description:k})}let y={source:n,duration:a,scenes:C,transcript:u};if(t.outputFormat==="json"){let f=JSON.stringify(y,null,2),w=ve(o,"analysis.json");Xo(w,f),console.log(f)}else{let f=["# Video Analysis","",`**Source:** ${Xi(n)}`,`**Duration:** ${Ct(a)} (${a.toFixed(1)}s)`,`**Scenes:** ${C.length}`,"","## Scenes",""];for(let k of C){if(f.push(`### Scene ${k.id} (${Ct(k.startTime)} - ${Ct(k.endTime)}) [${k.duration.toFixed(1)}s]`),k.description&&f.push(`**Visual:** ${k.description}`),u?.segments){let S=u.segments.filter(R=>R.end>k.startTime&&R.start<k.endTime);S.length>0&&f.push(`**Audio:** ${S.map(R=>R.text).join(" ").trim()}`)}f.push(`**Frame:** ${k.framePath}`),f.push("")}u?.text&&(f.push("## Full Transcript"),f.push(""),f.push(u.text.trim()),f.push(""));let w=f.join(`
3736
+ `),I=ve(o,"analysis.md");Xo(I,w),console.log(w),console.log(`
3737
+ Results saved to: ${o}`)}});var ss="inizio-inc/remotion-video-template#main",qe=30;async function as(n){let t=await Rt(n,"utf-8");return JSON.parse(t)}async function cs(n){let t=V(n,"template.manifest.json");try{return await as(t)}catch{return{entry:"src/Root.tsx",compositions:[{id:"Main",type:"youtube",aspect:"16:9",default:!0}]}}}function Zo(){try{return Be("bun --version",{stdio:"ignore"}),!0}catch{return!1}}function ls(n){if(n.includes("---")||n.includes("[Section")){let r=n.split(/---|\[Section \d+\]/i).filter(i=>i.trim());if(r.length>1)return r.map(i=>i.trim())}let t=n.split(/(?<=[.!?])\s+/).map(r=>r.trim()).filter(r=>r.length>0),e=[],o="";for(let r of t){let i=r.split(/\s+/).length;o?(e.push(`${o} ${r}`),o=""):i<5&&e.length<t.length-1?o=r:e.push(r)}return o&&(e.length>0?e[e.length-1]+=` ${o}`:e.push(o)),e}function ds(n,t,e=qe,o){if(o&&o.characters.length>0)return us(n,o,e);let r=n.reduce((s,a)=>s+a.split(/\s+/).length,0),i=0;return n.map((s,a)=>{let c=s.split(/\s+/).length,d=c/r,u=t*d,C=Math.round(u*e),y=s.split(""),f=u/y.length,w={characters:y,characterStartTimesSeconds:y.map((k,S)=>S*f),characterEndTimesSeconds:y.map((k,S)=>(S+1)*f)},I={id:a+1,text:s,wordCount:c,startTime:i,endTime:i+u,durationInSeconds:u,durationInFrames:C,timestamps:w};return i+=u,I})}function us(n,t,e){let{characters:o,characterStartTimesSeconds:r,characterEndTimesSeconds:i}=t,s=o.join(""),a=[],c=0;for(let d=0;d<n.length;d++){let u=n[d],C=u.length;for(;c<o.length&&o[c].match(/^\s*$/);)c++;let y=c,f=r[y]||0;c+=C;let w=c-1;for(;w>y&&o[w]?.match(/^\s*$/);)w--;let I=i[Math.min(w,i.length-1)]||f+1,k=I-f,S=Math.round(k*e),R={characters:o.slice(y,w+1),characterStartTimesSeconds:r.slice(y,w+1).map($=>$-f),characterEndTimesSeconds:i.slice(y,w+1).map($=>$-f)};a.push({id:d+1,text:u,wordCount:u.split(/\s+/).length,startTime:f,endTime:I,durationInSeconds:k,durationInFrames:S,timestamps:R})}return a}function ms(n){let t=n==="tiktok"?"vertical":n==="audiogram"?"square":"widescreen";return{scenes:[{name:"Hook",script:"Replace this with a bold opening line that grabs attention.",imageQuery:`cinematic ${t} intro visual, dramatic lighting`,videoQuery:`abstract ${t} motion background`},{name:"Proof",script:"Share the core insight, benefit, or product moment you want viewers to remember.",imageQuery:`people collaborating ${t} office, warm lighting`,videoQuery:`close-up hands using technology ${t}`},{name:"Close",script:"End with a crisp call to action and a confident closing line.",imageQuery:`bold typography ${t} background, high contrast`,videoQuery:`sunrise skyline ${t} timelapse`}],voice:"en-US-Neural2-C",voiceSettings:{speed:1,stability:.4,style:.6},musicPrompt:"uplifting cinematic background, modern and confident"}}async function ps(n,t,e){let o=V(n,"public"),r=V(n,"scripts");await Ge(o,{recursive:!0}),await Ge(r,{recursive:!0});let i=V(o,"scenes.json");await ae(i,JSON.stringify(ms(t),null,2),"utf-8");let s=`import { execSync } from "node:child_process";
3738
3738
 
3739
3739
  execSync("${e} video generate plan --project .", { stdio: "inherit" });
3740
- `,s=`import { execSync } from "node:child_process";
3740
+ `,a=`import { execSync } from "node:child_process";
3741
3741
 
3742
3742
  const args = process.argv.slice(2).join(" ");
3743
3743
  execSync("${e} video export --project . " + args, { stdio: "inherit" });
3744
- `;await ae(j(r,"plan.ts"),a,"utf-8"),await ae(j(r,"export.ts"),s,"utf-8")}async function Zo(){return process.stdin.isTTY?null:new Promise(n=>{let t="",e=!1;process.stdin.setEncoding("utf-8"),process.stdin.on("data",o=>{t+=o}),process.stdin.on("end",()=>{e||(e=!0,n(t.trim()||null))}),process.stdin.on("error",()=>{e||(e=!0,n(null))}),setTimeout(()=>{!e&&!t&&(e=!0,n(null))},500)})}function fa(n){return n.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function ga(n){let t={shortTitle:"Video",elements:[],audio:[],text:[],scenes:[]},e=!0;return n.forEach(o=>{let r=o.startTime*1e3,i=o.endTime*1e3,a=o.durationInSeconds*1e3;t.scenes.push({name:o.name||`Scene ${o.id}`,text:o.text,startMs:r,endMs:i}),o.imagePath?(t.elements.push({startMs:r,endMs:i,imageUrl:o.imagePath,enterTransition:"blur",exitTransition:"blur",animations:[{type:"scale",from:e?1.3:1,to:e?1:1.3,startMs:0,endMs:a}]}),e=!e):o.videoPath&&t.elements.push({startMs:r,endMs:i,videoUrl:o.videoPath,enterTransition:"blur",exitTransition:"blur",animations:[]}),o.audioPath&&t.audio.push({startMs:r,endMs:i,audioUrl:o.audioPath}),o.timestamps&&t.text.push({startMs:r,endMs:i,text:o.text,position:"bottom",animations:[],timestamps:o.timestamps})}),t}async function It(n,t){if(n.startsWith("data:")){let r=n.match(/^data:[^;]+;base64,(.+)$/);if(!r)throw new Error("Invalid data URL format");let i=Buffer.from(r[1],"base64");await ae(t,i);return}let e=await fetch(n);if(!e.ok)throw new Error(`Failed to download: ${e.status}`);let o=await e.arrayBuffer();await ae(t,Buffer.from(o))}function ha(n){try{let o=new URL(n).pathname.split(".").pop()?.toLowerCase();if(o&&["jpg","jpeg","png","gif","webp"].includes(o))return o}catch{}return"jpg"}var ya=new se("assets").description("Generate assets (voiceover per scene, music, images, video)").option("-s, --script <text>","Narration script (legacy single-script mode)").option("--script-file <path>","Path to script file (legacy) or scenes JSON").option("--scenes <path>","Path to scenes.json (defaults to <project>/public/scenes.json)").option("-p, --project <dir>","Project directory (defaults to current directory; uses <dir>/public for output)").option("-t, --topic <text>","Topic for image search").option("-v, --voice <name>","TTS voice ID (ElevenLabs: Rachel, Josh, Adam; OpenAI: alloy, nova; Gemini: Kore, Puck)").option("-m, --music-prompt <text>","Music description").option("-n, --num-images <number>","Number of images to search/download","5").option("-o, --output <dir>","Output directory","./public").option("-f, --format <format>","Output format: human, json, quiet","human").action(async n=>{let t=n.format,e=t==="human"?Ze("Initializing...").start():null,o=n.project?Qe(process.cwd(),n.project):null;try{let r=await Zo(),i=null;if(n.scenes&&!n.scriptFile&&(n.scriptFile=n.scenes),o&&(n.output=j(o,"public"),n.scriptFile?n.scriptFile=Qe(o,n.scriptFile):!n.script&&!r&&(n.scriptFile=j(o,"public","scenes.json"))),r)try{let b=JSON.parse(r);b.scenes&&Array.isArray(b.scenes)&&(i=b)}catch{}if(!i&&n.scriptFile)try{let b=await Rt(n.scriptFile,"utf-8"),q=JSON.parse(b);q.scenes&&Array.isArray(q.scenes)&&(i=q)}catch{}let a=i?.voice||n.voice,s=i?.voiceId,c=i?.provider,d=i?.model,m=i?.voiceInstructions,C=i?.musicPrompt||n.musicPrompt||"uplifting background music, positive energy",h=i?.musicDuration,f=j(n.output,"audio"),w=j(n.output,"images"),$=j(n.output,"videos");e&&(e.text="Creating directories..."),await Be(f,{recursive:!0}),await Be(w,{recursive:!0}),await Be($,{recursive:!0});let k=0,y=[],R=0,T=[],g=[];if(i&&i.scenes.length>0){t==="human"&&(e?.stop(),p(`Processing ${i.scenes.length} scenes...`),e?.start());let b=i.scenes.map((X,L)=>{let re=X.script;return X.voiceStyle&&(re=`${X.voiceStyle} ${re}`),{text:re,id:`scene-${L}`}});e&&(e.text="Generating speech for all scenes...");let q=await Wn({texts:b,options:{provider:c,voice:a,voiceId:s,model:d,voiceSettings:i.voiceSettings,instructions:m}});k+=q.totalCost;let K=0;for(let X=0;X<i.scenes.length;X++){let L=i.scenes[X],re=fa(L.name),Z=q.results[X];e&&(e.text=`[${L.name}] Saving audio...`);let Et=j(f,`${re}.${Z.format}`);await ae(Et,Z.audioData);let we=Z.duration,cr=Math.round(we*_e),We={id:X+1,name:L.name,text:L.script,wordCount:L.script.split(/\s+/).length,startTime:K,endTime:K+we,durationInSeconds:we,durationInFrames:cr,audioPath:`audio/${re}.${Z.format}`,timestamps:Z.timestamps};if(L.imageQuery){e&&(e.text=`[${L.name}] Searching image...`);try{let W=await dt({query:L.imageQuery,options:{maxResults:1,size:"large",safeSearch:!0}}),Ye=W.data.results.flatMap(G=>G.results);if(k+=W.data.totalCost,Ye.length>0){let G=Ye[0],He=ha(G.url),me=`${re}.${He}`,Pt=j(w,me);await It(G.url,Pt),We.imagePath=`images/${me}`,T.push({path:`images/${me}`,url:G.url,width:G.width,height:G.height,query:L.imageQuery})}}catch(W){t==="human"&&(e?.stop(),I(`[${L.name}] Image search failed: ${W instanceof Error?W.message:"Unknown"}`),e?.start())}}if(L.videoQuery){e&&(e.text=`[${L.name}] Searching video...`);try{let W=await _t({query:L.videoQuery,options:{maxResults:1,license:"free"}}),Ye=W.data.results.flatMap(G=>G.results);if(k+=W.data.totalCost,Ye.length>0){let G=Ye[0],He=G.previewUrl||G.downloadUrl;if(He){let me=`${re}.mp4`,Pt=j($,me);await It(He,Pt),We.videoPath=`videos/${me}`,g.push({path:`videos/${me}`,url:He,width:G.width,height:G.height,duration:G.duration,query:L.videoQuery})}}}catch(W){t==="human"&&(e?.stop(),I(`[${L.name}] Video search failed: ${W instanceof Error?W.message:"Unknown"}`),e?.start())}}if(y.push(We),K+=we,R+=we,t==="human"){e?.stop();let W=[`audio: ${we.toFixed(1)}s`,We.imagePath?"image":null,We.videoPath?"video":null].filter(Boolean).join(", ");v(` ${L.name}: ${W}`),e?.start()}}}else{let b=n.script;if(n.scriptFile)try{b=await Rt(n.scriptFile,"utf-8")}catch(Z){e?.stop(),l(`Failed to read script file: ${Z instanceof Error?Z.message:"Unknown error"}`),process.exit(S.INVALID_INPUT)}(!b||b.trim().length===0)&&(e?.stop(),l("Provide scenes via stdin JSON, --scenes/--script-file with scenes JSON, or --script for legacy mode"),process.exit(S.INVALID_INPUT)),b=b.trim();let q=n.topic||b.split(".")[0].slice(0,50);e&&(e.text="Generating voiceover...");let K=await ct({text:b,options:{voice:a}}),X=j(f,`voiceover.${K.format}`);await ae(X,K.audioData),k+=K.cost,R=K.duration;let L=la(b);y=da(L,K.duration,_e,K.timestamps).map((Z,Et)=>({...Z,name:`Section${Et+1}`,audioPath:`audio/voiceover.${K.format}`})),t==="human"&&(e?.stop(),v(`Voiceover: ${X} (${K.duration.toFixed(1)}s)`),e?.start())}e&&(e.text="Creating timeline...");let A=ga(y),B=Math.max(A.audio.length>0?Math.max(...A.audio.map(b=>b.endMs)):0,A.text.length>0?Math.max(...A.text.map(b=>b.endMs)):0,A.elements.length>0?Math.max(...A.elements.map(b=>b.endMs)):0),z=B/1e3,oe=h?Math.min(300,Math.max(3,h)):Math.min(300,Math.ceil(z));console.log("[Music Generation] Requesting music:",{prompt:C,requestedDuration:oe,totalAudioDuration:R,actualVideoDuration:z,timelineDurationMs:B});let ve,Ge;e&&(e.text="Generating music and thumbnail...");let ir=`YouTube thumbnail style: BIG BOLD short headline text (like "$50K/MONTH"), dramatic engaging scene, arrows pointing to key elements, high contrast, vibrant colors, clean composition, 16:9. Video context: ${y.map(b=>b.text).join(" ")}`,At=[],ar=(async()=>{if(oe<3)return t==="human"&&(e?.stop(),I(`Video duration (${z.toFixed(1)}s) is too short for music generation (minimum 3s).`),e?.start()),null;try{let b=await lt({prompt:C,duration:oe});if(b.status!=="completed"&&b.status!=="failed"&&(b=await de(()=>ze(b.requestId),60,2e3)),b.status==="failed")throw new Error(b.error||"Unknown error");let q=j(f,"music.mp3");return b.audioUrl&&await It(b.audioUrl,q),{path:"audio/music.mp3",duration:b.duration||oe,prompt:C,cost:b.cost||0}}catch(b){return t==="human"&&(e?.stop(),I(`Music generation failed: ${b.message}`),e?.start()),null}})();At.push(ar);let sr=(async()=>{try{let b=await Jn({prompt:ir,options:{width:1280,height:720}});if(b.success&&b.data.url){let q=j(n.output,"thumbnail.jpg");return await It(b.data.url,q),k+=b.data.cost||0,q}return null}catch(b){return t==="human"&&(e?.stop(),I(`Thumbnail generation failed: ${b.message}`),e?.start()),null}})();At.push(sr);let[xe,hn]=await Promise.all(At);xe&&(ve=xe,k+=xe.cost||0,t==="human"&&(e?.stop(),v(`Music: ${j(f,"music.mp3")} (${xe.duration}s)`),xe.duration<z&&I(`Music duration (${xe.duration.toFixed(1)}s) is shorter than video duration (${z.toFixed(1)}s).`),e?.start())),hn&&(Ge=hn,t==="human"&&(e?.stop(),v(`Thumbnail: ${Ge}`),e?.start())),e&&(e.text="Writing manifest...");let yn=Math.round(z*_e),bn={music:ve,thumbnail:Ge?"thumbnail.jpg":void 0,images:T,videos:g,scenes:y,timeline:A,totalDurationInFrames:yn,fps:_e,totalCost:k,createdAt:new Date().toISOString()},Ot=j(n.output,"video-manifest.json");if(await ae(Ot,JSON.stringify(bn,null,2)),e?.stop(),t==="json"){let{totalCost:b,...q}=bn;V(q);return}if(t==="quiet"){console.log(Ot);return}console.log(),v("Video assets created successfully!"),console.log(),p(`Scenes: ${y.length} (${yn} frames at ${_e}fps)`);for(let b of y){let q=[b.audioPath?"audio":null,b.imagePath?"image":null,b.videoPath?"video":null].filter(Boolean).join(", ");p(` - ${b.name}: ${b.durationInSeconds.toFixed(1)}s [${q}]`)}p(`Music: ${ve?.path} (${ve?.duration}s)`),p(`Manifest: ${Ot}`),console.log(),p(`Total cost: $${k.toFixed(4)}`)}catch(r){e?.stop(),l(r instanceof Error?r.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),ba=new se("find").description("Find stock video clips (supporting)").argument("<query>","Search query").option("-n, --max-results <count>","Maximum number of results","10").option("-o, --orientation <type>","Video orientation: landscape, portrait, square, any","any").option("-l, --license <type>","License type: free, premium, any","free").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{let{maxResults:e,orientation:o,license:r,format:i}=t,a=i==="human"?Ze("Finding videos...").start():null;try{let s=await _t({query:n,options:{maxResults:parseInt(e,10),orientation:o,license:r}});a?.stop();let c=s.data.results.flatMap(d=>d.results);if(i==="json"){let{totalCost:d,...m}=s.data;V({...s,data:m});return}if(i==="quiet"){c.forEach(d=>{console.log(d.previewUrl||d.thumbnailUrl)});return}if(c.length===0){p("No videos found");return}v(`Found ${c.length} videos for "${n}"`),console.log(),c.forEach((d,m)=>{console.log(`[${m+1}] ${d.title}`),console.log(` URL: ${d.previewUrl||d.thumbnailUrl}`),console.log(` Duration: ${d.duration}s | Size: ${d.width}x${d.height}`),console.log(` Provider: ${d.provider}`),console.log()}),p(`Total cost: $${s.data.totalCost.toFixed(4)}`)}catch(s){a?.stop(),l(s instanceof Error?s.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),va=new se("new").description("Create a new video project from a template").argument("<name>","Project directory name").option("-t, --template <repo>","GitHub repo (user/repo#commit)",aa).option("--type <type>","Video type: youtube (16:9), tiktok (9:16), or audiogram (1:1)","youtube").option("--no-install","Skip dependency install").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{let e=t.format,o=e==="human"?Ze("Initializing video project...").start():null;try{let r=je();await Be(r,{recursive:!0});let i=Ct(n),a=t.type,s=await dn();if(s.includes(n)){let f=Ho(n,s);o?.stop(),l(`Project "${n}" already exists at: ${i}`),p(`Try: ${u.commands[0]} video generate new ${f}`),process.exit(S.INVALID_INPUT)}/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_.-]+(#[a-zA-Z0-9_.\/-]+)?$/.test(t.template)||(o?.stop(),l(`Invalid template format: "${t.template}". Expected format: owner/repo or owner/repo#branch`),process.exit(S.INVALID_INPUT)),["youtube","tiktok","audiogram"].includes(a)||(o?.stop(),l(`Invalid type "${a}". Use youtube, tiktok, or audiogram.`),process.exit(S.INVALID_INPUT)),o&&(o.text=`Cloning template from ${t.template}...`);let[d,m]=t.template.split("#"),C=m?`-b ${m}`:"";try{qe(`git clone ${C} --depth 1 https://github.com/${d}.git "${i}"`,{stdio:"pipe"}),await un(j(i,".git"),{recursive:!0,force:!0})}catch(f){o?.stop(),l(`Failed to clone template: ${f instanceof Error?f.message:"Unknown error"}`),process.exit(S.GENERAL_ERROR)}e==="human"&&(o?.stop(),v(`Template downloaded to ${n}/`),o?.start());let h;try{h=await ca(i)}catch{o?.stop(),l("template.manifest.json not found or invalid in template repo"),process.exit(S.INVALID_INPUT)}if(h.propsSchema&&h.propsSchema!=="video-plan.v1"&&(o?.stop(),l(`Template propsSchema must be video-plan.v1 (found ${h.propsSchema})`),process.exit(S.INVALID_INPUT)),o&&(o.text="Writing scaffold files..."),await pa(i,a,u.commands[0]),t.install){let f=Qo()?"bun":"npm";o&&(o.text=`Installing dependencies with ${f}...`),await new Promise((w,$)=>{let k=oa(f,["install"],{cwd:i,stdio:"pipe",shell:!0});k.on("close",y=>{y===0?w():$(new Error(`${f} install failed with code ${y}`))}),k.on("error",$)}),e==="human"&&(o?.stop(),v("Dependencies installed"),o?.start())}if(o?.stop(),e==="json"){V({name:n,path:i,template:t.template,type:a,installed:t.install});return}if(e==="quiet"){console.log(i);return}console.log(),v(`Video project "${n}" created successfully!`),p(`Location: ${i}`),a==="tiktok"?p("Format: TikTok/Reels/Shorts (1080x1920 @ 30fps)"):a==="audiogram"?p("Format: Audiogram (1080x1080 @ 30fps)"):p("Format: YouTube (1920x1080 @ 30fps)"),console.log(),p("Next steps:"),p(` cd ${i}`),t.install||p(` ${Qo()?"bun":"npm"} install`),p(" bun run dev # Preview in Remotion Studio"),p(` ${u.commands[0]} video generate assets --scenes public/scenes.json`),p(` ${u.commands[0]} video generate plan`)}catch(r){o?.stop(),l(r instanceof Error?r.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),xa=new se("plan").description("Generate video plan from context (via stdin or --context)").option("-c, --context <text>","Context for plan generation").option("-o, --output <path>","Save plan to file").option("-b, --branding <path>","Branding JSON file to include").action(async n=>{let t=Ze("Generating video plan...").start();try{let e=n.context;if(!e){let a=await Zo();a&&(e=a)}e||(t.stop(),l("Provide context via stdin or --context flag"),process.exit(S.INVALID_INPUT));let o;if(n.branding)try{o=await Rt(n.branding,"utf-8")}catch{t.stop(),l(`Could not read branding file: ${n.branding}`),process.exit(S.INVALID_INPUT)}let r=await Xn({context:e,branding:o});t.stop(),r.success||(l(r.error||"Failed to generate plan"),process.exit(S.GENERAL_ERROR));let i=r.data;n.output?(await ae(n.output,i),v(`Plan saved to ${n.output}`)):console.log(i)}catch(e){t.stop(),l(e instanceof Error?e.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),wa=new se("generate").description("Generate parts of a video project").addCommand(va).addCommand(ya).addCommand(xa),Sa=new se("projects").description("List all video projects").option("-f, --format <format>","Output format: human, json","human").action(async n=>{let t=await dn();if(n.format==="json"){V({projectsDir:je(),projects:t.map(e=>({name:e,path:Ct(e)}))});return}if(t.length===0){p("No video projects found"),p(`Projects are stored in: ${je()}`);return}console.log(`
3745
- Video Projects:`),console.log("-".repeat(50));for(let e of t)console.log(` ${e}`),console.log(` ${Ct(e)}`);console.log()}),Ca=new se("inject").description("Inject thumbnail into video (first frame + file icon)").requiredOption("-i, --video <path>","Input video file").requiredOption("-t, --thumbnail <path>","Thumbnail image").option("-o, --output <path>","Output video (default: video-with-thumb.mp4)").option("-f, --format <format>","Output format: human, json, quiet","human").action(async n=>{let t=n.format,e=t==="human"?Ze("Injecting thumbnail...").start():null;try{let o=Qe(n.video),r=Qe(n.thumbnail),i=n.output?Qe(n.output):o.replace(/\.mp4$/,"-with-thumb.mp4");await mn(o),await mn(r);let a=ia;if(a)try{await mn(a)}catch{a=null}if(!a)try{a=qe("which ffmpeg",{encoding:"utf8"}).trim()}catch{throw new Error("ffmpeg not found. Install ffmpeg or ffmpeg-static.")}let s=ra(a,["-i",o],{encoding:"utf8"});if(s.error)throw new Error(`Failed to probe video: ${s.error.message}`);let c=(s.stderr??"").match(/(\d{2,5})x(\d{2,5})/);if(!c)throw new Error("Could not detect video dimensions");let[,d,m]=c;e&&(e.text="Creating thumbnail frame...");let C="/tmp/cc-thumb-frame.mp4";qe(`${a} -y -loop 1 -i "${r}" -vf "scale=${d}:${m}:force_original_aspect_ratio=decrease,pad=${d}:${m}:(ow-iw)/2:(oh-ih)/2,setsar=1" -t 0.033 -r 30 -c:v libx264 -pix_fmt yuv420p "${C}"`,{stdio:"pipe"}),e&&(e.text="Concatenating with video...");let h="/tmp/cc-concat-video.mp4";if(qe(`${a} -y -i "${C}" -i "${o}" -filter_complex "[0:v][1:v]concat=n=2:v=1:a=0[v]" -map "[v]" -map 1:a -c:v libx264 -preset ultrafast -crf 18 -c:a copy "${h}"`,{stdio:"pipe"}),e&&(e.text="Adding file icon thumbnail..."),qe(`${a} -y -i "${h}" -i "${r}" -map 0 -map 1 -c copy -c:v:1 png -disposition:v:1 attached_pic "${i}"`,{stdio:"pipe"}),await un(C,{force:!0}),await un(h,{force:!0}),e?.stop(),t==="json"){V({success:!0,output:i});return}if(t==="quiet"){console.log(i);return}v(`Thumbnail injected: ${i}`)}catch(o){e?.stop(),l(o instanceof Error?o.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),ka=new se("thumbnail").description("Thumbnail operations").addCommand(Ca),er=new se("video").description("Video generation commands").addCommand(wa).addCommand(ba).addCommand(Sa).addCommand(ka).addCommand(Xo);import{Command as Ta}from"commander";import $a from"ora";import{writeFile as Ia}from"fs/promises";var tr=new Ta("scrape").description("Extract content from a URL").argument("<url>","URL to scrape").option("-o, --output <path>","Save content to file").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{let e=t.format,o=e==="human"?$a("Scraping URL...").start():null;try{let r=await zn(n);o?.stop(),r.success||(l(r.error||"Failed to scrape URL"),process.exit(S.GENERAL_ERROR));let i=r.data;if(t.output&&(await Ia(t.output,i.content,"utf-8"),e==="human"&&v(`Content saved to: ${t.output}`)),e==="json"){let{cost:a,...s}=i;V(s);return}if(e==="quiet"){console.log(i.content);return}i.title&&(console.log(),console.log(`Title: ${i.title}`)),i.metadata?.description&&console.log(`Description: ${i.metadata.description}`),console.log(`URL: ${i.url}`),console.log(`Tokens: ~${i.metadata?.tokenUsage?.toLocaleString()||"unknown"}`),i.warning&&I(i.warning),t.output||(console.log(),console.log("--- Content ---"),console.log(i.content)),i.cost&&i.cost>0&&p(`Cost: $${i.cost.toFixed(6)}`)}catch(r){o?.stop(),l(r instanceof Error?r.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}});import{Command as gn}from"commander";import pn from"ora";import{writeFile as nr,mkdir as Ra}from"fs/promises";import{dirname as Aa}from"path";function fn(n,t){if(t==="json"){let{cost:e,...o}=n;V(o);return}if(t==="quiet"){n.audioUrl?console.log(n.audioUrl):n.requestId?console.log(n.requestId):console.log(n.id);return}p(`Request ID: ${n.requestId||n.id}`),p(`Status: ${n.status}`),n.duration&&p(`Duration: ${n.duration}s`),n.audioUrl&&v(`Audio URL: ${n.audioUrl}`),n.cost!==void 0&&p(`Cost: $${n.cost.toFixed(4)}`),n.error&&l(`Error: ${n.error}`)}async function Oa(n,t){if(await Ra(Aa(t),{recursive:!0}),n.startsWith("data:")){let r=n.match(/^data:[^;]+;base64,(.+)$/);if(!r)throw new Error("Invalid data URL format");let i=Buffer.from(r[1],"base64");await nr(t,i);return}let e=await fetch(n);if(!e.ok)throw new Error(`Failed to download: ${e.status}`);let o=await e.arrayBuffer();await nr(t,Buffer.from(o))}var Ea=new gn("generate").description("Generate sound effects from a text prompt").requiredOption("-t, --text <text>","Sound effect description (e.g., 'thunder rumbling, rain on window')").option("-d, --duration <seconds>","Duration in seconds (0.5-30)").option("-p, --provider <provider>","Provider (elevenlabs)","elevenlabs").option("--prompt-influence <value>","How closely to follow prompt (0-1)","0.3").option("-l, --loop","Generate seamless looping audio",!1).option("--format <format>","Audio format: mp3, wav, ogg","mp3").option("-o, --output <path>","Output file path").option("--no-wait","Do not wait for completion").option("-f, --output-format <format>","Output format: human, json, quiet","human").action(async n=>{let t;n.duration&&(t=parseFloat(n.duration),(isNaN(t)||t<.5||t>30)&&(l("Duration must be between 0.5 and 30 seconds"),process.exit(S.INVALID_INPUT)));let e;n.promptInfluence&&(e=parseFloat(n.promptInfluence),(isNaN(e)||e<0||e>1)&&(l("Prompt influence must be between 0 and 1"),process.exit(S.INVALID_INPUT)));let o=n.outputFormat,r=o==="human"?pn("Generating sound effects...").start():null;try{let i=await Kn({text:n.text,duration:t,options:{provider:n.provider,promptInfluence:e,loop:n.loop,format:n.format}});if(!n.wait){r?.stop(),fn(i,o);return}let a=i;if(i.status!=="completed"&&i.status!=="failed"){let s=i.requestId||i.id;r&&(r.text=`Processing (ID: ${s})...`),a=await de(()=>qt(s),60,2e3)}if(r?.stop(),a.status==="failed"&&(l(a.error||"Sound effects generation failed"),process.exit(S.GENERAL_ERROR)),fn(a,o),n.output&&a.audioUrl){let s=o==="human"?pn("Downloading...").start():null;try{await Oa(a.audioUrl,n.output),s?.stop(),o==="human"&&v(`Saved to: ${n.output}`)}catch(c){s?.stop(),I(`Failed to download: ${c instanceof Error?c.message:"Unknown error"}`)}}}catch(i){r?.stop(),l(i instanceof Error?i.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),Pa=new gn("status").description("Check status of a sound effects generation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{let e=t.format==="human"?pn("Checking status...").start():null;try{let o=await qt(n);e?.stop(),fn(o,t.format)}catch(o){e?.stop(),l(o instanceof Error?o.message:"Unknown error"),process.exit(S.GENERAL_ERROR)}}),or=new gn("sfx").description("Sound effects generation commands").addCommand(Ea).addCommand(Pa);var Da="0.1.38",N=new Fa,ce=u.commands[0];N.name(ce).description(u.description).version(Da,"-v, --version","Show version number").option("--debug","Enable debug logging").option("--no-color","Disable colored output").configureOutput({outputError:(n,t)=>{t(Q.red(n))}});N.addCommand(io);N.addCommand(ao);N.addCommand(co);N.addCommand(po);N.addCommand(fo);N.addCommand(go);N.addCommand(ho);N.addCommand(bo);N.addCommand(xo);N.addCommand(So);N.addCommand(To);N.addCommand($o);N.addCommand(Me);N.addCommand(Vo);N.addCommand(qo);N.addCommand(Bo);N.addCommand(Wo);N.addCommand(er);N.addCommand(tr);N.addCommand(or);var rr=ko();rr.commands.length>0&&N.addCommand(rr);N.on("command:*",n=>{console.error(Q.red(`Error: Unknown command '${n[0]}'`)),console.error(),console.error(`Run '${ce} --help' to see available commands.`),process.exit(1)});N.addHelpText("after",`
3746
- ${Q.bold("Examples:")}
3747
- ${Q.gray("# Log in (opens browser)")}
3748
- $ ${ce} login
3749
-
3750
- ${Q.gray("# Create a presentation (recommended pattern)")}
3751
- $ ${ce} create "Q4 Business Review" \\
3744
+ `;await ae(V(r,"plan.ts"),s,"utf-8"),await ae(V(r,"export.ts"),a,"utf-8")}async function er(){return process.stdin.isTTY?null:new Promise(n=>{let t="",e=!1;process.stdin.setEncoding("utf-8"),process.stdin.on("data",o=>{t+=o}),process.stdin.on("end",()=>{e||(e=!0,n(t.trim()||null))}),process.stdin.on("error",()=>{e||(e=!0,n(null))}),setTimeout(()=>{!e&&!t&&(e=!0,n(null))},500)})}function fs(n){return n.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function gs(n){let t={shortTitle:"Video",elements:[],audio:[],text:[],scenes:[]},e=!0;return n.forEach(o=>{let r=o.startTime*1e3,i=o.endTime*1e3,s=o.durationInSeconds*1e3;t.scenes.push({name:o.name||`Scene ${o.id}`,text:o.text,startMs:r,endMs:i}),o.imagePath?(t.elements.push({startMs:r,endMs:i,imageUrl:o.imagePath,enterTransition:"blur",exitTransition:"blur",animations:[{type:"scale",from:e?1.3:1,to:e?1:1.3,startMs:0,endMs:s}]}),e=!e):o.videoPath&&t.elements.push({startMs:r,endMs:i,videoUrl:o.videoPath,enterTransition:"blur",exitTransition:"blur",animations:[]}),o.audioPath&&t.audio.push({startMs:r,endMs:i,audioUrl:o.audioPath}),o.timestamps&&t.text.push({startMs:r,endMs:i,text:o.text,position:"bottom",animations:[],timestamps:o.timestamps})}),t}async function It(n,t){if(n.startsWith("data:")){let r=n.match(/^data:[^;]+;base64,(.+)$/);if(!r)throw new Error("Invalid data URL format");let i=Buffer.from(r[1],"base64");await ae(t,i);return}let e=await fetch(n);if(!e.ok)throw new Error(`Failed to download: ${e.status}`);let o=await e.arrayBuffer();await ae(t,Buffer.from(o))}function hs(n){try{let o=new URL(n).pathname.split(".").pop()?.toLowerCase();if(o&&["jpg","jpeg","png","gif","webp"].includes(o))return o}catch{}return"jpg"}var ys=new ce("assets").description("Generate assets (voiceover per scene, music, images, video)").option("-s, --script <text>","Narration script (legacy single-script mode)").option("--script-file <path>","Path to script file (legacy) or scenes JSON").option("--scenes <path>","Path to scenes.json (defaults to <project>/public/scenes.json)").option("-p, --project <dir>","Project directory (defaults to current directory; uses <dir>/public for output)").option("-t, --topic <text>","Topic for image search").option("-v, --voice <name>","TTS voice ID (ElevenLabs: Rachel, Josh, Adam; OpenAI: alloy, nova; Gemini: Kore, Puck)").option("-m, --music-prompt <text>","Music description").option("-n, --num-images <number>","Number of images to search/download","5").option("-o, --output <dir>","Output directory","./public").option("-f, --format <format>","Output format: human, json, quiet","human").action(async n=>{let t=n.format,e=t==="human"?Ze("Initializing...").start():null,o=n.project?Qe(process.cwd(),n.project):null;try{let r=await er(),i=null;if(n.scenes&&!n.scriptFile&&(n.scriptFile=n.scenes),o&&(n.output=V(o,"public"),n.scriptFile?n.scriptFile=Qe(o,n.scriptFile):!n.script&&!r&&(n.scriptFile=V(o,"public","scenes.json"))),r)try{let b=JSON.parse(r);b.scenes&&Array.isArray(b.scenes)&&(i=b)}catch{}if(!i&&n.scriptFile)try{let b=await Rt(n.scriptFile,"utf-8"),B=JSON.parse(b);B.scenes&&Array.isArray(B.scenes)&&(i=B)}catch{}let s=i?.voice||n.voice,a=i?.voiceId,c=i?.provider,d=i?.model,u=i?.voiceInstructions,C=i?.musicPrompt||n.musicPrompt||"uplifting background music, positive energy",y=i?.musicDuration,f=V(n.output,"audio"),w=V(n.output,"images"),I=V(n.output,"videos");e&&(e.text="Creating directories..."),await Ge(f,{recursive:!0}),await Ge(w,{recursive:!0}),await Ge(I,{recursive:!0});let k=0,S=[],R=0,$=[],h=[];if(i&&i.scenes.length>0){t==="human"&&(e?.stop(),p(`Processing ${i.scenes.length} scenes...`),e?.start());let b=i.scenes.map((Q,M)=>{let ie=Q.script;return Q.voiceStyle&&(ie=`${Q.voiceStyle} ${ie}`),{text:ie,id:`scene-${M}`}});e&&(e.text="Generating speech for all scenes...");let B=await Yn({texts:b,options:{provider:c,voice:s,voiceId:a,model:d,voiceSettings:i.voiceSettings,instructions:u}});k+=B.totalCost;let K=0;for(let Q=0;Q<i.scenes.length;Q++){let M=i.scenes[Q],ie=fs(M.name),ee=B.results[Q];e&&(e.text=`[${M.name}] Saving audio...`);let Et=V(f,`${ie}.${ee.format}`);await ae(Et,ee.audioData);let Se=ee.duration,lr=Math.round(Se*qe),Ye={id:Q+1,name:M.name,text:M.script,wordCount:M.script.split(/\s+/).length,startTime:K,endTime:K+Se,durationInSeconds:Se,durationInFrames:lr,audioPath:`audio/${ie}.${ee.format}`,timestamps:ee.timestamps};if(M.imageQuery){e&&(e.text=`[${M.name}] Searching image...`);try{let Y=await dt({query:M.imageQuery,options:{maxResults:1,size:"large",safeSearch:!0}}),He=Y.data.results.flatMap(W=>W.results);if(k+=Y.data.totalCost,He.length>0){let W=He[0],Je=hs(W.url),me=`${ie}.${Je}`,Pt=V(w,me);await It(W.url,Pt),Ye.imagePath=`images/${me}`,$.push({path:`images/${me}`,url:W.url,width:W.width,height:W.height,query:M.imageQuery})}}catch(Y){t==="human"&&(e?.stop(),A(`[${M.name}] Image search failed: ${Y instanceof Error?Y.message:"Unknown"}`),e?.start())}}if(M.videoQuery){e&&(e.text=`[${M.name}] Searching video...`);try{let Y=await _t({query:M.videoQuery,options:{maxResults:1,license:"free"}}),He=Y.data.results.flatMap(W=>W.results);if(k+=Y.data.totalCost,He.length>0){let W=He[0],Je=W.previewUrl||W.downloadUrl;if(Je){let me=`${ie}.mp4`,Pt=V(I,me);await It(Je,Pt),Ye.videoPath=`videos/${me}`,h.push({path:`videos/${me}`,url:Je,width:W.width,height:W.height,duration:W.duration,query:M.videoQuery})}}}catch(Y){t==="human"&&(e?.stop(),A(`[${M.name}] Video search failed: ${Y instanceof Error?Y.message:"Unknown"}`),e?.start())}}if(S.push(Ye),K+=Se,R+=Se,t==="human"){e?.stop();let Y=[`audio: ${Se.toFixed(1)}s`,Ye.imagePath?"image":null,Ye.videoPath?"video":null].filter(Boolean).join(", ");v(` ${M.name}: ${Y}`),e?.start()}}}else{let b=n.script;if(n.scriptFile)try{b=await Rt(n.scriptFile,"utf-8")}catch(ee){e?.stop(),l(`Failed to read script file: ${ee instanceof Error?ee.message:"Unknown error"}`),process.exit(T.INVALID_INPUT)}(!b||b.trim().length===0)&&(e?.stop(),l("Provide scenes via stdin JSON, --scenes/--script-file with scenes JSON, or --script for legacy mode"),process.exit(T.INVALID_INPUT)),b=b.trim();let B=n.topic||b.split(".")[0].slice(0,50);e&&(e.text="Generating voiceover...");let K=await ct({text:b,options:{voice:s}}),Q=V(f,`voiceover.${K.format}`);await ae(Q,K.audioData),k+=K.cost,R=K.duration;let M=ls(b);S=ds(M,K.duration,qe,K.timestamps).map((ee,Et)=>({...ee,name:`Section${Et+1}`,audioPath:`audio/voiceover.${K.format}`})),t==="human"&&(e?.stop(),v(`Voiceover: ${Q} (${K.duration.toFixed(1)}s)`),e?.start())}e&&(e.text="Creating timeline...");let O=gs(S),G=Math.max(O.audio.length>0?Math.max(...O.audio.map(b=>b.endMs)):0,O.text.length>0?Math.max(...O.text.map(b=>b.endMs)):0,O.elements.length>0?Math.max(...O.elements.map(b=>b.endMs)):0),X=G/1e3,re=y?Math.min(300,Math.max(3,y)):Math.min(300,Math.ceil(X));console.log("[Music Generation] Requesting music:",{prompt:C,requestedDuration:re,totalAudioDuration:R,actualVideoDuration:X,timelineDurationMs:G});let xe,We;e&&(e.text="Generating music and thumbnail...");let sr=`YouTube thumbnail style: BIG BOLD short headline text (like "$50K/MONTH"), dramatic engaging scene, arrows pointing to key elements, high contrast, vibrant colors, clean composition, 16:9. Video context: ${S.map(b=>b.text).join(" ")}`,At=[],ar=(async()=>{if(re<3)return t==="human"&&(e?.stop(),A(`Video duration (${X.toFixed(1)}s) is too short for music generation (minimum 3s).`),e?.start()),null;try{let b=await lt({prompt:C,duration:re});if(b.status!=="completed"&&b.status!=="failed"&&(b=await ue(()=>ze(b.requestId),60,2e3)),b.status==="failed")throw new Error(b.error||"Unknown error");let B=V(f,"music.mp3");return b.audioUrl&&await It(b.audioUrl,B),{path:"audio/music.mp3",duration:b.duration||re,prompt:C,cost:b.cost||0}}catch(b){return t==="human"&&(e?.stop(),A(`Music generation failed: ${b.message}`),e?.start()),null}})();At.push(ar);let cr=(async()=>{try{let b=await zn({prompt:sr,options:{width:1280,height:720}});if(b.success&&b.data.url){let B=V(n.output,"thumbnail.jpg");return await It(b.data.url,B),k+=b.data.cost||0,B}return null}catch(b){return t==="human"&&(e?.stop(),A(`Thumbnail generation failed: ${b.message}`),e?.start()),null}})();At.push(cr);let[we,hn]=await Promise.all(At);we&&(xe=we,k+=we.cost||0,t==="human"&&(e?.stop(),v(`Music: ${V(f,"music.mp3")} (${we.duration}s)`),we.duration<X&&A(`Music duration (${we.duration.toFixed(1)}s) is shorter than video duration (${X.toFixed(1)}s).`),e?.start())),hn&&(We=hn,t==="human"&&(e?.stop(),v(`Thumbnail: ${We}`),e?.start())),e&&(e.text="Writing manifest...");let yn=Math.round(X*qe),bn={music:xe,thumbnail:We?"thumbnail.jpg":void 0,images:$,videos:h,scenes:S,timeline:O,totalDurationInFrames:yn,fps:qe,totalCost:k,createdAt:new Date().toISOString()},Ot=V(n.output,"video-manifest.json");if(await ae(Ot,JSON.stringify(bn,null,2)),e?.stop(),t==="json"){let{totalCost:b,...B}=bn;_(B);return}if(t==="quiet"){console.log(Ot);return}console.log(),v("Video assets created successfully!"),console.log(),p(`Scenes: ${S.length} (${yn} frames at ${qe}fps)`);for(let b of S){let B=[b.audioPath?"audio":null,b.imagePath?"image":null,b.videoPath?"video":null].filter(Boolean).join(", ");p(` - ${b.name}: ${b.durationInSeconds.toFixed(1)}s [${B}]`)}p(`Music: ${xe?.path} (${xe?.duration}s)`),p(`Manifest: ${Ot}`),console.log(),p(`Total cost: $${k.toFixed(4)}`)}catch(r){e?.stop(),l(r instanceof Error?r.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),bs=new ce("find").description("Find stock video clips (supporting)").argument("<query>","Search query").option("-n, --max-results <count>","Maximum number of results","10").option("-o, --orientation <type>","Video orientation: landscape, portrait, square, any","any").option("-l, --license <type>","License type: free, premium, any","free").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{let{maxResults:e,orientation:o,license:r,format:i}=t,s=i==="human"?Ze("Finding videos...").start():null;try{let a=await _t({query:n,options:{maxResults:parseInt(e,10),orientation:o,license:r}});s?.stop();let c=a.data.results.flatMap(d=>d.results);if(i==="json"){let{totalCost:d,...u}=a.data;_({...a,data:u});return}if(i==="quiet"){c.forEach(d=>{console.log(d.previewUrl||d.thumbnailUrl)});return}if(c.length===0){p("No videos found");return}v(`Found ${c.length} videos for "${n}"`),console.log(),c.forEach((d,u)=>{console.log(`[${u+1}] ${d.title}`),console.log(` URL: ${d.previewUrl||d.thumbnailUrl}`),console.log(` Duration: ${d.duration}s | Size: ${d.width}x${d.height}`),console.log(` Provider: ${d.provider}`),console.log()}),p(`Total cost: $${a.data.totalCost.toFixed(4)}`)}catch(a){s?.stop(),l(a instanceof Error?a.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),vs=new ce("new").description("Create a new video project from a template").argument("<name>","Project directory name").option("-t, --template <repo>","GitHub repo (user/repo#commit)",ss).option("--type <type>","Video type: youtube (16:9), tiktok (9:16), or audiogram (1:1)","youtube").option("--no-install","Skip dependency install").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{let e=t.format,o=e==="human"?Ze("Initializing video project...").start():null;try{let r=Ve();await Ge(r,{recursive:!0});let i=Tt(n),s=t.type,a=await dn();if(a.includes(n)){let f=Jo(n,a);o?.stop(),l(`Project "${n}" already exists at: ${i}`),p(`Try: ${m.commands[0]} video generate new ${f}`),process.exit(T.INVALID_INPUT)}/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_.-]+(#[a-zA-Z0-9_./-]+)?$/.test(t.template)||(o?.stop(),l(`Invalid template format: "${t.template}". Expected format: owner/repo or owner/repo#branch`),process.exit(T.INVALID_INPUT)),["youtube","tiktok","audiogram"].includes(s)||(o?.stop(),l(`Invalid type "${s}". Use youtube, tiktok, or audiogram.`),process.exit(T.INVALID_INPUT)),o&&(o.text=`Cloning template from ${t.template}...`);let[d,u]=t.template.split("#"),C=u?`-b ${u}`:"";try{Be(`git clone ${C} --depth 1 https://github.com/${d}.git "${i}"`,{stdio:"pipe"}),await mn(V(i,".git"),{recursive:!0,force:!0})}catch(f){o?.stop(),l(`Failed to clone template: ${f instanceof Error?f.message:"Unknown error"}`),process.exit(T.GENERAL_ERROR)}e==="human"&&(o?.stop(),v(`Template downloaded to ${n}/`),o?.start());let y;try{y=await cs(i)}catch{o?.stop(),l("template.manifest.json not found or invalid in template repo"),process.exit(T.INVALID_INPUT)}if(y.propsSchema&&y.propsSchema!=="video-plan.v1"&&(o?.stop(),l(`Template propsSchema must be video-plan.v1 (found ${y.propsSchema})`),process.exit(T.INVALID_INPUT)),o&&(o.text="Writing scaffold files..."),await ps(i,s,m.commands[0]),t.install){let f=Zo()?"bun":"npm";o&&(o.text=`Installing dependencies with ${f}...`),await new Promise((w,I)=>{let k=os(f,["install"],{cwd:i,stdio:"pipe",shell:!0});k.on("close",S=>{S===0?w():I(new Error(`${f} install failed with code ${S}`))}),k.on("error",I)}),e==="human"&&(o?.stop(),v("Dependencies installed"),o?.start())}if(o?.stop(),e==="json"){_({name:n,path:i,template:t.template,type:s,installed:t.install});return}if(e==="quiet"){console.log(i);return}console.log(),v(`Video project "${n}" created successfully!`),p(`Location: ${i}`),s==="tiktok"?p("Format: TikTok/Reels/Shorts (1080x1920 @ 30fps)"):s==="audiogram"?p("Format: Audiogram (1080x1080 @ 30fps)"):p("Format: YouTube (1920x1080 @ 30fps)"),console.log(),p("Next steps:"),p(` cd ${i}`),t.install||p(` ${Zo()?"bun":"npm"} install`),p(" bun run dev # Preview in Remotion Studio"),p(` ${m.commands[0]} video generate assets --scenes public/scenes.json`),p(` ${m.commands[0]} video generate plan`)}catch(r){o?.stop(),l(r instanceof Error?r.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),xs=new ce("plan").description("Generate video plan from context (via stdin or --context)").option("-c, --context <text>","Context for plan generation").option("-o, --output <path>","Save plan to file").option("-b, --branding <path>","Branding JSON file to include").action(async n=>{let t=Ze("Generating video plan...").start();try{let e=n.context;if(!e){let s=await er();s&&(e=s)}e||(t.stop(),l("Provide context via stdin or --context flag"),process.exit(T.INVALID_INPUT));let o;if(n.branding)try{o=await Rt(n.branding,"utf-8")}catch{t.stop(),l(`Could not read branding file: ${n.branding}`),process.exit(T.INVALID_INPUT)}let r=await Qn({context:e,branding:o});t.stop(),r.success||(l(r.error||"Failed to generate plan"),process.exit(T.GENERAL_ERROR));let i=r.data;n.output?(await ae(n.output,i),v(`Plan saved to ${n.output}`)):console.log(i)}catch(e){t.stop(),l(e instanceof Error?e.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),ws=new ce("generate").description("Generate parts of a video project").addCommand(vs).addCommand(ys).addCommand(xs),Ss=new ce("projects").description("List all video projects").option("-f, --format <format>","Output format: human, json","human").action(async n=>{let t=await dn();if(n.format==="json"){_({projectsDir:Ve(),projects:t.map(e=>({name:e,path:Tt(e)}))});return}if(t.length===0){p("No video projects found"),p(`Projects are stored in: ${Ve()}`);return}console.log(`
3745
+ Video Projects:`),console.log("-".repeat(50));for(let e of t)console.log(` ${e}`),console.log(` ${Tt(e)}`);console.log()}),Ts=new ce("inject").description("Inject thumbnail into video (first frame + file icon)").requiredOption("-i, --video <path>","Input video file").requiredOption("-t, --thumbnail <path>","Thumbnail image").option("-o, --output <path>","Output video (default: video-with-thumb.mp4)").option("-f, --format <format>","Output format: human, json, quiet","human").action(async n=>{let t=n.format,e=t==="human"?Ze("Injecting thumbnail...").start():null;try{let o=Qe(n.video),r=Qe(n.thumbnail),i=n.output?Qe(n.output):o.replace(/\.mp4$/,"-with-thumb.mp4");await un(o),await un(r);let s=is;if(s)try{await un(s)}catch{s=null}if(!s)try{s=Be("which ffmpeg",{encoding:"utf8"}).trim()}catch{throw new Error("ffmpeg not found. Install ffmpeg or ffmpeg-static.")}let a=rs(s,["-i",o],{encoding:"utf8"});if(a.error)throw new Error(`Failed to probe video: ${a.error.message}`);let c=(a.stderr??"").match(/(\d{2,5})x(\d{2,5})/);if(!c)throw new Error("Could not detect video dimensions");let[,d,u]=c;e&&(e.text="Creating thumbnail frame...");let C="/tmp/cc-thumb-frame.mp4";Be(`${s} -y -loop 1 -i "${r}" -vf "scale=${d}:${u}:force_original_aspect_ratio=decrease,pad=${d}:${u}:(ow-iw)/2:(oh-ih)/2,setsar=1" -t 0.033 -r 30 -c:v libx264 -pix_fmt yuv420p "${C}"`,{stdio:"pipe"}),e&&(e.text="Concatenating with video...");let y="/tmp/cc-concat-video.mp4";if(Be(`${s} -y -i "${C}" -i "${o}" -filter_complex "[0:v][1:v]concat=n=2:v=1:a=0[v]" -map "[v]" -map 1:a -c:v libx264 -preset ultrafast -crf 18 -c:a copy "${y}"`,{stdio:"pipe"}),e&&(e.text="Adding file icon thumbnail..."),Be(`${s} -y -i "${y}" -i "${r}" -map 0 -map 1 -c copy -c:v:1 png -disposition:v:1 attached_pic "${i}"`,{stdio:"pipe"}),await mn(C,{force:!0}),await mn(y,{force:!0}),e?.stop(),t==="json"){_({success:!0,output:i});return}if(t==="quiet"){console.log(i);return}v(`Thumbnail injected: ${i}`)}catch(o){e?.stop(),l(o instanceof Error?o.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),Cs=new ce("thumbnail").description("Thumbnail operations").addCommand(Ts),tr=new ce("video").description("Video generation commands").addCommand(ws).addCommand(bs).addCommand(Ss).addCommand(Cs).addCommand(Qo);import{Command as ks}from"commander";import $s from"ora";import{writeFile as Is}from"fs/promises";var nr=new ks("scrape").description("Extract content from a URL").argument("<url>","URL to scrape").option("-o, --output <path>","Save content to file").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{let e=t.format,o=e==="human"?$s("Scraping URL...").start():null;try{let r=await Xn(n);o?.stop(),r.success||(l(r.error||"Failed to scrape URL"),process.exit(T.GENERAL_ERROR));let i=r.data;if(t.output&&(await Is(t.output,i.content,"utf-8"),e==="human"&&v(`Content saved to: ${t.output}`)),e==="json"){let{cost:s,...a}=i;_(a);return}if(e==="quiet"){console.log(i.content);return}i.title&&(console.log(),console.log(`Title: ${i.title}`)),i.metadata?.description&&console.log(`Description: ${i.metadata.description}`),console.log(`URL: ${i.url}`),console.log(`Tokens: ~${i.metadata?.tokenUsage?.toLocaleString()||"unknown"}`),i.warning&&A(i.warning),t.output||(console.log(),console.log("--- Content ---"),console.log(i.content)),i.cost&&i.cost>0&&p(`Cost: $${i.cost.toFixed(6)}`)}catch(r){o?.stop(),l(r instanceof Error?r.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}});import{Command as gn}from"commander";import pn from"ora";import{writeFile as or,mkdir as Rs}from"fs/promises";import{dirname as As}from"path";function fn(n,t){if(t==="json"){let{cost:e,...o}=n;_(o);return}if(t==="quiet"){n.audioUrl?console.log(n.audioUrl):n.requestId?console.log(n.requestId):console.log(n.id);return}p(`Request ID: ${n.requestId||n.id}`),p(`Status: ${n.status}`),n.duration&&p(`Duration: ${n.duration}s`),n.audioUrl&&v(`Audio URL: ${n.audioUrl}`),n.cost!==void 0&&p(`Cost: $${n.cost.toFixed(4)}`),n.error&&l(`Error: ${n.error}`)}async function Os(n,t){if(await Rs(As(t),{recursive:!0}),n.startsWith("data:")){let r=n.match(/^data:[^;]+;base64,(.+)$/);if(!r)throw new Error("Invalid data URL format");let i=Buffer.from(r[1],"base64");await or(t,i);return}let e=await fetch(n);if(!e.ok)throw new Error(`Failed to download: ${e.status}`);let o=await e.arrayBuffer();await or(t,Buffer.from(o))}var Es=new gn("generate").description("Generate sound effects from a text prompt").requiredOption("-t, --text <text>","Sound effect description (e.g., 'thunder rumbling, rain on window')").option("-d, --duration <seconds>","Duration in seconds (0.5-30)").option("-p, --provider <provider>","Provider (elevenlabs)","elevenlabs").option("--prompt-influence <value>","How closely to follow prompt (0-1)","0.3").option("-l, --loop","Generate seamless looping audio",!1).option("--format <format>","Audio format: mp3, wav, ogg","mp3").option("-o, --output <path>","Output file path").option("--no-wait","Do not wait for completion").option("-f, --output-format <format>","Output format: human, json, quiet","human").action(async n=>{let t;n.duration&&(t=parseFloat(n.duration),(isNaN(t)||t<.5||t>30)&&(l("Duration must be between 0.5 and 30 seconds"),process.exit(T.INVALID_INPUT)));let e;n.promptInfluence&&(e=parseFloat(n.promptInfluence),(isNaN(e)||e<0||e>1)&&(l("Prompt influence must be between 0 and 1"),process.exit(T.INVALID_INPUT)));let o=n.outputFormat,r=o==="human"?pn("Generating sound effects...").start():null;try{let i=await Kn({text:n.text,duration:t,options:{provider:n.provider,promptInfluence:e,loop:n.loop,format:n.format}});if(!n.wait){r?.stop(),fn(i,o);return}let s=i;if(i.status!=="completed"&&i.status!=="failed"){let a=i.requestId||i.id;r&&(r.text=`Processing (ID: ${a})...`),s=await ue(()=>qt(a),60,2e3)}if(r?.stop(),s.status==="failed"&&(l(s.error||"Sound effects generation failed"),process.exit(T.GENERAL_ERROR)),fn(s,o),n.output&&s.audioUrl){let a=o==="human"?pn("Downloading...").start():null;try{await Os(s.audioUrl,n.output),a?.stop(),o==="human"&&v(`Saved to: ${n.output}`)}catch(c){a?.stop(),A(`Failed to download: ${c instanceof Error?c.message:"Unknown error"}`)}}}catch(i){r?.stop(),l(i instanceof Error?i.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),Ps=new gn("status").description("Check status of a sound effects generation request").argument("<id>","Request ID").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{let e=t.format==="human"?pn("Checking status...").start():null;try{let o=await qt(n);e?.stop(),fn(o,t.format)}catch(o){e?.stop(),l(o instanceof Error?o.message:"Unknown error"),process.exit(T.GENERAL_ERROR)}}),rr=new gn("sfx").description("Sound effects generation commands").addCommand(Es).addCommand(Ps);var Ds="0.2.0",U=new Fs,le=m.commands[0];U.name(le).description(m.description).version(Ds,"-v, --version","Show version number").option("--debug","Enable debug logging").option("--no-color","Disable colored output").configureOutput({outputError:(n,t)=>{t(Z.red(n))}});U.addCommand(so);U.addCommand(ao);U.addCommand(lo);U.addCommand(fo);U.addCommand(go);U.addCommand(ho);U.addCommand(yo);U.addCommand(vo);U.addCommand(wo);U.addCommand(To);U.addCommand($o);U.addCommand(Io);U.addCommand(je);U.addCommand(_o);U.addCommand(Bo);U.addCommand(Go);U.addCommand(Yo);U.addCommand(tr);U.addCommand(nr);U.addCommand(rr);var ir=ko();ir.commands.length>0&&U.addCommand(ir);U.on("command:*",n=>{console.error(Z.red(`Error: Unknown command '${n[0]}'`)),console.error(),console.error(`Run '${le} --help' to see available commands.`),process.exit(1)});U.addHelpText("after",`
3746
+ ${Z.bold("Examples:")}
3747
+ ${Z.gray("# Log in (opens browser)")}
3748
+ $ ${le} login
3749
+
3750
+ ${Z.gray("# Create a presentation (recommended pattern)")}
3751
+ $ ${le} create "Q4 Business Review" \\
3752
3752
  -n 12 -m best \\
3753
3753
  --audience "Executive leadership team" \\
3754
3754
  --context "Revenue: $50M (+25% YoY), New customers: 150"
3755
3755
 
3756
- ${Q.gray("# Create from a file")}
3757
- $ ${ce} create "Product Launch" \\
3756
+ ${Z.gray("# Create from a file")}
3757
+ $ ${le} create "Product Launch" \\
3758
3758
  -n 10 -m balanced \\
3759
3759
  --audience "Sales team and partners" \\
3760
3760
  --context-file ./launch-brief.md
3761
3761
 
3762
- ${Q.gray("# Create from URLs")}
3763
- $ ${ce} create "Market Analysis" \\
3762
+ ${Z.gray("# Create from URLs")}
3763
+ $ ${le} create "Market Analysis" \\
3764
3764
  -n 15 -m best \\
3765
3765
  --audience "Strategy team" \\
3766
3766
  --sources https://example.com/report.pdf
3767
3767
 
3768
- ${Q.gray("# List and export")}
3769
- $ ${ce} list --format table
3770
- $ ${ce} export <slug> -o backup.zip
3768
+ ${Z.gray("# List and export")}
3769
+ $ ${le} list --format table
3770
+ $ ${le} export <slug> -o backup.zip
3771
3771
 
3772
- ${Q.bold("Authentication:")}
3773
- Run '${ce} login' to authenticate (recommended).
3774
- Or set CC_MINDFRAMES_API_KEY environment variable for API key auth.
3772
+ ${Z.bold("Authentication:")}
3773
+ Run '${le} login' to authenticate (recommended).
3774
+ Or set CC_SLIDES_API_KEY environment variable for API key auth.
3775
3775
 
3776
- ${Q.bold("More Info:")}
3777
- ${Q.blue(u.docsUrl)}
3778
- `);N.parse();
3776
+ ${Z.bold("More Info:")}
3777
+ ${Z.blue(m.docsUrl)}
3778
+ `);U.parse(xn(process.argv.slice(2)),{from:"user"});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@conceptcraft/mindframes",
3
- "version": "0.1.38",
4
- "description": "CLI tool for creating AI-powered presentations with Mindframes",
3
+ "version": "0.2.0",
4
+ "description": "CLI tool for creating AI-powered presentations with ConceptCraft",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "mf": "./bin/cli.js",
@@ -16,10 +16,14 @@
16
16
  "scripts": {
17
17
  "build": "tsup",
18
18
  "dev": "tsup --watch",
19
+ "cli:staging": "pnpm build && CONCEPTCRAFT_API_URL=https://cc-slides.productcabin.co node bin/cli.js",
20
+ "cli:local": "pnpm build && CONCEPTCRAFT_API_URL=http://localhost:3000 node bin/cli.js",
21
+ "cli:smoke": "bash scripts/live-smoke.sh",
19
22
  "lint": "biome lint --write --unsafe",
20
23
  "format": "biome format --write",
21
24
  "typecheck": "tsc --noEmit",
22
- "prepublishOnly": "npm run build",
25
+ "verify:package": "node scripts/verify-package.mjs",
26
+ "prepublishOnly": "npm run build && npm run verify:package",
23
27
  "postinstall": "node ./bin/postinstall.js",
24
28
  "test": "vitest run",
25
29
  "test:watch": "vitest",
@@ -30,7 +34,7 @@
30
34
  "test:all": "vitest run && vitest run --config vitest.e2e.config.ts"
31
35
  },
32
36
  "keywords": [
33
- "mindframes",
37
+ "conceptcraft",
34
38
  "slides",
35
39
  "presentation",
36
40
  "ai",
@@ -39,16 +43,18 @@
39
43
  "deck",
40
44
  "generator"
41
45
  ],
42
- "author": "Mindframes AI",
46
+ "author": "ConceptCraft AI",
43
47
  "license": "SEE LICENSE IN LICENSE",
44
48
  "homepage": "https://conceptcraft.ai",
45
49
  "publishConfig": {
46
- "access": "public"
50
+ "access": "public",
51
+ "registry": "https://registry.npmjs.org"
47
52
  },
48
53
  "engines": {
49
54
  "node": ">=20.0.0"
50
55
  },
51
56
  "dependencies": {
57
+ "@inquirer/prompts": "^8.1.0",
52
58
  "@remotion/bundler": "4.0.375",
53
59
  "@remotion/renderer": "4.0.375",
54
60
  "chalk": "^5.3.0",