@vivipilot/cli 0.1.0 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/chunk-FGUKEVKT.js +1 -0
  2. package/dist/chunk-FN7FHZ3D.js +1 -0
  3. package/dist/chunk-JJDAKVXA.js +8 -0
  4. package/dist/chunk-L3C7EOPY.js +2 -0
  5. package/dist/chunk-ZIATVRTF.js +3 -0
  6. package/dist/chunk-ZZ72PPC3.js +1 -0
  7. package/dist/cli.d.ts +5 -4
  8. package/dist/cli.js +57 -495
  9. package/dist/config-DAG58pP-.d.ts +16 -0
  10. package/dist/index.d.ts +121 -7
  11. package/dist/index.js +1 -7
  12. package/dist/manifest-TDCIHZ46.js +1 -0
  13. package/dist/mcp-DTGU64NI.js +1 -0
  14. package/dist/render-CVXYAUBY.js +1 -0
  15. package/package.json +6 -2
  16. package/dist/api.d.ts +0 -86
  17. package/dist/api.d.ts.map +0 -1
  18. package/dist/api.js +0 -77
  19. package/dist/api.js.map +0 -1
  20. package/dist/args.d.ts +0 -11
  21. package/dist/args.d.ts.map +0 -1
  22. package/dist/args.js +0 -53
  23. package/dist/args.js.map +0 -1
  24. package/dist/browser.d.ts +0 -31
  25. package/dist/browser.d.ts.map +0 -1
  26. package/dist/browser.js +0 -162
  27. package/dist/browser.js.map +0 -1
  28. package/dist/cli.d.ts.map +0 -1
  29. package/dist/cli.js.map +0 -1
  30. package/dist/config.d.ts +0 -15
  31. package/dist/config.d.ts.map +0 -1
  32. package/dist/config.js +0 -58
  33. package/dist/config.js.map +0 -1
  34. package/dist/errors.d.ts +0 -6
  35. package/dist/errors.d.ts.map +0 -1
  36. package/dist/errors.js +0 -12
  37. package/dist/errors.js.map +0 -1
  38. package/dist/index.d.ts.map +0 -1
  39. package/dist/index.js.map +0 -1
  40. package/dist/manifest.d.ts +0 -40
  41. package/dist/manifest.d.ts.map +0 -1
  42. package/dist/manifest.js +0 -90
  43. package/dist/manifest.js.map +0 -1
  44. package/dist/mcp.d.ts +0 -13
  45. package/dist/mcp.d.ts.map +0 -1
  46. package/dist/mcp.js +0 -392
  47. package/dist/mcp.js.map +0 -1
  48. package/dist/render.d.ts +0 -21
  49. package/dist/render.d.ts.map +0 -1
  50. package/dist/render.js +0 -369
  51. package/dist/render.js.map +0 -1
  52. package/src/api.ts +0 -163
  53. package/src/args.test.ts +0 -21
  54. package/src/args.ts +0 -64
  55. package/src/browser.test.ts +0 -103
  56. package/src/browser.ts +0 -174
  57. package/src/cli.ts +0 -656
  58. package/src/config.test.ts +0 -30
  59. package/src/config.ts +0 -71
  60. package/src/errors.ts +0 -14
  61. package/src/index.ts +0 -25
  62. package/src/manifest.test.ts +0 -105
  63. package/src/manifest.ts +0 -126
  64. package/src/mcp.test.ts +0 -48
  65. package/src/mcp.ts +0 -438
  66. package/src/render.ts +0 -424
  67. package/tsconfig.json +0 -26
@@ -0,0 +1 @@
1
+ import{f as a,g as p,i}from"./chunk-L3C7EOPY.js";var u=class{config;env;fetchImpl;constructor(e){this.config=e.config,this.env=e.env??process.env,this.fetchImpl=e.fetchImpl??fetch}apiUrl(){return a(this.config,this.env)}apiKey(){let e=p(this.config,this.env);if(!e)throw new i("Vivipilot CLI/MCP generation is paid-only. Set VIVIPILOT_API_KEY or run `vivipilot login --api-key <key>`.",2);return e}async requestJson(e,t={}){let s=new Headers(t.headers);s.set("accept","application/json"),s.set("authorization",`Bearer ${this.apiKey()}`),s.set("x-vivipilot-client","@vivipilot/cli"),t.body&&!s.has("content-type")&&s.set("content-type","application/json");let n=await this.fetchImpl(`${this.apiUrl()}${e}`,{...t,headers:s}),o=await n.text(),r={};try{r=o.length>0?JSON.parse(o):{}}catch{throw n.ok?new i("Failed to parse response from Vivipilot API as JSON.",1):new i(`Vivipilot API request failed with status ${n.status}. The server did not return a valid JSON response. Ensure your API URL is correct.`,1)}if(!n.ok){let l=r&&typeof r=="object"&&"error"in r?String(r.error):`Vivipilot API request failed with status ${n.status}`,g=n.status===402?" Run `vivipilot topup` to buy credits.":"";throw new i(`${l}${g}`,n.status===401?2:1)}return r}async whoami(){return this.requestJson("/api/v1/me")}async balance(){return this.requestJson("/api/v1/credits/balance")}async estimate(e){return this.requestJson("/api/v1/layouts/estimate",{method:"POST",body:JSON.stringify(e)})}async generate(e,t){return this.requestJson("/api/v1/layouts/generate",{method:"POST",headers:{"idempotency-key":t},body:JSON.stringify({...e,outputFormat:"manifest"})})}async startGenerate(e,t){return this.requestJson("/api/v1/layouts/generate/start",{method:"POST",headers:{"idempotency-key":t},body:JSON.stringify({...e,outputFormat:"manifest"})})}async generationProgress(e){return this.requestJson(`/api/v1/layouts/${encodeURIComponent(e)}?progress=true`)}async generationStatus(e){return this.requestJson(`/api/v1/layouts/${encodeURIComponent(e)}`)}};export{u as a};
@@ -0,0 +1 @@
1
+ import{f as v,g as b,h as k,i as _}from"./chunk-L3C7EOPY.js";import{readFile as V}from"fs/promises";var C="vivipilot.renderManifest.v1",w="Ed25519",y={name:w},h=/^[a-f0-9]{64}$/i;function n(e,t){return{ok:!1,reason:e,message:t}}function d(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function a(e){return typeof e=="string"&&e.length>0}function c(e){return typeof e=="number"&&Number.isFinite(e)&&e>0}function g(e,t="$"){if(e===null)return;let r=typeof e;if(!(r==="string"||r==="boolean")){if(r==="number"){if(!Number.isFinite(e))throw new Error(`Non-finite number at ${t}`);return}if(Array.isArray(e)){e.forEach((i,s)=>g(i,`${t}[${s}]`));return}if(r==="object"){for(let[i,s]of Object.entries(e)){if(s===void 0)throw new Error(`Undefined value at ${t}.${i}`);g(s,`${t}.${i}`)}return}throw new Error(`Unsupported JSON value at ${t}`)}}function p(e){return g(e),e===null||typeof e!="object"?JSON.stringify(e):Array.isArray(e)?`[${e.map(t=>p(t)).join(",")}]`:`{${Object.entries(e).filter(([,t])=>t!==void 0).sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>`${JSON.stringify(t)}:${p(r)}`).join(",")}}`}function A(e){return new TextEncoder().encode(e)}function R(e){let t=e.replace(/-/g,"+").replace(/_/g,"/"),r=t.padEnd(t.length+(4-t.length%4)%4,"="),i=atob(r),s=new Uint8Array(i.length);for(let l=0;l<i.length;l++)s[l]=i.charCodeAt(l);return s}function E(e){return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}function x(e){return e??globalThis.crypto??null}async function M(e,t){let r=x(t);if(!r?.subtle)throw new Error("crypto_unavailable");let i=typeof e=="string"?A(e):e,s=await r.subtle.digest("SHA-256",i);return new Uint8Array(s)}async function H(e,t){return[...await M(e,t)].map(r=>r.toString(16).padStart(2,"0")).join("")}function I(e){let t={...e};return delete t.signature,t}function N(e){let t=I(e);return{...t,integrity:{...t.integrity,canonicalPayloadHash:""}}}function U(e){return p(I(e))}async function T(e,t){return H(p(N(e)),t)}async function q(e,t){return e instanceof CryptoKey?e:typeof e=="string"?t.subtle.importKey("raw",E(R(e)),y,!1,["verify"]):t.subtle.importKey("jwk",e,y,!1,["verify"])}function K(e){return d(e)?a(e.assetId)&&a(e.url)&&a(e.sha256)&&h.test(e.sha256)&&a(e.mimeType)&&c(e.byteLength):!1}function O(e){return d(e)?e.schema!==C?n("invalid_shape","Unsupported render manifest schema."):a(e.manifestId)?a(e.generationId)?a(e.userId)?!a(e.createdAt)||Number.isNaN(Date.parse(e.createdAt))?n("invalid_shape","createdAt must be an ISO date string."):e.expiresAt!==void 0&&(!a(e.expiresAt)||Number.isNaN(Date.parse(e.expiresAt)))?n("invalid_shape","expiresAt must be an ISO date string when provided."):a(e.engineVersion)?d(e.entitlement)?d(e.billing)?a(e.billing.creditTransactionId)?c(e.billing.creditsCharged)?a(e.billing.idempotencyKey)?a(e.billing.creditSource)?d(e.render)?d(e.render.canvas)?!c(e.render.canvas.width)||!c(e.render.canvas.height)||!c(e.render.canvas.fps)?n("invalid_shape","render.canvas dimensions and fps must be positive."):c(e.render.durationFrames)?Array.isArray(e.render.overlays)?e.render.assets!==void 0&&(!Array.isArray(e.render.assets)||!e.render.assets.every(K))?n("invalid_shape","render.assets must contain immutable asset references with SHA-256 hashes."):d(e.integrity)?!a(e.integrity.canonicalPayloadHash)||!h.test(e.integrity.canonicalPayloadHash)?n("invalid_shape","integrity.canonicalPayloadHash must be a SHA-256 hex digest."):!a(e.integrity.sceneHash)||!h.test(e.integrity.sceneHash)?n("invalid_shape","integrity.sceneHash must be a SHA-256 hex digest."):d(e.signature)?e.signature.alg!==w?n("invalid_shape","Unsupported signature algorithm."):a(e.signature.keyId)?a(e.signature.value)?{ok:!0,manifest:e,canonicalPayloadHash:e.integrity.canonicalPayloadHash}:n("invalid_shape","signature.value is required."):n("invalid_shape","signature.keyId is required."):n("invalid_shape","signature is required."):n("invalid_shape","integrity is required."):n("invalid_shape","render.overlays must be an array."):n("invalid_shape","render.durationFrames must be positive."):n("invalid_shape","render.canvas is required."):n("invalid_shape","render payload is required."):n("invalid_shape","billing.creditSource is required."):n("invalid_shape","billing.idempotencyKey is required."):n("invalid_shape","billing.creditsCharged must be positive."):n("invalid_shape","billing.creditTransactionId is required."):n("invalid_shape","billing is required."):n("invalid_shape","entitlement is required."):n("invalid_shape","engineVersion is required."):n("invalid_shape","userId is required."):n("invalid_shape","generationId is required."):n("invalid_shape","manifestId is required."):n("invalid_shape","Manifest must be an object.")}async function P(e,t){return typeof t=="function"?t(e):Array.isArray(t)?t.find(r=>r.keyId===e)?.publicKey:t[e]}function F(e,t=new Date){return typeof e.expiresAt=="string"&&Date.parse(e.expiresAt)<=t.getTime()}async function S(e,t){let r=O(e);if(!r.ok)return r;let i=r.manifest;if((t.checkExpiry??!0)&&F(i,t.now??new Date))return n("expired","Render manifest has expired.");let s;try{s=await T(i,t.crypto)}catch(o){return n("crypto_unavailable",o instanceof Error?o.message:"Unable to hash manifest payload.")}if(s!==i.integrity.canonicalPayloadHash)return n("invalid_canonical_payload_hash","Manifest canonical payload hash does not match payload.");let l=await P(i.signature.keyId,t.publicKeys);if(!l)return n("missing_public_key",`No public key registered for keyId ${i.signature.keyId}.`);let f=x(t.crypto);if(!f?.subtle)return n("crypto_unavailable","WebCrypto subtle crypto is unavailable.");try{let o=await q(l,f);if(!await f.subtle.verify(y,o,E(R(i.signature.value)),A(U(i))))return n("invalid_signature","Manifest signature is invalid.")}catch(o){return n("invalid_key",o instanceof Error?o.message:"Unable to import or verify public key.")}return{ok:!0,manifest:i,canonicalPayloadHash:s}}async function j(e){return JSON.parse(await V(e,"utf8"))}async function W(e,t,r=process.env){let i=await j(e);return S(i,{publicKeys:k(t,r)})}async function Q(e,t,r=process.env,i=fetch){let s=b(t,r);if(!s)return{revoked:!1,revokedAt:null,checked:!1,error:"no_api_key"};let f=`${v(t,r)}/api/v1/manifests/${encodeURIComponent(e.manifestId)}/revocation`,o=new AbortController,$=setTimeout(()=>o.abort(),5e3);try{let u=await i(f,{headers:{authorization:`Bearer ${s}`},signal:o.signal});if(!u.ok)return{revoked:!1,revokedAt:null,checked:!1,error:`http_${u.status}`};let m=await u.json();return{revoked:m.revoked===!0,revokedAt:m.revokedAt??null,checked:!0}}catch(u){return{revoked:!1,revokedAt:null,checked:!1,error:u instanceof Error?u.message:String(u)}}finally{clearTimeout($)}}function X(e){if(e.checked&&e.revoked)throw new _(`Manifest has been revoked server-side${e.revokedAt?` at ${new Date(e.revokedAt).toISOString()}`:""}. Generate a new manifest with \`vivipilot generate\`.`,1)}var D={"720p":720,"1080p":1080,"2k":1440,"4k":2160};function Y(e,t){let r=D[e.entitlement.maxResolution],i=t.height??e.render.canvas.height;return i>r?{ok:!1,reason:"resolution_exceeds_entitlement",message:`Requested height ${i}px exceeds the manifest entitlement (${e.entitlement.maxResolution}, max ${r}px). Top up or generate a higher-entitlement manifest.`}:t.format&&Array.isArray(e.entitlement.allowedFormats)&&e.entitlement.allowedFormats.length>0&&!e.entitlement.allowedFormats.includes(t.format)?{ok:!1,reason:"format_not_allowed",message:`Format ${t.format} is not allowed by this manifest entitlement. Allowed: ${e.entitlement.allowedFormats.join(", ")}.`}:{ok:!0}}export{j as a,W as b,Q as c,X as d,Y as e};
@@ -0,0 +1,8 @@
1
+ import{b as U,c as D,d as F,e as j}from"./chunk-FN7FHZ3D.js";import{f as _,i as w}from"./chunk-L3C7EOPY.js";import{spawn as le}from"child_process";import{createServer as K}from"http";import{readFile as k,writeFile as I,access as W,stat as he,mkdir as de}from"fs/promises";import{constants as ue,openSync as me,writeSync as V,closeSync as fe}from"fs";import{join as C}from"path";import{createHash as pe}from"crypto";import{existsSync as ne}from"fs";import{access as oe,constants as se}from"fs/promises";import{homedir as E}from"os";import{join as g}from"path";var O=class extends Error{constructor(e){super(e),this.name="BrowserNotFoundError"}};async function G(t=process.env){let e=t.VIVIPILOT_HEADLESS_BROWSER;if(e&&await S(e))return{executablePath:e,source:"env"};let r=await ae();if(r)return{executablePath:r,source:"chrome-headless-shell"};let a=await ie();if(a)return{executablePath:a,source:"system-chrome"};let o=await ce();if(o)return{executablePath:o,source:"system-chromium"};throw new O(`No headless browser found. To install a lightweight headless browser automatically, run:
2
+ npx @puppeteer/browsers install chrome-headless-shell
3
+
4
+ Alternatively, install Chrome/Chromium on your system, or set VIVIPILOT_HEADLESS_BROWSER to your binary path.`)}async function S(t){try{return await oe(t,se.X_OK),!0}catch{return!1}}async function ae(){let t=[process.env.PUPPETEER_EXECUTABLE_PATH,g(E(),".cache","puppeteer","chrome-headless-shell"),"/usr/bin/chrome-headless-shell","/usr/local/bin/chrome-headless-shell","/snap/bin/chrome-headless-shell",g(E(),".local","share","chrome-headless-shell","chrome-headless-shell"),"/opt/chrome-headless-shell/chrome-headless-shell","/Applications/Google Chrome Headless Shell.app/Contents/MacOS/Google Chrome Headless Shell",g(E(),"AppData","Local","chrome-headless-shell","chrome-headless-shell.exe")];for(let e of t)if(e){if(await S(e))return e;if(ne(e)&&!e.endsWith("chrome-headless-shell")&&!e.endsWith(".exe")){let{readdirSync:r}=await import("fs");try{let a=r(e,{withFileTypes:!0});for(let o of a){if(!o.isDirectory())continue;let h=g(e,o.name,"chrome-headless-shell");if(await S(h))return h;let i=g(e,o.name,"chrome-headless-shell.exe");if(await S(i))return i}}catch{}}}return null}async function ie(){let t=["/usr/bin/google-chrome","/usr/bin/google-chrome-stable","/usr/bin/google-chrome-unstable","/usr/local/bin/google-chrome","/opt/google/chrome/chrome","/snap/bin/google-chrome","/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",g(E(),"AppData","Local","Google","Chrome","Application","chrome.exe"),"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe","C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"];for(let e of t)if(await S(e))return e;return null}async function ce(){let t=["/usr/bin/chromium","/usr/bin/chromium-browser","/usr/local/bin/chromium","/snap/bin/chromium","/usr/bin/brave-browser","/usr/bin/brave","/Applications/Chromium.app/Contents/MacOS/Chromium",g(E(),"AppData","Local","Chromium","Application","chromium.exe"),"C:\\Program Files\\Chromium\\Application\\chromium.exe"];for(let e of t)if(await S(e))return e;return null}function J(t,e){let r=e?.windowSize?.width??1920,a=e?.windowSize?.height??1080;return["--headless=new","--no-sandbox","--disable-gpu-sandbox","--disable-dev-shm-usage","--disable-extensions","--disable-background-networking","--disable-sync","--disable-translate","--disable-default-apps","--disable-popup-blocking","--disable-component-update","--disable-metrics","--no-first-run","--mute-audio","--enable-logging=stderr","--log-level=0","--v=1",`--window-size=${r},${a}`,"--enable-features=Vulkan","--use-gl=angle","--use-angle=swiftshader","--enable-unsafe-swiftshader","--ignore-gpu-blocklist",...e?.extraArgs??[],t]}var we=3e5;function ge(t){return new Promise((e,r)=>{let a=null,o=null,h=K(async(i,c)=>{if(c.setHeader("Access-Control-Allow-Origin","*"),c.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),c.setHeader("Access-Control-Allow-Headers","Content-Type"),i.method==="OPTIONS"){c.writeHead(204),c.end();return}let p=new URL(i.url??"/","http://localhost");if(p.pathname==="/manifest.json"&&i.method==="GET"){try{let u=await k(t.replace(/\.mp4$|\.webm$|\.gif$|\.mov$/,".vivi.json"),"utf8");c.writeHead(200,{"content-type":"application/json"}),c.end(u)}catch{c.writeHead(404),c.end("Manifest not found")}return}if(p.pathname==="/result"&&i.method==="POST"){let u=[];i.on("data",m=>u.push(m)),i.on("end",async()=>{a=Buffer.concat(u);try{await I(t,a),c.writeHead(200,{"content-type":"application/json"}),c.end(JSON.stringify({ok:!0,size:a.length}))}catch(m){c.writeHead(500,{"content-type":"application/json"}),c.end(JSON.stringify({ok:!1,error:m instanceof Error?m.message:String(m)}))}});return}if(p.pathname==="/error"&&i.method==="POST"){let u=[];i.on("data",m=>u.push(m)),i.on("end",()=>{try{o=JSON.parse(Buffer.concat(u).toString()).message??"Unknown render error"}catch{o=Buffer.concat(u).toString()||"Unknown render error"}c.writeHead(200,{"content-type":"application/json"}),c.end(JSON.stringify({ok:!0}))});return}if(p.pathname==="/status"&&i.method==="GET"){c.writeHead(200,{"content-type":"application/json"}),c.end(JSON.stringify({done:a!==null||o!==null,error:o,hasBlob:a!==null,blobSize:a?.length??0}));return}c.writeHead(404),c.end("Not found")});h.on("error",r),h.listen(0,"127.0.0.1",()=>{let i=h.address();if(!i||typeof i=="string"){r(new Error("Failed to bind callback server"));return}e({server:h,port:i.port})})})}async function be(t,e){let r=Date.now()+e;for(;Date.now()<r;){try{let o=await(await fetch(`http://127.0.0.1:${t}/status`)).json();if(o.done)return o.error?{size:0,error:o.error}:{size:o.blobSize,error:null}}catch{}await new Promise(a=>setTimeout(a,1e3))}return{size:0,error:`Render timed out after ${e/1e3}s`}}async function Ne(t,e,r=process.env){let{manifestPath:a,outPath:o}=t,h=await U(a,e,r);if(!h.ok)throw new w(`Manifest verification failed: ${h.message}`,1);let i=await D(h.manifest,e,r);F(i);let c={...t.format?{format:t.format}:{},...t.width?{width:t.width}:{},...t.height?{height:t.height}:{}},p=j(h.manifest,c);if(!p.ok)throw new w(p.message,1);if(t.verifyOnly)return{ok:!0,outPath:o,size:0,manifestId:h.manifest.manifestId};let u;try{u=await G(r)}catch(n){throw n instanceof O?new w(n.message,1):n}let m=await k(a,"utf8"),b=JSON.parse(m),$=b.render.canvas,B="";if(b.render.assets&&Array.isArray(b.render.assets))try{B=await ye(b.render.assets)}catch(n){throw new w(`Failed to cache assets: ${n instanceof Error?n.message:String(n)}`,1)}let{server:X}=await ge(o);X.close();let P=null,x=!1,N=0,v=K((n,s)=>{if(s.setHeader("Access-Control-Allow-Origin","*"),s.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),s.setHeader("Access-Control-Allow-Headers","Content-Type"),n.method==="OPTIONS"){s.writeHead(204),s.end();return}let f=new URL(n.url??"/","http://localhost");if(B&&f.pathname.startsWith("/assets/")&&n.method==="GET"){let d=f.pathname.slice(8),l=C(B,d);k(l).then(y=>{let te=b.render.assets?.find(re=>re.sha256===d);s.writeHead(200,{"content-type":te?.mimeType||"application/octet-stream"}),s.end(y)}).catch(()=>{s.writeHead(404),s.end("Asset not found")});return}if(f.pathname==="/manifest.json"&&n.method==="GET"){let d={...b};d.render?.assets&&(d.render.assets=d.render.assets.map(l=>({...l,url:`http://127.0.0.1:${A}/assets/${l.sha256}`}))),s.writeHead(200,{"content-type":"application/json"}),s.end(JSON.stringify(d));return}if(f.pathname==="/result"&&n.method==="POST"){let d=[];n.on("data",l=>d.push(l)),n.on("end",async()=>{let l=Buffer.concat(d);try{await I(o,l),x=!0,N=l.length,s.writeHead(200,{"content-type":"application/json"}),s.end(JSON.stringify({ok:!0,size:l.length}))}catch(y){P=y instanceof Error?y.message:String(y),s.writeHead(500,{"content-type":"application/json"}),s.end(JSON.stringify({ok:!1,error:P}))}});return}if(f.pathname==="/error"&&n.method==="POST"){let d=[];n.on("data",l=>d.push(l)),n.on("end",()=>{let l="Unknown render error";try{l=JSON.parse(Buffer.concat(d).toString()).message??l}catch{l=Buffer.concat(d).toString()||l}P=l,s.writeHead(200,{"content-type":"application/json"}),s.end(JSON.stringify({ok:!0,error:l}))});return}if(f.pathname==="/status"&&n.method==="GET"){s.writeHead(200,{"content-type":"application/json"}),s.end(JSON.stringify({done:x||P!==null,error:P,hasBlob:x,blobSize:N}));return}s.writeHead(404),s.end("Not found")}),A=await new Promise((n,s)=>{v.on("error",s),v.listen(0,"127.0.0.1",()=>{let f=v.address();if(!f||typeof f=="string"){s(new Error("Failed to bind manifest server"));return}n(f.port)})}),Y=r.VIVIPILOT_RENDER_URL??`${_(e,r)}/headless-render`,R=new URLSearchParams({manifest:`http://127.0.0.1:${A}/manifest.json`,format:t.format??"mp4",headless:"true",callback:`http://127.0.0.1:${A}/result`});t.scale&&R.set("scale",String(t.scale)),t.transparent&&R.set("transparent","true"),t.fps&&R.set("fps",String(t.fps));let Q=`${Y}?${R.toString()}`,Z=J(Q,{windowSize:{width:Math.max($.width,1280),height:Math.max($.height,720)}}),T=le(u.executablePath,Z,{stdio:["ignore","pipe","pipe"],env:{...r,DISPLAY:r.DISPLAY??":99"}}),q=C(process.cwd(),"host","chrome_browser.log"),H=me(q,"w"),L="",z="";T.stderr?.on("data",n=>{L+=n.toString();try{V(H,n)}catch{}}),T.stdout?.on("data",n=>{z+=n.toString();try{V(H,n)}catch{}});let ee=parseInt(r.VIVIPILOT_RENDER_TIMEOUT_MS??String(we),10),M=await be(A,ee);T.kill("SIGTERM"),setTimeout(()=>{try{T.kill("SIGKILL")}catch{}},5e3),v.close();try{fe(H)}catch{}if(M.error)throw new w(`Render failed: ${M.error}
5
+ Browser stderr (last 2KB):
6
+ ${L.slice(-2e3)}
7
+ Browser stdout (last 1KB):
8
+ ${z.slice(-1e3)}`,1);try{await W(o,ue.R_OK);let n=await he(o);return{ok:!0,outPath:o,size:n.size,manifestId:h.manifest.manifestId}}catch{throw new w(`Render completed but output file not found at ${o}`,1)}}async function ye(t){let e=C(process.env.HOME||process.env.USERPROFILE||process.cwd(),".cache","vivipilot","assets");await de(e,{recursive:!0});for(let r of t){if(!r.sha256||!r.url)continue;let a=C(e,r.sha256);try{await W(a);continue}catch{}let o=await fetch(r.url);if(!o.ok)throw new Error(`Failed to download asset ${r.url}: HTTP ${o.status}`);let h=Buffer.from(await o.arrayBuffer()),i=pe("sha256").update(h).digest("hex");if(i!==r.sha256)throw new Error(`Asset hash mismatch for ${r.url}: expected ${r.sha256}, got ${i}`);await I(a,h)}return e}export{Ne as a};
@@ -0,0 +1,2 @@
1
+ import{mkdir as s,readFile as c,rm as I,writeFile as f}from"fs/promises";import{homedir as u}from"os";import{dirname as a,join as e}from"path";var p="https://vivipilot.com";function l(r){return r.XDG_CONFIG_HOME?r.XDG_CONFIG_HOME:r.APPDATA?r.APPDATA:e(u(),".config")}function o(r=process.env){return r.VIVIPILOT_CONFIG??e(l(r),"vivipilot","config.json")}function g(r){return typeof r=="object"&&r!==null&&"code"in r&&r.code==="ENOENT"}async function E(r=o()){try{let i=await c(r,"utf8"),n=JSON.parse(i);return n&&typeof n=="object"&&!Array.isArray(n)?n:{}}catch(i){if(g(i))return{};throw i}}async function P(r,i=o()){await s(a(i),{recursive:!0}),await f(i,`${JSON.stringify(r,null,2)}
2
+ `,{mode:384})}async function y(r=o()){await I(r,{force:!0})}function A(r,i=process.env){return(i.VIVIPILOT_API_URL??r.apiUrl??p).replace(/\/+$/,"")}function m(r,i=process.env){let n=i.VIVIPILOT_API_KEY??r.apiKey;return n&&n.trim().length>0?n.trim():void 0}function T(r,i=process.env){if(i.VIVIPILOT_MANIFEST_PUBLIC_KEYS){let n=JSON.parse(i.VIVIPILOT_MANIFEST_PUBLIC_KEYS);if(n&&typeof n=="object"&&!Array.isArray(n))return n}return i.VIVIPILOT_MANIFEST_PUBLIC_KEY_ID&&i.VIVIPILOT_MANIFEST_PUBLIC_KEY?{[i.VIVIPILOT_MANIFEST_PUBLIC_KEY_ID]:i.VIVIPILOT_MANIFEST_PUBLIC_KEY}:r.publicKeys??{}}var t=class extends Error{exitCode;constructor(i,n=1){super(i),this.name="CliError",this.exitCode=n}};function O(r){return r instanceof t}export{p as a,o as b,E as c,P as d,y as e,A as f,m as g,T as h,t as i,O as j};
@@ -0,0 +1,3 @@
1
+ import{a as k}from"./chunk-FGUKEVKT.js";import{f as b}from"./chunk-L3C7EOPY.js";import{mkdir as V,writeFile as E}from"fs/promises";import{dirname as x}from"path";import{createInterface as A}from"readline";import{randomUUID as q}from"crypto";var J="2025-06-18";function S(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function g(e,o){let n=e[o];return typeof n=="number"&&Number.isFinite(n)?n:void 0}function p(e,o){let n=e[o];return typeof n=="string"&&n.trim()?n.trim():void 0}function P(e){let o=p(e,"prompt");if(!o)throw new Error("prompt is required");let n=p(e,"engine"),l=n==="pixi"||n==="three"||n==="auto"?n:void 0,m=g(e,"width"),r=g(e,"height"),t=g(e,"fps"),i=g(e,"durationSeconds")??g(e,"duration");return{prompt:o,...m||r||t?{canvas:{width:m,height:r,fps:t}}:{},...i?{durationSeconds:i}:{},...l?{enginePreference:l}:{}}}function u(e,o=!1){return{content:[{type:"text",text:JSON.stringify(e,null,2)}],structuredContent:e,isError:o}}function M(e){let o=e instanceof Error?e.message:String(e);return u({ok:!1,error:o},!0)}async function R(e,o){await V(x(e),{recursive:!0}),await E(e,`${JSON.stringify(o,null,2)}
2
+ `,"utf8")}async function T(e,o,n){let{verifyManifestFile:l}=await import("./manifest-TDCIHZ46.js");return l(e,o,n)}function N(){return[{name:"vivipilot_get_balance",title:"Get Vivipilot paid credit balance",description:"Returns Vivipilot account balance and paid top-up balance. CLI/MCP generation is paid-only and never grants trial credits.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"vivipilot_estimate_motion_layout",title:"Estimate Vivipilot motion layout credits",description:"Estimates paid credits for a cloud layout generation. This does not burn credits.",inputSchema:{type:"object",properties:{prompt:{type:"string"},width:{type:"number"},height:{type:"number"},fps:{type:"number"},durationSeconds:{type:"number"},engine:{type:"string",enum:["pixi","three","auto"]}},required:["prompt"],additionalProperties:!1}},{name:"vivipilot_generate_motion_layout",title:"Generate signed Vivipilot render manifest",description:"Paid-only cloud generation. Burns paid credits only after cloud orchestration is wired; local rendering uses the client's hardware.",inputSchema:{type:"object",properties:{prompt:{type:"string"},out:{type:"string"},idempotencyKey:{type:"string"},width:{type:"number"},height:{type:"number"},fps:{type:"number"},durationSeconds:{type:"number"},engine:{type:"string",enum:["pixi","three","auto"]}},required:["prompt"],additionalProperties:!1}},{name:"vivipilot_verify_manifest",title:"Verify Vivipilot render manifest",description:"Verifies a signed Vivipilot manifest locally using public keys. This does not burn credits.",inputSchema:{type:"object",properties:{manifestPath:{type:"string"}},required:["manifestPath"],additionalProperties:!1}},{name:"vivipilot_render_video",title:"Render Vivipilot video locally",description:"Renders a signed manifest on local hardware after signature verification. No cloud rendering is used.",inputSchema:{type:"object",properties:{manifestPath:{type:"string"},out:{type:"string"},verifyOnly:{type:"boolean"}},required:["manifestPath"],additionalProperties:!1}},{name:"vivipilot_get_generation_status",title:"Get Vivipilot generation status",description:"Checks cloud status for a Vivipilot layout generation. This does not burn credits.",inputSchema:{type:"object",properties:{generationId:{type:"string"}},required:["generationId"],additionalProperties:!1}}]}async function O(e,o,n,l,m){let r=S(o)?o:{};try{switch(e){case"vivipilot_get_balance":{let t=await n.balance(),a=(typeof t.paidBalance=="number"?t.paidBalance:0)>0?[{tool:"vivipilot_estimate_motion_layout",reason:"Estimate credits for a generation before spending."},{tool:"vivipilot_generate_motion_layout",reason:"Generate a signed manifest (paid credits will be burned)."}]:[{action:"topup",reason:`Buy credits at ${b(l,m)}/edit?billing=topup before generating. CLI/MCP generation is paid-only.`}];return u({ok:!0,...t,nextActions:a})}case"vivipilot_estimate_motion_layout":{let t=await n.estimate(P(r)),i=typeof t.estimatedCredits=="number"?t.estimatedCredits:0;return u({ok:!0,...t,nextActions:[{tool:"vivipilot_generate_motion_layout",reason:`Generate now for ~${i} credits (paid-only).`},{tool:"vivipilot_get_balance",reason:"Check balance before generating."}]})}case"vivipilot_generate_motion_layout":{let t=p(r,"out")??"scene.vivi.json",i=p(r,"idempotencyKey")??`mcp_${q()}`,a=P(r),f=await n.startGenerate({...a,outputFormat:"manifest"},i),d=f.generationId;if(f.idempotentReplay&&f.status==="completed"){let s=await n.generationProgress(d);if(s.manifestData)return await R(t,s.manifestData),u({ok:!0,generationId:d,manifestPath:t,creditsCharged:s.creditsCharged??null,status:"completed",nextActions:[{tool:"vivipilot_verify_manifest",args:{manifestPath:t},reason:"Verify the signed manifest locally before rendering."},{tool:"vivipilot_render_video",args:{manifestPath:t},reason:"Render the manifest to video on local hardware."}]})}let v=3e5,_=2e3,w=Date.now(),c="";for(;Date.now()-w<v;){await new Promise(I=>setTimeout(I,_));let s;try{s=await n.generationProgress(d)}catch{continue}if(s.progressMessage&&s.progressMessage!==c&&(c=s.progressMessage),s.status==="completed"&&s.manifestData)return await R(t,s.manifestData),u({ok:!0,generationId:d,manifestPath:t,creditsCharged:s.creditsCharged??null,engine:s.engine,status:"completed",progressLog:c,nextActions:[{tool:"vivipilot_verify_manifest",args:{manifestPath:t},reason:"Verify the signed manifest locally before rendering."},{tool:"vivipilot_render_video",args:{manifestPath:t},reason:"Render the manifest to video on local hardware."}]});if(s.status==="failed")return u({ok:!1,generationId:d,error:s.error??"Generation failed.",progressLog:c,nextActions:[{tool:"vivipilot_generate_motion_layout",reason:"Retry with a new prompt or idempotency key."},{tool:"vivipilot_get_balance",reason:"Check balance before retrying."}]},!0)}return u({ok:!1,generationId:d,error:"Generation timed out after 5 minutes.",nextActions:[{tool:"vivipilot_get_generation_status",args:{generationId:d},reason:"Check if generation completed after timeout."}]},!0)}case"vivipilot_verify_manifest":{let t=p(r,"manifestPath");if(!t)throw new Error("manifestPath is required");let i=await T(t,l,m);if(!i.ok)throw new Error(i.message);return u({ok:!0,manifestId:i.manifest.manifestId,generationId:i.manifest.generationId,canonicalPayloadHash:i.canonicalPayloadHash,nextActions:[{tool:"vivipilot_render_video",args:{manifestPath:t},reason:"Render the verified manifest to video."}]})}case"vivipilot_render_video":{let t=p(r,"manifestPath");if(!t)throw new Error("manifestPath is required");let i=p(r,"out")??"video.mp4",a=p(r,"format"),f=g(r,"scale"),d=g(r,"fps"),v=r.transparent===!0,_=r.verifyOnly===!0,{renderManifest:w}=await import("./render-CVXYAUBY.js"),c=await w({manifestPath:t,outPath:i,...a?{format:a}:{},...f?{scale:f}:{},...d?{fps:d}:{},...v?{transparent:v}:{},verifyOnly:_},l,m);return u({ok:!0,manifestId:c.manifestId,out:c.outPath,size:c.size,nextActions:[{action:"file_ready",reason:`Video written to ${c.outPath} (${(c.size/1024/1024).toFixed(2)} MB).`}]})}case"vivipilot_get_generation_status":{let t=p(r,"generationId");if(!t)throw new Error("generationId is required");let i=await n.generationProgress(t),a=[];return i.status==="completed"&&i.manifest?(a.push({tool:"vivipilot_verify_manifest",reason:"Verify the completed manifest."}),a.push({tool:"vivipilot_render_video",reason:"Render the completed manifest to video."})):i.status==="failed"?(a.push({tool:"vivipilot_generate_motion_layout",reason:"Retry with a new idempotency key."}),a.push({tool:"vivipilot_get_balance",reason:"Check balance before retrying."})):a.push({tool:"vivipilot_get_generation_status",args:{generationId:t},reason:"Poll again \u2014 generation still in progress."}),u({ok:!0,...i,nextActions:a})}default:throw new Error(`Unknown tool: ${e}`)}}catch(t){return M(t)}}function C(e,o){e.write(`${JSON.stringify(o)}
3
+ `)}function y(e,o,n){C(e,{jsonrpc:"2.0",id:o,result:n})}function h(e,o,n,l){C(e,{jsonrpc:"2.0",id:o??null,error:{code:n,message:l}})}async function F(e){let o=e.env??process.env,n=new k({config:e.config,env:o}),l=A({input:e.stdin});for await(let m of l){let r=m.trim();if(!r)continue;let t;try{t=JSON.parse(r)}catch{h(e.stdout,null,-32700,"Parse error");continue}let i=t.id;try{switch(t.method){case"initialize":y(e.stdout,i??null,{protocolVersion:J,capabilities:{tools:{listChanged:!1}},serverInfo:{name:"vivipilot",title:"Vivipilot MCP",version:"0.1.0"},instructions:"Vivipilot generation tools are paid-only and require VIVIPILOT_API_KEY or `vivipilot login` configuration. Local render tools use the client's hardware."});break;case"notifications/initialized":break;case"ping":y(e.stdout,i??null,{});break;case"tools/list":y(e.stdout,i??null,{tools:N()});break;case"tools/call":{if(!S(t.params)||typeof t.params.name!="string"){h(e.stdout,i,-32602,"tools/call requires params.name");break}let a=await O(t.params.name,t.params.arguments,n,e.config,o);y(e.stdout,i??null,a);break}default:i!==void 0&&h(e.stdout,i,-32601,`Method not found: ${t.method??""}`)}}catch(a){let f=a instanceof Error?a.message:String(a);i!==void 0&&h(e.stdout,i,-32603,f)}}}export{F as a};
@@ -0,0 +1 @@
1
+ function g(r){return r.replace(/^-+/,"").trim()}function d(r){let[t,...n]=r,e={},o=[];for(let i=0;i<n.length;i++){let s=n[i];if(s==="--"){o.push(...n.slice(i+1));break}if(s.startsWith("--")){let a=s.indexOf("=");if(a>-1){e[g(s.slice(0,a))]=s.slice(a+1);continue}let l=g(s),u=n[i+1];u&&!u.startsWith("-")?(e[l]=u,i++):e[l]=!0;continue}o.push(s)}return{command:t,flags:e,positionals:o}}function f(r,t){for(let n of t){let e=r.flags[n];if(typeof e=="string"&&e.length>0)return e}}function c(r,t){return t.some(n=>r.flags[n]===!0||r.flags[n]==="true")}function p(r,t){let n=f(r,t);if(n===void 0)return;let e=Number(n);return Number.isFinite(e)?e:void 0}export{d as a,f as b,c,p as d};
package/dist/cli.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { type Env } from "./config.js";
2
+ import { E as Env } from './config-DAG58pP-.js';
3
+
3
4
  type WritableLike = {
4
5
  write(chunk: string): void;
5
6
  };
@@ -7,6 +8,6 @@ type CliIo = {
7
8
  stdout: WritableLike;
8
9
  stderr: WritableLike;
9
10
  };
10
- export declare function runCli(argv?: string[], env?: Env, io?: CliIo): Promise<void>;
11
- export {};
12
- //# sourceMappingURL=cli.d.ts.map
11
+ declare function runCli(argv?: string[], env?: Env, io?: CliIo): Promise<void>;
12
+
13
+ export { runCli };