phala 1.0.32 → 1.0.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -59,7 +59,7 @@ ${v}/dashboard/cvms/app_${n.app_id}`)}catch(r){o.error(`Failed to stop CVM: ${r
59
59
  ${v}/dashboard/cvms/app_${n.app_id}`)}catch(r){o.error(`Failed to restart CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as to}from"commander";import ie from"chalk";var Mr=new to().name("attestation").description("Get attestation information for a CVM").argument("[app-id]","CVM app ID (will prompt for selection if not provided)").option("-j, --json","Output in JSON format").action(async(e,r)=>{try{let t;if(e)t=await re(e);else{o.info("No CVM specified, fetching available CVMs...");let s=await te();if(!s)return;t=s}let n=o.startSpinner(`Fetching attestation information for CVM app_${t}...`);try{let s=await We(t);if(n.stop(!0),!s||Object.keys(s).length===0){o.info("No attestation information found");return}if(r?.json){o.info(JSON.stringify(s,null,2));return}o.success("Attestation Summary:");let i={Status:s.is_online?ie.green("Online"):ie.red("Offline"),"Public Access":s.is_public?ie.green("Enabled"):ie.yellow("Disabled"),Error:s.error||"None",Certificates:`${s.app_certificates?.length||0} found`};if(o.keyValueTable(i,{borderStyle:"rounded"}),s.app_certificates&&s.app_certificates.length>0&&s.app_certificates.forEach((c,m)=>{o.break(),o.success(`Certificate #${m+1} (${c.position_in_chain===0?"End Entity":"CA"}):`);let p={Subject:`${c.subject.common_name||"Unknown"}${c.subject.organization?` (${c.subject.organization})`:""}`,Issuer:`${c.issuer.common_name||"Unknown"}${c.issuer.organization?` (${c.issuer.organization})`:""}`,"Serial Number":c.serial_number,Validity:`${new Date(c.not_before).toLocaleString()} to ${new Date(c.not_after).toLocaleString()}`,Fingerprint:c.fingerprint,"Signature Algorithm":c.signature_algorithm,"Is CA":c.is_ca?"Yes":"No","Position in Chain":c.position_in_chain};o.keyValueTable(p,{borderStyle:"rounded"})}),s.tcb_info){o.break(),o.success("Trusted Computing Base (TCB) Information:");let c={Mrtd:s.tcb_info.mrtd,"Rootfs Hash":s.tcb_info.rootfs_hash,Rtmr0:s.tcb_info.rtmr0,Rtmr1:s.tcb_info.rtmr1,Rtmr2:s.tcb_info.rtmr2,Rtmr3:s.tcb_info.rtmr3,"Event Log Entries":`${s.tcb_info.event_log.length} entries`};if(o.keyValueTable(c,{borderStyle:"rounded"}),s.tcb_info.event_log&&s.tcb_info.event_log.length>0){o.break(),o.success("Event Log (Showing entries to reproduce RTMR3):");let m=5,p=s.tcb_info.event_log.filter(l=>l.event!==null&&l.event!=="").map(l=>({Event:l.event,IMR:l.imr.toString(),"Event Type":l.event_type.toString(),Payload:l.event_payload}));o.table(p,[{key:"Event",header:"Event",minWidth:8},{key:"IMR",header:"IMR",minWidth:3},{key:"Event Type",header:"Type",minWidth:8},{key:"Payload",header:"Payload",minWidth:25}]),s.tcb_info.event_log.length>m&&o.info("To see all full attestation data, use --json"),o.break(),o.success("To reproduce RTMR3, use the tool at https://rtmr3-calculator.vercel.app/")}}}catch(s){throw n.stop(!1),s}}catch(t){o.error(`Failed to get attestation information: ${t instanceof Error?t.message:String(t)}`)}});import{Command as oo}from"commander";import{encryptEnvVars as no}from"@phala/cloud";import Lr from"node:fs";import so from"node:path";import Ur from"inquirer";import*as Nr from"node:fs";var X=(e,r)=>{let t={};if(e){for(let n of e)if(n.includes("=")){let[s,...i]=n.split("="),c=i.join("=");s&&(t[s]=c)}}if(r){let n=Nr.readFileSync(r,"utf8");for(let s of n.split(`
60
60
  `)){if(!s.trim()||s.trim().startsWith("#"))continue;let i=-1,c=!1,m="";for(let g=0;g<s.length;g++)if((s[g]==='"'||s[g]==="'"||s[g]==="`")&&(g===0||s[g-1]!=="\\"))c&&s[g]===m?(c=!1,m=""):c||(c=!0,m=s[g]);else if(s[g]==="="&&!c){i=g;break}else if(s[g]==="#"&&!c)break;if(i===-1){s.trim().startsWith("#");continue}let p=s.substring(0,i).trim(),l=s.substring(i+1),a=!1,f="",u=-1;for(let g=0;g<l.length;g++)if((l[g]==='"'||l[g]==="'"||l[g]==="`")&&(g===0||l[g-1]!=="\\"))a&&l[g]===f?(a=!1,f=""):a||(a=!0,f=l[g]);else if(l[g]==="#"&&!a&&g>0&&l[g-1]===" "){u=g-1;break}else if(l[g]==="#"&&!a&&g===0){u=g;break}u!==-1&&(l=l.substring(0,u)),l===void 0&&(l="");let d=l.charAt(0),y=l.charAt(l.length-1);d==='"'&&y==='"'||d==="'"&&y==="'"||d==="`"&&y==="`"?(l=l.substring(1,l.length-1),d==='"'&&(l=l.replace(/\\\\n/g,`
61
61
  `))):l=l.trim(),p&&(t[p]=l)}}return Object.entries(t).map(([n,s])=>({key:n,value:s}))};var Vr=new oo().name("create").description("Create a new CVM").option("-n, --name <name>","Name of the CVM").option("-c, --compose <compose>","Path to Docker Compose file").option("--vcpu <vcpu>",`Number of vCPUs, default is ${R}`).option("--memory <memory>",`Memory in MB, default is ${M}`).option("--disk-size <diskSize>",`Disk size in GB, default is ${N}`).option("--teepod-id <teepodId>","TEEPod ID to use. If not provided, it will be selected from the list of available TEEPods.").option("--image <image>","Version of dstack image to use. If not provided, it will be selected from the list of available images for the selected TEEPod.").option("-e, --env-file <envFile>","Path to environment file").option("--skip-env","Skip environment variable prompt",!1).option("--debug","Enable debug mode",!1).action(async e=>{try{if(!e.name){let{name:_}=await Ur.prompt([{type:"input",name:"name",message:"Enter a name for the CVM:",validate:$=>$.trim()?$.trim().length>20?"CVM name must be less than 20 characters":$.trim().length<3?"CVM name must be at least 3 characters":/^[a-zA-Z0-9_-]+$/.test($)?!0:"CVM name must contain only letters, numbers, underscores, and hyphens":"CVM name is required"}]);e.name=_}if(!e.compose){let $=j(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");e.compose=await I("Enter the path to your Docker Compose file:",$,"file")}let r=so.resolve(e.compose);Lr.existsSync(r)||(o.error(`Docker Compose file not found: ${r}`),process.exit(1));let t=Lr.readFileSync(r,"utf8");await U(),process.env.DSTACK_DOCKER_USERNAME&&process.env.DSTACK_DOCKER_PASSWORD?o.info("\u{1F510} Using private DockerHub registry credentials..."):process.env.DSTACK_AWS_ACCESS_KEY_ID&&process.env.DSTACK_AWS_SECRET_ACCESS_KEY&&process.env.DSTACK_AWS_REGION&&process.env.DSTACK_AWS_ECR_REGISTRY?o.info(`\u{1F510} Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`):o.info("\u{1F510} Using public DockerHub registry...");let n=[];if(e.envFile)try{n=X([],e.envFile)}catch(_){o.error(`Failed to read environment file: ${_ instanceof Error?_.message:String(_)}`),process.exit(1)}else if(!e.skipEnv){let{shouldSkip:_}=await Ur.prompt([{type:"confirm",name:"shouldSkip",message:"Do you want to skip environment variable prompt?",default:!0}]);if(_)o.info("Skipping environment variable prompt");else{let $=await I("Enter the path to your environment file:",".env","file");n=X([],$)}}let s=Number(e.vcpu)||R,i=Number(e.memory)||M,c=Number(e.diskSize)||N;(Number.isNaN(s)||s<=0)&&(o.error(`Invalid number of vCPUs: ${s}`),process.exit(1)),(Number.isNaN(i)||i<=0)&&(o.error(`Invalid memory: ${i}`),process.exit(1)),(Number.isNaN(c)||c<=0)&&(o.error(`Invalid disk size: ${c}`),process.exit(1));let m=o.startSpinner("Fetching available TEEPods"),p=await K();m.stop(!0),p.nodes.length===0&&(o.error("No TEEPods available. Please try again later."),process.exit(1));let l;e.teepodId?(l=p.nodes.find(_=>_.teepod_id===Number(e.teepodId)),l||(o.error("Failed to find selected TEEPod"),process.exit(1))):(l=p.nodes[0],l||(o.error("Failed to find default TEEPod"),process.exit(1)));let a;e.image?(a=l.images?.find(_=>_.name===e.image),a||(o.error(`Failed to find selected image: ${e.image}`),process.exit(1))):(a=l.images?.find(_=>_.name===ge),a||(o.error(`Failed to find default image ${ge}`),process.exit(1)));let f={teepod_id:l.teepod_id,name:e.name,image:a.name,vcpu:s,memory:i,disk_size:c,compose_manifest:{docker_compose_file:t,docker_config:{url:"",username:"",password:""},features:["kms","tproxy-net"],kms_enabled:!0,manifest_version:2,name:e.name,public_logs:!0,public_sysinfo:!0,tproxy_enabled:!0},listed:!1},u=o.startSpinner("Getting public key from CVM"),d=await Ke(f);u.stop(!0),d||(o.error("Failed to get public key from CVM"),process.exit(1));let y=o.startSpinner("Encrypting environment variables"),g=await no(n,d.app_env_encrypt_pubkey);y.stop(!0),e.debug&&(o.debug("Public key:",d.app_env_encrypt_pubkey),o.debug("Encrypted environment variables:",g),o.debug("Environment variables:",JSON.stringify(n)));let C=o.startSpinner("Creating CVM"),w=await je({...f,encrypted_env:g,app_env_encrypt_pubkey:d.app_env_encrypt_pubkey,app_id_salt:d.app_id_salt});C.stop(!0),w||(o.error("Failed to create CVM"),process.exit(1)),o.success("CVM created successfully"),o.break();let me={"CVM ID":w.id,Name:w.name,Status:w.status,"App ID":`app_${w.app_id}`,"App URL":w.app_url?w.app_url:`${v}/dashboard/cvms/app_${w.app_id}`};o.keyValueTable(me,{borderStyle:"rounded"}),o.info(""),o.success(`Your CVM is being created. You can check its status with:
62
- phala cvms get app_${w.app_id}`)}catch(r){o.error(`Failed to create CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as io}from"commander";import ao from"inquirer";var Or=new io().name("delete").description("Delete a CVM").argument("[app-id]","App ID of the CVM to delete (if not provided, a selection prompt will appear)").option("-f, --force","Skip confirmation prompt",!1).action(async(e,r)=>{try{let t=await b(e);if(!r.force){let{confirm:i}=await ao.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete CVM with App ID app_${t}? This action cannot be undone.`,default:!1}]);if(!i){o.info("Deletion cancelled");return}}let n=o.startSpinner(`Deleting CVM app_${t}`),s=await ze(t);n.stop(!0),s||(o.error(`Failed to delete CVM app_${t}`),process.exit(1)),o.success(`CVM app_${t} deleted successfully`)}catch(t){o.error(`Failed to delete CVM: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as en}from"commander";import Wo from"node:http";import Jo from"node:https";var T=!!globalThis.process?.env?.FORCE_NODE_FETCH,Se=!T&&globalThis.fetch||sr,pc=!T&&globalThis.Blob||Xe,uc=!T&&globalThis.File||Ze,dc=!T&&globalThis.FormData||er,Kr=!T&&globalThis.Headers||rr,fc=!T&&globalThis.Request||or,gc=!T&&globalThis.Response||tr,jr=!T&&globalThis.AbortController||nr;var co=/"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/,mo=/"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/,lo=/^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/;function po(e,r){if(e==="__proto__"||e==="constructor"&&r&&typeof r=="object"&&"prototype"in r){uo(e);return}return r}function uo(e){console.warn(`[destr] Dropping "${e}" key to prevent prototype pollution.`)}function Br(e,r={}){if(typeof e!="string")return e;if(e[0]==='"'&&e[e.length-1]==='"'&&e.indexOf("\\")===-1)return e.slice(1,-1);let t=e.trim();if(t.length<=9)switch(t.toLowerCase()){case"true":return!0;case"false":return!1;case"undefined":return;case"null":return null;case"nan":return Number.NaN;case"infinity":return Number.POSITIVE_INFINITY;case"-infinity":return Number.NEGATIVE_INFINITY}if(!lo.test(e)){if(r.strict)throw new SyntaxError("[destr] Invalid JSON");return e}try{if(co.test(e)||mo.test(e)){if(r.strict)throw new Error("[destr] Possible prototype pollution");return JSON.parse(e,po)}return JSON.parse(e)}catch(n){if(r.strict)throw n;return e}}var wc=String.fromCharCode;var fo=/#/g,go=/&/g,ho=/\//g,yo=/=/g;var Pe=/\+/g,vo=/%5e/gi,wo=/%60/gi;var Co=/%7c/gi;var Eo=/%20/gi;function _o(e){return encodeURI(""+e).replace(Co,"|")}function Ie(e){return _o(typeof e=="string"?e:JSON.stringify(e)).replace(Pe,"%2B").replace(Eo,"+").replace(fo,"%23").replace(go,"%26").replace(wo,"`").replace(vo,"^").replace(ho,"%2F")}function $e(e){return Ie(e).replace(yo,"%3D")}function Gr(e=""){try{return decodeURIComponent(""+e)}catch{return""+e}}function bo(e){return Gr(e.replace(Pe," "))}function ko(e){return Gr(e.replace(Pe," "))}function So(e=""){let r=Object.create(null);e[0]==="?"&&(e=e.slice(1));for(let t of e.split("&")){let n=t.match(/([^=]+)=?(.*)/)||[];if(n.length<2)continue;let s=bo(n[1]);if(s==="__proto__"||s==="constructor")continue;let i=ko(n[2]||"");r[s]===void 0?r[s]=i:Array.isArray(r[s])?r[s].push(i):r[s]=[r[s],i]}return r}function $o(e,r){return(typeof r=="number"||typeof r=="boolean")&&(r=String(r)),r?Array.isArray(r)?r.map(t=>`${$e(e)}=${Ie(t)}`).join("&"):`${$e(e)}=${Ie(r)}`:$e(e)}function Io(e){return Object.keys(e).filter(r=>e[r]!==void 0).map(r=>$o(r,e[r])).filter(Boolean).join("&")}var Do=/^[\s\w\0+.-]{2,}:([/\\]{1,2})/,Po=/^[\s\w\0+.-]{2,}:([/\\]{2})?/,Ao=/^([/\\]\s*){2,}[^/\\]/;var Fo=/\/$|\/\?|\/#/,To=/^\.?\//;function Hr(e,r={}){return typeof r=="boolean"&&(r={acceptRelative:r}),r.strict?Do.test(e):Po.test(e)||(r.acceptRelative?Ao.test(e):!1)}function De(e="",r){return r?Fo.test(e):e.endsWith("/")}function xo(e="",r){if(!r)return(De(e)?e.slice(0,-1):e)||"/";if(!De(e,!0))return e||"/";let t=e,n="",s=e.indexOf("#");s!==-1&&(t=e.slice(0,s),n=e.slice(s));let[i,...c]=t.split("?");return((i.endsWith("/")?i.slice(0,-1):i)||"/")+(c.length>0?`?${c.join("?")}`:"")+n}function Ro(e="",r){if(!r)return e.endsWith("/")?e:e+"/";if(De(e,!0))return e||"/";let t=e,n="",s=e.indexOf("#");if(s!==-1&&(t=e.slice(0,s),n=e.slice(s),!t))return n;let[i,...c]=t.split("?");return i+"/"+(c.length>0?`?${c.join("?")}`:"")+n}function zr(e,r){if(Mo(r)||Hr(e))return e;let t=xo(r);return e.startsWith(t)?e:Lo(t,e)}function Wr(e,r){let t=Yr(e),n={...So(t.search),...r};return t.search=Io(n),Uo(t)}function Mo(e){return!e||e==="/"}function No(e){return e&&e!=="/"}function Lo(e,...r){let t=e||"";for(let n of r.filter(s=>No(s)))if(t){let s=n.replace(To,"");t=Ro(t)+s}else t=n;return t}var Jr=Symbol.for("ufo:protocolRelative");function Yr(e="",r){let t=e.match(/^[\s\0]*(blob:|data:|javascript:|vbscript:)(.*)/i);if(t){let[,f,u=""]=t;return{protocol:f.toLowerCase(),pathname:u,href:f+u,auth:"",host:"",search:"",hash:""}}if(!Hr(e,{acceptRelative:!0}))return r?Yr(r+e):qr(e);let[,n="",s,i=""]=e.replace(/\\/g,"/").match(/^[\s\0]*([\w+.-]{2,}:)?\/\/([^/@]+@)?(.*)/)||[],[,c="",m=""]=i.match(/([^#/?]*)(.*)?/)||[];n==="file:"&&(m=m.replace(/\/(?=[A-Za-z]:)/,""));let{pathname:p,search:l,hash:a}=qr(m);return{protocol:n.toLowerCase(),auth:s?s.slice(0,Math.max(0,s.length-1)):"",host:c,pathname:p,search:l,hash:a,[Jr]:!n}}function qr(e=""){let[r="",t="",n=""]=(e.match(/([^#?]*)(\?[^#]*)?(#.*)?/)||[]).splice(1);return{pathname:r,search:t,hash:n}}function Uo(e){let r=e.pathname||"",t=e.search?(e.search.startsWith("?")?"":"?")+e.search:"",n=e.hash||"",s=e.auth?e.auth+"@":"",i=e.host||"";return(e.protocol||e[Jr]?(e.protocol||"")+"//":"")+s+i+r+t+n}var B=class extends Error{constructor(r,t){super(r,t),this.name="FetchError",t?.cause&&!this.cause&&(this.cause=t.cause)}};function Xr(e){let r=e.error?.message||e.error?.toString()||"",t=e.request?.method||e.options?.method||"GET",n=e.request?.url||String(e.request)||"/",s=`[${t}] ${JSON.stringify(n)}`,i=e.response?`${e.response.status} ${e.response.statusText}`:"<no response>",c=`${s}: ${i}${r?` ${r}`:""}`,m=new B(c,e.error?{cause:e.error}:void 0);for(let p of["request","options","response"])Object.defineProperty(m,p,{get(){return e[p]}});for(let[p,l]of[["data","_data"],["status","status"],["statusCode","status"],["statusText","statusText"],["statusMessage","statusText"]])Object.defineProperty(m,p,{get(){return e.response&&e.response[l]}});return m}var Vo=new Set(Object.freeze(["PATCH","POST","PUT","DELETE"]));function Qr(e="GET"){return Vo.has(e.toUpperCase())}function Oo(e){if(e===void 0)return!1;let r=typeof e;return r==="string"||r==="number"||r==="boolean"||r===null?!0:r!=="object"?!1:Array.isArray(e)?!0:e.buffer?!1:e.constructor&&e.constructor.name==="Object"||typeof e.toJSON=="function"}var Ko=new Set(["image/svg","application/xml","application/xhtml","application/html"]),jo=/^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;function Bo(e=""){if(!e)return"json";let r=e.split(";").shift()||"";return jo.test(r)?"json":Ko.has(r)||r.startsWith("text/")?"text":"blob"}function qo(e,r,t,n){let s=Go(r?.headers??e?.headers,t?.headers,n),i;return(t?.query||t?.params||r?.params||r?.query)&&(i={...t?.params,...t?.query,...r?.params,...r?.query}),{...t,...r,query:i,params:i,headers:s}}function Go(e,r,t){if(!r)return new t(e);let n=new t(r);if(e)for(let[s,i]of Symbol.iterator in e||Array.isArray(e)?e:new t(e))n.set(s,i);return n}async function ae(e,r){if(r)if(Array.isArray(r))for(let t of r)await t(e);else await r(e)}var Ho=new Set([408,409,425,429,500,502,503,504]),zo=new Set([101,204,205,304]);function Ae(e={}){let{fetch:r=globalThis.fetch,Headers:t=globalThis.Headers,AbortController:n=globalThis.AbortController}=e;async function s(m){let p=m.error&&m.error.name==="AbortError"&&!m.options.timeout||!1;if(m.options.retry!==!1&&!p){let a;typeof m.options.retry=="number"?a=m.options.retry:a=Qr(m.options.method)?0:1;let f=m.response&&m.response.status||500;if(a>0&&(Array.isArray(m.options.retryStatusCodes)?m.options.retryStatusCodes.includes(f):Ho.has(f))){let u=typeof m.options.retryDelay=="function"?m.options.retryDelay(m):m.options.retryDelay||0;return u>0&&await new Promise(d=>setTimeout(d,u)),i(m.request,{...m.options,retry:a-1})}}let l=Xr(m);throw Error.captureStackTrace&&Error.captureStackTrace(l,i),l}let i=async function(p,l={}){let a={request:p,options:qo(p,l,e.defaults,t),response:void 0,error:void 0};a.options.method&&(a.options.method=a.options.method.toUpperCase()),a.options.onRequest&&await ae(a,a.options.onRequest),typeof a.request=="string"&&(a.options.baseURL&&(a.request=zr(a.request,a.options.baseURL)),a.options.query&&(a.request=Wr(a.request,a.options.query),delete a.options.query),"query"in a.options&&delete a.options.query,"params"in a.options&&delete a.options.params),a.options.body&&Qr(a.options.method)&&(Oo(a.options.body)?(a.options.body=typeof a.options.body=="string"?a.options.body:JSON.stringify(a.options.body),a.options.headers=new t(a.options.headers||{}),a.options.headers.has("content-type")||a.options.headers.set("content-type","application/json"),a.options.headers.has("accept")||a.options.headers.set("accept","application/json")):("pipeTo"in a.options.body&&typeof a.options.body.pipeTo=="function"||typeof a.options.body.pipe=="function")&&("duplex"in a.options||(a.options.duplex="half")));let f;if(!a.options.signal&&a.options.timeout){let d=new n;f=setTimeout(()=>{let y=new Error("[TimeoutError]: The operation was aborted due to timeout");y.name="TimeoutError",y.code=23,d.abort(y)},a.options.timeout),a.options.signal=d.signal}try{a.response=await r(a.request,a.options)}catch(d){return a.error=d,a.options.onRequestError&&await ae(a,a.options.onRequestError),await s(a)}finally{f&&clearTimeout(f)}if((a.response.body||a.response._bodyInit)&&!zo.has(a.response.status)&&a.options.method!=="HEAD"){let d=(a.options.parseResponse?"json":a.options.responseType)||Bo(a.response.headers.get("content-type")||"");switch(d){case"json":{let y=await a.response.text(),g=a.options.parseResponse||Br;a.response._data=g(y);break}case"stream":{a.response._data=a.response.body||a.response._bodyInit;break}default:a.response._data=await a.response[d]()}}return a.options.onResponse&&await ae(a,a.options.onResponse),!a.options.ignoreResponseError&&a.response.status>=400&&a.response.status<600?(a.options.onResponseError&&await ae(a,a.options.onResponseError),await s(a)):a.response},c=async function(p,l){return(await i(p,l))._data};return c.raw=i,c.native=(...m)=>r(...m),c.create=(m={},p={})=>Ae({...e,...p,defaults:{...e.defaults,...p.defaults,...m}}),c}function Yo(){if(!JSON.parse(process.env.FETCH_KEEP_ALIVE||"false"))return Se;let r={keepAlive:!0},t=new Wo.Agent(r),n=new Jo.Agent(r),s={agent(i){return i.protocol==="http:"?t:n}};return function(c,m){return Se(c,{...s,...m})}}var Qo=globalThis.fetch?(...e)=>globalThis.fetch(...e):Yo(),Xo=globalThis.Headers||Kr,Zo=globalThis.AbortController||jr,Dc=Ae({fetch:Qo,Headers:Xo,AbortController:Zo});import rn from"node:fs";import{encryptEnvVars as tn}from"@phala/cloud";var Zr=new en().name("upgrade").description("Upgrade a CVM to a new version").argument("[app-id]","CVM app ID to upgrade (will prompt for selection if not provided)").option("-c, --compose <compose>","Path to new Docker Compose file").option("-e, --env-file <envFile>","Path to environment file").option("--debug","Enable debug mode",!1).action(async(e,r)=>{try{let t=await b(e),n=o.startSpinner(`Fetching current configuration for CVM app_${t}`),s=await O(t);if(n.stop(!0),s||(o.error(`CVM with App ID app_${t} not found`),process.exit(1)),!r.compose){let u=j(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");r.compose=await I("Enter the path to your Docker Compose file:",u,"file")}let i="",c=[];if(r.compose)try{i=rn.readFileSync(r.compose,"utf8")}catch(f){o.error(`Failed to read Docker Compose file: ${f instanceof Error?f.message:String(f)}`),process.exit(1)}await U(),process.env.DSTACK_DOCKER_USERNAME&&process.env.DSTACK_DOCKER_PASSWORD?o.info("\u{1F510} Using private DockerHub registry credentials..."):process.env.DSTACK_AWS_ACCESS_KEY_ID&&process.env.DSTACK_AWS_SECRET_ACCESS_KEY&&process.env.DSTACK_AWS_REGION&&process.env.DSTACK_AWS_ECR_REGISTRY?o.info(`\u{1F510} Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`):o.info("\u{1F510} Using public DockerHub registry...");let m;if(r.envFile){let f=[];if(r.envFile)try{f=X([],r.envFile),m=await tn(f,s.encrypted_env_pubkey),c=f.map(u=>u.keys)}catch(u){o.error(`Failed to read environment file: ${u instanceof Error?u.message:String(u)}`),process.exit(1)}}let p={compose_manifest:{docker_compose_file:i,manifest_version:1,runner:"docker-compose",version:"1.0.0",features:["kms","tproxy-net"],name:`app_${t}`},encrypted_env:m,allow_restart:!0,env_keys:c},l=o.startSpinner(`Upgrading CVM app_${t}`),a=await He(t,p);a||(l.stop(!1),o.error("Failed to upgrade CVM"),process.exit(1)),l.stop(!0),a.detail&&o.info(`Details: ${a.detail}`),o.break(),o.success(`Your CVM is being upgraded. You can check the dashboard for more details:
62
+ phala cvms get app_${w.app_id}`)}catch(r){o.error(`Failed to create CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as io}from"commander";import ao from"inquirer";var Or=new io().name("delete").description("Delete a CVM").argument("[app-id]","App ID of the CVM to delete (if not provided, a selection prompt will appear)").option("-f, --force","Skip confirmation prompt",!1).action(async(e,r)=>{try{let t=await b(e);if(!r.force){let{confirm:i}=await ao.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete CVM with App ID app_${t}? This action cannot be undone.`,default:!1}]);if(!i){o.info("Deletion cancelled");return}}let n=o.startSpinner(`Deleting CVM app_${t}`),s=await ze(t);n.stop(!0),s||(o.error(`Failed to delete CVM app_${t}`),process.exit(1)),o.success(`CVM app_${t} deleted successfully`)}catch(t){o.error(`Failed to delete CVM: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as en}from"commander";import Wo from"node:http";import Jo from"node:https";var T=!!globalThis.process?.env?.FORCE_NODE_FETCH,Se=!T&&globalThis.fetch||sr,pc=!T&&globalThis.Blob||Xe,uc=!T&&globalThis.File||Ze,dc=!T&&globalThis.FormData||er,Kr=!T&&globalThis.Headers||rr,fc=!T&&globalThis.Request||or,gc=!T&&globalThis.Response||tr,jr=!T&&globalThis.AbortController||nr;var co=/"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/,mo=/"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/,lo=/^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/;function po(e,r){if(e==="__proto__"||e==="constructor"&&r&&typeof r=="object"&&"prototype"in r){uo(e);return}return r}function uo(e){console.warn(`[destr] Dropping "${e}" key to prevent prototype pollution.`)}function Br(e,r={}){if(typeof e!="string")return e;if(e[0]==='"'&&e[e.length-1]==='"'&&e.indexOf("\\")===-1)return e.slice(1,-1);let t=e.trim();if(t.length<=9)switch(t.toLowerCase()){case"true":return!0;case"false":return!1;case"undefined":return;case"null":return null;case"nan":return Number.NaN;case"infinity":return Number.POSITIVE_INFINITY;case"-infinity":return Number.NEGATIVE_INFINITY}if(!lo.test(e)){if(r.strict)throw new SyntaxError("[destr] Invalid JSON");return e}try{if(co.test(e)||mo.test(e)){if(r.strict)throw new Error("[destr] Possible prototype pollution");return JSON.parse(e,po)}return JSON.parse(e)}catch(n){if(r.strict)throw n;return e}}var wc=String.fromCharCode;var fo=/#/g,go=/&/g,ho=/\//g,yo=/=/g;var Pe=/\+/g,vo=/%5e/gi,wo=/%60/gi;var Co=/%7c/gi;var Eo=/%20/gi;function _o(e){return encodeURI(""+e).replace(Co,"|")}function Ie(e){return _o(typeof e=="string"?e:JSON.stringify(e)).replace(Pe,"%2B").replace(Eo,"+").replace(fo,"%23").replace(go,"%26").replace(wo,"`").replace(vo,"^").replace(ho,"%2F")}function $e(e){return Ie(e).replace(yo,"%3D")}function Gr(e=""){try{return decodeURIComponent(""+e)}catch{return""+e}}function bo(e){return Gr(e.replace(Pe," "))}function ko(e){return Gr(e.replace(Pe," "))}function So(e=""){let r=Object.create(null);e[0]==="?"&&(e=e.slice(1));for(let t of e.split("&")){let n=t.match(/([^=]+)=?(.*)/)||[];if(n.length<2)continue;let s=bo(n[1]);if(s==="__proto__"||s==="constructor")continue;let i=ko(n[2]||"");r[s]===void 0?r[s]=i:Array.isArray(r[s])?r[s].push(i):r[s]=[r[s],i]}return r}function $o(e,r){return(typeof r=="number"||typeof r=="boolean")&&(r=String(r)),r?Array.isArray(r)?r.map(t=>`${$e(e)}=${Ie(t)}`).join("&"):`${$e(e)}=${Ie(r)}`:$e(e)}function Io(e){return Object.keys(e).filter(r=>e[r]!==void 0).map(r=>$o(r,e[r])).filter(Boolean).join("&")}var Do=/^[\s\w\0+.-]{2,}:([/\\]{1,2})/,Po=/^[\s\w\0+.-]{2,}:([/\\]{2})?/,Ao=/^([/\\]\s*){2,}[^/\\]/;var Fo=/\/$|\/\?|\/#/,To=/^\.?\//;function Hr(e,r={}){return typeof r=="boolean"&&(r={acceptRelative:r}),r.strict?Do.test(e):Po.test(e)||(r.acceptRelative?Ao.test(e):!1)}function De(e="",r){return r?Fo.test(e):e.endsWith("/")}function xo(e="",r){if(!r)return(De(e)?e.slice(0,-1):e)||"/";if(!De(e,!0))return e||"/";let t=e,n="",s=e.indexOf("#");s!==-1&&(t=e.slice(0,s),n=e.slice(s));let[i,...c]=t.split("?");return((i.endsWith("/")?i.slice(0,-1):i)||"/")+(c.length>0?`?${c.join("?")}`:"")+n}function Ro(e="",r){if(!r)return e.endsWith("/")?e:e+"/";if(De(e,!0))return e||"/";let t=e,n="",s=e.indexOf("#");if(s!==-1&&(t=e.slice(0,s),n=e.slice(s),!t))return n;let[i,...c]=t.split("?");return i+"/"+(c.length>0?`?${c.join("?")}`:"")+n}function zr(e,r){if(Mo(r)||Hr(e))return e;let t=xo(r);return e.startsWith(t)?e:Lo(t,e)}function Wr(e,r){let t=Yr(e),n={...So(t.search),...r};return t.search=Io(n),Uo(t)}function Mo(e){return!e||e==="/"}function No(e){return e&&e!=="/"}function Lo(e,...r){let t=e||"";for(let n of r.filter(s=>No(s)))if(t){let s=n.replace(To,"");t=Ro(t)+s}else t=n;return t}var Jr=Symbol.for("ufo:protocolRelative");function Yr(e="",r){let t=e.match(/^[\s\0]*(blob:|data:|javascript:|vbscript:)(.*)/i);if(t){let[,f,u=""]=t;return{protocol:f.toLowerCase(),pathname:u,href:f+u,auth:"",host:"",search:"",hash:""}}if(!Hr(e,{acceptRelative:!0}))return r?Yr(r+e):qr(e);let[,n="",s,i=""]=e.replace(/\\/g,"/").match(/^[\s\0]*([\w+.-]{2,}:)?\/\/([^/@]+@)?(.*)/)||[],[,c="",m=""]=i.match(/([^#/?]*)(.*)?/)||[];n==="file:"&&(m=m.replace(/\/(?=[A-Za-z]:)/,""));let{pathname:p,search:l,hash:a}=qr(m);return{protocol:n.toLowerCase(),auth:s?s.slice(0,Math.max(0,s.length-1)):"",host:c,pathname:p,search:l,hash:a,[Jr]:!n}}function qr(e=""){let[r="",t="",n=""]=(e.match(/([^#?]*)(\?[^#]*)?(#.*)?/)||[]).splice(1);return{pathname:r,search:t,hash:n}}function Uo(e){let r=e.pathname||"",t=e.search?(e.search.startsWith("?")?"":"?")+e.search:"",n=e.hash||"",s=e.auth?e.auth+"@":"",i=e.host||"";return(e.protocol||e[Jr]?(e.protocol||"")+"//":"")+s+i+r+t+n}var B=class extends Error{constructor(r,t){super(r,t),this.name="FetchError",t?.cause&&!this.cause&&(this.cause=t.cause)}};function Xr(e){let r=e.error?.message||e.error?.toString()||"",t=e.request?.method||e.options?.method||"GET",n=e.request?.url||String(e.request)||"/",s=`[${t}] ${JSON.stringify(n)}`,i=e.response?`${e.response.status} ${e.response.statusText}`:"<no response>",c=`${s}: ${i}${r?` ${r}`:""}`,m=new B(c,e.error?{cause:e.error}:void 0);for(let p of["request","options","response"])Object.defineProperty(m,p,{get(){return e[p]}});for(let[p,l]of[["data","_data"],["status","status"],["statusCode","status"],["statusText","statusText"],["statusMessage","statusText"]])Object.defineProperty(m,p,{get(){return e.response&&e.response[l]}});return m}var Vo=new Set(Object.freeze(["PATCH","POST","PUT","DELETE"]));function Qr(e="GET"){return Vo.has(e.toUpperCase())}function Oo(e){if(e===void 0)return!1;let r=typeof e;return r==="string"||r==="number"||r==="boolean"||r===null?!0:r!=="object"?!1:Array.isArray(e)?!0:e.buffer?!1:e.constructor&&e.constructor.name==="Object"||typeof e.toJSON=="function"}var Ko=new Set(["image/svg","application/xml","application/xhtml","application/html"]),jo=/^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;function Bo(e=""){if(!e)return"json";let r=e.split(";").shift()||"";return jo.test(r)?"json":Ko.has(r)||r.startsWith("text/")?"text":"blob"}function qo(e,r,t,n){let s=Go(r?.headers??e?.headers,t?.headers,n),i;return(t?.query||t?.params||r?.params||r?.query)&&(i={...t?.params,...t?.query,...r?.params,...r?.query}),{...t,...r,query:i,params:i,headers:s}}function Go(e,r,t){if(!r)return new t(e);let n=new t(r);if(e)for(let[s,i]of Symbol.iterator in e||Array.isArray(e)?e:new t(e))n.set(s,i);return n}async function ae(e,r){if(r)if(Array.isArray(r))for(let t of r)await t(e);else await r(e)}var Ho=new Set([408,409,425,429,500,502,503,504]),zo=new Set([101,204,205,304]);function Ae(e={}){let{fetch:r=globalThis.fetch,Headers:t=globalThis.Headers,AbortController:n=globalThis.AbortController}=e;async function s(m){let p=m.error&&m.error.name==="AbortError"&&!m.options.timeout||!1;if(m.options.retry!==!1&&!p){let a;typeof m.options.retry=="number"?a=m.options.retry:a=Qr(m.options.method)?0:1;let f=m.response&&m.response.status||500;if(a>0&&(Array.isArray(m.options.retryStatusCodes)?m.options.retryStatusCodes.includes(f):Ho.has(f))){let u=typeof m.options.retryDelay=="function"?m.options.retryDelay(m):m.options.retryDelay||0;return u>0&&await new Promise(d=>setTimeout(d,u)),i(m.request,{...m.options,retry:a-1})}}let l=Xr(m);throw Error.captureStackTrace&&Error.captureStackTrace(l,i),l}let i=async function(p,l={}){let a={request:p,options:qo(p,l,e.defaults,t),response:void 0,error:void 0};a.options.method&&(a.options.method=a.options.method.toUpperCase()),a.options.onRequest&&await ae(a,a.options.onRequest),typeof a.request=="string"&&(a.options.baseURL&&(a.request=zr(a.request,a.options.baseURL)),a.options.query&&(a.request=Wr(a.request,a.options.query),delete a.options.query),"query"in a.options&&delete a.options.query,"params"in a.options&&delete a.options.params),a.options.body&&Qr(a.options.method)&&(Oo(a.options.body)?(a.options.body=typeof a.options.body=="string"?a.options.body:JSON.stringify(a.options.body),a.options.headers=new t(a.options.headers||{}),a.options.headers.has("content-type")||a.options.headers.set("content-type","application/json"),a.options.headers.has("accept")||a.options.headers.set("accept","application/json")):("pipeTo"in a.options.body&&typeof a.options.body.pipeTo=="function"||typeof a.options.body.pipe=="function")&&("duplex"in a.options||(a.options.duplex="half")));let f;if(!a.options.signal&&a.options.timeout){let d=new n;f=setTimeout(()=>{let y=new Error("[TimeoutError]: The operation was aborted due to timeout");y.name="TimeoutError",y.code=23,d.abort(y)},a.options.timeout),a.options.signal=d.signal}try{a.response=await r(a.request,a.options)}catch(d){return a.error=d,a.options.onRequestError&&await ae(a,a.options.onRequestError),await s(a)}finally{f&&clearTimeout(f)}if((a.response.body||a.response._bodyInit)&&!zo.has(a.response.status)&&a.options.method!=="HEAD"){let d=(a.options.parseResponse?"json":a.options.responseType)||Bo(a.response.headers.get("content-type")||"");switch(d){case"json":{let y=await a.response.text(),g=a.options.parseResponse||Br;a.response._data=g(y);break}case"stream":{a.response._data=a.response.body||a.response._bodyInit;break}default:a.response._data=await a.response[d]()}}return a.options.onResponse&&await ae(a,a.options.onResponse),!a.options.ignoreResponseError&&a.response.status>=400&&a.response.status<600?(a.options.onResponseError&&await ae(a,a.options.onResponseError),await s(a)):a.response},c=async function(p,l){return(await i(p,l))._data};return c.raw=i,c.native=(...m)=>r(...m),c.create=(m={},p={})=>Ae({...e,...p,defaults:{...e.defaults,...p.defaults,...m}}),c}function Yo(){if(!JSON.parse(process.env.FETCH_KEEP_ALIVE||"false"))return Se;let r={keepAlive:!0},t=new Wo.Agent(r),n=new Jo.Agent(r),s={agent(i){return i.protocol==="http:"?t:n}};return function(c,m){return Se(c,{...s,...m})}}var Qo=globalThis.fetch?(...e)=>globalThis.fetch(...e):Yo(),Xo=globalThis.Headers||Kr,Zo=globalThis.AbortController||jr,Dc=Ae({fetch:Qo,Headers:Xo,AbortController:Zo});import rn from"node:fs";import{encryptEnvVars as tn}from"@phala/cloud";var Zr=new en().name("upgrade").description("Upgrade a CVM to a new version").argument("[app-id]","CVM app ID to upgrade (will prompt for selection if not provided)").option("-c, --compose <compose>","Path to new Docker Compose file").option("-e, --env-file <envFile>","Path to environment file").option("--debug","Enable debug mode",!1).action(async(e,r)=>{try{let t=await b(e),n=o.startSpinner(`Fetching current configuration for CVM app_${t}`),s=await O(t);if(n.stop(!0),s||(o.error(`CVM with App ID app_${t} not found`),process.exit(1)),!r.compose){let u=j(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");r.compose=await I("Enter the path to your Docker Compose file:",u,"file")}let i="",c=[];if(r.compose)try{i=rn.readFileSync(r.compose,"utf8")}catch(f){o.error(`Failed to read Docker Compose file: ${f instanceof Error?f.message:String(f)}`),process.exit(1)}await U(),process.env.DSTACK_DOCKER_USERNAME&&process.env.DSTACK_DOCKER_PASSWORD?o.info("\u{1F510} Using private DockerHub registry credentials..."):process.env.DSTACK_AWS_ACCESS_KEY_ID&&process.env.DSTACK_AWS_SECRET_ACCESS_KEY&&process.env.DSTACK_AWS_REGION&&process.env.DSTACK_AWS_ECR_REGISTRY?o.info(`\u{1F510} Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`):o.info("\u{1F510} Using public DockerHub registry...");let m;if(r.envFile){let f=[];if(r.envFile)try{f=X([],r.envFile),m=await tn(f,s.encrypted_env_pubkey),c=f.map(u=>u.key)}catch(u){o.error(`Failed to read environment file: ${u instanceof Error?u.message:String(u)}`),process.exit(1)}}let p={compose_manifest:{docker_compose_file:i,manifest_version:1,runner:"docker-compose",version:"1.0.0",features:["kms","tproxy-net"],name:`app_${t}`,allowed_envs:c},encrypted_env:m,allow_restart:!0,env_keys:c},l=o.startSpinner(`Upgrading CVM app_${t}`),a=await He(t,p);a||(l.stop(!1),o.error("Failed to upgrade CVM"),process.exit(1)),l.stop(!0),a.detail&&o.info(`Details: ${a.detail}`),o.break(),o.success(`Your CVM is being upgraded. You can check the dashboard for more details:
63
63
  ${v}/dashboard/cvms/app_${t}`)}catch(t){if(o.error(`Failed to upgrade CVM: ${t instanceof Error?t.message:String(t)}`),t instanceof B||t?.constructor?.name==="FetchError"||t&&typeof t=="object"&&"status"in t&&"statusText"in t&&"data"in t){let s=t;o.error("=== HTTP Error Details ==="),o.error("Status:",s.status),o.error("Status Text:",s.statusText),o.error("URL:",s.request),o.error("Response Body:",JSON.stringify(s.data,null,2)),r.debug&&o.error("Full Error Object:",t)}else r.debug&&o.error("Full Error:",t);process.exit(1)}});import{Command as on}from"commander";import Z from"inquirer";import x from"chalk";var et=new on().name("resize").description("Resize resources for a CVM").argument("[app-id]","App ID of the CVM (if not provided, a selection prompt will appear)").option("-v, --vcpu <vcpu>","Number of virtual CPUs").option("-m, --memory <memory>","Memory size in MB").option("-d, --disk-size <diskSize>","Disk size in GB").option("-r, --allow-restart <allowRestart>","Allow restart of the CVM if needed for resizing").option("-y, --yes","Automatically confirm the resize operation").action(async(e,r)=>{try{let t=await b(e),n=await O(t),s=r.vcpu,i=r.memory,c=r.diskSize,m=r.allowRestart;s||(s=(await Z.prompt([{type:"input",name:"vcpu",message:"Enter number of vCPUs:",validate:u=>{let d=parseInt(u);return isNaN(d)||d<0?"Please enter a valid non-negative number":!0},default:n.vcpu,filter:u=>parseInt(u)}])).vcpu),i||(i=(await Z.prompt([{type:"input",name:"memory",message:"Enter memory in MB:",validate:u=>{let d=parseInt(u);return isNaN(d)||d<0?"Please enter a valid non-negative number":!0},default:n.memory,filter:u=>parseInt(u)}])).memory),c||(c=(await Z.prompt([{type:"input",name:"diskSize",message:"Enter disk size in GB:",validate:u=>{let d=parseInt(u);return isNaN(d)||d<0?"Please enter a valid non-negative number":!0},default:n.disk_size,filter:u=>parseInt(u)}])).diskSize),m||(m=(await Z.prompt([{type:"confirm",name:"allowRestart",message:"Allow restart of the CVM if needed for resizing?",default:!1}])).allowRestart);let p=`Are you sure you want to resize CVM app_${t} with the following changes:
64
64
  `;if(o.keyValueTable({vCPUs:n.vcpu!==s?`${x.red(n.vcpu)} -> ${x.green(s)}`:n.vcpu,Memory:n.memory!==i?`${x.red(n.memory)} MB -> ${x.green(i)} MB`:n.memory,"Disk Size":n.disk_size!==c?`${x.red(n.disk_size)} GB -> ${x.green(c)} GB`:n.disk_size,"Allow Restart":m?x.green("Yes"):x.red("No")}),!r.yes){let{confirm:f}=await Z.prompt([{type:"confirm",name:"confirm",message:p,default:!1}]);if(!f){o.info("Resize operation cancelled");return}}let l=o.startSpinner(`Resizing CVM with App ID app_${t}`);await Qe(t,s,i,c,m?1:0),l.stop(!0),o.break(),o.success(`Your CVM is being resized. You can check the dashboard for more details:
65
65
  ${v}/dashboard/cvms/app_${t}`)}catch(t){o.error(`Failed to resize CVM: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as nn}from"commander";var rt=new nn().name("list-nodes").description("List all available worker nodes.").action(async()=>{try{let{nodes:e,kms_list:r}=await K();if(e.length===0){o.info("No available nodes found.");return}o.info("Available Nodes:"),e.forEach(t=>{o.info("----------------------------------------"),o.info(` ID: ${t.teepod_id}`),o.info(` Name: ${t.name}`),o.info(` Region: ${t.region_identifier}`),o.info(` FMSPC: ${t.fmspc||"N/A"}`),o.info(` Device ID: ${t.device_id||"N/A"}`),o.info(` Support Onchain KMS: ${t.support_onchain_kms}`),o.info(" Images:"),t.images&&t.images.length>0?t.images.forEach(n=>{o.info(` - ${n.name}`),o.info(` Hash: ${n.os_image_hash||"N/A"}`)}):o.info(" N/A")}),r&&r.length>0&&(o.info(`