@mynthio/cli 0.0.17 → 0.0.18

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 (2) hide show
  1. package/dist/bin.js +8 -8
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import {Command,Option,Help}from'commander';import {z}from'zod';import*as $ from'cross-keychain';import {readFile,mkdir,writeFile,chmod,rm,stat}from'fs/promises';import {homedir}from'os';import {resolve,join,extname,basename}from'path';import wt from'chalk';import Cn from'ora';var A=class extends Error{_tag="MynthCliError";cause;constructor(e){super(e.message),this.name=this._tag,this.cause=e.cause;}},l=class extends Error{_tag="CliUsageError";constructor(e){super(e),this.name=this._tag;}},R=class extends Error{_tag="NotAuthenticatedError";constructor(e={}){super(e.reason??"not authenticated"),this.name=this._tag;}},S=class extends Error{_tag="CredentialsStoreError";cause;constructor(e){super(e.message),this.name=this._tag,this.cause=e.cause;}},b=class extends Error{_tag="WorkOSError";code;status;cause;constructor(e){super(e.message),this.name=this._tag,this.code=e.code,this.status=e.status,this.cause=e.cause;}},C=class extends Error{_tag="AuthorizationPendingError";slowDown;constructor(e){super("authorization pending"),this.name=this._tag,this.slowDown=e.slowDown;}},E=class extends Error{_tag="AuthorizationExpiredError";constructor(){super("authorization expired"),this.name=this._tag;}},P=class extends Error{_tag="AuthorizationDeniedError";constructor(){super("authorization denied"),this.name=this._tag;}},k={error:1,usage:2,auth:3,insufficientCredits:4,moderation:5,rateLimited:6},$t={UNAUTHORIZED:k.auth,VALIDATION_ERROR:k.usage,INSUFFICIENT_BALANCE:k.insufficientCredits,RESTRICTED_CONTENT:k.moderation},De=t=>{if(t instanceof l)return k.usage;if(t instanceof R)return k.auth;if(t instanceof d){let n=t.code!==void 0?$t[t.code]:void 0;return n!==void 0?n:t.status===401||t.status===403?k.auth:t.status===429?k.rateLimited:k.error}let e=t.code;return typeof e=="string"&&e.startsWith("commander.")?k.usage:k.error},me=t=>{let e=t.result?.images,n=[...(t.errors??[]).map(s=>s.code),...(e??[]).map(s=>s.error?.code)].filter(s=>typeof s=="string");return n.find(s=>s==="RESTRICTED_CONTENT")??n[0]},Le=t=>me(t)==="RESTRICTED_CONTENT"?k.moderation:k.error,d=class extends Error{_tag="MynthApiError";status;code;cause;constructor(e){super(e.message),this.name=this._tag,this.status=e.status,this.code=e.code,this.cause=e.cause;}};var Ue=z.object({id:z.string(),email:z.string(),first_name:z.string().nullable().optional(),last_name:z.string().nullable().optional()}),Je=z.object({device_code:z.string(),user_code:z.string(),verification_uri:z.string(),verification_uri_complete:z.string().optional(),expires_in:z.number(),interval:z.number().optional()}),Fe=z.object({access_token:z.string(),refresh_token:z.string(),user:Ue.optional(),organization_id:z.string().optional()}),Ke=z.object({error:z.string().optional(),error_description:z.string().optional(),message:z.string().optional(),code:z.string().optional()}),Ct=z.object({kind:z.literal("oauth"),access_token:z.string(),refresh_token:z.string(),expires_at:z.number(),user:Ue.optional()}),Et=z.object({kind:z.literal("api_key"),api_key:z.string()}),ze=z.union([Ct,Et]),q=z.lazy(()=>z.union([z.string(),z.number(),z.boolean(),z.null(),z.array(q),z.record(q)])),We=z.object({data:z.object({urls:z.array(z.string())})}),Pt=z.union([z.object({status:z.literal("success"),url:z.string(),level:z.string()}),z.object({status:z.literal("failed"),url:z.string(),error:z.object({code:z.string()})})]),qe=z.object({data:z.object({task:z.object({id:z.string(),status:z.literal("completed"),cost:z.string()}),results:z.array(Pt)})}),Be=z.object({data:z.object({taskId:z.string(),estimatedCost:z.string().optional(),access:z.object({publicAccessToken:z.string()}).optional()})}),He=z.object({data:z.object({estimatedCost:z.string(),currency:z.string(),estimateKind:z.union([z.literal("exact"),z.literal("upper_bound")])})}),Ye=z.object({data:z.object({userId:z.string(),auth:z.object({method:z.string(),apiKey:z.object({id:z.string(),name:z.string().nullable(),keyPreview:z.string()}).optional()})})}),Ge=z.object({data:z.object({balance:z.string(),reserved:z.string(),available:z.string(),currency:z.string(),apiKey:z.object({spendingLimit:z.string(),spendingLimitPeriod:z.string(),usedInPeriod:z.string(),remainingInPeriod:z.string()}).optional()})}),B=z.object({data:z.object({status:z.union([z.literal("pending"),z.literal("completed"),z.literal("failed")])})}),Ot=z.object({id:z.string(),type:z.union([z.literal("image.generate"),z.literal("image.rate")]),status:z.union([z.literal("pending"),z.literal("completed"),z.literal("failed")]),userId:z.string(),apiKeyId:z.string().nullable(),cost:z.string().nullable(),request:q,result:q,errors:z.array(z.object({code:z.string()})).nullable().optional(),createdAt:z.string(),updatedAt:z.string()}),H=z.object({data:Ot}),It=z.object({id:z.string(),type:z.string(),status:z.string(),cost:z.string().nullable(),createdAt:z.string(),updatedAt:z.string()}),Ve=z.object({data:z.array(It)}),jt=z.object({perImage:z.object({base:z.string(),"4k":z.string().optional()}),perInput:z.string().optional()}),Mt=z.object({id:z.string(),displayName:z.string().nullable(),pricing:jt.nullable()}),Xe=z.object({data:z.array(Mt)});var Nt=t=>t.kind==="api_key"?t.apiKey:t.accessToken,x=async t=>{try{return await t.json()}catch(e){throw new d({message:`invalid JSON response: ${e.message}`,status:t.status,cause:e})}},N=async t=>{try{return await t.text()}catch{return ""}},w=async(t,e)=>{if(t.status>=200&&t.status<300)return;let n=await N(t),s;try{let a=JSON.parse(n);typeof a.code=="string"&&(s=a.code);}catch{}throw new d({message:`${e} failed (${t.status}): ${n||"no body"}`,status:t.status,...s!==void 0?{code:s}:{}})},Y=class{constructor(e,n){this.auth=n;this.baseUrl=e.mynthApiUrl;}baseUrl;cachedAuth;async execute(e,n={}){let s=await this.attempt(e,n,false);return s.status!==401?s:this.attempt(e,n,true)}async executePublic(e,n={}){try{return await fetch(`${this.baseUrl}${e}`,n)}catch(s){throw new d({message:`request failed: ${s.message}`,status:0,cause:s})}}async attempt(e,n,s){let a=await this.getAuth(s),i=new Headers(n.headers);i.set("Authorization",`Bearer ${Nt(a)}`);try{return await fetch(`${this.baseUrl}${e}`,{...n,headers:i})}catch(c){throw new d({message:`request failed: ${c.message}`,status:0,cause:c})}}async getAuth(e){return e&&(this.cachedAuth=void 0),this.cachedAuth!==void 0?this.cachedAuth:(this.cachedAuth=await this.auth.resolve(),this.cachedAuth)}};var G=class{constructor(e){this.api=e;}async me(){let e=await this.api.execute("/me");await w(e,"me");let n=Ye.safeParse(await x(e));if(!n.success)throw new d({message:"invalid me response",status:e.status,cause:n.error});return n.data.data}async balance(){let e=await this.api.execute("/balance");await w(e,"balance");let n=Ge.safeParse(await x(e));if(!n.success)throw new d({message:"invalid balance response",status:e.status,cause:n.error});return n.data.data}};var Dt=6e4,V=t=>t?{user:t}:{},pe=(t,e)=>new R({reason:e instanceof Error?`${t}: ${e.message}`:t}),X=class{constructor(e,n,s){this.config=e;this.store=n;this.workos=s;this.envApiKey=e.apiKeyEnvOverride,this.envApiKeySet=this.envApiKey!==void 0&&this.envApiKey.length>0;}envApiKeySet;envApiKey;async resolve(){if(this.envApiKeySet)return {kind:"api_key",apiKey:this.envApiKey,source:"env"};let e;try{e=await this.store.get();}catch(s){throw pe("could not read credentials",s)}if(e===void 0)throw new R({reason:"no credentials configured"});if(e.kind==="api_key")return {kind:"api_key",apiKey:e.api_key,source:"stored"};let n=await this.refreshIfNeeded(e);return {kind:"oauth",accessToken:n.access_token,...V(n.user)}}async status(){if(this.envApiKeySet)return {kind:"env",source:"MYNTH_API_KEY"};let e;try{e=await this.store.get();}catch{e=void 0;}return e===void 0?{kind:"none"}:e.kind==="api_key"?{kind:"api_key"}:{kind:"oauth",expiresAt:e.expires_at,...V(e.user)}}async setApiKey(e){await this.store.set({kind:"api_key",api_key:e});}async saveOAuth(e){await this.store.set({kind:"oauth",access_token:e.accessToken,refresh_token:e.refreshToken,expires_at:e.expiresAt,...V(e.user)});}async logout(){await this.store.clear();}async refreshIfNeeded(e){if(e.expires_at-Date.now()>Dt)return e;let n;try{n=await this.workos.refresh(e.refresh_token);}catch(a){throw pe("token refresh failed",a)}let s={kind:"oauth",access_token:n.token.access_token,refresh_token:n.token.refresh_token,expires_at:n.expiresAt,...V(n.token.user??e.user)};try{await this.store.set(s);}catch(a){throw pe("could not persist refreshed token",a)}return s}};var Ze=()=>{let t=process.env.MYNTH_API_KEY;return {mynthApiUrl:process.env.MYNTH_API_URL??"https://api.mynth.io",mynthDocsUrl:process.env.MYNTH_DOCS_URL??"https://docs.mynth.io",...t!==void 0?{apiKeyEnvOverride:t}:{}}};var ge="mynth-cli",he="default",qt="credentials.json",Bt=t=>{let e=t?.name;return e==="NoKeyringError"||e==="InitError"},Z=async(t,e)=>{try{return {available:true,value:await t()}}catch(n){if(Bt(n))return {available:false};throw new S({message:e,cause:n})}},Qe=t=>{let e;try{e=JSON.parse(t);}catch(s){throw new S({message:"credentials JSON parse failed",cause:s})}let n=ze.safeParse(e);if(!n.success)throw new S({message:"credentials shape invalid",cause:n.error});return n.data},et=t=>JSON.stringify(t),Ht=()=>{let t=process.env.XDG_CONFIG_HOME,e=t&&t.length>0?t:join(homedir(),".config");return join(e,"mynth")},tt=async t=>{try{return await stat(t),true}catch{return false}},Q=class{filePath;dir;constructor(){this.dir=Ht(),this.filePath=join(this.dir,qt);}async get(){let e=await Z(()=>$.getPassword(ge,he),"keychain get failed");if(e.available)return e.value===null?void 0:Qe(e.value);if(await tt(this.filePath))try{return Qe(await readFile(this.filePath,"utf8"))}catch(n){throw n instanceof S?n:new S({message:"read credentials file failed",cause:n})}}async set(e){if((await Z(()=>$.setPassword(ge,he,et(e)),"keychain set failed")).available){await this.deleteFileSilently();return}await mkdir(this.dir,{recursive:true}).catch(s=>{throw new S({message:"create config dir failed",cause:s})}),await writeFile(this.filePath,et(e),"utf8").catch(s=>{throw new S({message:"write credentials file failed",cause:s})}),await chmod(this.filePath,384).catch(()=>{});}async clear(){await Z(()=>$.deletePassword(ge,he),"keychain delete failed").catch(()=>{}),await this.deleteFileSilently();}async usingKeychain(){let e=await Z(()=>$.getKeyring(),"keychain probe failed");return e.available&&e.value!==null}async deleteFileSilently(){await tt(this.filePath)&&await rm(this.filePath).catch(e=>{throw new S({message:"delete credentials file failed",cause:e})});}};var Yt=t=>{if(t.length===0)return "no response body";try{let e=JSON.parse(t);if(typeof e.error=="string"&&e.error.length>0)return e.error}catch{}return t.length>500?`${t.slice(0,500)}\u2026`:t},nt=async(t,e)=>{if(t.ok)return;let n=Yt(await N(t));throw new d({message:`${e} failed (${t.status}): ${n}`,status:t.status})},st=async(t,e,n)=>{try{return await fetch(t,n)}catch(s){throw new d({message:`${e} failed: ${s.message}`,status:0,cause:s})}},at=async(t,e)=>{try{return await t.text()}catch(n){throw new d({message:`${e} failed while reading the response: ${n.message}`,status:t.status,cause:n})}},Gt=t=>{let e=t.trim();if(e.length===0)throw new l("documentation path must not be empty");if(e.length>2048)throw new l("documentation path is too long");if(e.startsWith("//")||e.includes("://"))throw new l("documentation path must be a path, not a URL");if(e.includes("?")||e.includes("#")||e.includes("\\"))throw new l("documentation path must not contain a query, fragment, or backslash");let n=e.startsWith("/")?e.slice(1):e;if(n.endsWith(".md"))throw new l("documentation path must not include the .md suffix");let s=n.split("/");if(s.some(a=>a.length===0||a==="."||a===".."||!/^[A-Za-z0-9._~%-]+$/.test(a)))throw new l("documentation path contains an invalid segment");return s.join("/")},ee=class{docsUrl;constructor(e){this.docsUrl=e.mynthDocsUrl.replace(/\/$/,"");}async get(e){let n=Gt(e),s=n.split("/").map(encodeURIComponent).join("/"),a=await st(`${this.docsUrl}/${s}.md`,`documentation page fetch for ${n}`);return await nt(a,`documentation page fetch for ${n}`),{path:n,content:await at(a,`documentation page fetch for ${n}`)}}async list(){let e=await st(`${this.docsUrl}/llms.txt`,"documentation index fetch");return await nt(e,"documentation index fetch"),at(e,"documentation index fetch")}};var D=10,L=10,U=2,J=7,rt=300*1e3,sn=12e3,an=2500,rn=5e3,on={".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png",".webp":"image/webp"},cn=t=>new Promise(e=>setTimeout(e,t)),dn=(t,e,n)=>{try{let a=new URL(t).pathname.split("/").filter(Boolean).pop();if(a&&a.length>0)return decodeURIComponent(a)}catch{}return `${e}-${n}`},ln=async t=>{let e=extname(t).toLowerCase(),n=on[e];if(!n)throw new d({message:`unsupported image extension "${e}" for ${t} (allowed: .jpg, .jpeg, .png, .webp)`,status:0});let s;try{s=await readFile(t);}catch(i){throw new d({message:`could not read ${t}: ${i.message}`,status:0,cause:i})}let a=s.buffer.slice(s.byteOffset,s.byteOffset+s.byteLength);return new File([new Uint8Array(a)],basename(t),{type:n})},O=async(t,e,n)=>{let s=e.safeParse(await x(t));if(!s.success)throw new d({message:n,status:t.status,cause:s.error});return s.data},un=async(t,e,n)=>{let s=Array.from({length:t.length}),a=0,i=async()=>{for(;;){let c=a++,h=t[c];if(h===void 0)return;s[c]=await n(h,c);}};return await Promise.all(Array.from({length:Math.min(e,t.length)},i)),s},te=class{constructor(e){this.api=e;}async upload(e){if(e.length===0)throw new d({message:"no files to upload",status:0});if(e.length>D)throw new d({message:`too many files: ${e.length} (max ${D})`,status:0});let n=await Promise.all(e.map(ln)),s=new FormData;for(let c of n)s.append("images",c);let a=await this.api.execute("/image/upload",{method:"POST",body:s});await w(a,"upload");let i=await O(a,We,"invalid upload response");return e.map((c,h)=>({path:c,url:i.data.urls[h]}))}async rate(e){if(e.urls.length===0)throw new d({message:"no image URLs to rate",status:0});if(e.urls.length>L)throw new d({message:`too many images: ${e.urls.length} (max ${L})`,status:0});if(e.levels!==void 0&&(e.levels.length<U||e.levels.length>J))throw new d({message:`levels must have between ${U} and ${J} items (got ${e.levels.length})`,status:0});let n=e.levels!==void 0?{urls:e.urls,mode:"custom",levels:e.levels}:{urls:e.urls,mode:"nsfw_sfw"},s=await this.api.execute("/image/rate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});return await w(s,"rate"),(await O(s,qe,"invalid rate response")).data}async generate(e){let n=e.requestPat?{...e.request,access:{...e.request.access,pat:{enabled:true}}}:e.request,s=await this.api.execute("/image/generate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});await w(s,"generate");let a=await O(s,Be,"invalid generate response"),i=a.data.access?.publicAccessToken;return {taskId:a.data.taskId,...i!==void 0?{pat:i}:{}}}async estimate(e){let n=await this.api.execute("/image/generate/estimate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});return await w(n,"estimate"),(await O(n,He,"invalid estimate response")).data}async waitForTask(e,n){let s=Date.now();for(;;){let a=Date.now()-s;if(a>=rt)throw new d({message:`task ${e} polling timed out after ${rt}ms`,status:0});let i=await this.getTaskStatus(e,n);if(i==="completed")return this.getTaskDetails(e);if(i==="failed"){let h=await this.getTaskDetails(e).catch(()=>{}),y=h!==void 0?me(h):void 0;throw new d({message:`task ${e} failed during generation${y!==void 0?` (${y})`:""}`,status:0,...y!==void 0?{code:y}:{}})}let c=a<sn?an:rn;await cn(c+Math.floor(Math.random()*500));}}async getTaskDetails(e){let n=await this.api.execute(`/tasks/${e}`);return await w(n,"task details"),(await O(n,H,"invalid task details response")).data}async downloadImages(e){let n=resolve(e.destinationDir);try{await mkdir(n,{recursive:true});}catch(s){throw new d({message:`could not create output directory ${n}: ${s.message}`,status:0,cause:s})}return un(e.urls,4,async(s,a)=>{let i;try{i=await fetch(s);}catch(f){throw new d({message:`download failed for ${s}: ${f.message}`,status:0,cause:f})}if(i.status<200||i.status>=300)throw new d({message:`download failed for ${s} (${i.status})`,status:i.status});let c;try{c=await i.arrayBuffer();}catch(f){throw new d({message:`could not read body for ${s}: ${f.message}`,status:i.status,cause:f})}let h=dn(s,e.taskId,a),y=join(n,h);try{await writeFile(y,new Uint8Array(c));}catch(f){throw new d({message:`could not write ${y}: ${f.message}`,status:0,cause:f})}return y})}async getTaskStatus(e,n){let s=`/tasks/${e}/status`,a;if(n!==void 0)try{a=await fetch(`${this.api.baseUrl}${s}`,{headers:{Authorization:`Bearer ${n}`}});}catch(c){throw new d({message:`task status request failed: ${c.message}`,status:0,cause:c})}else a=await this.api.execute(s);return await w(a,"task status"),(await O(a,B,"invalid task status response")).data.status}};var ne=class{constructor(e){this.api=e;}async list(){let e=await this.api.executePublic("/models");if(e.status<200||e.status>=300){let s=await N(e);throw new d({message:`models fetch failed (${e.status}): ${s||"no body"}`,status:e.status})}let n=Xe.safeParse(await x(e));if(!n.success)throw new d({message:"invalid models response",status:e.status,cause:n.error});return n.data.data}};var mn=300*1e3,pn=12e3,gn=2500,hn=5e3,fn=t=>new Promise(e=>setTimeout(e,t)),se=class{constructor(e){this.api=e;}async getTask(e){let n=await this.api.execute(`/tasks/${e}`);await w(n,"task fetch");let s=H.safeParse(await x(n));if(!s.success)throw new d({message:"invalid task response",status:n.status,cause:s.error});return s.data.data}async listTasks(e={}){let n=new URLSearchParams;e.limit!==void 0&&n.set("limit",String(e.limit)),e.after!==void 0&&n.set("after",e.after);let s=n.size>0?`?${n}`:"",a=await this.api.execute(`/tasks${s}`);await w(a,"task list");let i=Ve.safeParse(await x(a));if(!i.success)throw new d({message:"invalid task list response",status:a.status,cause:i.error});return i.data.data}async getTaskStatus(e){let n=await this.api.execute(`/tasks/${e}/status`);await w(n,"task status");let s=B.safeParse(await x(n));if(!s.success)throw new d({message:"invalid task status response",status:n.status,cause:s.error});return s.data.data.status}async waitForTask(e,n=mn){let s=Date.now();for(;;){if(await this.getTaskStatus(e)!=="pending")return this.getTask(e);let i=Date.now()-s;if(i>=n)throw new d({message:`task ${e} did not complete within ${Math.round(n/1e3)}s`,status:0});let c=i<pn?gn:hn;await fn(c+Math.floor(Math.random()*500));}}};var ae="client_01KATK792RR5ZCHMF5YMNN1ZSE",ot="https://api.workos.com";var yn="urn:ietf:params:oauth:grant-type:device_code",wn="refresh_token",vn=t=>{try{let e=t.split(".");if(e.length<2)throw new Error("malformed jwt");let n=JSON.parse(Buffer.from(e[1],"base64url").toString("utf8"));if(typeof n.exp!="number")throw new Error("jwt missing exp claim");return n.exp*1e3}catch(e){throw new b({message:"could not decode access token",cause:e})}},ye=async t=>{try{return await t.json()}catch{return {}}},ct=async t=>Ke.catch({}).parse(await ye(t)),it=async(t,e)=>{let n=await ct(t),s=n.error??n.code;throw new b({message:n.error_description??n.message??e,status:t.status,...s!==void 0?{code:s}:{}})},dt=async(t,e)=>{let n=Fe.safeParse(await ye(t));if(!n.success)throw new b({message:`invalid ${e} response`,status:t.status,cause:n.error});return {token:n.data,expiresAt:vn(n.data.access_token)}},kn=async t=>{if(t.status===200)return dt(t,"token");let e=await ct(t),n=e.error??e.code;switch(n){case "authorization_pending":throw new C({slowDown:false});case "slow_down":throw new C({slowDown:true});case "expired_token":throw new E;case "access_denied":throw new P;default:throw new b({message:e.error_description??e.message??"WorkOS error",status:t.status,...n!==void 0?{code:n}:{}})}},re=class{baseUrl=ot;async requestDeviceAuthorization(){let e=await this.post("/user_management/authorize/device",new URLSearchParams({client_id:ae}),"device authorize request failed");if(e.status!==200)return it(e,"device authorize failed");let n=Je.safeParse(await ye(e));if(!n.success)throw new b({message:"invalid device authorize response",status:e.status,cause:n.error});return n.data}async exchangeDeviceCode(e){let n=await this.post("/user_management/authenticate",JSON.stringify({grant_type:yn,client_id:ae,device_code:e}),"authenticate request failed",{"Content-Type":"application/json"});return kn(n)}async refresh(e){let n=await this.post("/user_management/authenticate",JSON.stringify({grant_type:wn,client_id:ae,refresh_token:e}),"refresh request failed",{"Content-Type":"application/json"});return n.status===200?dt(n,"refresh"):it(n,"refresh failed")}async post(e,n,s,a={}){try{return await fetch(`${this.baseUrl}${e}`,{method:"POST",body:n,headers:{Accept:"application/json",...a}})}catch(i){throw new b({message:s,cause:i})}}};var lt=()=>{let t=Ze(),e=new Q,n=new re,s=new X(t,e,n),a=new Y(t,s);return {account:new G(a),auth:s,credentialsStore:e,docs:new ee(t),images:new te(a),models:new ne(a),tasks:new se(a),workos:n}};var o=(t="")=>{process.stdout.write(`${t}
3
- `);},oe=(t="")=>{process.stderr.write(`${t}
4
- `);};var Sn=t=>new Date(t).toISOString(),bn=t=>new Promise(e=>setTimeout(e,t)),ut=wt.green("\u2713"),mt=(t,e)=>new A({message:e instanceof Error?`${t}: ${e.message}`:t,cause:e}),xn=async(t,e,n,s)=>{let a=n;for(;;){if(Date.now()>=s)throw new A({message:"device code expired before approval"});try{return await t.workos.exchangeDeviceCode(e)}catch(i){if(i instanceof C){i.slowDown&&(a+=5e3),await bn(a);continue}throw i instanceof P?new A({message:"login denied by user"}):i instanceof E?new A({message:"device code expired"}):i instanceof b?new A({message:i.message,cause:i}):i}}},we=t=>{let e=new Command("auth");return e.command("login").description("Authenticate with Mynth using OAuth device login").action(async()=>{if(t.auth.envApiKeySet)throw o(`MYNTH_API_KEY is set in your environment; that takes precedence over login.
5
- Unset it to use OAuth, or just continue using the env API key.`),new A({message:"env api key takes precedence"});let n;try{n=await t.workos.requestDeviceAuthorization();}catch(i){throw mt("device authorize",i)}o(""),o(` First copy your one-time code: ${n.user_code}`),o(` Then open: ${n.verification_uri_complete??n.verification_uri}`),o(""),o("Waiting for confirmation...");let s=await xn(t,n.device_code,(n.interval??5)*1e3,Date.now()+n.expires_in*1e3);try{await t.auth.saveOAuth({accessToken:s.token.access_token,refreshToken:s.token.refresh_token,expiresAt:s.expiresAt,...s.token.user?{user:s.token.user}:{}});}catch(i){throw mt("could not save credentials",i)}let a=s.token.user?.email??s.token.user?.id??"unknown user";o(`${ut} Logged in as ${a}`);}),e.command("logout").description("Clear local Mynth credentials").action(async()=>{await t.auth.logout(),o(`${ut} Local credentials cleared`),t.auth.envApiKeySet&&o("Note: MYNTH_API_KEY is still set in your environment and will be used.");}),e.command("status").description("Show current authentication status").action(async()=>{let n=await t.auth.status(),a=await t.credentialsStore.usingKeychain()?"system keychain":`file (${t.credentialsStore.filePath})`;switch(n.kind){case "env":o("Authenticated via env: MYNTH_API_KEY");return;case "none":o("Not authenticated. Run `mynth auth login` or set an API key.");return;case "api_key":o(`Authenticated via stored API key (${a})`);return;case "oauth":{let i=n.user?.email??n.user?.id??"unknown user";o(`Authenticated via OAuth as ${i} (${a})`),o(` access token expires: ${Sn(n.expiresAt)}`);}}}),e.addCommand(ie(t)),e},ie=t=>new Command("whoami").description("Print the active Mynth identity, verified against the API").action(async()=>{let e=await t.auth.status();if(e.kind==="none")throw o("not authenticated"),new R;let n=e.kind==="env"?"env:MYNTH_API_KEY":e.kind==="api_key"?"api-key":e.user?.email??e.user?.id??"oauth",s=await t.account.me();o(n),o(` user: ${s.userId}`),s.auth.apiKey&&o(` key: ${s.auth.apiKey.name??"unnamed"} (${s.auth.apiKey.keyPreview})`);});var ve=t=>new Command("balance").description("Show account balance and API key spending limit usage").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async e=>{let n=await t.account.balance();if(e.json){o(JSON.stringify(n,null,2));return}o(`Balance: $${n.balance}`),o(`Reserved: $${n.reserved}`),o(`Available: $${n.available}`),n.apiKey&&(o(""),o(`API key limit: $${n.apiKey.spendingLimit} / ${n.apiKey.spendingLimitPeriod}`),o(` used: $${n.apiKey.usedInPeriod}`),o(` remaining: $${n.apiKey.remainingInPeriod}`));});var gt=wt.green("\u2713"),Rn=async()=>{try{let t="";process.stdin.setEncoding("utf8");for await(let e of process.stdin)t+=e;return t.trim()}catch(t){throw new A({message:"could not read stdin",cause:t})}},Ae=t=>{let e=new Command("config"),n=new Command("set").description("Set local CLI configuration");n.command("api-key").description("Save a Mynth API key").argument("<value>","API key value, or `-` to read from stdin").action(async a=>{let i=a==="-"?await Rn():a;if(i.length===0)throw new A({message:"API key is empty"});try{await t.auth.setApiKey(i);}catch(c){throw new A({message:`could not save API key: ${c.message}`,cause:c})}o(`${gt} API key saved`),t.auth.envApiKeySet&&o("Note: MYNTH_API_KEY is also set in your environment and will take precedence.");});let s=new Command("unset").description("Unset local CLI configuration");return s.command("api-key").description("Clear stored Mynth credentials").action(async()=>{await t.auth.logout(),o(`${gt} Stored credentials cleared`);}),e.addCommand(n),e.addCommand(s),e};var Se=t=>{let e=new Command("docs").description("Read Mynth documentation");return e.command("get").description("Fetch a documentation page as Markdown").argument("<path>","Documentation path without the .md suffix").option("--json","Output machine-readable JSON").action(async(n,s)=>{let a=await t.docs.get(n);o(s.json?JSON.stringify(a,null,2):a.content);}),e.command("list").description("Fetch the complete documentation index").option("--json","Output machine-readable JSON").action(async n=>{let s=await t.docs.list();o(n.json?JSON.stringify({content:s},null,2):s);}),e};var En=["Priming the canvas","Summoning pixels","Mixing digital pigments","Whispering to the model","Dreaming up details","Sketching silhouettes","Arranging composition","Weaving light and shadow","Polishing reflections","Sculpting atmosphere","Tracing final strokes"],Pn=()=>typeof process<"u"&&process.stderr&&process.stderr.isTTY===true,On=t=>{let e=t.slice();for(let n=e.length-1;n>0;n--){let s=Math.floor(Math.random()*(n+1));[e[n],e[s]]=[e[s],e[n]];}return e},ce=async(t,e={})=>{if(!Pn())return t;let n=On(e.messages??En),s=0,a=Cn({text:n[0]??"Working",stream:process.stderr}).start(),i=setInterval(()=>{s++,a.text=n[s%n.length]??"Working";},2800);try{return await t}finally{clearInterval(i),a.stop();}};var be=20,Nn="webp",Dn=80,Te=["auto","person","garment","pose","source","reference"],Ln="https://dry-run.mynth.io/input",_=wt.green("\u2713"),Un=wt.red("\u2717"),xe=()=>new Option("--json","Output machine-readable JSON instead of a human-readable summary"),Jn=z.array(z.object({value:z.string(),description:z.string()})),le=t=>/^https?:\/\//i.test(t),vt=(t,e=[])=>[...e,t],kt=t=>{let e=Number.parseInt(t,10);if(!Number.isInteger(e)||String(e)!==t)throw new l(`invalid integer: "${t}"`);return e},Fn=t=>{let e=kt(t);if(e<1||e>100)throw new l(`invalid quality: "${t}" (expected 1-100)`);return e},Kn=t=>{let e=t.indexOf("=");if(e<=0)throw new l(`invalid --level "${t}": expected "value=description"`);let n={value:t.slice(0,e).trim(),description:t.slice(e+1).trim()};if(n.value.length===0||n.description.length===0)throw new l(`invalid --level "${t}": value and description must be non-empty`);return n},ht=(t,e)=>{let n;try{n=JSON.parse(t);}catch(a){throw new l(`invalid JSON in ${e}: ${a.message}`)}let s=Jn.safeParse(n);if(!s.success)throw new l(`invalid levels in ${e}: expected array of { value, description }`);return s.data},ft=async t=>{let e=[t.levelPairs.length>0?"--level":null,t.levelsFile!==void 0?"--levels-file":null,t.levelsJson!==void 0?"--levels-json":null].filter(a=>a!==null);if(e.length===0)return;if(e.length>1)throw new l(`conflicting level options: ${e.join(", ")} - use only one`);let n;if(t.levelPairs.length>0)n=t.levelPairs.map(Kn);else if(t.levelsFile!==void 0){let a;try{a=await readFile(t.levelsFile,"utf8");}catch(i){throw new l(`could not read ${t.levelsFile}: ${i.message}`)}n=ht(a,t.levelsFile);}else n=ht(t.levelsJson??"[]","--levels-json");if(n.length<U||n.length>J)throw new l(`levels must have between ${U} and ${J} items (got ${n.length})`);let s=new Set;for(let a of n){if(s.has(a.value))throw new l(`duplicate level value: "${a.value}"`);s.add(a.value);}return n},zn=t=>{let e=t.indexOf(":"),n=/^https?:/i.test(t),s,a=t;if(e>0&&!n){let i=t.slice(0,e);if(!Te.includes(i))throw new l(`invalid --input as "${i}". Expected one of: ${Te.join(", ")}`);s=i,a=t.slice(e+1);}if(a.length===0)throw new l(`invalid --input "${t}": missing path or URL`);return {...s!==void 0?{as:s}:{},value:a,isFile:!le(a)}},Wn=t=>{let e;try{e=JSON.parse(t);}catch(n){throw new l(`invalid --metadata JSON: ${n.message}`)}if(e===null||typeof e!="object"||Array.isArray(e))throw new l("--metadata must be a JSON object");return e},yt=t=>t.option("-l, --level <value>",'Custom rating level as "value=description" (repeatable, 2-7 items). Example: -l safe="No explicit content" -l nsfw="Contains nudity"',vt).option("--levels-file <path>",'Path to a JSON file containing an array of { "value": string, "description": string } (2-7 items). Alternative to --level when descriptions contain special characters.').option("--levels-json <json>",'Inline JSON array of { "value": string, "description": string } (2-7 items). Alternative to --level / --levels-file.'),Re=(t,e)=>{let n=t.result??{},s=n.images??[];e>0&&o(`${_} Uploaded ${e} input image${e===1?"":"s"}`);let a=s.filter(i=>i.status==="success");if(o(`${_} Generated ${a.length}/${s.length} image${s.length===1?"":"s"} (task ${t.id})`),n.model!==void 0&&o(` Model: ${n.model}`),t.cost!==null&&o(` Cost: ${t.cost}`),n.magic_prompt?.positive!==void 0&&(o(""),o("Enhanced prompt (mynth):"),o(` ${n.magic_prompt.positive}`),n.magic_prompt.negative!==void 0&&n.magic_prompt.negative.length>0&&o(` negative: ${n.magic_prompt.negative}`)),s.length>0){o("");for(let i of s){let c=i;if(c.status==="success"){let h=c.rating,y=h?.level!==void 0?` [${h.level}]`:"",f=c.url??c.mynth_url;o(` ${_} ${f}${y}`);}else o(` ${Un} ${qn(c.error)}`);}}},qn=t=>{if(typeof t=="string")return t;if(t!==null&&typeof t=="object"){let e=t,n=typeof e.code=="string"?e.code:"unknown error",s=typeof e.message=="string"?e.message:void 0;return s!==void 0?`${n}: ${s}`:n}return "unknown error"},$e=t=>{let e=t.result??{},n=(e.images??[]).map(s=>{let a=s;return a.status==="success"?{status:"success",url:a.url??null,mynth_url:a.mynth_url??null,size:a.size,rating:a.rating}:{status:"failed",error:a.error,mynth_url:a.mynth_url??null}});return {taskId:t.id,status:t.status,images:n,...e.magic_prompt?{magic_prompt:e.magic_prompt}:{},...t.cost!==null?{cost:t.cost}:{},...e.model!==void 0?{model:e.model}:{}}},Bn=async(t,e,n)=>{let a=((e.result??{}).images??[]).map(i=>i).filter(i=>i.status==="success").map(i=>i.url??i.mynth_url).filter(i=>typeof i=="string"&&i.length>0);return a.length===0?[]:t.downloadImages({urls:a,destinationDir:n,taskId:e.id})},Ce=t=>{let e=new Command("image");e.command("upload").description("Upload local images to Mynth").argument("<files...>","Path to a local image file (.jpg, .jpeg, .png, .webp)").addOption(xe()).action(async(a,i)=>{if(a.length>D)throw new l(`too many files: ${a.length} (max ${D})`);let c=await t.images.upload(a);if(i.json){o(JSON.stringify({images:c},null,2));return}o(`${_} Uploaded ${c.length} image${c.length===1?"":"s"}`);for(let{path:h,url:y}of c)o(` ${h}`),o(` -> ${y}`);});let n=e.command("rate").description("Rate images by URL or local file").argument("<image...>","Image URL (http://, https://) or path to a local image file to upload first").addOption(xe());yt(n),n.action(async(a,i)=>{if(a.length>L)throw new l(`too many images: ${a.length} (max ${L})`);let c=await ft({levelPairs:i.level??[],levelsFile:i.levelsFile,levelsJson:i.levelsJson}),h=a.filter(le),y=a.filter(m=>!le(m)),f=y.length>0?await t.images.upload(y):[],ue=new Map(f.map(m=>[m.path,m.url])),F=a.map(m=>le(m)?m:ue.get(m)??m),T=await t.images.rate({urls:F,...c?{levels:c}:{}});if(i.json){o(JSON.stringify(T,null,2));return}let K=T.results.filter(m=>m.status==="success"),z=T.results.filter(m=>m.status==="failed");f.length>0&&o(`${_} Uploaded ${f.length} image${f.length===1?"":"s"}`),o(`${_} Rated ${K.length}/${T.results.length} (task ${T.task.id})`);for(let m of K)o(` ${m.level} ${m.url}`);for(let m of z)o(` ERROR ${m.error.code} ${m.url}`);if(h.length===0&&f.length>0){o(""),o("Uploaded source files:");for(let m of f)o(` ${m.path} -> ${m.url}`);}});let s=e.command("generate").description("Generate images with Mynth").addHelpText("after",`
6
- Models: mynth models list`);return s.option("-p, --prompt <text>","Text prompt describing the image to generate").option("-n, --negative <text>","Negative prompt (elements to exclude)").addOption(new Option("--enhance <mode>",'Prompt enhancement mode: "prefer_magic" (Mynth) or "none". "prefer_native" is no longer supported by the API.').choices(["prefer_magic","prefer_native","none"])).option("-m, --model <id>",'Model ID (e.g. "black-forest-labs/flux.1-dev"). Default: "auto"').option("-s, --size <size>",'Size preset or aspect ratio: "square", "portrait", "landscape", "1:1", "16:9", "16:9_4k", "auto", etc.').option("-c, --count <number>","Number of images to generate (default: 1)",kt).addOption(new Option("-f, --format <format>","Output image format (default: webp)").choices(["png","jpg","webp"])).option("-q, --quality <number>","Output quality 1-100 (default: 80)",Fn).option("-i, --input <value>",`Input image as "[as:]path-or-url" (repeatable, up to ${be}). as is optional and must be one of: ${Te.join(", ")}. Examples: -i ./img.jpg, -i source:https://example.com/a.png, -i reference:./style.png`,vt).option("-o, --output-dir <dir>","Directory to save generated images to. Created if it doesn't exist. Ignored in --async mode since the task hasn't completed yet.").option("--destination <name>","Name (slug) of a user-configured destination to deliver the result to. Falls back to MYNTH_DESTINATION env var if not set.").option("--metadata <json>","Inline JSON object of custom metadata to attach to the task (max 2KB)").option("--content-rating","Enable content rating classification using default sfw/nsfw levels. For custom levels use --level / --levels-file / --levels-json.").option("--dry-run","Validate the request and print the estimated cost without generating anything").option("--async","Return the task ID immediately instead of polling until completion").option("--detailed","Include full task data (all fields) in the output").addOption(xe()),yt(s),s.action(async a=>{let i=a.prompt??"";if(a.enhance==="prefer_native")throw new l('--enhance prefer_native is no longer supported by the API; use "prefer_magic" or "none"');let c=a.input??[];if(c.length>be)throw new l(`too many --input values: ${c.length} (max ${be})`);let h=c.map(zn),y=a.metadata!==void 0?Wn(a.metadata):void 0,f=await ft({levelPairs:a.level??[],levelsFile:a.levelsFile,levelsJson:a.levelsJson}),ue=h.filter(u=>u.isFile).map(u=>u.value),F=Array.from(new Set(ue)),T=F.length>0&&!a.dryRun?await t.images.upload(F):[],K=new Map(T.map(u=>[u.path,u.url])),z=h.map(u=>({type:"image",...u.as?{as:u.as}:{},source:{type:"url",url:u.isFile?K.get(u.value)??Ln:u.value}})),m=a.format!==void 0||a.quality!==void 0?{format:a.format??Nn,quality:a.quality??Dn}:void 0,je=f!==void 0?{mode:"custom",levels:f}:a.contentRating?true:void 0,v={prompt:i};if(a.model!==void 0&&(v.model=a.model),a.negative!==void 0&&(v.negative_prompt=a.negative),a.enhance==="prefer_magic"&&(v.magic_prompt=true),a.size!==void 0&&(v.size=a.size),a.count!==void 0&&(v.count=a.count),m!==void 0&&(v.output=m),z.length>0&&(v.inputs=z),a.destination!==void 0&&(v.destination=a.destination),je!==void 0&&(v.rating=je),y!==void 0&&(v.metadata=y),a.dryRun){let u=await t.images.estimate(v);if(a.json){o(JSON.stringify(u,null,2));return}let M=u.estimateKind==="upper_bound"?" (upper bound)":"";o(`${_} Estimated cost: $${u.estimatedCost}${M}`);return}if(a.async){let u=await t.images.generate({request:v,requestPat:true}),M={taskId:u.taskId,...u.pat!==void 0?{access:{publicAccessToken:u.pat}}:{}};if(a.json){o(JSON.stringify(M,null,2));return}o(`${_} Task created: ${u.taskId}`),u.pat!==void 0&&o(` PAT: ${u.pat}`);return}let Me=await t.images.generate({request:v,requestPat:true}),Ne=t.images.waitForTask(Me.taskId,Me.pat),W=a.json?await Ne:await ce(Ne),I=a.outputDir!==void 0?resolve(a.outputDir):void 0,j=I!==void 0?await Bn(t.images,W,I):[];if(a.json){let u=a.detailed?W:$e(W),M=I!==void 0?{...u,downloadedFiles:j}:u;o(JSON.stringify(M,null,2));return}if(Re(W,T.length),I!==void 0&&j.length>0){o(""),o(`${_} Saved ${j.length} image${j.length===1?"":"s"} to ${I}`);for(let u of j)o(` ${u}`);}}),e};var Ee=t=>t??"-",Yn=t=>{if(t.length===0){o("No models available.");return}let e=t.map(s=>({id:s.id,name:s.displayName??"-",base:Ee(s.pricing?.perImage.base),fourK:Ee(s.pricing?.perImage["4k"]),inputFee:Ee(s.pricing?.perInput)})),n={id:Math.max(2,...e.map(s=>s.id.length)),name:Math.max(4,...e.map(s=>s.name.length)),base:Math.max(4,...e.map(s=>s.base.length)),fourK:Math.max(2,...e.map(s=>s.fourK.length)),inputFee:Math.max(9,...e.map(s=>s.inputFee.length))};o(["ID".padEnd(n.id),"Name".padEnd(n.name),"Base".padEnd(n.base),"4K".padEnd(n.fourK),"Input fee".padEnd(n.inputFee)].join(" "));for(let s of e)o([s.id.padEnd(n.id),s.name.padEnd(n.name),s.base.padEnd(n.base),s.fourK.padEnd(n.fourK),s.inputFee.padEnd(n.inputFee)].join(" "));},Pe=t=>{let e=new Command("models").description("Browse the public Mynth model catalog");return e.command("list").description("List available image generation models").option("--json","Output machine-readable JSON instead of a human-readable table").action(async n=>{let s=await t.models.list();if(n.json){o(JSON.stringify(s,null,2));return}Yn(s);}),e};var At=300,St=t=>e=>{let n=Number.parseInt(e,10);if(!Number.isInteger(n)||String(n)!==e||n<=0)throw new l(`invalid ${t}: "${e}" (expected a positive integer)`);return n},xt=t=>{switch(t){case "completed":return "\u2713";case "failed":return "\u2717";default:return "\u2026"}},Vn=(t,e)=>{let n=" ".repeat(e);return t.split(`
7
- `).map(s=>`${n}${s}`).join(`
8
- `)},bt=t=>{o(`${xt(t.status)} Task ${t.id}`),o(` Type: ${t.type}`),o(` Status: ${t.status}`),t.cost!==null&&o(` Cost: ${t.cost}`),o(` Created: ${t.createdAt}`),o(` Updated: ${t.updatedAt}`),t.result!==null&&t.result!==void 0&&(o(""),o("Result:"),o(Vn(JSON.stringify(t.result,null,2),2)));},Xn=t=>{if(t.length===0){o("No tasks found.");return}for(let e of t){let n=e.cost!==null?` ${e.cost}`:"";o(`${xt(e.status)} ${e.id} ${e.type} ${e.status}${n} ${e.createdAt}`);}},Oe=t=>{let e=new Command("task");return e.command("get").description("Fetch a task by ID").argument("<id>","Task ID").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async(n,s)=>{let a=await t.tasks.getTask(n);if(s.json){o(JSON.stringify(a,null,2));return}bt(a);}),e.command("wait").description("Block until a task completes (or fails), then print it").argument("<id>","Task ID").option("--timeout <seconds>",`Max seconds to wait before giving up (default: ${At})`,St("--timeout")).option("--detailed","Include full task data (all fields) in the output").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async(n,s)=>{let a=(s.timeout??At)*1e3,i=t.tasks.waitForTask(n,a),c=s.json?await i:await ce(i);if(c.status==="failed"&&(process.exitCode=Le(c)),s.json){let h=s.detailed||c.type!=="image.generate"?c:$e(c);o(JSON.stringify(h,null,2));return}if(c.type==="image.generate"&&c.status==="completed"){Re(c,0);return}bt(c);}),e.command("list").description("List recent tasks, newest first").option("--limit <number>","Max tasks to return (1-100, default: 20)",St("--limit")).option("--after <id>","Cursor: return tasks created before this task ID").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async n=>{let s=await t.tasks.listTasks({...n.limit!==void 0?{limit:n.limit}:{},...n.after!==void 0?{after:n.after}:{}});if(n.json){o(JSON.stringify({tasks:s},null,2));return}Xn(s);}),e};var Ie=class extends Help{optionTerm(e){return `(${e.flags.replaceAll("<","").replaceAll(">","")})`}subcommandTerm(e){let n=e.registeredArguments.map(s=>s.required?`${s.name()}${s.variadic?"...":""}`:`[${s.name()}]`).join(" ");return n.length>0?`${e.name()} ${n}`:e.name()}},_t=()=>{let t=lt(),e=new Command("mynth");return e.description("Official Mynth CLI").version("0.0.12"),e.addHelpText("after",`
2
+ import {Command,Option,Help}from'commander';import {z}from'zod';import*as _ from'cross-keychain';import {readFile,mkdir,writeFile,chmod,rm,stat}from'fs/promises';import {homedir}from'os';import {resolve,join,extname,basename}from'path';import Dt from'chalk';import Qn from'ora';var A=class extends Error{_tag="MynthCliError";cause;constructor(e){super(e.message),this.name=this._tag,this.cause=e.cause;}},l=class extends Error{_tag="CliUsageError";constructor(e){super(e),this.name=this._tag;}},O=class extends Error{_tag="NotAuthenticatedError";constructor(e={}){super(e.reason??"not authenticated"),this.name=this._tag;}},S=class extends Error{_tag="CredentialsStoreError";cause;constructor(e){super(e.message),this.name=this._tag,this.cause=e.cause;}},x=class extends Error{_tag="WorkOSError";code;status;cause;constructor(e){super(e.message),this.name=this._tag,this.code=e.code,this.status=e.status,this.cause=e.cause;}},T=class extends Error{_tag="AuthorizationPendingError";slowDown;constructor(e){super("authorization pending"),this.name=this._tag,this.slowDown=e.slowDown;}},E=class extends Error{_tag="AuthorizationExpiredError";constructor(){super("authorization expired"),this.name=this._tag;}},P=class extends Error{_tag="AuthorizationDeniedError";constructor(){super("authorization denied"),this.name=this._tag;}},b={error:1,usage:2,auth:3,insufficientCredits:4,moderation:5,rateLimited:6},Yt={UNAUTHORIZED:b.auth,VALIDATION_ERROR:b.usage,INSUFFICIENT_BALANCE:b.insufficientCredits,RESTRICTED_CONTENT:b.moderation},qe=t=>{if(t instanceof l)return b.usage;if(t instanceof O)return b.auth;if(t instanceof c){let n=t.code!==void 0?Yt[t.code]:void 0;return n!==void 0?n:t.status===401||t.status===403?b.auth:t.status===429?b.rateLimited:b.error}let e=t.code;return typeof e=="string"&&e.startsWith("commander.")?b.usage:b.error},ge=t=>{let e=t.result?.images,n=[...(t.errors??[]).map(a=>a.code),...(e??[]).map(a=>a.error?.code)].filter(a=>typeof a=="string");return n.find(a=>a==="RESTRICTED_CONTENT")??n[0]},Be=t=>ge(t)==="RESTRICTED_CONTENT"?b.moderation:b.error,c=class extends Error{_tag="MynthApiError";status;code;cause;constructor(e){super(e.message),this.name=this._tag,this.status=e.status,this.code=e.code,this.cause=e.cause;}};var He=z.object({id:z.string(),email:z.string(),first_name:z.string().nullable().optional(),last_name:z.string().nullable().optional()}),Ye=z.object({device_code:z.string(),user_code:z.string(),verification_uri:z.string(),verification_uri_complete:z.string().optional(),expires_in:z.number(),interval:z.number().optional()}),Ge=z.object({access_token:z.string(),refresh_token:z.string(),user:He.optional(),organization_id:z.string().optional()}),Ve=z.object({error:z.string().optional(),error_description:z.string().optional(),message:z.string().optional(),code:z.string().optional()}),Gt=z.object({kind:z.literal("oauth"),access_token:z.string(),refresh_token:z.string(),expires_at:z.number(),user:He.optional()}),Vt=z.object({kind:z.literal("api_key"),api_key:z.string()}),Xe=z.union([Gt,Vt]),I=z.lazy(()=>z.union([z.string(),z.number(),z.boolean(),z.null(),z.array(I),z.record(I)])),Ze=z.object({data:z.object({urls:z.array(z.string())})}),Xt=z.union([z.object({status:z.literal("success"),url:z.string(),level:z.string()}),z.object({status:z.literal("failed"),url:z.string(),error:z.object({code:z.string()})})]),Qe=z.object({data:z.object({task:z.object({id:z.string(),status:z.literal("completed"),cost:z.string()}),results:z.array(Xt)})}),et=z.object({data:z.object({taskId:z.string(),estimatedCost:z.string().optional(),access:z.object({publicAccessToken:z.string()}).optional()})}),tt=z.object({data:z.object({estimatedCost:z.string(),currency:z.string(),estimateKind:z.union([z.literal("exact"),z.literal("upper_bound")])})}),nt=z.object({data:z.object({userId:z.string(),auth:z.object({method:z.string(),apiKey:z.object({id:z.string(),name:z.string().nullable(),keyPreview:z.string()}).optional()})})}),at=z.object({data:z.object({balance:z.string(),reserved:z.string(),available:z.string(),currency:z.string(),apiKey:z.object({spendingLimit:z.string(),spendingLimitPeriod:z.string(),usedInPeriod:z.string(),remainingInPeriod:z.string()}).optional()})}),H=z.object({data:z.object({status:z.union([z.literal("pending"),z.literal("completed"),z.literal("failed")])})}),Zt=z.object({id:z.string(),type:z.union([z.literal("image.generate"),z.literal("image.rate")]),status:z.union([z.literal("pending"),z.literal("completed"),z.literal("failed")]),userId:z.string(),apiKeyId:z.string().nullable(),cost:z.string().nullable(),request:I,result:I,errors:z.array(z.object({code:z.string()})).nullable().optional(),createdAt:z.string(),updatedAt:z.string()}),Y=z.object({data:Zt}),Qt=z.object({id:z.string(),type:z.string(),status:z.string(),cost:z.string().nullable(),createdAt:z.string(),updatedAt:z.string()}),st=z.object({data:z.array(Qt)}),en=z.object({perImage:z.object({base:z.string(),"4k":z.string().optional()}),perInput:z.string().optional()}),tn=z.object({id:z.string(),displayName:z.string().nullable(),pricing:en.nullable()}),rt=z.object({data:z.array(tn)}),ot=z.object({id:z.string(),name:z.string(),provider:I,config:I,createdAt:z.string(),updatedAt:z.string()}),it=z.object({data:ot}),dt=z.object({data:z.array(ot)}),ct=z.union([z.literal("all"),z.array(z.string())]),lt=z.object({data:z.object({id:z.string(),userId:z.string().optional(),enabled:z.boolean(),url:z.string(),secret:z.string(),events:ct,createdAt:z.string().optional(),updatedAt:z.string().optional()})}),ut=z.object({data:z.object({id:z.string(),enabled:z.boolean().optional(),url:z.string(),events:ct})});var nn=t=>t.kind==="api_key"?t.apiKey:t.accessToken,v=async t=>{try{return await t.json()}catch(e){throw new c({message:`invalid JSON response: ${e.message}`,status:t.status,cause:e})}},J=async t=>{try{return await t.text()}catch{return ""}},g=async(t,e)=>{if(t.status>=200&&t.status<300)return;let n=await J(t),a;try{let s=JSON.parse(n);typeof s.code=="string"&&(a=s.code);}catch{}throw new c({message:`${e} failed (${t.status}): ${n||"no body"}`,status:t.status,...a!==void 0?{code:a}:{}})},G=class{constructor(e,n){this.auth=n;this.baseUrl=e.mynthApiUrl;}baseUrl;cachedAuth;async execute(e,n={}){let a=await this.attempt(e,n,false);return a.status!==401?a:this.attempt(e,n,true)}async executePublic(e,n={}){try{return await fetch(`${this.baseUrl}${e}`,n)}catch(a){throw new c({message:`request failed: ${a.message}`,status:0,cause:a})}}async attempt(e,n,a){let s=await this.getAuth(a),i=new Headers(n.headers);i.set("Authorization",`Bearer ${nn(s)}`);try{return await fetch(`${this.baseUrl}${e}`,{...n,headers:i})}catch(d){throw new c({message:`request failed: ${d.message}`,status:0,cause:d})}}async getAuth(e){return e&&(this.cachedAuth=void 0),this.cachedAuth!==void 0?this.cachedAuth:(this.cachedAuth=await this.auth.resolve(),this.cachedAuth)}};var V=class{constructor(e){this.api=e;}async me(){let e=await this.api.execute("/me");await g(e,"me");let n=nt.safeParse(await v(e));if(!n.success)throw new c({message:"invalid me response",status:e.status,cause:n.error});return n.data.data}async balance(){let e=await this.api.execute("/balance");await g(e,"balance");let n=at.safeParse(await v(e));if(!n.success)throw new c({message:"invalid balance response",status:e.status,cause:n.error});return n.data.data}};var an=6e4,X=t=>t?{user:t}:{},fe=(t,e)=>new O({reason:e instanceof Error?`${t}: ${e.message}`:t}),Z=class{constructor(e,n,a){this.config=e;this.store=n;this.workos=a;this.envApiKey=e.apiKeyEnvOverride,this.envApiKeySet=this.envApiKey!==void 0&&this.envApiKey.length>0;}envApiKeySet;envApiKey;async resolve(){if(this.envApiKeySet)return {kind:"api_key",apiKey:this.envApiKey,source:"env"};let e;try{e=await this.store.get();}catch(a){throw fe("could not read credentials",a)}if(e===void 0)throw new O({reason:"no credentials configured"});if(e.kind==="api_key")return {kind:"api_key",apiKey:e.api_key,source:"stored"};let n=await this.refreshIfNeeded(e);return {kind:"oauth",accessToken:n.access_token,...X(n.user)}}async status(){if(this.envApiKeySet)return {kind:"env",source:"MYNTH_API_KEY"};let e;try{e=await this.store.get();}catch{e=void 0;}return e===void 0?{kind:"none"}:e.kind==="api_key"?{kind:"api_key"}:{kind:"oauth",expiresAt:e.expires_at,...X(e.user)}}async setApiKey(e){await this.store.set({kind:"api_key",api_key:e});}async saveOAuth(e){await this.store.set({kind:"oauth",access_token:e.accessToken,refresh_token:e.refreshToken,expires_at:e.expiresAt,...X(e.user)});}async logout(){await this.store.clear();}async refreshIfNeeded(e){if(e.expires_at-Date.now()>an)return e;let n;try{n=await this.workos.refresh(e.refresh_token);}catch(s){throw fe("token refresh failed",s)}let a={kind:"oauth",access_token:n.token.access_token,refresh_token:n.token.refresh_token,expires_at:n.expiresAt,...X(n.token.user??e.user)};try{await this.store.set(a);}catch(s){throw fe("could not persist refreshed token",s)}return a}};var pt=()=>{let t=process.env.MYNTH_API_KEY;return {mynthApiUrl:process.env.MYNTH_API_URL??"https://api.mynth.io",mynthDocsUrl:process.env.MYNTH_DOCS_URL??"https://docs.mynth.io",...t!==void 0?{apiKeyEnvOverride:t}:{}}};var ye="mynth-cli",we="default",pn="credentials.json",mn=t=>{let e=t?.name;return e==="NoKeyringError"||e==="InitError"},Q=async(t,e)=>{try{return {available:true,value:await t()}}catch(n){if(mn(n))return {available:false};throw new S({message:e,cause:n})}},mt=t=>{let e;try{e=JSON.parse(t);}catch(a){throw new S({message:"credentials JSON parse failed",cause:a})}let n=Xe.safeParse(e);if(!n.success)throw new S({message:"credentials shape invalid",cause:n.error});return n.data},ht=t=>JSON.stringify(t),hn=()=>{let t=process.env.XDG_CONFIG_HOME,e=t&&t.length>0?t:join(homedir(),".config");return join(e,"mynth")},gt=async t=>{try{return await stat(t),true}catch{return false}},ee=class{filePath;dir;constructor(){this.dir=hn(),this.filePath=join(this.dir,pn);}async get(){let e=await Q(()=>_.getPassword(ye,we),"keychain get failed");if(e.available)return e.value===null?void 0:mt(e.value);if(await gt(this.filePath))try{return mt(await readFile(this.filePath,"utf8"))}catch(n){throw n instanceof S?n:new S({message:"read credentials file failed",cause:n})}}async set(e){if((await Q(()=>_.setPassword(ye,we,ht(e)),"keychain set failed")).available){await this.deleteFileSilently();return}await mkdir(this.dir,{recursive:true}).catch(a=>{throw new S({message:"create config dir failed",cause:a})}),await writeFile(this.filePath,ht(e),"utf8").catch(a=>{throw new S({message:"write credentials file failed",cause:a})}),await chmod(this.filePath,384).catch(()=>{});}async clear(){await Q(()=>_.deletePassword(ye,we),"keychain delete failed").catch(()=>{}),await this.deleteFileSilently();}async usingKeychain(){let e=await Q(()=>_.getKeyring(),"keychain probe failed");return e.available&&e.value!==null}async deleteFileSilently(){await gt(this.filePath)&&await rm(this.filePath).catch(e=>{throw new S({message:"delete credentials file failed",cause:e})});}};var ke=(t,e)=>({method:t,headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),te=class{constructor(e){this.api=e;}async list(){let e=await this.api.execute("/destinations");await g(e,"destination list");let n=dt.safeParse(await v(e));if(!n.success)throw new c({message:"invalid destination list response",status:e.status,cause:n.error});return n.data.data}async get(e){let n=await this.api.execute(`/destinations/${e}`);return await g(n,"destination fetch"),this.parseOne(n)}async create(e){let n=await this.api.execute("/destinations",ke("POST",e));return await g(n,"destination create"),this.parseOne(n)}async update(e,n){let a=await this.api.execute(`/destinations/${e}`,ke("PUT",n));return await g(a,"destination update"),this.parseOne(a)}async test(e,n){let a=await this.api.execute(`/destinations/${e}/test`,ke("POST",{path:n}));await g(a,"destination test");}async delete(e){let n=await this.api.execute(`/destinations/${e}`,{method:"DELETE"});await g(n,"destination delete");}async parseOne(e){let n=it.safeParse(await v(e));if(!n.success)throw new c({message:"invalid destination response",status:e.status,cause:n.error});return n.data.data}};var gn=t=>{if(t.length===0)return "no response body";try{let e=JSON.parse(t);if(typeof e.error=="string"&&e.error.length>0)return e.error}catch{}return t.length>500?`${t.slice(0,500)}\u2026`:t},ft=async(t,e)=>{if(t.ok)return;let n=gn(await J(t));throw new c({message:`${e} failed (${t.status}): ${n}`,status:t.status})},yt=async(t,e,n)=>{try{return await fetch(t,n)}catch(a){throw new c({message:`${e} failed: ${a.message}`,status:0,cause:a})}},wt=async(t,e)=>{try{return await t.text()}catch(n){throw new c({message:`${e} failed while reading the response: ${n.message}`,status:t.status,cause:n})}},fn=t=>{let e=t.trim();if(e.length===0)throw new l("documentation path must not be empty");if(e.length>2048)throw new l("documentation path is too long");if(e.startsWith("//")||e.includes("://"))throw new l("documentation path must be a path, not a URL");if(e.includes("?")||e.includes("#")||e.includes("\\"))throw new l("documentation path must not contain a query, fragment, or backslash");let n=e.startsWith("/")?e.slice(1):e;if(n.endsWith(".md"))throw new l("documentation path must not include the .md suffix");let a=n.split("/");if(a.some(s=>s.length===0||s==="."||s===".."||!/^[A-Za-z0-9._~%-]+$/.test(s)))throw new l("documentation path contains an invalid segment");return a.join("/")},ne=class{docsUrl;constructor(e){this.docsUrl=e.mynthDocsUrl.replace(/\/$/,"");}async get(e){let n=fn(e),a=n.split("/").map(encodeURIComponent).join("/"),s=await yt(`${this.docsUrl}/${a}.md`,`documentation page fetch for ${n}`);return await ft(s,`documentation page fetch for ${n}`),{path:n,content:await wt(s,`documentation page fetch for ${n}`)}}async list(){let e=await yt(`${this.docsUrl}/llms.txt`,"documentation index fetch");return await ft(e,"documentation index fetch"),wt(e,"documentation index fetch")}};var L=10,U=10,F=2,W=7,vt=300*1e3,xn=12e3,Cn=2500,On=5e3,$n={".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png",".webp":"image/webp"},Rn=t=>new Promise(e=>setTimeout(e,t)),_n=(t,e,n)=>{try{let s=new URL(t).pathname.split("/").filter(Boolean).pop();if(s&&s.length>0)return decodeURIComponent(s)}catch{}return `${e}-${n}`},Tn=async t=>{let e=extname(t).toLowerCase(),n=$n[e];if(!n)throw new c({message:`unsupported image extension "${e}" for ${t} (allowed: .jpg, .jpeg, .png, .webp)`,status:0});let a;try{a=await readFile(t);}catch(i){throw new c({message:`could not read ${t}: ${i.message}`,status:0,cause:i})}let s=a.buffer.slice(a.byteOffset,a.byteOffset+a.byteLength);return new File([new Uint8Array(s)],basename(t),{type:n})},j=async(t,e,n)=>{let a=e.safeParse(await v(t));if(!a.success)throw new c({message:n,status:t.status,cause:a.error});return a.data},En=async(t,e,n)=>{let a=Array.from({length:t.length}),s=0,i=async()=>{for(;;){let d=s++,f=t[d];if(f===void 0)return;a[d]=await n(f,d);}};return await Promise.all(Array.from({length:Math.min(e,t.length)},i)),a},ae=class{constructor(e){this.api=e;}async upload(e){if(e.length===0)throw new c({message:"no files to upload",status:0});if(e.length>L)throw new c({message:`too many files: ${e.length} (max ${L})`,status:0});let n=await Promise.all(e.map(Tn)),a=new FormData;for(let d of n)a.append("images",d);let s=await this.api.execute("/image/upload",{method:"POST",body:a});await g(s,"upload");let i=await j(s,Ze,"invalid upload response");return e.map((d,f)=>({path:d,url:i.data.urls[f]}))}async rate(e){if(e.urls.length===0)throw new c({message:"no image URLs to rate",status:0});if(e.urls.length>U)throw new c({message:`too many images: ${e.urls.length} (max ${U})`,status:0});if(e.levels!==void 0&&(e.levels.length<F||e.levels.length>W))throw new c({message:`levels must have between ${F} and ${W} items (got ${e.levels.length})`,status:0});let n=e.levels!==void 0?{urls:e.urls,mode:"custom",levels:e.levels}:{urls:e.urls,mode:"nsfw_sfw"},a=await this.api.execute("/image/rate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});return await g(a,"rate"),(await j(a,Qe,"invalid rate response")).data}async generate(e){let n=e.requestPat?{...e.request,access:{...e.request.access,pat:{enabled:true}}}:e.request,a=await this.api.execute("/image/generate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});await g(a,"generate");let s=await j(a,et,"invalid generate response"),i=s.data.access?.publicAccessToken;return {taskId:s.data.taskId,...i!==void 0?{pat:i}:{}}}async estimate(e){let n=await this.api.execute("/image/generate/estimate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});return await g(n,"estimate"),(await j(n,tt,"invalid estimate response")).data}async waitForTask(e,n){let a=Date.now();for(;;){let s=Date.now()-a;if(s>=vt)throw new c({message:`task ${e} polling timed out after ${vt}ms`,status:0});let i=await this.getTaskStatus(e,n);if(i==="completed")return this.getTaskDetails(e);if(i==="failed"){let f=await this.getTaskDetails(e).catch(()=>{}),w=f!==void 0?ge(f):void 0;throw new c({message:`task ${e} failed during generation${w!==void 0?` (${w})`:""}`,status:0,...w!==void 0?{code:w}:{}})}let d=s<xn?Cn:On;await Rn(d+Math.floor(Math.random()*500));}}async getTaskDetails(e){let n=await this.api.execute(`/tasks/${e}`);return await g(n,"task details"),(await j(n,Y,"invalid task details response")).data}async downloadImages(e){let n=resolve(e.destinationDir);try{await mkdir(n,{recursive:true});}catch(a){throw new c({message:`could not create output directory ${n}: ${a.message}`,status:0,cause:a})}return En(e.urls,4,async(a,s)=>{let i;try{i=await fetch(a);}catch(y){throw new c({message:`download failed for ${a}: ${y.message}`,status:0,cause:y})}if(i.status<200||i.status>=300)throw new c({message:`download failed for ${a} (${i.status})`,status:i.status});let d;try{d=await i.arrayBuffer();}catch(y){throw new c({message:`could not read body for ${a}: ${y.message}`,status:i.status,cause:y})}let f=_n(a,e.taskId,s),w=join(n,f);try{await writeFile(w,new Uint8Array(d));}catch(y){throw new c({message:`could not write ${w}: ${y.message}`,status:0,cause:y})}return w})}async getTaskStatus(e,n){let a=`/tasks/${e}/status`,s;if(n!==void 0)try{s=await fetch(`${this.api.baseUrl}${a}`,{headers:{Authorization:`Bearer ${n}`}});}catch(d){throw new c({message:`task status request failed: ${d.message}`,status:0,cause:d})}else s=await this.api.execute(a);return await g(s,"task status"),(await j(s,H,"invalid task status response")).data.status}};var se=class{constructor(e){this.api=e;}async list(){let e=await this.api.executePublic("/models");if(e.status<200||e.status>=300){let a=await J(e);throw new c({message:`models fetch failed (${e.status}): ${a||"no body"}`,status:e.status})}let n=rt.safeParse(await v(e));if(!n.success)throw new c({message:"invalid models response",status:e.status,cause:n.error});return n.data.data}};var Pn=300*1e3,In=12e3,jn=2500,Dn=5e3,Nn=t=>new Promise(e=>setTimeout(e,t)),re=class{constructor(e){this.api=e;}async getTask(e){let n=await this.api.execute(`/tasks/${e}`);await g(n,"task fetch");let a=Y.safeParse(await v(n));if(!a.success)throw new c({message:"invalid task response",status:n.status,cause:a.error});return a.data.data}async listTasks(e={}){let n=new URLSearchParams;e.limit!==void 0&&n.set("limit",String(e.limit)),e.after!==void 0&&n.set("after",e.after);let a=n.size>0?`?${n}`:"",s=await this.api.execute(`/tasks${a}`);await g(s,"task list");let i=st.safeParse(await v(s));if(!i.success)throw new c({message:"invalid task list response",status:s.status,cause:i.error});return i.data.data}async getTaskStatus(e){let n=await this.api.execute(`/tasks/${e}/status`);await g(n,"task status");let a=H.safeParse(await v(n));if(!a.success)throw new c({message:"invalid task status response",status:n.status,cause:a.error});return a.data.data.status}async waitForTask(e,n=Pn){let a=Date.now();for(;;){if(await this.getTaskStatus(e)!=="pending")return this.getTask(e);let i=Date.now()-a;if(i>=n)throw new c({message:`task ${e} did not complete within ${Math.round(n/1e3)}s`,status:0});let d=i<In?jn:Dn;await Nn(d+Math.floor(Math.random()*500));}}};var kt=(t,e)=>({method:t,headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),oe=class{constructor(e){this.api=e;}async create(e){let n=await this.api.execute("/webhook",kt("POST",e));await g(n,"webhook create");let a=lt.safeParse(await v(n));if(!a.success)throw new c({message:"invalid webhook create response",status:n.status,cause:a.error});return a.data.data}async update(e,n){let a=await this.api.execute(`/webhook/${e}`,kt("PUT",n));await g(a,"webhook update");let s=ut.safeParse(await v(a));if(!s.success)throw new c({message:"invalid webhook update response",status:a.status,cause:s.error});return s.data.data}async delete(e){let n=await this.api.execute(`/webhook/${e}`,{method:"DELETE"});await g(n,"webhook delete");}};var ie="client_01KATK792RR5ZCHMF5YMNN1ZSE",bt="https://api.workos.com";var Mn="urn:ietf:params:oauth:grant-type:device_code",Jn="refresh_token",Ln=t=>{try{let e=t.split(".");if(e.length<2)throw new Error("malformed jwt");let n=JSON.parse(Buffer.from(e[1],"base64url").toString("utf8"));if(typeof n.exp!="number")throw new Error("jwt missing exp claim");return n.exp*1e3}catch(e){throw new x({message:"could not decode access token",cause:e})}},be=async t=>{try{return await t.json()}catch{return {}}},St=async t=>Ve.catch({}).parse(await be(t)),At=async(t,e)=>{let n=await St(t),a=n.error??n.code;throw new x({message:n.error_description??n.message??e,status:t.status,...a!==void 0?{code:a}:{}})},xt=async(t,e)=>{let n=Ge.safeParse(await be(t));if(!n.success)throw new x({message:`invalid ${e} response`,status:t.status,cause:n.error});return {token:n.data,expiresAt:Ln(n.data.access_token)}},Un=async t=>{if(t.status===200)return xt(t,"token");let e=await St(t),n=e.error??e.code;switch(n){case "authorization_pending":throw new T({slowDown:false});case "slow_down":throw new T({slowDown:true});case "expired_token":throw new E;case "access_denied":throw new P;default:throw new x({message:e.error_description??e.message??"WorkOS error",status:t.status,...n!==void 0?{code:n}:{}})}},de=class{baseUrl=bt;async requestDeviceAuthorization(){let e=await this.post("/user_management/authorize/device",new URLSearchParams({client_id:ie}),"device authorize request failed");if(e.status!==200)return At(e,"device authorize failed");let n=Ye.safeParse(await be(e));if(!n.success)throw new x({message:"invalid device authorize response",status:e.status,cause:n.error});return n.data}async exchangeDeviceCode(e){let n=await this.post("/user_management/authenticate",JSON.stringify({grant_type:Mn,client_id:ie,device_code:e}),"authenticate request failed",{"Content-Type":"application/json"});return Un(n)}async refresh(e){let n=await this.post("/user_management/authenticate",JSON.stringify({grant_type:Jn,client_id:ie,refresh_token:e}),"refresh request failed",{"Content-Type":"application/json"});return n.status===200?xt(n,"refresh"):At(n,"refresh failed")}async post(e,n,a,s={}){try{return await fetch(`${this.baseUrl}${e}`,{method:"POST",body:n,headers:{Accept:"application/json",...s}})}catch(i){throw new x({message:a,cause:i})}}};var Ct=()=>{let t=pt(),e=new ee,n=new de,a=new Z(t,e,n),s=new G(t,a);return {account:new V(s),auth:a,credentialsStore:e,destinations:new te(s),docs:new ne(t),images:new ae(s),models:new se(s),tasks:new re(s),webhooks:new oe(s),workos:n}};var o=(t="")=>{process.stdout.write(`${t}
3
+ `);},ce=(t="")=>{process.stderr.write(`${t}
4
+ `);};var Wn=t=>new Date(t).toISOString(),Kn=t=>new Promise(e=>setTimeout(e,t)),Ot=Dt.green("\u2713"),$t=(t,e)=>new A({message:e instanceof Error?`${t}: ${e.message}`:t,cause:e}),zn=async(t,e,n,a)=>{let s=n;for(;;){if(Date.now()>=a)throw new A({message:"device code expired before approval"});try{return await t.workos.exchangeDeviceCode(e)}catch(i){if(i instanceof T){i.slowDown&&(s+=5e3),await Kn(s);continue}throw i instanceof P?new A({message:"login denied by user"}):i instanceof E?new A({message:"device code expired"}):i instanceof x?new A({message:i.message,cause:i}):i}}},Ae=t=>{let e=new Command("auth");return e.command("login").description("Authenticate with Mynth using OAuth device login").action(async()=>{if(t.auth.envApiKeySet)throw o(`MYNTH_API_KEY is set in your environment; that takes precedence over login.
5
+ Unset it to use OAuth, or just continue using the env API key.`),new A({message:"env api key takes precedence"});let n;try{n=await t.workos.requestDeviceAuthorization();}catch(i){throw $t("device authorize",i)}o(""),o(` First copy your one-time code: ${n.user_code}`),o(` Then open: ${n.verification_uri_complete??n.verification_uri}`),o(""),o("Waiting for confirmation...");let a=await zn(t,n.device_code,(n.interval??5)*1e3,Date.now()+n.expires_in*1e3);try{await t.auth.saveOAuth({accessToken:a.token.access_token,refreshToken:a.token.refresh_token,expiresAt:a.expiresAt,...a.token.user?{user:a.token.user}:{}});}catch(i){throw $t("could not save credentials",i)}let s=a.token.user?.email??a.token.user?.id??"unknown user";o(`${Ot} Logged in as ${s}`);}),e.command("logout").description("Clear local Mynth credentials").action(async()=>{await t.auth.logout(),o(`${Ot} Local credentials cleared`),t.auth.envApiKeySet&&o("Note: MYNTH_API_KEY is still set in your environment and will be used.");}),e.command("status").description("Show current authentication status").action(async()=>{let n=await t.auth.status(),s=await t.credentialsStore.usingKeychain()?"system keychain":`file (${t.credentialsStore.filePath})`;switch(n.kind){case "env":o("Authenticated via env: MYNTH_API_KEY");return;case "none":o("Not authenticated. Run `mynth auth login` or set an API key.");return;case "api_key":o(`Authenticated via stored API key (${s})`);return;case "oauth":{let i=n.user?.email??n.user?.id??"unknown user";o(`Authenticated via OAuth as ${i} (${s})`),o(` access token expires: ${Wn(n.expiresAt)}`);}}}),e.addCommand(le(t)),e},le=t=>new Command("whoami").description("Print the active Mynth identity, verified against the API").action(async()=>{let e=await t.auth.status();if(e.kind==="none")throw o("not authenticated"),new O;let n=e.kind==="env"?"env:MYNTH_API_KEY":e.kind==="api_key"?"api-key":e.user?.email??e.user?.id??"oauth",a=await t.account.me();o(n),o(` user: ${a.userId}`),a.auth.apiKey&&o(` key: ${a.auth.apiKey.name??"unnamed"} (${a.auth.apiKey.keyPreview})`);});var Se=t=>new Command("balance").description("Show account balance and API key spending limit usage").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async e=>{let n=await t.account.balance();if(e.json){o(JSON.stringify(n,null,2));return}o(`Balance: $${n.balance}`),o(`Reserved: $${n.reserved}`),o(`Available: $${n.available}`),n.apiKey&&(o(""),o(`API key limit: $${n.apiKey.spendingLimit} / ${n.apiKey.spendingLimitPeriod}`),o(` used: $${n.apiKey.usedInPeriod}`),o(` remaining: $${n.apiKey.remainingInPeriod}`));});var _t=Dt.green("\u2713"),Hn=async()=>{try{let t="";process.stdin.setEncoding("utf8");for await(let e of process.stdin)t+=e;return t.trim()}catch(t){throw new A({message:"could not read stdin",cause:t})}},Ce=t=>{let e=new Command("config"),n=new Command("set").description("Set local CLI configuration");n.command("api-key").description("Save a Mynth API key").argument("<value>","API key value, or `-` to read from stdin").action(async s=>{let i=s==="-"?await Hn():s;if(i.length===0)throw new A({message:"API key is empty"});try{await t.auth.setApiKey(i);}catch(d){throw new A({message:`could not save API key: ${d.message}`,cause:d})}o(`${_t} API key saved`),t.auth.envApiKeySet&&o("Note: MYNTH_API_KEY is also set in your environment and will take precedence.");});let a=new Command("unset").description("Unset local CLI configuration");return a.command("api-key").description("Clear stored Mynth credentials").action(async()=>{await t.auth.logout(),o(`${_t} Stored credentials cleared`);}),e.addCommand(n),e.addCommand(a),e};var C=async t=>{if((await t.auth.status()).kind!=="oauth")throw new O({reason:"destination/webhook commands require OAuth login (run 'mynth auth login'); API key auth is not supported for this resource yet"})},Gn=async()=>{let t="";process.stdin.setEncoding("utf8");for await(let e of process.stdin)t+=e;return t},Oe=async t=>{let e;try{e=t==="-"?await Gn():await readFile(t,"utf8");}catch(n){throw new l(`could not read ${t}: ${n.message}`)}try{return JSON.parse(e)}catch(n){throw new l(`invalid JSON in ${t}: ${n.message}`)}};var Tt=/^[a-z0-9-]+$/,Et=t=>{let e=t.provider;return typeof e?.id=="string"?e.id:"-"},Xn=t=>{if(t.length===0){o("No destinations found.");return}let e=t.map(s=>({id:s.id,name:s.name,provider:Et(s),created:s.createdAt})),n=(s,i)=>Math.max(i.length,...e.map(d=>d[s].length)),a={id:n("id","ID"),name:n("name","Name"),provider:n("provider","Provider")};o(["ID".padEnd(a.id),"Name".padEnd(a.name),"Provider".padEnd(a.provider),"Created"].join(" "));for(let s of e)o([s.id.padEnd(a.id),s.name.padEnd(a.name),s.provider.padEnd(a.provider),s.created].join(" "));},$e=t=>{o(`Destination ${t.id}`),o(` Name: ${t.name}`),o(` Provider: ${Et(t)}`),o(` Created: ${t.createdAt}`),o(` Updated: ${t.updatedAt}`);},Re=t=>{let e=new Command("destination").description("Manage storage destinations (OAuth login required)");return e.command("list").description("List storage destinations").option("--json","Output machine-readable JSON instead of a human-readable table").action(async n=>{await C(t);let a=await t.destinations.list();if(n.json){o(JSON.stringify(a,null,2));return}Xn(a);}),e.command("get").description("Fetch a destination by ID").argument("<id>","Destination ID").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async(n,a)=>{await C(t);let s=await t.destinations.get(n);if(a.json){o(JSON.stringify(s,null,2));return}$e(s);}),e.command("create").description("Create a destination from a JSON file ({ name, provider, config, secret })").requiredOption("--file <path>","Path to a JSON file, or `-` to read from stdin").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async n=>{await C(t);let a=await Oe(n.file),s=a?.name;if(typeof s!="string"||s.length<1||s.length>64||!Tt.test(s))throw new l(`invalid destination name: expected 1-64 chars matching ${Tt.source}`);let i=await t.destinations.create(a);if(n.json){o(JSON.stringify(i,null,2));return}$e(i),o(""),o(`Next: verify credentials with 'mynth destination test ${i.id}'`);}),e.command("update").description("Update a destination from a JSON file ({ provider, config, secret? })").argument("<id>","Destination ID").requiredOption("--file <path>","Path to a JSON file, or `-` to read from stdin").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async(n,a)=>{await C(t);let s=await Oe(a.file),{name:i,...d}=s??{},f=await t.destinations.update(n,d);if(a.json){o(JSON.stringify(f,null,2));return}$e(f);}),e.command("test").description("Test a destination's credentials by uploading a probe file").argument("<id>","Destination ID").option("--path <path>","Object path to write (defaults to a unique probe path)").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async(n,a)=>{await C(t);let s=a.path??`mynth-cli-test/${Date.now()}.txt`;if(await t.destinations.test(n,s),a.json){o(JSON.stringify({id:n,path:s,ok:true},null,2));return}o(`\u2713 credentials valid (wrote ${s})`);}),e.command("delete").description("Delete a destination (requires --yes)").argument("<id>","Destination ID").option("--yes","Confirm deletion (required; no interactive prompt)").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async(n,a)=>{if(a.yes!==true)throw new l("refusing to delete without --yes");if(await C(t),await t.destinations.delete(n),a.json){o(JSON.stringify({deleted:n},null,2));return}o(`\u2713 deleted destination ${n}`);}),e};var _e=t=>{let e=new Command("docs").description("Read Mynth documentation");return e.command("get").description("Fetch a documentation page as Markdown").argument("<path>","Documentation path without the .md suffix").option("--json","Output machine-readable JSON").action(async(n,a)=>{let s=await t.docs.get(n);o(a.json?JSON.stringify(s,null,2):s.content);}),e.command("list").description("Fetch the complete documentation index").option("--json","Output machine-readable JSON").action(async n=>{let a=await t.docs.list();o(n.json?JSON.stringify({content:a},null,2):a);}),e};var ea=["Priming the canvas","Summoning pixels","Mixing digital pigments","Whispering to the model","Dreaming up details","Sketching silhouettes","Arranging composition","Weaving light and shadow","Polishing reflections","Sculpting atmosphere","Tracing final strokes"],ta=()=>typeof process<"u"&&process.stderr&&process.stderr.isTTY===true,na=t=>{let e=t.slice();for(let n=e.length-1;n>0;n--){let a=Math.floor(Math.random()*(n+1));[e[n],e[a]]=[e[a],e[n]];}return e},ue=async(t,e={})=>{if(!ta())return t;let n=na(e.messages??ea),a=0,s=Qn({text:n[0]??"Working",stream:process.stderr}).start(),i=setInterval(()=>{a++,s.text=n[a%n.length]??"Working";},2800);try{return await t}finally{clearInterval(i),s.stop();}};var Te=20,oa="webp",ia=80,Ie=["auto","person","garment","pose","source","reference"],da="https://dry-run.mynth.io/input",$=Dt.green("\u2713"),ca=Dt.red("\u2717"),Ee=()=>new Option("--json","Output machine-readable JSON instead of a human-readable summary"),la=z.array(z.object({value:z.string(),description:z.string()})),me=t=>/^https?:\/\//i.test(t),Nt=(t,e=[])=>[...e,t],Mt=t=>{let e=Number.parseInt(t,10);if(!Number.isInteger(e)||String(e)!==t)throw new l(`invalid integer: "${t}"`);return e},ua=t=>{let e=Mt(t);if(e<1||e>100)throw new l(`invalid quality: "${t}" (expected 1-100)`);return e},pa=t=>{let e=t.indexOf("=");if(e<=0)throw new l(`invalid --level "${t}": expected "value=description"`);let n={value:t.slice(0,e).trim(),description:t.slice(e+1).trim()};if(n.value.length===0||n.description.length===0)throw new l(`invalid --level "${t}": value and description must be non-empty`);return n},Pt=(t,e)=>{let n;try{n=JSON.parse(t);}catch(s){throw new l(`invalid JSON in ${e}: ${s.message}`)}let a=la.safeParse(n);if(!a.success)throw new l(`invalid levels in ${e}: expected array of { value, description }`);return a.data},It=async t=>{let e=[t.levelPairs.length>0?"--level":null,t.levelsFile!==void 0?"--levels-file":null,t.levelsJson!==void 0?"--levels-json":null].filter(s=>s!==null);if(e.length===0)return;if(e.length>1)throw new l(`conflicting level options: ${e.join(", ")} - use only one`);let n;if(t.levelPairs.length>0)n=t.levelPairs.map(pa);else if(t.levelsFile!==void 0){let s;try{s=await readFile(t.levelsFile,"utf8");}catch(i){throw new l(`could not read ${t.levelsFile}: ${i.message}`)}n=Pt(s,t.levelsFile);}else n=Pt(t.levelsJson??"[]","--levels-json");if(n.length<F||n.length>W)throw new l(`levels must have between ${F} and ${W} items (got ${n.length})`);let a=new Set;for(let s of n){if(a.has(s.value))throw new l(`duplicate level value: "${s.value}"`);a.add(s.value);}return n},ma=t=>{let e=t.indexOf(":"),n=/^https?:/i.test(t),a,s=t;if(e>0&&!n){let i=t.slice(0,e);if(!Ie.includes(i))throw new l(`invalid --input as "${i}". Expected one of: ${Ie.join(", ")}`);a=i,s=t.slice(e+1);}if(s.length===0)throw new l(`invalid --input "${t}": missing path or URL`);return {...a!==void 0?{as:a}:{},value:s,isFile:!me(s)}},ha=t=>{let e;try{e=JSON.parse(t);}catch(n){throw new l(`invalid --metadata JSON: ${n.message}`)}if(e===null||typeof e!="object"||Array.isArray(e))throw new l("--metadata must be a JSON object");return e},jt=t=>t.option("-l, --level <value>",'Custom rating level as "value=description" (repeatable, 2-7 items). Example: -l safe="No explicit content" -l nsfw="Contains nudity"',Nt).option("--levels-file <path>",'Path to a JSON file containing an array of { "value": string, "description": string } (2-7 items). Alternative to --level when descriptions contain special characters.').option("--levels-json <json>",'Inline JSON array of { "value": string, "description": string } (2-7 items). Alternative to --level / --levels-file.'),je=(t,e)=>{let n=t.result??{},a=n.images??[];e>0&&o(`${$} Uploaded ${e} input image${e===1?"":"s"}`);let s=a.filter(i=>i.status==="success");if(o(`${$} Generated ${s.length}/${a.length} image${a.length===1?"":"s"} (task ${t.id})`),n.model!==void 0&&o(` Model: ${n.model}`),t.cost!==null&&o(` Cost: ${t.cost}`),n.magic_prompt?.positive!==void 0&&(o(""),o("Enhanced prompt (mynth):"),o(` ${n.magic_prompt.positive}`),n.magic_prompt.negative!==void 0&&n.magic_prompt.negative.length>0&&o(` negative: ${n.magic_prompt.negative}`)),a.length>0){o("");for(let i of a){let d=i;if(d.status==="success"){let f=d.rating,w=f?.level!==void 0?` [${f.level}]`:"",y=d.url??d.mynth_url;o(` ${$} ${y}${w}`);}else o(` ${ca} ${ga(d.error)}`);}}},ga=t=>{if(typeof t=="string")return t;if(t!==null&&typeof t=="object"){let e=t,n=typeof e.code=="string"?e.code:"unknown error",a=typeof e.message=="string"?e.message:void 0;return a!==void 0?`${n}: ${a}`:n}return "unknown error"},De=t=>{let e=t.result??{},n=(e.images??[]).map(a=>{let s=a;return s.status==="success"?{status:"success",url:s.url??null,mynth_url:s.mynth_url??null,size:s.size,rating:s.rating}:{status:"failed",error:s.error,mynth_url:s.mynth_url??null}});return {taskId:t.id,status:t.status,images:n,...e.magic_prompt?{magic_prompt:e.magic_prompt}:{},...t.cost!==null?{cost:t.cost}:{},...e.model!==void 0?{model:e.model}:{}}},fa=async(t,e,n)=>{let s=((e.result??{}).images??[]).map(i=>i).filter(i=>i.status==="success").map(i=>i.url??i.mynth_url).filter(i=>typeof i=="string"&&i.length>0);return s.length===0?[]:t.downloadImages({urls:s,destinationDir:n,taskId:e.id})},Ne=t=>{let e=new Command("image");e.command("upload").description("Upload local images to Mynth").argument("<files...>","Path to a local image file (.jpg, .jpeg, .png, .webp)").addOption(Ee()).action(async(s,i)=>{if(s.length>L)throw new l(`too many files: ${s.length} (max ${L})`);let d=await t.images.upload(s);if(i.json){o(JSON.stringify({images:d},null,2));return}o(`${$} Uploaded ${d.length} image${d.length===1?"":"s"}`);for(let{path:f,url:w}of d)o(` ${f}`),o(` -> ${w}`);});let n=e.command("rate").description("Rate images by URL or local file").argument("<image...>","Image URL (http://, https://) or path to a local image file to upload first").addOption(Ee());jt(n),n.action(async(s,i)=>{if(s.length>U)throw new l(`too many images: ${s.length} (max ${U})`);let d=await It({levelPairs:i.level??[],levelsFile:i.levelsFile,levelsJson:i.levelsJson}),f=s.filter(me),w=s.filter(h=>!me(h)),y=w.length>0?await t.images.upload(w):[],he=new Map(y.map(h=>[h.path,h.url])),K=s.map(h=>me(h)?h:he.get(h)??h),R=await t.images.rate({urls:K,...d?{levels:d}:{}});if(i.json){o(JSON.stringify(R,null,2));return}let z=R.results.filter(h=>h.status==="success"),q=R.results.filter(h=>h.status==="failed");y.length>0&&o(`${$} Uploaded ${y.length} image${y.length===1?"":"s"}`),o(`${$} Rated ${z.length}/${R.results.length} (task ${R.task.id})`);for(let h of z)o(` ${h.level} ${h.url}`);for(let h of q)o(` ERROR ${h.error.code} ${h.url}`);if(f.length===0&&y.length>0){o(""),o("Uploaded source files:");for(let h of y)o(` ${h.path} -> ${h.url}`);}});let a=e.command("generate").description("Generate images with Mynth").addHelpText("after",`
6
+ Models: mynth models list`);return a.option("-p, --prompt <text>","Text prompt describing the image to generate").option("-n, --negative <text>","Negative prompt (elements to exclude)").addOption(new Option("--enhance <mode>",'Prompt enhancement mode: "prefer_magic" (Mynth) or "none". "prefer_native" is no longer supported by the API.').choices(["prefer_magic","prefer_native","none"])).option("-m, --model <id>",'Model ID (e.g. "black-forest-labs/flux.1-dev"). Default: "auto"').option("-s, --size <size>",'Size preset or aspect ratio: "square", "portrait", "landscape", "1:1", "16:9", "16:9_4k", "auto", etc.').option("-c, --count <number>","Number of images to generate (default: 1)",Mt).addOption(new Option("-f, --format <format>","Output image format (default: webp)").choices(["png","jpg","webp"])).option("-q, --quality <number>","Output quality 1-100 (default: 80)",ua).option("-i, --input <value>",`Input image as "[as:]path-or-url" (repeatable, up to ${Te}). as is optional and must be one of: ${Ie.join(", ")}. Examples: -i ./img.jpg, -i source:https://example.com/a.png, -i reference:./style.png`,Nt).option("-o, --output-dir <dir>","Directory to save generated images to. Created if it doesn't exist. Ignored in --async mode since the task hasn't completed yet.").option("--destination <name>","Name (slug) of a user-configured destination to deliver the result to. Falls back to MYNTH_DESTINATION env var if not set.").option("--metadata <json>","Inline JSON object of custom metadata to attach to the task (max 2KB)").option("--content-rating","Enable content rating classification using default sfw/nsfw levels. For custom levels use --level / --levels-file / --levels-json.").option("--dry-run","Validate the request and print the estimated cost without generating anything").option("--async","Return the task ID immediately instead of polling until completion").option("--detailed","Include full task data (all fields) in the output").addOption(Ee()),jt(a),a.action(async s=>{let i=s.prompt??"";if(s.enhance==="prefer_native")throw new l('--enhance prefer_native is no longer supported by the API; use "prefer_magic" or "none"');let d=s.input??[];if(d.length>Te)throw new l(`too many --input values: ${d.length} (max ${Te})`);let f=d.map(ma),w=s.metadata!==void 0?ha(s.metadata):void 0,y=await It({levelPairs:s.level??[],levelsFile:s.levelsFile,levelsJson:s.levelsJson}),he=f.filter(m=>m.isFile).map(m=>m.value),K=Array.from(new Set(he)),R=K.length>0&&!s.dryRun?await t.images.upload(K):[],z=new Map(R.map(m=>[m.path,m.url])),q=f.map(m=>({type:"image",...m.as?{as:m.as}:{},source:{type:"url",url:m.isFile?z.get(m.value)??da:m.value}})),h=s.format!==void 0||s.quality!==void 0?{format:s.format??oa,quality:s.quality??ia}:void 0,We=y!==void 0?{mode:"custom",levels:y}:s.contentRating?true:void 0,k={prompt:i};if(s.model!==void 0&&(k.model=s.model),s.negative!==void 0&&(k.negative_prompt=s.negative),s.enhance==="prefer_magic"&&(k.magic_prompt=true),s.size!==void 0&&(k.size=s.size),s.count!==void 0&&(k.count=s.count),h!==void 0&&(k.output=h),q.length>0&&(k.inputs=q),s.destination!==void 0&&(k.destination=s.destination),We!==void 0&&(k.rating=We),w!==void 0&&(k.metadata=w),s.dryRun){let m=await t.images.estimate(k);if(s.json){o(JSON.stringify(m,null,2));return}let M=m.estimateKind==="upper_bound"?" (upper bound)":"";o(`${$} Estimated cost: $${m.estimatedCost}${M}`);return}if(s.async){let m=await t.images.generate({request:k,requestPat:true}),M={taskId:m.taskId,...m.pat!==void 0?{access:{publicAccessToken:m.pat}}:{}};if(s.json){o(JSON.stringify(M,null,2));return}o(`${$} Task created: ${m.taskId}`),m.pat!==void 0&&o(` PAT: ${m.pat}`);return}let Ke=await t.images.generate({request:k,requestPat:true}),ze=t.images.waitForTask(Ke.taskId,Ke.pat),B=s.json?await ze:await ue(ze),D=s.outputDir!==void 0?resolve(s.outputDir):void 0,N=D!==void 0?await fa(t.images,B,D):[];if(s.json){let m=s.detailed?B:De(B),M=D!==void 0?{...m,downloadedFiles:N}:m;o(JSON.stringify(M,null,2));return}if(je(B,R.length),D!==void 0&&N.length>0){o(""),o(`${$} Saved ${N.length} image${N.length===1?"":"s"} to ${D}`);for(let m of N)o(` ${m}`);}}),e};var Me=t=>t??"-",wa=t=>{if(t.length===0){o("No models available.");return}let e=t.map(a=>({id:a.id,name:a.displayName??"-",base:Me(a.pricing?.perImage.base),fourK:Me(a.pricing?.perImage["4k"]),inputFee:Me(a.pricing?.perInput)})),n={id:Math.max(2,...e.map(a=>a.id.length)),name:Math.max(4,...e.map(a=>a.name.length)),base:Math.max(4,...e.map(a=>a.base.length)),fourK:Math.max(2,...e.map(a=>a.fourK.length)),inputFee:Math.max(9,...e.map(a=>a.inputFee.length))};o(["ID".padEnd(n.id),"Name".padEnd(n.name),"Base".padEnd(n.base),"4K".padEnd(n.fourK),"Input fee".padEnd(n.inputFee)].join(" "));for(let a of e)o([a.id.padEnd(n.id),a.name.padEnd(n.name),a.base.padEnd(n.base),a.fourK.padEnd(n.fourK),a.inputFee.padEnd(n.inputFee)].join(" "));},Je=t=>{let e=new Command("models").description("Browse the public Mynth model catalog");return e.command("list").description("List available image generation models").option("--json","Output machine-readable JSON instead of a human-readable table").action(async n=>{let a=await t.models.list();if(n.json){o(JSON.stringify(a,null,2));return}wa(a);}),e};var Jt=300,Lt=t=>e=>{let n=Number.parseInt(e,10);if(!Number.isInteger(n)||String(n)!==e||n<=0)throw new l(`invalid ${t}: "${e}" (expected a positive integer)`);return n},Ft=t=>{switch(t){case "completed":return "\u2713";case "failed":return "\u2717";default:return "\u2026"}},ka=(t,e)=>{let n=" ".repeat(e);return t.split(`
7
+ `).map(a=>`${n}${a}`).join(`
8
+ `)},Ut=t=>{o(`${Ft(t.status)} Task ${t.id}`),o(` Type: ${t.type}`),o(` Status: ${t.status}`),t.cost!==null&&o(` Cost: ${t.cost}`),o(` Created: ${t.createdAt}`),o(` Updated: ${t.updatedAt}`),t.result!==null&&t.result!==void 0&&(o(""),o("Result:"),o(ka(JSON.stringify(t.result,null,2),2)));},ba=t=>{if(t.length===0){o("No tasks found.");return}for(let e of t){let n=e.cost!==null?` ${e.cost}`:"";o(`${Ft(e.status)} ${e.id} ${e.type} ${e.status}${n} ${e.createdAt}`);}},Le=t=>{let e=new Command("task");return e.command("get").description("Fetch a task by ID").argument("<id>","Task ID").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async(n,a)=>{let s=await t.tasks.getTask(n);if(a.json){o(JSON.stringify(s,null,2));return}Ut(s);}),e.command("wait").description("Block until a task completes (or fails), then print it").argument("<id>","Task ID").option("--timeout <seconds>",`Max seconds to wait before giving up (default: ${Jt})`,Lt("--timeout")).option("--detailed","Include full task data (all fields) in the output").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async(n,a)=>{let s=(a.timeout??Jt)*1e3,i=t.tasks.waitForTask(n,s),d=a.json?await i:await ue(i);if(d.status==="failed"&&(process.exitCode=Be(d)),a.json){let f=a.detailed||d.type!=="image.generate"?d:De(d);o(JSON.stringify(f,null,2));return}if(d.type==="image.generate"&&d.status==="completed"){je(d,0);return}Ut(d);}),e.command("list").description("List recent tasks, newest first").option("--limit <number>","Max tasks to return (1-100, default: 20)",Lt("--limit")).option("--after <id>","Cursor: return tasks created before this task ID").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async n=>{let a=await t.tasks.listTasks({...n.limit!==void 0?{limit:n.limit}:{},...n.after!==void 0?{after:n.after}:{}});if(n.json){o(JSON.stringify({tasks:a},null,2));return}ba(a);}),e};var Wt=["task.completed","task.failed","task.image.generate.completed","task.image.generate.failed","task.image.rate.completed","task.image.rate.failed","task.image.alt.completed","task.image.alt.failed"],Kt=(t,e=[])=>[...e,t],zt=t=>{if(t===void 0||t.length===0)throw new l("at least one --event is required");if(t.includes("all"))return "all";for(let e of t)if(!Wt.includes(e))throw new l(`unknown event "${e}". Valid events: all, ${Wt.join(", ")}`);return t},Sa=t=>{if(t.enabled===true&&t.disabled===true)throw new l("--enabled and --disabled are mutually exclusive");return t.disabled!==true},xa=t=>{o(`\u2713 Webhook ${t.id} created`),o(` URL: ${t.url}`),o(` Enabled: ${t.enabled}`),o(` Events: ${Array.isArray(t.events)?t.events.join(", "):t.events}`),o(""),o(` Signing secret: ${t.secret}`),o(" Save this now \u2014 it is shown only once and cannot be retrieved again.");},Ca=t=>{o(`\u2713 Webhook ${t.id} updated`),o(` URL: ${t.url}`),t.enabled!==void 0&&o(` Enabled: ${t.enabled}`),o(` Events: ${Array.isArray(t.events)?t.events.join(", "):t.events}`);},Ue=t=>{let e=new Command("webhook").description("Manage registered webhooks (OAuth login required)");return e.command("create").description("Register a webhook; the signing secret is shown once on success").requiredOption("--url <url>","Destination URL for webhook deliveries").option("-e, --event <name>","Event to subscribe to (repeatable, or `all`)",Kt).option("--disabled","Create the webhook disabled (default: enabled)").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async n=>{await C(t);let a={enabled:n.disabled!==true,url:n.url,events:zt(n.event)},s=await t.webhooks.create(a);if(n.json){o(JSON.stringify(s,null,2));return}xa(s);}),e.command("update").description("Replace a webhook's configuration (all fields required)").argument("<id>","Webhook ID").requiredOption("--url <url>","Destination URL for webhook deliveries").option("-e, --event <name>","Event to subscribe to (repeatable, or `all`)",Kt).option("--enabled","Enable the webhook").option("--disabled","Disable the webhook").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async(n,a)=>{await C(t);let s={enabled:Sa(a),url:a.url,events:zt(a.event)},i=await t.webhooks.update(n,s);if(a.json){o(JSON.stringify(i,null,2));return}Ca(i);}),e.command("delete").description("Delete a webhook (requires --yes)").argument("<id>","Webhook ID").option("--yes","Confirm deletion (required; no interactive prompt)").option("--json","Output machine-readable JSON instead of a human-readable summary").action(async(n,a)=>{if(a.yes!==true)throw new l("refusing to delete without --yes");if(await C(t),await t.webhooks.delete(n),a.json){o(JSON.stringify({deleted:n},null,2));return}o(`\u2713 deleted webhook ${n}`);}),e};var Fe=class extends Help{optionTerm(e){return `(${e.flags.replaceAll("<","").replaceAll(">","")})`}subcommandTerm(e){let n=e.registeredArguments.map(a=>a.required?`${a.name()}${a.variadic?"...":""}`:`[${a.name()}]`).join(" ");return n.length>0?`${e.name()} ${n}`:e.name()}},qt=()=>{let t=Ct(),e=new Command("mynth");return e.description("Official Mynth CLI").version("0.0.12"),e.addHelpText("after",`
9
9
  Exit codes:
10
10
  0 success
11
11
  1 error (network, server, or unexpected failure)
@@ -13,4 +13,4 @@ Exit codes:
13
13
  3 authentication error (missing or invalid credentials)
14
14
  4 insufficient credits
15
15
  5 blocked by content moderation
16
- 6 rate limited`),e.addCommand(we(t)),e.addCommand(ve(t)),e.addCommand(Ae(t)),e.addCommand(Se(t)),e.addCommand(Ce(t)),e.addCommand(Pe(t)),e.addCommand(Oe(t)),e.addCommand(ie(t)),Tt(e),e},Tt=t=>{t.configureHelp({helpWidth:100}),t.createHelp=()=>new Ie;for(let e of t.commands)Tt(e);};var es=process.env.MYNTH_DEBUG==="1"||process.env.MYNTH_DEBUG==="true",ts=t=>t instanceof Error?t.message:String(t),Rt=t=>{t.exitOverride();for(let e of t.commands)Rt(e);},ns=async()=>{let t=_t();Rt(t);try{await t.parseAsync(process.argv);}catch(e){let n=e.code;if(n==="commander.helpDisplayed"||n==="commander.version")return;(typeof n!="string"||!n.startsWith("commander."))&&(oe(ts(e)),es&&e instanceof Error&&(oe("=== MYNTH_DEBUG cause ==="),oe(JSON.stringify(e.cause??e,null,2)))),process.exitCode=De(e);}};await ns();
16
+ 6 rate limited`),e.addCommand(Ae(t)),e.addCommand(Se(t)),e.addCommand(Ce(t)),e.addCommand(Re(t)),e.addCommand(_e(t)),e.addCommand(Ne(t)),e.addCommand(Je(t)),e.addCommand(Le(t)),e.addCommand(Ue(t)),e.addCommand(le(t)),Bt(e),e},Bt=t=>{t.configureHelp({helpWidth:100}),t.createHelp=()=>new Fe;for(let e of t.commands)Bt(e);};var Ra=process.env.MYNTH_DEBUG==="1"||process.env.MYNTH_DEBUG==="true",_a=t=>t instanceof Error?t.message:String(t),Ht=t=>{t.exitOverride();for(let e of t.commands)Ht(e);},Ta=async()=>{let t=qt();Ht(t);try{await t.parseAsync(process.argv);}catch(e){let n=e.code;if(n==="commander.helpDisplayed"||n==="commander.version")return;(typeof n!="string"||!n.startsWith("commander."))&&(ce(_a(e)),Ra&&e instanceof Error&&(ce("=== MYNTH_DEBUG cause ==="),ce(JSON.stringify(e.cause??e,null,2)))),process.exitCode=qe(e);}};await Ta();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mynthio/cli",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "description": "Official Mynth CLI",
5
5
  "keywords": [
6
6
  "ai",