phala 1.0.17 → 1.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.
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
@@ -54,7 +54,7 @@ ${h}/dashboard/cvms/app_${i.app_id}`)}catch(t){e.error(`Failed to start CVM: ${t
|
|
54
54
|
${h}/dashboard/cvms/app_${i.app_id}`)}catch(t){e.error(`Failed to stop CVM: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as er}from"commander";var it=new er().name("restart").description("Restart a CVM").argument("[app-id]","App ID of the CVM (if not provided, a selection prompt will appear)").action(async o=>{try{let t=await w(o),r=e.startSpinner(`Restarting CVM with App ID app_${t}`),i=await Se(t);r.stop(!0),e.break();let n={"CVM ID":i.id,Name:i.name,Status:i.status,"App ID":`app_${i.app_id}`,"App URL":i.app_url?i.app_url:`${h}/dashboard/cvms/app_${i.app_id}`};e.keyValueTable(n,{borderStyle:"rounded"}),e.break(),e.success(`Your CVM is being restarted. You can check the dashboard for more details:
|
55
55
|
${h}/dashboard/cvms/app_${i.app_id}`)}catch(t){e.error(`Failed to restart CVM: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as tr}from"commander";import oe from"chalk";var nt=new tr().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(o,t)=>{try{let r;if(o)r=await q(o);else{e.info("No CVM specified, fetching available CVMs...");let n=await Z();if(!n)return;r=n}let i=e.startSpinner(`Fetching attestation information for CVM app_${r}...`);try{let n=await $e(r);if(i.stop(!0),!n||Object.keys(n).length===0){e.info("No attestation information found");return}if(t?.json){e.info(JSON.stringify(n,null,2));return}e.success("Attestation Summary:");let m={Status:n.is_online?oe.green("Online"):oe.red("Offline"),"Public Access":n.is_public?oe.green("Enabled"):oe.yellow("Disabled"),Error:n.error||"None",Certificates:`${n.app_certificates?.length||0} found`};if(e.keyValueTable(m,{borderStyle:"rounded"}),n.app_certificates&&n.app_certificates.length>0&&n.app_certificates.forEach((a,c)=>{e.break(),e.success(`Certificate #${c+1} (${a.position_in_chain===0?"End Entity":"CA"}):`);let l={Subject:`${a.subject.common_name||"Unknown"}${a.subject.organization?` (${a.subject.organization})`:""}`,Issuer:`${a.issuer.common_name||"Unknown"}${a.issuer.organization?` (${a.issuer.organization})`:""}`,"Serial Number":a.serial_number,Validity:`${new Date(a.not_before).toLocaleString()} to ${new Date(a.not_after).toLocaleString()}`,Fingerprint:a.fingerprint,"Signature Algorithm":a.signature_algorithm,"Is CA":a.is_ca?"Yes":"No","Position in Chain":a.position_in_chain};e.keyValueTable(l,{borderStyle:"rounded"})}),n.tcb_info){e.break(),e.success("Trusted Computing Base (TCB) Information:");let a={Mrtd:n.tcb_info.mrtd,"Rootfs Hash":n.tcb_info.rootfs_hash,Rtmr0:n.tcb_info.rtmr0,Rtmr1:n.tcb_info.rtmr1,Rtmr2:n.tcb_info.rtmr2,Rtmr3:n.tcb_info.rtmr3,"Event Log Entries":`${n.tcb_info.event_log.length} entries`};if(e.keyValueTable(a,{borderStyle:"rounded"}),n.tcb_info.event_log&&n.tcb_info.event_log.length>0){e.break(),e.success("Event Log (Showing entries to reproduce RTMR3):");let c=5,l=n.tcb_info.event_log.filter(s=>s.event!==null&&s.event!=="").map(s=>({Event:s.event,IMR:s.imr.toString(),"Event Type":s.event_type.toString(),Payload:s.event_payload}));e.table(l,[{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}]),n.tcb_info.event_log.length>c&&e.info("To see all full attestation data, use --json"),e.break(),e.success("To reproduce RTMR3, use the tool at https://rtmr3-calculator.vercel.app/")}}}catch(n){throw i.stop(!1),n}}catch(r){e.error(`Failed to get attestation information: ${r instanceof Error?r.message:String(r)}`)}});import{Command as rr}from"commander";import{encryptEnvVars as or}from"@phala/dstack-sdk/encrypt-env-vars";import st from"node:fs";import ir from"node:path";import mt from"inquirer";import*as at from"node:fs";var M=(o,t)=>{let r={};if(o){for(let i of o)if(i.includes("=")){let[n,...m]=i.split("="),a=m.join("=");n&&(r[n]=a)}}if(t){let i=at.readFileSync(t,"utf8");for(let n of i.split(`
|
56
56
|
`)){if(!n.trim()||n.trim().startsWith("#"))continue;let m=-1,a=!1,c="";for(let d=0;d<n.length;d++)if((n[d]==='"'||n[d]==="'"||n[d]==="`")&&(d===0||n[d-1]!=="\\"))a&&n[d]===c?(a=!1,c=""):a||(a=!0,c=n[d]);else if(n[d]==="="&&!a){m=d;break}else if(n[d]==="#"&&!a)break;if(m===-1){n.trim().startsWith("#");continue}let l=n.substring(0,m).trim(),s=n.substring(m+1),f=!1,g="",p=-1;for(let d=0;d<s.length;d++)if((s[d]==='"'||s[d]==="'"||s[d]==="`")&&(d===0||s[d-1]!=="\\"))f&&s[d]===g?(f=!1,g=""):f||(f=!0,g=s[d]);else if(s[d]==="#"&&!f&&d>0&&s[d-1]===" "){p=d-1;break}else if(s[d]==="#"&&!f&&d===0){p=d;break}p!==-1&&(s=s.substring(0,p)),s===void 0&&(s="");let u=s.charAt(0),y=s.charAt(s.length-1);u==='"'&&y==='"'||u==="'"&&y==="'"||u==="`"&&y==="`"?(s=s.substring(1,s.length-1),u==='"'&&(s=s.replace(/\\\\n/g,`
|
57
|
-
`))):s=s.trim(),l&&(r[l]=s)}}return Object.entries(r).map(([i,n])=>({key:i,value:n}))};var ct=new rr().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 ${ae}`).option("--memory <memory>",`Memory in MB, default is ${se}`).option("--disk-size <diskSize>",`Disk size in GB, default is ${me}`).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 o=>{try{if(!o.name){let{name:k}=await mt.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"}]);o.name=k}if(!o.compose){let $=ee(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");o.compose=await F("Enter the path to your Docker Compose file:",$,"file")}let t=ir.resolve(o.compose);st.existsSync(t)||(e.error(`Docker Compose file not found: ${t}`),process.exit(1));let r=st.readFileSync(t,"utf8");await T(),process.env.DSTACK_DOCKER_USERNAME&&process.env.DSTACK_DOCKER_PASSWORD?e.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?e.info(`\u{1F510} Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`):e.info("\u{1F510} Using public DockerHub registry...");let i=[];if(o.envFile)try{i=M([],o.envFile)}catch(k){e.error(`Failed to read environment file: ${k instanceof Error?k.message:String(k)}`),process.exit(1)}else if(!o.skipEnv){let{shouldSkip:k}=await mt.prompt([{type:"confirm",name:"shouldSkip",message:"Do you want to skip environment variable prompt?",default:!0}]);if(k)e.info("Skipping environment variable prompt");else{let $=await F("Enter the path to your environment file:",".env","file");i=M([],$)}}let n=Number(o.vcpu)||ae,m=Number(o.memory)||se,a=Number(o.diskSize)||me;(Number.isNaN(n)||n<=0)&&(e.error(`Invalid number of vCPUs: ${n}`),process.exit(1)),(Number.isNaN(m)||m<=0)&&(e.error(`Invalid memory: ${m}`),process.exit(1)),(Number.isNaN(a)||a<=0)&&(e.error(`Invalid disk size: ${a}`),process.exit(1));let c=e.startSpinner("Fetching available TEEPods"),l=await N();c.stop(!0),l.length===0&&(e.error("No TEEPods available. Please try again later."),process.exit(1));let s;o.teepodId?(s=l.find(k=>k.teepod_id===Number(o.teepodId)),s||(e.error("Failed to find selected TEEPod"),process.exit(1))):(s=l[0],s||(e.error("Failed to find default TEEPod"),process.exit(1)));let f;o.image?(f=s.images?.find(k=>k.name===o.image),f||(e.error(`Failed to find selected image: ${o.image}`),process.exit(1))):(f=s.images?.find(k=>k.name===O),f||(e.error(`Failed to find default image ${O}`),process.exit(1)));let g={teepod_id:s.teepod_id,name:o.name,image:f.name,vcpu:n,memory:m,disk_size:a,compose_manifest:{docker_compose_file:r,docker_config:{url:"",username:"",password:""},features:["kms","tproxy-net"],kms_enabled:!0,manifest_version:2,name:o.name,public_logs:!0,public_sysinfo:!0,tproxy_enabled:!0},listed:!1},p=e.startSpinner("Getting public key from CVM"),u=await J(g);p.stop(!0),u||(e.error("Failed to get public key from CVM"),process.exit(1));let y=e.startSpinner("Encrypting environment variables"),d=await or(i,u.app_env_encrypt_pubkey);y.stop(!0),o.debug&&(e.debug("Public key:",u.app_env_encrypt_pubkey),e.debug("Encrypted environment variables:",d),e.debug("Environment variables:",JSON.stringify(i)));let I=e.startSpinner("Creating CVM"),S=await Q({...g,encrypted_env:d,app_env_encrypt_pubkey:u.app_env_encrypt_pubkey,app_id_salt:u.app_id_salt});I.stop(!0),S||(e.error("Failed to create CVM"),process.exit(1)),e.success("CVM created successfully"),e.break();let Et={"CVM ID":S.id,Name:S.name,Status:S.status,"App ID":`app_${S.app_id}`,"App URL":S.app_url?S.app_url:`${h}/dashboard/cvms/app_${S.app_id}`};e.keyValueTable(Et,{borderStyle:"rounded"}),e.info(""),e.success(`Your CVM is being created. You can check its status with:
|
57
|
+
`))):s=s.trim(),l&&(r[l]=s)}}return Object.entries(r).map(([i,n])=>({key:i,value:n}))};var ct=new rr().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 ${ae}`).option("--memory <memory>",`Memory in MB, default is ${se}`).option("--disk-size <diskSize>",`Disk size in GB, default is ${me}`).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 o=>{try{if(!o.name){let{name:k}=await mt.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"}]);o.name=k}if(!o.compose){let $=ee(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");o.compose=await F("Enter the path to your Docker Compose file:",$,"file")}let t=ir.resolve(o.compose);st.existsSync(t)||(e.error(`Docker Compose file not found: ${t}`),process.exit(1));let r=st.readFileSync(t,"utf8");await T(),process.env.DSTACK_DOCKER_USERNAME&&process.env.DSTACK_DOCKER_PASSWORD?e.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?e.info(`\u{1F510} Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`):e.info("\u{1F510} Using public DockerHub registry...");let i=[];if(o.envFile)try{i=M([],o.envFile)}catch(k){e.error(`Failed to read environment file: ${k instanceof Error?k.message:String(k)}`),process.exit(1)}else if(!o.skipEnv){let{shouldSkip:k}=await mt.prompt([{type:"confirm",name:"shouldSkip",message:"Do you want to skip environment variable prompt?",default:!0}]);if(k)e.info("Skipping environment variable prompt");else{let $=await F("Enter the path to your environment file:",".env","file");i=M([],$)}}let n=Number(o.vcpu)||ae,m=Number(o.memory)||se,a=Number(o.diskSize)||me;(Number.isNaN(n)||n<=0)&&(e.error(`Invalid number of vCPUs: ${n}`),process.exit(1)),(Number.isNaN(m)||m<=0)&&(e.error(`Invalid memory: ${m}`),process.exit(1)),(Number.isNaN(a)||a<=0)&&(e.error(`Invalid disk size: ${a}`),process.exit(1));let c=e.startSpinner("Fetching available TEEPods"),l=await N();c.stop(!0),l.nodes.length===0&&(e.error("No TEEPods available. Please try again later."),process.exit(1));let s;o.teepodId?(s=l.nodes.find(k=>k.teepod_id===Number(o.teepodId)),s||(e.error("Failed to find selected TEEPod"),process.exit(1))):(s=l.nodes[0],s||(e.error("Failed to find default TEEPod"),process.exit(1)));let f;o.image?(f=s.images?.find(k=>k.name===o.image),f||(e.error(`Failed to find selected image: ${o.image}`),process.exit(1))):(f=s.images?.find(k=>k.name===O),f||(e.error(`Failed to find default image ${O}`),process.exit(1)));let g={teepod_id:s.teepod_id,name:o.name,image:f.name,vcpu:n,memory:m,disk_size:a,compose_manifest:{docker_compose_file:r,docker_config:{url:"",username:"",password:""},features:["kms","tproxy-net"],kms_enabled:!0,manifest_version:2,name:o.name,public_logs:!0,public_sysinfo:!0,tproxy_enabled:!0},listed:!1},p=e.startSpinner("Getting public key from CVM"),u=await J(g);p.stop(!0),u||(e.error("Failed to get public key from CVM"),process.exit(1));let y=e.startSpinner("Encrypting environment variables"),d=await or(i,u.app_env_encrypt_pubkey);y.stop(!0),o.debug&&(e.debug("Public key:",u.app_env_encrypt_pubkey),e.debug("Encrypted environment variables:",d),e.debug("Environment variables:",JSON.stringify(i)));let I=e.startSpinner("Creating CVM"),S=await Q({...g,encrypted_env:d,app_env_encrypt_pubkey:u.app_env_encrypt_pubkey,app_id_salt:u.app_id_salt});I.stop(!0),S||(e.error("Failed to create CVM"),process.exit(1)),e.success("CVM created successfully"),e.break();let Et={"CVM ID":S.id,Name:S.name,Status:S.status,"App ID":`app_${S.app_id}`,"App URL":S.app_url?S.app_url:`${h}/dashboard/cvms/app_${S.app_id}`};e.keyValueTable(Et,{borderStyle:"rounded"}),e.info(""),e.success(`Your CVM is being created. You can check its status with:
|
58
58
|
phala cvms get app_${S.app_id}`)}catch(t){e.error(`Failed to create CVM: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as nr}from"commander";import ar from"inquirer";var pt=new nr().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(o,t)=>{try{let r=await w(o);if(!t.force){let{confirm:m}=await ar.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete CVM with App ID app_${r}? This action cannot be undone.`,default:!1}]);if(!m){e.info("Deletion cancelled");return}}let i=e.startSpinner(`Deleting CVM app_${r}`),n=await Ee(r);i.stop(!0),n||(e.error(`Failed to delete CVM app_${r}`),process.exit(1)),e.success(`CVM app_${r} deleted successfully`)}catch(r){e.error(`Failed to delete CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as sr}from"commander";import mr from"node:fs";import{encryptEnvVars as cr}from"@phala/dstack-sdk/encrypt-env-vars";var lt=new sr().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(o,t)=>{try{let r=await w(o),i=e.startSpinner(`Fetching current configuration for CVM app_${r}`),n=await V(r);if(i.stop(!0),n||(e.error(`CVM with App ID app_${r} not found`),process.exit(1)),!t.compose){let g=ee(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");t.compose=await F("Enter the path to your Docker Compose file:",g,"file")}let m="";if(t.compose)try{m=mr.readFileSync(t.compose,"utf8")}catch(f){e.error(`Failed to read Docker Compose file: ${f instanceof Error?f.message:String(f)}`),process.exit(1)}await T(),process.env.DSTACK_DOCKER_USERNAME&&process.env.DSTACK_DOCKER_PASSWORD?e.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?e.info(`\u{1F510} Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`):e.info("\u{1F510} Using public DockerHub registry...");let a="";if(t.envFile){let f=[];if(t.envFile)try{f=M([],t.envFile),a=await cr(f,n.encrypted_env_pubkey)}catch(g){e.error(`Failed to read environment file: ${g instanceof Error?g.message:String(g)}`),process.exit(1)}}let c={compose_manifest:{docker_compose_file:m,manifest_version:1,runner:"docker-compose",version:"1.0.0",features:["kms","tproxy-net"],name:`app_${r}`},encrypted_env:a,allow_restart:!0},l=e.startSpinner(`Upgrading CVM app_${r}`),s=await _e(r,c);s||(l.stop(!1),e.error("Failed to upgrade CVM"),process.exit(1)),l.stop(!0),s.detail&&e.info(`Details: ${s.detail}`),e.break(),e.success(`Your CVM is being upgraded. You can check the dashboard for more details:
|
59
59
|
${h}/dashboard/cvms/app_${r}`)}catch(r){e.error(`Failed to upgrade CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as pr}from"commander";import H from"inquirer";import x from"chalk";var dt=new pr().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(o,t)=>{try{let r=await w(o),i=await V(r),n=t.vcpu,m=t.memory,a=t.diskSize,c=t.allowRestart;n||(n=(await H.prompt([{type:"input",name:"vcpu",message:"Enter number of vCPUs:",validate:p=>{let u=parseInt(p);return isNaN(u)||u<0?"Please enter a valid non-negative number":!0},default:i.vcpu,filter:p=>parseInt(p)}])).vcpu),m||(m=(await H.prompt([{type:"input",name:"memory",message:"Enter memory in MB:",validate:p=>{let u=parseInt(p);return isNaN(u)||u<0?"Please enter a valid non-negative number":!0},default:i.memory,filter:p=>parseInt(p)}])).memory),a||(a=(await H.prompt([{type:"input",name:"diskSize",message:"Enter disk size in GB:",validate:p=>{let u=parseInt(p);return isNaN(u)||u<0?"Please enter a valid non-negative number":!0},default:i.disk_size,filter:p=>parseInt(p)}])).diskSize),c||(c=(await H.prompt([{type:"confirm",name:"allowRestart",message:"Allow restart of the CVM if needed for resizing?",default:!1}])).allowRestart);let l=`Are you sure you want to resize CVM app_${r} with the following changes:
|
60
60
|
`;if(e.keyValueTable({vCPUs:i.vcpu!==n?`${x.red(i.vcpu)} -> ${x.green(n)}`:i.vcpu,Memory:i.memory!==m?`${x.red(i.memory)} MB -> ${x.green(m)} MB`:i.memory,"Disk Size":i.disk_size!==a?`${x.red(i.disk_size)} GB -> ${x.green(a)} GB`:i.disk_size,"Allow Restart":c?x.green("Yes"):x.red("No")}),!t.yes){let{confirm:g}=await H.prompt([{type:"confirm",name:"confirm",message:l,default:!1}]);if(!g){e.info("Resize operation cancelled");return}}let s=e.startSpinner(`Resizing CVM with App ID app_${r}`);await Ie(r,n,m,a,c?1:0),s.stop(!0),e.break(),e.success(`Your CVM is being resized. You can check the dashboard for more details:
|
package/dist/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/utils/banner.ts","../src/commands/auth/index.ts","../src/commands/auth/login.ts","../src/commands/auth/logout.ts","../src/commands/auth/status.ts","../src/commands/docker/index.ts","../src/commands/docker/login.ts","../src/utils/docker.ts","../src/utils/prompts.ts","../src/utils/simulator.ts","../src/commands/docker/build.ts","../src/commands/docker/push.ts","../src/commands/docker/generate.ts","../src/commands/simulator/index.ts","../src/commands/simulator/start.ts","../src/commands/simulator/stop.ts","../src/commands/cvms/index.ts","../src/commands/cvms/list.ts","../src/commands/cvms/get.ts","../src/utils/cvms.ts","../src/commands/cvms/start.ts","../src/commands/cvms/stop.ts","../src/commands/cvms/restart.ts","../src/commands/cvms/attestation.ts","../src/commands/cvms/create.ts","../src/utils/secrets.ts","../src/commands/cvms/delete.ts","../src/commands/cvms/upgrade.ts","../src/commands/cvms/resize.ts","../src/commands/cvms/list-node.ts","../src/commands/cvms/replicate.ts","../src/commands/join.ts","../src/commands/demo/index.ts","../src/utils/demo.ts","../src/commands/nodes/index.ts","../src/commands/nodes/list.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport { logo } from \"./utils/banner\";\nimport { authCommands } from \"./commands/auth\";\nimport { dockerCommands } from \"./commands/docker\";\nimport { simulatorCommands } from \"./commands/simulator\";\nimport { logger } from \"./utils/logger\";\nimport { cvmsCommand } from \"./commands/cvms\";\nimport { joinCommand } from \"./commands/join\";\nimport { demoCommands } from \"./commands/demo\";\nimport { nodesCommand } from \"./commands/nodes\";\n\nprocess.on(\"SIGINT\", () => process.exit(0));\nprocess.on(\"SIGTERM\", () => process.exit(0));\n\nasync function main() {\n const program = new Command()\n\t\t\t.name(\"phala\")\n\t\t\t.alias(\"pha\")\n\t\t\t.description(\n\t\t\t\t`${logo}\\nPhala Cloud CLI - Manage your Phala Cloud Deployments`,\n\t\t\t)\n\t\t\t.version(\"v1.0.15\")\n\t\t\t.addCommand(authCommands)\n\t\t\t.addCommand(cvmsCommand)\n\t\t\t.addCommand(dockerCommands)\n\t\t\t.addCommand(simulatorCommands)\n\t\t\t.addCommand(demoCommands)\n\t\t\t.addCommand(joinCommand)\n\t\t\t.addCommand(nodesCommand);\n\n\tprogram.parse(process.argv);\n}\n\nmain().catch((error) => {\n\tlogger.error(\"An error occurred:\", error);\n\tprocess.exit(1);\n});\n","import chalk from 'chalk';\nconst logoColor = chalk.hex('#cdfa50');\nexport const logo = logoColor(`\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣤⣤⣤⣀⡀⠀⢀⣀⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⡿⠛⠉⠁⠀⠈⠉⠛⠿⠛⠉⠉⠉⠉⠙⠷⣄⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣧⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣆⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⠞⠛⠉⠙⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠛⢶⣄⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣦⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⣷⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣿⣿⡿⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀⣀⣴⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⠿⠿⠿⠃⠀⢀⣾⣿⣿⣿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠛⠋⠁⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⡿⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⡤⠤⠤⠴⠒⠒⠒⠒⠒⢿⡿⠓⠒⠒⠢⠤⠤⠤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣯⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⣀⣨⣿⣦⣤⣀⡀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣾⣿⣿⣿⣿⣿⡏⠉⠛⣿⣆⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⣀⣀⣀⣀⡸⠿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⣸⡿⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣿⣿⣿⣿⣿⣿⣿⠀⢸⣿⣿⣿⣿⡇⠀⣿⣿⣿⣿⣿⣿⠃⢀⣠⣴⡿⠃⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣿⠿⢇⣀⣀⣀⣀⣸⣿⣿⣿⣿⣿⡿⠿⠿⠛⠛⠁⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⡠⠀⠀⠀⠀⠈⠻⢿⣿⣿⣿⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠠⣄⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⢸⣆⠀⠀⠀⠀⠀⠀⠀⠉⠛⠿⠿⣿⣿⣿⣿⣿⠿⠟⠋⠁⠀⠀⠀⠀⠀⠀⣀⣾⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠙⠻⢶⣦⣤⣄⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣤⣴⣶⠿⠛⠁⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠙⠛⠻⠿⠿⠿⠿⢿⣿⣿⣿⠿⠿⠿⠿⠟⠛⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n`);\n\nexport const smallLogo = logoColor(`\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣤⣤⣤⣀⡀⠀⢀⣀⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⡿⠛⠉⠁⠀⠈⠉⠛⠿⠛⠉⠉⠉⠉⠙⠷⣄⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣧⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣆⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⠞⠛⠉⠙⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠛⢶⣄⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣦⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⣷⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣿⣿⡿⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀⣀⣴⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⠿⠿⠿⠃⠀⢀⣾⣿⣿⣿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠛⠋⠁⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⡿⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⡤⠤⠤⠴⠒⠒⠒⠒⠒⢿⡿⠓⠒⠒⠢⠤⠤⠤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣯⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⣀⣨⣿⣦⣤⣀⡀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣾⣿⣿⣿⣿⣿⡏⠉⠛⣿⣆⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⣀⣀⣀⣀⡸⠿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⣸⡿⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣿⣿⣿⣿⣿⣿⣿⠀⢸⣿⣿⣿⣿⡇⠀⣿⣿⣿⣿⣿⣿⠃⢀⣠⣴⡿⠃⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣿⠿⢇⣀⣀⣀⣀⣸⣿⣿⣿⣿⣿⡿⠿⠿⠛⠛⠁⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⡠⠀⠀⠀⠀⠈⠻⢿⣿⣿⣿⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠠⣄⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⢸⣆⠀⠀⠀⠀⠀⠀⠀⠉⠛⠿⠿⣿⣿⣿⣿⣿⠿⠟⠋⠁⠀⠀⠀⠀⠀⠀⣀⣾⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠙⠻⢶⣦⣤⣄⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣤⣴⣶⠿⠛⠁⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠙⠛⠻⠿⠿⠿⠿⢿⣿⣿⣿⠿⠿⠿⠿⠟⠛⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n`);\n\nexport const minimalLogo = chalk.cyan('PHALA TEE CLOUD CLI');","import { Command } from 'commander';\nimport { loginCommand } from './login';\nimport { logoutCommand } from './logout';\nimport { statusCommand } from './status';\n\nexport const authCommands = new Command()\n .name('auth')\n .description('Authenticate with Phala Cloud')\n .addCommand(loginCommand)\n .addCommand(logoutCommand)\n .addCommand(statusCommand);\n","import { Command } from 'commander';\nimport { removeApiKey, saveApiKey } from '@/src/utils/credentials';\nimport { logger } from '@/src/utils/logger';\nimport prompts from 'prompts';\nimport { getUserInfo } from '@/src/api/auth';\nimport { CLOUD_URL } from '@/src/utils/constants';\n\nexport const loginCommand = new Command()\n .name('login')\n .description('Set the API key for authentication')\n .argument('[api-key]', 'Phala Cloud API key to set')\n .action(async (apiKey?: string) => {\n try {\n let checkUserInfo;\n // If no API key is provided, prompt for it\n if (!apiKey) {\n const response = await prompts({\n type: 'password',\n name: 'apiKey',\n message: 'Enter your API key:',\n validate: async (value) => {\n if (value.length === 0) {\n return 'API key cannot be empty';\n }\n try {\n await saveApiKey(value);\n checkUserInfo = await getUserInfo();\n if (!checkUserInfo.username) {\n await removeApiKey();\n return 'Invalid API key';\n }\n } catch (error) {\n return 'Invalid API key';\n }\n return true;\n }\n });\n \n apiKey = response.apiKey;\n } else {\n await saveApiKey(apiKey);\n // Validate the API key\n checkUserInfo = await getUserInfo();\n if (!checkUserInfo.username) {\n await removeApiKey();\n return 'Invalid API key';\n }\n }\n \n logger.success(`Welcome ${checkUserInfo.username}! API key validated and saved successfully`);\n logger.break();\n logger.info(`Open in Web UI at ${CLOUD_URL}/dashboard/`);\n } catch (error) {\n logger.error(`Failed to set API key: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { removeApiKey } from '@/src/utils/credentials';\nimport { logger } from '@/src/utils/logger';\n\nexport const logoutCommand = new Command()\n .name('logout')\n .description('Remove the stored API key')\n .action(async () => {\n try {\n await removeApiKey();\n logger.success('API key removed successfully');\n } catch (error) {\n logger.error(`Failed to remove API key: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { getApiKey } from '@/src/utils/credentials';\nimport { getUserInfo } from '@/src/api/auth';\nimport { logger } from '@/src/utils/logger';\n\nexport const statusCommand = new Command()\n .name('status')\n .description('Check authentication status')\n .option('-j, --json', 'Output in JSON format')\n .option('-d, --debug', 'Enable debug output')\n .action(async (options) => {\n try {\n // Enable debug mode if requested\n if (options.debug) {\n process.env.DEBUG = 'true';\n }\n \n const apiKey = await getApiKey();\n \n if (!apiKey) {\n logger.warn('Not authenticated. Please set an API key with \"phala auth login\"');\n return;\n }\n \n logger.debug(`Using API key: ${apiKey.substring(0, 5)}...`);\n const spinner = logger.startSpinner('Checking authentication status');\n \n try {\n const userInfo = await getUserInfo();\n spinner.stop(true);\n \n if (options.json) {\n console.log(JSON.stringify(userInfo, null, 2));\n return;\n }\n \n logger.break();\n logger.success(`Authenticated as ${userInfo.username}`);\n \n // Create a simple object\n const tableData = {\n 'Username': userInfo.username,\n 'Email': userInfo.email,\n 'Role': userInfo.role,\n 'Team': `${userInfo.team_name} (${userInfo.team_tier})`,\n 'Credits': `$${(userInfo.credits + userInfo.granted_credits).toFixed(2)}`\n };\n \n if (userInfo.trial_ended_at) {\n tableData['Trial Ended At'] = userInfo.trial_ended_at;\n }\n \n // Display the table\n logger.keyValueTable(tableData, {\n borderStyle: 'rounded'\n });\n } catch (error) {\n spinner.stop(false);\n logger.error('Authentication failed. Your API key may be invalid or expired.');\n logger.info('Please set a new API key with \"phala auth login\"');\n \n if (options.debug) {\n logger.debug(`Error details: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n } catch (error) {\n logger.error(`Failed to check authentication status: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { loginCommand } from './login';\nimport { buildCommand } from './build';\nimport { pushCommand } from './push';\nimport { generateCommand } from './generate';\n\nexport const dockerCommands = new Command()\n .name('docker')\n .description('Login to Docker Hub and manage Docker images')\n .addCommand(loginCommand)\n .addCommand(buildCommand)\n .addCommand(pushCommand)\n .addCommand(generateCommand);\n","import { Command } from 'commander';\nimport { DockerService } from '@/src/utils/docker';\nimport { saveDockerCredentials } from '@/src/utils/credentials';\nimport { logger } from '@/src/utils/logger';\nimport prompts from 'prompts';\n\nexport const loginCommand = new Command()\n .name('login')\n .description('Login to Docker Hub')\n .option('-u, --username <username>', 'Docker Hub username')\n .option('-p, --password <password>', 'Docker Hub password')\n .option('-r, --registry <registry>', 'Docker registry URL')\n .action(async (options) => {\n try {\n let username = options.username;\n let password = options.password;\n const registry = options.registry;\n \n // If no username is provided, prompt for it\n if (!username) {\n logger.info('First we need your Docker Hub username to check if you are already logged in.');\n\n const response = await prompts({\n type: 'text',\n name: 'username',\n message: 'Enter your Docker Hub username:',\n validate: value => value.length > 0 ? true : 'Username cannot be empty'\n });\n \n if (!response.username) {\n logger.error('Username is required');\n process.exit(1);\n }\n \n username = response.username;\n }\n\n // Check if Docker is already logged in\n const dockerService = new DockerService('', username, registry);\n const loggedIn = await dockerService.login(username);\n if (loggedIn) {\n logger.success(`${username} is logged in to Docker Hub`);\n // Save credentials\n await saveDockerCredentials({\n username,\n registry: registry || null,\n });\n return;\n }\n \n // If no password is provided, prompt for it\n if (!password) {\n const response = await prompts({\n type: 'password',\n name: 'password',\n message: 'Enter your Docker Hub password:',\n validate: value => value.length > 0 ? true : 'Password cannot be empty'\n });\n \n if (!response.password) {\n logger.error('Password is required');\n process.exit(1);\n }\n \n password = response.password;\n }\n \n // Login to Docker Hub\n const success = await dockerService.login(username, password, registry);\n \n if (!success) {\n logger.error('Failed to login to Docker Hub');\n process.exit(1);\n }\n \n // Save credentials\n await saveDockerCredentials({\n username,\n registry: registry || null\n });\n \n logger.success('Logged in to Docker Hub successfully');\n } catch (error) {\n logger.error(`Failed to login to Docker Hub: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { execa } from 'execa';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { logger } from './logger';\nimport { DOCKER_COMPOSE_BASIC_TEMPLATE, DOCKER_COMPOSE_ELIZA_V2_TEMPLATE } from './constants';\nimport { getDockerCredentials } from './credentials';\nimport Handlebars from 'handlebars';\nimport { exec, spawn } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport os from 'node:os';\nimport { validateFileExists } from './prompts';\nimport { ComposeTemplateSchema } from './types';\nimport { deleteSimulatorEndpointEnv, setSimulatorEndpointEnv } from './simulator';\nconst execAsync = promisify(exec);\n\nconst LOGS_DIR = '.phala-cloud/logs';\nconst COMPOSE_FILES_DIR = '.phala-cloud/compose';\nconst MAX_CONSOLE_LINES = 10;\n\nexport class DockerService {\n private username: string;\n private image: string;\n private registry: string;\n\n constructor(image: string, username?: string, registry?: string) {\n this.image = image;\n this.username = username || '';\n this.registry = registry || '';\n }\n\n private ensureLogsDir(): void {\n const logsPath = path.resolve(LOGS_DIR);\n if (!fs.existsSync(logsPath)) {\n fs.mkdirSync(logsPath, { recursive: true });\n }\n }\n\n private getLogFilePath(operation: string, image?: string): string {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n return path.resolve(LOGS_DIR, `${image || this.image}-${operation}-${timestamp}.log`);\n }\n\n private getSystemArchitecture(): string {\n const arch = os.arch();\n switch (arch) {\n case 'arm':\n case 'arm64':\n return 'arm64';\n case 'x64':\n return 'amd64';\n default:\n return arch;\n }\n }\n\n private spawnProcess(command: string, args: string[], operation: string, image?: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const proc = spawn(command, args);\n // Ensure logs directory exists before creating write stream\n this.ensureLogsDir();\n\n const logFile = this.getLogFilePath(operation, image);\n\n const logStream = fs.createWriteStream(logFile, { flags: 'a' });\n const consoleBuffer: string[] = [];\n\n const processOutput = (data: Buffer, isError = false) => {\n const lines = data.toString().split('\\n');\n\n // Write to log file\n logStream.write(data);\n\n // Update console buffer\n for (const line of lines) {\n if (line.trim()) {\n consoleBuffer.push(line);\n // Keep only the last MAX_CONSOLE_LINES lines\n if (consoleBuffer.length > MAX_CONSOLE_LINES) {\n consoleBuffer.shift();\n }\n\n // Clear console and print the buffer\n console.clear();\n console.log(`Latest ${MAX_CONSOLE_LINES} lines (full log at ${logFile}):`);\n console.log('-'.repeat(50));\n for (const bufferedLine of consoleBuffer) {\n if (isError) {\n console.error(bufferedLine);\n } else {\n console.log(bufferedLine);\n }\n }\n }\n }\n };\n\n proc.stdout.on('data', (data) => processOutput(data));\n proc.stderr.on('data', (data) => processOutput(data, true));\n\n proc.on('close', (code) => {\n logStream.end();\n if (code === 0) {\n console.log(`\\nOperation completed. Full log available at: ${logFile}`);\n resolve();\n } else {\n reject(new Error(`Process exited with code ${code}. Check log file: ${logFile}`));\n }\n });\n\n proc.on('error', (err) => {\n logStream.end();\n reject(err);\n });\n });\n }\n\n /**\n * Set Docker credentials\n * @param username Docker username\n * @param registry Docker registry\n */\n setCredentials(username: string, registry?: string): void {\n this.username = username;\n if (registry) {\n this.registry = registry;\n }\n }\n\n /**\n * Build a Docker image\n * @param dockerfile Path to Dockerfile\n * @param tag Tag for the image\n * @returns Success status\n */\n async buildImage(dockerfile: string, tag: string): Promise<boolean> {\n try {\n const arch = this.getSystemArchitecture();\n const fullImageName = `${this.username}/${this.image}:${tag}`;\n\n const spinner = logger.startSpinner(`Building Docker image ${this.username}/${this.image}:${tag}`);\n\n // Ensure the Dockerfile exists\n validateFileExists(dockerfile);\n\n const buildArgs = ['build', '-t', fullImageName, '-f', dockerfile];\n\n if (arch === 'arm64') {\n console.log('Detected arm64 architecture, using --platform linux/amd64');\n buildArgs.push('--platform', 'linux/amd64');\n }\n\n // Build the image\n buildArgs.push('.');\n\n await this.spawnProcess('docker', buildArgs, 'build', this.image);\n\n spinner.stop(true, `Docker image ${fullImageName} built successfully`);\n return true;\n } catch (error) {\n logger.error(`Failed to build Docker image: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n /**\n * Push a Docker image to Docker Hub\n * @param imageName Full image name (e.g. username/image:tag)\n * @returns Success status\n */\n async pushImage(imageName: string): Promise<boolean> {\n try {\n const spinner = logger.startSpinner(`Pushing Docker image ${imageName} to Docker Hub`);\n\n // Check if user is logged in\n const credentials = await getDockerCredentials();\n if (!credentials) {\n spinner.stop(false);\n throw new Error('Docker credentials not found. Please log in first with \"phala docker login\"');\n }\n\n const fullImageName = imageName;\n console.log(`Pushing image ${fullImageName} to Docker Hub...`);\n\n await this.spawnProcess('docker', ['push', fullImageName], 'push', imageName.replace(/.*\\/+([\\w-]+):.*$/g, '$1'));\n\n spinner.stop(true, `Docker image ${fullImageName} pushed successfully`);\n return true;\n } catch (error) {\n logger.error(`Failed to push Docker image: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n\n /**\n * Login to Docker Hub\n * @param username Docker username\n * @param password Docker password\n * @param registry Docker registry\n * @returns Success status\n */\n async login(username: string, password?: string, registry?: string): Promise<boolean> {\n try {\n const spinner = logger.startSpinner(`Logging in to Docker Hub as ${username}`);\n\n // Check if already logged in\n const loggedIn = await this.checkLogin();\n if (loggedIn) {\n spinner.stop(true, 'Already logged in to Docker Hub');\n this.setCredentials(username, registry);\n return true;\n }\n\n // Verify password was provided\n if (!password) {\n spinner.stop(false);\n throw new Error('Password is required for Docker login');\n }\n\n // Login to Docker with timeout protection\n try {\n const loginProcess = execa('docker', [\n 'login',\n ...(registry ? [registry] : []),\n '-u',\n username,\n '--password-stdin'\n ], {\n input: password,\n timeout: 10000 // 10 second timeout\n });\n\n await loginProcess;\n } catch (loginError) {\n if (loginError.timedOut) {\n spinner.stop(false);\n throw new Error('Docker login timed out. Please check your credentials and try again.');\n }\n throw loginError;\n }\n\n spinner.stop(true, 'Logged in to Docker Hub successfully');\n this.setCredentials(username, registry);\n return true;\n } catch (error) {\n logger.error(`Failed to login to Docker Hub: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n /**\n * Check if Docker is logged in\n * @returns Success status\n */\n async checkLogin(): Promise<boolean> {\n try {\n // Instead of checking via \"docker login\" which is interactive,\n // check if the Docker config.json file exists and contains auth data\n const homeDir = os.homedir();\n const dockerConfigPath = path.join(homeDir, '.docker', 'config.json');\n \n if (!fs.existsSync(dockerConfigPath)) {\n return false;\n }\n \n // Read the docker config file\n const dockerConfig = JSON.parse(fs.readFileSync(dockerConfigPath, 'utf-8'));\n \n // Check if the config has auths data\n return !!(dockerConfig?.auths && Object.keys(dockerConfig.auths).length > 0);\n } catch (error) {\n logger.debug(`Docker login check failed: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n /**\n * Build a Docker Compose file\n * @param imageName Name of the image\n * @param envFile Optional path to environment file\n * @param version Version of the template to use\n * @returns Path to the generated Docker Compose file\n */\n async buildComposeFile(imageName: string, envFile?: string, templateType?: string): Promise<string> {\n if (!this.username) {\n throw new Error('Docker Hub username is required for building compose file');\n }\n\n const template = (templateType === 'eliza') ? DOCKER_COMPOSE_ELIZA_V2_TEMPLATE : DOCKER_COMPOSE_BASIC_TEMPLATE;\n\n // Validate template structure\n const validatedTemplate = ComposeTemplateSchema.parse({ template });\n\n // Ensure compose files directory exists\n const composePath = path.resolve(COMPOSE_FILES_DIR);\n \n // Create directory if it doesn't exist\n if (!fs.existsSync(composePath)) {\n logger.info(`Creating directory: ${composePath}`);\n fs.mkdirSync(composePath, { recursive: true });\n }\n\n let envVars: string[] = [];\n \n // Only parse env file if it's provided\n if (envFile) {\n // Parse env file to get variable names\n const envContent = fs.readFileSync(envFile, 'utf-8');\n envVars = envContent\n .split('\\n')\n .filter(line => line && !line.startsWith('#'))\n .map(line => {\n // Remove inline comments\n const commentIndex = line.indexOf('#');\n if (commentIndex > 0) {\n line = line.substring(0, commentIndex).trim();\n }\n return line.trim();\n })\n .filter(line => line.includes('='))\n .map(line => {\n const [key, value] = line.split('=', 2);\n const trimmedKey = key.trim();\n const trimmedValue = value ? value.trim() : '';\n\n // Skip empty values\n if (trimmedValue === '') {\n return null;\n }\n\n // Keep the original key without any transformation\n return `${trimmedKey}=${trimmedKey}`; // Create KEY=KEY format\n })\n .filter(Boolean as unknown as ((value: string | null) => value is string)); // Remove null entries\n }\n\n // Create full image name with username\n const fullImageName = imageName;\n\n // Compile template with data\n const compiledTemplate = Handlebars.compile(validatedTemplate.template, { noEscape: true });\n const composeContent = compiledTemplate({\n imageName: fullImageName,\n envVars: envVars.map(env => env.replace(/=.*/, `=\\${${env.split('=')[0]}}`))\n });\n\n // Write the docker-compose file with standardized name in the compose directory\n const composeFile = path.join(\n composePath,\n `${imageName.replace(/.*\\/+([\\w-]+):.*$/g, \"$1\")}-tee-compose.yaml`,\n );\n fs.writeFileSync(composeFile, composeContent);\n\n logger.success(`Backup of docker compose file created at: ${composeFile}`);\n return composeFile;\n }\n\n /**\n * Run a Docker Compose file locally\n * @param composePath Path to Docker Compose file\n * @param envFile Path to environment file\n * @returns Success status\n */\n async runComposeLocally(composePath: string, envFile?: string): Promise<boolean> {\n try {\n // TODO: Update log when optimized simulator is implemented\n const spinner = logger.startSpinner(`Running Docker Compose file at ${composePath}`);\n\n // Ensure the Docker Compose file exists\n validateFileExists(composePath);\n\n // Build the command arguments\n const composeArgs = [\n '-f',\n composePath,\n 'up',\n '-d'\n ];\n\n // Only add env-file if it's provided\n if (envFile) {\n // Ensure the environment file exists\n validateFileExists(envFile);\n composeArgs.splice(2, 0, '--env-file', envFile);\n }\n\n // Run the Docker Compose file\n await execAsync(`docker compose ${composeArgs.join(' ')}`);\n\n spinner.stop(true, 'Docker Compose file running successfully');\n return true;\n } catch (error) {\n logger.error(`Failed to run Docker Compose file: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n /**\n * Run the TEE simulator\n * @param image Simulator image\n * @returns Success status\n */\n async runSimulator(image: string, port: string): Promise<boolean> {\n try {\n logger.info(`Running TEE simulator with image ${image}`);\n\n logger.info('Pulling latest simulator image...');\n await execAsync(`docker pull ${image}`);\n\n logger.info('Starting simulator in background...');\n const { stdout } = await execAsync(`docker run -d --name tee-simulator --rm -p ${port}:${port} ${image}`);\n const containerId = stdout.trim();\n\n logger.success(`TEE simulator running successfully. Container ID: ${containerId}`);\n logger.break();\n logger.break();\n logger.info('Useful commands:');\n logger.info(`- View logs: docker logs -f ${containerId}`);\n logger.info(`- Stop simulator: docker stop ${containerId}`);\n\n setSimulatorEndpointEnv(`http://localhost:${port}`);\n \n return true;\n } catch (error) {\n logger.error(`Failed to run TEE simulator: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n /**\n * Stop the TEE simulator\n * @returns Success status\n */\n async stopSimulator(): Promise<boolean> {\n try {\n const spinner = logger.startSpinner('Stopping TEE simulator...');\n\n // Stop the simulator\n await execAsync('docker stop tee-simulator');\n await deleteSimulatorEndpointEnv();\n\n spinner.stop(true, 'TEE simulator stopped successfully');\n return true;\n } catch (error) {\n logger.error(`Failed to stop TEE simulator: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n /**\n * List local Docker images and their tags\n * @returns Array of objects with image name and tag\n */\n static async listLocalImages(): Promise<Array<{ imageName: string}>> {\n try {\n // Query Docker for local images in format that outputs repository and tag\n const { stdout } = await execAsync('docker images --format \"{{.Repository}}:{{.Tag}}\"');\n const credentials = await getDockerCredentials();\n const username = credentials?.username;\n // Parse the output and filter out any <none> tags or images\n const imageList = stdout.split('\\n')\n .filter(line => line && !line.includes('<none>'))\n .filter(line => line.includes(`${username}/`))\n .map(line => {\n const imageName = line;\n return { imageName };\n });\n\n return imageList;\n } catch (error) {\n logger.error(`Failed to list local Docker images: ${error instanceof Error ? error.message : String(error)}`);\n return [];\n }\n }\n}\n\n","import inquirer from 'inquirer';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { logger } from './logger';\n\n/**\n * Validates that a file exists at the given path\n * @param filePath Path to the file to validate\n * @param basePath Optional base path to resolve relative paths against (defaults to process.cwd())\n * @returns True if the file exists, throws an error if not\n * @throws Error if the file does not exist\n */\nexport function validateFileExists(\n filePath: string,\n basePath: string = process.cwd()\n): boolean {\n const resolvedPath = path.resolve(basePath, filePath);\n if (!fs.existsSync(resolvedPath)) {\n throw new Error(`File not found at ${resolvedPath}`);\n }\n return true;\n}\n\n/**\n * Prompts the user for a file path and validates that the file exists\n * @param message The prompt message to display\n * @param defaultValue The default value for the prompt\n * @param name The name of the prompt (used as property name in the returned object)\n * @param basePath Optional base path to resolve relative paths against (defaults to process.cwd())\n * @returns The validated file path\n */\nexport async function promptForFile(\n message: string,\n defaultValue: string,\n name = 'file',\n basePath: string = process.cwd()\n): Promise<string> {\n const response = await inquirer.prompt([\n {\n type: 'input',\n name,\n message,\n default: defaultValue,\n validate: (input) => {\n const filePath = path.resolve(basePath, input);\n if (!fs.existsSync(filePath)) {\n return `File not found at ${filePath}`;\n }\n return true;\n }\n }\n ]);\n\n return response[name];\n}\n\nexport function detectFileInCurrentDir(\n possibleFiles: string[],\n logMessage?: string\n): string | undefined {\n for (const file of possibleFiles) {\n const filePath = path.join(process.cwd(), file);\n if (fs.existsSync(filePath)) {\n if (logMessage) {\n logger.info(logMessage.replace('{path}', filePath));\n } else {\n logger.info(`File detected: ${filePath}`);\n }\n return file;\n }\n }\n return undefined;\n}","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { execSync, spawn, type StdioOptions } from 'node:child_process';\nimport * as net from 'node:net';\nimport { logger } from './logger';\n\n// Configuration for simulator\nconst SIMULATOR_CONFIG = {\n version: '0.1.4',\n baseUrl: 'https://github.com/Leechael/tappd-simulator/releases/download/v0.1.4',\n installDir: path.join(os.homedir(), '.phala-cloud', 'tappd-simulator'),\n // Default log file path\n defaultLogPath: path.join(os.homedir(), '.phala-cloud', 'logs', 'tappd-simulator.log'),\n platforms: {\n darwin: {\n filename: 'tappd-simulator-0.1.4-aarch64-apple-darwin.tgz',\n extractedFolder: 'tappd-simulator-0.1.4-aarch64-apple-darwin',\n socketArg: 'unix:/tmp/tappd.sock'\n },\n linux: {\n filename: 'tappd-simulator-0.1.4-x86_64-linux-musl.tgz',\n extractedFolder: 'tappd-simulator-0.1.4-x86_64-linux-musl',\n socketArg: 'unix:/tmp/tappd.sock'\n },\n win32: {\n filename: 'tappd-simulator-0.1.4-x86_64-pc-windows-msvc.tgz',\n extractedFolder: 'tappd-simulator-0.1.4-x86_64-pc-windows-msvc',\n socketArg: '127.0.0.1:8090'\n }\n }\n};\n\n/**\n * Check if the simulator is already installed\n * @returns boolean indicating if simulator is installed\n */\nexport function isSimulatorInstalled(): boolean {\n try {\n // Check if the main installation directory exists\n if (!fs.existsSync(SIMULATOR_CONFIG.installDir)) {\n return false;\n }\n\n // Get platform-specific folder name\n const platform = os.platform() as 'darwin' | 'linux' | 'win32';\n if (!SIMULATOR_CONFIG.platforms[platform]) {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n\n const extractedFolderPath = path.join(\n SIMULATOR_CONFIG.installDir,\n SIMULATOR_CONFIG.platforms[platform].extractedFolder\n );\n\n // Check if the extracted folder exists\n if (!fs.existsSync(extractedFolderPath)) {\n return false;\n }\n\n // Check if the executable exists\n const executableName = platform === 'win32' ? 'tappd-simulator.exe' : 'tappd-simulator';\n const executablePath = path.join(extractedFolderPath, executableName);\n return fs.existsSync(executablePath);\n } catch (error) {\n logger.error('Error checking if simulator is installed:', error);\n return false;\n }\n}\n\n/**\n * Get the current platform\n * @returns The current platform: 'darwin', 'linux', or 'win32'\n * @throws Error if the platform is not supported\n */\nexport function getPlatform(): 'darwin' | 'linux' | 'win32' {\n const platform = os.platform() as 'darwin' | 'linux' | 'win32';\n if (!SIMULATOR_CONFIG.platforms[platform]) {\n throw new Error(`Unsupported platform: ${platform}. Only darwin, linux, and win32 are supported.`);\n }\n return platform;\n}\n\n/**\n * Install the simulator based on the current platform\n * @param progressCallback Optional callback to report progress\n * @returns Promise that resolves when installation is complete\n */\nexport async function installSimulator(\n progressCallback?: (message: string) => void\n): Promise<void> {\n const log = (message: string) => {\n logger.info(message);\n if (progressCallback) progressCallback(message);\n };\n\n try {\n const platform = getPlatform();\n const platformConfig = SIMULATOR_CONFIG.platforms[platform];\n \n // Create installation directory if it doesn't exist\n if (!fs.existsSync(SIMULATOR_CONFIG.installDir)) {\n logger.info(`Creating installation directory at ${SIMULATOR_CONFIG.installDir}`);\n fs.mkdirSync(SIMULATOR_CONFIG.installDir, { recursive: true });\n }\n\n // Change to the installation directory\n process.chdir(SIMULATOR_CONFIG.installDir);\n \n // Download the simulator\n const downloadUrl = `${SIMULATOR_CONFIG.baseUrl}/${platformConfig.filename}`;\n logger.info(`Downloading simulator from ${downloadUrl}`);\n execSync(`wget ${downloadUrl}`, { stdio: 'inherit' });\n \n // Extract the archive\n logger.info(`Extracting ${platformConfig.filename}`);\n execSync(`tar -xvf ${platformConfig.filename}`, { stdio: 'inherit' });\n \n logger.success('Simulator installation completed successfully');\n } catch (error) {\n logger.error('Error installing simulator:', error);\n throw new Error(`Failed to install simulator: ${error}`);\n }\n}\n\n/**\n * Run the simulator\n * @param options Configuration options for running the simulator\n * @returns A child process representing the running simulator\n */\nexport async function runSimulator(options: {\n background?: boolean;\n logToFile?: boolean;\n logFilePath?: string;\n} = {}): Promise<ReturnType<typeof spawn>> {\n try {\n const platform = getPlatform();\n const platformConfig = SIMULATOR_CONFIG.platforms[platform];\n const extractedFolderPath = path.join(\n SIMULATOR_CONFIG.installDir,\n platformConfig.extractedFolder\n );\n \n // Change to the extracted folder directory\n process.chdir(extractedFolderPath);\n \n // Start the simulator\n const executableName = platform === 'win32' ? 'tappd-simulator.exe' : './tappd-simulator';\n \n // Default options\n const runOptions = {\n background: options.background ?? true,\n logToFile: options.logToFile ?? true,\n logFilePath: options.logFilePath ?? SIMULATOR_CONFIG.defaultLogPath\n };\n \n // Create log directory if it doesn't exist\n if (runOptions.logToFile) {\n const logDir = path.dirname(runOptions.logFilePath);\n if (!fs.existsSync(logDir)) {\n fs.mkdirSync(logDir, { recursive: true });\n }\n logger.info(`Simulator logs will be written to: ${runOptions.logFilePath}`);\n }\n \n logger.info(`Starting simulator with: ${executableName} -l ${platformConfig.socketArg}`);\n \n // Configure stdio based on logging preferences\n let stdio: StdioOptions = 'inherit';\n let outputStream: fs.WriteStream = null;\n \n if (runOptions.logToFile) {\n // Create/open the log file for appending\n outputStream = fs.createWriteStream(runOptions.logFilePath, { flags: 'a' });\n \n // Use the stream for both stdout and stderr\n stdio = ['ignore', outputStream, outputStream];\n }\n \n // Run the simulator\n const simulatorProcess = spawn(executableName, ['-l', platformConfig.socketArg], {\n stdio,\n shell: platform === 'win32', // Use shell on Windows\n detached: runOptions.background // Detach process when running in background\n });\n \n // Write startup entry to log file with timestamp\n if (outputStream) {\n const timestamp = new Date().toISOString();\n outputStream.write(`\\n[${timestamp}] Simulator started\\n`);\n }\n \n // If running in background, unref to allow the parent process to exit\n if (runOptions.background) {\n simulatorProcess.unref();\n logger.success('Simulator is running in the background');\n }\n \n await setSimulatorEndpointEnv();\n return simulatorProcess;\n } catch (error) {\n logger.error('Error running simulator:', error);\n throw new Error(`Failed to run simulator: ${error}`);\n }\n}\n\n/**\n * Ensures the simulator is installed and running\n * @param options Configuration options for running the simulator\n * @returns A promise that resolves to a child process representing the running simulator\n */\nexport async function ensureSimulatorRunning(options: {\n background?: boolean;\n logToFile?: boolean;\n logFilePath?: string;\n} = {}): Promise<ReturnType<typeof spawn>> {\n if (!isSimulatorInstalled()) {\n logger.info('Simulator not installed. Installing now...');\n await installSimulator((message) => logger.info(`Installation progress: ${message}`));\n }\n \n if (await isSimulatorRunning()) {\n logger.info('Simulator is already running');\n return null;\n }\n \n logger.info('Starting simulator...');\n return await runSimulator(options);\n}\n\n/**\n * Check if the simulator is currently running\n * For Unix platforms (Darwin/Linux), checks if the Unix socket exists and is accessible\n * For Windows, tries to connect to the TCP port the simulator should be listening on\n * @returns Promise<boolean> indicating if the simulator is running\n */\nexport async function isSimulatorRunning(): Promise<boolean> {\n try {\n const platform = getPlatform();\n const platformConfig = SIMULATOR_CONFIG.platforms[platform];\n \n if (platform === 'darwin' || platform === 'linux') {\n // For Unix platforms, check if the socket file exists and is accessible\n const socketPath = '/tmp/tappd.sock';\n \n // Check if the socket file exists\n if (!fs.existsSync(socketPath)) {\n return false;\n }\n \n // Try to connect to the socket to verify it's active\n return new Promise<boolean>((resolve) => {\n const client = net.createConnection({ path: socketPath })\n .on('connect', () => {\n client.end();\n resolve(true);\n })\n .on('error', () => {\n resolve(false);\n });\n \n // Set timeout to avoid hanging if socket exists but nothing is listening\n setTimeout(() => {\n client.end();\n resolve(false);\n }, 1000);\n });\n } \n if (platform === 'win32') {\n // For Windows, try to connect to the TCP port\n const host = '127.0.0.1';\n const port = 8090;\n \n return new Promise<boolean>((resolve) => {\n const client = net.createConnection({ host, port })\n .on('connect', () => {\n client.end();\n resolve(true);\n })\n .on('error', () => {\n resolve(false);\n });\n \n // Set timeout to avoid hanging\n setTimeout(() => {\n client.end();\n resolve(false);\n }, 1000);\n });\n }\n \n return false;\n } catch (error) {\n logger.error('Error checking if simulator is running:', error);\n return false;\n }\n}\n\n/**\n * Stops the simulator if it's running\n * @returns Promise<boolean> indicating if the simulator was successfully stopped\n */\nexport async function stopSimulator(): Promise<boolean> {\n try {\n const platform = getPlatform();\n \n if (!await isSimulatorRunning()) {\n logger.info('Simulator is not running');\n return true;\n }\n \n logger.info('Stopping simulator...');\n \n if (platform === 'win32') {\n // For Windows, find the process listening on port 8080 and kill it\n execSync('for /f \"tokens=5\" %a in (\\'netstat -ano ^| findstr :8080\\') do taskkill /F /PID %a', { stdio: 'inherit' });\n } else {\n // For Unix platforms, find and kill the tappd-simulator process\n execSync('pkill -f tappd-simulator', { stdio: 'inherit' });\n }\n \n // Verify the simulator has stopped\n const stopped = !(await isSimulatorRunning());\n if (stopped) {\n logger.success('Simulator stopped successfully');\n } else {\n logger.error('Failed to stop simulator');\n }\n \n await deleteSimulatorEndpointEnv();\n return stopped;\n } catch (error) {\n logger.error('Error stopping simulator:', error);\n return false;\n }\n}\n\n/**\n * Gets the path to the simulator log file\n * @param customPath Optional custom log file path\n * @returns The path to the log file\n */\nexport function getSimulatorLogPath(customPath?: string): string {\n return customPath ?? SIMULATOR_CONFIG.defaultLogPath;\n}\n\n/**\n * Reads the recent logs from the simulator log file\n * @param options Options for reading logs\n * @returns Recent log content or null if log file doesn't exist\n */\nexport function getSimulatorLogs(options: {\n logFilePath?: string;\n maxLines?: number;\n} = {}): string | null {\n const logFilePath = options.logFilePath ?? SIMULATOR_CONFIG.defaultLogPath;\n const maxLines = options.maxLines ?? 100;\n \n try {\n if (!fs.existsSync(logFilePath)) {\n return null;\n }\n \n // Read the log file\n const logContent = fs.readFileSync(logFilePath, 'utf8');\n \n // Split by lines and get the most recent ones\n const lines = logContent.split('\\n');\n return lines.slice(-maxLines).join('\\n');\n } catch (error) {\n logger.error('Error reading simulator logs:', error);\n return null;\n }\n}\n\n/**\n * Gets the simulator endpoint URL based on the current platform\n * @returns The endpoint URL for the simulator\n */\nexport function getSimulatorEndpoint(): string {\n const platform = getPlatform();\n \n if (platform === 'win32') {\n return 'http://127.0.0.1:8090';\n }\n\n return 'unix:///tmp/tappd.sock';\n}\n\n/**\n * Sets the DSTACK_SIMULATOR_ENDPOINT environment variable based on the current platform\n * @param options Configuration options for setting the environment variable\n * @returns The endpoint URL that was set\n */\nexport async function setSimulatorEndpointEnv(endpoint?: string): Promise<string> {\n try {\n const simulatorEndpoint = getSimulatorEndpoint();\n // Set for the current Node.js process\n const envEndpoint = (endpoint) ? endpoint : simulatorEndpoint;\n await execSync(`export DSTACK_SIMULATOR_ENDPOINT=${envEndpoint}`);\n logger.success(`Setting DSTACK_SIMULATOR_ENDPOINT=${envEndpoint} for current process`);\n \n return endpoint;\n } catch (error) {\n logger.error('Error setting simulator endpoint environment variable:', error);\n throw new Error(`Failed to set simulator endpoint: ${error}`);\n }\n}\n\n/**\n * Deletes the DSTACK_SIMULATOR_ENDPOINT environment variable\n * @returns boolean indicating if deletion was successful\n */\nexport async function deleteSimulatorEndpointEnv(): Promise<boolean> {\n await execSync('unset DSTACK_SIMULATOR_ENDPOINT');\n logger.debug('Deleted DSTACK_SIMULATOR_ENDPOINT from current process');\n return true;\n}\n","import { Command } from 'commander';\nimport { DockerService } from '@/src/utils/docker';\nimport { getDockerCredentials } from '@/src/utils/credentials';\nimport { logger } from '@/src/utils/logger';\nimport path from 'node:path';\nimport inquirer from 'inquirer';\nimport fs from 'node:fs';\nimport { promptForFile } from '@/src/utils/prompts';\n\nexport const buildCommand = new Command()\n .name('build')\n .description('Build a Docker image')\n .option('-i, --image <image>', 'Image name')\n .option('-t, --tag <tag>', 'Image tag')\n .option('-f, --file <file>', 'Path to Dockerfile', 'Dockerfile')\n .action(async (options) => {\n try {\n // Get Docker credentials\n const credentials = await getDockerCredentials();\n \n if (!credentials) {\n logger.error('Docker information not found. Please login first with \"phala docker login\"');\n process.exit(1);\n }\n \n // Prompt for image name if not provided\n if (!options.image) {\n const response = await inquirer.prompt([\n {\n type: 'input',\n name: 'image',\n message: 'Enter the Docker image name:',\n validate: (input) => {\n if (!input.trim()) {\n return 'Image name is required';\n }\n return true;\n }\n }\n ]);\n \n options.image = response.image;\n }\n\n if (!options.tag) {\n const response = await inquirer.prompt([\n {\n type: 'input',\n name: 'tag',\n message: 'Enter the Docker image tag:',\n default: 'latest', // Add random hash later\n validate: (input) => {\n if (!input.trim()) {\n return 'Tag is required';\n }\n return true;\n }\n }\n ]);\n\n options.tag = response.tag;\n }\n\n // Prompt for Dockerfile path if the default doesn't exist\n const defaultPath = path.resolve(process.cwd(), options.file);\n if (!fs.existsSync(defaultPath)) {\n logger.info(`Default Dockerfile not found at ${defaultPath}`);\n \n options.file = await promptForFile(\n 'Enter the path to your Dockerfile:',\n 'Dockerfile',\n 'file'\n );\n }\n \n // Resolve the Dockerfile path\n const dockerfilePath = path.resolve(process.cwd(), options.file);\n \n // Build the image\n const dockerService = new DockerService(options.image, credentials.username, credentials.registry);\n const success = await dockerService.buildImage(dockerfilePath, options.tag);\n \n if (!success) {\n logger.error('Failed to build Docker image');\n process.exit(1);\n }\n \n logger.success(`Docker image ${credentials.username}/${options.image}:${options.tag} built successfully`);\n } catch (error) {\n logger.error(`Failed to build Docker image: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { DockerService } from '@/src/utils/docker';\nimport { getDockerCredentials } from '@/src/utils/credentials';\nimport { logger } from '@/src/utils/logger';\nimport inquirer from 'inquirer';\n\nexport const pushCommand = new Command()\n .name('push')\n .description('Push a Docker image to Docker Hub')\n .option('-i, --image <image>', 'Full image name (e.g. username/image:tag)')\n .action(async (options) => {\n try {\n // Get Docker credentials\n const credentials = await getDockerCredentials();\n \n if (!credentials) {\n logger.error('Docker information not found. Please login first with \"phala docker login\"');\n process.exit(1);\n }\n\n let imageName = options.image;\n\n // If image name is not provided, list local images and prompt user to select\n if (!imageName) {\n const localImages = await DockerService.listLocalImages();\n \n if (localImages.length === 0) {\n logger.error('No local Docker images found. Please build an image first with \"phala docker build\"');\n process.exit(1);\n }\n\n // If no image specified, prompt to select from available images\n if (!imageName) {\n // Get unique image names\n const uniqueImageNames = Array.from(new Set(localImages.map(img => img.imageName)));\n \n const { selectedImage } = await inquirer.prompt([\n {\n type: 'list',\n name: 'selectedImage',\n message: 'Select an image to push:',\n choices: uniqueImageNames\n }\n ]);\n \n imageName = selectedImage;\n }\n }\n \n // Push the image\n const dockerService = new DockerService('', credentials.username, credentials.registry);\n const success = await dockerService.pushImage(imageName);\n \n if (!success) {\n logger.error('Failed to push Docker image');\n process.exit(1);\n }\n \n logger.success(`Docker image ${imageName} pushed successfully`);\n } catch (error) {\n logger.error(`Failed to push Docker image: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { DockerService } from '@/src/utils/docker';\nimport { getDockerCredentials } from '@/src/utils/credentials';\nimport { logger } from '@/src/utils/logger';\nimport inquirer from 'inquirer';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { validateFileExists } from '@/src/utils/prompts';\n\nexport const generateCommand = new Command()\n .name('generate')\n .description('Generate a Docker Compose file')\n .option('-i, --image <imageName>', 'Docker image name to use in the compose file (e.g. phala/phala-cloud)')\n .option('-e, --env-file <envFile>', 'Path to environment variables file')\n .option('-o, --output <output>', 'Output path for generated docker-compose.yml')\n .option('--template <template>', 'Template to use for the generated docker-compose.yml', )\n .action(async (options) => {\n try {\n // Get Docker credentials to create the Docker service\n const credentials = await getDockerCredentials();\n if (!credentials || !credentials.username) {\n logger.error('Docker Hub username not found. Please login first with `phala docker login`');\n process.exit(1);\n }\n\n let imageName = options.image;\n\n if (!imageName) {\n // If image name is not provided, list local images and prompt user to select\n const localImages = await DockerService.listLocalImages();\n\n if (localImages.length === 0) {\n logger.error(\n 'No local Docker images found. Please build an image first with \"phala docker build\"',\n );\n process.exit(1);\n }\n\n // If no image specified, prompt to select from available images\n if (!imageName) {\n // Get unique image names\n const uniqueImageNames = Array.from(\n new Set(localImages.map((img) => img.imageName)),\n );\n\n const { selectedImage } = await inquirer.prompt([\n {\n type: \"list\",\n name: \"selectedImage\",\n message: \"Select an image to use in the compose file:\",\n choices: uniqueImageNames,\n },\n ]);\n\n imageName = selectedImage;\n }\n }\n \n // Get environment file path from options or prompt\n let envFilePath = options.envFile;\n if (!envFilePath) {\n // Check if .env exists in current directory\n const defaultEnvPath = path.join(process.cwd(), '.env');\n const hasDefaultEnv = fs.existsSync(defaultEnvPath);\n\n if (hasDefaultEnv) {\n const { useDefault } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'useDefault',\n message: 'Use .env file in current directory?',\n default: true\n }\n ]);\n\n if (useDefault) {\n envFilePath = defaultEnvPath;\n }\n }\n\n // If still no env file path, prompt for it\n if (!envFilePath) {\n const { envPath } = await inquirer.prompt([\n {\n type: 'input',\n name: 'envPath',\n message: 'Enter path to environment variables file:',\n validate: (input) => {\n try {\n validateFileExists(input);\n return true;\n } catch (error) {\n return `File not found: ${input}`;\n }\n }\n }\n ]);\n envFilePath = envPath;\n }\n } else {\n // Validate the provided env file path\n try {\n validateFileExists(envFilePath);\n } catch (error) {\n logger.error(`File not found: ${envFilePath}`);\n process.exit(1);\n }\n }\n\n // Get output path from options or set default\n let outputPath = options.output;\n if (!outputPath) {\n outputPath = path.join(process.cwd(), 'docker-compose.yml');\n \n // If file already exists, confirm overwrite\n if (fs.existsSync(outputPath)) {\n const { confirmOverwrite } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'confirmOverwrite',\n message: `File ${outputPath} already exists. Overwrite?`,\n default: false\n }\n ]);\n if (!confirmOverwrite) {\n const { customPath } = await inquirer.prompt([\n {\n type: 'input',\n name: 'customPath',\n message: 'Enter alternative output path:',\n default: path.join(process.cwd(), 'docker-generated-compose.yml')\n }\n ]);\n outputPath = customPath;\n }\n }\n }\n \n // Create a DockerService instance\n const dockerService = new DockerService('', credentials.username, credentials.registry);\n\n // Generate the Docker Compose file\n if (envFilePath) {\n logger.info(`Generating Docker Compose file for ${imageName} using env file: ${envFilePath}`);\n } else {\n logger.info(`Generating Docker Compose file for ${imageName} without env file`);\n }\n const composePath = await dockerService.buildComposeFile(imageName, envFilePath, options.template);\n \n // Copy the generated file to the output path if needed\n if (composePath !== outputPath) {\n // Ensure the output directory exists\n const outputDir = path.dirname(outputPath);\n if (!fs.existsSync(outputDir)) {\n logger.info(`Creating directory: ${outputDir}`);\n fs.mkdirSync(outputDir, { recursive: true });\n }\n \n fs.copyFileSync(composePath, outputPath);\n }\n \n logger.success(`Docker Compose file generated successfully: ${outputPath}`);\n } catch (error) {\n logger.error(`Failed to generate Docker Compose file: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { startCommand } from './start';\nimport { stopCommand } from './stop';\n\nexport const simulatorCommands = new Command()\n .name('simulator')\n .description('TEE simulator commands')\n .addCommand(startCommand)\n .addCommand(stopCommand);\n","import { Command } from 'commander';\nimport { DockerService } from '@/src/utils/docker';\nimport { logger } from '@/src/utils/logger';\nimport { TEE_SIMULATOR } from '@/src/utils/constants';\nimport { installSimulator, isSimulatorInstalled, isSimulatorRunning, runSimulator } from '@/src/utils/simulator';\n\nexport const startCommand = new Command()\n .name('start')\n .description('Start the TEE simulator')\n .option('-i, --image <image>', 'Simulator image', TEE_SIMULATOR)\n .option('-p, --port <port>', 'Simulator port (default: 8090)', '8090')\n .option('-t, --type <type>', 'Simulator type (docker, native)', 'docker')\n .action(async (options) => {\n try {\n if (options.type === 'docker') {\n // Start the simulator\n const dockerService = new DockerService('');\n const success = await dockerService.runSimulator(options.image, options.port);\n \n if (!success) {\n logger.error('Failed to start TEE simulator');\n process.exit(1);\n }\n } else if (options.type === 'native') {\n if (!isSimulatorInstalled()) {\n await installSimulator();\n }\n const running = await isSimulatorRunning();\n if (running) {\n logger.success('TEE simulator is already running');\n return;\n } else {\n const simulatorProcess = runSimulator();\n logger.success('TEE simulator started successfully');\n }\n } else {\n logger.error('Invalid simulator type');\n process.exit(1);\n }\n } catch (error) {\n logger.error(`Failed to start TEE simulator: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { DockerService } from '../../utils/docker';\nimport { logger } from '../../utils/logger';\nimport { stopSimulator } from '@/src/utils/simulator';\n\nexport const stopCommand = new Command()\n .name('stop')\n .description('Stop the TEE simulator')\n .option('-t, --type <type>', 'Simulator type (docker, native)', 'docker')\n .action(async (options) => {\n try {\n if (options.type === 'docker') {\n // Stop the simulator\n const dockerService = new DockerService('');\n const success = await dockerService.stopSimulator();\n\n if (!success) {\n logger.error('Failed to stop TEE simulator');\n process.exit(1);\n }\n } else if (options.type === 'native') {\n // Stop the native simulator\n const success = await stopSimulator();\n \n if (!success) {\n logger.error('Failed to stop TEE simulator');\n process.exit(1);\n }\n } else {\n logger.error('Invalid simulator type');\n process.exit(1);\n }\n } catch (error) {\n logger.error(`Failed to stop TEE simulator: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });","import { Command } from 'commander';\nimport { listCommand } from './list';\nimport { getCommand } from './get';\nimport { startCommand } from './start';\nimport { stopCommand } from './stop';\nimport { restartCommand } from './restart';\nimport { attestationCommand } from './attestation';\nimport { createCommand } from './create';\nimport { deleteCommand } from './delete';\nimport { upgradeCommand } from './upgrade';\nimport { resizeCommand } from './resize';\nimport { listNodesCommand } from './list-node';\nimport { replicateCommand } from './replicate';\n\nexport const cvmsCommand = new Command()\n .name('cvms')\n .description('Manage Phala Confidential Virtual Machines (CVMs)')\n .addCommand(attestationCommand)\n .addCommand(createCommand)\n .addCommand(deleteCommand)\n .addCommand(getCommand)\n .addCommand(listCommand)\n .addCommand(startCommand)\n .addCommand(stopCommand)\n .addCommand(resizeCommand)\n .addCommand(restartCommand)\n .addCommand(upgradeCommand)\n .addCommand(listNodesCommand)\n .addCommand(replicateCommand);\n ","import { Command } from 'commander';\nimport { getCvms } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport { CLOUD_URL } from '@/src/utils/constants';\nimport chalk from 'chalk';\n\nexport const listCommand = new Command()\n .name('list')\n .alias('ls')\n .description('List all CVMs')\n .option('-j, --json', 'Output in JSON format')\n .action(async (options) => {\n try {\n const spinner = logger.startSpinner('Fetching CVMs');\n \n const cvms = await getCvms();\n \n spinner.stop(true);\n \n if (!cvms || cvms.length === 0) {\n logger.info('No CVMs found');\n return;\n }\n \n if (options.json) {\n console.log(JSON.stringify(cvms, null, 2));\n return;\n }\n \n for (const cvm of cvms) {\n logger.keyValueTable({\n Name: cvm.name,\n \"App ID\": `app_${cvm.hosted.app_id}`,\n \"CVM ID\": cvm.hosted.id.replace(/-/g, ''),\n \"Region\": cvm.node.region_identifier,\n Status:\n cvm.status === \"running\"\n ? chalk.green(cvm.status)\n : cvm.status === \"stopped\"\n ? chalk.red(cvm.status)\n : chalk.yellow(cvm.status),\n \"Node Info URL\": cvm.hosted.app_url,\n \"App URL\": `${CLOUD_URL}/dashboard/cvms/${cvm.hosted.id.replace(/-/g, '')}`,\n });\n logger.break();\n }\n logger.success(`Found ${cvms.length} CVMs`);\n logger.break();\n logger.info(`Go to ${CLOUD_URL}/dashboard/ to view your CVMs`);\n } catch (error) {\n logger.error(`Failed to list CVMs: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { checkCvmExists, getCvmByAppId, getCvms, selectCvm } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport { CLOUD_URL } from '@/src/utils/constants';\nimport chalk from 'chalk';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\n\nexport const getCommand = new Command()\n .name('get')\n .description('Get details of a CVM')\n .argument('[app-id]', 'App ID of the CVM (optional)')\n .option('-j, --json', 'Output in JSON format')\n .action(async (appId, options) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n \n const spinner = logger.startSpinner(`Fetching CVM with App ID app_${resolvedAppId}`);\n \n const cvm = await getCvmByAppId(resolvedAppId);\n \n spinner.stop(true);\n logger.break();\n \n if (!cvm) {\n logger.error(`CVM with App ID app_${resolvedAppId} not found`);\n process.exit(1);\n }\n \n if (options.json) {\n console.log(JSON.stringify(cvm, null, 2));\n return;\n }\n \n // Display additional details if available\n logger.keyValueTable({\n 'Name': cvm.name,\n 'App ID': `app_${cvm.app_id}`,\n 'Status': (cvm.status === 'running') ? chalk.green(cvm.status) : (cvm.status === 'stopped') ? chalk.red(cvm.status) : chalk.yellow(cvm.status),\n 'vCPU': cvm.vcpu,\n 'Memory': `${cvm.memory} MB`,\n 'Disk Size': `${cvm.disk_size} GB`,\n 'Dstack Image': cvm.base_image,\n 'App URL': `${CLOUD_URL}/dashboard/cvms/app_${cvm.app_id}`\n });\n } catch (error) {\n logger.error(`Failed to get CVM details: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { selectCvm, checkCvmExists } from \"@/src/api/cvms\";\nimport { logger } from \"./logger\";\n\n/**\n * Resolves a CVM App ID either by prompting the user to select one if none is provided,\n * or by validating the provided App ID exists.\n *\n * @param appId Optional App ID to resolve\n * @returns The resolved App ID or undefined if none was selected/found\n */\nexport async function resolveCvmAppId(\n\tappId?: string,\n): Promise<string | undefined> {\n\tif (!appId) {\n\t\t// If no app ID is provided, prompt user to select one\n\t\tconst selectedCvm = await selectCvm();\n\t\tif (!selectedCvm) {\n\t\t\treturn undefined; // No CVMs found or user canceled\n\t\t}\n\t\treturn selectedCvm;\n\t}\n\t// Verify the provided App ID exists\n\treturn await checkCvmExists(appId);\n}","import { Command } from 'commander';\nimport { startCvm, selectCvm, checkCvmExists } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\nimport { CLOUD_URL } from '@/src/utils/constants';\n\nexport const startCommand = new Command()\n .name('start')\n .description('Start a stopped CVM')\n .argument('[app-id]', 'App ID of the CVM (if not provided, a selection prompt will appear)')\n .action(async (appId) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n \n const spinner = logger.startSpinner(`Starting CVM with App ID app_${resolvedAppId}`);\n \n const response = await startCvm(resolvedAppId);\n \n spinner.stop(true);\n logger.break();\n \n const tableData = {\n 'CVM ID': response.id,\n 'Name': response.name,\n 'Status': response.status,\n 'App ID': `app_${response.app_id}`,\n };\n logger.keyValueTable(tableData, {\n borderStyle: 'rounded'\n });\n \n logger.break();\n logger.success(\n `Your CVM is being started. You can check the dashboard for more details:\\n${CLOUD_URL}/dashboard/cvms/app_${response.app_id}`);\n } catch (error) {\n logger.error(`Failed to start CVM: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { stopCvm, selectCvm, checkCvmExists } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\nimport { CLOUD_URL } from '@/src/utils/constants';\n\nexport const stopCommand = new Command()\n .name('stop')\n .description('Stop a running CVM')\n .argument('[app-id]', 'App ID of the CVM (if not provided, a selection prompt will appear)')\n .action(async (appId) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n\n const spinner = logger.startSpinner(\n `Stopping CVM with App ID app_${resolvedAppId}`,\n );\n\n const response = await stopCvm(resolvedAppId);\n\n spinner.stop(true);\n logger.break();\n\n const tableData = {\n 'CVM ID': response.id,\n 'Name': response.name,\n 'Status': response.status,\n 'App ID': `app_${response.app_id}`,\n };\n logger.keyValueTable(tableData, {\n borderStyle: 'rounded'\n });\n\n logger.break();\n logger.success(\n `Your CVM is being stopped. You can check the dashboard for more details:\\n${CLOUD_URL}/dashboard/cvms/app_${response.app_id}`);\n \n } catch (error) {\n logger.error(`Failed to stop CVM: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { checkCvmExists, restartCvm, selectCvm } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\nimport { CLOUD_URL } from '@/src/utils/constants';\n\nexport const restartCommand = new Command()\n .name('restart')\n .description('Restart a CVM')\n .argument('[app-id]', 'App ID of the CVM (if not provided, a selection prompt will appear)')\n .action(async (appId) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n\n const spinner = logger.startSpinner(\n `Restarting CVM with App ID app_${resolvedAppId}`,\n );\n\n const response = await restartCvm(resolvedAppId);\n\n spinner.stop(true);\n logger.break();\n\n const tableData = {\n 'CVM ID': response.id,\n 'Name': response.name,\n 'Status': response.status,\n 'App ID': `app_${response.app_id}`,\n 'App URL': response.app_url\n ? response.app_url\n : `${CLOUD_URL}/dashboard/cvms/app_${response.app_id}`,\n };\n logger.keyValueTable(tableData, {\n borderStyle: \"rounded\",\n });\n\n logger.break();\n logger.success(\n `Your CVM is being restarted. You can check the dashboard for more details:\\n${CLOUD_URL}/dashboard/cvms/app_${response.app_id}`);\n } catch (error) {\n logger.error(`Failed to restart CVM: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { checkCvmExists, getCvmAttestation, selectCvm } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport chalk from 'chalk';\nimport type { CvmAttestationResponse } from '@/src/api/types';\n\nexport const attestationCommand = new Command()\n .name('attestation')\n .description('Get attestation information for a CVM')\n .argument('[app-id]', 'CVM app ID (will prompt for selection if not provided)')\n .option('-j, --json', 'Output in JSON format')\n .action(async (appId?: string, options?: { json?: boolean }) => {\n try {\n let resolvedAppId: string;\n \n if (!appId) {\n logger.info('No CVM specified, fetching available CVMs...');\n const selectedCvm = await selectCvm();\n if (!selectedCvm) {\n return;\n }\n resolvedAppId = selectedCvm;\n } else {\n resolvedAppId = await checkCvmExists(appId);\n }\n\n const spinner = logger.startSpinner(`Fetching attestation information for CVM app_${resolvedAppId}...`);\n\n try {\n const attestationData: CvmAttestationResponse = await getCvmAttestation(resolvedAppId);\n spinner.stop(true);\n\n if (!attestationData || Object.keys(attestationData).length === 0) {\n logger.info('No attestation information found');\n return;\n }\n\n // If JSON output is requested, just print the raw response\n if (options?.json) {\n logger.info(JSON.stringify(attestationData, null, 2));\n return;\n }\n\n // Display the attestation summary\n logger.success('Attestation Summary:');\n const summaryData = {\n 'Status': attestationData.is_online ? chalk.green('Online') : chalk.red('Offline'),\n 'Public Access': attestationData.is_public ? chalk.green('Enabled') : chalk.yellow('Disabled'),\n 'Error': attestationData.error || 'None',\n 'Certificates': `${attestationData.app_certificates?.length || 0} found`\n };\n \n logger.keyValueTable(summaryData, {\n borderStyle: 'rounded'\n });\n\n // Display certificate information\n if (attestationData.app_certificates && attestationData.app_certificates.length > 0) {\n \n attestationData.app_certificates.forEach((cert, index) => {\n logger.break();\n logger.success(`Certificate #${index + 1} (${cert.position_in_chain === 0 ? 'End Entity' : 'CA'}):`);\n \n const certData = {\n 'Subject': `${cert.subject.common_name || 'Unknown'}${cert.subject.organization ? ` (${cert.subject.organization})` : ''}`,\n 'Issuer': `${cert.issuer.common_name || 'Unknown'}${cert.issuer.organization ? ` (${cert.issuer.organization})` : ''}`,\n 'Serial Number': cert.serial_number,\n 'Validity': `${new Date(cert.not_before).toLocaleString()} to ${new Date(cert.not_after).toLocaleString()}`,\n 'Fingerprint': cert.fingerprint,\n 'Signature Algorithm': cert.signature_algorithm,\n 'Is CA': cert.is_ca ? 'Yes' : 'No',\n 'Position in Chain': cert.position_in_chain\n };\n \n logger.keyValueTable(certData, {\n borderStyle: 'rounded'\n });\n \n // Skip displaying the quote as it's very large and mostly binary data\n });\n }\n\n // Display TCB info if available\n if (attestationData.tcb_info) {\n logger.break();\n logger.success('Trusted Computing Base (TCB) Information:');\n \n // Create a formatted version of the TCB info without the event log\n const tcbBasicInfo = {\n 'Mrtd': attestationData.tcb_info.mrtd,\n 'Rootfs Hash': attestationData.tcb_info.rootfs_hash,\n 'Rtmr0': attestationData.tcb_info.rtmr0,\n 'Rtmr1': attestationData.tcb_info.rtmr1,\n 'Rtmr2': attestationData.tcb_info.rtmr2,\n 'Rtmr3': attestationData.tcb_info.rtmr3,\n 'Event Log Entries': `${attestationData.tcb_info.event_log.length} entries`\n };\n \n // Display basic TCB info\n logger.keyValueTable(tcbBasicInfo, {\n borderStyle: 'rounded'\n });\n \n // Display event log entries separately if they exist\n if (attestationData.tcb_info.event_log && attestationData.tcb_info.event_log.length > 0) {\n logger.break();\n logger.success('Event Log (Showing entries to reproduce RTMR3):');\n \n // Show the first 5 entries\n const maxEntriesToShow = 5;\n const entries = attestationData.tcb_info.event_log\n .filter(entry => entry.event !== null && entry.event !== \"\")\n .map((entry) => ({\n 'Event': entry.event,\n 'IMR': entry.imr.toString(),\n 'Event Type': entry.event_type.toString(),\n 'Payload': entry.event_payload,\n }));\n \n // Display entries in a table format\n logger.table(entries, [\n { key: \"Event\", header: \"Event\", minWidth: 8 },\n { key: \"IMR\", header: \"IMR\", minWidth: 3 },\n { key: \"Event Type\", header: \"Type\", minWidth: 8 },\n { key: \"Payload\", header: \"Payload\", minWidth: 25 },\n ]);\n \n if (attestationData.tcb_info.event_log.length > maxEntriesToShow) {\n logger.info('To see all full attestation data, use --json');\n }\n logger.break();\n logger.success('To reproduce RTMR3, use the tool at https://rtmr3-calculator.vercel.app/');\n }\n }\n } catch (error) {\n spinner.stop(false);\n throw error;\n }\n } catch (error) {\n logger.error(`Failed to get attestation information: ${error instanceof Error ? error.message : String(error)}`);\n }\n });\n","import { Command } from 'commander';\nimport { createCvm, getPubkeyFromCvm } from '@/src/api/cvms';\nimport { getTeepods } from '@/src/api/teepods';\nimport { logger } from '@/src/utils/logger';\nimport type { TEEPod, Image } from '@/src/api/types';\nimport { DEFAULT_VCPU, DEFAULT_MEMORY, DEFAULT_DISK_SIZE, CLOUD_URL, DEFAULT_IMAGE } from '@/src/utils/constants';\nimport { encryptEnvVars } from '@phala/dstack-sdk/encrypt-env-vars';\nimport type { EnvVar } from '@phala/dstack-sdk/encrypt-env-vars';\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport inquirer from 'inquirer';\nimport { parseEnv } from '@/src/utils/secrets';\nimport { detectFileInCurrentDir, promptForFile } from '@/src/utils/prompts';\nimport { deleteSimulatorEndpointEnv } from '@/src/utils/simulator';\n\nexport const createCommand = new Command()\n .name('create')\n .description('Create a new CVM')\n .option('-n, --name <name>', 'Name of the CVM')\n .option('-c, --compose <compose>', 'Path to Docker Compose file')\n .option('--vcpu <vcpu>', `Number of vCPUs, default is ${DEFAULT_VCPU}`)\n .option('--memory <memory>', `Memory in MB, default is ${DEFAULT_MEMORY}`)\n .option('--disk-size <diskSize>', `Disk size in GB, default is ${DEFAULT_DISK_SIZE}`)\n .option('--teepod-id <teepodId>', 'TEEPod ID to use. If not provided, it will be selected from the list of available TEEPods.')\n .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.')\n .option('-e, --env-file <envFile>', 'Path to environment file')\n .option('--skip-env', 'Skip environment variable prompt', false)\n .option('--debug', 'Enable debug mode', false)\n .action(async (options) => {\n try {\n // Prompt for required options if not provided\n if (!options.name) {\n const { name } = await inquirer.prompt([\n {\n type: 'input',\n name: 'name',\n message: 'Enter a name for the CVM:',\n validate: (input) => {\n if (!input.trim()) {\n return 'CVM name is required';\n }\n if (input.trim().length > 20) {\n return 'CVM name must be less than 20 characters';\n } \n if (input.trim().length < 3) {\n return 'CVM name must be at least 3 characters';\n } \n if (!/^[a-zA-Z0-9_-]+$/.test(input)) {\n return 'CVM name must contain only letters, numbers, underscores, and hyphens';\n }\n return true;\n }\n }\n ]);\n options.name = name;\n }\n\n // If compose path not provided, prompt with examples\n if (!options.compose) {\n const possibleFiles = ['docker-compose.yml', 'docker-compose.yaml'];\n const composeFileName = detectFileInCurrentDir(possibleFiles, 'Detected docker compose file: {path}');\n\n options.compose = await promptForFile(\n 'Enter the path to your Docker Compose file:',\n composeFileName,\n 'file'\n );\n }\n\n const composePath = path.resolve(options.compose);\n if (!fs.existsSync(composePath)) {\n logger.error(`Docker Compose file not found: ${composePath}`);\n process.exit(1);\n }\n const composeString = fs.readFileSync(composePath, 'utf8');\n\n // Delete DSTACK_SIMULATOR_ENDPOINT environment variable\n await deleteSimulatorEndpointEnv();\n\n // Print if they are using a private registry\n if (process.env.DSTACK_DOCKER_USERNAME && process.env.DSTACK_DOCKER_PASSWORD) {\n logger.info(\"🔐 Using private DockerHub registry credentials...\");\n } else if (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) {\n logger.info(`🔐 Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`);\n } else {\n logger.info(\"🔐 Using public DockerHub registry...\");\n }\n\n // Process environment variables\n let envs: EnvVar[] = [];\n\n // Process environment variables from file\n if (options.envFile) {\n try {\n envs = parseEnv([], options.envFile);\n } catch (error) {\n logger.error(`Failed to read environment file: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n } else if (!options.skipEnv) {\n // Prompt to input env file or skip\n const { shouldSkip } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'shouldSkip',\n message: 'Do you want to skip environment variable prompt?',\n default: true\n }\n ]);\n \n if (shouldSkip) {\n logger.info('Skipping environment variable prompt');\n } else {\n const envVars = await promptForFile(\n 'Enter the path to your environment file:',\n '.env',\n 'file',\n );\n envs = parseEnv([], envVars);\n }\n }\n\n const vcpu = Number(options.vcpu) || DEFAULT_VCPU;\n const memory = Number(options.memory) || DEFAULT_MEMORY;\n const diskSize = Number(options.diskSize) || DEFAULT_DISK_SIZE;\n\n if (Number.isNaN(vcpu) || vcpu <= 0) {\n logger.error(`Invalid number of vCPUs: ${vcpu}`);\n process.exit(1);\n }\n\n if (Number.isNaN(memory) || memory <= 0) {\n logger.error(`Invalid memory: ${memory}`);\n process.exit(1);\n }\n\n if (Number.isNaN(diskSize) || diskSize <= 0) {\n logger.error(`Invalid disk size: ${diskSize}`);\n process.exit(1);\n }\n\n const teepodsSpinner = logger.startSpinner('Fetching available TEEPods');\n const teepods = await getTeepods();\n teepodsSpinner.stop(true);\n if (teepods.length === 0) {\n logger.error('No TEEPods available. Please try again later.');\n process.exit(1);\n }\n\n let selectedTeepod: TEEPod;\n // Fetch available TEEPods\n if (!options.teepodId) {\n selectedTeepod = teepods[0];\n if (!selectedTeepod) {\n logger.error('Failed to find default TEEPod');\n process.exit(1);\n }\n } else {\n selectedTeepod = teepods.find(pod => pod.teepod_id === Number(options.teepodId));\n if (!selectedTeepod) {\n logger.error('Failed to find selected TEEPod');\n process.exit(1);\n }\n }\n\n let selectedImage: Image;\n if (!options.image) {\n selectedImage = selectedTeepod.images?.find(image => image.name === DEFAULT_IMAGE);\n if (!selectedImage) {\n logger.error(`Failed to find default image ${DEFAULT_IMAGE}`);\n process.exit(1);\n }\n } else {\n selectedImage = selectedTeepod.images?.find(image => image.name === options.image);\n if (!selectedImage) {\n logger.error(`Failed to find selected image: ${options.image}`);\n process.exit(1);\n }\n }\n\n // Prepare VM configuration\n const vmConfig = {\n teepod_id: selectedTeepod.teepod_id,\n name: options.name,\n image: selectedImage.name,\n vcpu: vcpu,\n memory: memory,\n disk_size: diskSize,\n compose_manifest: {\n docker_compose_file: composeString,\n docker_config: {\n url: '',\n username: '',\n password: '',\n },\n features: ['kms', 'tproxy-net'],\n kms_enabled: true,\n manifest_version: 2,\n name: options.name,\n public_logs: true,\n public_sysinfo: true,\n tproxy_enabled: true,\n },\n listed: false,\n };\n\n // Get public key from CVM\n const spinner = logger.startSpinner('Getting public key from CVM');\n const pubkey = await getPubkeyFromCvm(vmConfig);\n spinner.stop(true);\n\n if (!pubkey) {\n logger.error('Failed to get public key from CVM');\n process.exit(1);\n }\n\n // Encrypt environment variables\n const encryptSpinner = logger.startSpinner('Encrypting environment variables');\n const encrypted_env = await encryptEnvVars(envs, pubkey.app_env_encrypt_pubkey);\n encryptSpinner.stop(true);\n\n if (options.debug) {\n logger.debug('Public key:', pubkey.app_env_encrypt_pubkey);\n logger.debug('Encrypted environment variables:', encrypted_env);\n logger.debug('Environment variables:', JSON.stringify(envs));\n }\n\n // Create the CVM\n const createSpinner = logger.startSpinner('Creating CVM');\n const response = await createCvm({\n ...vmConfig,\n encrypted_env,\n app_env_encrypt_pubkey: pubkey.app_env_encrypt_pubkey,\n app_id_salt: pubkey.app_id_salt,\n });\n createSpinner.stop(true);\n\n if (!response) {\n logger.error('Failed to create CVM');\n process.exit(1);\n }\n\n logger.success('CVM created successfully');\n logger.break();\n const tableData = {\n 'CVM ID': response.id,\n 'Name': response.name,\n 'Status': response.status,\n 'App ID': `app_${response.app_id}`,\n 'App URL': response.app_url ? response.app_url : `${CLOUD_URL}/dashboard/cvms/app_${response.app_id}`,\n };\n logger.keyValueTable(tableData, {\n borderStyle: 'rounded'\n });\n\n logger.info('');\n logger.success(`Your CVM is being created. You can check its status with:\\nphala cvms get app_${response.app_id}`);\n } catch (error) {\n logger.error(`Failed to create CVM: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import * as fs from 'node:fs';\nimport type { EnvVar } from '@phala/dstack-sdk/encrypt-env-vars';\n\nexport const parseEnv = (envs: string[], envFile: string): EnvVar[] => {\n const envVars: Record<string, string> = {};\n\n // Process environment variables passed directly\n if (envs) {\n for (const env of envs) {\n if (env.includes(\"=\")) {\n const [key, ...valueParts] = env.split(\"=\");\n const value = valueParts.join(\"=\"); // Handle cases where value might contain '='\n if (key) { // Allow empty value\n envVars[key] = value;\n }\n }\n }\n }\n\n if (envFile) {\n const envFileContent = fs.readFileSync(envFile, \"utf8\");\n for (const line of envFileContent.split(\"\\n\")) {\n // Skip empty lines\n if (!line.trim()) {\n continue;\n }\n\n // Skip comments\n if (line.trim().startsWith('#')) {\n continue;\n }\n\n // Find the first '=' that is not part of an inline comment\n let delimiterIndex = -1;\n let inQuotes = false;\n let quoteChar = '';\n\n for (let i = 0; i < line.length; i++) {\n if ((line[i] === '\"' || line[i] === \"'\" || line[i] === '`') && (i === 0 || line[i-1] !== '\\\\')) {\n if (inQuotes && line[i] === quoteChar) {\n inQuotes = false;\n quoteChar = '';\n } else if (!inQuotes) {\n inQuotes = true;\n quoteChar = line[i];\n }\n } else if (line[i] === '=' && !inQuotes) {\n delimiterIndex = i;\n break;\n } else if (line[i] === '#' && !inQuotes) {\n // If a comment starts before any '=', treat the whole line as a comment if no '=' found yet\n // Or, if '=' is found, this part is an inline comment.\n if (delimiterIndex === -1) { // No '=' encountered yet, so this is a full-line comment essentially or malformed\n // We already skip lines starting with #, this handles cases like \" #comment\"\n // or \"KEY #comment\" (which is not a valid assignment according to rules)\n // However, the rule \" # marks the beginning of a comment (unless when the value is wrapped in quotes)\"\n // implies that \"KEY=value #comment\" is valid.\n // The current logic handles inline comments on the value side later.\n // If # appears before =, it's either a full comment (handled) or part of the key (unusual, but let it pass to split)\n }\n break; // Stop processing at the comment marker for the key or if it's an inline comment for the value\n }\n }\n\n\n if (delimiterIndex === -1) {\n // Handles lines without '=' or lines that are effectively comments.\n if (!line.trim().startsWith('#')) {\n // It's not a comment line, but has no '='.\n // According to \"EMPTY= becomes {EMPTY: ''}\", lines like \"ONLYKEY\" are not defined.\n // So we can skip them or treat as an error. Skipping for now.\n }\n continue;\n }\n\n const key = line.substring(0, delimiterIndex).trim();\n let value = line.substring(delimiterIndex + 1);\n\n // Remove inline comments from the value part\n // A comment starts with ' #' (space followed by #)\n // unless the # is within quotes.\n let valueInQuotes = false;\n let valueQuoteChar = '';\n let commentStartIndex = -1;\n\n for (let i = 0; i < value.length; i++) {\n if ((value[i] === '\"' || value[i] === \"'\" || value[i] === '`') && (i === 0 || value[i-1] !== '\\\\')) {\n if (valueInQuotes && value[i] === valueQuoteChar) {\n valueInQuotes = false;\n valueQuoteChar = '';\n } else if (!valueInQuotes) {\n valueInQuotes = true;\n valueQuoteChar = value[i];\n }\n } else if (value[i] === '#' && !valueInQuotes && i > 0 && value[i-1] === ' ') {\n commentStartIndex = i -1; // Start of \" #\"\n break;\n } else if (value[i] === '#' && !valueInQuotes && i === 0) { // Value starts directly with #\n commentStartIndex = i;\n break;\n }\n }\n\n if (commentStartIndex !== -1) {\n value = value.substring(0, commentStartIndex);\n }\n\n\n // Handle empty values: EMPTY= becomes {EMPTY: ''}\n if (value === undefined) { // Should not happen if split correctly\n value = '';\n }\n\n\n // Trim whitespace for unquoted values, preserve for quoted\n const firstChar = value.charAt(0);\n const lastChar = value.charAt(value.length - 1);\n\n if ((firstChar === '\"' && lastChar === '\"') ||\n (firstChar === \"'\" && lastChar === \"'\") ||\n (firstChar === '`' && lastChar === '`')) {\n // Quoted value, remove the outer quotes\n value = value.substring(1, value.length - 1);\n\n // Expand newlines for double-quoted values\n if (firstChar === '\"') {\n value = value.replace(/\\\\\\\\n/g, '\\n');\n }\n // Unescape inner quotes for single and backtick quotes if they were escaped like \\\\' or \\\\`\n // The rules state \"inner quotes are maintained (think JSON)\"\n // and \"single and double quoted values are escaped\"\n // This implies that within a string like SINGLE_QUOTE='value with \\\\' quote'\n // the result should be \"value with ' quote\"\n // For JSON example: JSON={\"foo\": \"bar\"} becomes {JSON:\"{\\\"foo\\\": \\\"bar\\\"}\"}\n // This needs careful handling. The current approach of just slicing quotes might be too simple.\n // Let's assume the provided examples are the source of truth.\n // \"JSON={\"foo\": \"bar\"}\" -> JSON: \"{\\\"foo\\\": \\\"bar\\\"}\"\n // This means the quotes *around* the JSON are stripped, but the inner quotes *within* the JSON string literal itself are preserved.\n // The rule \"single and double quoted values are escaped (SINGLE_QUOTE='quoted' becomes {SINGLE_QUOTE: \"quoted\"})\"\n // seems to imply that the outer quotes are removed, and the content becomes a JS string.\n // The parsing engine should output a JS object, so values will be JS strings.\n // SINGLE_QUOTE='quoted' -> {SINGLE_QUOTE: 'quoted'} (JS string)\n // FOO=\" some value \" -> {FOO: ' some value '} (JS string)\n // JSON={\"foo\": \"bar\"} -> {JSON: '{\"foo\": \"bar\"}'} (JS string)\n // MULTILINE=\"new\\\\nline\" -> {MULTILINE: 'new\\\\nline'} (JS string with literal \\n)\n // The rule says: MULTILINE=\"new\\\\nline\" becomes {MULTILINE: 'new\\nline'} (with actual newline)\n // So, my previous .replace(/\\\\n/g, '\\n') for double quotes is correct.\n\n // For single quotes and backticks, the rules don't explicitly state escaped char handling other than `\\\\n` for double quotes.\n // \"inner quotes are maintained (think JSON)\" - this is key for JSON={\"foo\": \"bar\"}\n // Let's ensure that if a value is `'{\"key\": \"value\"}'`, it becomes `{\"key\": \"value\"}`.\n // The current `substring(1, value.length - 1)` does this.\n // Let's consider BACKTICK_KEY=`This has 'single' and \"double\" quotes inside of it.`\n // This should become {BACKTICK_KEY: \"This has 'single' and \\\"double\\\" quotes inside of it.\"}\n // The current slicing handles this correctly. Escaped backticks like \\` needs to be considered if they should be unescaped.\n // The rules do not specify un-escaping for \\\\', \\\\\", or \\\\` within their respective quotes.\n // So, 'it\\'s a test' would become \"it\\'s a test\". If it should be \"it's a test\", then un-escaping is needed.\n // Given \"single and double quoted values are escaped\", it seems like what's inside the quotes is the literal string value.\n // Let's stick to the examples: SINGLE_QUOTE='quoted' becomes {SINGLE_QUOTE: \"quoted\"}. This means the value is 'quoted'.\n } else {\n // Unquoted value, trim whitespace\n value = value.trim();\n }\n\n\n if (key) { // Ensure key is not empty\n envVars[key] = value;\n }\n }\n }\n\n // Add environment variables to the payload\n return Object.entries(envVars).map(([key, value]) => ({\n key,\n value,\n }));\n};","import { Command } from 'commander';\nimport { checkCvmExists, deleteCvm, selectCvm } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport inquirer from 'inquirer';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\n\nexport const deleteCommand = new Command()\n .name('delete')\n .description('Delete a CVM')\n .argument('[app-id]', 'App ID of the CVM to delete (if not provided, a selection prompt will appear)')\n .option('-f, --force', 'Skip confirmation prompt', false)\n .action(async (appId, options) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n \n // Confirm deletion unless force option is used\n if (!options.force) {\n const { confirm } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'confirm',\n message: `Are you sure you want to delete CVM with App ID app_${resolvedAppId}? This action cannot be undone.`,\n default: false,\n },\n ]);\n \n if (!confirm) {\n logger.info('Deletion cancelled');\n return;\n }\n }\n \n // Delete the CVM\n const spinner = logger.startSpinner(`Deleting CVM app_${resolvedAppId}`);\n const success = await deleteCvm(resolvedAppId);\n spinner.stop(true);\n \n if (!success) {\n logger.error(`Failed to delete CVM app_${resolvedAppId}`);\n process.exit(1);\n }\n\n\t\tlogger.success(`CVM app_${resolvedAppId} deleted successfully`);\n\t} catch (error) {\n\t\tlogger.error(\n\t\t\t`Failed to delete CVM: ${error instanceof Error ? error.message : String(error)}`\n\t\t);\n\t\tprocess.exit(1);\n\t}\n }); ","import { Command } from 'commander';\nimport { upgradeCvm, getCvmByAppId, selectCvm, checkCvmExists } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport fs from 'node:fs';\nimport { detectFileInCurrentDir, promptForFile } from '@/src/utils/prompts';\nimport { parseEnv } from '@/src/utils/secrets';\nimport { encryptEnvVars, type EnvVar } from '@phala/dstack-sdk/encrypt-env-vars';\nimport { deleteSimulatorEndpointEnv } from '@/src/utils/simulator';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\nimport { CLOUD_URL } from '@/src/utils/constants';\n\nexport const upgradeCommand = new Command()\n .name('upgrade')\n .description('Upgrade a CVM to a new version')\n .argument('[app-id]', 'CVM app ID to upgrade (will prompt for selection if not provided)')\n .option('-c, --compose <compose>', 'Path to new Docker Compose file')\n .option('-e, --env-file <envFile>', 'Path to environment file')\n .option('--debug', 'Enable debug mode', false)\n .action(async (appId, options) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n\n // Get current CVM configuration\n const spinner = logger.startSpinner(`Fetching current configuration for CVM app_${resolvedAppId}`);\n const currentCvm = await getCvmByAppId(resolvedAppId);\n spinner.stop(true);\n \n if (!currentCvm) {\n logger.error(`CVM with App ID app_${resolvedAppId} not found`);\n process.exit(1);\n }\n \n // If compose path not provided, prompt with examples\n if (!options.compose) {\n const possibleFiles = ['docker-compose.yml', 'docker-compose.yaml'];\n const composeFileName = detectFileInCurrentDir(possibleFiles, 'Detected docker compose file: {path}');\n \n options.compose = await promptForFile(\n 'Enter the path to your Docker Compose file:',\n composeFileName,\n 'file'\n );\n }\n \n // Update Docker Compose file if provided\n let composeString = '';\n if (options.compose) {\n try {\n composeString = fs.readFileSync(options.compose, 'utf8');\n } catch (error) {\n logger.error(`Failed to read Docker Compose file: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }\n \n // Delete DSTACK_SIMULATOR_ENDPOINT environment variable\n await deleteSimulatorEndpointEnv();\n // Print if they are using a private registry\n if (process.env.DSTACK_DOCKER_USERNAME && process.env.DSTACK_DOCKER_PASSWORD) {\n logger.info(\"🔐 Using private DockerHub registry credentials...\");\n } else if (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) {\n logger.info(`🔐 Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`);\n } else {\n logger.info(\"🔐 Using public DockerHub registry...\");\n }\n\n // Process environment variables if provided\n let encrypted_env = \"\";\n if (options.envFile) {\n let envs: EnvVar[] = [];\n \n // Process environment variables from file\n if (options.envFile) {\n try {\n envs = parseEnv([], options.envFile);\n encrypted_env = await encryptEnvVars(envs, currentCvm.encrypted_env_pubkey);\n } catch (error) {\n logger.error(`Failed to read environment file: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }\n \n }\n\n const vm_config = {\n compose_manifest: {\n docker_compose_file: composeString,\n manifest_version: 1,\n runner: \"docker-compose\",\n version: \"1.0.0\",\n features: [\"kms\", \"tproxy-net\"],\n name: `app_${resolvedAppId}`,\n },\n encrypted_env,\n allow_restart: true,\n };\n \n // Upgrade the CVM\n const upgradeSpinner = logger.startSpinner(`Upgrading CVM app_${resolvedAppId}`);\n const response = await upgradeCvm(resolvedAppId, vm_config);\n \n if (!response) {\n upgradeSpinner.stop(false);\n logger.error('Failed to upgrade CVM');\n process.exit(1);\n }\n upgradeSpinner.stop(true);\n\n if (response.detail) {\n logger.info(`Details: ${response.detail}`);\n }\n\n logger.break();\n logger.success(\n `Your CVM is being upgraded. You can check the dashboard for more details:\\n${CLOUD_URL}/dashboard/cvms/app_${resolvedAppId}`\n );\n } catch (error) {\n logger.error(`Failed to upgrade CVM: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { checkCvmExists, getCvmByAppId, resizeCvm, selectCvm } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport inquirer from 'inquirer';\nimport chalk from 'chalk';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\nimport { CLOUD_URL } from '@/src/utils/constants';\n\nexport const resizeCommand = new Command()\n .name('resize')\n .description('Resize resources for a CVM')\n .argument('[app-id]', 'App ID of the CVM (if not provided, a selection prompt will appear)')\n .option('-v, --vcpu <vcpu>', 'Number of virtual CPUs')\n .option('-m, --memory <memory>', 'Memory size in MB')\n .option('-d, --disk-size <diskSize>', 'Disk size in GB')\n .option('-r, --allow-restart <allowRestart>', 'Allow restart of the CVM if needed for resizing')\n .option('-y, --yes', 'Automatically confirm the resize operation')\n .action(async (appId, options) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n\n const cvm = await getCvmByAppId(resolvedAppId);\n \n // Initialize parameters\n let vcpu: number | undefined = options.vcpu;\n let memory: number | undefined = options.memory;\n let diskSize: number | undefined = options.diskSize;\n let allowRestart: boolean | undefined = options.allowRestart;\n // Prompt for vCPU if selected\n if (!vcpu) {\n const response = await inquirer.prompt([\n {\n type: 'input',\n name: 'vcpu',\n message: 'Enter number of vCPUs:',\n validate: (input) => {\n const num = parseInt(input);\n if (isNaN(num) || num < 0) {\n return 'Please enter a valid non-negative number';\n }\n return true;\n },\n default: cvm.vcpu,\n filter: (input) => parseInt(input)\n }\n ]);\n vcpu = response.vcpu;\n }\n \n // Prompt for memory\n if (!memory) {\n const response = await inquirer.prompt([\n {\n type: 'input',\n name: 'memory',\n message: 'Enter memory in MB:',\n validate: (input) => {\n const num = parseInt(input);\n if (isNaN(num) || num < 0) {\n return 'Please enter a valid non-negative number';\n }\n return true;\n },\n default: cvm.memory,\n filter: (input) => parseInt(input)\n }\n ]);\n memory = response.memory;\n }\n \n // Prompt for disk size\n if (!diskSize) {\n const response = await inquirer.prompt([\n {\n type: 'input',\n name: 'diskSize',\n message: 'Enter disk size in GB:',\n validate: (input) => {\n const num = parseInt(input);\n if (isNaN(num) || num < 0) {\n return 'Please enter a valid non-negative number';\n }\n return true;\n },\n default: cvm.disk_size,\n filter: (input) => parseInt(input)\n }\n ]);\n diskSize = response.diskSize;\n }\n \n // Ask about restart permission\n if (!allowRestart) {\n const response = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'allowRestart',\n message: 'Allow restart of the CVM if needed for resizing?',\n default: false\n }\n ]);\n allowRestart = response.allowRestart;\n }\n \n // Prepare confirmation message\n const confirmMessage = `Are you sure you want to resize CVM app_${resolvedAppId} with the following changes:\\n`;\n logger.keyValueTable(\n { 'vCPUs': cvm.vcpu !== vcpu ? `${chalk.red(cvm.vcpu)} -> ${chalk.green(vcpu)}` : cvm.vcpu,\n 'Memory': cvm.memory !== memory ? `${chalk.red(cvm.memory)} MB -> ${chalk.green(memory)} MB` : cvm.memory,\n 'Disk Size': cvm.disk_size !== diskSize ? `${chalk.red(cvm.disk_size)} GB -> ${chalk.green(diskSize)} GB` : cvm.disk_size,\n 'Allow Restart': allowRestart ? chalk.green('Yes') : chalk.red('No') }\n );\n \n // Confirm the resize operation\n if (!options.yes) {\n const { confirm } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'confirm',\n message: confirmMessage,\n default: false\n }\n ]);\n \n if (!confirm) {\n logger.info('Resize operation cancelled');\n return;\n }\n }\n \n const spinner = logger.startSpinner(`Resizing CVM with App ID app_${resolvedAppId}`);\n \n // Convert boolean to number (0 or 1) as expected by the API\n const allowRestartValue = allowRestart ? 1 : 0;\n \n await resizeCvm(resolvedAppId, vcpu, memory, diskSize, allowRestartValue);\n\n spinner.stop(true);\n logger.break();\n logger.success(\n `Your CVM is being resized. You can check the dashboard for more details:\\n${CLOUD_URL}/dashboard/cvms/app_${resolvedAppId}`\n );\n } catch (error) {\n logger.error(\n `Failed to resize CVM: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { getTeepods } from '@/src/api/teepods';\nimport { logger } from '@/src/utils/logger';\nimport { KmsListItem, TEEPod } from '@/src/api/types';\n\nexport const listNodesCommand = new Command()\n .name('list-nodes')\n .description('List all available worker nodes.')\n .action(async () => {\n try {\n const { nodes: teepods, kms_list: kmsList } = await getTeepods();\n\n if (teepods.length === 0) {\n logger.info('No available nodes found.');\n return;\n }\n\n logger.info('Available Nodes:');\n teepods.forEach((teepod: TEEPod) => {\n logger.info('----------------------------------------');\n logger.info(` ID: ${teepod.teepod_id}`);\n logger.info(` Name: ${teepod.name}`);\n logger.info(` Region: ${teepod.region_identifier}`);\n logger.info(` FMSPC: ${teepod.fmspc || 'N/A'}`);\n logger.info(` Device ID: ${teepod.device_id || 'N/A'}`);\n logger.info(` Support Onchain KMS: ${teepod.support_onchain_kms}`);\n logger.info(' Images:');\n if (teepod.images && teepod.images.length > 0) {\n teepod.images.forEach(img => {\n logger.info(` - ${img.name}`);\n logger.info(` Hash: ${img.os_image_hash || 'N/A'}`);\n });\n } else {\n logger.info(' N/A');\n }\n });\n\n if (kmsList && kmsList.length > 0) {\n logger.info('\\nAvailable KMS Instances:');\n kmsList.forEach((kms: KmsListItem) => {\n logger.info('----------------------------------------');\n logger.info(` ID: ${kms.id}`);\n logger.info(` URL: ${kms.url}`);\n logger.info(` Version: ${kms.version}`);\n logger.info(` Chain ID: ${kms.chain_id}`);\n logger.info(` Contract Address: ${kms.kms_contract_address}`);\n logger.info(` Gateway App ID: ${kms.gateway_app_id}`);\n });\n }\n } catch (error) {\n logger.error(`Failed to list available nodes: ${error instanceof Error ? error.message : String(error)}`);\n }\n });","import { Command } from 'commander';\nimport { replicateCvm, getCvmComposeConfig } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport { encryptEnvVars } from '@phala/dstack-sdk/encrypt-env-vars';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nexport const replicateCommand = new Command()\n .name('replicate')\n .description('Create a replica of an existing CVM')\n .argument('<cvm-id>', 'UUID of the CVM to replicate')\n .option('--teepod-id <teepodId>', 'TEEPod ID to use for the replica')\n .option('-e, --env-file <envFile>', 'Path to environment file')\n .action(async (cvmId, options) => {\n try {\n let encryptedEnv: string | undefined;\n cvmId = cvmId.replace(/-/g, '');\n\n // Handle environment variables if provided\n if (options.envFile) {\n const envPath = path.resolve(process.cwd(), options.envFile);\n if (!fs.existsSync(envPath)) {\n throw new Error(`Environment file not found: ${envPath}`);\n }\n\n // Read and parse the environment file\n const envContent = fs.readFileSync(envPath, 'utf-8');\n const envVars = envContent\n .split('\\n')\n .filter(line => line.trim() !== '' && !line.trim().startsWith('#'))\n .map(line => {\n const [key, ...value] = line.split('=');\n return {\n key: key.trim(),\n value: value.join('=').trim()\n };\n });\n\n // Get CVM compose config which includes the public key\n const cvmConfig = await getCvmComposeConfig(cvmId);\n\n // Encrypt the environment variables\n logger.info('Encrypting environment variables...');\n const encryptedVars = await encryptEnvVars(\n envVars,\n cvmConfig.env_pubkey\n );\n encryptedEnv = encryptedVars;\n }\n\n // Prepare the request body\n const requestBody: {\n teepod_id?: number;\n encrypted_env?: string;\n } = {};\n\n if (options.teepodId) {\n requestBody.teepod_id = parseInt(options.teepodId, 10);\n }\n if (encryptedEnv) {\n requestBody.encrypted_env = encryptedEnv;\n }\n\n // Call the API to create the replica\n const replica = await replicateCvm(cvmId, requestBody);\n\n logger.success(`Successfully created replica of CVM UUID: ${cvmId} with App ID: ${replica.app_id}`);\n\n const tableData = {\n 'CVM UUID': replica.vm_uuid.replace(/-/g, ''),\n 'App ID': replica.app_id,\n 'Name': replica.name,\n 'Status': replica.status,\n 'TEEPod': `${replica.teepod.name} (ID: ${replica.teepod_id})`,\n 'vCPUs': replica.vcpu,\n 'Memory': `${replica.memory} MB`,\n 'Disk Size': `${replica.disk_size} GB`,\n 'App URL': replica.app_url || `${process.env.CLOUD_URL || 'https://cloud.phala.network'}/dashboard/cvms/${replica.vm_uuid.replace(/-/g, '')}`\n };\n\n logger.keyValueTable(tableData, {\n borderStyle: 'rounded'\n });\n logger.success(`Your CVM replica is being created. You can check its status with:\\nphala cvms get ${replica.app_id}`);\n } catch (error) {\n logger.error('Failed to create CVM replica:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport { logger } from '@/src/utils/logger';\nimport { execSync } from 'node:child_process';\nimport * as os from 'node:os';\nimport { logo } from '../utils/banner';\n\n\n/**\n * Opens a URL in the default web browser based on the current operating system\n * @param url The URL to open\n */\nfunction openBrowser(url: string): void {\n const platform = os.platform();\n \n try {\n switch (platform) {\n case 'darwin': // macOS\n execSync(`open \"${url}\"`);\n break;\n case 'win32': // Windows\n execSync(`start \"\" \"${url}\"`);\n break;\n case 'linux': // Linux\n // Try different commands in order\n try {\n execSync(`xdg-open \"${url}\"`);\n } catch (error) {\n try {\n execSync(`gnome-open \"${url}\"`);\n } catch (error) {\n execSync(`kde-open \"${url}\"`);\n }\n }\n break;\n default:\n throw new Error(`Unsupported platform: ${platform}`);\n }\n logger.success(`Opened URL in your default browser: ${url}`);\n } catch (error) {\n logger.error(`Failed to open URL: ${error instanceof Error ? error.message : String(error)}`);\n logger.info(`Please manually open this URL in your browser: ${url}`);\n }\n}\n\n/**\n * Pauses execution for the specified number of milliseconds\n * @param {number} ms - Time to sleep in milliseconds\n * @returns {Promise} Promise that resolves after the specified time\n */\nfunction sleep(ms) {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport const joinCommand = new Command()\n .name('join')\n .alias('free')\n .description('Join Phala Cloud! Get an account and deploy a CVM for FREE')\n .action(async () => {\n try {\n const inviteUrl = 'https://cloud.phala.network/register?invite=beta';\n const spinner =logger.startSpinner('Brewing a fresh cup of TEE 🍵');\n await sleep(2000);\n spinner.stop(true);\n logger.break();\n logger.break();\n console.log(logo);\n logger.info('TEE is served! Opening Phala Cloud registration page...');\n await sleep(1000);\n logger.break()\n openBrowser(inviteUrl);\n } catch (error) {\n logger.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from \"commander\";\nimport { logger } from \"@/src/utils/logger\";\nimport { getApiKey } from \"@/src/utils/credentials\";\nimport { getUserInfo } from \"@/src/api/auth\";\nimport { createCvm, getPubkeyFromCvm } from \"@/src/api/cvms\";\nimport { DEFAULT_IMAGE, CLOUD_URL } from \"@/src/utils/constants\";\nimport { demoTemplates } from \"@/src/utils/demo\";\nimport {\n\tencryptEnvVars,\n\ttype EnvVar,\n} from \"@phala/dstack-sdk/encrypt-env-vars\";\nimport inquirer from \"inquirer\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport { parseEnv } from \"@/src/utils/secrets\";\n\nexport const demoCommands = new Command()\n .name(\"demo\")\n .description(\"Demo commands to launch a demo on Phala Cloud\")\n .action(async () => {\n try {\n // 1. Check if the user is logged in\n const apiKey = await getApiKey();\n if (!apiKey) {\n logger.error(\"You need to be logged in to use the demo command\");\n logger.info(\"Please login with: phala auth login\");\n process.exit(1);\n }\n\n // Verify user credentials\n try {\n const spinner = logger.startSpinner(\"Verifying your credentials\");\n const userInfo = await getUserInfo();\n spinner.stop(true);\n logger.success(`Logged in as ${userInfo.username}`);\n } catch (error) {\n logger.error(\"Authentication failed. Your API key may be invalid or expired.\");\n logger.info(\"Please set a new API key with: phala auth login\");\n process.exit(1);\n }\n\n // 2. Get list of available templates\n const templates = Object.values(demoTemplates);\n\n if (templates.length === 0) {\n logger.error(\"No template files found in the templates directory\");\n process.exit(1);\n }\n\n // 3. Prompt user to select a template\n const { selectedTemplate } = await inquirer.prompt([\n {\n type: \"list\",\n name: \"selectedTemplate\",\n message: \"Select a template to deploy:\",\n choices: templates.map(t => ({\n name: t.name,\n value: t\n }))\n }\n ]);\n\n // 4. Read the selected template\n const templateContent = selectedTemplate.compose;\n logger.success(`Selected template: ${selectedTemplate.name}`);\n\n // 5. Generate a random token for services that might need it\n const token = crypto.randomBytes(16).toString(\"hex\");\n const envVars = parseEnv([`TOKEN=${token}`], \"\");\n \n \n // 6. Ask for CVM name\n const { cvmName } = await inquirer.prompt([\n {\n type: \"input\",\n name: \"cvmName\",\n message: \"Enter a name for your CVM:\",\n default: `${selectedTemplate.name.replace(\" \", \"-\")}`,\n validate: (input) => {\n if (!input.trim()) {\n return \"CVM name is required\";\n }\n return true;\n }\n }\n ]);\n\n // 7. Deploy the CVM with the specified resources\n logger.info(\"Preparing to deploy your CVM...\");\n \n // Prepare VM configuration with specified resources\n const vmConfig = {\n teepod_id: 3,\n name: cvmName,\n image: DEFAULT_IMAGE,\n vcpu: 2,\n memory: 2048,\n disk_size: 20,\n compose_manifest: {\n docker_compose_file: templateContent,\n docker_config: {\n url: \"\",\n username: \"\",\n password: \"\",\n },\n features: [\"kms\", \"tproxy-net\"],\n kms_enabled: true,\n manifest_version: 2,\n name: cvmName,\n public_logs: true,\n public_sysinfo: true,\n tproxy_enabled: true,\n },\n listed: false,\n };\n\n // Get public key from CVM for the API call structure\n const spinner = logger.startSpinner(\"Preparing CVM configuration\");\n const pubkey = await getPubkeyFromCvm(vmConfig);\n spinner.stop(true);\n \n if (!pubkey) {\n logger.error(\"Failed to prepare CVM configuration\");\n process.exit(1);\n }\n\n const encrypted_env = await encryptEnvVars(\n\t\t\t\t\t\t\tenvVars,\n\t\t\t\t\t\t\tpubkey.app_env_encrypt_pubkey,\n\t\t\t\t\t\t);\n\n logger.debug(\"Public key:\", pubkey.app_env_encrypt_pubkey);\n logger.debug(\"Encrypted environment variables:\", encrypted_env);\n // Create the CVM\n const createSpinner = logger.startSpinner(\"Creating your demo CVM\");\n const response = await createCvm({\n ...vmConfig,\n encrypted_env,\n app_env_encrypt_pubkey: pubkey.app_env_encrypt_pubkey,\n app_id_salt: pubkey.app_id_salt,\n });\n createSpinner.stop(true);\n\n if (!response) {\n logger.error(\"Failed to create demo CVM\");\n process.exit(1);\n }\n\n logger.success(\"Demo CVM created successfully! 🎉\");\n logger.break();\n \n const tableData = {\n \"CVM ID\": response.id,\n \"Name\": response.name,\n \"Status\": response.status,\n \"App ID\": `app_${response.app_id}`,\n \"App URL\": response.app_url ? response.app_url : `${CLOUD_URL}/dashboard/cvms/app_${response.app_id}`,\n \"Template\": selectedTemplate.name,\n \"Resources\": \"2 vCPUs, 2GB RAM, 20GB Storage\",\n };\n \n if (selectedTemplate.name.includes(\"Jupyter Notebook\")) {\n tableData[\"Jupyter Token\"] = token;\n tableData[\"Access Instructions\"] = \"Access your Jupyter notebook using the token above. Go to 'Network' tab to see the public URL.\";\n }\n \n logger.keyValueTable(tableData, {\n borderStyle: \"rounded\"\n });\n\n logger.break();\n logger.success(`Your demo is being created. You can check its status with:\\nphala cvms get app_${response.app_id}`);\n\n } catch (error) {\n logger.error(`Failed to launch demo: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n","const jupyterCompose = `version: '3'\nservices:\n jupyter:\n image: quay.io/jupyter/base-notebook\n ports:\n - 8080:8888\n volumes:\n - /var/run/tappd.sock:/var/run/tappd.sock\n environment:\n - GRANT_SUDO=yes\n user: root\n command: \"start-notebook.sh --NotebookApp.token=\\${TOKEN}\"\n`;\n\nexport const httpbinCompose = `version: '3'\nservices:\n httpbin:\n image: kennethreitz/httpbin:latest\n ports:\n - \"80:80\"\n`;\n\n\nexport const demoTemplates = {\n jupyter: {\n compose: jupyterCompose,\n name: \"Jupyter Notebook\",\n },\n httpbin: {\n compose: httpbinCompose,\n name: \"HTTPBin\",\n },\n};\n","import { Command } from 'commander';\nimport { listNodes } from './list.js';\n\nexport const nodesCommand = new Command()\n .name('nodes')\n .description('List and manage TEE nodes')\n .action(listNodes)\n .addCommand(\n new Command('list')\n .description('List all available worker nodes')\n .alias('ls')\n .action(listNodes)\n );\n","import { getTeepods } from '@/src/api/teepods';\nimport { logger } from '@/src/utils/logger';\nimport { KmsListItem, TEEPod } from '@/src/api/types';\n\nexport async function listNodes() {\n try {\n const { nodes: teepods, kms_list: kmsList } = await getTeepods();\n\n if (teepods.length === 0) {\n logger.info('No available nodes found.');\n return;\n }\n\n logger.info('Available Nodes:');\n teepods.forEach((teepod: TEEPod) => {\n logger.info('----------------------------------------');\n logger.info(` ID: ${teepod.teepod_id}`);\n logger.info(` Name: ${teepod.name}`);\n logger.info(` Region: ${teepod.region_identifier}`);\n logger.info(` FMSPC: ${teepod.fmspc || 'N/A'}`);\n logger.info(` Device ID: ${teepod.device_id || 'N/A'}`);\n logger.info(` Support Onchain KMS: ${teepod.support_onchain_kms}`);\n \n logger.info(' Images:');\n if (teepod.images && teepod.images.length > 0) {\n teepod.images.forEach(img => {\n logger.info(` - ${img.name}`);\n logger.info(` Hash: ${img.os_image_hash || 'N/A'}`);\n });\n } else {\n logger.info(' N/A');\n }\n });\n\n if (kmsList && kmsList.length > 0) {\n logger.info('\\nAvailable KMS Instances:');\n kmsList.forEach((kms: KmsListItem) => {\n logger.info('----------------------------------------');\n logger.info(` ID: ${kms.id}`);\n logger.info(` URL: ${kms.url}`);\n logger.info(` Version: ${kms.version}`);\n logger.info(` Chain ID: ${kms.chain_id}`);\n logger.info(` Contract Address: ${kms.kms_contract_address}`);\n logger.info(` Gateway App ID: ${kms.gateway_app_id}`);\n });\n }\n } catch (error) {\n logger.error(`Failed to list available nodes: ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n}\n"],"mappings":"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","names":["Command","chalk","logoColor","logo","smallLogo","minimalLogo","Command","Command","prompts","loginCommand","Command","apiKey","checkUserInfo","prompts","value","saveApiKey","getUserInfo","removeApiKey","logger","CLOUD_URL","error","Command","logoutCommand","Command","removeApiKey","logger","error","Command","statusCommand","Command","options","apiKey","getApiKey","logger","spinner","userInfo","getUserInfo","tableData","error","authCommands","Command","loginCommand","logoutCommand","statusCommand","Command","Command","execa","fs","path","Handlebars","exec","spawn","promisify","os","inquirer","fs","path","validateFileExists","filePath","basePath","resolvedPath","path","fs","promptForFile","message","defaultValue","name","inquirer","input","detectFileInCurrentDir","possibleFiles","logMessage","file","logger","fs","path","os","execSync","spawn","net","SIMULATOR_CONFIG","isSimulatorInstalled","platform","extractedFolderPath","executablePath","error","logger","getPlatform","installSimulator","progressCallback","log","message","platformConfig","downloadUrl","execSync","runSimulator","options","executableName","runOptions","logDir","stdio","outputStream","simulatorProcess","spawn","timestamp","setSimulatorEndpointEnv","isSimulatorRunning","platform","getPlatform","platformConfig","SIMULATOR_CONFIG","socketPath","resolve","client","host","error","logger","stopSimulator","execSync","stopped","deleteSimulatorEndpointEnv","getSimulatorEndpoint","getPlatform","setSimulatorEndpointEnv","endpoint","simulatorEndpoint","envEndpoint","execSync","logger","error","deleteSimulatorEndpointEnv","execAsync","promisify","exec","LOGS_DIR","COMPOSE_FILES_DIR","MAX_CONSOLE_LINES","DockerService","image","username","registry","logsPath","path","fs","operation","timestamp","arch","os","command","args","resolve","reject","proc","spawn","logFile","logStream","consoleBuffer","processOutput","data","isError","lines","line","bufferedLine","code","err","dockerfile","tag","fullImageName","spinner","logger","validateFileExists","buildArgs","error","imageName","getDockerCredentials","password","execa","loginError","homeDir","dockerConfigPath","dockerConfig","envFile","templateType","template","DOCKER_COMPOSE_ELIZA_V2_TEMPLATE","DOCKER_COMPOSE_BASIC_TEMPLATE","validatedTemplate","ComposeTemplateSchema","composePath","envVars","commentIndex","key","value","trimmedKey","composeContent","Handlebars","env","composeFile","composeArgs","port","stdout","containerId","setSimulatorEndpointEnv","deleteSimulatorEndpointEnv","prompts","loginCommand","Command","options","username","password","registry","logger","response","value","dockerService","DockerService","saveDockerCredentials","error","Command","path","inquirer","fs","buildCommand","Command","options","credentials","getDockerCredentials","logger","response","inquirer","input","defaultPath","path","fs","promptForFile","dockerfilePath","DockerService","error","Command","inquirer","pushCommand","Command","options","credentials","getDockerCredentials","logger","imageName","localImages","DockerService","uniqueImageNames","img","selectedImage","error","Command","inquirer","fs","path","generateCommand","Command","options","credentials","getDockerCredentials","logger","imageName","localImages","DockerService","uniqueImageNames","img","selectedImage","inquirer","envFilePath","validateFileExists","defaultEnvPath","path","fs","useDefault","envPath","input","outputPath","confirmOverwrite","customPath","dockerService","composePath","outputDir","error","dockerCommands","Command","loginCommand","buildCommand","pushCommand","generateCommand","Command","Command","startCommand","Command","TEE_SIMULATOR","options","DockerService","logger","isSimulatorInstalled","installSimulator","isSimulatorRunning","simulatorProcess","runSimulator","error","Command","stopCommand","Command","options","DockerService","logger","stopSimulator","error","simulatorCommands","Command","startCommand","stopCommand","Command","Command","chalk","listCommand","Command","options","spinner","logger","cvms","getCvms","cvm","CLOUD_URL","error","Command","chalk","resolveCvmAppId","appId","selectedCvm","selectCvm","checkCvmExists","getCommand","Command","appId","options","resolvedAppId","resolveCvmAppId","spinner","logger","cvm","getCvmByAppId","chalk","CLOUD_URL","error","Command","startCommand","Command","appId","resolvedAppId","resolveCvmAppId","spinner","logger","response","startCvm","tableData","CLOUD_URL","error","Command","stopCommand","Command","appId","resolvedAppId","resolveCvmAppId","spinner","logger","response","stopCvm","tableData","CLOUD_URL","error","Command","restartCommand","Command","appId","resolvedAppId","resolveCvmAppId","spinner","logger","response","restartCvm","tableData","CLOUD_URL","error","Command","chalk","attestationCommand","Command","appId","options","resolvedAppId","checkCvmExists","logger","selectedCvm","selectCvm","spinner","attestationData","getCvmAttestation","summaryData","cert","index","certData","tcbBasicInfo","maxEntriesToShow","entries","entry","error","Command","encryptEnvVars","fs","path","inquirer","fs","parseEnv","envs","envFile","envVars","env","key","valueParts","value","envFileContent","line","delimiterIndex","inQuotes","quoteChar","i","valueInQuotes","valueQuoteChar","commentStartIndex","firstChar","lastChar","createCommand","Command","DEFAULT_VCPU","DEFAULT_MEMORY","DEFAULT_DISK_SIZE","options","name","inquirer","input","composeFileName","detectFileInCurrentDir","promptForFile","composePath","path","fs","logger","composeString","deleteSimulatorEndpointEnv","envs","parseEnv","error","shouldSkip","envVars","vcpu","memory","diskSize","teepodsSpinner","teepods","getTeepods","selectedTeepod","pod","selectedImage","image","DEFAULT_IMAGE","vmConfig","spinner","pubkey","getPubkeyFromCvm","encryptSpinner","encrypted_env","encryptEnvVars","createSpinner","response","createCvm","tableData","CLOUD_URL","Command","inquirer","deleteCommand","Command","appId","options","resolvedAppId","resolveCvmAppId","confirm","inquirer","logger","spinner","success","deleteCvm","error","Command","fs","encryptEnvVars","upgradeCommand","Command","appId","options","resolvedAppId","resolveCvmAppId","spinner","logger","currentCvm","getCvmByAppId","composeFileName","detectFileInCurrentDir","promptForFile","composeString","fs","error","deleteSimulatorEndpointEnv","encrypted_env","envs","parseEnv","encryptEnvVars","vm_config","upgradeSpinner","response","upgradeCvm","CLOUD_URL","Command","inquirer","chalk","resizeCommand","Command","appId","options","resolvedAppId","resolveCvmAppId","cvm","getCvmByAppId","vcpu","memory","diskSize","allowRestart","inquirer","input","num","confirmMessage","logger","chalk","confirm","spinner","resizeCvm","CLOUD_URL","error","Command","listNodesCommand","Command","teepods","kmsList","getTeepods","logger","teepod","img","kms","error","Command","encryptEnvVars","fs","path","replicateCommand","Command","cvmId","options","encryptedEnv","envPath","envVars","line","key","value","cvmConfig","getCvmComposeConfig","logger","requestBody","replica","replicateCvm","tableData","error","cvmsCommand","Command","attestationCommand","createCommand","deleteCommand","getCommand","listCommand","startCommand","stopCommand","resizeCommand","restartCommand","upgradeCommand","listNodesCommand","replicateCommand","Command","execSync","os","openBrowser","url","platform","execSync","logger","error","sleep","ms","resolve","joinCommand","Command","inviteUrl","spinner","logo","Command","jupyterCompose","httpbinCompose","demoTemplates","encryptEnvVars","inquirer","crypto","demoCommands","Command","getApiKey","logger","spinner","userInfo","getUserInfo","templates","demoTemplates","selectedTemplate","inquirer","t","templateContent","token","crypto","envVars","parseEnv","cvmName","input","vmConfig","DEFAULT_IMAGE","pubkey","getPubkeyFromCvm","encrypted_env","encryptEnvVars","createSpinner","response","createCvm","tableData","CLOUD_URL","error","Command","listNodes","teepods","kmsList","getTeepods","logger","teepod","img","kms","error","nodesCommand","Command","listNodes","main","Command","logo","authCommands","cvmsCommand","dockerCommands","simulatorCommands","demoCommands","joinCommand","nodesCommand","error","logger"]}
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils/banner.ts","../src/commands/auth/index.ts","../src/commands/auth/login.ts","../src/commands/auth/logout.ts","../src/commands/auth/status.ts","../src/commands/docker/index.ts","../src/commands/docker/login.ts","../src/utils/docker.ts","../src/utils/prompts.ts","../src/utils/simulator.ts","../src/commands/docker/build.ts","../src/commands/docker/push.ts","../src/commands/docker/generate.ts","../src/commands/simulator/index.ts","../src/commands/simulator/start.ts","../src/commands/simulator/stop.ts","../src/commands/cvms/index.ts","../src/commands/cvms/list.ts","../src/commands/cvms/get.ts","../src/utils/cvms.ts","../src/commands/cvms/start.ts","../src/commands/cvms/stop.ts","../src/commands/cvms/restart.ts","../src/commands/cvms/attestation.ts","../src/commands/cvms/create.ts","../src/utils/secrets.ts","../src/commands/cvms/delete.ts","../src/commands/cvms/upgrade.ts","../src/commands/cvms/resize.ts","../src/commands/cvms/list-node.ts","../src/commands/cvms/replicate.ts","../src/commands/join.ts","../src/commands/demo/index.ts","../src/utils/demo.ts","../src/commands/nodes/index.ts","../src/commands/nodes/list.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport { logo } from \"./utils/banner\";\nimport { authCommands } from \"./commands/auth\";\nimport { dockerCommands } from \"./commands/docker\";\nimport { simulatorCommands } from \"./commands/simulator\";\nimport { logger } from \"./utils/logger\";\nimport { cvmsCommand } from \"./commands/cvms\";\nimport { joinCommand } from \"./commands/join\";\nimport { demoCommands } from \"./commands/demo\";\nimport { nodesCommand } from \"./commands/nodes\";\n\nprocess.on(\"SIGINT\", () => process.exit(0));\nprocess.on(\"SIGTERM\", () => process.exit(0));\n\nasync function main() {\n const program = new Command()\n\t\t\t.name(\"phala\")\n\t\t\t.alias(\"pha\")\n\t\t\t.description(\n\t\t\t\t`${logo}\\nPhala Cloud CLI - Manage your Phala Cloud Deployments`,\n\t\t\t)\n\t\t\t.version(\"v1.0.15\")\n\t\t\t.addCommand(authCommands)\n\t\t\t.addCommand(cvmsCommand)\n\t\t\t.addCommand(dockerCommands)\n\t\t\t.addCommand(simulatorCommands)\n\t\t\t.addCommand(demoCommands)\n\t\t\t.addCommand(joinCommand)\n\t\t\t.addCommand(nodesCommand);\n\n\tprogram.parse(process.argv);\n}\n\nmain().catch((error) => {\n\tlogger.error(\"An error occurred:\", error);\n\tprocess.exit(1);\n});\n","import chalk from 'chalk';\nconst logoColor = chalk.hex('#cdfa50');\nexport const logo = logoColor(`\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣤⣤⣤⣀⡀⠀⢀⣀⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⡿⠛⠉⠁⠀⠈⠉⠛⠿⠛⠉⠉⠉⠉⠙⠷⣄⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣧⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣆⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⠞⠛⠉⠙⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠛⢶⣄⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣦⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⣷⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣿⣿⡿⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀⣀⣴⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⠿⠿⠿⠃⠀⢀⣾⣿⣿⣿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠛⠋⠁⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⡿⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⡤⠤⠤⠴⠒⠒⠒⠒⠒⢿⡿⠓⠒⠒⠢⠤⠤⠤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣯⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⣀⣨⣿⣦⣤⣀⡀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣾⣿⣿⣿⣿⣿⡏⠉⠛⣿⣆⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⣀⣀⣀⣀⡸⠿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⣸⡿⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣿⣿⣿⣿⣿⣿⣿⠀⢸⣿⣿⣿⣿⡇⠀⣿⣿⣿⣿⣿⣿⠃⢀⣠⣴⡿⠃⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣿⠿⢇⣀⣀⣀⣀⣸⣿⣿⣿⣿⣿⡿⠿⠿⠛⠛⠁⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⡠⠀⠀⠀⠀⠈⠻⢿⣿⣿⣿⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠠⣄⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⢸⣆⠀⠀⠀⠀⠀⠀⠀⠉⠛⠿⠿⣿⣿⣿⣿⣿⠿⠟⠋⠁⠀⠀⠀⠀⠀⠀⣀⣾⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠙⠻⢶⣦⣤⣄⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣤⣴⣶⠿⠛⠁⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠙⠛⠻⠿⠿⠿⠿⢿⣿⣿⣿⠿⠿⠿⠿⠟⠛⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n`);\n\nexport const smallLogo = logoColor(`\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣤⣤⣤⣀⡀⠀⢀⣀⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⡿⠛⠉⠁⠀⠈⠉⠛⠿⠛⠉⠉⠉⠉⠙⠷⣄⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣧⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣆⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⠞⠛⠉⠙⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠛⢶⣄⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣦⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⣷⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣿⣿⡿⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀⣀⣴⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⠿⠿⠿⠃⠀⢀⣾⣿⣿⣿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠛⠋⠁⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⡿⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⡤⠤⠤⠴⠒⠒⠒⠒⠒⢿⡿⠓⠒⠒⠢⠤⠤⠤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣯⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⣀⣨⣿⣦⣤⣀⡀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣾⣿⣿⣿⣿⣿⡏⠉⠛⣿⣆⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⣀⣀⣀⣀⡸⠿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⣸⡿⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣿⣿⣿⣿⣿⣿⣿⠀⢸⣿⣿⣿⣿⡇⠀⣿⣿⣿⣿⣿⣿⠃⢀⣠⣴⡿⠃⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣿⠿⢇⣀⣀⣀⣀⣸⣿⣿⣿⣿⣿⡿⠿⠿⠛⠛⠁⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⡠⠀⠀⠀⠀⠈⠻⢿⣿⣿⣿⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠠⣄⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⢸⣆⠀⠀⠀⠀⠀⠀⠀⠉⠛⠿⠿⣿⣿⣿⣿⣿⠿⠟⠋⠁⠀⠀⠀⠀⠀⠀⣀⣾⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠙⠻⢶⣦⣤⣄⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣤⣴⣶⠿⠛⠁⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠙⠛⠻⠿⠿⠿⠿⢿⣿⣿⣿⠿⠿⠿⠿⠟⠛⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n`);\n\nexport const minimalLogo = chalk.cyan('PHALA TEE CLOUD CLI');","import { Command } from 'commander';\nimport { loginCommand } from './login';\nimport { logoutCommand } from './logout';\nimport { statusCommand } from './status';\n\nexport const authCommands = new Command()\n .name('auth')\n .description('Authenticate with Phala Cloud')\n .addCommand(loginCommand)\n .addCommand(logoutCommand)\n .addCommand(statusCommand);\n","import { Command } from 'commander';\nimport { removeApiKey, saveApiKey } from '@/src/utils/credentials';\nimport { logger } from '@/src/utils/logger';\nimport prompts from 'prompts';\nimport { getUserInfo } from '@/src/api/auth';\nimport { CLOUD_URL } from '@/src/utils/constants';\n\nexport const loginCommand = new Command()\n .name('login')\n .description('Set the API key for authentication')\n .argument('[api-key]', 'Phala Cloud API key to set')\n .action(async (apiKey?: string) => {\n try {\n let checkUserInfo;\n // If no API key is provided, prompt for it\n if (!apiKey) {\n const response = await prompts({\n type: 'password',\n name: 'apiKey',\n message: 'Enter your API key:',\n validate: async (value) => {\n if (value.length === 0) {\n return 'API key cannot be empty';\n }\n try {\n await saveApiKey(value);\n checkUserInfo = await getUserInfo();\n if (!checkUserInfo.username) {\n await removeApiKey();\n return 'Invalid API key';\n }\n } catch (error) {\n return 'Invalid API key';\n }\n return true;\n }\n });\n \n apiKey = response.apiKey;\n } else {\n await saveApiKey(apiKey);\n // Validate the API key\n checkUserInfo = await getUserInfo();\n if (!checkUserInfo.username) {\n await removeApiKey();\n return 'Invalid API key';\n }\n }\n \n logger.success(`Welcome ${checkUserInfo.username}! API key validated and saved successfully`);\n logger.break();\n logger.info(`Open in Web UI at ${CLOUD_URL}/dashboard/`);\n } catch (error) {\n logger.error(`Failed to set API key: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { removeApiKey } from '@/src/utils/credentials';\nimport { logger } from '@/src/utils/logger';\n\nexport const logoutCommand = new Command()\n .name('logout')\n .description('Remove the stored API key')\n .action(async () => {\n try {\n await removeApiKey();\n logger.success('API key removed successfully');\n } catch (error) {\n logger.error(`Failed to remove API key: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { getApiKey } from '@/src/utils/credentials';\nimport { getUserInfo } from '@/src/api/auth';\nimport { logger } from '@/src/utils/logger';\n\nexport const statusCommand = new Command()\n .name('status')\n .description('Check authentication status')\n .option('-j, --json', 'Output in JSON format')\n .option('-d, --debug', 'Enable debug output')\n .action(async (options) => {\n try {\n // Enable debug mode if requested\n if (options.debug) {\n process.env.DEBUG = 'true';\n }\n \n const apiKey = await getApiKey();\n \n if (!apiKey) {\n logger.warn('Not authenticated. Please set an API key with \"phala auth login\"');\n return;\n }\n \n logger.debug(`Using API key: ${apiKey.substring(0, 5)}...`);\n const spinner = logger.startSpinner('Checking authentication status');\n \n try {\n const userInfo = await getUserInfo();\n spinner.stop(true);\n \n if (options.json) {\n console.log(JSON.stringify(userInfo, null, 2));\n return;\n }\n \n logger.break();\n logger.success(`Authenticated as ${userInfo.username}`);\n \n // Create a simple object\n const tableData = {\n 'Username': userInfo.username,\n 'Email': userInfo.email,\n 'Role': userInfo.role,\n 'Team': `${userInfo.team_name} (${userInfo.team_tier})`,\n 'Credits': `$${(userInfo.credits + userInfo.granted_credits).toFixed(2)}`\n };\n \n if (userInfo.trial_ended_at) {\n tableData['Trial Ended At'] = userInfo.trial_ended_at;\n }\n \n // Display the table\n logger.keyValueTable(tableData, {\n borderStyle: 'rounded'\n });\n } catch (error) {\n spinner.stop(false);\n logger.error('Authentication failed. Your API key may be invalid or expired.');\n logger.info('Please set a new API key with \"phala auth login\"');\n \n if (options.debug) {\n logger.debug(`Error details: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n } catch (error) {\n logger.error(`Failed to check authentication status: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { loginCommand } from './login';\nimport { buildCommand } from './build';\nimport { pushCommand } from './push';\nimport { generateCommand } from './generate';\n\nexport const dockerCommands = new Command()\n .name('docker')\n .description('Login to Docker Hub and manage Docker images')\n .addCommand(loginCommand)\n .addCommand(buildCommand)\n .addCommand(pushCommand)\n .addCommand(generateCommand);\n","import { Command } from 'commander';\nimport { DockerService } from '@/src/utils/docker';\nimport { saveDockerCredentials } from '@/src/utils/credentials';\nimport { logger } from '@/src/utils/logger';\nimport prompts from 'prompts';\n\nexport const loginCommand = new Command()\n .name('login')\n .description('Login to Docker Hub')\n .option('-u, --username <username>', 'Docker Hub username')\n .option('-p, --password <password>', 'Docker Hub password')\n .option('-r, --registry <registry>', 'Docker registry URL')\n .action(async (options) => {\n try {\n let username = options.username;\n let password = options.password;\n const registry = options.registry;\n \n // If no username is provided, prompt for it\n if (!username) {\n logger.info('First we need your Docker Hub username to check if you are already logged in.');\n\n const response = await prompts({\n type: 'text',\n name: 'username',\n message: 'Enter your Docker Hub username:',\n validate: value => value.length > 0 ? true : 'Username cannot be empty'\n });\n \n if (!response.username) {\n logger.error('Username is required');\n process.exit(1);\n }\n \n username = response.username;\n }\n\n // Check if Docker is already logged in\n const dockerService = new DockerService('', username, registry);\n const loggedIn = await dockerService.login(username);\n if (loggedIn) {\n logger.success(`${username} is logged in to Docker Hub`);\n // Save credentials\n await saveDockerCredentials({\n username,\n registry: registry || null,\n });\n return;\n }\n \n // If no password is provided, prompt for it\n if (!password) {\n const response = await prompts({\n type: 'password',\n name: 'password',\n message: 'Enter your Docker Hub password:',\n validate: value => value.length > 0 ? true : 'Password cannot be empty'\n });\n \n if (!response.password) {\n logger.error('Password is required');\n process.exit(1);\n }\n \n password = response.password;\n }\n \n // Login to Docker Hub\n const success = await dockerService.login(username, password, registry);\n \n if (!success) {\n logger.error('Failed to login to Docker Hub');\n process.exit(1);\n }\n \n // Save credentials\n await saveDockerCredentials({\n username,\n registry: registry || null\n });\n \n logger.success('Logged in to Docker Hub successfully');\n } catch (error) {\n logger.error(`Failed to login to Docker Hub: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { execa } from 'execa';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { logger } from './logger';\nimport { DOCKER_COMPOSE_BASIC_TEMPLATE, DOCKER_COMPOSE_ELIZA_V2_TEMPLATE } from './constants';\nimport { getDockerCredentials } from './credentials';\nimport Handlebars from 'handlebars';\nimport { exec, spawn } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport os from 'node:os';\nimport { validateFileExists } from './prompts';\nimport { ComposeTemplateSchema } from './types';\nimport { deleteSimulatorEndpointEnv, setSimulatorEndpointEnv } from './simulator';\nconst execAsync = promisify(exec);\n\nconst LOGS_DIR = '.phala-cloud/logs';\nconst COMPOSE_FILES_DIR = '.phala-cloud/compose';\nconst MAX_CONSOLE_LINES = 10;\n\nexport class DockerService {\n private username: string;\n private image: string;\n private registry: string;\n\n constructor(image: string, username?: string, registry?: string) {\n this.image = image;\n this.username = username || '';\n this.registry = registry || '';\n }\n\n private ensureLogsDir(): void {\n const logsPath = path.resolve(LOGS_DIR);\n if (!fs.existsSync(logsPath)) {\n fs.mkdirSync(logsPath, { recursive: true });\n }\n }\n\n private getLogFilePath(operation: string, image?: string): string {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n return path.resolve(LOGS_DIR, `${image || this.image}-${operation}-${timestamp}.log`);\n }\n\n private getSystemArchitecture(): string {\n const arch = os.arch();\n switch (arch) {\n case 'arm':\n case 'arm64':\n return 'arm64';\n case 'x64':\n return 'amd64';\n default:\n return arch;\n }\n }\n\n private spawnProcess(command: string, args: string[], operation: string, image?: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const proc = spawn(command, args);\n // Ensure logs directory exists before creating write stream\n this.ensureLogsDir();\n\n const logFile = this.getLogFilePath(operation, image);\n\n const logStream = fs.createWriteStream(logFile, { flags: 'a' });\n const consoleBuffer: string[] = [];\n\n const processOutput = (data: Buffer, isError = false) => {\n const lines = data.toString().split('\\n');\n\n // Write to log file\n logStream.write(data);\n\n // Update console buffer\n for (const line of lines) {\n if (line.trim()) {\n consoleBuffer.push(line);\n // Keep only the last MAX_CONSOLE_LINES lines\n if (consoleBuffer.length > MAX_CONSOLE_LINES) {\n consoleBuffer.shift();\n }\n\n // Clear console and print the buffer\n console.clear();\n console.log(`Latest ${MAX_CONSOLE_LINES} lines (full log at ${logFile}):`);\n console.log('-'.repeat(50));\n for (const bufferedLine of consoleBuffer) {\n if (isError) {\n console.error(bufferedLine);\n } else {\n console.log(bufferedLine);\n }\n }\n }\n }\n };\n\n proc.stdout.on('data', (data) => processOutput(data));\n proc.stderr.on('data', (data) => processOutput(data, true));\n\n proc.on('close', (code) => {\n logStream.end();\n if (code === 0) {\n console.log(`\\nOperation completed. Full log available at: ${logFile}`);\n resolve();\n } else {\n reject(new Error(`Process exited with code ${code}. Check log file: ${logFile}`));\n }\n });\n\n proc.on('error', (err) => {\n logStream.end();\n reject(err);\n });\n });\n }\n\n /**\n * Set Docker credentials\n * @param username Docker username\n * @param registry Docker registry\n */\n setCredentials(username: string, registry?: string): void {\n this.username = username;\n if (registry) {\n this.registry = registry;\n }\n }\n\n /**\n * Build a Docker image\n * @param dockerfile Path to Dockerfile\n * @param tag Tag for the image\n * @returns Success status\n */\n async buildImage(dockerfile: string, tag: string): Promise<boolean> {\n try {\n const arch = this.getSystemArchitecture();\n const fullImageName = `${this.username}/${this.image}:${tag}`;\n\n const spinner = logger.startSpinner(`Building Docker image ${this.username}/${this.image}:${tag}`);\n\n // Ensure the Dockerfile exists\n validateFileExists(dockerfile);\n\n const buildArgs = ['build', '-t', fullImageName, '-f', dockerfile];\n\n if (arch === 'arm64') {\n console.log('Detected arm64 architecture, using --platform linux/amd64');\n buildArgs.push('--platform', 'linux/amd64');\n }\n\n // Build the image\n buildArgs.push('.');\n\n await this.spawnProcess('docker', buildArgs, 'build', this.image);\n\n spinner.stop(true, `Docker image ${fullImageName} built successfully`);\n return true;\n } catch (error) {\n logger.error(`Failed to build Docker image: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n /**\n * Push a Docker image to Docker Hub\n * @param imageName Full image name (e.g. username/image:tag)\n * @returns Success status\n */\n async pushImage(imageName: string): Promise<boolean> {\n try {\n const spinner = logger.startSpinner(`Pushing Docker image ${imageName} to Docker Hub`);\n\n // Check if user is logged in\n const credentials = await getDockerCredentials();\n if (!credentials) {\n spinner.stop(false);\n throw new Error('Docker credentials not found. Please log in first with \"phala docker login\"');\n }\n\n const fullImageName = imageName;\n console.log(`Pushing image ${fullImageName} to Docker Hub...`);\n\n await this.spawnProcess('docker', ['push', fullImageName], 'push', imageName.replace(/.*\\/+([\\w-]+):.*$/g, '$1'));\n\n spinner.stop(true, `Docker image ${fullImageName} pushed successfully`);\n return true;\n } catch (error) {\n logger.error(`Failed to push Docker image: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n\n /**\n * Login to Docker Hub\n * @param username Docker username\n * @param password Docker password\n * @param registry Docker registry\n * @returns Success status\n */\n async login(username: string, password?: string, registry?: string): Promise<boolean> {\n try {\n const spinner = logger.startSpinner(`Logging in to Docker Hub as ${username}`);\n\n // Check if already logged in\n const loggedIn = await this.checkLogin();\n if (loggedIn) {\n spinner.stop(true, 'Already logged in to Docker Hub');\n this.setCredentials(username, registry);\n return true;\n }\n\n // Verify password was provided\n if (!password) {\n spinner.stop(false);\n throw new Error('Password is required for Docker login');\n }\n\n // Login to Docker with timeout protection\n try {\n const loginProcess = execa('docker', [\n 'login',\n ...(registry ? [registry] : []),\n '-u',\n username,\n '--password-stdin'\n ], {\n input: password,\n timeout: 10000 // 10 second timeout\n });\n\n await loginProcess;\n } catch (loginError) {\n if (loginError.timedOut) {\n spinner.stop(false);\n throw new Error('Docker login timed out. Please check your credentials and try again.');\n }\n throw loginError;\n }\n\n spinner.stop(true, 'Logged in to Docker Hub successfully');\n this.setCredentials(username, registry);\n return true;\n } catch (error) {\n logger.error(`Failed to login to Docker Hub: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n /**\n * Check if Docker is logged in\n * @returns Success status\n */\n async checkLogin(): Promise<boolean> {\n try {\n // Instead of checking via \"docker login\" which is interactive,\n // check if the Docker config.json file exists and contains auth data\n const homeDir = os.homedir();\n const dockerConfigPath = path.join(homeDir, '.docker', 'config.json');\n \n if (!fs.existsSync(dockerConfigPath)) {\n return false;\n }\n \n // Read the docker config file\n const dockerConfig = JSON.parse(fs.readFileSync(dockerConfigPath, 'utf-8'));\n \n // Check if the config has auths data\n return !!(dockerConfig?.auths && Object.keys(dockerConfig.auths).length > 0);\n } catch (error) {\n logger.debug(`Docker login check failed: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n /**\n * Build a Docker Compose file\n * @param imageName Name of the image\n * @param envFile Optional path to environment file\n * @param version Version of the template to use\n * @returns Path to the generated Docker Compose file\n */\n async buildComposeFile(imageName: string, envFile?: string, templateType?: string): Promise<string> {\n if (!this.username) {\n throw new Error('Docker Hub username is required for building compose file');\n }\n\n const template = (templateType === 'eliza') ? DOCKER_COMPOSE_ELIZA_V2_TEMPLATE : DOCKER_COMPOSE_BASIC_TEMPLATE;\n\n // Validate template structure\n const validatedTemplate = ComposeTemplateSchema.parse({ template });\n\n // Ensure compose files directory exists\n const composePath = path.resolve(COMPOSE_FILES_DIR);\n \n // Create directory if it doesn't exist\n if (!fs.existsSync(composePath)) {\n logger.info(`Creating directory: ${composePath}`);\n fs.mkdirSync(composePath, { recursive: true });\n }\n\n let envVars: string[] = [];\n \n // Only parse env file if it's provided\n if (envFile) {\n // Parse env file to get variable names\n const envContent = fs.readFileSync(envFile, 'utf-8');\n envVars = envContent\n .split('\\n')\n .filter(line => line && !line.startsWith('#'))\n .map(line => {\n // Remove inline comments\n const commentIndex = line.indexOf('#');\n if (commentIndex > 0) {\n line = line.substring(0, commentIndex).trim();\n }\n return line.trim();\n })\n .filter(line => line.includes('='))\n .map(line => {\n const [key, value] = line.split('=', 2);\n const trimmedKey = key.trim();\n const trimmedValue = value ? value.trim() : '';\n\n // Skip empty values\n if (trimmedValue === '') {\n return null;\n }\n\n // Keep the original key without any transformation\n return `${trimmedKey}=${trimmedKey}`; // Create KEY=KEY format\n })\n .filter(Boolean as unknown as ((value: string | null) => value is string)); // Remove null entries\n }\n\n // Create full image name with username\n const fullImageName = imageName;\n\n // Compile template with data\n const compiledTemplate = Handlebars.compile(validatedTemplate.template, { noEscape: true });\n const composeContent = compiledTemplate({\n imageName: fullImageName,\n envVars: envVars.map(env => env.replace(/=.*/, `=\\${${env.split('=')[0]}}`))\n });\n\n // Write the docker-compose file with standardized name in the compose directory\n const composeFile = path.join(\n composePath,\n `${imageName.replace(/.*\\/+([\\w-]+):.*$/g, \"$1\")}-tee-compose.yaml`,\n );\n fs.writeFileSync(composeFile, composeContent);\n\n logger.success(`Backup of docker compose file created at: ${composeFile}`);\n return composeFile;\n }\n\n /**\n * Run a Docker Compose file locally\n * @param composePath Path to Docker Compose file\n * @param envFile Path to environment file\n * @returns Success status\n */\n async runComposeLocally(composePath: string, envFile?: string): Promise<boolean> {\n try {\n // TODO: Update log when optimized simulator is implemented\n const spinner = logger.startSpinner(`Running Docker Compose file at ${composePath}`);\n\n // Ensure the Docker Compose file exists\n validateFileExists(composePath);\n\n // Build the command arguments\n const composeArgs = [\n '-f',\n composePath,\n 'up',\n '-d'\n ];\n\n // Only add env-file if it's provided\n if (envFile) {\n // Ensure the environment file exists\n validateFileExists(envFile);\n composeArgs.splice(2, 0, '--env-file', envFile);\n }\n\n // Run the Docker Compose file\n await execAsync(`docker compose ${composeArgs.join(' ')}`);\n\n spinner.stop(true, 'Docker Compose file running successfully');\n return true;\n } catch (error) {\n logger.error(`Failed to run Docker Compose file: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n /**\n * Run the TEE simulator\n * @param image Simulator image\n * @returns Success status\n */\n async runSimulator(image: string, port: string): Promise<boolean> {\n try {\n logger.info(`Running TEE simulator with image ${image}`);\n\n logger.info('Pulling latest simulator image...');\n await execAsync(`docker pull ${image}`);\n\n logger.info('Starting simulator in background...');\n const { stdout } = await execAsync(`docker run -d --name tee-simulator --rm -p ${port}:${port} ${image}`);\n const containerId = stdout.trim();\n\n logger.success(`TEE simulator running successfully. Container ID: ${containerId}`);\n logger.break();\n logger.break();\n logger.info('Useful commands:');\n logger.info(`- View logs: docker logs -f ${containerId}`);\n logger.info(`- Stop simulator: docker stop ${containerId}`);\n\n setSimulatorEndpointEnv(`http://localhost:${port}`);\n \n return true;\n } catch (error) {\n logger.error(`Failed to run TEE simulator: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n /**\n * Stop the TEE simulator\n * @returns Success status\n */\n async stopSimulator(): Promise<boolean> {\n try {\n const spinner = logger.startSpinner('Stopping TEE simulator...');\n\n // Stop the simulator\n await execAsync('docker stop tee-simulator');\n await deleteSimulatorEndpointEnv();\n\n spinner.stop(true, 'TEE simulator stopped successfully');\n return true;\n } catch (error) {\n logger.error(`Failed to stop TEE simulator: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n /**\n * List local Docker images and their tags\n * @returns Array of objects with image name and tag\n */\n static async listLocalImages(): Promise<Array<{ imageName: string}>> {\n try {\n // Query Docker for local images in format that outputs repository and tag\n const { stdout } = await execAsync('docker images --format \"{{.Repository}}:{{.Tag}}\"');\n const credentials = await getDockerCredentials();\n const username = credentials?.username;\n // Parse the output and filter out any <none> tags or images\n const imageList = stdout.split('\\n')\n .filter(line => line && !line.includes('<none>'))\n .filter(line => line.includes(`${username}/`))\n .map(line => {\n const imageName = line;\n return { imageName };\n });\n\n return imageList;\n } catch (error) {\n logger.error(`Failed to list local Docker images: ${error instanceof Error ? error.message : String(error)}`);\n return [];\n }\n }\n}\n\n","import inquirer from 'inquirer';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { logger } from './logger';\n\n/**\n * Validates that a file exists at the given path\n * @param filePath Path to the file to validate\n * @param basePath Optional base path to resolve relative paths against (defaults to process.cwd())\n * @returns True if the file exists, throws an error if not\n * @throws Error if the file does not exist\n */\nexport function validateFileExists(\n filePath: string,\n basePath: string = process.cwd()\n): boolean {\n const resolvedPath = path.resolve(basePath, filePath);\n if (!fs.existsSync(resolvedPath)) {\n throw new Error(`File not found at ${resolvedPath}`);\n }\n return true;\n}\n\n/**\n * Prompts the user for a file path and validates that the file exists\n * @param message The prompt message to display\n * @param defaultValue The default value for the prompt\n * @param name The name of the prompt (used as property name in the returned object)\n * @param basePath Optional base path to resolve relative paths against (defaults to process.cwd())\n * @returns The validated file path\n */\nexport async function promptForFile(\n message: string,\n defaultValue: string,\n name = 'file',\n basePath: string = process.cwd()\n): Promise<string> {\n const response = await inquirer.prompt([\n {\n type: 'input',\n name,\n message,\n default: defaultValue,\n validate: (input) => {\n const filePath = path.resolve(basePath, input);\n if (!fs.existsSync(filePath)) {\n return `File not found at ${filePath}`;\n }\n return true;\n }\n }\n ]);\n\n return response[name];\n}\n\nexport function detectFileInCurrentDir(\n possibleFiles: string[],\n logMessage?: string\n): string | undefined {\n for (const file of possibleFiles) {\n const filePath = path.join(process.cwd(), file);\n if (fs.existsSync(filePath)) {\n if (logMessage) {\n logger.info(logMessage.replace('{path}', filePath));\n } else {\n logger.info(`File detected: ${filePath}`);\n }\n return file;\n }\n }\n return undefined;\n}","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { execSync, spawn, type StdioOptions } from 'node:child_process';\nimport * as net from 'node:net';\nimport { logger } from './logger';\n\n// Configuration for simulator\nconst SIMULATOR_CONFIG = {\n version: '0.1.4',\n baseUrl: 'https://github.com/Leechael/tappd-simulator/releases/download/v0.1.4',\n installDir: path.join(os.homedir(), '.phala-cloud', 'tappd-simulator'),\n // Default log file path\n defaultLogPath: path.join(os.homedir(), '.phala-cloud', 'logs', 'tappd-simulator.log'),\n platforms: {\n darwin: {\n filename: 'tappd-simulator-0.1.4-aarch64-apple-darwin.tgz',\n extractedFolder: 'tappd-simulator-0.1.4-aarch64-apple-darwin',\n socketArg: 'unix:/tmp/tappd.sock'\n },\n linux: {\n filename: 'tappd-simulator-0.1.4-x86_64-linux-musl.tgz',\n extractedFolder: 'tappd-simulator-0.1.4-x86_64-linux-musl',\n socketArg: 'unix:/tmp/tappd.sock'\n },\n win32: {\n filename: 'tappd-simulator-0.1.4-x86_64-pc-windows-msvc.tgz',\n extractedFolder: 'tappd-simulator-0.1.4-x86_64-pc-windows-msvc',\n socketArg: '127.0.0.1:8090'\n }\n }\n};\n\n/**\n * Check if the simulator is already installed\n * @returns boolean indicating if simulator is installed\n */\nexport function isSimulatorInstalled(): boolean {\n try {\n // Check if the main installation directory exists\n if (!fs.existsSync(SIMULATOR_CONFIG.installDir)) {\n return false;\n }\n\n // Get platform-specific folder name\n const platform = os.platform() as 'darwin' | 'linux' | 'win32';\n if (!SIMULATOR_CONFIG.platforms[platform]) {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n\n const extractedFolderPath = path.join(\n SIMULATOR_CONFIG.installDir,\n SIMULATOR_CONFIG.platforms[platform].extractedFolder\n );\n\n // Check if the extracted folder exists\n if (!fs.existsSync(extractedFolderPath)) {\n return false;\n }\n\n // Check if the executable exists\n const executableName = platform === 'win32' ? 'tappd-simulator.exe' : 'tappd-simulator';\n const executablePath = path.join(extractedFolderPath, executableName);\n return fs.existsSync(executablePath);\n } catch (error) {\n logger.error('Error checking if simulator is installed:', error);\n return false;\n }\n}\n\n/**\n * Get the current platform\n * @returns The current platform: 'darwin', 'linux', or 'win32'\n * @throws Error if the platform is not supported\n */\nexport function getPlatform(): 'darwin' | 'linux' | 'win32' {\n const platform = os.platform() as 'darwin' | 'linux' | 'win32';\n if (!SIMULATOR_CONFIG.platforms[platform]) {\n throw new Error(`Unsupported platform: ${platform}. Only darwin, linux, and win32 are supported.`);\n }\n return platform;\n}\n\n/**\n * Install the simulator based on the current platform\n * @param progressCallback Optional callback to report progress\n * @returns Promise that resolves when installation is complete\n */\nexport async function installSimulator(\n progressCallback?: (message: string) => void\n): Promise<void> {\n const log = (message: string) => {\n logger.info(message);\n if (progressCallback) progressCallback(message);\n };\n\n try {\n const platform = getPlatform();\n const platformConfig = SIMULATOR_CONFIG.platforms[platform];\n \n // Create installation directory if it doesn't exist\n if (!fs.existsSync(SIMULATOR_CONFIG.installDir)) {\n logger.info(`Creating installation directory at ${SIMULATOR_CONFIG.installDir}`);\n fs.mkdirSync(SIMULATOR_CONFIG.installDir, { recursive: true });\n }\n\n // Change to the installation directory\n process.chdir(SIMULATOR_CONFIG.installDir);\n \n // Download the simulator\n const downloadUrl = `${SIMULATOR_CONFIG.baseUrl}/${platformConfig.filename}`;\n logger.info(`Downloading simulator from ${downloadUrl}`);\n execSync(`wget ${downloadUrl}`, { stdio: 'inherit' });\n \n // Extract the archive\n logger.info(`Extracting ${platformConfig.filename}`);\n execSync(`tar -xvf ${platformConfig.filename}`, { stdio: 'inherit' });\n \n logger.success('Simulator installation completed successfully');\n } catch (error) {\n logger.error('Error installing simulator:', error);\n throw new Error(`Failed to install simulator: ${error}`);\n }\n}\n\n/**\n * Run the simulator\n * @param options Configuration options for running the simulator\n * @returns A child process representing the running simulator\n */\nexport async function runSimulator(options: {\n background?: boolean;\n logToFile?: boolean;\n logFilePath?: string;\n} = {}): Promise<ReturnType<typeof spawn>> {\n try {\n const platform = getPlatform();\n const platformConfig = SIMULATOR_CONFIG.platforms[platform];\n const extractedFolderPath = path.join(\n SIMULATOR_CONFIG.installDir,\n platformConfig.extractedFolder\n );\n \n // Change to the extracted folder directory\n process.chdir(extractedFolderPath);\n \n // Start the simulator\n const executableName = platform === 'win32' ? 'tappd-simulator.exe' : './tappd-simulator';\n \n // Default options\n const runOptions = {\n background: options.background ?? true,\n logToFile: options.logToFile ?? true,\n logFilePath: options.logFilePath ?? SIMULATOR_CONFIG.defaultLogPath\n };\n \n // Create log directory if it doesn't exist\n if (runOptions.logToFile) {\n const logDir = path.dirname(runOptions.logFilePath);\n if (!fs.existsSync(logDir)) {\n fs.mkdirSync(logDir, { recursive: true });\n }\n logger.info(`Simulator logs will be written to: ${runOptions.logFilePath}`);\n }\n \n logger.info(`Starting simulator with: ${executableName} -l ${platformConfig.socketArg}`);\n \n // Configure stdio based on logging preferences\n let stdio: StdioOptions = 'inherit';\n let outputStream: fs.WriteStream = null;\n \n if (runOptions.logToFile) {\n // Create/open the log file for appending\n outputStream = fs.createWriteStream(runOptions.logFilePath, { flags: 'a' });\n \n // Use the stream for both stdout and stderr\n stdio = ['ignore', outputStream, outputStream];\n }\n \n // Run the simulator\n const simulatorProcess = spawn(executableName, ['-l', platformConfig.socketArg], {\n stdio,\n shell: platform === 'win32', // Use shell on Windows\n detached: runOptions.background // Detach process when running in background\n });\n \n // Write startup entry to log file with timestamp\n if (outputStream) {\n const timestamp = new Date().toISOString();\n outputStream.write(`\\n[${timestamp}] Simulator started\\n`);\n }\n \n // If running in background, unref to allow the parent process to exit\n if (runOptions.background) {\n simulatorProcess.unref();\n logger.success('Simulator is running in the background');\n }\n \n await setSimulatorEndpointEnv();\n return simulatorProcess;\n } catch (error) {\n logger.error('Error running simulator:', error);\n throw new Error(`Failed to run simulator: ${error}`);\n }\n}\n\n/**\n * Ensures the simulator is installed and running\n * @param options Configuration options for running the simulator\n * @returns A promise that resolves to a child process representing the running simulator\n */\nexport async function ensureSimulatorRunning(options: {\n background?: boolean;\n logToFile?: boolean;\n logFilePath?: string;\n} = {}): Promise<ReturnType<typeof spawn>> {\n if (!isSimulatorInstalled()) {\n logger.info('Simulator not installed. Installing now...');\n await installSimulator((message) => logger.info(`Installation progress: ${message}`));\n }\n \n if (await isSimulatorRunning()) {\n logger.info('Simulator is already running');\n return null;\n }\n \n logger.info('Starting simulator...');\n return await runSimulator(options);\n}\n\n/**\n * Check if the simulator is currently running\n * For Unix platforms (Darwin/Linux), checks if the Unix socket exists and is accessible\n * For Windows, tries to connect to the TCP port the simulator should be listening on\n * @returns Promise<boolean> indicating if the simulator is running\n */\nexport async function isSimulatorRunning(): Promise<boolean> {\n try {\n const platform = getPlatform();\n const platformConfig = SIMULATOR_CONFIG.platforms[platform];\n \n if (platform === 'darwin' || platform === 'linux') {\n // For Unix platforms, check if the socket file exists and is accessible\n const socketPath = '/tmp/tappd.sock';\n \n // Check if the socket file exists\n if (!fs.existsSync(socketPath)) {\n return false;\n }\n \n // Try to connect to the socket to verify it's active\n return new Promise<boolean>((resolve) => {\n const client = net.createConnection({ path: socketPath })\n .on('connect', () => {\n client.end();\n resolve(true);\n })\n .on('error', () => {\n resolve(false);\n });\n \n // Set timeout to avoid hanging if socket exists but nothing is listening\n setTimeout(() => {\n client.end();\n resolve(false);\n }, 1000);\n });\n } \n if (platform === 'win32') {\n // For Windows, try to connect to the TCP port\n const host = '127.0.0.1';\n const port = 8090;\n \n return new Promise<boolean>((resolve) => {\n const client = net.createConnection({ host, port })\n .on('connect', () => {\n client.end();\n resolve(true);\n })\n .on('error', () => {\n resolve(false);\n });\n \n // Set timeout to avoid hanging\n setTimeout(() => {\n client.end();\n resolve(false);\n }, 1000);\n });\n }\n \n return false;\n } catch (error) {\n logger.error('Error checking if simulator is running:', error);\n return false;\n }\n}\n\n/**\n * Stops the simulator if it's running\n * @returns Promise<boolean> indicating if the simulator was successfully stopped\n */\nexport async function stopSimulator(): Promise<boolean> {\n try {\n const platform = getPlatform();\n \n if (!await isSimulatorRunning()) {\n logger.info('Simulator is not running');\n return true;\n }\n \n logger.info('Stopping simulator...');\n \n if (platform === 'win32') {\n // For Windows, find the process listening on port 8080 and kill it\n execSync('for /f \"tokens=5\" %a in (\\'netstat -ano ^| findstr :8080\\') do taskkill /F /PID %a', { stdio: 'inherit' });\n } else {\n // For Unix platforms, find and kill the tappd-simulator process\n execSync('pkill -f tappd-simulator', { stdio: 'inherit' });\n }\n \n // Verify the simulator has stopped\n const stopped = !(await isSimulatorRunning());\n if (stopped) {\n logger.success('Simulator stopped successfully');\n } else {\n logger.error('Failed to stop simulator');\n }\n \n await deleteSimulatorEndpointEnv();\n return stopped;\n } catch (error) {\n logger.error('Error stopping simulator:', error);\n return false;\n }\n}\n\n/**\n * Gets the path to the simulator log file\n * @param customPath Optional custom log file path\n * @returns The path to the log file\n */\nexport function getSimulatorLogPath(customPath?: string): string {\n return customPath ?? SIMULATOR_CONFIG.defaultLogPath;\n}\n\n/**\n * Reads the recent logs from the simulator log file\n * @param options Options for reading logs\n * @returns Recent log content or null if log file doesn't exist\n */\nexport function getSimulatorLogs(options: {\n logFilePath?: string;\n maxLines?: number;\n} = {}): string | null {\n const logFilePath = options.logFilePath ?? SIMULATOR_CONFIG.defaultLogPath;\n const maxLines = options.maxLines ?? 100;\n \n try {\n if (!fs.existsSync(logFilePath)) {\n return null;\n }\n \n // Read the log file\n const logContent = fs.readFileSync(logFilePath, 'utf8');\n \n // Split by lines and get the most recent ones\n const lines = logContent.split('\\n');\n return lines.slice(-maxLines).join('\\n');\n } catch (error) {\n logger.error('Error reading simulator logs:', error);\n return null;\n }\n}\n\n/**\n * Gets the simulator endpoint URL based on the current platform\n * @returns The endpoint URL for the simulator\n */\nexport function getSimulatorEndpoint(): string {\n const platform = getPlatform();\n \n if (platform === 'win32') {\n return 'http://127.0.0.1:8090';\n }\n\n return 'unix:///tmp/tappd.sock';\n}\n\n/**\n * Sets the DSTACK_SIMULATOR_ENDPOINT environment variable based on the current platform\n * @param options Configuration options for setting the environment variable\n * @returns The endpoint URL that was set\n */\nexport async function setSimulatorEndpointEnv(endpoint?: string): Promise<string> {\n try {\n const simulatorEndpoint = getSimulatorEndpoint();\n // Set for the current Node.js process\n const envEndpoint = (endpoint) ? endpoint : simulatorEndpoint;\n await execSync(`export DSTACK_SIMULATOR_ENDPOINT=${envEndpoint}`);\n logger.success(`Setting DSTACK_SIMULATOR_ENDPOINT=${envEndpoint} for current process`);\n \n return endpoint;\n } catch (error) {\n logger.error('Error setting simulator endpoint environment variable:', error);\n throw new Error(`Failed to set simulator endpoint: ${error}`);\n }\n}\n\n/**\n * Deletes the DSTACK_SIMULATOR_ENDPOINT environment variable\n * @returns boolean indicating if deletion was successful\n */\nexport async function deleteSimulatorEndpointEnv(): Promise<boolean> {\n await execSync('unset DSTACK_SIMULATOR_ENDPOINT');\n logger.debug('Deleted DSTACK_SIMULATOR_ENDPOINT from current process');\n return true;\n}\n","import { Command } from 'commander';\nimport { DockerService } from '@/src/utils/docker';\nimport { getDockerCredentials } from '@/src/utils/credentials';\nimport { logger } from '@/src/utils/logger';\nimport path from 'node:path';\nimport inquirer from 'inquirer';\nimport fs from 'node:fs';\nimport { promptForFile } from '@/src/utils/prompts';\n\nexport const buildCommand = new Command()\n .name('build')\n .description('Build a Docker image')\n .option('-i, --image <image>', 'Image name')\n .option('-t, --tag <tag>', 'Image tag')\n .option('-f, --file <file>', 'Path to Dockerfile', 'Dockerfile')\n .action(async (options) => {\n try {\n // Get Docker credentials\n const credentials = await getDockerCredentials();\n \n if (!credentials) {\n logger.error('Docker information not found. Please login first with \"phala docker login\"');\n process.exit(1);\n }\n \n // Prompt for image name if not provided\n if (!options.image) {\n const response = await inquirer.prompt([\n {\n type: 'input',\n name: 'image',\n message: 'Enter the Docker image name:',\n validate: (input) => {\n if (!input.trim()) {\n return 'Image name is required';\n }\n return true;\n }\n }\n ]);\n \n options.image = response.image;\n }\n\n if (!options.tag) {\n const response = await inquirer.prompt([\n {\n type: 'input',\n name: 'tag',\n message: 'Enter the Docker image tag:',\n default: 'latest', // Add random hash later\n validate: (input) => {\n if (!input.trim()) {\n return 'Tag is required';\n }\n return true;\n }\n }\n ]);\n\n options.tag = response.tag;\n }\n\n // Prompt for Dockerfile path if the default doesn't exist\n const defaultPath = path.resolve(process.cwd(), options.file);\n if (!fs.existsSync(defaultPath)) {\n logger.info(`Default Dockerfile not found at ${defaultPath}`);\n \n options.file = await promptForFile(\n 'Enter the path to your Dockerfile:',\n 'Dockerfile',\n 'file'\n );\n }\n \n // Resolve the Dockerfile path\n const dockerfilePath = path.resolve(process.cwd(), options.file);\n \n // Build the image\n const dockerService = new DockerService(options.image, credentials.username, credentials.registry);\n const success = await dockerService.buildImage(dockerfilePath, options.tag);\n \n if (!success) {\n logger.error('Failed to build Docker image');\n process.exit(1);\n }\n \n logger.success(`Docker image ${credentials.username}/${options.image}:${options.tag} built successfully`);\n } catch (error) {\n logger.error(`Failed to build Docker image: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { DockerService } from '@/src/utils/docker';\nimport { getDockerCredentials } from '@/src/utils/credentials';\nimport { logger } from '@/src/utils/logger';\nimport inquirer from 'inquirer';\n\nexport const pushCommand = new Command()\n .name('push')\n .description('Push a Docker image to Docker Hub')\n .option('-i, --image <image>', 'Full image name (e.g. username/image:tag)')\n .action(async (options) => {\n try {\n // Get Docker credentials\n const credentials = await getDockerCredentials();\n \n if (!credentials) {\n logger.error('Docker information not found. Please login first with \"phala docker login\"');\n process.exit(1);\n }\n\n let imageName = options.image;\n\n // If image name is not provided, list local images and prompt user to select\n if (!imageName) {\n const localImages = await DockerService.listLocalImages();\n \n if (localImages.length === 0) {\n logger.error('No local Docker images found. Please build an image first with \"phala docker build\"');\n process.exit(1);\n }\n\n // If no image specified, prompt to select from available images\n if (!imageName) {\n // Get unique image names\n const uniqueImageNames = Array.from(new Set(localImages.map(img => img.imageName)));\n \n const { selectedImage } = await inquirer.prompt([\n {\n type: 'list',\n name: 'selectedImage',\n message: 'Select an image to push:',\n choices: uniqueImageNames\n }\n ]);\n \n imageName = selectedImage;\n }\n }\n \n // Push the image\n const dockerService = new DockerService('', credentials.username, credentials.registry);\n const success = await dockerService.pushImage(imageName);\n \n if (!success) {\n logger.error('Failed to push Docker image');\n process.exit(1);\n }\n \n logger.success(`Docker image ${imageName} pushed successfully`);\n } catch (error) {\n logger.error(`Failed to push Docker image: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { DockerService } from '@/src/utils/docker';\nimport { getDockerCredentials } from '@/src/utils/credentials';\nimport { logger } from '@/src/utils/logger';\nimport inquirer from 'inquirer';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { validateFileExists } from '@/src/utils/prompts';\n\nexport const generateCommand = new Command()\n .name('generate')\n .description('Generate a Docker Compose file')\n .option('-i, --image <imageName>', 'Docker image name to use in the compose file (e.g. phala/phala-cloud)')\n .option('-e, --env-file <envFile>', 'Path to environment variables file')\n .option('-o, --output <output>', 'Output path for generated docker-compose.yml')\n .option('--template <template>', 'Template to use for the generated docker-compose.yml', )\n .action(async (options) => {\n try {\n // Get Docker credentials to create the Docker service\n const credentials = await getDockerCredentials();\n if (!credentials || !credentials.username) {\n logger.error('Docker Hub username not found. Please login first with `phala docker login`');\n process.exit(1);\n }\n\n let imageName = options.image;\n\n if (!imageName) {\n // If image name is not provided, list local images and prompt user to select\n const localImages = await DockerService.listLocalImages();\n\n if (localImages.length === 0) {\n logger.error(\n 'No local Docker images found. Please build an image first with \"phala docker build\"',\n );\n process.exit(1);\n }\n\n // If no image specified, prompt to select from available images\n if (!imageName) {\n // Get unique image names\n const uniqueImageNames = Array.from(\n new Set(localImages.map((img) => img.imageName)),\n );\n\n const { selectedImage } = await inquirer.prompt([\n {\n type: \"list\",\n name: \"selectedImage\",\n message: \"Select an image to use in the compose file:\",\n choices: uniqueImageNames,\n },\n ]);\n\n imageName = selectedImage;\n }\n }\n \n // Get environment file path from options or prompt\n let envFilePath = options.envFile;\n if (!envFilePath) {\n // Check if .env exists in current directory\n const defaultEnvPath = path.join(process.cwd(), '.env');\n const hasDefaultEnv = fs.existsSync(defaultEnvPath);\n\n if (hasDefaultEnv) {\n const { useDefault } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'useDefault',\n message: 'Use .env file in current directory?',\n default: true\n }\n ]);\n\n if (useDefault) {\n envFilePath = defaultEnvPath;\n }\n }\n\n // If still no env file path, prompt for it\n if (!envFilePath) {\n const { envPath } = await inquirer.prompt([\n {\n type: 'input',\n name: 'envPath',\n message: 'Enter path to environment variables file:',\n validate: (input) => {\n try {\n validateFileExists(input);\n return true;\n } catch (error) {\n return `File not found: ${input}`;\n }\n }\n }\n ]);\n envFilePath = envPath;\n }\n } else {\n // Validate the provided env file path\n try {\n validateFileExists(envFilePath);\n } catch (error) {\n logger.error(`File not found: ${envFilePath}`);\n process.exit(1);\n }\n }\n\n // Get output path from options or set default\n let outputPath = options.output;\n if (!outputPath) {\n outputPath = path.join(process.cwd(), 'docker-compose.yml');\n \n // If file already exists, confirm overwrite\n if (fs.existsSync(outputPath)) {\n const { confirmOverwrite } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'confirmOverwrite',\n message: `File ${outputPath} already exists. Overwrite?`,\n default: false\n }\n ]);\n if (!confirmOverwrite) {\n const { customPath } = await inquirer.prompt([\n {\n type: 'input',\n name: 'customPath',\n message: 'Enter alternative output path:',\n default: path.join(process.cwd(), 'docker-generated-compose.yml')\n }\n ]);\n outputPath = customPath;\n }\n }\n }\n \n // Create a DockerService instance\n const dockerService = new DockerService('', credentials.username, credentials.registry);\n\n // Generate the Docker Compose file\n if (envFilePath) {\n logger.info(`Generating Docker Compose file for ${imageName} using env file: ${envFilePath}`);\n } else {\n logger.info(`Generating Docker Compose file for ${imageName} without env file`);\n }\n const composePath = await dockerService.buildComposeFile(imageName, envFilePath, options.template);\n \n // Copy the generated file to the output path if needed\n if (composePath !== outputPath) {\n // Ensure the output directory exists\n const outputDir = path.dirname(outputPath);\n if (!fs.existsSync(outputDir)) {\n logger.info(`Creating directory: ${outputDir}`);\n fs.mkdirSync(outputDir, { recursive: true });\n }\n \n fs.copyFileSync(composePath, outputPath);\n }\n \n logger.success(`Docker Compose file generated successfully: ${outputPath}`);\n } catch (error) {\n logger.error(`Failed to generate Docker Compose file: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { startCommand } from './start';\nimport { stopCommand } from './stop';\n\nexport const simulatorCommands = new Command()\n .name('simulator')\n .description('TEE simulator commands')\n .addCommand(startCommand)\n .addCommand(stopCommand);\n","import { Command } from 'commander';\nimport { DockerService } from '@/src/utils/docker';\nimport { logger } from '@/src/utils/logger';\nimport { TEE_SIMULATOR } from '@/src/utils/constants';\nimport { installSimulator, isSimulatorInstalled, isSimulatorRunning, runSimulator } from '@/src/utils/simulator';\n\nexport const startCommand = new Command()\n .name('start')\n .description('Start the TEE simulator')\n .option('-i, --image <image>', 'Simulator image', TEE_SIMULATOR)\n .option('-p, --port <port>', 'Simulator port (default: 8090)', '8090')\n .option('-t, --type <type>', 'Simulator type (docker, native)', 'docker')\n .action(async (options) => {\n try {\n if (options.type === 'docker') {\n // Start the simulator\n const dockerService = new DockerService('');\n const success = await dockerService.runSimulator(options.image, options.port);\n \n if (!success) {\n logger.error('Failed to start TEE simulator');\n process.exit(1);\n }\n } else if (options.type === 'native') {\n if (!isSimulatorInstalled()) {\n await installSimulator();\n }\n const running = await isSimulatorRunning();\n if (running) {\n logger.success('TEE simulator is already running');\n return;\n } else {\n const simulatorProcess = runSimulator();\n logger.success('TEE simulator started successfully');\n }\n } else {\n logger.error('Invalid simulator type');\n process.exit(1);\n }\n } catch (error) {\n logger.error(`Failed to start TEE simulator: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { DockerService } from '../../utils/docker';\nimport { logger } from '../../utils/logger';\nimport { stopSimulator } from '@/src/utils/simulator';\n\nexport const stopCommand = new Command()\n .name('stop')\n .description('Stop the TEE simulator')\n .option('-t, --type <type>', 'Simulator type (docker, native)', 'docker')\n .action(async (options) => {\n try {\n if (options.type === 'docker') {\n // Stop the simulator\n const dockerService = new DockerService('');\n const success = await dockerService.stopSimulator();\n\n if (!success) {\n logger.error('Failed to stop TEE simulator');\n process.exit(1);\n }\n } else if (options.type === 'native') {\n // Stop the native simulator\n const success = await stopSimulator();\n \n if (!success) {\n logger.error('Failed to stop TEE simulator');\n process.exit(1);\n }\n } else {\n logger.error('Invalid simulator type');\n process.exit(1);\n }\n } catch (error) {\n logger.error(`Failed to stop TEE simulator: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });","import { Command } from 'commander';\nimport { listCommand } from './list';\nimport { getCommand } from './get';\nimport { startCommand } from './start';\nimport { stopCommand } from './stop';\nimport { restartCommand } from './restart';\nimport { attestationCommand } from './attestation';\nimport { createCommand } from './create';\nimport { deleteCommand } from './delete';\nimport { upgradeCommand } from './upgrade';\nimport { resizeCommand } from './resize';\nimport { listNodesCommand } from './list-node';\nimport { replicateCommand } from './replicate';\n\nexport const cvmsCommand = new Command()\n .name('cvms')\n .description('Manage Phala Confidential Virtual Machines (CVMs)')\n .addCommand(attestationCommand)\n .addCommand(createCommand)\n .addCommand(deleteCommand)\n .addCommand(getCommand)\n .addCommand(listCommand)\n .addCommand(startCommand)\n .addCommand(stopCommand)\n .addCommand(resizeCommand)\n .addCommand(restartCommand)\n .addCommand(upgradeCommand)\n .addCommand(listNodesCommand)\n .addCommand(replicateCommand);\n ","import { Command } from 'commander';\nimport { getCvms } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport { CLOUD_URL } from '@/src/utils/constants';\nimport chalk from 'chalk';\n\nexport const listCommand = new Command()\n .name('list')\n .alias('ls')\n .description('List all CVMs')\n .option('-j, --json', 'Output in JSON format')\n .action(async (options) => {\n try {\n const spinner = logger.startSpinner('Fetching CVMs');\n \n const cvms = await getCvms();\n \n spinner.stop(true);\n \n if (!cvms || cvms.length === 0) {\n logger.info('No CVMs found');\n return;\n }\n \n if (options.json) {\n console.log(JSON.stringify(cvms, null, 2));\n return;\n }\n \n for (const cvm of cvms) {\n logger.keyValueTable({\n Name: cvm.name,\n \"App ID\": `app_${cvm.hosted.app_id}`,\n \"CVM ID\": cvm.hosted.id.replace(/-/g, ''),\n \"Region\": cvm.node.region_identifier,\n Status:\n cvm.status === \"running\"\n ? chalk.green(cvm.status)\n : cvm.status === \"stopped\"\n ? chalk.red(cvm.status)\n : chalk.yellow(cvm.status),\n \"Node Info URL\": cvm.hosted.app_url,\n \"App URL\": `${CLOUD_URL}/dashboard/cvms/${cvm.hosted.id.replace(/-/g, '')}`,\n });\n logger.break();\n }\n logger.success(`Found ${cvms.length} CVMs`);\n logger.break();\n logger.info(`Go to ${CLOUD_URL}/dashboard/ to view your CVMs`);\n } catch (error) {\n logger.error(`Failed to list CVMs: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { checkCvmExists, getCvmByAppId, getCvms, selectCvm } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport { CLOUD_URL } from '@/src/utils/constants';\nimport chalk from 'chalk';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\n\nexport const getCommand = new Command()\n .name('get')\n .description('Get details of a CVM')\n .argument('[app-id]', 'App ID of the CVM (optional)')\n .option('-j, --json', 'Output in JSON format')\n .action(async (appId, options) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n \n const spinner = logger.startSpinner(`Fetching CVM with App ID app_${resolvedAppId}`);\n \n const cvm = await getCvmByAppId(resolvedAppId);\n \n spinner.stop(true);\n logger.break();\n \n if (!cvm) {\n logger.error(`CVM with App ID app_${resolvedAppId} not found`);\n process.exit(1);\n }\n \n if (options.json) {\n console.log(JSON.stringify(cvm, null, 2));\n return;\n }\n \n // Display additional details if available\n logger.keyValueTable({\n 'Name': cvm.name,\n 'App ID': `app_${cvm.app_id}`,\n 'Status': (cvm.status === 'running') ? chalk.green(cvm.status) : (cvm.status === 'stopped') ? chalk.red(cvm.status) : chalk.yellow(cvm.status),\n 'vCPU': cvm.vcpu,\n 'Memory': `${cvm.memory} MB`,\n 'Disk Size': `${cvm.disk_size} GB`,\n 'Dstack Image': cvm.base_image,\n 'App URL': `${CLOUD_URL}/dashboard/cvms/app_${cvm.app_id}`\n });\n } catch (error) {\n logger.error(`Failed to get CVM details: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { selectCvm, checkCvmExists } from \"@/src/api/cvms\";\nimport { logger } from \"./logger\";\n\n/**\n * Resolves a CVM App ID either by prompting the user to select one if none is provided,\n * or by validating the provided App ID exists.\n *\n * @param appId Optional App ID to resolve\n * @returns The resolved App ID or undefined if none was selected/found\n */\nexport async function resolveCvmAppId(\n\tappId?: string,\n): Promise<string | undefined> {\n\tif (!appId) {\n\t\t// If no app ID is provided, prompt user to select one\n\t\tconst selectedCvm = await selectCvm();\n\t\tif (!selectedCvm) {\n\t\t\treturn undefined; // No CVMs found or user canceled\n\t\t}\n\t\treturn selectedCvm;\n\t}\n\t// Verify the provided App ID exists\n\treturn await checkCvmExists(appId);\n}","import { Command } from 'commander';\nimport { startCvm, selectCvm, checkCvmExists } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\nimport { CLOUD_URL } from '@/src/utils/constants';\n\nexport const startCommand = new Command()\n .name('start')\n .description('Start a stopped CVM')\n .argument('[app-id]', 'App ID of the CVM (if not provided, a selection prompt will appear)')\n .action(async (appId) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n \n const spinner = logger.startSpinner(`Starting CVM with App ID app_${resolvedAppId}`);\n \n const response = await startCvm(resolvedAppId);\n \n spinner.stop(true);\n logger.break();\n \n const tableData = {\n 'CVM ID': response.id,\n 'Name': response.name,\n 'Status': response.status,\n 'App ID': `app_${response.app_id}`,\n };\n logger.keyValueTable(tableData, {\n borderStyle: 'rounded'\n });\n \n logger.break();\n logger.success(\n `Your CVM is being started. You can check the dashboard for more details:\\n${CLOUD_URL}/dashboard/cvms/app_${response.app_id}`);\n } catch (error) {\n logger.error(`Failed to start CVM: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { stopCvm, selectCvm, checkCvmExists } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\nimport { CLOUD_URL } from '@/src/utils/constants';\n\nexport const stopCommand = new Command()\n .name('stop')\n .description('Stop a running CVM')\n .argument('[app-id]', 'App ID of the CVM (if not provided, a selection prompt will appear)')\n .action(async (appId) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n\n const spinner = logger.startSpinner(\n `Stopping CVM with App ID app_${resolvedAppId}`,\n );\n\n const response = await stopCvm(resolvedAppId);\n\n spinner.stop(true);\n logger.break();\n\n const tableData = {\n 'CVM ID': response.id,\n 'Name': response.name,\n 'Status': response.status,\n 'App ID': `app_${response.app_id}`,\n };\n logger.keyValueTable(tableData, {\n borderStyle: 'rounded'\n });\n\n logger.break();\n logger.success(\n `Your CVM is being stopped. You can check the dashboard for more details:\\n${CLOUD_URL}/dashboard/cvms/app_${response.app_id}`);\n \n } catch (error) {\n logger.error(`Failed to stop CVM: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { checkCvmExists, restartCvm, selectCvm } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\nimport { CLOUD_URL } from '@/src/utils/constants';\n\nexport const restartCommand = new Command()\n .name('restart')\n .description('Restart a CVM')\n .argument('[app-id]', 'App ID of the CVM (if not provided, a selection prompt will appear)')\n .action(async (appId) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n\n const spinner = logger.startSpinner(\n `Restarting CVM with App ID app_${resolvedAppId}`,\n );\n\n const response = await restartCvm(resolvedAppId);\n\n spinner.stop(true);\n logger.break();\n\n const tableData = {\n 'CVM ID': response.id,\n 'Name': response.name,\n 'Status': response.status,\n 'App ID': `app_${response.app_id}`,\n 'App URL': response.app_url\n ? response.app_url\n : `${CLOUD_URL}/dashboard/cvms/app_${response.app_id}`,\n };\n logger.keyValueTable(tableData, {\n borderStyle: \"rounded\",\n });\n\n logger.break();\n logger.success(\n `Your CVM is being restarted. You can check the dashboard for more details:\\n${CLOUD_URL}/dashboard/cvms/app_${response.app_id}`);\n } catch (error) {\n logger.error(`Failed to restart CVM: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { checkCvmExists, getCvmAttestation, selectCvm } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport chalk from 'chalk';\nimport type { CvmAttestationResponse } from '@/src/api/types';\n\nexport const attestationCommand = new Command()\n .name('attestation')\n .description('Get attestation information for a CVM')\n .argument('[app-id]', 'CVM app ID (will prompt for selection if not provided)')\n .option('-j, --json', 'Output in JSON format')\n .action(async (appId?: string, options?: { json?: boolean }) => {\n try {\n let resolvedAppId: string;\n \n if (!appId) {\n logger.info('No CVM specified, fetching available CVMs...');\n const selectedCvm = await selectCvm();\n if (!selectedCvm) {\n return;\n }\n resolvedAppId = selectedCvm;\n } else {\n resolvedAppId = await checkCvmExists(appId);\n }\n\n const spinner = logger.startSpinner(`Fetching attestation information for CVM app_${resolvedAppId}...`);\n\n try {\n const attestationData: CvmAttestationResponse = await getCvmAttestation(resolvedAppId);\n spinner.stop(true);\n\n if (!attestationData || Object.keys(attestationData).length === 0) {\n logger.info('No attestation information found');\n return;\n }\n\n // If JSON output is requested, just print the raw response\n if (options?.json) {\n logger.info(JSON.stringify(attestationData, null, 2));\n return;\n }\n\n // Display the attestation summary\n logger.success('Attestation Summary:');\n const summaryData = {\n 'Status': attestationData.is_online ? chalk.green('Online') : chalk.red('Offline'),\n 'Public Access': attestationData.is_public ? chalk.green('Enabled') : chalk.yellow('Disabled'),\n 'Error': attestationData.error || 'None',\n 'Certificates': `${attestationData.app_certificates?.length || 0} found`\n };\n \n logger.keyValueTable(summaryData, {\n borderStyle: 'rounded'\n });\n\n // Display certificate information\n if (attestationData.app_certificates && attestationData.app_certificates.length > 0) {\n \n attestationData.app_certificates.forEach((cert, index) => {\n logger.break();\n logger.success(`Certificate #${index + 1} (${cert.position_in_chain === 0 ? 'End Entity' : 'CA'}):`);\n \n const certData = {\n 'Subject': `${cert.subject.common_name || 'Unknown'}${cert.subject.organization ? ` (${cert.subject.organization})` : ''}`,\n 'Issuer': `${cert.issuer.common_name || 'Unknown'}${cert.issuer.organization ? ` (${cert.issuer.organization})` : ''}`,\n 'Serial Number': cert.serial_number,\n 'Validity': `${new Date(cert.not_before).toLocaleString()} to ${new Date(cert.not_after).toLocaleString()}`,\n 'Fingerprint': cert.fingerprint,\n 'Signature Algorithm': cert.signature_algorithm,\n 'Is CA': cert.is_ca ? 'Yes' : 'No',\n 'Position in Chain': cert.position_in_chain\n };\n \n logger.keyValueTable(certData, {\n borderStyle: 'rounded'\n });\n \n // Skip displaying the quote as it's very large and mostly binary data\n });\n }\n\n // Display TCB info if available\n if (attestationData.tcb_info) {\n logger.break();\n logger.success('Trusted Computing Base (TCB) Information:');\n \n // Create a formatted version of the TCB info without the event log\n const tcbBasicInfo = {\n 'Mrtd': attestationData.tcb_info.mrtd,\n 'Rootfs Hash': attestationData.tcb_info.rootfs_hash,\n 'Rtmr0': attestationData.tcb_info.rtmr0,\n 'Rtmr1': attestationData.tcb_info.rtmr1,\n 'Rtmr2': attestationData.tcb_info.rtmr2,\n 'Rtmr3': attestationData.tcb_info.rtmr3,\n 'Event Log Entries': `${attestationData.tcb_info.event_log.length} entries`\n };\n \n // Display basic TCB info\n logger.keyValueTable(tcbBasicInfo, {\n borderStyle: 'rounded'\n });\n \n // Display event log entries separately if they exist\n if (attestationData.tcb_info.event_log && attestationData.tcb_info.event_log.length > 0) {\n logger.break();\n logger.success('Event Log (Showing entries to reproduce RTMR3):');\n \n // Show the first 5 entries\n const maxEntriesToShow = 5;\n const entries = attestationData.tcb_info.event_log\n .filter(entry => entry.event !== null && entry.event !== \"\")\n .map((entry) => ({\n 'Event': entry.event,\n 'IMR': entry.imr.toString(),\n 'Event Type': entry.event_type.toString(),\n 'Payload': entry.event_payload,\n }));\n \n // Display entries in a table format\n logger.table(entries, [\n { key: \"Event\", header: \"Event\", minWidth: 8 },\n { key: \"IMR\", header: \"IMR\", minWidth: 3 },\n { key: \"Event Type\", header: \"Type\", minWidth: 8 },\n { key: \"Payload\", header: \"Payload\", minWidth: 25 },\n ]);\n \n if (attestationData.tcb_info.event_log.length > maxEntriesToShow) {\n logger.info('To see all full attestation data, use --json');\n }\n logger.break();\n logger.success('To reproduce RTMR3, use the tool at https://rtmr3-calculator.vercel.app/');\n }\n }\n } catch (error) {\n spinner.stop(false);\n throw error;\n }\n } catch (error) {\n logger.error(`Failed to get attestation information: ${error instanceof Error ? error.message : String(error)}`);\n }\n });\n","import { Command } from 'commander';\nimport { createCvm, getPubkeyFromCvm } from '@/src/api/cvms';\nimport { getTeepods } from '@/src/api/teepods';\nimport { logger } from '@/src/utils/logger';\nimport type { TEEPod, Image } from '@/src/api/types';\nimport { DEFAULT_VCPU, DEFAULT_MEMORY, DEFAULT_DISK_SIZE, CLOUD_URL, DEFAULT_IMAGE } from '@/src/utils/constants';\nimport { encryptEnvVars } from '@phala/dstack-sdk/encrypt-env-vars';\nimport type { EnvVar } from '@phala/dstack-sdk/encrypt-env-vars';\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport inquirer from 'inquirer';\nimport { parseEnv } from '@/src/utils/secrets';\nimport { detectFileInCurrentDir, promptForFile } from '@/src/utils/prompts';\nimport { deleteSimulatorEndpointEnv } from '@/src/utils/simulator';\n\nexport const createCommand = new Command()\n .name('create')\n .description('Create a new CVM')\n .option('-n, --name <name>', 'Name of the CVM')\n .option('-c, --compose <compose>', 'Path to Docker Compose file')\n .option('--vcpu <vcpu>', `Number of vCPUs, default is ${DEFAULT_VCPU}`)\n .option('--memory <memory>', `Memory in MB, default is ${DEFAULT_MEMORY}`)\n .option('--disk-size <diskSize>', `Disk size in GB, default is ${DEFAULT_DISK_SIZE}`)\n .option('--teepod-id <teepodId>', 'TEEPod ID to use. If not provided, it will be selected from the list of available TEEPods.')\n .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.')\n .option('-e, --env-file <envFile>', 'Path to environment file')\n .option('--skip-env', 'Skip environment variable prompt', false)\n .option('--debug', 'Enable debug mode', false)\n .action(async (options) => {\n try {\n // Prompt for required options if not provided\n if (!options.name) {\n const { name } = await inquirer.prompt([\n {\n type: 'input',\n name: 'name',\n message: 'Enter a name for the CVM:',\n validate: (input) => {\n if (!input.trim()) {\n return 'CVM name is required';\n }\n if (input.trim().length > 20) {\n return 'CVM name must be less than 20 characters';\n } \n if (input.trim().length < 3) {\n return 'CVM name must be at least 3 characters';\n } \n if (!/^[a-zA-Z0-9_-]+$/.test(input)) {\n return 'CVM name must contain only letters, numbers, underscores, and hyphens';\n }\n return true;\n }\n }\n ]);\n options.name = name;\n }\n\n // If compose path not provided, prompt with examples\n if (!options.compose) {\n const possibleFiles = ['docker-compose.yml', 'docker-compose.yaml'];\n const composeFileName = detectFileInCurrentDir(possibleFiles, 'Detected docker compose file: {path}');\n\n options.compose = await promptForFile(\n 'Enter the path to your Docker Compose file:',\n composeFileName,\n 'file'\n );\n }\n\n const composePath = path.resolve(options.compose);\n if (!fs.existsSync(composePath)) {\n logger.error(`Docker Compose file not found: ${composePath}`);\n process.exit(1);\n }\n const composeString = fs.readFileSync(composePath, 'utf8');\n\n // Delete DSTACK_SIMULATOR_ENDPOINT environment variable\n await deleteSimulatorEndpointEnv();\n\n // Print if they are using a private registry\n if (process.env.DSTACK_DOCKER_USERNAME && process.env.DSTACK_DOCKER_PASSWORD) {\n logger.info(\"🔐 Using private DockerHub registry credentials...\");\n } else if (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) {\n logger.info(`🔐 Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`);\n } else {\n logger.info(\"🔐 Using public DockerHub registry...\");\n }\n\n // Process environment variables\n let envs: EnvVar[] = [];\n\n // Process environment variables from file\n if (options.envFile) {\n try {\n envs = parseEnv([], options.envFile);\n } catch (error) {\n logger.error(`Failed to read environment file: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n } else if (!options.skipEnv) {\n // Prompt to input env file or skip\n const { shouldSkip } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'shouldSkip',\n message: 'Do you want to skip environment variable prompt?',\n default: true\n }\n ]);\n \n if (shouldSkip) {\n logger.info('Skipping environment variable prompt');\n } else {\n const envVars = await promptForFile(\n 'Enter the path to your environment file:',\n '.env',\n 'file',\n );\n envs = parseEnv([], envVars);\n }\n }\n\n const vcpu = Number(options.vcpu) || DEFAULT_VCPU;\n const memory = Number(options.memory) || DEFAULT_MEMORY;\n const diskSize = Number(options.diskSize) || DEFAULT_DISK_SIZE;\n\n if (Number.isNaN(vcpu) || vcpu <= 0) {\n logger.error(`Invalid number of vCPUs: ${vcpu}`);\n process.exit(1);\n }\n\n if (Number.isNaN(memory) || memory <= 0) {\n logger.error(`Invalid memory: ${memory}`);\n process.exit(1);\n }\n\n if (Number.isNaN(diskSize) || diskSize <= 0) {\n logger.error(`Invalid disk size: ${diskSize}`);\n process.exit(1);\n }\n\n const teepodsSpinner = logger.startSpinner('Fetching available TEEPods');\n const teepods = await getTeepods();\n teepodsSpinner.stop(true);\n if (teepods.nodes.length === 0) {\n logger.error('No TEEPods available. Please try again later.');\n process.exit(1);\n }\n\n let selectedTeepod: TEEPod;\n // Fetch available TEEPods\n if (!options.teepodId) {\n selectedTeepod = teepods.nodes[0];\n if (!selectedTeepod) {\n logger.error('Failed to find default TEEPod');\n process.exit(1);\n }\n } else {\n selectedTeepod = teepods.nodes.find(pod => pod.teepod_id === Number(options.teepodId));\n if (!selectedTeepod) {\n logger.error('Failed to find selected TEEPod');\n process.exit(1);\n }\n }\n\n let selectedImage: Image;\n if (!options.image) {\n selectedImage = selectedTeepod.images?.find(image => image.name === DEFAULT_IMAGE);\n if (!selectedImage) {\n logger.error(`Failed to find default image ${DEFAULT_IMAGE}`);\n process.exit(1);\n }\n } else {\n selectedImage = selectedTeepod.images?.find(image => image.name === options.image);\n if (!selectedImage) {\n logger.error(`Failed to find selected image: ${options.image}`);\n process.exit(1);\n }\n }\n\n // Prepare VM configuration\n const vmConfig = {\n teepod_id: selectedTeepod.teepod_id,\n name: options.name,\n image: selectedImage.name,\n vcpu: vcpu,\n memory: memory,\n disk_size: diskSize,\n compose_manifest: {\n docker_compose_file: composeString,\n docker_config: {\n url: '',\n username: '',\n password: '',\n },\n features: ['kms', 'tproxy-net'],\n kms_enabled: true,\n manifest_version: 2,\n name: options.name,\n public_logs: true,\n public_sysinfo: true,\n tproxy_enabled: true,\n },\n listed: false,\n };\n\n // Get public key from CVM\n const spinner = logger.startSpinner('Getting public key from CVM');\n const pubkey = await getPubkeyFromCvm(vmConfig);\n spinner.stop(true);\n\n if (!pubkey) {\n logger.error('Failed to get public key from CVM');\n process.exit(1);\n }\n\n // Encrypt environment variables\n const encryptSpinner = logger.startSpinner('Encrypting environment variables');\n const encrypted_env = await encryptEnvVars(envs, pubkey.app_env_encrypt_pubkey);\n encryptSpinner.stop(true);\n\n if (options.debug) {\n logger.debug('Public key:', pubkey.app_env_encrypt_pubkey);\n logger.debug('Encrypted environment variables:', encrypted_env);\n logger.debug('Environment variables:', JSON.stringify(envs));\n }\n\n // Create the CVM\n const createSpinner = logger.startSpinner('Creating CVM');\n const response = await createCvm({\n ...vmConfig,\n encrypted_env,\n app_env_encrypt_pubkey: pubkey.app_env_encrypt_pubkey,\n app_id_salt: pubkey.app_id_salt,\n });\n createSpinner.stop(true);\n\n if (!response) {\n logger.error('Failed to create CVM');\n process.exit(1);\n }\n\n logger.success('CVM created successfully');\n logger.break();\n const tableData = {\n 'CVM ID': response.id,\n 'Name': response.name,\n 'Status': response.status,\n 'App ID': `app_${response.app_id}`,\n 'App URL': response.app_url ? response.app_url : `${CLOUD_URL}/dashboard/cvms/app_${response.app_id}`,\n };\n logger.keyValueTable(tableData, {\n borderStyle: 'rounded'\n });\n\n logger.info('');\n logger.success(`Your CVM is being created. You can check its status with:\\nphala cvms get app_${response.app_id}`);\n } catch (error) {\n logger.error(`Failed to create CVM: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import * as fs from 'node:fs';\nimport type { EnvVar } from '@phala/dstack-sdk/encrypt-env-vars';\n\nexport const parseEnv = (envs: string[], envFile: string): EnvVar[] => {\n const envVars: Record<string, string> = {};\n\n // Process environment variables passed directly\n if (envs) {\n for (const env of envs) {\n if (env.includes(\"=\")) {\n const [key, ...valueParts] = env.split(\"=\");\n const value = valueParts.join(\"=\"); // Handle cases where value might contain '='\n if (key) { // Allow empty value\n envVars[key] = value;\n }\n }\n }\n }\n\n if (envFile) {\n const envFileContent = fs.readFileSync(envFile, \"utf8\");\n for (const line of envFileContent.split(\"\\n\")) {\n // Skip empty lines\n if (!line.trim()) {\n continue;\n }\n\n // Skip comments\n if (line.trim().startsWith('#')) {\n continue;\n }\n\n // Find the first '=' that is not part of an inline comment\n let delimiterIndex = -1;\n let inQuotes = false;\n let quoteChar = '';\n\n for (let i = 0; i < line.length; i++) {\n if ((line[i] === '\"' || line[i] === \"'\" || line[i] === '`') && (i === 0 || line[i-1] !== '\\\\')) {\n if (inQuotes && line[i] === quoteChar) {\n inQuotes = false;\n quoteChar = '';\n } else if (!inQuotes) {\n inQuotes = true;\n quoteChar = line[i];\n }\n } else if (line[i] === '=' && !inQuotes) {\n delimiterIndex = i;\n break;\n } else if (line[i] === '#' && !inQuotes) {\n // If a comment starts before any '=', treat the whole line as a comment if no '=' found yet\n // Or, if '=' is found, this part is an inline comment.\n if (delimiterIndex === -1) { // No '=' encountered yet, so this is a full-line comment essentially or malformed\n // We already skip lines starting with #, this handles cases like \" #comment\"\n // or \"KEY #comment\" (which is not a valid assignment according to rules)\n // However, the rule \" # marks the beginning of a comment (unless when the value is wrapped in quotes)\"\n // implies that \"KEY=value #comment\" is valid.\n // The current logic handles inline comments on the value side later.\n // If # appears before =, it's either a full comment (handled) or part of the key (unusual, but let it pass to split)\n }\n break; // Stop processing at the comment marker for the key or if it's an inline comment for the value\n }\n }\n\n\n if (delimiterIndex === -1) {\n // Handles lines without '=' or lines that are effectively comments.\n if (!line.trim().startsWith('#')) {\n // It's not a comment line, but has no '='.\n // According to \"EMPTY= becomes {EMPTY: ''}\", lines like \"ONLYKEY\" are not defined.\n // So we can skip them or treat as an error. Skipping for now.\n }\n continue;\n }\n\n const key = line.substring(0, delimiterIndex).trim();\n let value = line.substring(delimiterIndex + 1);\n\n // Remove inline comments from the value part\n // A comment starts with ' #' (space followed by #)\n // unless the # is within quotes.\n let valueInQuotes = false;\n let valueQuoteChar = '';\n let commentStartIndex = -1;\n\n for (let i = 0; i < value.length; i++) {\n if ((value[i] === '\"' || value[i] === \"'\" || value[i] === '`') && (i === 0 || value[i-1] !== '\\\\')) {\n if (valueInQuotes && value[i] === valueQuoteChar) {\n valueInQuotes = false;\n valueQuoteChar = '';\n } else if (!valueInQuotes) {\n valueInQuotes = true;\n valueQuoteChar = value[i];\n }\n } else if (value[i] === '#' && !valueInQuotes && i > 0 && value[i-1] === ' ') {\n commentStartIndex = i -1; // Start of \" #\"\n break;\n } else if (value[i] === '#' && !valueInQuotes && i === 0) { // Value starts directly with #\n commentStartIndex = i;\n break;\n }\n }\n\n if (commentStartIndex !== -1) {\n value = value.substring(0, commentStartIndex);\n }\n\n\n // Handle empty values: EMPTY= becomes {EMPTY: ''}\n if (value === undefined) { // Should not happen if split correctly\n value = '';\n }\n\n\n // Trim whitespace for unquoted values, preserve for quoted\n const firstChar = value.charAt(0);\n const lastChar = value.charAt(value.length - 1);\n\n if ((firstChar === '\"' && lastChar === '\"') ||\n (firstChar === \"'\" && lastChar === \"'\") ||\n (firstChar === '`' && lastChar === '`')) {\n // Quoted value, remove the outer quotes\n value = value.substring(1, value.length - 1);\n\n // Expand newlines for double-quoted values\n if (firstChar === '\"') {\n value = value.replace(/\\\\\\\\n/g, '\\n');\n }\n // Unescape inner quotes for single and backtick quotes if they were escaped like \\\\' or \\\\`\n // The rules state \"inner quotes are maintained (think JSON)\"\n // and \"single and double quoted values are escaped\"\n // This implies that within a string like SINGLE_QUOTE='value with \\\\' quote'\n // the result should be \"value with ' quote\"\n // For JSON example: JSON={\"foo\": \"bar\"} becomes {JSON:\"{\\\"foo\\\": \\\"bar\\\"}\"}\n // This needs careful handling. The current approach of just slicing quotes might be too simple.\n // Let's assume the provided examples are the source of truth.\n // \"JSON={\"foo\": \"bar\"}\" -> JSON: \"{\\\"foo\\\": \\\"bar\\\"}\"\n // This means the quotes *around* the JSON are stripped, but the inner quotes *within* the JSON string literal itself are preserved.\n // The rule \"single and double quoted values are escaped (SINGLE_QUOTE='quoted' becomes {SINGLE_QUOTE: \"quoted\"})\"\n // seems to imply that the outer quotes are removed, and the content becomes a JS string.\n // The parsing engine should output a JS object, so values will be JS strings.\n // SINGLE_QUOTE='quoted' -> {SINGLE_QUOTE: 'quoted'} (JS string)\n // FOO=\" some value \" -> {FOO: ' some value '} (JS string)\n // JSON={\"foo\": \"bar\"} -> {JSON: '{\"foo\": \"bar\"}'} (JS string)\n // MULTILINE=\"new\\\\nline\" -> {MULTILINE: 'new\\\\nline'} (JS string with literal \\n)\n // The rule says: MULTILINE=\"new\\\\nline\" becomes {MULTILINE: 'new\\nline'} (with actual newline)\n // So, my previous .replace(/\\\\n/g, '\\n') for double quotes is correct.\n\n // For single quotes and backticks, the rules don't explicitly state escaped char handling other than `\\\\n` for double quotes.\n // \"inner quotes are maintained (think JSON)\" - this is key for JSON={\"foo\": \"bar\"}\n // Let's ensure that if a value is `'{\"key\": \"value\"}'`, it becomes `{\"key\": \"value\"}`.\n // The current `substring(1, value.length - 1)` does this.\n // Let's consider BACKTICK_KEY=`This has 'single' and \"double\" quotes inside of it.`\n // This should become {BACKTICK_KEY: \"This has 'single' and \\\"double\\\" quotes inside of it.\"}\n // The current slicing handles this correctly. Escaped backticks like \\` needs to be considered if they should be unescaped.\n // The rules do not specify un-escaping for \\\\', \\\\\", or \\\\` within their respective quotes.\n // So, 'it\\'s a test' would become \"it\\'s a test\". If it should be \"it's a test\", then un-escaping is needed.\n // Given \"single and double quoted values are escaped\", it seems like what's inside the quotes is the literal string value.\n // Let's stick to the examples: SINGLE_QUOTE='quoted' becomes {SINGLE_QUOTE: \"quoted\"}. This means the value is 'quoted'.\n } else {\n // Unquoted value, trim whitespace\n value = value.trim();\n }\n\n\n if (key) { // Ensure key is not empty\n envVars[key] = value;\n }\n }\n }\n\n // Add environment variables to the payload\n return Object.entries(envVars).map(([key, value]) => ({\n key,\n value,\n }));\n};","import { Command } from 'commander';\nimport { checkCvmExists, deleteCvm, selectCvm } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport inquirer from 'inquirer';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\n\nexport const deleteCommand = new Command()\n .name('delete')\n .description('Delete a CVM')\n .argument('[app-id]', 'App ID of the CVM to delete (if not provided, a selection prompt will appear)')\n .option('-f, --force', 'Skip confirmation prompt', false)\n .action(async (appId, options) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n \n // Confirm deletion unless force option is used\n if (!options.force) {\n const { confirm } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'confirm',\n message: `Are you sure you want to delete CVM with App ID app_${resolvedAppId}? This action cannot be undone.`,\n default: false,\n },\n ]);\n \n if (!confirm) {\n logger.info('Deletion cancelled');\n return;\n }\n }\n \n // Delete the CVM\n const spinner = logger.startSpinner(`Deleting CVM app_${resolvedAppId}`);\n const success = await deleteCvm(resolvedAppId);\n spinner.stop(true);\n \n if (!success) {\n logger.error(`Failed to delete CVM app_${resolvedAppId}`);\n process.exit(1);\n }\n\n\t\tlogger.success(`CVM app_${resolvedAppId} deleted successfully`);\n\t} catch (error) {\n\t\tlogger.error(\n\t\t\t`Failed to delete CVM: ${error instanceof Error ? error.message : String(error)}`\n\t\t);\n\t\tprocess.exit(1);\n\t}\n }); ","import { Command } from 'commander';\nimport { upgradeCvm, getCvmByAppId, selectCvm, checkCvmExists } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport fs from 'node:fs';\nimport { detectFileInCurrentDir, promptForFile } from '@/src/utils/prompts';\nimport { parseEnv } from '@/src/utils/secrets';\nimport { encryptEnvVars, type EnvVar } from '@phala/dstack-sdk/encrypt-env-vars';\nimport { deleteSimulatorEndpointEnv } from '@/src/utils/simulator';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\nimport { CLOUD_URL } from '@/src/utils/constants';\n\nexport const upgradeCommand = new Command()\n .name('upgrade')\n .description('Upgrade a CVM to a new version')\n .argument('[app-id]', 'CVM app ID to upgrade (will prompt for selection if not provided)')\n .option('-c, --compose <compose>', 'Path to new Docker Compose file')\n .option('-e, --env-file <envFile>', 'Path to environment file')\n .option('--debug', 'Enable debug mode', false)\n .action(async (appId, options) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n\n // Get current CVM configuration\n const spinner = logger.startSpinner(`Fetching current configuration for CVM app_${resolvedAppId}`);\n const currentCvm = await getCvmByAppId(resolvedAppId);\n spinner.stop(true);\n \n if (!currentCvm) {\n logger.error(`CVM with App ID app_${resolvedAppId} not found`);\n process.exit(1);\n }\n \n // If compose path not provided, prompt with examples\n if (!options.compose) {\n const possibleFiles = ['docker-compose.yml', 'docker-compose.yaml'];\n const composeFileName = detectFileInCurrentDir(possibleFiles, 'Detected docker compose file: {path}');\n \n options.compose = await promptForFile(\n 'Enter the path to your Docker Compose file:',\n composeFileName,\n 'file'\n );\n }\n \n // Update Docker Compose file if provided\n let composeString = '';\n if (options.compose) {\n try {\n composeString = fs.readFileSync(options.compose, 'utf8');\n } catch (error) {\n logger.error(`Failed to read Docker Compose file: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }\n \n // Delete DSTACK_SIMULATOR_ENDPOINT environment variable\n await deleteSimulatorEndpointEnv();\n // Print if they are using a private registry\n if (process.env.DSTACK_DOCKER_USERNAME && process.env.DSTACK_DOCKER_PASSWORD) {\n logger.info(\"🔐 Using private DockerHub registry credentials...\");\n } else if (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) {\n logger.info(`🔐 Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`);\n } else {\n logger.info(\"🔐 Using public DockerHub registry...\");\n }\n\n // Process environment variables if provided\n let encrypted_env = \"\";\n if (options.envFile) {\n let envs: EnvVar[] = [];\n \n // Process environment variables from file\n if (options.envFile) {\n try {\n envs = parseEnv([], options.envFile);\n encrypted_env = await encryptEnvVars(envs, currentCvm.encrypted_env_pubkey);\n } catch (error) {\n logger.error(`Failed to read environment file: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }\n \n }\n\n const vm_config = {\n compose_manifest: {\n docker_compose_file: composeString,\n manifest_version: 1,\n runner: \"docker-compose\",\n version: \"1.0.0\",\n features: [\"kms\", \"tproxy-net\"],\n name: `app_${resolvedAppId}`,\n },\n encrypted_env,\n allow_restart: true,\n };\n \n // Upgrade the CVM\n const upgradeSpinner = logger.startSpinner(`Upgrading CVM app_${resolvedAppId}`);\n const response = await upgradeCvm(resolvedAppId, vm_config);\n \n if (!response) {\n upgradeSpinner.stop(false);\n logger.error('Failed to upgrade CVM');\n process.exit(1);\n }\n upgradeSpinner.stop(true);\n\n if (response.detail) {\n logger.info(`Details: ${response.detail}`);\n }\n\n logger.break();\n logger.success(\n `Your CVM is being upgraded. You can check the dashboard for more details:\\n${CLOUD_URL}/dashboard/cvms/app_${resolvedAppId}`\n );\n } catch (error) {\n logger.error(`Failed to upgrade CVM: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { checkCvmExists, getCvmByAppId, resizeCvm, selectCvm } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport inquirer from 'inquirer';\nimport chalk from 'chalk';\nimport { resolveCvmAppId } from '@/src/utils/cvms';\nimport { CLOUD_URL } from '@/src/utils/constants';\n\nexport const resizeCommand = new Command()\n .name('resize')\n .description('Resize resources for a CVM')\n .argument('[app-id]', 'App ID of the CVM (if not provided, a selection prompt will appear)')\n .option('-v, --vcpu <vcpu>', 'Number of virtual CPUs')\n .option('-m, --memory <memory>', 'Memory size in MB')\n .option('-d, --disk-size <diskSize>', 'Disk size in GB')\n .option('-r, --allow-restart <allowRestart>', 'Allow restart of the CVM if needed for resizing')\n .option('-y, --yes', 'Automatically confirm the resize operation')\n .action(async (appId, options) => {\n try {\n const resolvedAppId = await resolveCvmAppId(appId);\n\n const cvm = await getCvmByAppId(resolvedAppId);\n \n // Initialize parameters\n let vcpu: number | undefined = options.vcpu;\n let memory: number | undefined = options.memory;\n let diskSize: number | undefined = options.diskSize;\n let allowRestart: boolean | undefined = options.allowRestart;\n // Prompt for vCPU if selected\n if (!vcpu) {\n const response = await inquirer.prompt([\n {\n type: 'input',\n name: 'vcpu',\n message: 'Enter number of vCPUs:',\n validate: (input) => {\n const num = parseInt(input);\n if (isNaN(num) || num < 0) {\n return 'Please enter a valid non-negative number';\n }\n return true;\n },\n default: cvm.vcpu,\n filter: (input) => parseInt(input)\n }\n ]);\n vcpu = response.vcpu;\n }\n \n // Prompt for memory\n if (!memory) {\n const response = await inquirer.prompt([\n {\n type: 'input',\n name: 'memory',\n message: 'Enter memory in MB:',\n validate: (input) => {\n const num = parseInt(input);\n if (isNaN(num) || num < 0) {\n return 'Please enter a valid non-negative number';\n }\n return true;\n },\n default: cvm.memory,\n filter: (input) => parseInt(input)\n }\n ]);\n memory = response.memory;\n }\n \n // Prompt for disk size\n if (!diskSize) {\n const response = await inquirer.prompt([\n {\n type: 'input',\n name: 'diskSize',\n message: 'Enter disk size in GB:',\n validate: (input) => {\n const num = parseInt(input);\n if (isNaN(num) || num < 0) {\n return 'Please enter a valid non-negative number';\n }\n return true;\n },\n default: cvm.disk_size,\n filter: (input) => parseInt(input)\n }\n ]);\n diskSize = response.diskSize;\n }\n \n // Ask about restart permission\n if (!allowRestart) {\n const response = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'allowRestart',\n message: 'Allow restart of the CVM if needed for resizing?',\n default: false\n }\n ]);\n allowRestart = response.allowRestart;\n }\n \n // Prepare confirmation message\n const confirmMessage = `Are you sure you want to resize CVM app_${resolvedAppId} with the following changes:\\n`;\n logger.keyValueTable(\n { 'vCPUs': cvm.vcpu !== vcpu ? `${chalk.red(cvm.vcpu)} -> ${chalk.green(vcpu)}` : cvm.vcpu,\n 'Memory': cvm.memory !== memory ? `${chalk.red(cvm.memory)} MB -> ${chalk.green(memory)} MB` : cvm.memory,\n 'Disk Size': cvm.disk_size !== diskSize ? `${chalk.red(cvm.disk_size)} GB -> ${chalk.green(diskSize)} GB` : cvm.disk_size,\n 'Allow Restart': allowRestart ? chalk.green('Yes') : chalk.red('No') }\n );\n \n // Confirm the resize operation\n if (!options.yes) {\n const { confirm } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'confirm',\n message: confirmMessage,\n default: false\n }\n ]);\n \n if (!confirm) {\n logger.info('Resize operation cancelled');\n return;\n }\n }\n \n const spinner = logger.startSpinner(`Resizing CVM with App ID app_${resolvedAppId}`);\n \n // Convert boolean to number (0 or 1) as expected by the API\n const allowRestartValue = allowRestart ? 1 : 0;\n \n await resizeCvm(resolvedAppId, vcpu, memory, diskSize, allowRestartValue);\n\n spinner.stop(true);\n logger.break();\n logger.success(\n `Your CVM is being resized. You can check the dashboard for more details:\\n${CLOUD_URL}/dashboard/cvms/app_${resolvedAppId}`\n );\n } catch (error) {\n logger.error(\n `Failed to resize CVM: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n }); ","import { Command } from 'commander';\nimport { getTeepods } from '@/src/api/teepods';\nimport { logger } from '@/src/utils/logger';\nimport { KmsListItem, TEEPod } from '@/src/api/types';\n\nexport const listNodesCommand = new Command()\n .name('list-nodes')\n .description('List all available worker nodes.')\n .action(async () => {\n try {\n const { nodes: teepods, kms_list: kmsList } = await getTeepods();\n\n if (teepods.length === 0) {\n logger.info('No available nodes found.');\n return;\n }\n\n logger.info('Available Nodes:');\n teepods.forEach((teepod: TEEPod) => {\n logger.info('----------------------------------------');\n logger.info(` ID: ${teepod.teepod_id}`);\n logger.info(` Name: ${teepod.name}`);\n logger.info(` Region: ${teepod.region_identifier}`);\n logger.info(` FMSPC: ${teepod.fmspc || 'N/A'}`);\n logger.info(` Device ID: ${teepod.device_id || 'N/A'}`);\n logger.info(` Support Onchain KMS: ${teepod.support_onchain_kms}`);\n logger.info(' Images:');\n if (teepod.images && teepod.images.length > 0) {\n teepod.images.forEach(img => {\n logger.info(` - ${img.name}`);\n logger.info(` Hash: ${img.os_image_hash || 'N/A'}`);\n });\n } else {\n logger.info(' N/A');\n }\n });\n\n if (kmsList && kmsList.length > 0) {\n logger.info('\\nAvailable KMS Instances:');\n kmsList.forEach((kms: KmsListItem) => {\n logger.info('----------------------------------------');\n logger.info(` ID: ${kms.id}`);\n logger.info(` URL: ${kms.url}`);\n logger.info(` Version: ${kms.version}`);\n logger.info(` Chain ID: ${kms.chain_id}`);\n logger.info(` Contract Address: ${kms.kms_contract_address}`);\n logger.info(` Gateway App ID: ${kms.gateway_app_id}`);\n });\n }\n } catch (error) {\n logger.error(`Failed to list available nodes: ${error instanceof Error ? error.message : String(error)}`);\n }\n });","import { Command } from 'commander';\nimport { replicateCvm, getCvmComposeConfig } from '@/src/api/cvms';\nimport { logger } from '@/src/utils/logger';\nimport { encryptEnvVars } from '@phala/dstack-sdk/encrypt-env-vars';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nexport const replicateCommand = new Command()\n .name('replicate')\n .description('Create a replica of an existing CVM')\n .argument('<cvm-id>', 'UUID of the CVM to replicate')\n .option('--teepod-id <teepodId>', 'TEEPod ID to use for the replica')\n .option('-e, --env-file <envFile>', 'Path to environment file')\n .action(async (cvmId, options) => {\n try {\n let encryptedEnv: string | undefined;\n cvmId = cvmId.replace(/-/g, '');\n\n // Handle environment variables if provided\n if (options.envFile) {\n const envPath = path.resolve(process.cwd(), options.envFile);\n if (!fs.existsSync(envPath)) {\n throw new Error(`Environment file not found: ${envPath}`);\n }\n\n // Read and parse the environment file\n const envContent = fs.readFileSync(envPath, 'utf-8');\n const envVars = envContent\n .split('\\n')\n .filter(line => line.trim() !== '' && !line.trim().startsWith('#'))\n .map(line => {\n const [key, ...value] = line.split('=');\n return {\n key: key.trim(),\n value: value.join('=').trim()\n };\n });\n\n // Get CVM compose config which includes the public key\n const cvmConfig = await getCvmComposeConfig(cvmId);\n\n // Encrypt the environment variables\n logger.info('Encrypting environment variables...');\n const encryptedVars = await encryptEnvVars(\n envVars,\n cvmConfig.env_pubkey\n );\n encryptedEnv = encryptedVars;\n }\n\n // Prepare the request body\n const requestBody: {\n teepod_id?: number;\n encrypted_env?: string;\n } = {};\n\n if (options.teepodId) {\n requestBody.teepod_id = parseInt(options.teepodId, 10);\n }\n if (encryptedEnv) {\n requestBody.encrypted_env = encryptedEnv;\n }\n\n // Call the API to create the replica\n const replica = await replicateCvm(cvmId, requestBody);\n\n logger.success(`Successfully created replica of CVM UUID: ${cvmId} with App ID: ${replica.app_id}`);\n\n const tableData = {\n 'CVM UUID': replica.vm_uuid.replace(/-/g, ''),\n 'App ID': replica.app_id,\n 'Name': replica.name,\n 'Status': replica.status,\n 'TEEPod': `${replica.teepod.name} (ID: ${replica.teepod_id})`,\n 'vCPUs': replica.vcpu,\n 'Memory': `${replica.memory} MB`,\n 'Disk Size': `${replica.disk_size} GB`,\n 'App URL': replica.app_url || `${process.env.CLOUD_URL || 'https://cloud.phala.network'}/dashboard/cvms/${replica.vm_uuid.replace(/-/g, '')}`\n };\n\n logger.keyValueTable(tableData, {\n borderStyle: 'rounded'\n });\n logger.success(`Your CVM replica is being created. You can check its status with:\\nphala cvms get ${replica.app_id}`);\n } catch (error) {\n logger.error('Failed to create CVM replica:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport { logger } from '@/src/utils/logger';\nimport { execSync } from 'node:child_process';\nimport * as os from 'node:os';\nimport { logo } from '../utils/banner';\n\n\n/**\n * Opens a URL in the default web browser based on the current operating system\n * @param url The URL to open\n */\nfunction openBrowser(url: string): void {\n const platform = os.platform();\n \n try {\n switch (platform) {\n case 'darwin': // macOS\n execSync(`open \"${url}\"`);\n break;\n case 'win32': // Windows\n execSync(`start \"\" \"${url}\"`);\n break;\n case 'linux': // Linux\n // Try different commands in order\n try {\n execSync(`xdg-open \"${url}\"`);\n } catch (error) {\n try {\n execSync(`gnome-open \"${url}\"`);\n } catch (error) {\n execSync(`kde-open \"${url}\"`);\n }\n }\n break;\n default:\n throw new Error(`Unsupported platform: ${platform}`);\n }\n logger.success(`Opened URL in your default browser: ${url}`);\n } catch (error) {\n logger.error(`Failed to open URL: ${error instanceof Error ? error.message : String(error)}`);\n logger.info(`Please manually open this URL in your browser: ${url}`);\n }\n}\n\n/**\n * Pauses execution for the specified number of milliseconds\n * @param {number} ms - Time to sleep in milliseconds\n * @returns {Promise} Promise that resolves after the specified time\n */\nfunction sleep(ms) {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport const joinCommand = new Command()\n .name('join')\n .alias('free')\n .description('Join Phala Cloud! Get an account and deploy a CVM for FREE')\n .action(async () => {\n try {\n const inviteUrl = 'https://cloud.phala.network/register?invite=beta';\n const spinner =logger.startSpinner('Brewing a fresh cup of TEE 🍵');\n await sleep(2000);\n spinner.stop(true);\n logger.break();\n logger.break();\n console.log(logo);\n logger.info('TEE is served! Opening Phala Cloud registration page...');\n await sleep(1000);\n logger.break()\n openBrowser(inviteUrl);\n } catch (error) {\n logger.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n }); ","import { Command } from \"commander\";\nimport { logger } from \"@/src/utils/logger\";\nimport { getApiKey } from \"@/src/utils/credentials\";\nimport { getUserInfo } from \"@/src/api/auth\";\nimport { createCvm, getPubkeyFromCvm } from \"@/src/api/cvms\";\nimport { DEFAULT_IMAGE, CLOUD_URL } from \"@/src/utils/constants\";\nimport { demoTemplates } from \"@/src/utils/demo\";\nimport {\n\tencryptEnvVars,\n\ttype EnvVar,\n} from \"@phala/dstack-sdk/encrypt-env-vars\";\nimport inquirer from \"inquirer\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport { parseEnv } from \"@/src/utils/secrets\";\n\nexport const demoCommands = new Command()\n .name(\"demo\")\n .description(\"Demo commands to launch a demo on Phala Cloud\")\n .action(async () => {\n try {\n // 1. Check if the user is logged in\n const apiKey = await getApiKey();\n if (!apiKey) {\n logger.error(\"You need to be logged in to use the demo command\");\n logger.info(\"Please login with: phala auth login\");\n process.exit(1);\n }\n\n // Verify user credentials\n try {\n const spinner = logger.startSpinner(\"Verifying your credentials\");\n const userInfo = await getUserInfo();\n spinner.stop(true);\n logger.success(`Logged in as ${userInfo.username}`);\n } catch (error) {\n logger.error(\"Authentication failed. Your API key may be invalid or expired.\");\n logger.info(\"Please set a new API key with: phala auth login\");\n process.exit(1);\n }\n\n // 2. Get list of available templates\n const templates = Object.values(demoTemplates);\n\n if (templates.length === 0) {\n logger.error(\"No template files found in the templates directory\");\n process.exit(1);\n }\n\n // 3. Prompt user to select a template\n const { selectedTemplate } = await inquirer.prompt([\n {\n type: \"list\",\n name: \"selectedTemplate\",\n message: \"Select a template to deploy:\",\n choices: templates.map(t => ({\n name: t.name,\n value: t\n }))\n }\n ]);\n\n // 4. Read the selected template\n const templateContent = selectedTemplate.compose;\n logger.success(`Selected template: ${selectedTemplate.name}`);\n\n // 5. Generate a random token for services that might need it\n const token = crypto.randomBytes(16).toString(\"hex\");\n const envVars = parseEnv([`TOKEN=${token}`], \"\");\n \n \n // 6. Ask for CVM name\n const { cvmName } = await inquirer.prompt([\n {\n type: \"input\",\n name: \"cvmName\",\n message: \"Enter a name for your CVM:\",\n default: `${selectedTemplate.name.replace(\" \", \"-\")}`,\n validate: (input) => {\n if (!input.trim()) {\n return \"CVM name is required\";\n }\n return true;\n }\n }\n ]);\n\n // 7. Deploy the CVM with the specified resources\n logger.info(\"Preparing to deploy your CVM...\");\n \n // Prepare VM configuration with specified resources\n const vmConfig = {\n teepod_id: 3,\n name: cvmName,\n image: DEFAULT_IMAGE,\n vcpu: 2,\n memory: 2048,\n disk_size: 20,\n compose_manifest: {\n docker_compose_file: templateContent,\n docker_config: {\n url: \"\",\n username: \"\",\n password: \"\",\n },\n features: [\"kms\", \"tproxy-net\"],\n kms_enabled: true,\n manifest_version: 2,\n name: cvmName,\n public_logs: true,\n public_sysinfo: true,\n tproxy_enabled: true,\n },\n listed: false,\n };\n\n // Get public key from CVM for the API call structure\n const spinner = logger.startSpinner(\"Preparing CVM configuration\");\n const pubkey = await getPubkeyFromCvm(vmConfig);\n spinner.stop(true);\n \n if (!pubkey) {\n logger.error(\"Failed to prepare CVM configuration\");\n process.exit(1);\n }\n\n const encrypted_env = await encryptEnvVars(\n\t\t\t\t\t\t\tenvVars,\n\t\t\t\t\t\t\tpubkey.app_env_encrypt_pubkey,\n\t\t\t\t\t\t);\n\n logger.debug(\"Public key:\", pubkey.app_env_encrypt_pubkey);\n logger.debug(\"Encrypted environment variables:\", encrypted_env);\n // Create the CVM\n const createSpinner = logger.startSpinner(\"Creating your demo CVM\");\n const response = await createCvm({\n ...vmConfig,\n encrypted_env,\n app_env_encrypt_pubkey: pubkey.app_env_encrypt_pubkey,\n app_id_salt: pubkey.app_id_salt,\n });\n createSpinner.stop(true);\n\n if (!response) {\n logger.error(\"Failed to create demo CVM\");\n process.exit(1);\n }\n\n logger.success(\"Demo CVM created successfully! 🎉\");\n logger.break();\n \n const tableData = {\n \"CVM ID\": response.id,\n \"Name\": response.name,\n \"Status\": response.status,\n \"App ID\": `app_${response.app_id}`,\n \"App URL\": response.app_url ? response.app_url : `${CLOUD_URL}/dashboard/cvms/app_${response.app_id}`,\n \"Template\": selectedTemplate.name,\n \"Resources\": \"2 vCPUs, 2GB RAM, 20GB Storage\",\n };\n \n if (selectedTemplate.name.includes(\"Jupyter Notebook\")) {\n tableData[\"Jupyter Token\"] = token;\n tableData[\"Access Instructions\"] = \"Access your Jupyter notebook using the token above. Go to 'Network' tab to see the public URL.\";\n }\n \n logger.keyValueTable(tableData, {\n borderStyle: \"rounded\"\n });\n\n logger.break();\n logger.success(`Your demo is being created. You can check its status with:\\nphala cvms get app_${response.app_id}`);\n\n } catch (error) {\n logger.error(`Failed to launch demo: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n","const jupyterCompose = `version: '3'\nservices:\n jupyter:\n image: quay.io/jupyter/base-notebook\n ports:\n - 8080:8888\n volumes:\n - /var/run/tappd.sock:/var/run/tappd.sock\n environment:\n - GRANT_SUDO=yes\n user: root\n command: \"start-notebook.sh --NotebookApp.token=\\${TOKEN}\"\n`;\n\nexport const httpbinCompose = `version: '3'\nservices:\n httpbin:\n image: kennethreitz/httpbin:latest\n ports:\n - \"80:80\"\n`;\n\n\nexport const demoTemplates = {\n jupyter: {\n compose: jupyterCompose,\n name: \"Jupyter Notebook\",\n },\n httpbin: {\n compose: httpbinCompose,\n name: \"HTTPBin\",\n },\n};\n","import { Command } from 'commander';\nimport { listNodes } from './list.js';\n\nexport const nodesCommand = new Command()\n .name('nodes')\n .description('List and manage TEE nodes')\n .action(listNodes)\n .addCommand(\n new Command('list')\n .description('List all available worker nodes')\n .alias('ls')\n .action(listNodes)\n );\n","import { getTeepods } from '@/src/api/teepods';\nimport { logger } from '@/src/utils/logger';\nimport { KmsListItem, TEEPod } from '@/src/api/types';\n\nexport async function listNodes() {\n try {\n const { nodes: teepods, kms_list: kmsList } = await getTeepods();\n\n if (teepods.length === 0) {\n logger.info('No available nodes found.');\n return;\n }\n\n logger.info('Available Nodes:');\n teepods.forEach((teepod: TEEPod) => {\n logger.info('----------------------------------------');\n logger.info(` ID: ${teepod.teepod_id}`);\n logger.info(` Name: ${teepod.name}`);\n logger.info(` Region: ${teepod.region_identifier}`);\n logger.info(` FMSPC: ${teepod.fmspc || 'N/A'}`);\n logger.info(` Device ID: ${teepod.device_id || 'N/A'}`);\n logger.info(` Support Onchain KMS: ${teepod.support_onchain_kms}`);\n \n logger.info(' Images:');\n if (teepod.images && teepod.images.length > 0) {\n teepod.images.forEach(img => {\n logger.info(` - ${img.name}`);\n logger.info(` Hash: ${img.os_image_hash || 'N/A'}`);\n });\n } else {\n logger.info(' N/A');\n }\n });\n\n if (kmsList && kmsList.length > 0) {\n logger.info('\\nAvailable KMS Instances:');\n kmsList.forEach((kms: KmsListItem) => {\n logger.info('----------------------------------------');\n logger.info(` ID: ${kms.id}`);\n logger.info(` URL: ${kms.url}`);\n logger.info(` Version: ${kms.version}`);\n logger.info(` Chain ID: ${kms.chain_id}`);\n logger.info(` Contract Address: ${kms.kms_contract_address}`);\n logger.info(` Gateway App ID: ${kms.gateway_app_id}`);\n });\n }\n } catch (error) {\n logger.error(`Failed to list available nodes: ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n}\n"],"mappings":"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","names":["Command","chalk","logoColor","logo","smallLogo","minimalLogo","Command","Command","prompts","loginCommand","Command","apiKey","checkUserInfo","prompts","value","saveApiKey","getUserInfo","removeApiKey","logger","CLOUD_URL","error","Command","logoutCommand","Command","removeApiKey","logger","error","Command","statusCommand","Command","options","apiKey","getApiKey","logger","spinner","userInfo","getUserInfo","tableData","error","authCommands","Command","loginCommand","logoutCommand","statusCommand","Command","Command","execa","fs","path","Handlebars","exec","spawn","promisify","os","inquirer","fs","path","validateFileExists","filePath","basePath","resolvedPath","path","fs","promptForFile","message","defaultValue","name","inquirer","input","detectFileInCurrentDir","possibleFiles","logMessage","file","logger","fs","path","os","execSync","spawn","net","SIMULATOR_CONFIG","isSimulatorInstalled","platform","extractedFolderPath","executablePath","error","logger","getPlatform","installSimulator","progressCallback","log","message","platformConfig","downloadUrl","execSync","runSimulator","options","executableName","runOptions","logDir","stdio","outputStream","simulatorProcess","spawn","timestamp","setSimulatorEndpointEnv","isSimulatorRunning","platform","getPlatform","platformConfig","SIMULATOR_CONFIG","socketPath","resolve","client","host","error","logger","stopSimulator","execSync","stopped","deleteSimulatorEndpointEnv","getSimulatorEndpoint","getPlatform","setSimulatorEndpointEnv","endpoint","simulatorEndpoint","envEndpoint","execSync","logger","error","deleteSimulatorEndpointEnv","execAsync","promisify","exec","LOGS_DIR","COMPOSE_FILES_DIR","MAX_CONSOLE_LINES","DockerService","image","username","registry","logsPath","path","fs","operation","timestamp","arch","os","command","args","resolve","reject","proc","spawn","logFile","logStream","consoleBuffer","processOutput","data","isError","lines","line","bufferedLine","code","err","dockerfile","tag","fullImageName","spinner","logger","validateFileExists","buildArgs","error","imageName","getDockerCredentials","password","execa","loginError","homeDir","dockerConfigPath","dockerConfig","envFile","templateType","template","DOCKER_COMPOSE_ELIZA_V2_TEMPLATE","DOCKER_COMPOSE_BASIC_TEMPLATE","validatedTemplate","ComposeTemplateSchema","composePath","envVars","commentIndex","key","value","trimmedKey","composeContent","Handlebars","env","composeFile","composeArgs","port","stdout","containerId","setSimulatorEndpointEnv","deleteSimulatorEndpointEnv","prompts","loginCommand","Command","options","username","password","registry","logger","response","value","dockerService","DockerService","saveDockerCredentials","error","Command","path","inquirer","fs","buildCommand","Command","options","credentials","getDockerCredentials","logger","response","inquirer","input","defaultPath","path","fs","promptForFile","dockerfilePath","DockerService","error","Command","inquirer","pushCommand","Command","options","credentials","getDockerCredentials","logger","imageName","localImages","DockerService","uniqueImageNames","img","selectedImage","error","Command","inquirer","fs","path","generateCommand","Command","options","credentials","getDockerCredentials","logger","imageName","localImages","DockerService","uniqueImageNames","img","selectedImage","inquirer","envFilePath","validateFileExists","defaultEnvPath","path","fs","useDefault","envPath","input","outputPath","confirmOverwrite","customPath","dockerService","composePath","outputDir","error","dockerCommands","Command","loginCommand","buildCommand","pushCommand","generateCommand","Command","Command","startCommand","Command","TEE_SIMULATOR","options","DockerService","logger","isSimulatorInstalled","installSimulator","isSimulatorRunning","simulatorProcess","runSimulator","error","Command","stopCommand","Command","options","DockerService","logger","stopSimulator","error","simulatorCommands","Command","startCommand","stopCommand","Command","Command","chalk","listCommand","Command","options","spinner","logger","cvms","getCvms","cvm","CLOUD_URL","error","Command","chalk","resolveCvmAppId","appId","selectedCvm","selectCvm","checkCvmExists","getCommand","Command","appId","options","resolvedAppId","resolveCvmAppId","spinner","logger","cvm","getCvmByAppId","chalk","CLOUD_URL","error","Command","startCommand","Command","appId","resolvedAppId","resolveCvmAppId","spinner","logger","response","startCvm","tableData","CLOUD_URL","error","Command","stopCommand","Command","appId","resolvedAppId","resolveCvmAppId","spinner","logger","response","stopCvm","tableData","CLOUD_URL","error","Command","restartCommand","Command","appId","resolvedAppId","resolveCvmAppId","spinner","logger","response","restartCvm","tableData","CLOUD_URL","error","Command","chalk","attestationCommand","Command","appId","options","resolvedAppId","checkCvmExists","logger","selectedCvm","selectCvm","spinner","attestationData","getCvmAttestation","summaryData","cert","index","certData","tcbBasicInfo","maxEntriesToShow","entries","entry","error","Command","encryptEnvVars","fs","path","inquirer","fs","parseEnv","envs","envFile","envVars","env","key","valueParts","value","envFileContent","line","delimiterIndex","inQuotes","quoteChar","i","valueInQuotes","valueQuoteChar","commentStartIndex","firstChar","lastChar","createCommand","Command","DEFAULT_VCPU","DEFAULT_MEMORY","DEFAULT_DISK_SIZE","options","name","inquirer","input","composeFileName","detectFileInCurrentDir","promptForFile","composePath","path","fs","logger","composeString","deleteSimulatorEndpointEnv","envs","parseEnv","error","shouldSkip","envVars","vcpu","memory","diskSize","teepodsSpinner","teepods","getTeepods","selectedTeepod","pod","selectedImage","image","DEFAULT_IMAGE","vmConfig","spinner","pubkey","getPubkeyFromCvm","encryptSpinner","encrypted_env","encryptEnvVars","createSpinner","response","createCvm","tableData","CLOUD_URL","Command","inquirer","deleteCommand","Command","appId","options","resolvedAppId","resolveCvmAppId","confirm","inquirer","logger","spinner","success","deleteCvm","error","Command","fs","encryptEnvVars","upgradeCommand","Command","appId","options","resolvedAppId","resolveCvmAppId","spinner","logger","currentCvm","getCvmByAppId","composeFileName","detectFileInCurrentDir","promptForFile","composeString","fs","error","deleteSimulatorEndpointEnv","encrypted_env","envs","parseEnv","encryptEnvVars","vm_config","upgradeSpinner","response","upgradeCvm","CLOUD_URL","Command","inquirer","chalk","resizeCommand","Command","appId","options","resolvedAppId","resolveCvmAppId","cvm","getCvmByAppId","vcpu","memory","diskSize","allowRestart","inquirer","input","num","confirmMessage","logger","chalk","confirm","spinner","resizeCvm","CLOUD_URL","error","Command","listNodesCommand","Command","teepods","kmsList","getTeepods","logger","teepod","img","kms","error","Command","encryptEnvVars","fs","path","replicateCommand","Command","cvmId","options","encryptedEnv","envPath","envVars","line","key","value","cvmConfig","getCvmComposeConfig","logger","requestBody","replica","replicateCvm","tableData","error","cvmsCommand","Command","attestationCommand","createCommand","deleteCommand","getCommand","listCommand","startCommand","stopCommand","resizeCommand","restartCommand","upgradeCommand","listNodesCommand","replicateCommand","Command","execSync","os","openBrowser","url","platform","execSync","logger","error","sleep","ms","resolve","joinCommand","Command","inviteUrl","spinner","logo","Command","jupyterCompose","httpbinCompose","demoTemplates","encryptEnvVars","inquirer","crypto","demoCommands","Command","getApiKey","logger","spinner","userInfo","getUserInfo","templates","demoTemplates","selectedTemplate","inquirer","t","templateContent","token","crypto","envVars","parseEnv","cvmName","input","vmConfig","DEFAULT_IMAGE","pubkey","getPubkeyFromCvm","encrypted_env","encryptEnvVars","createSpinner","response","createCvm","tableData","CLOUD_URL","error","Command","listNodes","teepods","kmsList","getTeepods","logger","teepod","img","kms","error","nodesCommand","Command","listNodes","main","Command","logo","authCommands","cvmsCommand","dockerCommands","simulatorCommands","demoCommands","joinCommand","nodesCommand","error","logger"]}
|