@conceptcraft/mindframes 0.2.0 → 0.3.1
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 +3 -3
- package/dist/index.js +86 -68
- package/package.json +5 -3
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://
|
|
3
|
+
Command-line tool for creating AI-powered presentations with [Mindframes](https://www.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://
|
|
19
|
+
Get your API key from [Mindframes Settings](https://www.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://
|
|
247
|
+
| `MINDFRAMES_API_URL` | Custom API URL (default: https://www.mindframes.app) |
|
|
248
248
|
|
|
249
249
|
## Requirements
|
|
250
250
|
|
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
|
-
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(`
|
|
3
|
+
var h={id:"mindframes",name:"mindframes",displayName:"Mindframes",description:"CLI tool for Mindframes presentation generation",commands:["mf","mindframes"],apiUrl:"https://www.mindframes.app",docsUrl:"https://docs.mindframes.ai",packageName:"@conceptcraft/mindframes",configDir:".mindframes",apiKeyEnvVar:"MINDFRAMES_API_KEY",apiUrlEnvVar:"MINDFRAMES_API_URL"};import ie from"chalk";import{Command as Wc}from"commander";import{Command as Pi}from"commander";import{randomUUID as Kt}from"crypto";import{readFileSync as wi,statSync as Si}from"fs";import{basename as no}from"path";import pt from"chalk";import yi from"conf";function Hn(n={}){let t=(s,l)=>{let d=n[s];return d&&d.trim().length>0?d.trim():l},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}`),a=e.toUpperCase().replace(/[^A-Z0-9]/g,"_");return{id:r,name:i.replace(/^\./,""),displayName:e,description:`CLI tool for ${e} presentation generation`,commands:[o,r],apiUrl: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:`${a}_API_KEY`,apiUrlEnvVar:`${a}_API_URL`}}var u=typeof h<"u"&&h?h:Hn(process.env);var zn=u.apiUrl,bi={apiKey:{type:"string"},apiUrl:{type:"string",default:zn},defaultTeamId:{type:"string"},accessToken:{type:"string"},refreshToken:{type:"string"},tokenExpiresAt:{type:"number"},clientId:{type:"string"},clientSecret:{type:"string"}},O=new yi({projectName:u.name,schema:bi});function Yn(){return{apiKey:de(),apiUrl:j(),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 de(){let n=process.env[u.apiKeyEnvVar]??process.env.CC_SLIDES_API_KEY;return n||O.get("apiKey")}function Ht(n){O.set("apiKey",n)}function j(){let n=process.env[u.apiUrlEnvVar]??process.env.CC_SLIDES_API_URL;return n||(O.get("apiUrl")??zn)}function zt(n){O.set("apiUrl",n)}function at(){return O.get("defaultTeamId")}function ke(n){O.set("defaultTeamId",n)}function st(){O.clear()}function ct(){return O.path}function Re(){return!!de()}function Kn(){return O.get("accessToken")}function Xn(){return O.get("refreshToken")}function lt(n,t,e){O.set("accessToken",n),O.set("refreshToken",t),O.set("tokenExpiresAt",Date.now()+(e-60)*1e3)}function dt(){O.delete("accessToken"),O.delete("refreshToken"),O.delete("tokenExpiresAt")}function Qn(){let n=O.get("tokenExpiresAt");return n?Date.now()>=n:!0}function be(){return!!O.get("accessToken")&&!!O.get("refreshToken")}function mt(){return O.get("clientId")}function ut(){return O.get("clientSecret")}function Zn(n,t){O.set("clientId",n),O.set("clientSecret",t)}var p={SUCCESS:0,GENERAL_ERROR:1,AUTH_ERROR:2,NOT_FOUND:3,RATE_LIMIT:4,NETWORK_ERROR:5,INVALID_INPUT:6};async function vi(){let n=Xn(),t=mt(),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}),a=ut();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 dt(),null;let l=await s.json();return lt(l.access_token,l.refresh_token,l.expires_in),l.access_token}catch{return null}}async function eo(){return be()?Qn()?vi():Kn()||null:null}function oe(){return be()||Re()}async function E(){if(!oe()){let n=u.commands[0],t=u.apiKeyEnvVar;console.error(pt.red("\u2717 Not authenticated.")),console.error(),console.error(pt.bold("To authenticate, run:")),console.error(pt.cyan(` ${n} login`)),console.error(),console.error(pt.gray(`Or set ${t} environment variable.`)),process.exit(p.AUTH_ERROR)}}function xi(n){return n.length<=14?"****":`${n.slice(0,10)}...${n.slice(-4)}`}function to(){let n=de();if(n)return xi(n)}function Yt(n){return["cc_slides_","mcp_","cc_sk_","sk_"].some(e=>n.startsWith(e))}async function ge(){let n=await eo();if(n)return{Authorization:`Bearer ${n}`};let t=de();return t?{"x-api-key":t}:{}}var D=class extends Error{constructor(e,o,r=1,i="operation_failed",a=!1){super(e);this.statusCode=o;this.exitCode=r;this.errorCode=i;this.retryable=a;this.name="ApiError"}statusCode;exitCode;errorCode;retryable},oo="Idempotency-Key";function Ci(n){return n&&n!=="GET"?{[oo]:Kt()}:{}}async function J(n,t={}){let e=j();if(!oe())throw new D(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2,"authentication_required");let o=await ge(),r=`${e}${n}`,i={...o,...Ci(t.method),...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 D(`Network error: ${d instanceof Error?d.message:"Unknown error"}`,0,5,"service_unavailable",!0)}if(!s.ok){let d=await s.text().catch(()=>""),f=Ti(d,s.status),b=1;switch(s.status){case 401:b=2;break;case 403:b=2;break;case 404:b=3;break;case 429:b=4;break;case 500:b=1;break}let v=`[${f.code}] ${f.message}`;throw new D(v,s.status,b,f.code,f.retryable)}return t.stream?s:s.headers.get("content-type")?.includes("application/json")?s.json():s.text()}function Ii(n){switch(n){case 400:return"invalid_input";case 401:return"authentication_required";case 402:return"insufficient_credits";case 403:return"access_denied";case 404:return"not_found";case 429:return"rate_limited";case 503:return"service_unavailable";default:return"operation_failed"}}function Ti(n,t){let e=Ii(t),o=n.trim()||`HTTP ${t}: The request could not be completed.`;try{let r=JSON.parse(n),i=typeof r.error=="object"&&r.error!==null?r.error:void 0;if(r.ok===!1&&typeof i?.code=="string"&&typeof i.message=="string")return{code:i.code,message:i.message,retryable:i.retryable===!0};if(typeof r.error=="string")return{code:/^[a-z][a-z0-9_]+$/.test(r.error)?r.error:e,message:typeof r.message=="string"?r.message:r.error,retryable:t===429||t>=500}}catch{}return{code:e,message:o,retryable:t===429||t>=500}}async function ro(){return J("/api/cli/capabilities")}async function F(n,t,e){let o=e?`?teamId=${encodeURIComponent(e)}`:"";return J(`/api/cli/tool-runs/${encodeURIComponent(n)}/${encodeURIComponent(t)}${o}`)}async function R(n,t){return J(`/api/cli/tools/${encodeURIComponent(n)}`,{body:t,method:"POST"})}async function ki(n,t,e=120){for(let o=0;o<e;o++){let r=await F(n,t);if(r.done){if(r.error)throw new D(`[${r.error.code??"operation_failed"}] ${r.error.message}`,500,1,r.error.code??"operation_failed",r.error.retryable);return r}await new Promise(i=>setTimeout(i,(r.nextPollAfterSeconds??2)*1e3))}throw new D("[operation_timed_out] The background operation timed out.",408,1,"operation_timed_out",!0)}function Xt(n){return n.error||n.status==="failed"?"failed":n.done||n.status==="completed"?"completed":n.status==="in_progress"?"processing":"pending"}function Ri(n){try{let e=new URL(n).pathname.split("/").pop()?.split(".").pop()?.toLowerCase();return e&&/^[a-z0-9]+$/.test(e)?e:void 0}catch{return}}function $i(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 Ai(n){let t=j();if(!oe())throw new D(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2);let e=await ge(),o=Si(n),r=no(n),i=$i(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 v=await a.text();throw new D(v||"Failed to get upload URL",a.status,1)}let s=await a.json(),l=wi(n),d=new FormData;for(let[v,g]of Object.entries(s.fields||{}))d.append(v,g);let f=new Blob([l],{type:i});d.append("file",f,r);let b=await fetch(s.url,{method:"POST",body:d});if(!b.ok)throw new D("Failed to upload file to storage",b.status,1);return{id:Kt(),name:r,url:s.fileUrl,size:o.size,type:i,selected:!0}}async function io(n,t){let e=[];for(let o=0;o<n.length;o++){let r=n[o],i=no(r);t?.(o,n.length,i);let a=await Ai(r);e.push(a)}return t?.(n.length,n.length,""),e}async function ao(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),R("createSlides",{...t,approvalReceipt:"cli:create"})}async function so(n,t=20){let e=new URLSearchParams;return e.set("limit",String(t)),n&&e.set("teamId",n),(await J(`/api/cli/presentations?${e}`)).presentations}async function fe(n){return J(`/api/cli/presentation/${n}`)}async function co(n){await J(`/api/cli/presentation/${n}`,{method:"DELETE"})}async function lo(n,t={}){let e=j();if(!oe())throw new D(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2);let o=await ge(),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 D(await r.text(),r.status,r.status===404?3:1);return r.arrayBuffer()}async function mo(n,t,e={}){let o=j();if(!oe())throw new D(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2);let r=await ge(),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}),l=await s.json();if(!s.ok)throw new D(l.errors?.[0]?.message??"Import failed",s.status,1);return l}async function Qt(){return J("/api/cli/branding")}async function uo(n,t=25){let e=new URLSearchParams;return e.set("limit",String(t)),n&&e.set("search",n),J(`/api/cli/templates?${e}`)}async function po(n){return J(`/api/branding/${n}`)}async function go(n,t,e){return R("extractBranding",{approvalReceipt:e,teamId:t,url:n})}async function me(){return J("/api/cli/whoami")}async function fo(){return J("/api/cli/features")}async function ho(n,t,e={}){let o=j();if(!oe())throw new D(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2);let r=await ge(),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 D(await i.text(),i.status,i.status===404?3:1);return i}async function Ei(n){let t=new URLSearchParams;n&&t.set("teamId",n);let e=t.toString();return J(`/api/cli/limits${e?`?${e}`:""}`)}async function yo(n,t,e){let o=await Ei(e);if(!o.canGenerate[n]){let r=o.remaining[n]??0,i=o.limits[n]??0;throw i===0?new D(`The "${n}" mode is not available on your ${o.planName} plan. Available modes: ${o.availableModes.join(", ")||"none"}`,403,2):new D(`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 D(`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 bo(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 gt(n){let t=await R("generateSpeech",{approvalReceipt:"cli:tts-generate",...n,text:bo(n.text)}),o=(await ki("generateSpeech",t.runId)).entity?.url;if(!o)throw new D("Speech completed without an audio URL",500);let r=await fetch(o);if(!r.ok)throw new D("Failed to download speech audio",502);return{audioData:Buffer.from(await r.arrayBuffer()),duration:0,cost:0,provider:n.options?.provider??"gemini",format:Ri(o)??"mp3",requestId:t.runId}}async function vo(n){let t=j();if(!oe())throw new D(`Not authenticated. Run '${u.commands[0]} login' or set ${u.apiKeyEnvVar} environment variable.`,401,2);let e=await ge(),o=Kt(),r={...n,texts:n.texts.map(s=>({...s,text:bo(s.text)}))},i;try{i=await fetch(`${t}/api/cli/tts/batch`,{method:"POST",headers:{"Content-Type":"application/json",[oo]:o,...e},body:JSON.stringify(r)})}catch(s){throw new D(`Network error: ${s instanceof Error?s.message:"Unknown error"}`,0,5)}if(!i.ok){let s=await i.text().catch(()=>"Unknown error"),l;try{let d=JSON.parse(s);l=d.error||d.message||s}catch{l=s}throw new D(l,i.status,i.status===401?2:1)}let a=await i.json();return a.results=a.results.map(s=>({...s,audioData:Buffer.from(s.audioData,"base64")})),a}async function xo(n){let t=n?`/api/cli/tts?provider=${n}`:"/api/cli/tts";return J(t)}async function ft(n){return{requestId:(await R("generateMusic",{...n,approvalReceipt:"cli:music-generate"})).runId,status:"pending"}}async function Qe(n){let t=await F("generateMusic",n);return{requestId:n,status:Xt(t),audioUrl:t.entity?.url,error:t.error?.message}}async function wo(n){return{requestId:(await R("mixAudio",{...n,approvalReceipt:"cli:mix-create"})).runId,status:"pending"}}async function Zt(n){let t=await F("mixAudio",n);return{requestId:n,status:Xt(t),outputUrl:t.entity?.url,error:t.error?.message}}async function ht(n){return J("/api/cli/images/search",{method:"POST",body:n})}async function So(n){return J("/api/cli/images/generate",{method:"POST",body:n})}async function en(n){return J("/api/cli/videos/search",{method:"POST",body:n})}async function he(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 D("Operation timed out",408,1)}async function Co(n,t){let e=await R("scrape",{teamId:t,url:n});return{data:{content:e.content,cost:e.totalCost??0,metadata:{description:"",format:"markdown",tokenUsage:Math.ceil(e.content.length/4)},title:e.title??"",url:e.url},success:!0}}async function Io(n){let t=await R("generateSfx",{...n,approvalReceipt:"cli:sfx-generate"});return{id:t.runId,requestId:t.runId,status:"pending"}}async function tn(n){let t=await F("generateSfx",n);return{id:t.entity?.id??n,requestId:n,status:Xt(t),audioUrl:t.entity?.url,error:t.error?.message}}async function nn(n){return R("generateVideoPlan",{...n,approvalReceipt:"cli:video-plan"})}async function To(n){return R("createVideo",{...n,approvalReceipt:"cli:video-create"})}async function ko(n){return J("/api/cli/video/plan",{body:n,method:"POST"})}import P from"chalk";import on from"cli-table3";function C(n,t="human"){t!=="quiet"&&t!=="json"&&console.log(P.green("\u2713"),n)}function c(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 m(n,t="human"){t!=="quiet"&&t!=="json"&&console.log(P.blue("\u2139"),n)}function $e(n,t="en"){return n?`${j()}/${t}/view/presentations/${n}`:"N/A"}function Ro(n,t={}){let{showLinks:e=!1,language:o="en"}=t,r=(s,l)=>s.length>l?s.slice(0,l-1)+"\u2026":s,i=s=>{try{return new Date(s).toLocaleString("en-US",{month:"short",day:"numeric",hour:"numeric",minute:"2-digit",hour12:!0}).replace(" at ",", ")}catch{return"-"}};if(e){let s=new on({head:[P.cyan("Slug"),P.cyan("Title"),P.cyan("Slides"),P.cyan("Created"),P.cyan("URL")]});for(let l of n)s.push([r(l.slug||l.id.slice(0,8),30),r(l.title||"Untitled",22),String(l.numberOfSlides||"-"),i(l.createdAt),$e(l.slug,o)]);return s.toString()}let a=new on({head:[P.cyan("Slug"),P.cyan("Title"),P.cyan("Slides"),P.cyan("Mode"),P.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 $o(n){return n.map(t=>t.slug||t.id).join(`
|
|
4
|
+
`)}function Ao(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 on({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 rn(n){try{return new Date(n).toLocaleString()}catch{return n}}function se(n){console.log(),console.log(P.bold(n)),console.log(P.gray("\u2500".repeat(n.length)))}function I(n,t){console.log(` ${P.gray(n+":")} ${t??"-"}`)}function Oi(n){return JSON.stringify(n,null,2)}function x(n){console.log(Oi(n))}var Eo=new Pi("capabilities").description("List callable capabilities and their parity state").option("-f, --format <format>","Output format: human, json, quiet","human").action(async n=>{try{let t=await ro();if(n.format==="json"){x(t);return}for(let e of t.capabilities){if(n.format==="quiet"){console.log(e.name);continue}console.log(`${e.name} ${e.state} ${e.milestone}`)}}catch(t){c(t instanceof Error?t.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}});import{Command as we}from"commander";import Ze from"chalk";import{input as Li,password as Ui,confirm as No,select as _i}from"@inquirer/prompts";import sn from"ora";import Di from"conf";var yt=new Di({projectName:"conceptcraft",configName:"feature-cache"}),Ni=3600*1e3,Fi=1440*60*1e3;function Oo(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 Po(){if(!Re())return null;let n=yt.get("featureFlags");if(!n)return null;let t=Oo(de());if(n.apiKeyHash&&n.apiKeyHash!==t)return xe(),null;let e=Date.now()-n.fetchedAt;return e>Fi?null:(e>Ni&&an(),n.flags)}function an(){ve().catch(()=>{})}async function ve(){let n=await fo(),t=de();return yt.set("featureFlags",{flags:n,fetchedAt:Date.now(),apiKeyHash:t?Oo(t):void 0}),n}function xe(){yt.delete("featureFlags")}function Do(){return yt.path}var Fo=new we("config").description("Manage CLI configuration").addCommand(new we("init").description("Initialize configuration interactively").action(async()=>{console.log(),console.log(Ze.bold(`${u.displayName} CLI Configuration`)),console.log(Ze.gray("\u2500".repeat(35))),console.log();try{let n=await Ui({message:"Enter your API key:",mask:"*",validate:o=>!o||o.trim().length===0?"API key is required":Yt(o.trim())?!0:"Invalid API key format. Keys should start with 'cc_slides_' or 'mcp_'"});if(Ht(n.trim()),await No({message:`Use a custom API URL? (default: ${u.apiUrl.replace("https://","")})`,default:!1})){let o=await Li({message:"Enter API URL:",default:j(),validate:r=>{try{return new URL(r),!0}catch{return"Invalid URL format"}}});zt(o)}console.log();let e=sn("Verifying API key...").start();try{let o=await me();if(e.succeed("API key verified!"),console.log(),m(`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];ke(r.id),m(`Team: ${r.name} (${r.planName})`)}else{console.log(),m(`You have access to ${o.teams.length} teams.`);let r=await _i({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});ke(r);let i=o.teams.find(a=>a.id===r);C(`Selected team: ${i?.name}`)}try{await ve()}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: ${u.commands[0]} config set team-id <id>`)}console.log(),C("Configuration saved!"),m(`Config file: ${ct()}`),console.log()}catch(n){if(n.name==="ExitPromptError"){console.log(),m("Configuration cancelled.");return}throw n}})).addCommand(new we("show").description("Show current configuration").option("--verify","Verify API key and show team details").action(async n=>{let t=Yn();if(se("Current Configuration"),console.log(),I("API Key",to()??Ze.red("Not set")),I("API URL",t.apiUrl),I("Default Team ID",t.defaultTeamId??Ze.gray("Not set")),console.log(),I("Config file",ct()),n.verify&&t.apiKey){console.log();let e=sn("Verifying...").start();try{let o=await me();e.succeed("Verified"),console.log(),I("User",o.user.email),o.currentTeam&&I("Current Team",`${o.currentTeam.name} (${o.currentTeam.planName})`),o.teams.length>1&&I("Total Teams",String(o.teams.length))}catch(o){e.fail("Verification failed"),A(o instanceof Error?o.message:String(o))}}console.log()})).addCommand(new we("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":Yt(t)||(c("Invalid API key format. Keys should start with 'cc_slides_' or 'mcp_'"),process.exit(6)),Ht(t),xe(),C("API key updated"),ve().catch(()=>{});break;case"api-url":try{new URL(t),zt(t),C(`API URL set to: ${t}`)}catch{c("Invalid URL format"),process.exit(6)}break;case"team-id":ke(t),C(`Default team ID set to: ${t}`);break;default:c(`Unknown config key: ${n}`),console.log(Ze.gray("Valid keys: api-key, api-url, team-id")),process.exit(6)}})).addCommand(new we("clear").description("Clear all configuration").action(async()=>{try{await No({message:"Are you sure you want to clear all configuration?",default:!1})?(st(),xe(),C("Configuration cleared")):m("Cancelled")}catch{m("Cancelled")}})).addCommand(new we("refresh").description("Refresh cached feature flags").action(async()=>{let n=sn("Refreshing feature flags...").start();try{await ve(),n.succeed("Feature flags refreshed"),m(`Run '${u.commands[0]} --help' to see updated commands`)}catch(t){n.fail("Failed to refresh"),c(t instanceof Error?t.message:String(t)),process.exit(1)}})).addCommand(new we("path").description("Show configuration file path").option("--cache","Show feature cache file path").action(n=>{n.cache?console.log(Do()):console.log(ct())}));import{Command as Mi}from"commander";import{confirm as ji}from"@inquirer/prompts";var Lo=new Mi("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 E(),!t.force)try{if(!await ji({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 co(n),t.quiet||C(`Presentation "${n}" deleted`)}catch(e){c(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}});import{Command as Ae}from"commander";import _o from"chalk";import Vi from"ora";import{createParser as dd}from"eventsource-parser";import ud from"chalk";import gd from"ora";async function Uo(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}function qi(){return new Ae("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 E();let e=parseInt(t.words,10);(isNaN(e)||e<50||e>2e3)&&(c("Word count must be between 50 and 2000"),process.exit(6));let o=["professional","casual","educational"];o.includes(t.tone)||(c(`Invalid tone. Valid options: ${o.join(", ")}`),process.exit(6));let r=Vi("Fetching presentation...").start();try{let i=await fe(n);r.text="Generating blog post...";let a=await ho(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 Uo(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(_o.bold(`Blog: ${i.title}`)),console.log(_o.gray("\u2500".repeat(40))),console.log(),console.log(s),console.log())}catch(i){r.fail("Generation failed"),c(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}})}function Bi(){return new Ae("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 E(),m("Tweet generation coming soon.")})}function Gi(){return new Ae("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 E(),m("LinkedIn carousel generation coming soon.")})}function Wi(){return new Ae("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 E(),m("Question generation coming soon.")})}function Ji(){return new Ae("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 E(),m("Cheat sheet generation coming soon.")})}function Mo(){let n=new Ae("derive").description("Generate derivative content from a presentation"),t=Po();return t&&(t.deckToBlog&&n.addCommand(qi()),t.deckToTweets&&n.addCommand(Bi()),t.linkedInCarousel&&n.addCommand(Gi()),t.redTeamQuestions&&n.addCommand(Wi()),t.presenterCheatSheet&&n.addCommand(Ji())),n}import{Command as Hi}from"commander";import{writeFile as zi}from"fs/promises";import{resolve as jo}from"path";import Yi from"ora";var Vo=new Hi("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 E();let e=Yi("Fetching presentation...").start();try{let o=await fe(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],l=`${a}_${s}.zip`,d=t.output?jo(t.output):jo(process.cwd(),l);e.text=`Exporting "${r}"...`;let f=await lo(i,{includeImages:t.includeImages,includeBranding:t.includeBranding,includeExternal:!t.noExternal});e.text="Saving file...",await zi(d,Buffer.from(f)),e.succeed("Export complete!"),console.log(),m(`File saved: ${d}`),m(`Size: ${Ki(f.byteLength)}`),console.log()}catch(o){e.fail("Export failed"),c(o instanceof Error?o.message:String(o)),process.exit(o.exitCode??1)}});function Ki(n){return n<1024?`${n} B`:n<1024*1024?`${(n/1024).toFixed(1)} KB`:`${(n/(1024*1024)).toFixed(1)} MB`}import{Command as Xi}from"commander";import cn from"chalk";var qo=new Xi("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 E(),m("Idea generation is available in the web dashboard."),console.log(),console.log(cn.gray("The CLI will support idea generation in a future release.")),console.log(),console.log("For now, try these approaches:"),console.log(cn.gray("` 1. Visit the ${brand.displayName} dashboard and use the idea generator`")),console.log(cn.gray(" 2. Create a presentation with a broad topic and refine it")),console.log()});import{Command as Qi}from"commander";import{readFile as Zi}from"fs/promises";import{resolve as ea,basename as ta}from"path";import na from"ora";var Bo=new Qi("import").description("Import a presentation from ZIP (admin only)").argument("<file>","Path to ZIP file");Bo._hidden=!0;var Go=Bo.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 E();try{(await me()).user.role!=="admin"&&(c("This command is only available to administrators"),process.exit(2))}catch{c("Failed to verify permissions"),process.exit(2)}let e=ea(n),o=ta(e);o.endsWith(".zip")||(c("File must be a ZIP archive"),process.exit(6));let r=na("Reading file...").start();try{let i=await Zi(e);t.dryRun?r.text="Validating...":r.text="Importing presentation...";let a=await mo(i,o,{dryRun:t.dryRun});if(a.success){if(t.dryRun)r.succeed("Validation passed!"),console.log(),m("The file is valid and can be imported."),a.statistics&&(console.log(),I("Slides",String(a.statistics.slidesImported)),I("Images",String(a.statistics.imagesUploaded)));else if(r.succeed("Import complete!"),console.log(),I("Presentation ID",a.presentationId??"N/A"),I("Document ID",a.documentId??"N/A"),a.statistics&&(I("Slides imported",String(a.statistics.slidesImported)),I("Images uploaded",String(a.statistics.imagesUploaded)),I("Time",`${a.statistics.totalTimeMs}ms`)),a.presentationId){let s=j();I("View URL",`${s}/p/${a.presentationId}`)}if(a.warnings&&a.warnings.length>0){console.log();for(let s of a.warnings)A(s)}console.log()}else{if(r.fail("Import failed"),console.log(),a.errors)for(let s of a.errors)c(`${s.type}: ${s.message}`);process.exit(1)}}catch(i){r.fail("Import failed"),i.code==="ENOENT"&&(c(`File not found: ${e}`),process.exit(3)),c(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}});import{Command as oa}from"commander";var Wo=new oa("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 E();let t=parseInt(n.limit,10);(isNaN(t)||t<1)&&(c("Invalid limit value"),process.exit(6));let e=n.teamId??at();e||(c("`Team ID required. Set a default with '${brand.commands[0]} config set team-id <id>' or use --team-id`"),process.exit(6));try{let o=await so(e,t);if(o.length===0){n.format==="json"?console.log(JSON.stringify([])):n.format!=="ids"&&m("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($o(o));break;default:console.log(Ro(o,{showLinks:n.detail,language:n.language}));break}}catch(o){c(o instanceof Error?o.message:String(o)),process.exit(o.exitCode??1)}});import{Command as ra}from"commander";import Jo from"chalk";import Ho from"ora";import zo from"http";import{randomBytes as Yo,createHash as ia}from"crypto";import aa from"open";var sa=`${u.displayName} CLI`,ca=8765,la=8775;function da(){return Yo(32).toString("base64url")}function ma(n){return ia("sha256").update(n).digest("base64url")}function ua(){return Yo(16).toString("hex")}async function pa(n,t){for(let e=n;e<=t;e++)try{return await new Promise((o,r)=>{let i=zo.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 ga(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 fa(n,t){let e=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_name:sa,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 ha(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 ya(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),l.close())},s=()=>{a(),o(new Error("Login cancelled"))},l=zo.createServer((d,f)=>{let b=new URL(d.url||"",`http://localhost:${n}`);if(b.pathname!=="/callback"){f.writeHead(404),f.end("Not found");return}let v=b.searchParams.get("code"),g=b.searchParams.get("state"),y=b.searchParams.get("error"),k=b.searchParams.get("error_description");if(f.writeHead(200,{"Content-Type":"text/html"}),y){f.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>${
|
|
10
|
+
<p>${k||y}</p>
|
|
11
11
|
<p>You can close this window.</p>
|
|
12
12
|
</body>
|
|
13
13
|
</html>
|
|
14
|
-
`),
|
|
14
|
+
`),a(),o(new Error(k||y));return}if(!v||!g){f.end(`
|
|
15
15
|
<!DOCTYPE html>
|
|
16
16
|
<html>
|
|
17
17
|
<head><title>Login Failed</title></head>
|
|
@@ -21,7 +21,7 @@ var g={id:"mindframes",name:"mindframes",displayName:"Mindframes",description:"C
|
|
|
21
21
|
<p>You can close this window.</p>
|
|
22
22
|
</body>
|
|
23
23
|
</html>
|
|
24
|
-
`),
|
|
24
|
+
`),a(),o(new Error("Missing authorization code or state"));return}if(g!==t){f.end(`
|
|
25
25
|
<!DOCTYPE html>
|
|
26
26
|
<html>
|
|
27
27
|
<head><title>Login Failed</title></head>
|
|
@@ -31,7 +31,7 @@ var g={id:"mindframes",name:"mindframes",displayName:"Mindframes",description:"C
|
|
|
31
31
|
<p>You can close this window.</p>
|
|
32
32
|
</body>
|
|
33
33
|
</html>
|
|
34
|
-
`),
|
|
34
|
+
`),a(),o(new Error("State mismatch"));return}f.end(`
|
|
35
35
|
<!DOCTYPE html>
|
|
36
36
|
<html>
|
|
37
37
|
<head><title>Login Successful</title></head>
|
|
@@ -40,9 +40,24 @@ var g={id:"mindframes",name:"mindframes",displayName:"Mindframes",description:"C
|
|
|
40
40
|
<p>You can close this window and return to the terminal.</p>
|
|
41
41
|
</body>
|
|
42
42
|
</html>
|
|
43
|
-
`),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
|
-
|
|
43
|
+
`),a(),e({code:v,state:g})});l.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 ba(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 va(n){let t=j(),e=Ho("Discovering OAuth server...").start();try{let o=await ga(t);e.succeed("Connecting to "+t);let r=await pa(ca,la),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=mt(),s=ut();if(!a){let $=await fa(o.registration_endpoint,i);a=$.client_id,s=$.client_secret,Zn(a,s)}let l=da(),d=ma(l),f=ua(),b=new URLSearchParams({client_id:a,redirect_uri:i,response_type:"code",scope:"presentations:read presentations:write",state:f,code_challenge:d,code_challenge_method:"S256"}),v=`${o.authorization_endpoint}?${b}`;console.log("Authorization URL: "+v),n.browser?(m("Opening browser..."),await aa(v)):(console.log(Jo.bold("Open this URL in your browser:")),console.log(Jo.cyan(v)));let g=ya(r,f),{code:y}=await g;e=Ho("Completing login...").start();let k=await ha(o.token_endpoint,y,l,i,a);lt(k.access_token,k.refresh_token,k.expires_in);let w=await ba(t,k.access_token);e.succeed("Logged in!"),console.log(),I("Logged in as",w.user.email),w.currentTeam&&(ke(w.currentTeam.id),I("Team",`${w.currentTeam.name} (${w.currentTeam.planName})`));try{await ve()}catch{}console.log(),C("You're all set!"),console.log()}catch(o){throw e.fail("Login failed"),c(o instanceof Error?o.message:String(o)),o}}var Ko=new ra("login").description(`Authenticate with ${u.displayName} (opens browser)`).option("--no-browser","Print URL instead of opening browser").action(async n=>{console.log(),be()&&(A("You are already logged in."),m(`Run '${u.commands[0]} logout' to log out first, or continue to re-authenticate.`),console.log());try{await va(n),process.exit(0)}catch{process.exit(1)}});import{Command as xa}from"commander";import{confirm as wa}from"@inquirer/prompts";var Xo=new xa("logout").description("Log out and clear authentication").option("--all","Clear all config including API key").action(async n=>{console.log();let t=be(),e=Re();if(!t&&!e){A("You are not logged in."),console.log();return}if(n.all)try{await wa({message:"Clear all configuration including API key?",default:!1})?(st(),xe(),C("All configuration cleared.")):m("Cancelled.")}catch{m("Cancelled.")}else dt(),xe(),C("Logged out successfully."),e&&m("Note: Your API key is still configured. Use --all to clear everything.");console.log()});import{homedir as Xa}from"os";import{join as Qa}from"path";import re from"chalk";import{Command as Za}from"commander";import{spawn as Sa}from"child_process";import{existsSync as Ca}from"fs";import{homedir as Zo}from"os";import{delimiter as Qo}from"path";import{query as Ia}from"@anthropic-ai/claude-agent-sdk";function Ta(n,t){let e=n.replace(/[/.]/g,"-");return`${Zo()}/.claude/projects/${e}/${t}.jsonl`}function bt(){let n=Zo(),t=[`${n}/.local/bin`,`${n}/.claude/local`,`${n}/.bun/bin`,`${n}/bin`,"/opt/homebrew/bin","/usr/local/bin"],o=(process.env.PATH??"").split(Qo);for(let r of t)o.includes(r)||o.push(r);return o.join(Qo)}async function vt(n){let t=n??"claude";return new Promise(e=>{let o=Sa(t,["--version"],{env:{...process.env,PATH:bt()},stdio:["ignore","pipe","ignore"]}),r="";o.stdout.on("data",i=>{r+=i.toString("utf8")}),o.on("error",()=>e(null)),o.on("close",i=>{if(i!==0)return e(null);let a=r.trim().split(`
|
|
44
|
+
`)[0]??"";e(a?{bin:t,version:a}:null)})})}var ka=new Set(["","default","best"]);function ln(n){let t=n.filter(i=>i.text.trim());if(t.length===0)return"";let e=t[t.length-1],o=t.slice(0,-1);return o.length===0?e.text:`<conversation-history>
|
|
45
|
+
${o.map(i=>`${i.role==="assistant"?"Assistant":"User"}: ${i.text}`).join(`
|
|
46
|
+
|
|
47
|
+
`)}
|
|
48
|
+
</conversation-history>
|
|
49
|
+
|
|
50
|
+
${e.text}`}function dn(n,t){return t?n.messages.filter(o=>o.text.trim()).at(-1)?.text??"":ln(n.messages)}function Ra({abortController:n,input:t,resumeSessionId:e,workspace:o}){let r=(t.modelId??"").trim(),i=t.thinking??null,a={abortController:n,allowedTools:["WebSearch","WebFetch"],cwd:o,env:{...process.env,PATH:bt()},includePartialMessages:!0,maxTurns:16,permissionMode:"dontAsk"};return ka.has(r)||(a.model=r),t.effort&&(a.effort=t.effort),i&&i!=="disabled"&&(a.thinking={display:"summarized",type:i==="enabled"?"enabled":"adaptive"}),e?a.resume=e:t.system?.trim()&&(a.systemPrompt=t.system),a}async function er(n){let t=dn(n.input,n.resumeSessionId);if(!t)throw new Error("Chat turn has no user text to send.");let e=new AbortController,o=()=>e.abort();n.signal?.addEventListener("abort",o,{once:!0});let r=null,i=null,a=null,s=null,l=null,d=0;try{let v=Ia({prompt:t,options:Ra({abortController:e,input:n.input,resumeSessionId:n.resumeSessionId,workspace:n.workspace})});for await(let g of v){let y=g;if(y.type==="system"&&y.subtype==="init"){typeof y.session_id=="string"&&(i=y.session_id),typeof y.model=="string"&&(r=y.model,n.onEvent({eventType:"chat.model",payload:{modelId:y.model}}));continue}if(y.type==="stream_event"){let k=y.event;if(k?.type!=="content_block_delta")continue;let w=k.delta;if(!w)continue;w.type==="text_delta"&&typeof w.text=="string"?(d+=w.text.length,n.onEvent({eventType:"chat.text.delta",payload:{text:w.text}})):w.type==="thinking_delta"&&typeof w.thinking=="string"&&n.onEvent({eventType:"chat.reasoning.delta",payload:{text:w.thinking}});continue}y.type==="result"&&(typeof y.result=="string"&&(s=y.result),y.usage&&typeof y.usage=="object"&&(a=y.usage),typeof y.session_id=="string"&&(i=y.session_id),(y.is_error===!0||y.subtype!=="success")&&(l=typeof y.result=="string"&&y.result||`Claude turn failed (${String(y.subtype)}).`,n.onEvent({eventType:"chat.error",message:l,payload:{message:l}})))}}finally{n.signal?.removeEventListener("abort",o)}if(n.signal?.aborted)throw new Error("Chat turn cancelled.");if(l)throw new Error(l);let f=s??"";d===0&&f&&n.onEvent({eventType:"chat.text.delta",payload:{text:f}});let b=i?Ta(n.workspace,i):null;return{modelId:r,sessionId:i,sessionPath:b&&Ca(b)?b:null,text:f,usage:a}}import{spawn as $a}from"child_process";import{readdirSync as Aa}from"fs";import{homedir as Ea}from"os";import{join as tr}from"path";import{Codex as Oa}from"@openai/codex-sdk";var Pa=["/Applications/Codex.app/Contents/Resources/codex"];async function xt(n){let t=n?[n]:["codex",...Pa];for(let e of t){let o=await Da(e);if(o)return{bin:e,version:o}}return null}function Da(n){return new Promise(t=>{let e=$a(n,["--version"],{env:{...process.env,PATH:bt()},stdio:["ignore","pipe","ignore"]}),o="";e.stdout.on("data",r=>{o+=r.toString("utf8")}),e.on("error",()=>t(null)),e.on("close",r=>{if(r!==0)return t(null);let i=o.trim().split(`
|
|
51
|
+
`)[0]??"";t(i||null)})})}function Na(n,t=tr(Ea(),".codex","sessions")){try{let o=Aa(t,{recursive:!0}).find(r=>typeof r=="string"&&r.endsWith(`${n}.jsonl`));return o?tr(t,o):null}catch{return null}}function Fa(n,t){if(t)return dn(n,t);let e=ln(n.messages);return e?n.system?.trim()?`<system-instructions>
|
|
52
|
+
${n.system}
|
|
53
|
+
</system-instructions>
|
|
54
|
+
|
|
55
|
+
${e}`:e:""}var La=new Set(["minimal","low","medium","high","xhigh"]);function Ua(n,t){let e={sandboxMode:"read-only",skipGitRepoCheck:!0,webSearchEnabled:!0,workingDirectory:t},o=(n.modelId??"").trim();return o&&o!=="default"&&(e.model=o),n.effort&&La.has(n.effort)&&(e.modelReasoningEffort=n.effort),e}async function nr(n){let t=Fa(n.input,n.resumeSessionId);if(!t)throw new Error("Chat turn has no user text to send.");let e=new Oa({codexPathOverride:n.bin}),o=Ua(n.input,n.workspace),r=n.resumeSessionId?e.resumeThread(n.resumeSessionId,o):e.startThread(o),i=n.resumeSessionId??null,a=null,s=null,l=[],{events:d}=await r.runStreamed(t);for await(let f of d){if(n.signal?.aborted)throw await d.return?.(void 0),new Error("Chat turn cancelled.");let b=f;if(b.type==="thread.started"){typeof b.thread_id=="string"&&(i=b.thread_id);continue}if(b.type==="item.completed"){let v=b.item;if(!v)continue;v.type==="agent_message"&&typeof v.text=="string"?(l.push(v.text),n.onEvent({eventType:"chat.text.delta",payload:{text:v.text}})):v.type==="reasoning"&&typeof v.text=="string"&&n.onEvent({eventType:"chat.reasoning.delta",payload:{text:v.text}});continue}if(b.type==="turn.completed"){b.usage&&typeof b.usage=="object"&&(a=b.usage);continue}if(b.type==="turn.failed"){let v=b.error;s=typeof v?.message=="string"&&v.message||"Codex turn failed.",n.onEvent({eventType:"chat.error",message:s,payload:{message:s}})}}if(s)throw new Error(s);return i=r.id??i,{modelId:n.input.modelId??null,sessionId:i,sessionPath:i?Na(i):null,text:l.join(`
|
|
56
|
+
|
|
57
|
+
`),usage:a}}import{randomUUID as qa}from"crypto";import{mkdir as Ba}from"fs/promises";import{hostname as fn,platform as Ga}from"os";import{join as Wa}from"path";var Ee=class extends Error{constructor(e,o,r=!1){super(e);this.statusCode=o;this.reRegister=r;this.name="RunnerApiError"}statusCode;reRegister};async function Oe(n,t={}){let e=await ge();t.body!==void 0&&(e["Content-Type"]="application/json");let o=new AbortController,r=setTimeout(()=>o.abort(),t.timeoutMs??3e4),i=()=>o.abort();t.signal?.addEventListener("abort",i,{once:!0});try{let a=await fetch(`${j()}${n}`,{body:t.body!==void 0?JSON.stringify(t.body):void 0,headers:e,method:t.method??"GET",signal:o.signal}),s=await a.text(),l={};try{l=s?JSON.parse(s):{}}catch{l={error:s.slice(0,300)}}if(!a.ok)throw new Ee(typeof l.error=="string"?l.error:`Runner API returned ${a.status}`,a.status,l.reRegister===!0);return l}finally{clearTimeout(r),t.signal?.removeEventListener("abort",i)}}async function or(n){await Oe("/api/runner/register",{body:n,method:"POST",timeoutMs:15e3})}async function rr(n,t){return(await Oe(`/api/runner/work?runnerId=${encodeURIComponent(n)}`,{signal:t,timeoutMs:28e3})).job??null}async function ir(n){await Oe("/api/runner/heartbeat",{body:{runnerId:n},method:"POST",timeoutMs:1e4})}async function ar(n,t){return{cancelRequested:(await Oe(`/api/runner/jobs/${encodeURIComponent(n)}/events`,{body:{events:t},method:"POST",timeoutMs:15e3})).cancelRequested===!0}}async function mn(n,t,e){await Oe(`/api/runner/jobs/${encodeURIComponent(n)}/complete`,{body:{result:e,runnerId:t},method:"POST",timeoutMs:15e3})}async function wt(n,t,e,o=!0){await Oe(`/api/runner/jobs/${encodeURIComponent(n)}/fail`,{body:{message:e,retryable:o,runnerId:t},method:"POST",timeoutMs:15e3})}import{mkdirSync as _a,readFileSync as Ma,writeFileSync as sr}from"fs";import{dirname as ja,join as Va}from"path";function un(n){return Va(n,"sessions.json")}function pn(n){try{let t=Ma(un(n),"utf8"),e=JSON.parse(t);if(e&&typeof e=="object"&&!Array.isArray(e))return e}catch{}return{}}function cr(n,t,e){return t?pn(n)[t]?.[e]??null:null}function lr(n,t,e,o){if(!(!t||!o))try{let r=un(n);_a(ja(r),{recursive:!0});let i=pn(n);i[t]={...i[t],[e]:o},sr(r,`${JSON.stringify(i,null," ")}
|
|
58
|
+
`,"utf8")}catch{}}function dr(n,t,e){if(t)try{let o=pn(n);if(!o[t])return;delete o[t][e],sr(un(n),`${JSON.stringify(o,null," ")}
|
|
59
|
+
`,"utf8")}catch{}}var Ja=300,Ha=3e4;async function mr(n){let[t,e]=await Promise.all([vt(n.claudeBin),xt(n.codexBin)]);if(!t&&!e)throw new Error("Neither Claude Code nor Codex was found on this machine. Install one and log in, then retry.");t?n.log(`Claude Code detected: ${t.version} (${t.bin})`):n.log("Claude Code not found \u2014 Claude turns will be declined."),e?n.log(`Codex detected: ${e.version} (${e.bin})`):n.log("Codex not found \u2014 Codex turns will be declined.");let o=[...t?["claude-code"]:[],...e?["codex"]:[]],r=`${fn().split(".")[0]}-${qa().slice(0,8)}`,i=()=>or({capabilities:["chat_turn","proof"],claudeCodeVersion:t?.version??null,cliVersion:n.version,codexVersion:e?.version??null,hostname:fn(),platform:Ga(),runnerId:r,runtimes:o});for(await i(),n.log(`Registered as ${r} (runtimes: ${o.join(", ")}). Waiting for work\u2026`);!n.signal?.aborted;){let a=null;try{a=await rr(r,n.signal)}catch(s){if(n.signal?.aborted)break;if(s instanceof Ee&&s.reRegister){n.log("Server asked for re-registration."),await i().catch(()=>{});continue}n.log(`Work poll failed (${s instanceof Error?s.message:"unknown"}); retrying\u2026`),await Ka(n.pollBackoffMs??5e3,n.signal);continue}if(!a){if(n.once)continue;continue}if(n.log(`Claimed ${a.jobType} job ${a.runId}.`),await za({claude:t,codex:e,job:a,options:n,runnerId:r}),n.once)break}}async function za({claude:n,codex:t,job:e,options:o,runnerId:r}){let i=new AbortController,a=()=>i.abort();o.signal?.addEventListener("abort",a,{once:!0});let s=setInterval(()=>{ir(r).catch(()=>{})},Ha),l=[],d=!1,f=async()=>{if(d||l.length===0)return;d=!0;let g=l.splice(0,100);try{let{cancelRequested:y}=await ar(e.runId,g);y&&i.abort()}catch(y){y instanceof Ee&&y.statusCode===409&&i.abort()}finally{d=!1}},b=setInterval(()=>{f()},Ja),v=g=>{l.push(g)};try{if(e.jobType==="runner.proof"){let g=typeof e.input.message=="string"?e.input.message:"proof";v({eventType:"proof.echo",payload:{message:g}}),await gn(f,l),await mn(e.runId,r,{echo:g}),o.log(`Proof job ${e.runId} completed.`);return}if(e.jobType==="runner.chat_turn"){let g=e.input.runtime==="codex"?"codex":"claude-code",y=g==="codex"?t&&{detection:t,run:nr}:n&&{detection:n,run:er};if(!y){await wt(e.runId,r,g==="codex"?"Codex is not available on this machine. Install the Codex app or CLI and log in, then retry.":"Claude Code is not available on this machine. Install it and log in, then retry.",!1);return}let k=typeof e.input.chatId=="string"&&e.input.chatId?e.input.chatId:null,w=Wa(o.workspaceRoot,"chats",k??e.runId);await Ba(w,{recursive:!0});let $=Ya(e.input),B=S=>v({eventType:S.eventType,message:S.message??null,payload:S.payload??{}}),L=cr(o.workspaceRoot,k,g),H;try{H=await y.run({bin:y.detection.bin,input:$,onEvent:B,resumeSessionId:L,signal:i.signal,workspace:w})}catch(S){if(!L||i.signal.aborted)throw S;o.log(`Resume of ${g} session failed (${S instanceof Error?S.message:"unknown"}); retrying fresh.`),dr(o.workspaceRoot,k,g),H=await y.run({bin:y.detection.bin,input:$,onEvent:B,resumeSessionId:null,signal:i.signal,workspace:w})}lr(o.workspaceRoot,k,g,H.sessionId),v({eventType:"chat.session",payload:{host:fn(),runtime:g,runtimeVersion:y.detection.version,sessionId:H.sessionId,sessionPath:H.sessionPath}}),await gn(f,l),await mn(e.runId,r,{modelId:H.modelId,runtime:g,runtimeVersion:y.detection.version,sessionId:H.sessionId,sessionPath:H.sessionPath,text:H.text,usage:H.usage??{}}),o.log(`Chat turn ${e.runId} (${g}) completed.`);return}await wt(e.runId,r,`This runner does not support ${e.jobType} jobs. Update the desktop app / CLI.`,!1)}catch(g){let y=g instanceof Error?g.message:"Local runner job crashed.";o.log(`Job ${e.runId} failed: ${y}`),await gn(f,l).catch(()=>{}),await wt(e.runId,r,y).catch(()=>{})}finally{clearInterval(b),clearInterval(s),o.signal?.removeEventListener("abort",a)}}function Ya(n){let t=Array.isArray(n.messages)?n.messages.map(e=>{if(!e||typeof e!="object")return null;let o=e;return{role:typeof o.role=="string"?o.role:"user",text:typeof o.text=="string"?o.text:""}}).filter(e=>!!e):[];return{effort:typeof n.effort=="string"?n.effort:null,messages:t,modelId:typeof n.modelId=="string"?n.modelId:null,system:typeof n.system=="string"?n.system:null,thinking:typeof n.thinking=="string"?n.thinking:null}}async function gn(n,t){for(;t.length>0;)await n(),t.length>0&&await new Promise(e=>setTimeout(e,25))}function Ka(n,t){return n<=0||t?.aborted?Promise.resolve():new Promise(e=>{let o=setTimeout(r,n);function r(){clearTimeout(o),t?.removeEventListener("abort",r),e()}t?.addEventListener("abort",r,{once:!0})})}function es(){return Qa(Xa(),`.${u.commands[0]}-runner`,"runs")}var St=new Za("runner").description("Run agent work locally with your own Claude Code / Codex login (desktop lane)");St.command("status").description("Check local Claude Code / Codex detection and account auth").action(async()=>{let[n,t]=await Promise.all([vt(),xt()]);if(console.log(n?re.green(`\u2713 Claude Code ${n.version}`):re.red("\u2717 Claude Code not found on PATH")),console.log(t?re.green(`\u2713 Codex ${t.version} (${t.bin})`):re.red("\u2717 Codex not found (PATH or Codex.app)")),!oe()){console.log(re.red(`\u2717 Not logged in. Run '${u.commands[0]} login' first.`)),process.exitCode=2;return}try{let e=await me();console.log(re.green(`\u2713 Logged in as ${e.user.email}`))}catch(e){console.log(re.red(`\u2717 Auth check failed: ${e instanceof Error?e.message:"unknown"}`)),process.exitCode=2}});St.command("start").description("Start the local runner (register + wait for work)").option("--once","Execute a single job, then exit").option("--workspace <dir>","Workspace root for job scratch directories").option("--claude-bin <path>","Path to the claude binary").option("--codex-bin <path>","Path to the codex binary").action(async n=>{oe()||(console.error(re.red(`Not authenticated. Run '${u.commands[0]} login' first.`)),process.exit(2));let t=new AbortController,e=()=>{console.log(re.gray(`
|
|
60
|
+
Stopping runner\u2026`)),t.abort()};process.on("SIGINT",e),process.on("SIGTERM",e);try{await mr({claudeBin:n.claudeBin,codexBin:n.codexBin,log:o=>console.log(re.gray(`[runner] ${o}`)),once:n.once,signal:t.signal,version:"0.3.1",workspaceRoot:n.workspace??es()})}catch(o){console.error(re.red(o instanceof Error?o.message:String(o))),process.exit(1)}});import{Command as as}from"commander";import N from"chalk";function Ct(n){let{name:t,cmd:e}=n,o=t.toUpperCase().replace(/[^A-Z0-9]/g,"_");return`---
|
|
46
61
|
name: ${t}
|
|
47
62
|
description: CLI with TTS (text-to-speech), AI music generation, sound effects, stock image/video search, audio mixing, URL scraping, and branding. Use when user asks for voiceover, narration, background music, sound effects, stock footage, or needs to scrape a website.
|
|
48
63
|
---
|
|
@@ -115,7 +130,7 @@ ${e} whoami
|
|
|
115
130
|
### Config
|
|
116
131
|
\`${e} config show\` \u2192 [references/config.md](references/config.md)
|
|
117
132
|
|
|
118
|
-
`}function
|
|
133
|
+
`}function It(n){let{name:t,cmd:e,mode:o="standalone"}=n,r=o==="studio";return`---
|
|
119
134
|
name: ${t}-video
|
|
120
135
|
description: Orchestrates video creation by coordinating specialized agents for branding, audio, and scene building. Gathers context, writes briefs, generates plans, and assembles Remotion videos. Use when user says "create a video", "make a promo", "product demo", "explainer video", "marketing video", "gather video assets", "video for my project", or "TikTok/Reels content".
|
|
121
136
|
---
|
|
@@ -629,7 +644,7 @@ The \`${e}\` CLI has tools for working with individual assets directly. This is
|
|
|
629
644
|
- **Audio mixing:** \`${e} mix\` \u2014 combine voice, music, and video tracks.
|
|
630
645
|
|
|
631
646
|
During the main workflow, branding and audio are handled by their dedicated agents. But for one-off fixes or user requests outside the workflow, use these commands directly.
|
|
632
|
-
`}function
|
|
647
|
+
`}function Tt(n){let{name:t,cmd:e}=n;return`---
|
|
633
648
|
name: ${t}-presentation
|
|
634
649
|
description: Use when user asks to create presentations, slides, decks, pitch decks.
|
|
635
650
|
Researches the topic, gathers context, and generates AI-powered presentations via CLI.
|
|
@@ -831,7 +846,7 @@ ${e} import ./presentation.zip
|
|
|
831
846
|
- **Auth fails** \u2192 \`${e} logout && ${e} login\` (browser required)
|
|
832
847
|
- **"Context required"** \u2192 add \`--context\`, \`--file\`, or \`--context-file\`
|
|
833
848
|
- **Rate limit (429)** \u2192 check plan with \`${e} whoami\`
|
|
834
|
-
`}function
|
|
849
|
+
`}function kt(n){let{name:t,cmd:e}=n;return`---
|
|
835
850
|
name: ${t}-presentation-edit
|
|
836
851
|
description: >
|
|
837
852
|
Use ONLY when editing an already-created presentation that has real slides:
|
|
@@ -1068,7 +1083,7 @@ Do NOT render or export the presentation \u2014 that's handled by the app.
|
|
|
1068
1083
|
| Create brand-new presentation (5+ slides, new topic) | \`${e} create ...\` via CLI |
|
|
1069
1084
|
| Redesign the whole deck | \`${e} create ...\` via CLI, then sync |
|
|
1070
1085
|
| User provides a URL to base the presentation on | \`${e} scrape <url>\` \u2192 \`${e} create ...\` |
|
|
1071
|
-
`}function
|
|
1086
|
+
`}function Pe(n){let{name:t,cmd:e}=n;return`---
|
|
1072
1087
|
name: ${t}-tts
|
|
1073
1088
|
description: Text-to-speech generation. Convert text to natural speech with multiple providers (Gemini, ElevenLabs, OpenAI) and voices. Use for voiceovers, narration, accessibility.
|
|
1074
1089
|
---
|
|
@@ -1267,7 +1282,7 @@ ${e} tts generate \\
|
|
|
1267
1282
|
2. **Voice matching** - Match voice style to content: Puck for upbeat, Charon for serious
|
|
1268
1283
|
3. **Speed adjustment** - Use 0.9-0.95 for narration, 1.0-1.1 for casual
|
|
1269
1284
|
4. **Batch processing** - Use \`video generate assets\` for multiple voiceovers
|
|
1270
|
-
`}function
|
|
1285
|
+
`}function De(n){let{name:t,cmd:e}=n;return`---
|
|
1271
1286
|
name: ${t}-music
|
|
1272
1287
|
description: AI music generation from text prompts. Create background music, soundtracks, jingles for videos, presentations, podcasts. Supports ElevenLabs and Suno providers.
|
|
1273
1288
|
---
|
|
@@ -1407,7 +1422,7 @@ ${e} music generate -p "calm piano" -d 30 -f json
|
|
|
1407
1422
|
2. **Looping** - For seamless loops, mention "loopable" in prompt.
|
|
1408
1423
|
3. **Video sync** - Use \`video generate assets\` to auto-generate music for video projects.
|
|
1409
1424
|
4. **Volume mixing** - Background music should be 20-30% volume when mixed with voiceover.
|
|
1410
|
-
`}function
|
|
1425
|
+
`}function Ne(n){let{name:t,cmd:e}=n;return`---
|
|
1411
1426
|
name: ${t}-sfx
|
|
1412
1427
|
description: AI sound effects generation from text descriptions. Create foley, ambient, UI sounds, impacts, whooshes for videos, games, apps. Uses ElevenLabs SFX.
|
|
1413
1428
|
---
|
|
@@ -1616,7 +1631,7 @@ ${e} sfx generate -t "click" -d 0.5 -f json
|
|
|
1616
1631
|
3. **Prompt influence** - Higher (0.7-1.0) = more literal, lower (0.1-0.3) = more creative.
|
|
1617
1632
|
4. **Descriptive prompts** - Add context: "door slam, heavy wooden door" > "door slam".
|
|
1618
1633
|
5. **Format** - Use WAV for editing, MP3 for final output.
|
|
1619
|
-
`}function
|
|
1634
|
+
`}function Fe(n){let{name:t,cmd:e}=n;return`---
|
|
1620
1635
|
name: ${t}-mix
|
|
1621
1636
|
description: Audio mixing for video production. Combine video with voiceover and background music. Supports volume control, fade effects, and multiple audio tracks.
|
|
1622
1637
|
---
|
|
@@ -1766,7 +1781,7 @@ ${e} mix status <request-id>
|
|
|
1766
1781
|
2. **Music selection** - Choose music that doesn't compete with voice frequency.
|
|
1767
1782
|
3. **Consistent levels** - Keep voice at 100%, adjust music only.
|
|
1768
1783
|
4. **File sizes** - Use \`--no-wait\` for large files to avoid timeout.
|
|
1769
|
-
`}function
|
|
1784
|
+
`}function Le(n){let{name:t,cmd:e}=n;return`---
|
|
1770
1785
|
name: ${t}-image
|
|
1771
1786
|
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
1787
|
---
|
|
@@ -1950,7 +1965,7 @@ Found 10 images for "mountain landscape"
|
|
|
1950
1965
|
3. **Size matters** - Use \`--size large\` for hero images
|
|
1951
1966
|
4. **JSON for automation** - Parse results programmatically
|
|
1952
1967
|
5. **Generation prompts** - Be detailed, describe style, lighting, composition
|
|
1953
|
-
`}function
|
|
1968
|
+
`}function Ue(n){let{name:t,cmd:e}=n;return`---
|
|
1954
1969
|
name: ${t}-video-search
|
|
1955
1970
|
description: Stock video search. Find royalty-free video clips from multiple providers (Pexels, Pixabay). For b-roll, backgrounds, transitions in video production.
|
|
1956
1971
|
---
|
|
@@ -2125,7 +2140,7 @@ ${e} video find "city timelapse" --orientation landscape -n 10
|
|
|
2125
2140
|
3. **Preview first** - Use preview URLs to check quality
|
|
2126
2141
|
4. **License** - Verify license for commercial use
|
|
2127
2142
|
5. **JSON export** - Save searches for batch processing
|
|
2128
|
-
`}function
|
|
2143
|
+
`}function _e(n){let{name:t,cmd:e}=n;return`---
|
|
2129
2144
|
name: ${t}-scrape
|
|
2130
2145
|
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
2146
|
---
|
|
@@ -2315,7 +2330,7 @@ ${e} scrape https://blog.example.com -f quiet | ${e} create "Blog Summary"
|
|
|
2315
2330
|
3. **Use JSON** - For programmatic processing of results
|
|
2316
2331
|
4. **Combine sources** - Scrape multiple URLs for comprehensive context
|
|
2317
2332
|
5. **Token count** - Check token usage for large documents
|
|
2318
|
-
`}function
|
|
2333
|
+
`}function Me(n){let{name:t,cmd:e}=n;return`---
|
|
2319
2334
|
name: ${t}-branding
|
|
2320
2335
|
description: Brand profile management. Extract branding from websites, manage saved brands, apply consistent styling to presentations.
|
|
2321
2336
|
---
|
|
@@ -2425,7 +2440,7 @@ ${e} branding set-default abc123
|
|
|
2425
2440
|
2. **If extraction fails** \u2014 Proceed without branding. Do not manually create brand assets.
|
|
2426
2441
|
3. **Set default** \u2014 If you mostly work with one brand, set it as default.
|
|
2427
2442
|
4. **Override** \u2014 Use \`--brand\` flag to override default for specific presentations.
|
|
2428
|
-
`}function
|
|
2443
|
+
`}function je(n){let{name:t,cmd:e}=n,o=t.toUpperCase().replace(/[^A-Z0-9]/g,"_");return`---
|
|
2429
2444
|
name: ${t}-config
|
|
2430
2445
|
description: CLI configuration management. Set API keys, team IDs, custom API URLs. Verify authentication status.
|
|
2431
2446
|
---
|
|
@@ -2586,7 +2601,7 @@ ${e} config show --verify # Test API key
|
|
|
2586
2601
|
\`\`\`bash
|
|
2587
2602
|
${e} config set team-id <correct-team-id>
|
|
2588
2603
|
\`\`\`
|
|
2589
|
-
`}var
|
|
2604
|
+
`}var hn={name:"video-ref-website-assets",description:"Extract maximum assets from websites for video production.",render:n=>`---
|
|
2590
2605
|
name: ${n.name}-video-ref-website-assets
|
|
2591
2606
|
description: Extract maximum assets from websites for video production.
|
|
2592
2607
|
---
|
|
@@ -2657,7 +2672,7 @@ agent-browser screenshot --path ./screenshots/hero.png
|
|
|
2657
2672
|
**Images 403/404** - may need referrer header: \`curl -e <site-url> -O <image-url>\`
|
|
2658
2673
|
|
|
2659
2674
|
**Lazy-loaded images** - use agent-browser to scroll and capture, or inspect network tab for actual URLs.
|
|
2660
|
-
`};var
|
|
2675
|
+
`};var yn={name:"video-ref-brief-guide",description:"How to write video brief for server-side plan generation.",render:n=>`---
|
|
2661
2676
|
name: ${n.name}-video-ref-brief-guide
|
|
2662
2677
|
description: How to write video brief for server-side plan generation.
|
|
2663
2678
|
---
|
|
@@ -2718,7 +2733,7 @@ These will be rebuilt as lightweight animated versions for Remotion. Focus on vi
|
|
|
2718
2733
|
---
|
|
2719
2734
|
|
|
2720
2735
|
**IMPORTANT:** The brief contains ONLY the 6 sections above. Do NOT add "Suggested Scenes", "Scene Breakdown", or any other sections \u2014 scene planning happens server-side via \`video generate plan\`.
|
|
2721
|
-
`};var
|
|
2736
|
+
`};var bn={name:"video-ref-source-scraping",description:"Extract content from various sources (YouTube, websites, Twitter).",render:n=>`---
|
|
2722
2737
|
name: ${n.name}-video-ref-source-scraping
|
|
2723
2738
|
description: Extract content from various sources (YouTube, websites, Twitter).
|
|
2724
2739
|
---
|
|
@@ -2754,19 +2769,19 @@ Extracts: tweet text, author info, media URLs
|
|
|
2754
2769
|
---
|
|
2755
2770
|
|
|
2756
2771
|
All scraped content is returned in markdown format.
|
|
2757
|
-
`};import{mkdirSync as
|
|
2772
|
+
`};import{mkdirSync as Rt,writeFileSync as $t,existsSync as Ve,rmSync as gr}from"fs";import{join as X,resolve as Se,relative as ts,basename as fr}from"path";import{homedir as At}from"os";var ce=[{name:"Claude Code",dir:".claude",provider:"claude"},{name:"GitHub Copilot",dir:".github",agentSuffix:".agent.md",provider:"copilot"},{name:"Cursor",dir:".cursor"},{name:"Codex",dir:".codex",agentSuffix:".toml",provider:"codex"},{name:"OpenCode",dir:".opencode"},{name:"Windsurf",dir:".windsurf"},{name:"Agent",dir:".agent"}];var ns={sonnet:"claude-sonnet-4.6",haiku:"claude-haiku-4.5",opus:"claude-opus-4.6"},os=["permissionMode","skills","subagentType"];function rs(n){let t=n.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(!t)return`developer_instructions = """
|
|
2758
2773
|
${n.replace(/"""/g,'\\"\\"\\"').trim()}
|
|
2759
2774
|
"""
|
|
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")??"",
|
|
2761
|
-
${
|
|
2775
|
+
`;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 = """
|
|
2776
|
+
${s}
|
|
2762
2777
|
"""`].join(`
|
|
2763
2778
|
`)+`
|
|
2764
|
-
`}function
|
|
2779
|
+
`}function vn(n,t){if(t==="codex")return rs(n);if(t!=="copilot")return n;let e=n.match(/^---\n([\s\S]*?)\n---\n/);if(!e)return ur(n);let o=e[1],r=n.slice(e.index+e[0].length);o=o.replace(/^(model:\s*)(\S+)([ \t]*)$/m,(a,s,l,d)=>`${s}${ns[l]??l}${d}`);for(let a of os)o=o.replace(new RegExp(`^${a}:[^
|
|
2765
2780
|
]*
|
|
2766
|
-
?`,"m"),"");o=o.replace(/\n+$/,"");let i=
|
|
2781
|
+
?`,"m"),"");o=o.replace(/\n+$/,"");let i=ur(r);return`---
|
|
2767
2782
|
${o}
|
|
2768
2783
|
---
|
|
2769
|
-
${i}`}function
|
|
2784
|
+
${i}`}function ur(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 is(n,t){let e=Se(n),o=Se(n,t);if(ts(e,o).startsWith("..")||Se(o)!==o.replace(/\.\./g,""))throw new Error(`Invalid path: "${t}" would escape base directory`);return o}function pr(n,t,e,o){let r=X(n,"SKILL.md");if(Rt(n,{recursive:!0}),$t(r,vn(t,o),"utf-8"),e&&e.length>0){let i=X(n,"references");Rt(i,{recursive:!0});for(let a of e){let s=X(i,`${a.name}.md`);$t(s,a.content,"utf-8")}}}function Et(n,t,e={},o){let r={installed:[],skipped:[],errors:[]},i=e.local?process.cwd():At();if(e.dir){let a=fr(Se(e.dir)),s=ce.find(l=>l.dir===a)?.provider;try{let l=Se(e.dir),d=is(l,X("skills",n));pr(d,t,o,s),r.installed.push(e.dir)}catch(l){r.errors.push(`${e.dir}: ${l instanceof Error?l.message:String(l)}`)}}else for(let a of ce){let s=X(i,a.dir),l=X(s,"skills",n),d=X(l,"SKILL.md");if(Ve(s)){if(Ve(d)&&!e.force){r.skipped.push(a.name);continue}try{pr(l,t,o,a.provider),r.installed.push(a.name)}catch(f){r.errors.push(`${a.name}: ${f instanceof Error?f.message:String(f)}`)}}}return r}function Ot(n,t={}){let e={removed:[],errors:[]},o=t.local?process.cwd():At();for(let r of ce){let i=X(o,r.dir,"skills",n);if(Ve(i))try{gr(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 hr(){return ce.map(n=>n.name)}function yr(n,t,e={}){let o={installed:[],skipped:[],errors:[]};if(e.dir){let a=fr(Se(e.dir)),s=ce.find(b=>b.dir===a),l=s?.agentSuffix??".md",d=X(Se(e.dir),"agents"),f=X(d,`${n}${l}`);if(Ve(f)&&!e.force)o.skipped.push(e.dir);else try{Rt(d,{recursive:!0}),$t(f,vn(t,s?.provider),"utf-8"),o.installed.push(e.dir)}catch(b){o.errors.push(`${e.dir}: ${b instanceof Error?b.message:String(b)}`)}return o}let r=At(),i=ce.filter(a=>a.dir===".claude"||a.dir===".github"||a.dir===".codex");for(let a of i){let s=a.agentSuffix??".md",l=X(r,a.dir,"agents"),d=X(l,`${n}${s}`);if(Ve(d)&&!e.force){o.skipped.push(a.name);continue}try{Rt(l,{recursive:!0}),$t(d,vn(t,a.provider),"utf-8"),o.installed.push(a.name)}catch(f){o.errors.push(`${a.name}: ${f instanceof Error?f.message:String(f)}`)}}return o}function br(n){let t={removed:[],errors:[]},e=At(),o=ce.filter(r=>r.dir===".claude"||r.dir===".github"||r.dir===".codex");for(let r of o){let i=r.agentSuffix??".md",a=X(e,r.dir,"agents",`${n}${i}`);if(Ve(a))try{gr(a),t.removed.push(r.name)}catch(s){t.errors.push(`${r.name}: ${s instanceof Error?s.message:String(s)}`)}}return t}function xn(){return`---
|
|
2770
2785
|
name: video-scene-reviewer
|
|
2771
2786
|
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
2787
|
tools: Read, Glob
|
|
@@ -2863,7 +2878,7 @@ Priority fixes:
|
|
|
2863
2878
|
- Scene under 80 lines with 5+ seconds duration = flag as too simple
|
|
2864
2879
|
- Be specific in fixes: exact icon name, exact component, exact file
|
|
2865
2880
|
- 85% pass rate minimum. Below = not ready for render
|
|
2866
|
-
`}function
|
|
2881
|
+
`}function wn(){return`---
|
|
2867
2882
|
name: video-scene-builder
|
|
2868
2883
|
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
2884
|
tools: Read, Write, Edit, Glob, Grep, Task, Bash
|
|
@@ -3046,7 +3061,7 @@ function AnimatedCamera() {
|
|
|
3046
3061
|
- Don't download assets \u2014 the main AI already did that
|
|
3047
3062
|
- Don't run render commands \u2014 the main AI handles that
|
|
3048
3063
|
- Don't modify video-plan.md \u2014 it's read-only to you
|
|
3049
|
-
`}function
|
|
3064
|
+
`}function Sn(n){return`---
|
|
3050
3065
|
name: video-audio-director
|
|
3051
3066
|
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
3067
|
tools: Read, Bash, Write
|
|
@@ -3206,7 +3221,7 @@ This saves money and time \u2014 generation is expensive, downloading is free.
|
|
|
3206
3221
|
- Don't choose voices \u2014 use the voice from your input
|
|
3207
3222
|
- Don't skip the timing manifest \u2014 it's the critical handoff to scene builders
|
|
3208
3223
|
- Don't re-generate audio if it was already generated successfully (see Error Handling above)
|
|
3209
|
-
`}function
|
|
3224
|
+
`}function Cn(){return`---
|
|
3210
3225
|
name: video-continuity-editor
|
|
3211
3226
|
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
3227
|
tools: Read, Glob, Grep
|
|
@@ -3317,7 +3332,7 @@ FIXES:
|
|
|
3317
3332
|
- Focus on CROSS-SCENE issues. Per-scene quality is the reviewer's job.
|
|
3318
3333
|
- Be specific in fixes: exact file, exact line, exact component.
|
|
3319
3334
|
- 85% pass rate minimum.
|
|
3320
|
-
`}function
|
|
3335
|
+
`}function In(n){let t=n?.cmd??"mf";return`---
|
|
3321
3336
|
name: video-branding-director
|
|
3322
3337
|
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
3338
|
tools: Read, Bash, Write
|
|
@@ -3420,7 +3435,7 @@ Query: <what was searched/extracted>
|
|
|
3420
3435
|
- Download logos or images from websites directly (only from branding.json URLs after successful extraction)
|
|
3421
3436
|
- Create or edit branding.json by hand
|
|
3422
3437
|
- Ask the user questions \u2014 return failure to the orchestrator instead
|
|
3423
|
-
`}function
|
|
3438
|
+
`}function vr(n){return`---
|
|
3424
3439
|
name: remotion-scene-craft
|
|
3425
3440
|
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
3441
|
---
|
|
@@ -3695,7 +3710,7 @@ const glow = interpolate(Math.sin(frame / fps * Math.PI * 2 / 2), [-1, 1], [0.1,
|
|
|
3695
3710
|
- Static scenes with no visual change for 2+ seconds -> Every 2s needs a visual event.
|
|
3696
3711
|
- Generic component substitution -> Plan says WhipPan, use WhipPan. Not slide() or wipe().
|
|
3697
3712
|
- 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
|
|
3713
|
+
`}var et=["main","video","presentation","presentation-edit","tts","music","sfx","mix","image","video-search","scrape","branding","config"],Pt=["standalone","studio"],xr={cmd:u.commands[0],pkg:u.packageName,url:u.apiUrl,name:u.name},qe=new as("skill").description(`Manage ${u.displayName} skills for AI coding assistants`).addHelpText("after",`
|
|
3699
3714
|
${N.bold("Skill Types:")}
|
|
3700
3715
|
${N.cyan("main")} Main CLI skill with all capabilities overview
|
|
3701
3716
|
${N.cyan("video")} Detailed video creation workflow with Remotion/R3F patterns
|
|
@@ -3715,64 +3730,67 @@ ${N.bold("Reference Skills:")}
|
|
|
3715
3730
|
|
|
3716
3731
|
${N.bold("Examples:")}
|
|
3717
3732
|
${N.gray("# Install main CLI skill (comprehensive overview)")}
|
|
3718
|
-
$ ${
|
|
3733
|
+
$ ${u.commands[0]} skill install main
|
|
3719
3734
|
|
|
3720
3735
|
${N.gray("# Install video skill")}
|
|
3721
|
-
$ ${
|
|
3736
|
+
$ ${u.commands[0]} skill install video
|
|
3722
3737
|
|
|
3723
3738
|
${N.gray("# Install presentation skill")}
|
|
3724
|
-
$ ${
|
|
3739
|
+
$ ${u.commands[0]} skill install presentation
|
|
3725
3740
|
|
|
3726
3741
|
${N.gray("# Install all skills")}
|
|
3727
|
-
$ ${
|
|
3742
|
+
$ ${u.commands[0]} skill install
|
|
3728
3743
|
|
|
3729
3744
|
${N.gray("# Install to specific directory")}
|
|
3730
|
-
$ ${
|
|
3745
|
+
$ ${u.commands[0]} skill install main --dir ~/.claude
|
|
3731
3746
|
|
|
3732
3747
|
${N.gray("# Show skill content")}
|
|
3733
|
-
$ ${
|
|
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
|
-
`)
|
|
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";
|
|
3748
|
+
$ ${u.commands[0]} skill show main
|
|
3749
|
+
`);qe.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&&!Pt.includes(t.mode)&&(c(`Invalid mode: ${t.mode}. Must be one of: ${Pt.join(", ")}`),process.exit(1));let e={...xr,mode:t.mode},o=[];n&&!et.includes(n)&&(c(`Invalid skill type: ${n}. Must be one of: ${et.join(", ")}`),process.exit(1));let r=[{name:"tts",content:Pe(e)},{name:"music",content:De(e)},{name:"sfx",content:Ne(e)},{name:"mix",content:Fe(e)},{name:"image",content:Le(e)},{name:"video-search",content:Ue(e)},{name:"scrape",content:_e(e)},{name:"branding",content:Me(e)},{name:"config",content:je(e)}];(!n||n==="main")&&o.push({name:u.name,content:Ct(e),references:r});let i=[{name:"brief-guide",content:yn.render(e)},{name:"website-assets",content:hn.render(e)},{name:"source-scraping",content:bn.render(e)}];(!n||n==="video")&&(o.push({name:`${u.name}-video`,content:It(e),references:i}),o.push({name:"remotion-scene-craft",content:vr(e)})),(!n||n==="presentation")&&o.push({name:`${u.name}-presentation`,content:Tt(e)}),(!n||n==="presentation-edit")&&o.push({name:`${u.name}-presentation-edit`,content:kt(e)}),n==="tts"&&o.push({name:`${u.name}-tts`,content:Pe(e)}),n==="music"&&o.push({name:`${u.name}-music`,content:De(e)}),n==="sfx"&&o.push({name:`${u.name}-sfx`,content:Ne(e)}),n==="mix"&&o.push({name:`${u.name}-mix`,content:Fe(e)}),n==="image"&&o.push({name:`${u.name}-image`,content:Le(e)}),n==="video-search"&&o.push({name:`${u.name}-video-search`,content:Ue(e)}),n==="scrape"&&o.push({name:`${u.name}-scrape`,content:_e(e)}),n==="branding"&&o.push({name:`${u.name}-branding`,content:Me(e)}),n==="config"&&o.push({name:`${u.name}-config`,content:je(e)}),console.log();for(let a of o){m(`Installing ${a.name}...`);let s=Et(a.name,a.content,{dir:t.dir,local:t.local,force:t.force},a.references);if(s.installed.length>0&&(C(`${a.name} installed successfully`),I(" Installed to",s.installed.join(", "))),s.skipped.length>0&&(m(` Skipped (already exists): ${s.skipped.join(", ")}`),console.log(N.gray(" Use --force to overwrite"))),s.errors.length>0)for(let l of s.errors)c(` ${l}`);s.installed.length===0&&s.skipped.length===0&&s.errors.length===0&&(m(" No supported AI coding assistants detected"),console.log(N.gray(" Supported editors: "+hr().join(", "))),console.log(N.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:()=>In(e)},{name:"video-scene-builder",generate:wn},{name:"video-scene-reviewer",generate:xn},{name:"video-audio-director",generate:()=>Sn(e)},{name:"video-continuity-editor",generate:Cn}]){m(`Installing ${a.name} agent...`);let s=yr(a.name,a.generate(),{force:t.force,dir:t.dir});if(s.installed.length>0){C(`${a.name} agent installed`);let l={"Claude Code":"~/.claude/agents/","GitHub Copilot":"~/.github/agents/"};I(" Installed to",s.installed.map(d=>t.dir?d:`${d} (${l[d]??"~/.<editor>/agents/"})`).join(", "))}s.skipped.length>0&&m(` Agent skipped (already exists): ${s.skipped.join(", ")}`)}console.log()}});qe.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&&!Pt.includes(t.mode)&&(c(`Invalid mode: ${t.mode}. Must be one of: ${Pt.join(", ")}`),process.exit(1));let e={...xr,mode:t.mode},r={main:()=>Ct(e),video:()=>It(e),presentation:()=>Tt(e),"presentation-edit":()=>kt(e),tts:()=>Pe(e),music:()=>De(e),sfx:()=>Ne(e),mix:()=>Fe(e),image:()=>Le(e),"video-search":()=>Ue(e),scrape:()=>_e(e),branding:()=>Me(e),config:()=>je(e),"video-branding-director":()=>In(e),"video-scene-builder":()=>wn(),"video-scene-reviewer":()=>xn(),"video-audio-director":()=>Sn(e),"video-continuity-editor":()=>Cn()}[n];if(r)console.log(r());else{let i=[...et,"video-branding-director","video-scene-builder","video-scene-reviewer","video-audio-director","video-continuity-editor"];c(`Invalid skill type: ${n}. Must be one of: ${i.join(", ")}`),process.exit(1)}});qe.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&&!et.includes(n)&&(c(`Invalid skill type: ${n}. Must be one of: ${et.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=Ot(o,{local:t.local});if(r.removed.length>0?(C(`${o} uninstalled`),I(" Removed from",r.removed.join(", "))):m(` ${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"])br(o).removed.length>0&&C(`${o} agent uninstalled`);console.log()});import{Command as ss}from"commander";import tt from"chalk";var wr=new ss("templates").description("List slide design templates (use with `create --template <id>`)").argument("[search]","Filter templates by name, description, or category").option("-f, --format <format>","Output format (table, json)","table").option("--limit <n>","Maximum templates to list","25").action(async(n,t)=>{await E();try{let e=Number.parseInt(t.limit??"25",10),{templates:o}=await uo(n,Number.isFinite(e)?e:25);if(o.length===0){t.format==="json"?console.log(JSON.stringify([])):m("No templates found");return}if(t.format==="json"){console.log(JSON.stringify(o,null,2));return}for(let r of o){let i=[r.isDefault?tt.green("default"):null,r.category??null,r.recommendedModes?.length?`modes: ${r.recommendedModes.join("/")}`:null].filter(Boolean).join(" \xB7 ");console.log(`${tt.bold(r.name)} ${tt.gray(r.id)}${i?`
|
|
3750
|
+
${tt.gray(i)}`:""}`)}console.log(),console.log(tt.gray(`Use one with: ${u.commands[0]} create "<topic>" --template <id>`))}catch(e){c(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}});import{Command as cs}from"commander";import Tn from"chalk";var Sr=new cs("whoami").description("Show current user and team information").option("-f, --format <format>","Output format (human, json)","human").action(async n=>{await E();try{let t=await me();if(an(),n.format==="json"){console.log(JSON.stringify(t,null,2));return}se("User"),console.log(),I("Email",t.user.email),t.user.username&&I("Username",t.user.username),(t.user.firstName||t.user.lastName)&&I("Name",[t.user.firstName,t.user.lastName].filter(Boolean).join(" "));let e=t.authType==="apiKey"?"API Key":t.authType==="oauth"?"OAuth":"Session";if(I("Auth Type",e),t.currentTeam&&(console.log(),se("Current Team"),console.log(),I("ID",t.currentTeam.id),I("Name",t.currentTeam.name),I("Plan",t.currentTeam.planName),I("Role",t.currentTeam.isOwner?"Owner":"Member")),t.teams.length>1){console.log(),se("All Teams"),console.log();for(let o of t.teams){let r=o.isCurrent?Tn.green(" (current)"):"";console.log(` ${Tn.bold(o.name)}${r}`),console.log(Tn.gray(` ID: ${o.id} | Plan: ${o.planName} | Role: ${o.role}`))}}console.log()}catch(t){c(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}});function Cr(n){return n[0]==="--"?n.slice(1):n}import{Command as kn}from"commander";function ls(n,t){return[...t,n]}var ds=new kn("create").description("Start durable ad-set generation").argument("<title>","Ad-set title").requiredOption("--brief <brief>","Campaign brief").option("--hook <text>","Opening hook (repeat)",ls,[]).option("--style <style>","ugc, clean, cinematic, or testimonial","ugc").option("--branding-id <id>","Branding ID").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(n,t)=>{if(!t.yes)return c("Pass --yes to approve generation");try{x(await R("createAdSet",{approvalReceipt:"cli:--yes",brandingId:t.brandingId,brief:t.brief,hooks:t.hook.length?t.hook:[t.brief],style:t.style,teamId:t.teamId,title:n}))}catch(e){c(e instanceof Error?e.message:"Generation failed"),process.exit(p.GENERAL_ERROR)}}),ms=new kn("status").description("Read ad-set generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(n,t)=>{try{x(await F("createAdSet",n,t.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(p.GENERAL_ERROR)}}),Ir=new kn("ad-set").description("Ad set commands").addCommand(ds).addCommand(ms);import{Command as kr}from"commander";function Tr(n){return new kr(n).description(n==="create"?"Create and activate a scheduled agent":"Create a reviewable agent recommendation").argument("<name>","Agent name").requiredOption("--instructions <markdown>","Agent instructions").option("--description <text>","Agent description","").option("--schedule <frequency>","manual, daily, weekdays, weekly, or monthly","weekly").option("--time <hh:mm>","Local run time","09:00").option("--timezone <zone>","IANA timezone","UTC").option("--output <adapter>","Output adapter","digest").option("--team-id <id>","Workspace ID").option("--yes","Approve saving the agent").action(async(t,e)=>{if(!e.yes)return c("Pass --yes to approve this operation");try{x(await R(n==="create"?"createAgent":"recommendAgent",{approvalReceipt:"cli:--yes",description:e.description,instructionsMarkdown:e.instructions,name:t,output:e.output,schedule:e.schedule,scheduleTime:e.time,teamId:e.teamId,timezone:e.timezone}))}catch(o){c(o instanceof Error?o.message:"Agent operation failed"),process.exit(p.GENERAL_ERROR)}})}var Rr=new kr("agent").description("Scheduled agent commands").addCommand(Tr("create")).addCommand(Tr("recommend"));import{writeFile as $r}from"fs/promises";import G from"chalk";import{Command as ne}from"commander";import us from"ora";var Ar=new ne("branding").description("Manage brand profiles").addCommand(new ne("list").description("List brand profiles").option("-f, --format <format>","Output format (table, json)","table").action(async n=>{await E();try{let t=await Qt();if(t.brandings.length===0){n.format==="json"?console.log(JSON.stringify([])):(m("No brand profiles found"),console.log(),console.log(G.gray(`Create one with: ${u.commands[0]} branding extract <url>`)));return}n.format==="json"?console.log(JSON.stringify(t.brandings,null,2)):console.log(Ao(t.brandings))}catch(t){c(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}})).addCommand(new ne("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 E();try{let e=await po(n);if(t.output){await $r(t.output,JSON.stringify(e,null,2)),C(`Brand profile saved to ${t.output}`);return}if(t.format==="json")console.log(JSON.stringify(e,null,2));else{if(se("Brand Profile"),console.log(),I("ID",e.id),I("Name",e.name),I("Source URL",e.sourceUrl??G.gray("None")),I("Default",e.isDefault?G.green("Yes"):"No"),e.createdAt&&I("Created",new Date(e.createdAt).toLocaleString()),console.log(),e.primaryColor||e.colors.length>0){if(console.log(G.bold(" Colors")),e.primaryColor){let r=G.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=G.bgHex(r.hex)(" "),a=r.role?G.gray(` (${r.role})`):"";console.log(` ${i} ${r.hex}${a}`)}}console.log()}e.logoUrl&&(console.log(G.bold(" Logo")),console.log(` ${e.logoUrl}`),console.log());let o=e.typography;o&&Object.keys(o).length>0&&(console.log(G.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(G.bold(" Extraction")),e.confidence&&console.log(` Confidence: ${Math.round(e.confidence*100)}%`),e.extractionMethod&&console.log(` Method: ${e.extractionMethod}`),console.log()),console.log(G.gray(" Use --format json for full details")),console.log()}}catch(e){c(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}})).addCommand(new ne("find").description("Find existing brand profile by name or URL").argument("<query>","Brand name or website URL to search for").action(async n=>{await E();try{let t=await Qt(),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){m(`No brand profiles matching "${n}"`),console.log(G.gray(` Extract one with: ${u.commands[0]} branding extract <url>`));return}console.log(`Found ${o.length} brand${o.length>1?"s":""}:
|
|
3751
|
+
`);for(let r of o){let i=r.primaryColor?`${G.bgHex(r.primaryColor)(" ")} ${r.primaryColor}`:"";console.log(` ${G.bold(r.name)} ${G.gray(r.id)}`),r.sourceUrl&&console.log(` ${G.gray(r.sourceUrl)}`),i&&console.log(` ${i}`),console.log()}console.log(G.gray(` Export with: ${u.commands[0]} branding get <id> -o branding.json`))}catch(t){c(t instanceof Error?t.message:String(t)),process.exit(t.exitCode??1)}})).addCommand(new ne("extract").description("Extract brand profile from a website").argument("<url>","Website URL to extract branding from").option("--team-id <id>","Team ID").option("--yes","Confirm starting a paid/external extraction").option("--no-save","Extract without saving").option("-o, --output <path>","Save JSON to file").action(async(n,t)=>{await E(),t.yes||(c("Pass --yes to confirm brand extraction."),process.exit(p.INVALID_INPUT));try{new URL(n.startsWith("http")?n:`https://${n}`)}catch{c("Invalid URL format"),process.exit(6)}let e=n.startsWith("http")?n:`https://${n}`,o=t.teamId??at(),r=us({text:`Extracting branding from ${e}...`,stream:process.stdout}).start();try{let i=await go(e,o,"cli:--yes");r.succeed("Brand extraction started");let a=JSON.stringify(i,null,2);t.output?(await $r(t.output,a),C(`Brand profile saved to ${t.output}`)):console.log(a),m(`Check progress with: ${u.commands[0]} branding status ${i.runId}`),console.log()}catch(i){r.fail("Extraction failed"),c(i instanceof Error?i.message:String(i)),process.exit(i.exitCode??1)}})).addCommand(new ne("status").description("Check a brand extraction run").argument("<run-id>","Run ID returned by branding extract").option("--team-id <id>","Workspace ID").action(async(n,t)=>{try{x(await F("extractBranding",n,t.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(p.GENERAL_ERROR)}})).addCommand(new ne("set-default").description("Set a brand profile as default").argument("<id>","Brand profile ID").action(async n=>{await E(),m(`To set brand ${n} as default, use the web dashboard.`),console.log(),console.log(G.gray("API support for setting default brand is coming soon."))})).addCommand(new ne("competitor").description("Brand competitor commands").addCommand(new ne("list").description("List competitors for a brand").option("--branding-id <id>","Brand ID").option("--team-id <id>","Workspace ID").action(async n=>{try{console.log(JSON.stringify(await R("getBrandCompetitors",{brandingId:n.brandingId,teamId:n.teamId}),null,2))}catch(t){c(t instanceof Error?t.message:"Lookup failed"),process.exit(1)}})).addCommand(new ne("add").description("Add or update a brand competitor").argument("<name>","Competitor name").option("--branding-id <id>","Brand ID").option("--team-id <id>","Workspace ID").option("--website <url>","Competitor website").option("--x-handle <handle>","Competitor X handle").option("--yes","Confirm writing brand data").action(async(n,t)=>{t.yes||(c("Pass --yes to confirm adding a competitor."),process.exit(p.INVALID_INPUT));try{x(await R("addCompetitor",{approvalReceipt:"cli:--yes",brandingId:t.brandingId,name:n,teamId:t.teamId,website:t.website,xHandle:t.xHandle}))}catch(e){c(e instanceof Error?e.message:"Write failed"),process.exit(p.GENERAL_ERROR)}}))).addCommand(new ne("social").description("Brand social handle commands").addCommand(new ne("add").description("Add or update a brand social handle").argument("<platform>","Social platform").argument("<handle>","Account handle").option("--branding-id <id>","Brand ID").option("--team-id <id>","Workspace ID").option("--yes","Confirm writing brand data").action(async(n,t,e)=>{e.yes||(c("Pass --yes to confirm adding a social handle."),process.exit(p.INVALID_INPUT));try{x(await R("addBrandSocialHandle",{approvalReceipt:"cli:--yes",brandingId:e.brandingId,handle:t,platform:n,teamId:e.teamId}))}catch(o){c(o instanceof Error?o.message:"Write failed"),process.exit(p.GENERAL_ERROR)}})));import{readFile as ps}from"fs/promises";import{Command as Er}from"commander";var gs=new Er("extract").description("Extract normalized text from a URL or local file").argument("<source>","URL, encoded source, or local file path").option("--team-id <id>","Workspace ID").option("--mime-type <type>","Source MIME type").option("--max-length <count>","Maximum output characters","30000").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{try{let e=n,o;n.includes("://")||(e=await ps(n,"utf8"),o=n);let r=await R("extractContent",{filename:o,maxLength:Number.parseInt(t.maxLength,10),mimeType:t.mimeType,source:e,teamId:t.teamId});t.format!=="quiet"&&x(r)}catch(e){c(e instanceof Error?e.message:"Extraction failed"),process.exit(p.GENERAL_ERROR)}}),Or=new Er("content").description("Content extraction commands").addCommand(gs);import Y from"chalk";import{Command as fs}from"commander";import{existsSync as hs,readFileSync as ys}from"fs";import bs,{resolve as Pr}from"path";var Dr=new fs("create").description("Create a new presentation").argument("<topic>","The topic or title for the presentation").option("-n, --slides <count>","Number of slides (1-20)").option("-m, --mode <mode>","Generation quality (best, balanced, fast, ultrafast, instant, image-min, image, image-max) \u2014 default: fast. image-min/image/image-max render each slide as a full-bleed AI image (text not editable); slower + pricier, require image-mode access, and cap at 25 slides. image-min is cheapest (brand colors only, no exact fonts).").option("--image-tier <tier>","Embedded-image quality for HTML modes: smart (default, auto-routes per image), fast (cheapest, no extra credits), balanced (+50 credits/slide), best (premium, +200 credits/slide, slow). Ignored for image-*/instant modes.").option("-t, --tone <tone>","Tone (creative, professional, educational, formal, casual)").option("--amount <amount>","Content density (minimal, concise, detailed, extensive)").option("--audience <text>","Target audience description").option("-l, --language <lang>","Output language").option("--branding-id <id>","Branding ID (from `ccr branding list` or `ccr branding extract`)").option("--brand-domain <url>","Brand the deck by website/domain (e.g. https://www.pfizer.com). Errors if no matching saved brand exists.").option("--template <id>","Slide template ID to style the deck after (from `ccr templates`). A default template is applied automatically when omitted.").option("-c, --context <text>","Inline text context (research notes, key facts)").option("--context-file <path>","Path to a context file (text, markdown, JSON)").option("--stdin","Read context from stdin").option("-f, --file <paths...>","Files to upload (PDF, PPTX, DOCX, images)").option("-g, --goal <type>","Goal (inform, persuade, train, learn, entertain, report)").option("--styling <mode>","Styling mode (freeform, brand-only, brand-plus-style, style-only, no-styling)").option("--reference-url <url>","Image URL to use as visual style reference").option("--thinking-depth <depth>","AI thinking depth (quick, moderate, deep, profound)").option("--theme <preset>","[instant mode only] Color theme preset (blue, violet, rose, orange, green)").option("--primary-color <hex>","[instant mode only] Primary color (e.g., #0066CC)").option("--secondary-color <hex>","[instant mode only] Secondary color").option("--accent-color <hex>","[instant mode only] Accent color").option("--background-color <hex>","[instant mode only] Background color").option("--foreground-color <hex>","[instant mode only] Foreground/text color").option("--decorations <style>","[instant mode only] Background decoration (none, waves-bottom-left, waves-top-right, blob-corners, minimal)").option("--team-id <id>","Team ID (switch teams)").option("-o, --output <format>","Output format (human, json, quiet)").option("--no-stream","Wait for completion without streaming progress").option("--wait","Poll until generation completes").option("--debug","Enable debug logging").option("--open","Open in browser after creation").option("--id <uuid>","Use a specific UUID for the presentation").option("--studio","Studio mode: use current directory name as presentation ID (auto-links to Studio preview)").action(async(n,t)=>{await E();let e;t.slides!==void 0&&(e=parseInt(t.slides,10),(Number.isNaN(e)||e<1||e>20)&&(c("Slide count must be between 1 and 20"),process.exit(6)));let o=["best","balanced","fast","ultrafast","instant","image-min","image","image-max"];t.mode&&!o.includes(t.mode)&&(c(`Invalid mode: ${t.mode}. Valid: ${o.join(", ")}`),process.exit(6));let r=["smart","fast","balanced","best"];t.imageTier&&!r.includes(t.imageTier)&&(c(`Invalid image tier: ${t.imageTier}. Valid: ${r.join(", ")}`),process.exit(6));let i=["creative","professional","educational","formal","casual"];t.tone&&!i.includes(t.tone)&&(c(`Invalid tone: ${t.tone}. Valid: ${i.join(", ")}`),process.exit(6));let a=["minimal","concise","detailed","extensive"];t.amount&&!a.includes(t.amount)&&(c(`Invalid amount: ${t.amount}. Valid: ${a.join(", ")}`),process.exit(6));let s=["freeform","brand-only","brand-plus-style","style-only","no-styling"];t.styling&&!s.includes(t.styling)&&(c(`Invalid styling: ${t.styling}. Valid: ${s.join(", ")}`),process.exit(6));let l=["quick","moderate","deep","profound"];t.thinkingDepth&&!l.includes(t.thinkingDepth)&&(c(`Invalid thinking-depth: ${t.thinkingDepth}. Valid: ${l.join(", ")}`),process.exit(6));let d=["inform","persuade","train","learn","entertain","report"];t.goal&&!d.includes(t.goal)&&(c(`Invalid goal: ${t.goal}. Valid: ${d.join(", ")}`),process.exit(6));let f=["blue","violet","rose","orange","green"];t.theme&&!f.includes(t.theme)&&(c(`Invalid theme: ${t.theme}. Valid: ${f.join(", ")}`),process.exit(6));let b=["none","waves-bottom-left","waves-top-right","blob-corners","minimal"];t.decorations&&!b.includes(t.decorations)&&(c(`Invalid decorations: ${t.decorations}. Valid: ${b.join(", ")}`),process.exit(6));let v=t.theme||t.primaryColor||t.secondaryColor||t.accentColor||t.backgroundColor||t.foregroundColor||t.decorations;v&&t.mode&&t.mode!=="instant"&&(c("--theme, --primary-color, --decorations and other color options are only supported with --mode instant"),process.exit(6));let g=t.mode??(v?"instant":"fast"),y=/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;for(let[S,U]of[["primary-color",t.primaryColor],["secondary-color",t.secondaryColor],["accent-color",t.accentColor],["background-color",t.backgroundColor],["foreground-color",t.foregroundColor]])U&&!y.test(U)&&(c(`Invalid ${S}: ${U}. Must be hex (e.g., #0066CC)`),process.exit(6));try{t.output!=="json"&&t.output!=="quiet"&&process.stdout.write(Y.gray("Checking generation limits... "));let S=await yo(g,e??10,t.teamId);if(t.output!=="json"&&t.output!=="quiet"){console.log(Y.green("\u2713"));let U=S.remaining[g],_=S.limits[g],Z=U===void 0||_===void 0?"":` | ${g}: ${U}/${_} remaining`;console.log(Y.gray(` Plan: ${S.planName}${Z}`))}}catch(S){t.output==="json"?console.log(JSON.stringify({success:!1,error:S instanceof Error?S.message:String(S)})):(console.log(Y.red("\u2717")),c(S instanceof Error?S.message:String(S))),process.exit(S.exitCode??1)}let k=[];if(t.file&&t.file.length>0){for(let S of t.file)hs(Pr(S))||(c(`File not found: ${S}`),process.exit(6));t.output!=="json"&&t.output!=="quiet"&&console.log(Y.gray(`
|
|
3752
|
+
Uploading ${t.file.length} file(s)...`));try{k=await io(t.file.map(S=>Pr(S)),(S,U,_)=>{t.output!=="json"&&t.output!=="quiet"&&_&&process.stdout.write(`\r ${Y.cyan("\u2B06")} Uploading: ${_} (${S+1}/${U})`)}),t.output!=="json"&&t.output!=="quiet"&&console.log(`\r ${Y.green("\u2713")} Uploaded ${k.length} file(s) `)}catch(S){c(`Failed to upload files: ${S instanceof Error?S.message:String(S)}`),process.exit(1)}}let w;(t.stdin||!process.stdin.isTTY)&&(w=await vs(),t.stdin&&!w&&(c("No content received from stdin"),process.exit(6)));let $=t.context;if(t.contextFile)try{$=ys(t.contextFile,"utf-8"),$.trim()||(c(`Context file is empty: ${t.contextFile}`),process.exit(6))}catch{c(`Failed to read context file: ${t.contextFile}`),process.exit(6)}!w&&!$&&k.length===0&&(c("Context is required to create a presentation."),console.log(),console.log(Y.gray(" -f, --file <paths...> Upload files (PDF, PPTX, images)")),console.log(Y.gray(" -c, --context <text> Inline text context")),console.log(Y.gray(" --context-file <path> Read from a file")),console.log(Y.gray(` cat file | ${u.commands[0]} Pipe content`)),process.exit(6));let B=[...k];w&&B.push({id:`stdin-${Date.now()}`,content:w,title:"Piped Content",mime:"text/plain",selected:!0}),$&&B.push({id:`context-${Date.now()}`,content:$,title:"Context",mime:"text/plain",selected:!0});let L,H=t.primaryColor||t.secondaryColor||t.accentColor||t.backgroundColor||t.foregroundColor;(t.theme||H||t.decorations)&&(L={},t.theme&&(L.preset=t.theme),H&&(L.custom={},t.primaryColor&&(L.custom.primary=t.primaryColor),t.secondaryColor&&(L.custom.secondary=t.secondaryColor),t.accentColor&&(L.custom.accent=t.accentColor),t.backgroundColor&&(L.custom.background=t.backgroundColor),t.foregroundColor&&(L.custom.foreground=t.foregroundColor)),t.decorations&&(L.decorations=t.decorations));try{let S=await ao({topic:n,...e!==void 0&&{slideCount:e},mode:g,...t.imageTier&&{imageTier:t.imageTier},...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.brandDomain&&{brandDomain:t.brandDomain},...t.template&&{templateId:t.template},...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},...L&&{theme:L},...t.studio?{documentId:bs.basename(process.cwd())}:t.id?{documentId:t.id}:{},...B.length>0&&{contentSources:{uploadedFiles:B,contextFiles:[]}}});if(!t.wait){t.output==="json"?console.log(JSON.stringify({success:!0,run:S},null,2)):t.output!=="quiet"&&(C("Presentation generation queued"),I("Run ID",S.runId),I("Status",S.status),console.log(Y.gray(` Check later with presentation status ${S.runId}`)));return}let U=await F("createSlides",S.runId,t.teamId);for(;!U.done;)t.output!=="json"&&t.output!=="quiet"&&console.log(Y.gray(` ${U.message}`)),await new Promise(Z=>setTimeout(Z,(U.nextPollAfterSeconds??5)*1e3)),U=await F("createSlides",S.runId,t.teamId);if(U.error)throw new Error(U.error.message);let _=U.entity?await fe(U.entity.id):void 0;if(t.output==="json")console.log(JSON.stringify({success:!0,presentation:_,run:U,viewUrl:_?$e(_.slug,t.language??"en"):void 0},null,2));else{console.log(),C("Presentation created successfully"),console.log(),I("Title",_?.title??n),I("Slides",String(_?.numberOfSlides??e??"\u2014")),console.log();let Z=_?$e(_.slug,t.language??"en"):"N/A";Z!=="N/A"&&(console.log(Y.bold(" Open: ")+Y.cyan.underline(Z)),t.open&&await(await import("open")).default(Z)),console.log()}}catch(S){t.output==="json"?console.log(JSON.stringify({success:!1,error:S instanceof Error?S.message:String(S)})):c(S instanceof Error?S.message:String(S)),process.exit(S.exitCode??1)}});async function vs(){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 xs}from"commander";import Dt from"chalk";var Nr=new xs("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 E();try{let e=await fe(n);if(t.format==="json"){console.log(JSON.stringify(e,null,2));return}let o=$e(e.slug,t.language);se("Presentation Details"),console.log(),I("Slug",e.slug),I("Title",e.title||"Untitled"),I("Description",e.description||Dt.gray("None")),I("Slides",String(e.numberOfSlides||"-")),I("Mode",e.mode||"-"),I("Created",rn(e.createdAt)),e.updatedAt&&I("Updated",rn(e.updatedAt)),console.log(),o!=="N/A"&&console.log(Dt.bold(" Open: ")+Dt.cyan.underline(o)),console.log(),t.format==="full"&&t.include?.includes("slides")&&(console.log(Dt.gray("(Full slide content available in JSON format)")),console.log())}catch(e){c(e instanceof Error?e.message:String(e)),process.exit(e.exitCode??1)}});import{Command as Nt}from"commander";import ws from"ora";var Ss=new Nt("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"?ws("Searching for images...").start():null,o;n.maxResults&&(o=parseInt(n.maxResults,10),(Number.isNaN(o)||o<1)&&(e?.stop(),c("Max results must be a positive number"),process.exit(p.INVALID_INPUT)));try{let r=await ht({query:n.query,options:{maxResults:o||10,size:n.size,safeSearch:n.safeSearch}});e?.stop(),r.success||(c("Search failed"),process.exit(p.GENERAL_ERROR));let i=r.data.results.flatMap(a=>a.results.map(s=>({...s,provider:a.providerName})));if(t==="json"){x({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){m("No images found");return}C(`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()}m(`Total cost: $${r.data.totalCost.toFixed(4)}`)}catch(r){e?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),Cs=new Nt("generate").description("Start background image generation").argument("<prompt>","Image prompt").option("--provider <provider>","Provider override").option("--model <model>","Model override").option("--width <pixels>","Width").option("--height <pixels>","Height").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(n,t)=>{if(!t.yes)return c("Pass --yes to approve image generation");try{x(await R("createImage",{approvalReceipt:"cli:--yes",height:t.height?Number.parseInt(t.height,10):void 0,model:t.model,prompt:n,provider:t.provider,teamId:t.teamId,width:t.width?Number.parseInt(t.width,10):void 0}))}catch(e){c(e instanceof Error?e.message:"Generation failed"),process.exit(p.GENERAL_ERROR)}}),Is=new Nt("status").description("Read image generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(n,t)=>{try{x(await F("createImage",n,t.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(p.GENERAL_ERROR)}}),Fr=new Nt("image").description("Image search and generation commands").addCommand(Ss).addCommand(Cs).addCommand(Is);import{Command as Rn}from"commander";var Ts=new Rn("search").description("Search the workspace Knowledge Hub").argument("[query]","Optional search query").option("--team-id <id>","Workspace ID").option("--kind <kind>","Knowledge kind").option("--limit <count>","Maximum results","10").action(async(n,t)=>{try{x(await R("searchKnowledge",{kind:t.kind,limit:Number.parseInt(t.limit,10),query:n,teamId:t.teamId}))}catch(e){c(e instanceof Error?e.message:"Knowledge search failed"),process.exit(p.GENERAL_ERROR)}}),ks=new Rn("bundle").description("Read a bounded Open Knowledge Format bundle").option("--team-id <id>","Workspace ID").option("--kind <kind>","Knowledge kind").action(async n=>{try{x(await R("getKnowledgeBundle",{kind:n.kind,teamId:n.teamId}))}catch(t){c(t instanceof Error?t.message:"Knowledge bundle failed"),process.exit(p.GENERAL_ERROR)}}),Lr=new Rn("knowledge").description("Knowledge Hub commands").addCommand(Ts).addCommand(ks);import{Command as $n}from"commander";var Rs=new $n("create").description("Start background microsite generation").argument("<title>","Microsite title").requiredOption("--description <brief>","Microsite brief").option("--audience <audience>","Target audience").option("--tone <tone>","Tone").option("--language <language>","Content language","en").option("--branding-id <id>","Branding ID").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(n,t)=>{if(!t.yes)return c("Pass --yes to approve generation");try{x(await R("createMicrosite",{approvalReceipt:"cli:--yes",audience:t.audience,brandingId:t.brandingId,description:t.description,language:t.language,teamId:t.teamId,title:n,tone:t.tone}))}catch(e){c(e instanceof Error?e.message:"Generation failed"),process.exit(p.GENERAL_ERROR)}}),$s=new $n("status").description("Read microsite generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(n,t)=>{try{x(await F("createMicrosite",n,t.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(p.GENERAL_ERROR)}}),Ur=new $n("microsite").description("Microsite commands").addCommand(Rs).addCommand($s);import{Command as On}from"commander";import An from"ora";import{writeFile as As}from"fs/promises";function En(n,t){if(t==="json"){let{cost:e,...o}=n;x(o);return}if(t==="quiet"){n.outputUrl?console.log(n.outputUrl):console.log(n.requestId);return}m(`Request ID: ${n.requestId}`),m(`Status: ${n.status}`),n.duration&&m(`Duration: ${n.duration}s`),n.outputUrl&&C(`Output URL: ${n.outputUrl}`),n.cost!==void 0&&m(`Cost: $${n.cost.toFixed(4)}`),n.error&&c(`Error: ${n.error}`)}async function Es(n,t){let e=await fetch(n);if(!e.ok)throw new Error(`Failed to download: ${e.status}`);let o=await e.arrayBuffer();await As(t,Buffer.from(o))}var Os=new On("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&&(c("At least one of --music or --voice must be provided"),process.exit(p.INVALID_INPUT));let t=parseInt(n.musicVolume,10)/100,e=parseInt(n.voiceVolume,10)/100;(Number.isNaN(t)||t<0||t>1)&&(c("Music volume must be between 0 and 100"),process.exit(p.INVALID_INPUT)),(Number.isNaN(e)||e<0||e>2)&&(c("Voice volume must be between 0 and 200"),process.exit(p.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 a=await wo({operation:"add-to-video",inputs:i,options:{musicVolume:t,voiceVolume:e}});if(!n.wait){r?.stop(),En(a,o);return}r&&(r.text=`Processing (ID: ${a.requestId})...`);let s=await he(()=>Zt(a.requestId),120,3e3);if(r?.stop(),s.status==="failed"&&(c(s.error||"Audio mixing failed"),process.exit(p.GENERAL_ERROR)),En(s,o),n.output&&s.outputUrl){let l=o==="human"?An("Downloading...").start():null;try{await Es(s.outputUrl,n.output),l?.stop(),o==="human"&&C(`Saved to: ${n.output}`)}catch(d){l?.stop(),A(`Failed to download: ${d instanceof Error?d.message:"Unknown error"}`)}}}catch(a){r?.stop(),c(a instanceof Error?a.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),Ps=new On("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 Zt(n);e?.stop(),En(o,t.format)}catch(o){e?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),_r=new On("mix").description("Audio mixing commands").addCommand(Os).addCommand(Ps);import{Command as Nn}from"commander";import Pn from"ora";import{writeFile as Mr,mkdir as Ds}from"fs/promises";import{dirname as Ns}from"path";function Dn(n,t){if(t==="json"){let{cost:e,...o}=n;x(o);return}if(t==="quiet"){n.audioUrl?console.log(n.audioUrl):console.log(n.requestId);return}m(`Request ID: ${n.requestId}`),m(`Status: ${n.status}`),n.duration&&m(`Duration: ${n.duration}s`),n.audioUrl&&C(`Audio URL: ${n.audioUrl}`),n.cost!==void 0&&m(`Cost: $${n.cost.toFixed(4)}`),n.error&&c(`Error: ${n.error}`)}async function Fs(n,t){if(await Ds(Ns(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 Mr(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 Mr(t,Buffer.from(o))}var Ls=new Nn("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);(Number.isNaN(t)||t<3||t>600)&&(c("Duration must be between 3 and 600 seconds (10 minutes)"),process.exit(p.INVALID_INPUT));let e=n.format,o=e==="human"?Pn("Generating music...").start():null;try{let r=await ft({prompt:n.prompt,duration:t,options:{provider:n.provider,style:n.style}});if(!n.wait){o?.stop(),Dn(r,e);return}let i=r;if(r.status!=="completed"&&r.status!=="failed"&&(o&&(o.text=`Processing (ID: ${r.requestId})...`),i=await he(()=>Qe(r.requestId),60,2e3)),o?.stop(),i.status==="failed"&&(c(i.error||"Music generation failed"),process.exit(p.GENERAL_ERROR)),Dn(i,e),n.output&&i.audioUrl){let a=e==="human"?Pn("Downloading...").start():null;try{await Fs(i.audioUrl,n.output),a?.stop(),e==="human"&&C(`Saved to: ${n.output}`)}catch(s){a?.stop(),A(`Failed to download: ${s instanceof Error?s.message:"Unknown error"}`)}}}catch(r){o?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),Us=new Nn("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"?Pn("Checking status...").start():null;try{let o=await Qe(n);e?.stop(),Dn(o,t.format)}catch(o){e?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),jr=new Nn("music").description("Music generation commands").addCommand(Ls).addCommand(Us);import{Command as Fn}from"commander";function Vr(n,t){return[...t,n]}var _s=new Fn("create").description("Create a standalone poll").argument("<question>","Poll question").option("--option <text>","Choice (repeat 2-10 times)",Vr,[]).option("--type <type>","single, multiple, or word-cloud","single").option("--title <title>","Poll title").option("--team-id <id>","Workspace ID").option("--yes","Approve creation").action(async(n,t)=>{if(!t.yes)return c("Pass --yes to approve poll creation");try{x(await R("createPoll",{approvalReceipt:"cli:--yes",options:t.option.map(e=>({text:e})),pollType:t.type,question:n,teamId:t.teamId,title:t.title}))}catch(e){c(e instanceof Error?e.message:"Poll creation failed"),process.exit(p.GENERAL_ERROR)}}),Ms=new Fn("edit").description("Edit a standalone poll").argument("<poll-id>","Poll UUID").option("--question <question>","New question").option("--option <text>","Replacement choice (repeat)",Vr).option("--type <type>","single, multiple, or word-cloud").option("--title <title>","Poll title").option("--team-id <id>","Workspace ID").option("--yes","Approve update").action(async(n,t)=>{if(!t.yes)return c("Pass --yes to approve poll update");try{x(await R("editPoll",{approvalReceipt:"cli:--yes",options:t.option?.map(e=>({text:e})),pollId:n,pollType:t.type,question:t.question,teamId:t.teamId,title:t.title}))}catch(e){c(e instanceof Error?e.message:"Poll update failed"),process.exit(p.GENERAL_ERROR)}}),qr=new Fn("poll").description("Standalone poll commands").addCommand(_s).addCommand(Ms);import{Command as Br}from"commander";var js=new Br("status").description("Check a presentation generation run").argument("<run-id>","Run ID returned by presentation generation").option("--team-id <id>","Workspace ID override").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{try{let e=await F("createSlides",n,t.teamId);if(t.format==="json"){x(e);return}if(t.format==="quiet"){console.log(e.status);return}m(`Status: ${e.status}`),m(e.message),e.progress!==null&&m(`Progress: ${e.progress}%`),e.error&&c(e.error.message)}catch(e){c(e instanceof Error?e.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),Gr=new Br("presentation").description("Presentation background-run commands").addCommand(js);import{writeFile as Vs}from"fs/promises";import{Command as qs}from"commander";import Bs from"ora";var Wr=new qs("scrape").description("Extract content from a URL").argument("<url>","URL to scrape").option("--team-id <id>","Workspace ID").option("-o, --output <path>","Save content to file").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{let e=t.format,o=e==="human"?Bs("Scraping URL...").start():null;try{let r=await Co(n,t.teamId);o?.stop(),(!r.success||!r.data)&&(c(r.error||"Failed to scrape URL"),process.exit(p.GENERAL_ERROR));let i=r.data;if(t.output&&(await Vs(t.output,i.content,"utf-8"),e==="human"&&C(`Content saved to: ${t.output}`)),e==="json"){let{cost:a,...s}=i;x(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&&A(i.warning),t.output||(console.log(),console.log("--- Content ---"),console.log(i.content)),i.cost&&i.cost>0&&m(`Cost: $${i.cost.toFixed(6)}`)}catch(r){o?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}});import{Command as nt}from"commander";function Ft(n,t){t!=="quiet"&&x(n)}var Gs=new nt("web").description("Search current public web sources").argument("<query>","Search query").option("--team-id <id>","Workspace ID").option("--max-results <count>","Maximum results","5").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{try{let e=await R("searchInternet",{maxResults:Number.parseInt(t.maxResults,10),query:n,teamId:t.teamId});Ft(e,t.format)}catch(e){c(e instanceof Error?e.message:"Search failed"),process.exit(p.GENERAL_ERROR)}}),Ws=new nt("news").description("Search recent news").argument("<topic>","News topic").option("--team-id <id>","Workspace ID").option("--timeframe <value>","Timeframe hint").option("--max-results <count>","Maximum results","6").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{try{let e=await R("getNews",{maxResults:Number.parseInt(t.maxResults,10),teamId:t.teamId,timeframe:t.timeframe,topic:n});Ft(e,t.format)}catch(e){c(e instanceof Error?e.message:"News search failed"),process.exit(p.GENERAL_ERROR)}}),Js=new nt("images").description("Search licensed image providers").argument("<query>","Image search query").option("--team-id <id>","Workspace ID").option("--max-results <count>","Maximum results","10").option("--aspect <aspect>","Aspect: any, square, wide, tall","any").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{try{let e=await R("searchImages",{aspect:t.aspect,maxResults:Number.parseInt(t.maxResults,10),query:n,teamId:t.teamId});Ft(e,t.format)}catch(e){c(e instanceof Error?e.message:"Image search failed"),process.exit(p.GENERAL_ERROR)}}),Hs=new nt("video").description("Search licensed stock-video providers").argument("<query>","Stock-video search query").option("--team-id <id>","Workspace ID").option("--max-results <count>","Maximum results","10").option("--orientation <value>","Orientation: landscape, portrait, square, any","any").option("--license <value>","License: free, premium, any","any").option("-f, --format <format>","Output format: human, json, quiet","human").action(async(n,t)=>{try{let e=await R("searchStockVideo",{license:t.license,maxResults:Number.parseInt(t.maxResults,10),orientation:t.orientation,query:n,teamId:t.teamId});Ft(e,t.format)}catch(e){c(e instanceof Error?e.message:"Video search failed"),process.exit(p.GENERAL_ERROR)}}),Jr=new nt("search").description("Web, news, image, and stock-video search").addCommand(Gs).addCommand(Ws).addCommand(Js).addCommand(Hs);import{Command as _n}from"commander";import Ln from"ora";import{writeFile as Hr,mkdir as zs}from"fs/promises";import{dirname as Ys}from"path";function Un(n,t){if(t==="json"){let{cost:e,...o}=n;x(o);return}if(t==="quiet"){n.audioUrl?console.log(n.audioUrl):n.requestId?console.log(n.requestId):console.log(n.id);return}m(`Request ID: ${n.requestId||n.id}`),m(`Status: ${n.status}`),n.duration&&m(`Duration: ${n.duration}s`),n.audioUrl&&C(`Audio URL: ${n.audioUrl}`),n.cost!==void 0&&m(`Cost: $${n.cost.toFixed(4)}`),n.error&&c(`Error: ${n.error}`)}async function Ks(n,t){if(await zs(Ys(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 Hr(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 Hr(t,Buffer.from(o))}var Xs=new _n("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)&&(c("Duration must be between 0.5 and 30 seconds"),process.exit(p.INVALID_INPUT)));let e;n.promptInfluence&&(e=parseFloat(n.promptInfluence),(isNaN(e)||e<0||e>1)&&(c("Prompt influence must be between 0 and 1"),process.exit(p.INVALID_INPUT)));let o=n.outputFormat,r=o==="human"?Ln("Generating sound effects...").start():null;try{let i=await Io({text:n.text,duration:t,options:{provider:n.provider,promptInfluence:e,loop:n.loop,format:n.format}});if(!n.wait){r?.stop(),Un(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 he(()=>tn(s),60,2e3)}if(r?.stop(),a.status==="failed"&&(c(a.error||"Sound effects generation failed"),process.exit(p.GENERAL_ERROR)),Un(a,o),n.output&&a.audioUrl){let s=o==="human"?Ln("Downloading...").start():null;try{await Ks(a.audioUrl,n.output),s?.stop(),o==="human"&&C(`Saved to: ${n.output}`)}catch(l){s?.stop(),A(`Failed to download: ${l instanceof Error?l.message:"Unknown error"}`)}}}catch(i){r?.stop(),c(i instanceof Error?i.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),Qs=new _n("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"?Ln("Checking status...").start():null;try{let o=await tn(n);e?.stop(),Un(o,t.format)}catch(o){e?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),zr=new _n("sfx").description("Sound effects generation commands").addCommand(Xs).addCommand(Qs);import{Command as Lt}from"commander";import Qr from"ora";import{writeFile as Yr,mkdir as Zs}from"fs/promises";import{dirname as ec}from"path";var Kr="en-US-Neural2-C",Xr="gemini",tc=new Lt("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: ${Kr})`).option("-p, --provider <provider>",`Provider: gemini, elevenlabs, openai (default: ${Xr})`).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"?Qr("Generating speech...").start():null,o;n.speed&&(o=parseFloat(n.speed),(isNaN(o)||o<.25||o>4)&&(e?.stop(),c("Speed must be between 0.25 and 4.0"),process.exit(p.INVALID_INPUT)));let r;if(n.speakers)try{r=JSON.parse(n.speakers),(!Array.isArray(r)||r.length>2)&&(e?.stop(),c("Speakers must be an array with max 2 items"),process.exit(p.INVALID_INPUT))}catch{e?.stop(),c(`Invalid --speakers JSON. Example: '[{"name":"Joe","voice":"Kore"}]'`),process.exit(p.INVALID_INPUT)}try{let i=n.voiceId,a=n.voice||Kr,s=n.provider||Xr,l={};r&&(l.gemini={speakers:r}),n.instructions&&(l.openai={instructions:n.instructions});let d=await gt({text:n.text,options:{provider:s,voiceId:i,voice:a,model:n.model,speed:o,providerOptions:Object.keys(l).length>0?l:void 0}});e?.stop();let f=n.output.endsWith(`.${d.format}`)?n.output:`${n.output}.${d.format}`;await Zs(ec(f),{recursive:!0}),await Yr(f,d.audioData);let b=f.replace(/\.[^.]+$/,".txt");if(await Yr(b,n.text,"utf-8"),t==="json"){x({status:"completed",output:f,duration:d.duration,provider:d.provider,format:d.format});return}if(t==="quiet"){console.log(f);return}C(`Saved to: ${f}`),m(`Duration: ${d.duration.toFixed(2)}s`),m(`Provider: ${d.provider}`),m(`Cost: $${d.cost.toFixed(6)}`)}catch(i){e?.stop(),c(i instanceof Error?i.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),nc=new Lt("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"?Qr("Fetching voices...").start():null;try{let e=await xo(n.provider);if(t?.stop(),n.format==="json"){x(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(),c(e instanceof Error?e.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),oc=new Lt("status").description("Read speech generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").option("-f, --format <format>","Output format: json","json").action(async(n,t)=>{try{x(await F("generateSpeech",n,t.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(p.GENERAL_ERROR)}}),Zr=new Lt("tts").description("Text-to-speech commands").addCommand(tc).addCommand(nc).addCommand(oc);import{execSync as Je,spawn as yc,spawnSync as bc}from"child_process";import{access as jn,mkdir as He,readFile as rt,rm as Vn,writeFile as ue}from"fs/promises";import{join as V,resolve as ot}from"path";import{Command as Q}from"commander";import vc from"ffmpeg-static";import it from"ora";import{homedir as rc}from"os";import{join as ei}from"path";import{readdir as ic}from"fs/promises";var ac="conceptcraft";function Be(){return ei(rc(),`.${ac}`,"projects")}function Ut(n){return ei(Be(),n)}async function Mn(){try{let n=Be();return(await ic(n,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>e.name)}catch{return[]}}function ti(n,t){let e=2,o=`${n}-${e}`;for(;t.includes(o);)e++,o=`${n}-${e}`;return o}import{Command as sc}from"commander";import cc from"ora";import{execSync as lc,spawnSync as Ge}from"child_process";import{mkdirSync as ni,existsSync as Mt,readFileSync as ri,writeFileSync as oi}from"fs";import{join as Ce,basename as dc}from"path";import{tmpdir as mc}from"os";function jt(n,t){try{return lc(t,{stdio:"ignore"}),!0}catch{return!1}}function _t(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 uc(n){let t=Ge("ffprobe",["-v","error","-show_entries","format=duration","-of","default=noprint_wrappers=1:nokey=1",n],{encoding:"utf-8"});return parseFloat(t.stdout.trim())}function pc(n,t){let e=Ge("ffmpeg",["-i",n,"-vf",`select='gt(scene,${t})',showinfo`,"-vsync","vfr","-f","null","-"],{encoding:"utf-8",timeout:12e4}),o=[0],r=(e.stderr||"").split(`
|
|
3753
|
+
`);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 gc(n,t,e){let o=[];for(let r=0;r<t.length;r++){let i=t[r]+.5,a=Ce(e,`scene_${String(r+1).padStart(2,"0")}.jpg`);Ge("ffmpeg",["-ss",String(i),"-i",n,"-vframes","1","-q:v","2","-y",a],{stdio:"ignore",timeout:3e4}),o.push(a)}return o}function fc(n,t){let e=Ce(t,"audio.wav");if(Ge("ffmpeg",["-i",n,"-vn","-acodec","pcm_s16le","-ar","16000","-ac","1","-y",e],{stdio:"ignore",timeout:6e4}),!Mt(e)||!jt("whisper","which whisper")&&!jt("whisper-cpp","which whisper-cpp"))return null;let r=Ge("whisper",[e,"--model","base","--output_format","json","--output_dir",t,"--language","en"],{encoding:"utf-8",timeout:3e5}),i=Ce(t,"audio.json");if(!Mt(i))return null;try{let a=JSON.parse(ri(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 hc(n,t){let e=ri(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=Ge("curl",["-s","-X","POST","http://localhost:11434/api/generate","-H","Content-Type: application/json","-d",o],{encoding:"utf-8",timeout:6e4});try{return(JSON.parse(r.stdout).response||"").replace(/!!!IMAGE!!!/gi,"").replace(/\[image[^\]]*\]/gi,"").trim()||"Unable to describe frame"}catch{return"Unable to describe frame"}}var ii=new sc("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=cc();Mt(n)||(console.error(`File not found: ${n}`),process.exit(1)),jt("ffmpeg","which ffmpeg")||(console.error("ffmpeg is required. Install: brew install ffmpeg"),process.exit(1)),t.vision!==!1&&!jt("ollama","which ollama")&&(console.error("ollama is required for vision. Install: brew install ollama"),process.exit(1));let o=t.output||Ce(mc(),`video-analyze-${Date.now()}`);ni(o,{recursive:!0});let r=Ce(o,"frames");ni(r,{recursive:!0});let i=parseFloat(t.threshold),a=t.model;e.start("Reading video metadata...");let s=uc(n);e.succeed(`Video: ${_t(s)} (${s.toFixed(1)}s)`),e.start("Detecting scenes...");let l=pc(n,i);e.succeed(`Detected ${l.length} scenes`),e.start("Extracting key frames...");let d=gc(n,l,r);e.succeed(`Extracted ${d.length} key frames`);let f=null;t.transcribe!==!1&&(e.start("Transcribing audio..."),f=fc(n,o),f?e.succeed(`Transcribed: ${f.segments.length} segments`):e.warn("Transcription skipped (whisper not installed: pip install openai-whisper)"));let b=[];for(let g=0;g<l.length;g++){let y=l[g],k=g<l.length-1?l[g+1]:s,w="";t.vision!==!1&&Mt(d[g])&&(e.start(`Describing scene ${g+1}/${l.length}...`),w=hc(d[g],a),e.succeed(`Scene ${g+1}: ${w}`)),b.push({id:g+1,startTime:y,endTime:k,duration:k-y,framePath:d[g],description:w})}let v={source:n,duration:s,scenes:b,transcript:f};if(t.outputFormat==="json"){let g=JSON.stringify(v,null,2),y=Ce(o,"analysis.json");oi(y,g),console.log(g)}else{let g=["# Video Analysis","",`**Source:** ${dc(n)}`,`**Duration:** ${_t(s)} (${s.toFixed(1)}s)`,`**Scenes:** ${b.length}`,"","## Scenes",""];for(let w of b){if(g.push(`### Scene ${w.id} (${_t(w.startTime)} - ${_t(w.endTime)}) [${w.duration.toFixed(1)}s]`),w.description&&g.push(`**Visual:** ${w.description}`),f?.segments){let $=f.segments.filter(B=>B.end>w.startTime&&B.start<w.endTime);$.length>0&&g.push(`**Audio:** ${$.map(B=>B.text).join(" ").trim()}`)}g.push(`**Frame:** ${w.framePath}`),g.push("")}f?.text&&(g.push("## Full Transcript"),g.push(""),g.push(f.text.trim()),g.push(""));let y=g.join(`
|
|
3754
|
+
`),k=Ce(o,"analysis.md");oi(k,y),console.log(y),console.log(`
|
|
3755
|
+
Results saved to: ${o}`)}});var xc="inizio-inc/remotion-video-template#main",We=30;async function wc(n){let t=await rt(n,"utf-8");return JSON.parse(t)}async function Sc(n){let t=V(n,"template.manifest.json");try{return await wc(t)}catch{return{entry:"src/Root.tsx",compositions:[{id:"Main",type:"youtube",aspect:"16:9",default:!0}]}}}function ai(){try{return Je("bun --version",{stdio:"ignore"}),!0}catch{return!1}}function Cc(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 Ic(n,t,e=We,o){if(o&&o.characters.length>0)return Tc(n,o,e);let r=n.reduce((a,s)=>a+s.split(/\s+/).length,0),i=0;return n.map((a,s)=>{let l=a.split(/\s+/).length,d=l/r,f=t*d,b=Math.round(f*e),v=a.split(""),g=f/v.length,y={characters:v,characterStartTimesSeconds:v.map((w,$)=>$*g),characterEndTimesSeconds:v.map((w,$)=>($+1)*g)},k={id:s+1,text:a,wordCount:l,startTime:i,endTime:i+f,durationInSeconds:f,durationInFrames:b,timestamps:y};return i+=f,k})}function Tc(n,t,e){let{characters:o,characterStartTimesSeconds:r,characterEndTimesSeconds:i}=t,a=o.join(""),s=[],l=0;for(let d=0;d<n.length;d++){let f=n[d],b=f.length;for(;l<o.length&&o[l].match(/^\s*$/);)l++;let v=l,g=r[v]||0;l+=b;let y=l-1;for(;y>v&&o[y]?.match(/^\s*$/);)y--;let k=i[Math.min(y,i.length-1)]||g+1,w=k-g,$=Math.round(w*e),B={characters:o.slice(v,y+1),characterStartTimesSeconds:r.slice(v,y+1).map(L=>L-g),characterEndTimesSeconds:i.slice(v,y+1).map(L=>L-g)};s.push({id:d+1,text:f,wordCount:f.split(/\s+/).length,startTime:g,endTime:k,durationInSeconds:w,durationInFrames:$,timestamps:B})}return s}function kc(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 Rc(n,t,e){let o=V(n,"public"),r=V(n,"scripts");await He(o,{recursive:!0}),await He(r,{recursive:!0});let i=V(o,"scenes.json");await ue(i,JSON.stringify(kc(t),null,2),"utf-8");let a=`import { execSync } from "node:child_process";
|
|
3738
3756
|
|
|
3739
3757
|
execSync("${e} video generate plan --project .", { stdio: "inherit" });
|
|
3740
|
-
`,
|
|
3758
|
+
`,s=`import { execSync } from "node:child_process";
|
|
3741
3759
|
|
|
3742
3760
|
const args = process.argv.slice(2).join(" ");
|
|
3743
3761
|
execSync("${e} video export --project . " + args, { stdio: "inherit" });
|
|
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(` ${
|
|
3746
|
-
${
|
|
3747
|
-
${
|
|
3748
|
-
$ ${
|
|
3749
|
-
|
|
3750
|
-
${
|
|
3751
|
-
$ ${
|
|
3762
|
+
`;await ue(V(r,"plan.ts"),a,"utf-8"),await ue(V(r,"export.ts"),s,"utf-8")}async function si(){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 $c(n){return n.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function Ac(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 Vt(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 ue(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 ue(t,Buffer.from(o))}function Ec(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 Oc=new Q("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"?it("Initializing...").start():null,o=n.project?ot(process.cwd(),n.project):null;try{let r=await si(),i=null;if(n.scenes&&!n.scriptFile&&(n.scriptFile=n.scenes),o&&(n.output=V(o,"public"),n.scriptFile?n.scriptFile=ot(o,n.scriptFile):!n.script&&!r&&(n.scriptFile=V(o,"public","scenes.json"))),r)try{let T=JSON.parse(r);T.scenes&&Array.isArray(T.scenes)&&(i=T)}catch{}if(!i&&n.scriptFile)try{let T=await rt(n.scriptFile,"utf-8"),W=JSON.parse(T);W.scenes&&Array.isArray(W.scenes)&&(i=W)}catch{}let a=i?.voice||n.voice,s=i?.voiceId,l=i?.provider,d=i?.model,f=i?.voiceInstructions,b=i?.musicPrompt||n.musicPrompt||"uplifting background music, positive energy",v=i?.musicDuration,g=V(n.output,"audio"),y=V(n.output,"images"),k=V(n.output,"videos");e&&(e.text="Creating directories..."),await He(g,{recursive:!0}),await He(y,{recursive:!0}),await He(k,{recursive:!0});let w=0,$=[],B=0,L=[],H=[];if(i&&i.scenes.length>0){t==="human"&&(e?.stop(),m(`Processing ${i.scenes.length} scenes...`),e?.start());let T=i.scenes.map((te,M)=>{let le=te.script;return te.voiceStyle&&(le=`${te.voiceStyle} ${le}`),{text:le,id:`scene-${M}`}});e&&(e.text="Generating speech for all scenes...");let W=await vo({texts:T,options:{provider:l,voice:a,voiceId:s,model:d,voiceSettings:i.voiceSettings,instructions:f}});w+=W.totalCost;let ee=0;for(let te=0;te<i.scenes.length;te++){let M=i.scenes[te],le=$c(M.name),ae=W.results[te];e&&(e.text=`[${M.name}] Saving audio...`);let Wt=V(g,`${le}.${ae.format}`);await ue(Wt,ae.audioData);let Te=ae.duration,fi=Math.round(Te*We),Ye={id:te+1,name:M.name,text:M.script,wordCount:M.script.split(/\s+/).length,startTime:ee,endTime:ee+Te,durationInSeconds:Te,durationInFrames:fi,audioPath:`audio/${le}.${ae.format}`,timestamps:ae.timestamps};if(M.imageQuery){e&&(e.text=`[${M.name}] Searching image...`);try{let K=await ht({query:M.imageQuery,options:{maxResults:1,size:"large",safeSearch:!0}}),Ke=K.data.results.flatMap(z=>z.results);if(w+=K.data.totalCost,Ke.length>0){let z=Ke[0],Xe=Ec(z.url),ye=`${le}.${Xe}`,Jt=V(y,ye);await Vt(z.url,Jt),Ye.imagePath=`images/${ye}`,L.push({path:`images/${ye}`,url:z.url,width:z.width,height:z.height,query:M.imageQuery})}}catch(K){t==="human"&&(e?.stop(),A(`[${M.name}] Image search failed: ${K instanceof Error?K.message:"Unknown"}`),e?.start())}}if(M.videoQuery){e&&(e.text=`[${M.name}] Searching video...`);try{let K=await en({query:M.videoQuery,options:{maxResults:1,license:"free"}}),Ke=K.data.results.flatMap(z=>z.results);if(w+=K.data.totalCost,Ke.length>0){let z=Ke[0],Xe=z.previewUrl||z.downloadUrl;if(Xe){let ye=`${le}.mp4`,Jt=V(k,ye);await Vt(Xe,Jt),Ye.videoPath=`videos/${ye}`,H.push({path:`videos/${ye}`,url:Xe,width:z.width,height:z.height,duration:z.duration,query:M.videoQuery})}}}catch(K){t==="human"&&(e?.stop(),A(`[${M.name}] Video search failed: ${K instanceof Error?K.message:"Unknown"}`),e?.start())}}if($.push(Ye),ee+=Te,B+=Te,t==="human"){e?.stop();let K=[`audio: ${Te.toFixed(1)}s`,Ye.imagePath?"image":null,Ye.videoPath?"video":null].filter(Boolean).join(", ");C(` ${M.name}: ${K}`),e?.start()}}}else{let T=n.script;if(n.scriptFile)try{T=await rt(n.scriptFile,"utf-8")}catch(ae){e?.stop(),c(`Failed to read script file: ${ae instanceof Error?ae.message:"Unknown error"}`),process.exit(p.INVALID_INPUT)}(!T||T.trim().length===0)&&(e?.stop(),c("Provide scenes via stdin JSON, --scenes/--script-file with scenes JSON, or --script for legacy mode"),process.exit(p.INVALID_INPUT)),T=T.trim();let W=n.topic||T.split(".")[0].slice(0,50);e&&(e.text="Generating voiceover...");let ee=await gt({text:T,options:{voice:a}}),te=V(g,`voiceover.${ee.format}`);await ue(te,ee.audioData),w+=ee.cost,B=ee.duration;let M=Cc(T);$=Ic(M,ee.duration,We,ee.timestamps).map((ae,Wt)=>({...ae,name:`Section${Wt+1}`,audioPath:`audio/voiceover.${ee.format}`})),t==="human"&&(e?.stop(),C(`Voiceover: ${te} (${ee.duration.toFixed(1)}s)`),e?.start())}e&&(e.text="Creating timeline...");let S=Ac($),U=Math.max(S.audio.length>0?Math.max(...S.audio.map(T=>T.endMs)):0,S.text.length>0?Math.max(...S.text.map(T=>T.endMs)):0,S.elements.length>0?Math.max(...S.elements.map(T=>T.endMs)):0),_=U/1e3,Z=v?Math.min(300,Math.max(3,v)):Math.min(300,Math.ceil(_));console.log("[Music Generation] Requesting music:",{prompt:b,requestedDuration:Z,totalAudioDuration:B,actualVideoDuration:_,timelineDurationMs:U});let ze,qt;e&&(e.text="Generating music and thumbnail...");let ui=`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: ${$.map(T=>T.text).join(" ")}`,Bt=[],pi=(async()=>{if(Z<3)return t==="human"&&(e?.stop(),A(`Video duration (${_.toFixed(1)}s) is too short for music generation (minimum 3s).`),e?.start()),null;try{let T=await ft({prompt:b,duration:Z});if(T.status!=="completed"&&T.status!=="failed"&&(T=await he(()=>Qe(T.requestId),60,2e3)),T.status==="failed")throw new Error(T.error||"Unknown error");let W=V(g,"music.mp3");return T.audioUrl&&await Vt(T.audioUrl,W),{path:"audio/music.mp3",duration:T.duration||Z,prompt:b,cost:T.cost||0}}catch(T){return t==="human"&&(e?.stop(),A(`Music generation failed: ${T.message}`),e?.start()),null}})();Bt.push(pi);let gi=(async()=>{try{let T=await So({prompt:ui,options:{width:1280,height:720}});if(T.success&&T.data.url){let W=V(n.output,"thumbnail.jpg");return await Vt(T.data.url,W),w+=T.data.cost||0,W}return null}catch(T){return t==="human"&&(e?.stop(),A(`Thumbnail generation failed: ${T.message}`),e?.start()),null}})();Bt.push(gi);let[Ie,Gn]=await Promise.all(Bt);Ie&&(ze=Ie,w+=Ie.cost||0,t==="human"&&(e?.stop(),C(`Music: ${V(g,"music.mp3")} (${Ie.duration}s)`),Ie.duration<_&&A(`Music duration (${Ie.duration.toFixed(1)}s) is shorter than video duration (${_.toFixed(1)}s).`),e?.start())),Gn&&(qt=Gn,t==="human"&&(e?.stop(),C(`Thumbnail: ${qt}`),e?.start())),e&&(e.text="Writing manifest...");let Wn=Math.round(_*We),Jn={music:ze,thumbnail:qt?"thumbnail.jpg":void 0,images:L,videos:H,scenes:$,timeline:S,totalDurationInFrames:Wn,fps:We,totalCost:w,createdAt:new Date().toISOString()},Gt=V(n.output,"video-manifest.json");if(await ue(Gt,JSON.stringify(Jn,null,2)),e?.stop(),t==="json"){let{totalCost:T,...W}=Jn;x(W);return}if(t==="quiet"){console.log(Gt);return}console.log(),C("Video assets created successfully!"),console.log(),m(`Scenes: ${$.length} (${Wn} frames at ${We}fps)`);for(let T of $){let W=[T.audioPath?"audio":null,T.imagePath?"image":null,T.videoPath?"video":null].filter(Boolean).join(", ");m(` - ${T.name}: ${T.durationInSeconds.toFixed(1)}s [${W}]`)}m(`Music: ${ze?.path} (${ze?.duration}s)`),m(`Manifest: ${Gt}`),console.log(),m(`Total cost: $${w.toFixed(4)}`)}catch(r){e?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),Pc=new Q("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"?it("Finding videos...").start():null;try{let s=await en({query:n,options:{maxResults:parseInt(e,10),orientation:o,license:r}});a?.stop();let l=s.data.results.flatMap(d=>d.results);if(i==="json"){let{totalCost:d,...f}=s.data;x({...s,data:f});return}if(i==="quiet"){l.forEach(d=>{console.log(d.previewUrl||d.thumbnailUrl)});return}if(l.length===0){m("No videos found");return}C(`Found ${l.length} videos for "${n}"`),console.log(),l.forEach((d,f)=>{console.log(`[${f+1}] ${d.title}`),console.log(` URL: ${d.previewUrl||d.thumbnailUrl}`),console.log(` Duration: ${d.duration}s | Size: ${d.width}x${d.height}`),console.log(` Provider: ${d.provider}`),console.log()}),m(`Total cost: $${s.data.totalCost.toFixed(4)}`)}catch(s){a?.stop(),c(s instanceof Error?s.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),Dc=new Q("new").description("Create a new video project from a template").argument("<name>","Project directory name").option("-t, --template <repo>","GitHub repo (user/repo#commit)",xc).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"?it("Initializing video project...").start():null;try{let r=Be();await He(r,{recursive:!0});let i=Ut(n),a=t.type,s=await Mn();if(s.includes(n)){let g=ti(n,s);o?.stop(),c(`Project "${n}" already exists at: ${i}`),m(`Try: ${u.commands[0]} video generate new ${g}`),process.exit(p.INVALID_INPUT)}/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_.-]+(#[a-zA-Z0-9_./-]+)?$/.test(t.template)||(o?.stop(),c(`Invalid template format: "${t.template}". Expected format: owner/repo or owner/repo#branch`),process.exit(p.INVALID_INPUT)),["youtube","tiktok","audiogram"].includes(a)||(o?.stop(),c(`Invalid type "${a}". Use youtube, tiktok, or audiogram.`),process.exit(p.INVALID_INPUT)),o&&(o.text=`Cloning template from ${t.template}...`);let[d,f]=t.template.split("#"),b=f?`-b ${f}`:"";try{Je(`git clone ${b} --depth 1 https://github.com/${d}.git "${i}"`,{stdio:"pipe"}),await Vn(V(i,".git"),{recursive:!0,force:!0})}catch(g){o?.stop(),c(`Failed to clone template: ${g instanceof Error?g.message:"Unknown error"}`),process.exit(p.GENERAL_ERROR)}e==="human"&&(o?.stop(),C(`Template downloaded to ${n}/`),o?.start());let v;try{v=await Sc(i)}catch{o?.stop(),c("template.manifest.json not found or invalid in template repo"),process.exit(p.INVALID_INPUT)}if(v.propsSchema&&v.propsSchema!=="video-plan.v1"&&(o?.stop(),c(`Template propsSchema must be video-plan.v1 (found ${v.propsSchema})`),process.exit(p.INVALID_INPUT)),o&&(o.text="Writing scaffold files..."),await Rc(i,a,u.commands[0]),t.install){let g=ai()?"bun":"npm";o&&(o.text=`Installing dependencies with ${g}...`),await new Promise((y,k)=>{let w=yc(g,["install"],{cwd:i,stdio:"pipe",shell:!0});w.on("close",$=>{$===0?y():k(new Error(`${g} install failed with code ${$}`))}),w.on("error",k)}),e==="human"&&(o?.stop(),C("Dependencies installed"),o?.start())}if(o?.stop(),e==="json"){x({name:n,path:i,template:t.template,type:a,installed:t.install});return}if(e==="quiet"){console.log(i);return}console.log(),C(`Video project "${n}" created successfully!`),m(`Location: ${i}`),a==="tiktok"?m("Format: TikTok/Reels/Shorts (1080x1920 @ 30fps)"):a==="audiogram"?m("Format: Audiogram (1080x1080 @ 30fps)"):m("Format: YouTube (1920x1080 @ 30fps)"),console.log(),m("Next steps:"),m(` cd ${i}`),t.install||m(` ${ai()?"bun":"npm"} install`),m(" bun run dev # Preview in Remotion Studio"),m(` ${u.commands[0]} video generate assets --scenes public/scenes.json`),m(` ${u.commands[0]} video generate plan`)}catch(r){o?.stop(),c(r instanceof Error?r.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),Nc=new Q("plan").description("Generate video plan from context (via stdin or --context)").option("-c, --context <text>","Context for plan generation").option("-o, --output <path>","Save plan to file").option("-b, --branding <path>","Branding JSON file to include").option("--render-target <target>","Plan target: hyperframes or remotion","hyperframes").option("--no-wait","Return the background run ID immediately").action(async n=>{let t=it("Generating video plan...").start();try{let e=n.context;if(!e){let l=await si();l&&(e=l)}e||(t.stop(),c("Provide context via stdin or --context flag"),process.exit(p.INVALID_INPUT));let o;if(n.branding)try{o=await rt(n.branding,"utf-8")}catch{t.stop(),c(`Could not read branding file: ${n.branding}`),process.exit(p.INVALID_INPUT)}let r=n.renderTarget==="remotion"?"remotion":"hyperframes",i={context:e,branding:o,renderTarget:r};if(n.wait===!1){t.stop(),x(await nn(i));return}let a=await ko(i);t.stop(),a.success||(c(a.error||"Failed to generate plan"),process.exit(p.GENERAL_ERROR));let s=a.data;n.output?(await ue(n.output,s),C(`Plan saved to ${n.output}`)):console.log(s)}catch(e){t.stop(),c(e instanceof Error?e.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),Fc=new Q("generate").description("Generate parts of a video project").addCommand(Dc).addCommand(Oc).addCommand(Nc),Lc=new Q("create").description("Start background standalone video generation").argument("<title>","Video title").requiredOption("--brief <brief>","Video brief").option("--topic <topic>","Video topic").option("--duration <seconds>","Duration in seconds","30").option("--format <format>","tiktok, instagram_reel, or youtube_short","tiktok").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(n,t)=>{if(!t.yes)return c("Pass --yes to approve video generation");try{x(await To({brief:t.brief,durationSec:Number(t.duration),format:t.format,title:n,topic:t.topic}))}catch(e){c(e instanceof Error?e.message:"Generation failed"),process.exit(p.GENERAL_ERROR)}}),ci=new Q("plan").description("Start background video-plan generation").requiredOption("--context <brief>","Video brief (minimum 100 characters)").option("--branding <path>","Branding JSON file").option("--render-target <target>","hyperframes or remotion","hyperframes").option("--yes","Approve generation").action(async n=>{if(!n.yes)return c("Pass --yes to approve plan generation");try{let t=n.branding?await rt(n.branding,"utf-8"):void 0;x(await nn({branding:t,context:n.context,renderTarget:n.renderTarget==="remotion"?"remotion":"hyperframes"}))}catch(t){c(t instanceof Error?t.message:"Plan generation failed"),process.exit(p.GENERAL_ERROR)}}),Uc=new Q("status").description("Read video or video-plan background status").argument("<run-id>","Run ID").option("--plan","Read a video-plan run").option("--team-id <id>","Workspace ID").action(async(n,t)=>{try{x(await F(t.plan?"generateVideoPlan":"createVideo",n,t.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(p.GENERAL_ERROR)}}),_c=new Q("status").description("Read video-plan background status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(n,t)=>{try{x(await F("generateVideoPlan",n,t.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(p.GENERAL_ERROR)}});ci.addCommand(_c);var Mc=new Q("projects").description("List all video projects").option("-f, --format <format>","Output format: human, json","human").action(async n=>{let t=await Mn();if(n.format==="json"){x({projectsDir:Be(),projects:t.map(e=>({name:e,path:Ut(e)}))});return}if(t.length===0){m("No video projects found"),m(`Projects are stored in: ${Be()}`);return}console.log(`
|
|
3763
|
+
Video Projects:`),console.log("-".repeat(50));for(let e of t)console.log(` ${e}`),console.log(` ${Ut(e)}`);console.log()}),jc=new Q("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"?it("Injecting thumbnail...").start():null;try{let o=ot(n.video),r=ot(n.thumbnail),i=n.output?ot(n.output):o.replace(/\.mp4$/,"-with-thumb.mp4");await jn(o),await jn(r);let a=vc;if(a)try{await jn(a)}catch{a=null}if(!a)try{a=Je("which ffmpeg",{encoding:"utf8"}).trim()}catch{throw new Error("ffmpeg not found. Install ffmpeg or ffmpeg-static.")}let s=bc(a,["-i",o],{encoding:"utf8"});if(s.error)throw new Error(`Failed to probe video: ${s.error.message}`);let l=(s.stderr??"").match(/(\d{2,5})x(\d{2,5})/);if(!l)throw new Error("Could not detect video dimensions");let[,d,f]=l;e&&(e.text="Creating thumbnail frame...");let b="/tmp/cc-thumb-frame.mp4";Je(`${a} -y -loop 1 -i "${r}" -vf "scale=${d}:${f}:force_original_aspect_ratio=decrease,pad=${d}:${f}:(ow-iw)/2:(oh-ih)/2,setsar=1" -t 0.033 -r 30 -c:v libx264 -pix_fmt yuv420p "${b}"`,{stdio:"pipe"}),e&&(e.text="Concatenating with video...");let v="/tmp/cc-concat-video.mp4";if(Je(`${a} -y -i "${b}" -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 "${v}"`,{stdio:"pipe"}),e&&(e.text="Adding file icon thumbnail..."),Je(`${a} -y -i "${v}" -i "${r}" -map 0 -map 1 -c copy -c:v:1 png -disposition:v:1 attached_pic "${i}"`,{stdio:"pipe"}),await Vn(b,{force:!0}),await Vn(v,{force:!0}),e?.stop(),t==="json"){x({success:!0,output:i});return}if(t==="quiet"){console.log(i);return}C(`Thumbnail injected: ${i}`)}catch(o){e?.stop(),c(o instanceof Error?o.message:"Unknown error"),process.exit(p.GENERAL_ERROR)}}),Vc=new Q("thumbnail").description("Thumbnail operations").addCommand(jc),qn=new Q("video").description("Video generation commands").addCommand(Fc).addCommand(Pc).addCommand(Mc).addCommand(Vc).addCommand(ii);qn.addCommand(Lc).addCommand(ci).addCommand(Uc);import{Command as Bn}from"commander";var qc=new Bn("create").description("Start background visual-abstract generation").argument("<brief>","Dense source brief").option("--title <title>","Artifact title").option("--aspect <ratio>","1:1, 16:9, 9:16, 4:3, or 3:4","1:1").option("--quality <tier>","fast, balanced, or best","best").option("--preset <preset>","Output preset","executive-one-pager").option("--branding-id <id>","Branding ID").option("--team-id <id>","Workspace ID").option("--yes","Approve generation").action(async(n,t)=>{if(!t.yes)return c("Pass --yes to approve visual-abstract generation");try{x(await R("createVisualAbstract",{approvalReceipt:"cli:--yes",aspectRatio:t.aspect,brandingId:t.brandingId,brief:n,outputPreset:t.preset,qualityTier:t.quality,teamId:t.teamId,title:t.title}))}catch(e){c(e instanceof Error?e.message:"Generation failed"),process.exit(p.GENERAL_ERROR)}}),Bc=new Bn("status").description("Read visual-abstract generation status").argument("<run-id>","Run ID").option("--team-id <id>","Workspace ID").action(async(n,t)=>{try{x(await F("createVisualAbstract",n,t.teamId))}catch(e){c(e instanceof Error?e.message:"Status failed"),process.exit(p.GENERAL_ERROR)}}),li=new Bn("visual-abstract").description("Visual abstract commands").addCommand(qc).addCommand(Bc);var Gc=[Dr,Nr,Ar,Zr,jr,_r,Fr,qn,Wr,zr,Gr,Jr,Or,Lr,qr,Rr,li,Ur,Ir];function di(n){for(let t of Gc)n.addCommand(t)}var Jc="0.3.1",q=new Wc,pe=u.commands[0];q.name(pe).description(u.description).version(Jc,"-v, --version","Show version number").option("--debug","Enable debug logging").option("--no-color","Disable colored output").configureOutput({outputError:(n,t)=>{t(ie.red(n))}});q.addCommand(Ko);q.addCommand(Xo);q.addCommand(Fo);q.addCommand(Wo);q.addCommand(Lo);q.addCommand(Vo);q.addCommand(Go);q.addCommand(wr);q.addCommand(qo);q.addCommand(Sr);q.addCommand(qe);q.addCommand(St);q.addCommand(Eo);di(q);var mi=Mo();mi.commands.length>0&&q.addCommand(mi);q.on("command:*",n=>{console.error(ie.red(`Error: Unknown command '${n[0]}'`)),console.error(),console.error(`Run '${pe} --help' to see available commands.`),process.exit(1)});q.addHelpText("after",`
|
|
3764
|
+
${ie.bold("Examples:")}
|
|
3765
|
+
${ie.gray("# Log in (opens browser)")}
|
|
3766
|
+
$ ${pe} login
|
|
3767
|
+
|
|
3768
|
+
${ie.gray("# Create a presentation (recommended pattern)")}
|
|
3769
|
+
$ ${pe} create "Q4 Business Review" \\
|
|
3752
3770
|
-n 12 -m best \\
|
|
3753
3771
|
--audience "Executive leadership team" \\
|
|
3754
3772
|
--context "Revenue: $50M (+25% YoY), New customers: 150"
|
|
3755
3773
|
|
|
3756
|
-
${
|
|
3757
|
-
$ ${
|
|
3758
|
-
-n 10 -m
|
|
3774
|
+
${ie.gray("# Create from a file")}
|
|
3775
|
+
$ ${pe} create "Product Launch" \\
|
|
3776
|
+
-n 10 -m fast \\
|
|
3759
3777
|
--audience "Sales team and partners" \\
|
|
3760
3778
|
--context-file ./launch-brief.md
|
|
3761
3779
|
|
|
3762
|
-
${
|
|
3763
|
-
$ ${
|
|
3780
|
+
${ie.gray("# Create from URLs")}
|
|
3781
|
+
$ ${pe} create "Market Analysis" \\
|
|
3764
3782
|
-n 15 -m best \\
|
|
3765
3783
|
--audience "Strategy team" \\
|
|
3766
3784
|
--sources https://example.com/report.pdf
|
|
3767
3785
|
|
|
3768
|
-
${
|
|
3769
|
-
$ ${
|
|
3770
|
-
$ ${
|
|
3786
|
+
${ie.gray("# List and export")}
|
|
3787
|
+
$ ${pe} list --format table
|
|
3788
|
+
$ ${pe} export <slug> -o backup.zip
|
|
3771
3789
|
|
|
3772
|
-
${
|
|
3773
|
-
Run '${
|
|
3790
|
+
${ie.bold("Authentication:")}
|
|
3791
|
+
Run '${pe} login' to authenticate (recommended).
|
|
3774
3792
|
Or set CC_SLIDES_API_KEY environment variable for API key auth.
|
|
3775
3793
|
|
|
3776
|
-
${
|
|
3777
|
-
${
|
|
3778
|
-
`);
|
|
3794
|
+
${ie.bold("More Info:")}
|
|
3795
|
+
${ie.blue(u.docsUrl)}
|
|
3796
|
+
`);q.parse(Cr(process.argv.slice(2)),{from:"user"});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@conceptcraft/mindframes",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "CLI tool for creating AI-powered presentations with ConceptCraft",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -51,10 +51,12 @@
|
|
|
51
51
|
"registry": "https://registry.npmjs.org"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
|
-
"node": ">=
|
|
54
|
+
"node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@
|
|
57
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.168",
|
|
58
|
+
"@inquirer/prompts": "8.5.2",
|
|
59
|
+
"@openai/codex-sdk": "^0.142.5",
|
|
58
60
|
"@remotion/bundler": "4.0.375",
|
|
59
61
|
"@remotion/renderer": "4.0.375",
|
|
60
62
|
"chalk": "^5.3.0",
|