phala 1.0.19 → 1.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{$ as Ee,N as A,O as ve,P as q,Q as N,R as J,T as Q,U as ke,V as we,W as be,X as Se,Y as _e,_ as Z,a as e,aa as $e,b as ie,ba as De,c as W,ca as xe,d as U,da as R,e as ne,f as _,g as h,h as ae,i as se,j as me,k as O,l as he,m as ye,p as Ce}from"./chunk-X3GHW5ET.js";import{Command as br}from"commander";import Ie from"chalk";var Ae=Ie.hex("#cdfa50"),X=Ae(`
2
+ import{$ as $e,N as A,O as ke,P as q,Q as N,R as J,T as Q,U as we,V as be,W as Se,X as Ee,Y as _e,_ as Z,a as e,aa as De,b as oe,ba as xe,c as W,ca as Ie,d as U,da as L,e as ie,f as $,g as y,h as ne,i as ae,j as se,k as O,l as ye,m as ve,p as Ce}from"./chunk-X3GHW5ET.js";import{Command as $r}from"commander";import Pe from"chalk";var Ae=Pe.hex("#cdfa50"),X=Ae(`
3
3
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28C0\u28E0\u28E4\u28E4\u28E4\u28C0\u2840\u2800\u2880\u28C0\u28E4\u28E4\u28C0\u2840\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800
4
4
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2880\u28F4\u287F\u281B\u2809\u2801\u2800\u2808\u2809\u281B\u283F\u281B\u2809\u2809\u2809\u2809\u2819\u2837\u28C4\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800
5
5
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28A0\u28FF\u280B\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2818\u28E7\u2800\u2800\u2800\u2800\u2800\u2800\u2800
@@ -21,7 +21,7 @@ import{$ as Ee,N as A,O as ve,P as q,Q as N,R as J,T as Q,U as ke,V as we,W as b
21
21
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28B8\u28C6\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2809\u281B\u283F\u283F\u28FF\u28FF\u28FF\u28FF\u28FF\u283F\u281F\u280B\u2801\u2800\u2800\u2800\u2800\u2800\u2800\u28C0\u28FE\u2800\u2800\u2800\u2800\u2800\u2800\u2800
22
22
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2819\u283B\u28B6\u28E6\u28E4\u28C4\u28C0\u28C0\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28C0\u28C0\u28C0\u28E4\u28F4\u28F6\u283F\u281B\u2801\u2800\u2800\u2800\u2800\u2800\u2800\u2800
23
23
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2808\u2809\u2819\u281B\u283B\u283F\u283F\u283F\u283F\u28BF\u28FF\u28FF\u28FF\u283F\u283F\u283F\u283F\u281F\u281B\u281B\u2809\u2801\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800
24
- `),Er=Ae(`
24
+ `),Ir=Ae(`
25
25
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28C0\u28E0\u28E4\u28E4\u28E4\u28C0\u2840\u2800\u2880\u28C0\u28E4\u28E4\u28C0\u2840\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800
26
26
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2880\u28F4\u287F\u281B\u2809\u2801\u2800\u2808\u2809\u281B\u283F\u281B\u2809\u2809\u2809\u2809\u2819\u2837\u28C4\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800
27
27
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28A0\u28FF\u280B\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2818\u28E7\u2800\u2800\u2800\u2800\u2800\u2800\u2800
@@ -43,27 +43,27 @@ import{$ as Ee,N as A,O as ve,P as q,Q as N,R as J,T as Q,U as ke,V as we,W as b
43
43
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28B8\u28C6\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2809\u281B\u283F\u283F\u28FF\u28FF\u28FF\u28FF\u28FF\u283F\u281F\u280B\u2801\u2800\u2800\u2800\u2800\u2800\u2800\u28C0\u28FE\u2800\u2800\u2800\u2800\u2800\u2800\u2800
44
44
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2819\u283B\u28B6\u28E6\u28E4\u28C4\u28C0\u28C0\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28C0\u28C0\u28C0\u28E4\u28F4\u28F6\u283F\u281B\u2801\u2800\u2800\u2800\u2800\u2800\u2800\u2800
45
45
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2808\u2809\u2819\u281B\u283B\u283F\u283F\u283F\u283F\u28BF\u28FF\u28FF\u28FF\u283F\u283F\u283F\u283F\u281F\u281B\u281B\u2809\u2801\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800
46
- `),$r=Ie.cyan("PHALA TEE CLOUD CLI");import{Command as It}from"commander";import{Command as Et}from"commander";import $t from"prompts";var Pe=new Et().name("login").description("Set the API key for authentication").argument("[api-key]","Phala Cloud API key to set").action(async o=>{try{let t;if(!o)o=(await $t({type:"password",name:"apiKey",message:"Enter your API key:",validate:async i=>{if(i.length===0)return"API key cannot be empty";try{if(await ie(i),t=await A(),!t.username)return await U(),"Invalid API key"}catch{return"Invalid API key"}return!0}})).apiKey;else if(await ie(o),t=await A(),!t.username)return await U(),"Invalid API key";e.success(`Welcome ${t.username}! API key validated and saved successfully`),e.break(),e.info(`Open in Web UI at ${h}/dashboard/`)}catch(t){e.error(`Failed to set API key: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as Dt}from"commander";var Fe=new Dt().name("logout").description("Remove the stored API key").action(async()=>{try{await U(),e.success("API key removed successfully")}catch(o){e.error(`Failed to remove API key: ${o instanceof Error?o.message:String(o)}`),process.exit(1)}});import{Command as xt}from"commander";var Te=new xt().name("status").description("Check authentication status").option("-j, --json","Output in JSON format").option("-d, --debug","Enable debug output").action(async o=>{try{o.debug&&(process.env.DEBUG="true");let t=await W();if(!t){e.warn('Not authenticated. Please set an API key with "phala auth login"');return}e.debug(`Using API key: ${t.substring(0,5)}...`);let r=e.startSpinner("Checking authentication status");try{let i=await A();if(r.stop(!0),o.json){console.log(JSON.stringify(i,null,2));return}e.break(),e.success(`Authenticated as ${i.username}`);let n={Username:i.username,Email:i.email,Role:i.role,Team:`${i.team_name} (${i.team_tier})`,Credits:`$${(i.credits+i.granted_credits).toFixed(2)}`};i.trial_ended_at&&(n["Trial Ended At"]=i.trial_ended_at),e.keyValueTable(n,{borderStyle:"rounded"})}catch(i){r.stop(!1),e.error("Authentication failed. Your API key may be invalid or expired."),e.info('Please set a new API key with "phala auth login"'),o.debug&&e.debug(`Error details: ${i instanceof Error?i.message:String(i)}`)}}catch(t){e.error(`Failed to check authentication status: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});var Me=new It().name("auth").description("Authenticate with Phala Cloud").addCommand(Pe).addCommand(Fe).addCommand(Te);import{Command as Gt}from"commander";import{Command as Ut}from"commander";import{execa as Tt}from"execa";import $ from"node:fs";import K from"node:path";import Mt from"handlebars";import{exec as Vt,spawn as Nt}from"node:child_process";import{promisify as Rt}from"node:util";import Ue from"node:os";import At from"inquirer";import ce from"node:fs";import pe from"node:path";function P(o,t=process.cwd()){let r=pe.resolve(t,o);if(!ce.existsSync(r))throw new Error(`File not found at ${r}`);return!0}async function F(o,t,r="file",i=process.cwd()){return(await At.prompt([{type:"input",name:r,message:o,default:t,validate:m=>{let a=pe.resolve(i,m);return ce.existsSync(a)?!0:`File not found at ${a}`}}]))[r]}function ee(o,t){for(let r of o){let i=pe.join(process.cwd(),r);if(ce.existsSync(i))return t?e.info(t.replace("{path}",i)):e.info(`File detected: ${i}`),r}}import*as C from"node:fs";import*as E from"node:path";import*as T from"node:os";import{execSync as L,spawn as Pt}from"node:child_process";import*as le from"node:net";var v={version:"0.5.3",baseUrl:"https://github.com/Dstack-TEE/dstack/releases/download/v0.5.3",installDir:E.join(T.homedir(),".phala-cloud","dstack-simulator"),defaultLogPath:E.join(T.homedir(),".phala-cloud","logs","dstack-simulator.log"),platforms:{darwin:{filename:"dstack-simulator-0.5.3-aarch64-apple-darwin.tgz",extractedFolder:"dstack-simulator-0.5.3-aarch64-apple-darwin",socketPath:E.join(T.homedir(),".phala-cloud","dstack-simulator","dstack-simulator-0.5.3-aarch64-apple-darwin","dstack.sock"),socketArg:"unix:/tmp/dstack.sock"},linux:{filename:"dstack-simulator-0.5.3-x86_64-linux-musl.tgz",extractedFolder:"dstack-simulator-0.5.3-x86_64-linux-musl",socketPath:"/tmp/dstack.sock",socketArg:"unix:/tmp/dstack.sock"},win32:{filename:"dstack-simulator-0.5.3-x86_64-pc-windows-msvc.tgz",extractedFolder:"dstack-simulator-0.5.3-x86_64-pc-windows-msvc",socketPath:"127.0.0.1:8090",socketArg:"127.0.0.1:8090"}}};function Ve(){try{if(!C.existsSync(v.installDir))return!1;let o=T.platform();if(!v.platforms[o])throw new Error(`Unsupported platform: ${o}`);let t=E.join(v.installDir,v.platforms[o].extractedFolder);if(!C.existsSync(t))return!1;let i=E.join(t,o==="win32"?"dstack-simulator.exe":"dstack-simulator");return C.existsSync(i)}catch(o){return e.error("Error checking if simulator is installed:",o),!1}}function z(){let o=T.platform();if(!v.platforms[o])throw new Error(`Unsupported platform: ${o}. Only darwin, linux, and win32 are supported.`);return o}async function Ne(o){let t=r=>{e.info(r),o&&o(r)};try{let r=z(),i=v.platforms[r];if(r==="win32")throw new Error("Windows platform is currently not supported. Support will be added in a future release.");C.existsSync(v.installDir)||(e.info(`Creating installation directory at ${v.installDir}`),C.mkdirSync(v.installDir,{recursive:!0})),process.chdir(v.installDir);let n=`${v.baseUrl}/${i.filename}`;e.info(`Downloading simulator from ${n}`),L(`wget ${n}`,{stdio:"inherit"}),e.info(`Extracting ${i.filename}`),L(`tar -xvf ${i.filename}`,{stdio:"inherit"}),e.success("Simulator installation completed successfully")}catch(r){throw e.error("Error installing simulator:",r),new Error(`Failed to install simulator: ${r}`)}}async function Re(o={}){try{let t=z(),r=v.platforms[t],i=E.join(v.installDir,r.extractedFolder);process.chdir(i);let n=t==="win32"?"dstack-simulator.exe":"./dstack-simulator",m={background:o.background??!0,logToFile:o.logToFile??!0,logFilePath:o.logFilePath??v.defaultLogPath};if(m.logToFile){let l=E.dirname(m.logFilePath);C.existsSync(l)||C.mkdirSync(l,{recursive:!0}),e.info(`Simulator logs will be written to: ${m.logFilePath}`)}e.info(`Starting simulator with: ${n}`);let a=m.logToFile?["ignore",C.openSync(m.logFilePath,"a"),C.openSync(m.logFilePath,"a")]:"inherit",c=Pt(n,[],{stdio:a,shell:t==="win32",detached:m.background});if(m.logToFile&&Array.isArray(a)&&(typeof a[1]=="number"&&C.closeSync(a[1]),typeof a[2]=="number"&&C.closeSync(a[2])),m.logToFile){let s=`
46
+ `),Pr=Pe.cyan("PHALA TEE CLOUD CLI");import{Command as At}from"commander";import{Command as Dt}from"commander";import xt from"prompts";var Fe=new Dt().name("login").description("Set the API key for authentication").argument("[api-key]","Phala Cloud API key to set").action(async o=>{try{let t;if(!o)o=(await xt({type:"password",name:"apiKey",message:"Enter your API key:",validate:async i=>{if(i.length===0)return"API key cannot be empty";try{if(await oe(i),t=await A(),!t.username)return await U(),"Invalid API key"}catch{return"Invalid API key"}return!0}})).apiKey;else if(await oe(o),t=await A(),!t.username)return await U(),"Invalid API key";e.success(`Welcome ${t.username}! API key validated and saved successfully`),e.break(),e.info(`Open in Web UI at ${y}/dashboard/`)}catch(t){e.error(`Failed to set API key: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as It}from"commander";var Te=new It().name("logout").description("Remove the stored API key").action(async()=>{try{await U(),e.success("API key removed successfully")}catch(o){e.error(`Failed to remove API key: ${o instanceof Error?o.message:String(o)}`),process.exit(1)}});import{Command as Pt}from"commander";var Me=new Pt().name("status").description("Check authentication status").option("-j, --json","Output in JSON format").option("-d, --debug","Enable debug output").action(async o=>{try{o.debug&&(process.env.DEBUG="true");let t=await W();if(!t){e.warn('Not authenticated. Please set an API key with "phala auth login"');return}e.debug(`Using API key: ${t.substring(0,5)}...`);let r=e.startSpinner("Checking authentication status");try{let i=await A();if(r.stop(!0),o.json){console.log(JSON.stringify(i,null,2));return}e.break(),e.success(`Authenticated as ${i.username}`);let n={Username:i.username,Email:i.email,Role:i.role,Team:`${i.team_name} (${i.team_tier})`,Credits:`$${(i.credits+i.granted_credits).toFixed(2)}`};i.trial_ended_at&&(n["Trial Ended At"]=i.trial_ended_at),e.keyValueTable(n,{borderStyle:"rounded"})}catch(i){r.stop(!1),e.error("Authentication failed. Your API key may be invalid or expired."),e.info('Please set a new API key with "phala auth login"'),o.debug&&e.debug(`Error details: ${i instanceof Error?i.message:String(i)}`)}}catch(t){e.error(`Failed to check authentication status: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});var Ve=new At().name("auth").description("Authenticate with Phala Cloud").addCommand(Fe).addCommand(Te).addCommand(Me);import{Command as qt}from"commander";import{Command as Kt}from"commander";import{execa as Nt}from"execa";import D from"node:fs";import j from"node:path";import Lt from"handlebars";import{exec as Ut,spawn as Ot}from"node:child_process";import{promisify as zt}from"node:util";import ze from"node:os";import Ft from"inquirer";import me from"node:fs";import ce from"node:path";function F(o,t=process.cwd()){let r=ce.resolve(t,o);if(!me.existsSync(r))throw new Error(`File not found at ${r}`);return!0}async function T(o,t,r="file",i=process.cwd()){return(await Ft.prompt([{type:"input",name:r,message:o,default:t,validate:s=>{let a=ce.resolve(i,s);return me.existsSync(a)?!0:`File not found at ${a}`}}]))[r]}function ee(o,t){for(let r of o){let i=ce.join(process.cwd(),r);if(me.existsSync(i))return t?e.info(t.replace("{path}",i)):e.info(`File detected: ${i}`),r}}import*as h from"node:fs";import*as b from"node:path";import*as _ from"node:os";import{execSync as M,spawn as Tt}from"node:child_process";import*as pe from"node:net";var C={version:"0.5.3",baseUrl:"https://github.com/Dstack-TEE/dstack/releases/download/v0.5.3",installDir:b.join(_.homedir(),".phala-cloud","simulator"),defaultLogPath:b.join(_.homedir(),".phala-cloud","logs","dstack-simulator.log"),platforms:{darwin:{filename:"dstack-simulator-0.5.3-aarch64-apple-darwin.tgz",extractedFolder:"0.5.3",socketPath:b.join(_.homedir(),".phala-cloud","simulator","0.5.3","dstack.sock")},linux:{filename:"dstack-simulator-0.5.3-x86_64-linux-musl.tgz",extractedFolder:"0.5.3",socketPath:b.join(_.homedir(),".phala-cloud","simulator","0.5.3","dstack.sock")},win32:{filename:"dstack-simulator-0.5.3-x86_64-pc-windows-msvc.tgz",extractedFolder:"dstack-simulator-0.5.3-x86_64-pc-windows-msvc",socketPath:"127.0.0.1:8090"}}};function Re(){try{if(!h.existsSync(C.installDir))return!1;let o=_.platform();if(!C.platforms[o])throw new Error(`Unsupported platform: ${o}`);let t=b.join(C.installDir,C.platforms[o].extractedFolder);if(!h.existsSync(t))return!1;let i=b.join(t,o==="win32"?"dstack-simulator.exe":"dstack-simulator");return h.existsSync(i)}catch(o){return e.error("Error checking if simulator is installed:",o),!1}}function z(){let o=_.platform();if(!C.platforms[o])throw new Error(`Unsupported platform: ${o}. Only darwin, linux, and win32 are supported.`);return o}async function Ne(o){let t=r=>{e.info(r),o&&o(r)};try{let r=z(),i=C.platforms[r];if(r==="win32"){try{M("tar --version",{stdio:"ignore"})}catch{throw new Error("Windows 10 build 17063 or later is required (includes tar command). Please update your Windows version.")}throw new Error("Windows platform is currently not supported. Support will be added in a future release.")}h.existsSync(C.installDir)||(e.info(`Creating installation directory at ${C.installDir}`),h.mkdirSync(C.installDir,{recursive:!0})),process.chdir(C.installDir);let n=`${C.baseUrl}/${i.filename}`;e.info(`Downloading simulator from ${n}`),M(`wget ${n}`,{stdio:"inherit"});let s=b.join(C.installDir,i.extractedFolder);h.existsSync(s)||h.mkdirSync(s,{recursive:!0}),e.info(`Extracting ${i.filename} to ${s}`);let a=`tar -xvf "${i.filename}" -C "${s}" --strip-components=1`;e.debug(`Running: ${a}`);try{M(a,{stdio:"inherit"}),h.unlinkSync(i.filename)}catch(c){throw e.error(`Failed to extract ${i.filename}:`,c),new Error("Failed to extract simulator archive. Make sure you have sufficient permissions and disk space.")}e.success("Simulator installation completed successfully")}catch(r){throw e.error("Error installing simulator:",r),new Error(`Failed to install simulator: ${r}`)}}var le=()=>b.join(_.tmpdir(),"dstack-simulator.pid");function Mt(o){return Buffer.byteLength(o,"utf8")>104}function Le(){try{let o=le();if(h.existsSync(o)){let t=parseInt(h.readFileSync(o,"utf-8").trim(),10);try{return process.kill(t,0),t}catch{h.unlinkSync(o)}}return null}catch(o){return e.warn("Error checking simulator PID:",o),null}}function Vt(o){try{let t=le();e.info(`Saving simulator PID ${o} to: ${t}`),h.writeFileSync(t,o.toString(),"utf-8")}catch(t){e.warn("Failed to save simulator PID:",t)}}async function Ue(o={}){try{let t=z(),r=C.platforms[t],i=b.join(C.installDir,r.extractedFolder),n=Le();if(n)throw new Error(`Simulator is already running with PID: ${n}`);if(t!=="win32"&&Mt(r.socketPath))throw new Error(`Socket path is too long (${r.socketPath.length} chars, max 104): ${r.socketPath}`);if(t!=="win32"&&h.existsSync(r.socketPath)){e.warn(`Removing existing socket file: ${r.socketPath}`);try{h.unlinkSync(r.socketPath)}catch(m){e.warn(`Failed to remove existing socket file: ${m}`)}}process.chdir(i);let s=t==="win32"?"dstack-simulator.exe":"./dstack-simulator";t!=="win32"&&e.info(`Using socket path: ${r.socketPath}`);let a={background:o.background??!0,logToFile:o.logToFile??!0,logFilePath:o.logFilePath??C.defaultLogPath};if(a.logToFile){let m=b.dirname(a.logFilePath);h.existsSync(m)||h.mkdirSync(m,{recursive:!0}),e.info(`Simulator logs will be written to: ${a.logFilePath}`)}e.info(`Starting simulator with: ${s}`);let c=a.logToFile?["ignore",h.openSync(a.logFilePath,"a"),h.openSync(a.logFilePath,"a")]:"inherit",l=Tt(s,[],{stdio:c,shell:t==="win32",detached:a.background});if(a.logToFile&&Array.isArray(c)&&(typeof c[1]=="number"&&h.closeSync(c[1]),typeof c[2]=="number"&&h.closeSync(c[2])),a.logToFile){let u=`
47
47
  === Simulator started at ${new Date().toISOString()} ===
48
- Command: ${n}
48
+ Command: ${s}
49
49
 
50
- `;C.appendFileSync(m.logFilePath,s)}return m.background&&(c.unref(),e.success("Simulator is running in the background")),await de(),c}catch(t){throw e.error("Error running simulator:",t),new Error(`Failed to run simulator: ${t}`)}}async function te(){try{let o=z(),t=v.platforms[o];if(o==="darwin"||o==="linux"){let r=t.socketPath;return C.existsSync(r)?new Promise(i=>{let n=le.createConnection({path:r}).on("connect",()=>{n.end(),i(!0)}).on("error",()=>{i(!1)});setTimeout(()=>{n.end(),i(!1)},1e3)}):!1}if(o==="win32"){let r="127.0.0.1";return new Promise(n=>{let m=le.createConnection({host:r,port:8090}).on("connect",()=>{m.end(),n(!0)}).on("error",()=>{n(!1)});setTimeout(()=>{m.end(),n(!1)},1e3)})}return!1}catch(o){return e.error("Error checking if simulator is running:",o),!1}}async function Le(){try{let o=z();if(!await te())return e.info("Simulator is not running"),!0;e.info("Stopping simulator..."),o==="win32"?L(`for /f "tokens=5" %a in ('netstat -ano ^| findstr :8080') do taskkill /F /PID %a`,{stdio:"inherit"}):L("pkill -f dstack-simulator",{stdio:"inherit"});let t=!await te();return t?e.success("Simulator stopped successfully"):e.error("Failed to stop simulator"),await M(),t}catch(o){return e.error("Error stopping simulator:",o),!1}}function Ft(){let o=z(),t=v.platforms[o];return o==="win32"?"http://127.0.0.1:8090":`${t.socketPath||"/tmp/dstack.sock"}`}async function de(o){try{let t=Ft(),r=o||t;return await L(`export DSTACK_SIMULATOR_ENDPOINT=${r}`),e.success(`Setting DSTACK_SIMULATOR_ENDPOINT=${r} for current process`),o}catch(t){throw e.error("Error setting simulator endpoint environment variable:",t),new Error(`Failed to set simulator endpoint: ${t}`)}}async function M(){return await L("unset DSTACK_SIMULATOR_ENDPOINT"),e.debug("Deleted DSTACK_SIMULATOR_ENDPOINT from current process"),!0}var j=Rt(Vt),Oe=".phala-cloud/logs",Lt=".phala-cloud/compose",ze=10,b=class{username;image;registry;constructor(t,r,i){this.image=t,this.username=r||"",this.registry=i||""}ensureLogsDir(){let t=K.resolve(Oe);$.existsSync(t)||$.mkdirSync(t,{recursive:!0})}getLogFilePath(t,r){let i=new Date().toISOString().replace(/[:.]/g,"-");return K.resolve(Oe,`${r||this.image}-${t}-${i}.log`)}getSystemArchitecture(){let t=Ue.arch();switch(t){case"arm":case"arm64":return"arm64";case"x64":return"amd64";default:return t}}spawnProcess(t,r,i,n){return new Promise((m,a)=>{let c=Nt(t,r);this.ensureLogsDir();let l=this.getLogFilePath(i,n),s=$.createWriteStream(l,{flags:"a"}),f=[],g=(p,u=!1)=>{let y=p.toString().split(`
51
- `);s.write(p);for(let d of y)if(d.trim()){f.push(d),f.length>ze&&f.shift(),console.clear(),console.log(`Latest ${ze} lines (full log at ${l}):`),console.log("-".repeat(50));for(let I of f)u?console.error(I):console.log(I)}};c.stdout.on("data",p=>g(p)),c.stderr.on("data",p=>g(p,!0)),c.on("close",p=>{s.end(),p===0?(console.log(`
52
- Operation completed. Full log available at: ${l}`),m()):a(new Error(`Process exited with code ${p}. Check log file: ${l}`))}),c.on("error",p=>{s.end(),a(p)})})}setCredentials(t,r){this.username=t,r&&(this.registry=r)}async buildImage(t,r){try{let i=this.getSystemArchitecture(),n=`${this.username}/${this.image}:${r}`,m=e.startSpinner(`Building Docker image ${this.username}/${this.image}:${r}`);P(t);let a=["build","-t",n,"-f",t];return i==="arm64"&&(console.log("Detected arm64 architecture, using --platform linux/amd64"),a.push("--platform","linux/amd64")),a.push("."),await this.spawnProcess("docker",a,"build",this.image),m.stop(!0,`Docker image ${n} built successfully`),!0}catch(i){return e.error(`Failed to build Docker image: ${i instanceof Error?i.message:String(i)}`),!1}}async pushImage(t){try{let r=e.startSpinner(`Pushing Docker image ${t} to Docker Hub`);if(!await _())throw r.stop(!1),new Error('Docker credentials not found. Please log in first with "phala docker login"');let n=t;return console.log(`Pushing image ${n} to Docker Hub...`),await this.spawnProcess("docker",["push",n],"push",t.replace(/.*\/+([\w-]+):.*$/g,"$1")),r.stop(!0,`Docker image ${n} pushed successfully`),!0}catch(r){return e.error(`Failed to push Docker image: ${r instanceof Error?r.message:String(r)}`),!1}}async login(t,r,i){try{let n=e.startSpinner(`Logging in to Docker Hub as ${t}`);if(await this.checkLogin())return n.stop(!0,"Already logged in to Docker Hub"),this.setCredentials(t,i),!0;if(!r)throw n.stop(!1),new Error("Password is required for Docker login");try{await Tt("docker",["login",...i?[i]:[],"-u",t,"--password-stdin"],{input:r,timeout:1e4})}catch(a){throw a.timedOut?(n.stop(!1),new Error("Docker login timed out. Please check your credentials and try again.")):a}return n.stop(!0,"Logged in to Docker Hub successfully"),this.setCredentials(t,i),!0}catch(n){return e.error(`Failed to login to Docker Hub: ${n instanceof Error?n.message:String(n)}`),!1}}async checkLogin(){try{let t=Ue.homedir(),r=K.join(t,".docker","config.json");if(!$.existsSync(r))return!1;let i=JSON.parse($.readFileSync(r,"utf-8"));return!!(i?.auths&&Object.keys(i.auths).length>0)}catch(t){return e.debug(`Docker login check failed: ${t instanceof Error?t.message:String(t)}`),!1}}async buildComposeFile(t,r,i){if(!this.username)throw new Error("Docker Hub username is required for building compose file");let n=i==="eliza"?he:ye,m=Ce.parse({template:n}),a=K.resolve(Lt);$.existsSync(a)||(e.info(`Creating directory: ${a}`),$.mkdirSync(a,{recursive:!0}));let c=[];r&&(c=$.readFileSync(r,"utf-8").split(`
53
- `).filter(u=>u&&!u.startsWith("#")).map(u=>{let y=u.indexOf("#");return y>0&&(u=u.substring(0,y).trim()),u.trim()}).filter(u=>u.includes("=")).map(u=>{let[y,d]=u.split("=",2),I=y.trim();return(d?d.trim():"")===""?null:`${I}=${I}`}).filter(Boolean));let l=t,f=Mt.compile(m.template,{noEscape:!0})({imageName:l,envVars:c.map(p=>p.replace(/=.*/,`=\${${p.split("=")[0]}}`))}),g=K.join(a,`${t.replace(/.*\/+([\w-]+):.*$/g,"$1")}-tee-compose.yaml`);return $.writeFileSync(g,f),e.success(`Backup of docker compose file created at: ${g}`),g}async runComposeLocally(t,r){try{let i=e.startSpinner(`Running Docker Compose file at ${t}`);P(t);let n=["-f",t,"up","-d"];return r&&(P(r),n.splice(2,0,"--env-file",r)),await j(`docker compose ${n.join(" ")}`),i.stop(!0,"Docker Compose file running successfully"),!0}catch(i){return e.error(`Failed to run Docker Compose file: ${i instanceof Error?i.message:String(i)}`),!1}}async runSimulator(t,r){try{e.info(`Running TEE simulator with image ${t}`),e.info("Pulling latest simulator image..."),await j(`docker pull ${t}`),e.info("Starting simulator in background...");let{stdout:i}=await j(`docker run -d --name tee-simulator --rm -p ${r}:${r} ${t}`),n=i.trim();return e.success(`TEE simulator running successfully. Container ID: ${n}`),e.break(),e.break(),e.info("Useful commands:"),e.info(`- View logs: docker logs -f ${n}`),e.info(`- Stop simulator: docker stop ${n}`),de(`http://localhost:${r}`),!0}catch(i){return e.error(`Failed to run TEE simulator: ${i instanceof Error?i.message:String(i)}`),!1}}async stopSimulator(){try{let t=e.startSpinner("Stopping TEE simulator...");return await j("docker stop tee-simulator"),await M(),t.stop(!0,"TEE simulator stopped successfully"),!0}catch(t){return e.error(`Failed to stop TEE simulator: ${t instanceof Error?t.message:String(t)}`),!1}}static async listLocalImages(){try{let{stdout:t}=await j('docker images --format "{{.Repository}}:{{.Tag}}"'),i=(await _())?.username;return t.split(`
54
- `).filter(m=>m&&!m.includes("<none>")).filter(m=>m.includes(`${i}/`)).map(m=>({imageName:m}))}catch(t){return e.error(`Failed to list local Docker images: ${t instanceof Error?t.message:String(t)}`),[]}}};import Ke from"prompts";var je=new Ut().name("login").description("Login to Docker Hub").option("-u, --username <username>","Docker Hub username").option("-p, --password <password>","Docker Hub password").option("-r, --registry <registry>","Docker registry URL").action(async o=>{try{let t=o.username,r=o.password,i=o.registry;if(!t){e.info("First we need your Docker Hub username to check if you are already logged in.");let c=await Ke({type:"text",name:"username",message:"Enter your Docker Hub username:",validate:l=>l.length>0?!0:"Username cannot be empty"});c.username||(e.error("Username is required"),process.exit(1)),t=c.username}let n=new b("",t,i);if(await n.login(t)){e.success(`${t} is logged in to Docker Hub`),await ne({username:t,registry:i||null});return}if(!r){let c=await Ke({type:"password",name:"password",message:"Enter your Docker Hub password:",validate:l=>l.length>0?!0:"Password cannot be empty"});c.password||(e.error("Password is required"),process.exit(1)),r=c.password}await n.login(t,r,i)||(e.error("Failed to login to Docker Hub"),process.exit(1)),await ne({username:t,registry:i||null}),e.success("Logged in to Docker Hub successfully")}catch(t){e.error(`Failed to login to Docker Hub: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as Ot}from"commander";import Be from"node:path";import Ge from"inquirer";import zt from"node:fs";var He=new Ot().name("build").description("Build a Docker image").option("-i, --image <image>","Image name").option("-t, --tag <tag>","Image tag").option("-f, --file <file>","Path to Dockerfile","Dockerfile").action(async o=>{try{let t=await _();if(t||(e.error('Docker information not found. Please login first with "phala docker login"'),process.exit(1)),!o.image){let a=await Ge.prompt([{type:"input",name:"image",message:"Enter the Docker image name:",validate:c=>c.trim()?!0:"Image name is required"}]);o.image=a.image}if(!o.tag){let a=await Ge.prompt([{type:"input",name:"tag",message:"Enter the Docker image tag:",default:"latest",validate:c=>c.trim()?!0:"Tag is required"}]);o.tag=a.tag}let r=Be.resolve(process.cwd(),o.file);zt.existsSync(r)||(e.info(`Default Dockerfile not found at ${r}`),o.file=await F("Enter the path to your Dockerfile:","Dockerfile","file"));let i=Be.resolve(process.cwd(),o.file);await new b(o.image,t.username,t.registry).buildImage(i,o.tag)||(e.error("Failed to build Docker image"),process.exit(1)),e.success(`Docker image ${t.username}/${o.image}:${o.tag} built successfully`)}catch(t){e.error(`Failed to build Docker image: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as Kt}from"commander";import jt from"inquirer";var Ye=new Kt().name("push").description("Push a Docker image to Docker Hub").option("-i, --image <image>","Full image name (e.g. username/image:tag)").action(async o=>{try{let t=await _();t||(e.error('Docker information not found. Please login first with "phala docker login"'),process.exit(1));let r=o.image;if(!r){let m=await b.listLocalImages();if(m.length===0&&(e.error('No local Docker images found. Please build an image first with "phala docker build"'),process.exit(1)),!r){let a=Array.from(new Set(m.map(l=>l.imageName))),{selectedImage:c}=await jt.prompt([{type:"list",name:"selectedImage",message:"Select an image to push:",choices:a}]);r=c}}await new b("",t.username,t.registry).pushImage(r)||(e.error("Failed to push Docker image"),process.exit(1)),e.success(`Docker image ${r} pushed successfully`)}catch(t){e.error(`Failed to push Docker image: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as Bt}from"commander";import B from"inquirer";import G from"node:fs";import re from"node:path";var We=new Bt().name("generate").description("Generate a Docker Compose file").option("-i, --image <imageName>","Docker image name to use in the compose file (e.g. phala/phala-cloud)").option("-e, --env-file <envFile>","Path to environment variables file").option("-o, --output <output>","Output path for generated docker-compose.yml").option("--template <template>","Template to use for the generated docker-compose.yml").action(async o=>{try{let t=await _();(!t||!t.username)&&(e.error("Docker Hub username not found. Please login first with `phala docker login`"),process.exit(1));let r=o.image;if(!r){let c=await b.listLocalImages();if(c.length===0&&(e.error('No local Docker images found. Please build an image first with "phala docker build"'),process.exit(1)),!r){let l=Array.from(new Set(c.map(f=>f.imageName))),{selectedImage:s}=await B.prompt([{type:"list",name:"selectedImage",message:"Select an image to use in the compose file:",choices:l}]);r=s}}let i=o.envFile;if(i)try{P(i)}catch{e.error(`File not found: ${i}`),process.exit(1)}else{let c=re.join(process.cwd(),".env");if(G.existsSync(c)){let{useDefault:s}=await B.prompt([{type:"confirm",name:"useDefault",message:"Use .env file in current directory?",default:!0}]);s&&(i=c)}if(!i){let{envPath:s}=await B.prompt([{type:"input",name:"envPath",message:"Enter path to environment variables file:",validate:f=>{try{return P(f),!0}catch{return`File not found: ${f}`}}}]);i=s}}let n=o.output;if(!n&&(n=re.join(process.cwd(),"docker-compose.yml"),G.existsSync(n))){let{confirmOverwrite:c}=await B.prompt([{type:"confirm",name:"confirmOverwrite",message:`File ${n} already exists. Overwrite?`,default:!1}]);if(!c){let{customPath:l}=await B.prompt([{type:"input",name:"customPath",message:"Enter alternative output path:",default:re.join(process.cwd(),"docker-generated-compose.yml")}]);n=l}}let m=new b("",t.username,t.registry);i?e.info(`Generating Docker Compose file for ${r} using env file: ${i}`):e.info(`Generating Docker Compose file for ${r} without env file`);let a=await m.buildComposeFile(r,i,o.template);if(a!==n){let c=re.dirname(n);G.existsSync(c)||(e.info(`Creating directory: ${c}`),G.mkdirSync(c,{recursive:!0})),G.copyFileSync(a,n)}e.success(`Docker Compose file generated successfully: ${n}`)}catch(t){e.error(`Failed to generate Docker Compose file: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});var qe=new Gt().name("docker").description("Login to Docker Hub and manage Docker images").addCommand(je).addCommand(He).addCommand(Ye).addCommand(We);import{Command as Wt}from"commander";import{Command as Ht}from"commander";var Je=new Ht().name("start").description("Start the TEE simulator").option("-p, --port <port>","Simulator port (default: 8090)","8090").action(async o=>{try{if(Ve()||await Ne(),await te()){e.success("TEE simulator is already running");return}let r=await Re();e.success("TEE simulator started successfully")}catch(t){e.error(`Failed to start TEE simulator: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as Yt}from"commander";var Qe=new Yt().name("stop").description("Stop the TEE simulator").action(async()=>{try{await Le()||(e.error("Failed to stop TEE simulator"),process.exit(1)),e.success("TEE simulator stopped successfully")}catch(o){e.error(`Failed to stop TEE simulator: ${o instanceof Error?o.message:String(o)}`),process.exit(1)}});var Ze=new Wt().name("simulator").description("TEE simulator commands").addCommand(Je).addCommand(Qe);import{Command as fr}from"commander";import{Command as qt}from"commander";import ue from"chalk";var Xe=new qt().name("list").alias("ls").description("List all CVMs").option("-j, --json","Output in JSON format").action(async o=>{try{let t=e.startSpinner("Fetching CVMs"),r=await ve();if(t.stop(!0),!r||r.length===0){e.info("No CVMs found");return}if(o.json){console.log(JSON.stringify(r,null,2));return}for(let i of r)e.keyValueTable({Name:i.name,"App ID":`app_${i.hosted.app_id}`,"CVM ID":i.hosted.id.replace(/-/g,""),Region:i.node.region_identifier,Status:i.status==="running"?ue.green(i.status):i.status==="stopped"?ue.red(i.status):ue.yellow(i.status),"Node Info URL":i.hosted.app_url,"App URL":`${h}/dashboard/cvms/${i.hosted.id.replace(/-/g,"")}`}),e.break();e.success(`Found ${r.length} CVMs`),e.break(),e.info(`Go to ${h}/dashboard/ to view your CVMs`)}catch(t){e.error(`Failed to list CVMs: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as Jt}from"commander";import fe from"chalk";async function w(o){if(!o){let t=await Z();return t||void 0}return await q(o)}var et=new Jt().name("get").description("Get details of a CVM").argument("[app-id]","App ID of the CVM (optional)").option("-j, --json","Output in JSON format").action(async(o,t)=>{try{let r=await w(o),i=e.startSpinner(`Fetching CVM with App ID app_${r}`),n=await N(r);if(i.stop(!0),e.break(),n||(e.error(`CVM with App ID app_${r} not found`),process.exit(1)),t.json){console.log(JSON.stringify(n,null,2));return}e.keyValueTable({Name:n.name,"App ID":`app_${n.app_id}`,Status:n.status==="running"?fe.green(n.status):n.status==="stopped"?fe.red(n.status):fe.yellow(n.status),vCPU:n.vcpu,Memory:`${n.memory} MB`,"Disk Size":`${n.disk_size} GB`,"Dstack Image":n.base_image,"App URL":`${h}/dashboard/cvms/app_${n.app_id}`})}catch(r){e.error(`Failed to get CVM details: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as Qt}from"commander";var tt=new Qt().name("start").description("Start a stopped 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(`Starting CVM with App ID app_${t}`),i=await ke(t);r.stop(!0),e.break();let n={"CVM ID":i.id,Name:i.name,Status:i.status,"App ID":`app_${i.app_id}`};e.keyValueTable(n,{borderStyle:"rounded"}),e.break(),e.success(`Your CVM is being started. You can check the dashboard for more details:
55
- ${h}/dashboard/cvms/app_${i.app_id}`)}catch(t){e.error(`Failed to start CVM: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as Zt}from"commander";var rt=new Zt().name("stop").description("Stop a running 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(`Stopping CVM with App ID app_${t}`),i=await we(t);r.stop(!0),e.break();let n={"CVM ID":i.id,Name:i.name,Status:i.status,"App ID":`app_${i.app_id}`};e.keyValueTable(n,{borderStyle:"rounded"}),e.break(),e.success(`Your CVM is being stopped. You can check the dashboard for more details:
56
- ${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 Xt}from"commander";var ot=new Xt().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 be(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:
57
- ${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 er}from"commander";import oe from"chalk";var it=new er().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 Ee(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 tr}from"commander";import{encryptEnvVars as rr}from"@phala/dstack-sdk/encrypt-env-vars";import at from"node:fs";import or from"node:path";import st from"inquirer";import*as nt from"node:fs";var V=(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=nt.readFileSync(t,"utf8");for(let n of i.split(`
58
- `)){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,`
59
- `))):s=s.trim(),l&&(r[l]=s)}}return Object.entries(r).map(([i,n])=>({key:i,value:n}))};var mt=new tr().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 st.prompt([{type:"input",name:"name",message:"Enter a name for the CVM:",validate:D=>D.trim()?D.trim().length>20?"CVM name must be less than 20 characters":D.trim().length<3?"CVM name must be at least 3 characters":/^[a-zA-Z0-9_-]+$/.test(D)?!0:"CVM name must contain only letters, numbers, underscores, and hyphens":"CVM name is required"}]);o.name=k}if(!o.compose){let D=ee(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");o.compose=await F("Enter the path to your Docker Compose file:",D,"file")}let t=or.resolve(o.compose);at.existsSync(t)||(e.error(`Docker Compose file not found: ${t}`),process.exit(1));let r=at.readFileSync(t,"utf8");await M(),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=V([],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 st.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 D=await F("Enter the path to your environment file:",".env","file");i=V([],D)}}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 R();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 rr(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 _t={"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(_t,{borderStyle:"rounded"}),e.info(""),e.success(`Your CVM is being created. You can check its status with:
60
- 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 ir}from"commander";import nr from"inquirer";var ct=new ir().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 nr.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 _e(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 ar}from"commander";import sr from"node:fs";import{encryptEnvVars as mr}from"@phala/dstack-sdk/encrypt-env-vars";var pt=new ar().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 N(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=sr.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 M(),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=V([],t.envFile),a=await mr(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 Se(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:
61
- ${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 cr}from"commander";import H from"inquirer";import x from"chalk";var lt=new cr().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 N(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:
62
- `;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 xe(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:
63
- ${h}/dashboard/cvms/app_${r}`)}catch(r){e.error(`Failed to resize CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as pr}from"commander";var dt=new pr().name("list-nodes").description("List all available worker nodes.").action(async()=>{try{let{nodes:o,kms_list:t}=await R();if(o.length===0){e.info("No available nodes found.");return}e.info("Available Nodes:"),o.forEach(r=>{e.info("----------------------------------------"),e.info(` ID: ${r.teepod_id}`),e.info(` Name: ${r.name}`),e.info(` Region: ${r.region_identifier}`),e.info(` FMSPC: ${r.fmspc||"N/A"}`),e.info(` Device ID: ${r.device_id||"N/A"}`),e.info(` Support Onchain KMS: ${r.support_onchain_kms}`),e.info(" Images:"),r.images&&r.images.length>0?r.images.forEach(i=>{e.info(` - ${i.name}`),e.info(` Hash: ${i.os_image_hash||"N/A"}`)}):e.info(" N/A")}),t&&t.length>0&&(e.info(`
64
- Available KMS Instances:`),t.forEach(r=>{e.info("----------------------------------------"),e.info(` ID: ${r.id}`),e.info(` URL: ${r.url}`),e.info(` Version: ${r.version}`),e.info(` Chain ID: ${r.chain_id}`),e.info(` Contract Address: ${r.kms_contract_address}`),e.info(` Gateway App ID: ${r.gateway_app_id}`)}))}catch(o){e.error(`Failed to list available nodes: ${o instanceof Error?o.message:String(o)}`)}});import{Command as lr}from"commander";import{encryptEnvVars as dr}from"@phala/dstack-sdk/encrypt-env-vars";import ut from"node:fs";import ur from"node:path";var ft=new lr().name("replicate").description("Create a replica of an existing CVM").argument("<cvm-id>","UUID of the CVM to replicate").option("--teepod-id <teepodId>","TEEPod ID to use for the replica").option("-e, --env-file <envFile>","Path to environment file").action(async(o,t)=>{try{let r;if(o=o.replace(/-/g,""),t.envFile){let a=ur.resolve(process.cwd(),t.envFile);if(!ut.existsSync(a))throw new Error(`Environment file not found: ${a}`);let l=ut.readFileSync(a,"utf-8").split(`
65
- `).filter(g=>g.trim()!==""&&!g.trim().startsWith("#")).map(g=>{let[p,...u]=g.split("=");return{key:p.trim(),value:u.join("=").trim()}}),s=await $e(o);e.info("Encrypting environment variables..."),r=await dr(l,s.env_pubkey)}let i={};t.teepodId&&(i.teepod_id=parseInt(t.teepodId,10)),r&&(i.encrypted_env=r);let n=await De(o,i);e.success(`Successfully created replica of CVM UUID: ${o} with App ID: ${n.app_id}`);let m={"CVM UUID":n.vm_uuid.replace(/-/g,""),"App ID":n.app_id,Name:n.name,Status:n.status,TEEPod:`${n.teepod.name} (ID: ${n.teepod_id})`,vCPUs:n.vcpu,Memory:`${n.memory} MB`,"Disk Size":`${n.disk_size} GB`,"App URL":n.app_url||`${process.env.CLOUD_URL||"https://cloud.phala.network"}/dashboard/cvms/${n.vm_uuid.replace(/-/g,"")}`};e.keyValueTable(m,{borderStyle:"rounded"}),e.success(`Your CVM replica is being created. You can check its status with:
66
- phala cvms get ${n.app_id}`)}catch(r){e.error("Failed to create CVM replica:",r instanceof Error?r.message:r),process.exit(1)}});var gt=new fr().name("cvms").description("Manage Phala Confidential Virtual Machines (CVMs)").addCommand(it).addCommand(mt).addCommand(ct).addCommand(et).addCommand(Xe).addCommand(tt).addCommand(rt).addCommand(lt).addCommand(ot).addCommand(pt).addCommand(dt).addCommand(ft);import{Command as gr}from"commander";import{execSync as Y}from"node:child_process";import*as yt from"node:os";function hr(o){let t=yt.platform();try{switch(t){case"darwin":Y(`open "${o}"`);break;case"win32":Y(`start "" "${o}"`);break;case"linux":try{Y(`xdg-open "${o}"`)}catch{try{Y(`gnome-open "${o}"`)}catch{Y(`kde-open "${o}"`)}}break;default:throw new Error(`Unsupported platform: ${t}`)}e.success(`Opened URL in your default browser: ${o}`)}catch(r){e.error(`Failed to open URL: ${r instanceof Error?r.message:String(r)}`),e.info(`Please manually open this URL in your browser: ${o}`)}}function ht(o){return new Promise(t=>setTimeout(t,o))}var Ct=new gr().name("join").alias("free").description("Join Phala Cloud! Get an account and deploy a CVM for FREE").action(async()=>{try{let o="https://cloud.phala.network/register?invite=beta",t=e.startSpinner("Brewing a fresh cup of TEE \u{1F375}");await ht(2e3),t.stop(!0),e.break(),e.break(),console.log(X),e.info("TEE is served! Opening Phala Cloud registration page..."),await ht(1e3),e.break(),hr(o)}catch(o){e.error(`Error: ${o instanceof Error?o.message:String(o)}`),process.exit(1)}});import{Command as vr}from"commander";var yr=`version: '3'
50
+ `;h.appendFileSync(a.logFilePath,u)}return l.pid&&Vt(l.pid),a.background&&(l.unref(),e.success("Simulator is running in the background")),await ue(),l}catch(t){throw e.error("Error running simulator:",t),new Error(`Failed to run simulator: ${t}`)}}async function de(){try{let o=z(),t=C.platforms[o];if(o==="darwin"||o==="linux"){let r=t.socketPath;return h.existsSync(r)?new Promise(i=>{let n=pe.createConnection({path:r}).on("connect",()=>{n.end(),i(!0)}).on("error",()=>{i(!1)});setTimeout(()=>{n.end(),i(!1)},1e3)}):!1}if(o==="win32"){let r="127.0.0.1";return new Promise(n=>{let s=pe.createConnection({host:r,port:8090}).on("connect",()=>{s.end(),n(!0)}).on("error",()=>{n(!1)});setTimeout(()=>{s.end(),n(!1)},1e3)})}return!1}catch(o){return e.error("Error checking if simulator is running:",o),!1}}async function Oe(){try{let o=Le();if(!await de()&&!o)return e.info("Simulator is not running"),!0;let r=z(),i=!1;if(r==="win32")try{o?(e.info(`Stopping simulator process (PID: ${o})...`),process.kill(o,"SIGTERM")):M("taskkill /F /IM dstack-simulator.exe",{stdio:"ignore"}),i=!0}catch(s){if(s.code!=="ESRCH")return e.error("Failed to stop simulator:",s),!1;i=!0}else try{o?(e.info(`Stopping simulator process (PID: ${o})...`),process.kill(o,"SIGTERM")):M("pkill -f dstack-simulator",{stdio:"ignore"}),i=!0}catch(s){if(s.code!=="ESRCH")return e.error("Failed to stop simulator:",s),!1;i=!0}let n=le();if(h.existsSync(n))try{h.unlinkSync(n)}catch(s){e.warn("Failed to remove PID file:",s)}return await V(),i&&e.success("Simulator stopped successfully"),i}catch(o){return e.error("Error stopping simulator:",o),!1}}function Rt(){let o=z(),t=C.platforms[o];return o==="win32"?"http://127.0.0.1:8090":`${t.socketPath||"/tmp/dstack.sock"}`}async function ue(o){try{let t=Rt(),r=o||t;return await M(`export DSTACK_SIMULATOR_ENDPOINT=${r}`),e.success(`Setting DSTACK_SIMULATOR_ENDPOINT=${r} for current process`),o}catch(t){throw e.error("Error setting simulator endpoint environment variable:",t),new Error(`Failed to set simulator endpoint: ${t}`)}}async function V(){return await M("unset DSTACK_SIMULATOR_ENDPOINT"),e.debug("Deleted DSTACK_SIMULATOR_ENDPOINT from current process"),!0}var K=zt(Ut),je=".phala-cloud/logs",jt=".phala-cloud/compose",Ke=10,S=class{username;image;registry;constructor(t,r,i){this.image=t,this.username=r||"",this.registry=i||""}ensureLogsDir(){let t=j.resolve(je);D.existsSync(t)||D.mkdirSync(t,{recursive:!0})}getLogFilePath(t,r){let i=new Date().toISOString().replace(/[:.]/g,"-");return j.resolve(je,`${r||this.image}-${t}-${i}.log`)}getSystemArchitecture(){let t=ze.arch();switch(t){case"arm":case"arm64":return"arm64";case"x64":return"amd64";default:return t}}spawnProcess(t,r,i,n){return new Promise((s,a)=>{let c=Ot(t,r);this.ensureLogsDir();let l=this.getLogFilePath(i,n),m=D.createWriteStream(l,{flags:"a"}),u=[],g=(p,f=!1)=>{let v=p.toString().split(`
51
+ `);m.write(p);for(let d of v)if(d.trim()){u.push(d),u.length>Ke&&u.shift(),console.clear(),console.log(`Latest ${Ke} lines (full log at ${l}):`),console.log("-".repeat(50));for(let P of u)f?console.error(P):console.log(P)}};c.stdout.on("data",p=>g(p)),c.stderr.on("data",p=>g(p,!0)),c.on("close",p=>{m.end(),p===0?(console.log(`
52
+ Operation completed. Full log available at: ${l}`),s()):a(new Error(`Process exited with code ${p}. Check log file: ${l}`))}),c.on("error",p=>{m.end(),a(p)})})}setCredentials(t,r){this.username=t,r&&(this.registry=r)}async buildImage(t,r){try{let i=this.getSystemArchitecture(),n=`${this.username}/${this.image}:${r}`,s=e.startSpinner(`Building Docker image ${this.username}/${this.image}:${r}`);F(t);let a=["build","-t",n,"-f",t];return i==="arm64"&&(console.log("Detected arm64 architecture, using --platform linux/amd64"),a.push("--platform","linux/amd64")),a.push("."),await this.spawnProcess("docker",a,"build",this.image),s.stop(!0,`Docker image ${n} built successfully`),!0}catch(i){return e.error(`Failed to build Docker image: ${i instanceof Error?i.message:String(i)}`),!1}}async pushImage(t){try{let r=e.startSpinner(`Pushing Docker image ${t} to Docker Hub`);if(!await $())throw r.stop(!1),new Error('Docker credentials not found. Please log in first with "phala docker login"');let n=t;return console.log(`Pushing image ${n} to Docker Hub...`),await this.spawnProcess("docker",["push",n],"push",t.replace(/.*\/+([\w-]+):.*$/g,"$1")),r.stop(!0,`Docker image ${n} pushed successfully`),!0}catch(r){return e.error(`Failed to push Docker image: ${r instanceof Error?r.message:String(r)}`),!1}}async login(t,r,i){try{let n=e.startSpinner(`Logging in to Docker Hub as ${t}`);if(await this.checkLogin())return n.stop(!0,"Already logged in to Docker Hub"),this.setCredentials(t,i),!0;if(!r)throw n.stop(!1),new Error("Password is required for Docker login");try{await Nt("docker",["login",...i?[i]:[],"-u",t,"--password-stdin"],{input:r,timeout:1e4})}catch(a){throw a.timedOut?(n.stop(!1),new Error("Docker login timed out. Please check your credentials and try again.")):a}return n.stop(!0,"Logged in to Docker Hub successfully"),this.setCredentials(t,i),!0}catch(n){return e.error(`Failed to login to Docker Hub: ${n instanceof Error?n.message:String(n)}`),!1}}async checkLogin(){try{let t=ze.homedir(),r=j.join(t,".docker","config.json");if(!D.existsSync(r))return!1;let i=JSON.parse(D.readFileSync(r,"utf-8"));return!!(i?.auths&&Object.keys(i.auths).length>0)}catch(t){return e.debug(`Docker login check failed: ${t instanceof Error?t.message:String(t)}`),!1}}async buildComposeFile(t,r,i){if(!this.username)throw new Error("Docker Hub username is required for building compose file");let n=i==="eliza"?ye:ve,s=Ce.parse({template:n}),a=j.resolve(jt);D.existsSync(a)||(e.info(`Creating directory: ${a}`),D.mkdirSync(a,{recursive:!0}));let c=[];r&&(c=D.readFileSync(r,"utf-8").split(`
53
+ `).filter(f=>f&&!f.startsWith("#")).map(f=>{let v=f.indexOf("#");return v>0&&(f=f.substring(0,v).trim()),f.trim()}).filter(f=>f.includes("=")).map(f=>{let[v,d]=f.split("=",2),P=v.trim();return(d?d.trim():"")===""?null:`${P}=${P}`}).filter(Boolean));let l=t,u=Lt.compile(s.template,{noEscape:!0})({imageName:l,envVars:c.map(p=>p.replace(/=.*/,`=\${${p.split("=")[0]}}`))}),g=j.join(a,`${t.replace(/.*\/+([\w-]+):.*$/g,"$1")}-tee-compose.yaml`);return D.writeFileSync(g,u),e.success(`Backup of docker compose file created at: ${g}`),g}async runComposeLocally(t,r){try{let i=e.startSpinner(`Running Docker Compose file at ${t}`);F(t);let n=["-f",t,"up","-d"];return r&&(F(r),n.splice(2,0,"--env-file",r)),await K(`docker compose ${n.join(" ")}`),i.stop(!0,"Docker Compose file running successfully"),!0}catch(i){return e.error(`Failed to run Docker Compose file: ${i instanceof Error?i.message:String(i)}`),!1}}async runSimulator(t,r){try{e.info(`Running TEE simulator with image ${t}`),e.info("Pulling latest simulator image..."),await K(`docker pull ${t}`),e.info("Starting simulator in background...");let{stdout:i}=await K(`docker run -d --name tee-simulator --rm -p ${r}:${r} ${t}`),n=i.trim();return e.success(`TEE simulator running successfully. Container ID: ${n}`),e.break(),e.break(),e.info("Useful commands:"),e.info(`- View logs: docker logs -f ${n}`),e.info(`- Stop simulator: docker stop ${n}`),ue(`http://localhost:${r}`),!0}catch(i){return e.error(`Failed to run TEE simulator: ${i instanceof Error?i.message:String(i)}`),!1}}async stopSimulator(){try{let t=e.startSpinner("Stopping TEE simulator...");return await K("docker stop tee-simulator"),await V(),t.stop(!0,"TEE simulator stopped successfully"),!0}catch(t){return e.error(`Failed to stop TEE simulator: ${t instanceof Error?t.message:String(t)}`),!1}}static async listLocalImages(){try{let{stdout:t}=await K('docker images --format "{{.Repository}}:{{.Tag}}"'),i=(await $())?.username;return t.split(`
54
+ `).filter(s=>s&&!s.includes("<none>")).filter(s=>s.includes(`${i}/`)).map(s=>({imageName:s}))}catch(t){return e.error(`Failed to list local Docker images: ${t instanceof Error?t.message:String(t)}`),[]}}};import Be from"prompts";var Ge=new Kt().name("login").description("Login to Docker Hub").option("-u, --username <username>","Docker Hub username").option("-p, --password <password>","Docker Hub password").option("-r, --registry <registry>","Docker registry URL").action(async o=>{try{let t=o.username,r=o.password,i=o.registry;if(!t){e.info("First we need your Docker Hub username to check if you are already logged in.");let c=await Be({type:"text",name:"username",message:"Enter your Docker Hub username:",validate:l=>l.length>0?!0:"Username cannot be empty"});c.username||(e.error("Username is required"),process.exit(1)),t=c.username}let n=new S("",t,i);if(await n.login(t)){e.success(`${t} is logged in to Docker Hub`),await ie({username:t,registry:i||null});return}if(!r){let c=await Be({type:"password",name:"password",message:"Enter your Docker Hub password:",validate:l=>l.length>0?!0:"Password cannot be empty"});c.password||(e.error("Password is required"),process.exit(1)),r=c.password}await n.login(t,r,i)||(e.error("Failed to login to Docker Hub"),process.exit(1)),await ie({username:t,registry:i||null}),e.success("Logged in to Docker Hub successfully")}catch(t){e.error(`Failed to login to Docker Hub: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as Bt}from"commander";import He from"node:path";import Ye from"inquirer";import Gt from"node:fs";var We=new Bt().name("build").description("Build a Docker image").option("-i, --image <image>","Image name").option("-t, --tag <tag>","Image tag").option("-f, --file <file>","Path to Dockerfile","Dockerfile").action(async o=>{try{let t=await $();if(t||(e.error('Docker information not found. Please login first with "phala docker login"'),process.exit(1)),!o.image){let a=await Ye.prompt([{type:"input",name:"image",message:"Enter the Docker image name:",validate:c=>c.trim()?!0:"Image name is required"}]);o.image=a.image}if(!o.tag){let a=await Ye.prompt([{type:"input",name:"tag",message:"Enter the Docker image tag:",default:"latest",validate:c=>c.trim()?!0:"Tag is required"}]);o.tag=a.tag}let r=He.resolve(process.cwd(),o.file);Gt.existsSync(r)||(e.info(`Default Dockerfile not found at ${r}`),o.file=await T("Enter the path to your Dockerfile:","Dockerfile","file"));let i=He.resolve(process.cwd(),o.file);await new S(o.image,t.username,t.registry).buildImage(i,o.tag)||(e.error("Failed to build Docker image"),process.exit(1)),e.success(`Docker image ${t.username}/${o.image}:${o.tag} built successfully`)}catch(t){e.error(`Failed to build Docker image: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as Ht}from"commander";import Yt from"inquirer";var qe=new Ht().name("push").description("Push a Docker image to Docker Hub").option("-i, --image <image>","Full image name (e.g. username/image:tag)").action(async o=>{try{let t=await $();t||(e.error('Docker information not found. Please login first with "phala docker login"'),process.exit(1));let r=o.image;if(!r){let s=await S.listLocalImages();if(s.length===0&&(e.error('No local Docker images found. Please build an image first with "phala docker build"'),process.exit(1)),!r){let a=Array.from(new Set(s.map(l=>l.imageName))),{selectedImage:c}=await Yt.prompt([{type:"list",name:"selectedImage",message:"Select an image to push:",choices:a}]);r=c}}await new S("",t.username,t.registry).pushImage(r)||(e.error("Failed to push Docker image"),process.exit(1)),e.success(`Docker image ${r} pushed successfully`)}catch(t){e.error(`Failed to push Docker image: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as Wt}from"commander";import B from"inquirer";import G from"node:fs";import te from"node:path";var Je=new Wt().name("generate").description("Generate a Docker Compose file").option("-i, --image <imageName>","Docker image name to use in the compose file (e.g. phala/phala-cloud)").option("-e, --env-file <envFile>","Path to environment variables file").option("-o, --output <output>","Output path for generated docker-compose.yml").option("--template <template>","Template to use for the generated docker-compose.yml").action(async o=>{try{let t=await $();(!t||!t.username)&&(e.error("Docker Hub username not found. Please login first with `phala docker login`"),process.exit(1));let r=o.image;if(!r){let c=await S.listLocalImages();if(c.length===0&&(e.error('No local Docker images found. Please build an image first with "phala docker build"'),process.exit(1)),!r){let l=Array.from(new Set(c.map(u=>u.imageName))),{selectedImage:m}=await B.prompt([{type:"list",name:"selectedImage",message:"Select an image to use in the compose file:",choices:l}]);r=m}}let i=o.envFile;if(i)try{F(i)}catch{e.error(`File not found: ${i}`),process.exit(1)}else{let c=te.join(process.cwd(),".env");if(G.existsSync(c)){let{useDefault:m}=await B.prompt([{type:"confirm",name:"useDefault",message:"Use .env file in current directory?",default:!0}]);m&&(i=c)}if(!i){let{envPath:m}=await B.prompt([{type:"input",name:"envPath",message:"Enter path to environment variables file:",validate:u=>{try{return F(u),!0}catch{return`File not found: ${u}`}}}]);i=m}}let n=o.output;if(!n&&(n=te.join(process.cwd(),"docker-compose.yml"),G.existsSync(n))){let{confirmOverwrite:c}=await B.prompt([{type:"confirm",name:"confirmOverwrite",message:`File ${n} already exists. Overwrite?`,default:!1}]);if(!c){let{customPath:l}=await B.prompt([{type:"input",name:"customPath",message:"Enter alternative output path:",default:te.join(process.cwd(),"docker-generated-compose.yml")}]);n=l}}let s=new S("",t.username,t.registry);i?e.info(`Generating Docker Compose file for ${r} using env file: ${i}`):e.info(`Generating Docker Compose file for ${r} without env file`);let a=await s.buildComposeFile(r,i,o.template);if(a!==n){let c=te.dirname(n);G.existsSync(c)||(e.info(`Creating directory: ${c}`),G.mkdirSync(c,{recursive:!0})),G.copyFileSync(a,n)}e.success(`Docker Compose file generated successfully: ${n}`)}catch(t){e.error(`Failed to generate Docker Compose file: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});var Qe=new qt().name("docker").description("Login to Docker Hub and manage Docker images").addCommand(Ge).addCommand(We).addCommand(qe).addCommand(Je);import{Command as Zt}from"commander";import{Command as Jt}from"commander";var Ze=new Jt().name("start").description("Start the TEE simulator").option("-p, --port <port>","Simulator port (default: 8090)","8090").action(async o=>{try{if(Re()||await Ne(),await de()){e.success("TEE simulator is already running");return}let r=await Ue();e.success("TEE simulator started successfully")}catch(t){e.error(`Failed to start TEE simulator: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as Qt}from"commander";var Xe=new Qt().name("stop").description("Stop the TEE simulator").action(async()=>{try{await Oe()||(e.error("Failed to stop TEE simulator"),process.exit(1)),e.success("TEE simulator stopped successfully")}catch(o){e.error(`Failed to stop TEE simulator: ${o instanceof Error?o.message:String(o)}`),process.exit(1)}});var et=new Zt().name("simulator").description("TEE simulator commands").addCommand(Ze).addCommand(Xe);import{Command as vr}from"commander";import{Command as Xt}from"commander";import fe from"chalk";var tt=new Xt().name("list").alias("ls").description("List all CVMs").option("-j, --json","Output in JSON format").action(async o=>{try{let t=e.startSpinner("Fetching CVMs"),r=await ke();if(t.stop(!0),!r||r.length===0){e.info("No CVMs found");return}if(o.json){console.log(JSON.stringify(r,null,2));return}for(let i of r)e.keyValueTable({Name:i.name,"App ID":`app_${i.hosted.app_id}`,"CVM ID":i.hosted.id.replace(/-/g,""),Region:i.node.region_identifier,Status:i.status==="running"?fe.green(i.status):i.status==="stopped"?fe.red(i.status):fe.yellow(i.status),"Node Info URL":i.hosted.app_url,"App URL":`${y}/dashboard/cvms/${i.hosted.id.replace(/-/g,"")}`}),e.break();e.success(`Found ${r.length} CVMs`),e.break(),e.info(`Go to ${y}/dashboard/ to view your CVMs`)}catch(t){e.error(`Failed to list CVMs: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as er}from"commander";import ge from"chalk";async function w(o){if(!o){let t=await Z();return t||void 0}return await q(o)}var rt=new er().name("get").description("Get details of a CVM").argument("[app-id]","App ID of the CVM (optional)").option("-j, --json","Output in JSON format").action(async(o,t)=>{try{let r=await w(o),i=e.startSpinner(`Fetching CVM with App ID app_${r}`),n=await N(r);if(i.stop(!0),e.break(),n||(e.error(`CVM with App ID app_${r} not found`),process.exit(1)),t.json){console.log(JSON.stringify(n,null,2));return}e.keyValueTable({Name:n.name,"App ID":`app_${n.app_id}`,Status:n.status==="running"?ge.green(n.status):n.status==="stopped"?ge.red(n.status):ge.yellow(n.status),vCPU:n.vcpu,Memory:`${n.memory} MB`,"Disk Size":`${n.disk_size} GB`,"Dstack Image":n.base_image,"App URL":`${y}/dashboard/cvms/app_${n.app_id}`})}catch(r){e.error(`Failed to get CVM details: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as tr}from"commander";var ot=new tr().name("start").description("Start a stopped 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(`Starting CVM with App ID app_${t}`),i=await we(t);r.stop(!0),e.break();let n={"CVM ID":i.id,Name:i.name,Status:i.status,"App ID":`app_${i.app_id}`};e.keyValueTable(n,{borderStyle:"rounded"}),e.break(),e.success(`Your CVM is being started. You can check the dashboard for more details:
55
+ ${y}/dashboard/cvms/app_${i.app_id}`)}catch(t){e.error(`Failed to start CVM: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as rr}from"commander";var it=new rr().name("stop").description("Stop a running 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(`Stopping CVM with App ID app_${t}`),i=await be(t);r.stop(!0),e.break();let n={"CVM ID":i.id,Name:i.name,Status:i.status,"App ID":`app_${i.app_id}`};e.keyValueTable(n,{borderStyle:"rounded"}),e.break(),e.success(`Your CVM is being stopped. You can check the dashboard for more details:
56
+ ${y}/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 or}from"commander";var nt=new or().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:`${y}/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:
57
+ ${y}/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 ir}from"commander";import re from"chalk";var at=new ir().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 s={Status:n.is_online?re.green("Online"):re.red("Offline"),"Public Access":n.is_public?re.green("Enabled"):re.yellow("Disabled"),Error:n.error||"None",Certificates:`${n.app_certificates?.length||0} found`};if(e.keyValueTable(s,{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(m=>m.event!==null&&m.event!=="").map(m=>({Event:m.event,IMR:m.imr.toString(),"Event Type":m.event_type.toString(),Payload:m.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 nr}from"commander";import{encryptEnvVars as ar}from"@phala/dstack-sdk/encrypt-env-vars";import mt from"node:fs";import sr from"node:path";import ct from"inquirer";import*as st from"node:fs";var R=(o,t)=>{let r={};if(o){for(let i of o)if(i.includes("=")){let[n,...s]=i.split("="),a=s.join("=");n&&(r[n]=a)}}if(t){let i=st.readFileSync(t,"utf8");for(let n of i.split(`
58
+ `)){if(!n.trim()||n.trim().startsWith("#"))continue;let s=-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){s=d;break}else if(n[d]==="#"&&!a)break;if(s===-1){n.trim().startsWith("#");continue}let l=n.substring(0,s).trim(),m=n.substring(s+1),u=!1,g="",p=-1;for(let d=0;d<m.length;d++)if((m[d]==='"'||m[d]==="'"||m[d]==="`")&&(d===0||m[d-1]!=="\\"))u&&m[d]===g?(u=!1,g=""):u||(u=!0,g=m[d]);else if(m[d]==="#"&&!u&&d>0&&m[d-1]===" "){p=d-1;break}else if(m[d]==="#"&&!u&&d===0){p=d;break}p!==-1&&(m=m.substring(0,p)),m===void 0&&(m="");let f=m.charAt(0),v=m.charAt(m.length-1);f==='"'&&v==='"'||f==="'"&&v==="'"||f==="`"&&v==="`"?(m=m.substring(1,m.length-1),f==='"'&&(m=m.replace(/\\\\n/g,`
59
+ `))):m=m.trim(),l&&(r[l]=m)}}return Object.entries(r).map(([i,n])=>({key:i,value:n}))};var pt=new nr().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 ${ne}`).option("--memory <memory>",`Memory in MB, default is ${ae}`).option("--disk-size <diskSize>",`Disk size in GB, default is ${se}`).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 ct.prompt([{type:"input",name:"name",message:"Enter a name for the CVM:",validate:x=>x.trim()?x.trim().length>20?"CVM name must be less than 20 characters":x.trim().length<3?"CVM name must be at least 3 characters":/^[a-zA-Z0-9_-]+$/.test(x)?!0:"CVM name must contain only letters, numbers, underscores, and hyphens":"CVM name is required"}]);o.name=k}if(!o.compose){let x=ee(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");o.compose=await T("Enter the path to your Docker Compose file:",x,"file")}let t=sr.resolve(o.compose);mt.existsSync(t)||(e.error(`Docker Compose file not found: ${t}`),process.exit(1));let r=mt.readFileSync(t,"utf8");await V(),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=R([],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 ct.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 x=await T("Enter the path to your environment file:",".env","file");i=R([],x)}}let n=Number(o.vcpu)||ne,s=Number(o.memory)||ae,a=Number(o.diskSize)||se;(Number.isNaN(n)||n<=0)&&(e.error(`Invalid number of vCPUs: ${n}`),process.exit(1)),(Number.isNaN(s)||s<=0)&&(e.error(`Invalid memory: ${s}`),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 L();c.stop(!0),l.nodes.length===0&&(e.error("No TEEPods available. Please try again later."),process.exit(1));let m;o.teepodId?(m=l.nodes.find(k=>k.teepod_id===Number(o.teepodId)),m||(e.error("Failed to find selected TEEPod"),process.exit(1))):(m=l.nodes[0],m||(e.error("Failed to find default TEEPod"),process.exit(1)));let u;o.image?(u=m.images?.find(k=>k.name===o.image),u||(e.error(`Failed to find selected image: ${o.image}`),process.exit(1))):(u=m.images?.find(k=>k.name===O),u||(e.error(`Failed to find default image ${O}`),process.exit(1)));let g={teepod_id:m.teepod_id,name:o.name,image:u.name,vcpu:n,memory:s,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"),f=await J(g);p.stop(!0),f||(e.error("Failed to get public key from CVM"),process.exit(1));let v=e.startSpinner("Encrypting environment variables"),d=await ar(i,f.app_env_encrypt_pubkey);v.stop(!0),o.debug&&(e.debug("Public key:",f.app_env_encrypt_pubkey),e.debug("Encrypted environment variables:",d),e.debug("Environment variables:",JSON.stringify(i)));let P=e.startSpinner("Creating CVM"),E=await Q({...g,encrypted_env:d,app_env_encrypt_pubkey:f.app_env_encrypt_pubkey,app_id_salt:f.app_id_salt});P.stop(!0),E||(e.error("Failed to create CVM"),process.exit(1)),e.success("CVM created successfully"),e.break();let $t={"CVM ID":E.id,Name:E.name,Status:E.status,"App ID":`app_${E.app_id}`,"App URL":E.app_url?E.app_url:`${y}/dashboard/cvms/app_${E.app_id}`};e.keyValueTable($t,{borderStyle:"rounded"}),e.info(""),e.success(`Your CVM is being created. You can check its status with:
60
+ phala cvms get app_${E.app_id}`)}catch(t){e.error(`Failed to create CVM: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as mr}from"commander";import cr from"inquirer";var lt=new mr().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:s}=await cr.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(!s){e.info("Deletion cancelled");return}}let i=e.startSpinner(`Deleting CVM app_${r}`),n=await _e(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 pr}from"commander";import lr from"node:fs";import{encryptEnvVars as dr}from"@phala/dstack-sdk/encrypt-env-vars";var dt=new pr().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 N(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 T("Enter the path to your Docker Compose file:",g,"file")}let s="";if(t.compose)try{s=lr.readFileSync(t.compose,"utf8")}catch(u){e.error(`Failed to read Docker Compose file: ${u instanceof Error?u.message:String(u)}`),process.exit(1)}await V(),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 u=[];if(t.envFile)try{u=R([],t.envFile),a=await dr(u,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:s,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}`),m=await Ee(r,c);m||(l.stop(!1),e.error("Failed to upgrade CVM"),process.exit(1)),l.stop(!0),m.detail&&e.info(`Details: ${m.detail}`),e.break(),e.success(`Your CVM is being upgraded. You can check the dashboard for more details:
61
+ ${y}/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 ur}from"commander";import H from"inquirer";import I from"chalk";var ut=new ur().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 N(r),n=t.vcpu,s=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 f=parseInt(p);return isNaN(f)||f<0?"Please enter a valid non-negative number":!0},default:i.vcpu,filter:p=>parseInt(p)}])).vcpu),s||(s=(await H.prompt([{type:"input",name:"memory",message:"Enter memory in MB:",validate:p=>{let f=parseInt(p);return isNaN(f)||f<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 f=parseInt(p);return isNaN(f)||f<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:
62
+ `;if(e.keyValueTable({vCPUs:i.vcpu!==n?`${I.red(i.vcpu)} -> ${I.green(n)}`:i.vcpu,Memory:i.memory!==s?`${I.red(i.memory)} MB -> ${I.green(s)} MB`:i.memory,"Disk Size":i.disk_size!==a?`${I.red(i.disk_size)} GB -> ${I.green(a)} GB`:i.disk_size,"Allow Restart":c?I.green("Yes"):I.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 m=e.startSpinner(`Resizing CVM with App ID app_${r}`);await Ie(r,n,s,a,c?1:0),m.stop(!0),e.break(),e.success(`Your CVM is being resized. You can check the dashboard for more details:
63
+ ${y}/dashboard/cvms/app_${r}`)}catch(r){e.error(`Failed to resize CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as fr}from"commander";var ft=new fr().name("list-nodes").description("List all available worker nodes.").action(async()=>{try{let{nodes:o,kms_list:t}=await L();if(o.length===0){e.info("No available nodes found.");return}e.info("Available Nodes:"),o.forEach(r=>{e.info("----------------------------------------"),e.info(` ID: ${r.teepod_id}`),e.info(` Name: ${r.name}`),e.info(` Region: ${r.region_identifier}`),e.info(` FMSPC: ${r.fmspc||"N/A"}`),e.info(` Device ID: ${r.device_id||"N/A"}`),e.info(` Support Onchain KMS: ${r.support_onchain_kms}`),e.info(" Images:"),r.images&&r.images.length>0?r.images.forEach(i=>{e.info(` - ${i.name}`),e.info(` Hash: ${i.os_image_hash||"N/A"}`)}):e.info(" N/A")}),t&&t.length>0&&(e.info(`
64
+ Available KMS Instances:`),t.forEach(r=>{e.info("----------------------------------------"),e.info(` ID: ${r.id}`),e.info(` URL: ${r.url}`),e.info(` Version: ${r.version}`),e.info(` Chain ID: ${r.chain_id}`),e.info(` Contract Address: ${r.kms_contract_address}`),e.info(` Gateway App ID: ${r.gateway_app_id}`)}))}catch(o){e.error(`Failed to list available nodes: ${o instanceof Error?o.message:String(o)}`)}});import{Command as gr}from"commander";import{encryptEnvVars as hr}from"@phala/dstack-sdk/encrypt-env-vars";import gt from"node:fs";import yr from"node:path";var ht=new gr().name("replicate").description("Create a replica of an existing CVM").argument("<cvm-id>","UUID of the CVM to replicate").option("--teepod-id <teepodId>","TEEPod ID to use for the replica").option("-e, --env-file <envFile>","Path to environment file").action(async(o,t)=>{try{let r;if(o=o.replace(/-/g,""),t.envFile){let a=yr.resolve(process.cwd(),t.envFile);if(!gt.existsSync(a))throw new Error(`Environment file not found: ${a}`);let l=gt.readFileSync(a,"utf-8").split(`
65
+ `).filter(g=>g.trim()!==""&&!g.trim().startsWith("#")).map(g=>{let[p,...f]=g.split("=");return{key:p.trim(),value:f.join("=").trim()}}),m=await De(o);e.info("Encrypting environment variables..."),r=await hr(l,m.env_pubkey)}let i={};t.teepodId&&(i.teepod_id=parseInt(t.teepodId,10)),r&&(i.encrypted_env=r);let n=await xe(o,i);e.success(`Successfully created replica of CVM UUID: ${o} with App ID: ${n.app_id}`);let s={"CVM UUID":n.vm_uuid.replace(/-/g,""),"App ID":n.app_id,Name:n.name,Status:n.status,TEEPod:`${n.teepod.name} (ID: ${n.teepod_id})`,vCPUs:n.vcpu,Memory:`${n.memory} MB`,"Disk Size":`${n.disk_size} GB`,"App URL":n.app_url||`${process.env.CLOUD_URL||"https://cloud.phala.network"}/dashboard/cvms/${n.vm_uuid.replace(/-/g,"")}`};e.keyValueTable(s,{borderStyle:"rounded"}),e.success(`Your CVM replica is being created. You can check its status with:
66
+ phala cvms get ${n.app_id}`)}catch(r){e.error("Failed to create CVM replica:",r instanceof Error?r.message:r),process.exit(1)}});var yt=new vr().name("cvms").description("Manage Phala Confidential Virtual Machines (CVMs)").addCommand(at).addCommand(pt).addCommand(lt).addCommand(rt).addCommand(tt).addCommand(ot).addCommand(it).addCommand(ut).addCommand(nt).addCommand(dt).addCommand(ft).addCommand(ht);import{Command as Cr}from"commander";import{execSync as Y}from"node:child_process";import*as Ct from"node:os";function kr(o){let t=Ct.platform();try{switch(t){case"darwin":Y(`open "${o}"`);break;case"win32":Y(`start "" "${o}"`);break;case"linux":try{Y(`xdg-open "${o}"`)}catch{try{Y(`gnome-open "${o}"`)}catch{Y(`kde-open "${o}"`)}}break;default:throw new Error(`Unsupported platform: ${t}`)}e.success(`Opened URL in your default browser: ${o}`)}catch(r){e.error(`Failed to open URL: ${r instanceof Error?r.message:String(r)}`),e.info(`Please manually open this URL in your browser: ${o}`)}}function vt(o){return new Promise(t=>setTimeout(t,o))}var kt=new Cr().name("join").alias("free").description("Join Phala Cloud! Get an account and deploy a CVM for FREE").action(async()=>{try{let o="https://cloud.phala.network/register?invite=beta",t=e.startSpinner("Brewing a fresh cup of TEE \u{1F375}");await vt(2e3),t.stop(!0),e.break(),e.break(),console.log(X),e.info("TEE is served! Opening Phala Cloud registration page..."),await vt(1e3),e.break(),kr(o)}catch(o){e.error(`Error: ${o instanceof Error?o.message:String(o)}`),process.exit(1)}});import{Command as Sr}from"commander";var wr=`version: '3'
67
67
  services:
68
68
  jupyter:
69
69
  image: quay.io/jupyter/base-notebook
@@ -75,14 +75,14 @@ services:
75
75
  - GRANT_SUDO=yes
76
76
  user: root
77
77
  command: "start-notebook.sh --NotebookApp.token=\${TOKEN}"
78
- `,Cr=`version: '3'
78
+ `,br=`version: '3'
79
79
  services:
80
80
  httpbin:
81
81
  image: kennethreitz/httpbin:latest
82
82
  ports:
83
83
  - "80:80"
84
- `,vt={jupyter:{compose:yr,name:"Jupyter Notebook"},httpbin:{compose:Cr,name:"HTTPBin"}};import{encryptEnvVars as kr}from"@phala/dstack-sdk/encrypt-env-vars";import kt from"inquirer";import wr from"node:crypto";var wt=new vr().name("demo").description("Demo commands to launch a demo on Phala Cloud").action(async()=>{try{await W()||(e.error("You need to be logged in to use the demo command"),e.info("Please login with: phala auth login"),process.exit(1));try{let y=e.startSpinner("Verifying your credentials"),d=await A();y.stop(!0),e.success(`Logged in as ${d.username}`)}catch{e.error("Authentication failed. Your API key may be invalid or expired."),e.info("Please set a new API key with: phala auth login"),process.exit(1)}let t=Object.values(vt);t.length===0&&(e.error("No template files found in the templates directory"),process.exit(1));let{selectedTemplate:r}=await kt.prompt([{type:"list",name:"selectedTemplate",message:"Select a template to deploy:",choices:t.map(y=>({name:y.name,value:y}))}]),i=r.compose;e.success(`Selected template: ${r.name}`);let n=wr.randomBytes(16).toString("hex"),m=V([`TOKEN=${n}`],""),{cvmName:a}=await kt.prompt([{type:"input",name:"cvmName",message:"Enter a name for your CVM:",default:`${r.name.replace(" ","-")}`,validate:y=>y.trim()?!0:"CVM name is required"}]);e.info("Preparing to deploy your CVM...");let c={teepod_id:3,name:a,image:O,vcpu:2,memory:2048,disk_size:20,compose_manifest:{docker_compose_file:i,docker_config:{url:"",username:"",password:""},features:["kms","tproxy-net"],kms_enabled:!0,manifest_version:2,name:a,public_logs:!0,public_sysinfo:!0,tproxy_enabled:!0},listed:!1},l=e.startSpinner("Preparing CVM configuration"),s=await J(c);l.stop(!0),s||(e.error("Failed to prepare CVM configuration"),process.exit(1));let f=await kr(m,s.app_env_encrypt_pubkey);e.debug("Public key:",s.app_env_encrypt_pubkey),e.debug("Encrypted environment variables:",f);let g=e.startSpinner("Creating your demo CVM"),p=await Q({...c,encrypted_env:f,app_env_encrypt_pubkey:s.app_env_encrypt_pubkey,app_id_salt:s.app_id_salt});g.stop(!0),p||(e.error("Failed to create demo CVM"),process.exit(1)),e.success("Demo CVM created successfully! \u{1F389}"),e.break();let u={"CVM ID":p.id,Name:p.name,Status:p.status,"App ID":`app_${p.app_id}`,"App URL":p.app_url?p.app_url:`${h}/dashboard/cvms/app_${p.app_id}`,Template:r.name,Resources:"2 vCPUs, 2GB RAM, 20GB Storage"};r.name.includes("Jupyter Notebook")&&(u["Jupyter Token"]=n,u["Access Instructions"]="Access your Jupyter notebook using the token above. Go to 'Network' tab to see the public URL."),e.keyValueTable(u,{borderStyle:"rounded"}),e.break(),e.success(`Your demo is being created. You can check its status with:
85
- phala cvms get app_${p.app_id}`)}catch(o){e.error(`Failed to launch demo: ${o instanceof Error?o.message:String(o)}`),process.exit(1)}});import{Command as bt}from"commander";async function ge(){try{let{nodes:o,kms_list:t}=await R();if(o.length===0){e.info("No available nodes found.");return}e.info("Available Nodes:"),o.forEach(r=>{e.info("----------------------------------------"),e.info(` ID: ${r.teepod_id}`),e.info(` Name: ${r.name}`),e.info(` Region: ${r.region_identifier}`),e.info(` FMSPC: ${r.fmspc||"N/A"}`),e.info(` Device ID: ${r.device_id||"N/A"}`),e.info(` Support Onchain KMS: ${r.support_onchain_kms}`),e.info(" Images:"),r.images&&r.images.length>0?r.images.forEach(i=>{e.info(` - ${i.name}`),e.info(` Hash: ${i.os_image_hash||"N/A"}`)}):e.info(" N/A")}),t&&t.length>0&&(e.info(`
86
- Available KMS Instances:`),t.forEach(r=>{e.info("----------------------------------------"),e.info(` Slug: ${r.slug}`),e.info(` URL: ${r.url}`),e.info(` Version: ${r.version}`),r.chain_id&&(e.info(` Chain ID: ${r.chain_id}`),e.info(` Contract Address: ${r.kms_contract_address}`),e.info(` Gateway App ID: ${r.gateway_app_id}`))}))}catch(o){throw e.error(`Failed to list available nodes: ${o instanceof Error?o.message:String(o)}`),o}}var St=new bt().name("nodes").description("List and manage TEE nodes").action(ge).addCommand(new bt("list").description("List all available worker nodes").alias("ls").action(ge));process.on("SIGINT",()=>process.exit(0));process.on("SIGTERM",()=>process.exit(0));async function Sr(){new br().name("phala").alias("pha").description(`${X}
87
- Phala Cloud CLI - Manage your Phala Cloud Deployments`).version("v1.0.15").addCommand(Me).addCommand(gt).addCommand(qe).addCommand(Ze).addCommand(wt).addCommand(Ct).addCommand(St).parse(process.argv)}Sr().catch(o=>{e.error("An error occurred:",o),process.exit(1)});
84
+ `,wt={jupyter:{compose:wr,name:"Jupyter Notebook"},httpbin:{compose:br,name:"HTTPBin"}};import{encryptEnvVars as Er}from"@phala/dstack-sdk/encrypt-env-vars";import bt from"inquirer";import _r from"node:crypto";var St=new Sr().name("demo").description("Demo commands to launch a demo on Phala Cloud").action(async()=>{try{await W()||(e.error("You need to be logged in to use the demo command"),e.info("Please login with: phala auth login"),process.exit(1));try{let v=e.startSpinner("Verifying your credentials"),d=await A();v.stop(!0),e.success(`Logged in as ${d.username}`)}catch{e.error("Authentication failed. Your API key may be invalid or expired."),e.info("Please set a new API key with: phala auth login"),process.exit(1)}let t=Object.values(wt);t.length===0&&(e.error("No template files found in the templates directory"),process.exit(1));let{selectedTemplate:r}=await bt.prompt([{type:"list",name:"selectedTemplate",message:"Select a template to deploy:",choices:t.map(v=>({name:v.name,value:v}))}]),i=r.compose;e.success(`Selected template: ${r.name}`);let n=_r.randomBytes(16).toString("hex"),s=R([`TOKEN=${n}`],""),{cvmName:a}=await bt.prompt([{type:"input",name:"cvmName",message:"Enter a name for your CVM:",default:`${r.name.replace(" ","-")}`,validate:v=>v.trim()?!0:"CVM name is required"}]);e.info("Preparing to deploy your CVM...");let c={teepod_id:3,name:a,image:O,vcpu:2,memory:2048,disk_size:20,compose_manifest:{docker_compose_file:i,docker_config:{url:"",username:"",password:""},features:["kms","tproxy-net"],kms_enabled:!0,manifest_version:2,name:a,public_logs:!0,public_sysinfo:!0,tproxy_enabled:!0},listed:!1},l=e.startSpinner("Preparing CVM configuration"),m=await J(c);l.stop(!0),m||(e.error("Failed to prepare CVM configuration"),process.exit(1));let u=await Er(s,m.app_env_encrypt_pubkey);e.debug("Public key:",m.app_env_encrypt_pubkey),e.debug("Encrypted environment variables:",u);let g=e.startSpinner("Creating your demo CVM"),p=await Q({...c,encrypted_env:u,app_env_encrypt_pubkey:m.app_env_encrypt_pubkey,app_id_salt:m.app_id_salt});g.stop(!0),p||(e.error("Failed to create demo CVM"),process.exit(1)),e.success("Demo CVM created successfully! \u{1F389}"),e.break();let f={"CVM ID":p.id,Name:p.name,Status:p.status,"App ID":`app_${p.app_id}`,"App URL":p.app_url?p.app_url:`${y}/dashboard/cvms/app_${p.app_id}`,Template:r.name,Resources:"2 vCPUs, 2GB RAM, 20GB Storage"};r.name.includes("Jupyter Notebook")&&(f["Jupyter Token"]=n,f["Access Instructions"]="Access your Jupyter notebook using the token above. Go to 'Network' tab to see the public URL."),e.keyValueTable(f,{borderStyle:"rounded"}),e.break(),e.success(`Your demo is being created. You can check its status with:
85
+ phala cvms get app_${p.app_id}`)}catch(o){e.error(`Failed to launch demo: ${o instanceof Error?o.message:String(o)}`),process.exit(1)}});import{Command as Et}from"commander";async function he(){try{let{nodes:o,kms_list:t}=await L();if(o.length===0){e.info("No available nodes found.");return}e.info("Available Nodes:"),o.forEach(r=>{e.info("----------------------------------------"),e.info(` ID: ${r.teepod_id}`),e.info(` Name: ${r.name}`),e.info(` Region: ${r.region_identifier}`),e.info(` FMSPC: ${r.fmspc||"N/A"}`),e.info(` Device ID: ${r.device_id||"N/A"}`),e.info(` Support Onchain KMS: ${r.support_onchain_kms}`),e.info(" Images:"),r.images&&r.images.length>0?r.images.forEach(i=>{e.info(` - ${i.name}`),e.info(` Hash: ${i.os_image_hash||"N/A"}`)}):e.info(" N/A")}),t&&t.length>0&&(e.info(`
86
+ Available KMS Instances:`),t.forEach(r=>{e.info("----------------------------------------"),e.info(` Slug: ${r.slug}`),e.info(` URL: ${r.url}`),e.info(` Version: ${r.version}`),r.chain_id&&(e.info(` Chain ID: ${r.chain_id}`),e.info(` Contract Address: ${r.kms_contract_address}`),e.info(` Gateway App ID: ${r.gateway_app_id}`))}))}catch(o){throw e.error(`Failed to list available nodes: ${o instanceof Error?o.message:String(o)}`),o}}var _t=new Et().name("nodes").description("List and manage TEE nodes").action(he).addCommand(new Et("list").description("List all available worker nodes").alias("ls").action(he));process.on("SIGINT",()=>process.exit(0));process.on("SIGTERM",()=>process.exit(0));async function Dr(){new $r().name("phala").alias("pha").description(`${X}
87
+ Phala Cloud CLI - Manage your Phala Cloud Deployments`).version("v1.0.15").addCommand(Ve).addCommand(yt).addCommand(Qe).addCommand(et).addCommand(St).addCommand(kt).addCommand(_t).parse(process.argv)}Dr().catch(o=>{e.error("An error occurred:",o),process.exit(1)});
88
88
  //# sourceMappingURL=index.js.map