phala 1.0.33 → 1.0.35

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 Ye,L as he,M as Oe,N as re,O,P as Ke,R as je,S as Be,T as qe,U as Ge,V as He,W as ze,Y as te,Z as We,_ as Je,a as o,aa as Qe,b as de,ba as K,c as V,d as G,e as fe,f as P,g as v,h as R,i as M,j as N,k as ge,l as Le,m as Ue,n as Ve}from"./chunk-2X5HREGL.js";import{a as Xe,b as Ze,c as er,d as rr,e as tr,f as or,g as nr,h as sr}from"./chunk-N7QSVRDT.js";import"./chunk-4YCH6IZV.js";import{Command as Kn}from"commander";import ir from"chalk";var ar=ir.hex("#cdfa50"),cr=ar(`
2
+ import{$ as Ye,L as he,M as Oe,N as re,O as K,P as Ke,R as je,S as Be,T as qe,U as Ge,V as He,W as ze,Y as te,Z as We,_ as Je,a as o,aa as Qe,b as de,ba as j,c as O,d as G,e as fe,f as P,g as v,h as M,i as N,j as L,k as ge,l as Le,m as Ue,n as Ve}from"./chunk-YJKUEQRT.js";import{a as Xe,b as Ze,c as er,d as rr,e as tr,f as or,g as nr,h as sr}from"./chunk-N7QSVRDT.js";import"./chunk-4YCH6IZV.js";import{Command as Kn}from"commander";import ir from"chalk";var ar=ir.hex("#cdfa50"),cr=ar(`
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
@@ -43,30 +43,30 @@ import{$ as Ye,L as he,M as Oe,N as re,O,P as Ke,R as je,S as Be,T as qe,U as Ge
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
- `),es=ir.cyan("PHALA TEE CLOUD CLI");import{Command as At}from"commander";import{Command as kt}from"commander";import St from"prompts";var mr=new kt().name("login").description("Set the API key for authentication").argument("[api-key]","Phala Cloud API key to set").action(async e=>{try{let r;if(!e)e=(await St({type:"password",name:"apiKey",message:"Enter your API key:",validate:async n=>{if(n.length===0)return"API key cannot be empty";try{if(await de(n),r=await he(n),!r.username)throw await G(),new Error("Invalid API key")}catch{throw new Error("Invalid API key")}return!0}})).apiKey;else if(await de(e),r=await he(e),!r.username)throw await G(),new Error("Invalid API key");o.success(`Welcome ${r.username}! API key validated and saved successfully`),o.break(),o.info(`Open in Web UI at ${v}/dashboard/`)}catch(r){o.error(`Failed to set API key: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as $t}from"commander";var lr=new $t().name("logout").description("Remove the stored API key").action(async()=>{try{await G(),o.success("API key removed successfully")}catch(e){o.error(`Failed to remove API key: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});import{createClient as It}from"@phala/cloud";import{Command as Dt}from"commander";import{safeGetCurrentUser as Pt}from"@phala/cloud";var pr=new Dt().name("status").description("Check authentication status").option("-j, --json","Output in JSON format").option("-d, --debug","Enable debug output").action(async e=>{try{let r=e.debug||process.env.DEBUG?.toLowerCase()==="true",t=V();if(!t){console.log('Not authenticated. Please set an API key with "phala auth login"');return}r&&o.debug(`Using API key: ${t.substring(0,5)}...`);try{let n=It({apiKey:t}),s=await Pt(n);if(!s.success){o.error("Failed to get user information"),s.error&&o.error(`Error: ${s.error.message}`);return}let i=s.data,c=process.env.PHALA_CLOUD_API_PREFIX||"https://cloud-api.phala.network/api/v1";if(e.json){console.log(JSON.stringify({apiUrl:c,username:i.username,team_name:i.team_name},null,2));return}console.log(`Integrated API: ${c}`),console.log(`Logged in as: ${i.username}`),console.log(`Current Workspace: ${i.team_name}`)}catch(n){console.error("Authentication failed. Your API key may be invalid or expired."),console.log('Please set a new API key with "phala auth login"'),r&&o.debug(`Error details: ${n instanceof Error?n.message:String(n)}`)}}catch(r){o.error(`Failed to check authentication status: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});var ur=new At().name("auth").description("Authenticate with Phala Cloud").addCommand(mr).addCommand(lr).addCommand(pr);import{Command as zt}from"commander";import{Command as Kt}from"commander";import{execa as Mt}from"execa";import F from"node:fs";import W from"node:path";import Nt from"handlebars";import{exec as Lt,spawn as Ut}from"node:child_process";import{promisify as Vt}from"node:util";import yr from"node:os";import Ft from"inquirer";import ye from"node:fs";import ve from"node:path";function L(e,r=process.cwd()){let t=ve.resolve(r,e);if(!ye.existsSync(t))throw new Error(`File not found at ${t}`);return!0}async function I(e,r,t="file",n=process.cwd()){return(await Ft.prompt([{type:"input",name:t,message:e,default:r,validate:i=>{let c=ve.resolve(n,i);return ye.existsSync(c)?!0:`File not found at ${c}`}}]))[t]}function j(e,r){for(let t of e){let n=ve.join(process.cwd(),t);if(ye.existsSync(n))return r?o.info(r.replace("{path}",n)):o.info(`File detected: ${n}`),t}}import*as h from"node:fs";import*as k from"node:path";import*as D from"node:os";import{execSync as A,spawn as Tt}from"node:child_process";import*as we from"node:net";var E={version:"0.5.3",baseUrl:"https://github.com/Dstack-TEE/dstack/releases/download/v0.5.3",installDir:k.join(D.homedir(),".phala-cloud","simulator"),defaultLogPath:k.join(D.homedir(),".phala-cloud","logs","dstack-simulator.log"),platforms:{darwin:{filename:"dstack-simulator-0.5.3-aarch64-apple-darwin.tgz",extractedFolder:"0.5.3",socketPath:k.join(D.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:k.join(D.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 dr(){try{if(!h.existsSync(E.installDir))return!1;let e=D.platform();if(!E.platforms[e])throw new Error(`Unsupported platform: ${e}`);let r=k.join(E.installDir,E.platforms[e].extractedFolder);if(!h.existsSync(r))return!1;let n=k.join(r,e==="win32"?"dstack-simulator.exe":"dstack-simulator");return h.existsSync(n)}catch(e){return o.error("Error checking if simulator is installed:",e),!1}}function H(){let e=D.platform();if(!E.platforms[e])throw new Error(`Unsupported platform: ${e}. Only darwin, linux, and win32 are supported.`);return e}async function fr(e){let r=t=>{o.info(t),e&&e(t)};try{let t=H(),n=E.platforms[t];if(t==="win32"){try{A("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(E.installDir)||(o.info(`Creating installation directory at ${E.installDir}`),h.mkdirSync(E.installDir,{recursive:!0})),process.chdir(E.installDir);let s=`${E.baseUrl}/${n.filename}`;o.info(`Downloading simulator from ${s}`),A(`wget ${s}`,{stdio:"inherit"});let i=k.join(E.installDir,n.extractedFolder);h.existsSync(i)||h.mkdirSync(i,{recursive:!0}),o.info(`Extracting ${n.filename} to ${i}`);let c=`tar -xvf "${n.filename}" -C "${i}" --strip-components=1`;o.debug(`Running: ${c}`);try{A(c,{stdio:"inherit"}),h.unlinkSync(n.filename)}catch(m){throw o.error(`Failed to extract ${n.filename}:`,m),new Error("Failed to extract simulator archive. Make sure you have sufficient permissions and disk space.")}o.success("Simulator installation completed successfully")}catch(t){throw o.error("Error installing simulator:",t),new Error(`Failed to install simulator: ${t}`)}}var Ce=()=>k.join(D.tmpdir(),"dstack-simulator.pid");function xt(e){return Buffer.byteLength(e,"utf8")>104}function oe(){try{let e=Ce();if(h.existsSync(e)){let r=parseInt(h.readFileSync(e,"utf-8").trim(),10);try{return process.kill(r,0),r}catch{h.unlinkSync(e)}}return null}catch(e){return o.warn("Error checking simulator PID:",e),null}}function Rt(e,r){try{let t=Ce();r&&o.info(`Saving simulator PID ${e} to: ${t}`),h.writeFileSync(t,e.toString(),"utf-8")}catch(t){o.warn("Failed to save simulator PID:",t)}}async function gr(e={}){try{let r=H(),t=E.platforms[r],n=k.join(E.installDir,t.extractedFolder),s=oe();if(s)throw new Error(`Simulator is already running with PID: ${s}`);if(r!=="win32"&&xt(t.socketPath))throw new Error(`Socket path is too long (${t.socketPath.length} chars, max 104): ${t.socketPath}`);if(r!=="win32"&&h.existsSync(t.socketPath)){o.warn(`Removing existing socket file: ${t.socketPath}`);try{h.unlinkSync(t.socketPath)}catch(l){o.warn(`Failed to remove existing socket file: ${l}`)}}process.chdir(n);let i=r==="win32"?"dstack-simulator.exe":"./dstack-simulator";e.verbose&&r!=="win32"&&o.info(`Using socket path: ${t.socketPath}`);let c={background:e.background??!0,logToFile:e.logToFile??!0,logFilePath:e.logFilePath??E.defaultLogPath};if(c.logToFile){let l=k.dirname(c.logFilePath);h.existsSync(l)||h.mkdirSync(l,{recursive:!0}),e.verbose&&o.info(`Simulator logs will be written to: ${c.logFilePath}`)}e.verbose&&o.info(`Starting simulator with: ${i}`);let m=c.logToFile?["ignore",h.openSync(c.logFilePath,"a"),h.openSync(c.logFilePath,"a")]:"inherit",p=Tt(i,[],{stdio:m,shell:r==="win32",detached:c.background});if(c.logToFile&&Array.isArray(m)&&(typeof m[1]=="number"&&h.closeSync(m[1]),typeof m[2]=="number"&&h.closeSync(m[2])),c.logToFile){let a=`
46
+ `),es=ir.cyan("PHALA TEE CLOUD CLI");import{Command as At}from"commander";import{Command as kt}from"commander";import St from"prompts";var mr=new kt().name("login").description("Set the API key for authentication").argument("[api-key]","Phala Cloud API key to set").action(async e=>{try{let r;if(!e)e=(await St({type:"password",name:"apiKey",message:"Enter your API key:",validate:async n=>{if(n.length===0)return"API key cannot be empty";try{if(await de(n),r=await he(n),!r.username)throw await G(),new Error("Invalid API key")}catch{throw new Error("Invalid API key")}return!0}})).apiKey;else if(await de(e),r=await he(e),!r.username)throw await G(),new Error("Invalid API key");o.success(`Welcome ${r.username}! API key validated and saved successfully`),o.break(),o.info(`Open in Web UI at ${v}/dashboard/`)}catch(r){o.error(`Failed to set API key: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as $t}from"commander";var lr=new $t().name("logout").description("Remove the stored API key").action(async()=>{try{await G(),o.success("API key removed successfully")}catch(e){o.error(`Failed to remove API key: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});import{createClient as It}from"@phala/cloud";import{Command as Dt}from"commander";import{safeGetCurrentUser as Pt}from"@phala/cloud";var pr=new Dt().name("status").description("Check authentication status").option("-j, --json","Output in JSON format").option("-d, --debug","Enable debug output").action(async e=>{try{let r=e.debug||process.env.DEBUG?.toLowerCase()==="true",t=O();if(!t){console.log('Not authenticated. Please set an API key with "phala auth login"');return}r&&o.debug(`Using API key: ${t.substring(0,5)}...`);try{let n=It({apiKey:t}),s=await Pt(n);if(!s.success){o.error("Failed to get user information"),s.error&&o.error(`Error: ${s.error.message}`);return}let i=s.data,c=process.env.PHALA_CLOUD_API_PREFIX||"https://cloud-api.phala.network/api/v1";if(e.json){console.log(JSON.stringify({apiUrl:c,username:i.username,team_name:i.team_name},null,2));return}console.log(`Integrated API: ${c}`),console.log(`Logged in as: ${i.username}`),console.log(`Current Workspace: ${i.team_name}`)}catch(n){console.error("Authentication failed. Your API key may be invalid or expired."),console.log('Please set a new API key with "phala auth login"'),r&&o.debug(`Error details: ${n instanceof Error?n.message:String(n)}`)}}catch(r){o.error(`Failed to check authentication status: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});var ur=new At().name("auth").description("Authenticate with Phala Cloud").addCommand(mr).addCommand(lr).addCommand(pr);import{Command as zt}from"commander";import{Command as Kt}from"commander";import{execa as Mt}from"execa";import F from"node:fs";import W from"node:path";import Nt from"handlebars";import{exec as Lt,spawn as Ut}from"node:child_process";import{promisify as Vt}from"node:util";import yr from"node:os";import Ft from"inquirer";import ye from"node:fs";import ve from"node:path";function U(e,r=process.cwd()){let t=ve.resolve(r,e);if(!ye.existsSync(t))throw new Error(`File not found at ${t}`);return!0}async function I(e,r,t="file",n=process.cwd()){return(await Ft.prompt([{type:"input",name:t,message:e,default:r,validate:i=>{let c=ve.resolve(n,i);return ye.existsSync(c)?!0:`File not found at ${c}`}}]))[t]}function B(e,r){for(let t of e){let n=ve.join(process.cwd(),t);if(ye.existsSync(n))return r?o.info(r.replace("{path}",n)):o.info(`File detected: ${n}`),t}}import*as h from"node:fs";import*as k from"node:path";import*as D from"node:os";import{execSync as A,spawn as Tt}from"node:child_process";import*as we from"node:net";var E={version:"0.5.3",baseUrl:"https://github.com/Dstack-TEE/dstack/releases/download/v0.5.3",installDir:k.join(D.homedir(),".phala-cloud","simulator"),defaultLogPath:k.join(D.homedir(),".phala-cloud","logs","dstack-simulator.log"),platforms:{darwin:{filename:"dstack-simulator-0.5.3-aarch64-apple-darwin.tgz",extractedFolder:"0.5.3",socketPath:k.join(D.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:k.join(D.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 dr(){try{if(!h.existsSync(E.installDir))return!1;let e=D.platform();if(!E.platforms[e])throw new Error(`Unsupported platform: ${e}`);let r=k.join(E.installDir,E.platforms[e].extractedFolder);if(!h.existsSync(r))return!1;let n=k.join(r,e==="win32"?"dstack-simulator.exe":"dstack-simulator");return h.existsSync(n)}catch(e){return o.error("Error checking if simulator is installed:",e),!1}}function H(){let e=D.platform();if(!E.platforms[e])throw new Error(`Unsupported platform: ${e}. Only darwin, linux, and win32 are supported.`);return e}async function fr(e){let r=t=>{o.info(t),e&&e(t)};try{let t=H(),n=E.platforms[t];if(t==="win32"){try{A("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(E.installDir)||(o.info(`Creating installation directory at ${E.installDir}`),h.mkdirSync(E.installDir,{recursive:!0})),process.chdir(E.installDir);let s=`${E.baseUrl}/${n.filename}`;o.info(`Downloading simulator from ${s}`),A(`wget ${s}`,{stdio:"inherit"});let i=k.join(E.installDir,n.extractedFolder);h.existsSync(i)||h.mkdirSync(i,{recursive:!0}),o.info(`Extracting ${n.filename} to ${i}`);let c=`tar -xvf "${n.filename}" -C "${i}" --strip-components=1`;o.debug(`Running: ${c}`);try{A(c,{stdio:"inherit"}),h.unlinkSync(n.filename)}catch(m){throw o.error(`Failed to extract ${n.filename}:`,m),new Error("Failed to extract simulator archive. Make sure you have sufficient permissions and disk space.")}o.success("Simulator installation completed successfully")}catch(t){throw o.error("Error installing simulator:",t),new Error(`Failed to install simulator: ${t}`)}}var Ce=()=>k.join(D.tmpdir(),"dstack-simulator.pid");function xt(e){return Buffer.byteLength(e,"utf8")>104}function oe(){try{let e=Ce();if(h.existsSync(e)){let r=parseInt(h.readFileSync(e,"utf-8").trim(),10);try{return process.kill(r,0),r}catch{h.unlinkSync(e)}}return null}catch(e){return o.warn("Error checking simulator PID:",e),null}}function Rt(e,r){try{let t=Ce();r&&o.info(`Saving simulator PID ${e} to: ${t}`),h.writeFileSync(t,e.toString(),"utf-8")}catch(t){o.warn("Failed to save simulator PID:",t)}}async function gr(e={}){try{let r=H(),t=E.platforms[r],n=k.join(E.installDir,t.extractedFolder),s=oe();if(s)throw new Error(`Simulator is already running with PID: ${s}`);if(r!=="win32"&&xt(t.socketPath))throw new Error(`Socket path is too long (${t.socketPath.length} chars, max 104): ${t.socketPath}`);if(r!=="win32"&&h.existsSync(t.socketPath)){o.warn(`Removing existing socket file: ${t.socketPath}`);try{h.unlinkSync(t.socketPath)}catch(l){o.warn(`Failed to remove existing socket file: ${l}`)}}process.chdir(n);let i=r==="win32"?"dstack-simulator.exe":"./dstack-simulator";e.verbose&&r!=="win32"&&o.info(`Using socket path: ${t.socketPath}`);let c={background:e.background??!0,logToFile:e.logToFile??!0,logFilePath:e.logFilePath??E.defaultLogPath};if(c.logToFile){let l=k.dirname(c.logFilePath);h.existsSync(l)||h.mkdirSync(l,{recursive:!0}),e.verbose&&o.info(`Simulator logs will be written to: ${c.logFilePath}`)}e.verbose&&o.info(`Starting simulator with: ${i}`);let m=c.logToFile?["ignore",h.openSync(c.logFilePath,"a"),h.openSync(c.logFilePath,"a")]:"inherit",p=Tt(i,[],{stdio:m,shell:r==="win32",detached:c.background});if(c.logToFile&&Array.isArray(m)&&(typeof m[1]=="number"&&h.closeSync(m[1]),typeof m[2]=="number"&&h.closeSync(m[2])),c.logToFile){let a=`
47
47
  === Simulator started at ${new Date().toISOString()} ===
48
48
  Command: ${i}
49
49
 
50
- `;h.appendFileSync(c.logFilePath,a)}return p.pid&&Rt(p.pid,e.verbose),c.background&&(p.unref(),e.verbose&&o.success("Simulator is running in the background")),await Ee(),p}catch(r){throw o.error("Error running simulator:",r),new Error(`Failed to run simulator: ${r}`)}}async function z(){try{let e=H(),r=E.platforms[e];if(e==="darwin"||e==="linux"){let t=r.socketPath;return h.existsSync(t)?new Promise(n=>{let s=we.createConnection({path:t}).on("connect",()=>{s.end(),n(!0)}).on("error",()=>{n(!1)});setTimeout(()=>{s.end(),n(!1)},1e3)}):!1}if(e==="win32"){let t="127.0.0.1";return new Promise(s=>{let i=we.createConnection({host:t,port:8090}).on("connect",()=>{i.end(),s(!0)}).on("error",()=>{s(!1)});setTimeout(()=>{i.end(),s(!1)},1e3)})}return!1}catch(e){return o.error("Error checking if simulator is running:",e),!1}}async function hr(){try{let e=oe();if(!await z()&&!e)return o.info("Simulator is not running"),!0;let t=H(),n=!1;if(t==="win32")try{e?(o.info(`Stopping simulator process (PID: ${e})...`),process.kill(e,"SIGTERM")):A("taskkill /F /IM dstack-simulator.exe",{stdio:"ignore"}),n=!0}catch(i){if(i.code!=="ESRCH")return o.error("Failed to stop simulator:",i),!1;n=!0}else try{e?(o.info(`Stopping simulator process (PID: ${e})...`),process.kill(e,"SIGTERM")):A("pkill -f dstack-simulator",{stdio:"ignore"}),n=!0}catch(i){if(i.code!=="ESRCH")return o.error("Failed to stop simulator:",i),!1;n=!0}let s=Ce();if(h.existsSync(s))try{h.unlinkSync(s)}catch(i){o.warn("Failed to remove PID file:",i)}return await U(),n&&o.success("Simulator stopped successfully"),n}catch(e){return o.error("Error stopping simulator:",e),!1}}function ne(){let e=H(),r=E.platforms[e];return e==="win32"?"http://127.0.0.1:8090":`${r.socketPath||"/tmp/dstack.sock"}`}async function Ee(e){try{let r=ne(),t=e||r;await A(`export DSTACK_SIMULATOR_ENDPOINT=${t}`);let n=t.replace(/dstack\.sock$/,"tappd.sock");return await A(`export TAPPD_SIMULATOR_ENDPOINT=${n}`),o.success("Setting environment for current process..."),o.success(` DSTACK_SIMULATOR_ENDPOINT=${t}`),o.success(` TAPPD_SIMULATOR_ENDPOINT=${n}`),t}catch(r){throw o.error("Error setting simulator endpoint environment variable:",r),new Error(`Failed to set simulator endpoint: ${r}`)}}async function U(){try{return await A("unset DSTACK_SIMULATOR_ENDPOINT"),await A("unset TAPPD_SIMULATOR_ENDPOINT"),o.debug("Deleted simulator endpoint environment variables from current process"),!0}catch(e){return o.warn("Error while unsetting simulator endpoint environment variables:",e),!1}}var J=Vt(Lt),vr=".phala-cloud/logs",Ot=".phala-cloud/compose",wr=10,S=class{username;image;registry;constructor(r,t,n){this.image=r,this.username=t||"",this.registry=n||""}ensureLogsDir(){let r=W.resolve(vr);F.existsSync(r)||F.mkdirSync(r,{recursive:!0})}getLogFilePath(r,t){let n=new Date().toISOString().replace(/[:.]/g,"-");return W.resolve(vr,`${t||this.image}-${r}-${n}.log`)}getSystemArchitecture(){let r=yr.arch();switch(r){case"arm":case"arm64":return"arm64";case"x64":return"amd64";default:return r}}spawnProcess(r,t,n,s){return new Promise((i,c)=>{let m=Ut(r,t);this.ensureLogsDir();let p=this.getLogFilePath(n,s),l=F.createWriteStream(p,{flags:"a"}),a=[],f=(u,d=!1)=>{let y=u.toString().split(`
50
+ `;h.appendFileSync(c.logFilePath,a)}return p.pid&&Rt(p.pid,e.verbose),c.background&&(p.unref(),e.verbose&&o.success("Simulator is running in the background")),await Ee(),p}catch(r){throw o.error("Error running simulator:",r),new Error(`Failed to run simulator: ${r}`)}}async function z(){try{let e=H(),r=E.platforms[e];if(e==="darwin"||e==="linux"){let t=r.socketPath;return h.existsSync(t)?new Promise(n=>{let s=we.createConnection({path:t}).on("connect",()=>{s.end(),n(!0)}).on("error",()=>{n(!1)});setTimeout(()=>{s.end(),n(!1)},1e3)}):!1}if(e==="win32"){let t="127.0.0.1";return new Promise(s=>{let i=we.createConnection({host:t,port:8090}).on("connect",()=>{i.end(),s(!0)}).on("error",()=>{s(!1)});setTimeout(()=>{i.end(),s(!1)},1e3)})}return!1}catch(e){return o.error("Error checking if simulator is running:",e),!1}}async function hr(){try{let e=oe();if(!await z()&&!e)return o.info("Simulator is not running"),!0;let t=H(),n=!1;if(t==="win32")try{e?(o.info(`Stopping simulator process (PID: ${e})...`),process.kill(e,"SIGTERM")):A("taskkill /F /IM dstack-simulator.exe",{stdio:"ignore"}),n=!0}catch(i){if(i.code!=="ESRCH")return o.error("Failed to stop simulator:",i),!1;n=!0}else try{e?(o.info(`Stopping simulator process (PID: ${e})...`),process.kill(e,"SIGTERM")):A("pkill -f dstack-simulator",{stdio:"ignore"}),n=!0}catch(i){if(i.code!=="ESRCH")return o.error("Failed to stop simulator:",i),!1;n=!0}let s=Ce();if(h.existsSync(s))try{h.unlinkSync(s)}catch(i){o.warn("Failed to remove PID file:",i)}return await V(),n&&o.success("Simulator stopped successfully"),n}catch(e){return o.error("Error stopping simulator:",e),!1}}function ne(){let e=H(),r=E.platforms[e];return e==="win32"?"http://127.0.0.1:8090":`${r.socketPath||"/tmp/dstack.sock"}`}async function Ee(e){try{let r=ne(),t=e||r;await A(`export DSTACK_SIMULATOR_ENDPOINT=${t}`);let n=t.replace(/dstack\.sock$/,"tappd.sock");return await A(`export TAPPD_SIMULATOR_ENDPOINT=${n}`),o.success("Setting environment for current process..."),o.success(` DSTACK_SIMULATOR_ENDPOINT=${t}`),o.success(` TAPPD_SIMULATOR_ENDPOINT=${n}`),t}catch(r){throw o.error("Error setting simulator endpoint environment variable:",r),new Error(`Failed to set simulator endpoint: ${r}`)}}async function V(){try{return await A("unset DSTACK_SIMULATOR_ENDPOINT"),await A("unset TAPPD_SIMULATOR_ENDPOINT"),o.debug("Deleted simulator endpoint environment variables from current process"),!0}catch(e){return o.warn("Error while unsetting simulator endpoint environment variables:",e),!1}}var J=Vt(Lt),vr=".phala-cloud/logs",Ot=".phala-cloud/compose",wr=10,S=class{username;image;registry;constructor(r,t,n){this.image=r,this.username=t||"",this.registry=n||""}ensureLogsDir(){let r=W.resolve(vr);F.existsSync(r)||F.mkdirSync(r,{recursive:!0})}getLogFilePath(r,t){let n=new Date().toISOString().replace(/[:.]/g,"-");return W.resolve(vr,`${t||this.image}-${r}-${n}.log`)}getSystemArchitecture(){let r=yr.arch();switch(r){case"arm":case"arm64":return"arm64";case"x64":return"amd64";default:return r}}spawnProcess(r,t,n,s){return new Promise((i,c)=>{let m=Ut(r,t);this.ensureLogsDir();let p=this.getLogFilePath(n,s),l=F.createWriteStream(p,{flags:"a"}),a=[],f=(u,d=!1)=>{let y=u.toString().split(`
51
51
  `);l.write(u);for(let g of y)if(g.trim()){a.push(g),a.length>wr&&a.shift(),console.clear(),console.log(`Latest ${wr} lines (full log at ${p}):`),console.log("-".repeat(50));for(let C of a)d?console.error(C):console.log(C)}};m.stdout.on("data",u=>f(u)),m.stderr.on("data",u=>f(u,!0)),m.on("close",u=>{l.end(),u===0?(console.log(`
52
- Operation completed. Full log available at: ${p}`),i()):c(new Error(`Process exited with code ${u}. Check log file: ${p}`))}),m.on("error",u=>{l.end(),c(u)})})}setCredentials(r,t){this.username=r,t&&(this.registry=t)}async buildImage(r,t){try{let n=this.getSystemArchitecture(),s=`${this.username}/${this.image}:${t}`,i=o.startSpinner(`Building Docker image ${this.username}/${this.image}:${t}`);L(r);let c=["build","-t",s,"-f",r];return n==="arm64"&&(console.log("Detected arm64 architecture, using --platform linux/amd64"),c.push("--platform","linux/amd64")),c.push("."),await this.spawnProcess("docker",c,"build",this.image),i.stop(!0,`Docker image ${s} built successfully`),!0}catch(n){return o.error(`Failed to build Docker image: ${n instanceof Error?n.message:String(n)}`),!1}}async pushImage(r){try{let t=o.startSpinner(`Pushing Docker image ${r} to Docker Hub`);if(!await P())throw t.stop(!1),new Error('Docker credentials not found. Please log in first with "phala docker login"');let s=r;return console.log(`Pushing image ${s} to Docker Hub...`),await this.spawnProcess("docker",["push",s],"push",r.replace(/.*\/+([\w-]+):.*$/g,"$1")),t.stop(!0,`Docker image ${s} pushed successfully`),!0}catch(t){return o.error(`Failed to push Docker image: ${t instanceof Error?t.message:String(t)}`),!1}}async login(r,t,n){try{let s=o.startSpinner(`Logging in to Docker Hub as ${r}`);if(await this.checkLogin())return s.stop(!0,"Already logged in to Docker Hub"),this.setCredentials(r,n),!0;if(!t)throw s.stop(!1),new Error("Password is required for Docker login");try{await Mt("docker",["login",...n?[n]:[],"-u",r,"--password-stdin"],{input:t,timeout:1e4})}catch(c){throw c.timedOut?(s.stop(!1),new Error("Docker login timed out. Please check your credentials and try again.")):c}return s.stop(!0,"Logged in to Docker Hub successfully"),this.setCredentials(r,n),!0}catch(s){return o.error(`Failed to login to Docker Hub: ${s instanceof Error?s.message:String(s)}`),!1}}async checkLogin(){try{let r=yr.homedir(),t=W.join(r,".docker","config.json");if(!F.existsSync(t))return!1;let n=JSON.parse(F.readFileSync(t,"utf-8"));return!!(n?.auths&&Object.keys(n.auths).length>0)}catch(r){return o.debug(`Docker login check failed: ${r instanceof Error?r.message:String(r)}`),!1}}async buildComposeFile(r,t,n){if(!this.username)throw new Error("Docker Hub username is required for building compose file");let s=n==="eliza"?Le:Ue,i=Ve.parse({template:s}),c=W.resolve(Ot);F.existsSync(c)||(o.info(`Creating directory: ${c}`),F.mkdirSync(c,{recursive:!0}));let m=[];t&&(m=F.readFileSync(t,"utf-8").split(`
53
- `).filter(d=>d&&!d.startsWith("#")).map(d=>{let y=d.indexOf("#");return y>0&&(d=d.substring(0,y).trim()),d.trim()}).filter(d=>d.includes("=")).map(d=>{let[y,g]=d.split("=",2),C=y.trim();return(g?g.trim():"")===""?null:`${C}=${C}`}).filter(Boolean));let p=r,a=Nt.compile(i.template,{noEscape:!0})({imageName:p,envVars:m.map(u=>u.replace(/=.*/,`=\${${u.split("=")[0]}}`))}),f=W.join(c,`${r.replace(/.*\/+([\w-]+):.*$/g,"$1")}-tee-compose.yaml`);return F.writeFileSync(f,a),o.success(`Backup of docker compose file created at: ${f}`),f}async runComposeLocally(r,t){try{let n=o.startSpinner(`Running Docker Compose file at ${r}`);L(r);let s=["-f",r,"up","-d"];return t&&(L(t),s.splice(2,0,"--env-file",t)),await J(`docker compose ${s.join(" ")}`),n.stop(!0,"Docker Compose file running successfully"),!0}catch(n){return o.error(`Failed to run Docker Compose file: ${n instanceof Error?n.message:String(n)}`),!1}}async runSimulator(r,t){try{o.info(`Running TEE simulator with image ${r}`),o.info("Pulling latest simulator image..."),await J(`docker pull ${r}`),o.info("Starting simulator in background...");let{stdout:n}=await J(`docker run -d --name tee-simulator --rm -p ${t}:${t} ${r}`),s=n.trim();return o.success(`TEE simulator running successfully. Container ID: ${s}`),o.break(),o.break(),o.info("Useful commands:"),o.info(`- View logs: docker logs -f ${s}`),o.info(`- Stop simulator: docker stop ${s}`),Ee(`http://localhost:${t}`),!0}catch(n){return o.error(`Failed to run TEE simulator: ${n instanceof Error?n.message:String(n)}`),!1}}async stopSimulator(){try{let r=o.startSpinner("Stopping TEE simulator...");return await J("docker stop tee-simulator"),await U(),r.stop(!0,"TEE simulator stopped successfully"),!0}catch(r){return o.error(`Failed to stop TEE simulator: ${r instanceof Error?r.message:String(r)}`),!1}}static async listLocalImages(){try{let{stdout:r}=await J('docker images --format "{{.Repository}}:{{.Tag}}"'),n=(await P())?.username;return r.split(`
54
- `).filter(i=>i&&!i.includes("<none>")).filter(i=>i.includes(`${n}/`)).map(i=>({imageName:i}))}catch(r){return o.error(`Failed to list local Docker images: ${r instanceof Error?r.message:String(r)}`),[]}}};import Cr from"prompts";var Er=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 e=>{try{let r=e.username,t=e.password,n=e.registry;if(!r){o.info("First we need your Docker Hub username to check if you are already logged in.");let m=await Cr({type:"text",name:"username",message:"Enter your Docker Hub username:",validate:p=>p.length>0?!0:"Username cannot be empty"});m.username||(o.error("Username is required"),process.exit(1)),r=m.username}let s=new S("",r,n);if(await s.login(r)){o.success(`${r} is logged in to Docker Hub`),await fe({username:r,registry:n||null});return}if(!t){let m=await Cr({type:"password",name:"password",message:"Enter your Docker Hub password:",validate:p=>p.length>0?!0:"Password cannot be empty"});m.password||(o.error("Password is required"),process.exit(1)),t=m.password}await s.login(r,t,n)||(o.error("Failed to login to Docker Hub"),process.exit(1)),await fe({username:r,registry:n||null}),o.success("Logged in to Docker Hub successfully")}catch(r){o.error(`Failed to login to Docker Hub: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as jt}from"commander";import _r from"node:path";import br from"inquirer";import Bt from"node:fs";var kr=new jt().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 e=>{try{let r=await P();if(r||(o.error('Docker information not found. Please login first with "phala docker login"'),process.exit(1)),!e.image){let c=await br.prompt([{type:"input",name:"image",message:"Enter the Docker image name:",validate:m=>m.trim()?!0:"Image name is required"}]);e.image=c.image}if(!e.tag){let c=await br.prompt([{type:"input",name:"tag",message:"Enter the Docker image tag:",default:"latest",validate:m=>m.trim()?!0:"Tag is required"}]);e.tag=c.tag}let t=_r.resolve(process.cwd(),e.file);Bt.existsSync(t)||(o.info(`Default Dockerfile not found at ${t}`),e.file=await I("Enter the path to your Dockerfile:","Dockerfile","file"));let n=_r.resolve(process.cwd(),e.file);await new S(e.image,r.username,r.registry).buildImage(n,e.tag)||(o.error("Failed to build Docker image"),process.exit(1)),o.success(`Docker image ${r.username}/${e.image}:${e.tag} built successfully`)}catch(r){o.error(`Failed to build Docker image: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as qt}from"commander";import Gt from"inquirer";var Sr=new qt().name("push").description("Push a Docker image to Docker Hub").option("-i, --image <image>","Full image name (e.g. username/image:tag)").action(async e=>{try{let r=await P();r||(o.error('Docker information not found. Please login first with "phala docker login"'),process.exit(1));let t=e.image;if(!t){let i=await S.listLocalImages();if(i.length===0&&(o.error('No local Docker images found. Please build an image first with "phala docker build"'),process.exit(1)),!t){let c=Array.from(new Set(i.map(p=>p.imageName))),{selectedImage:m}=await Gt.prompt([{type:"list",name:"selectedImage",message:"Select an image to push:",choices:c}]);t=m}}await new S("",r.username,r.registry).pushImage(t)||(o.error("Failed to push Docker image"),process.exit(1)),o.success(`Docker image ${t} pushed successfully`)}catch(r){o.error(`Failed to push Docker image: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as Ht}from"commander";import Y from"inquirer";import Q from"node:fs";import se from"node:path";var $r=new Ht().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 e=>{try{let r=await P();(!r||!r.username)&&(o.error("Docker Hub username not found. Please login first with `phala docker login`"),process.exit(1));let t=e.image;if(!t){let m=await S.listLocalImages();if(m.length===0&&(o.error('No local Docker images found. Please build an image first with "phala docker build"'),process.exit(1)),!t){let p=Array.from(new Set(m.map(a=>a.imageName))),{selectedImage:l}=await Y.prompt([{type:"list",name:"selectedImage",message:"Select an image to use in the compose file:",choices:p}]);t=l}}let n=e.envFile;if(n)try{L(n)}catch{o.error(`File not found: ${n}`),process.exit(1)}else{let m=se.join(process.cwd(),".env");if(Q.existsSync(m)){let{useDefault:l}=await Y.prompt([{type:"confirm",name:"useDefault",message:"Use .env file in current directory?",default:!0}]);l&&(n=m)}if(!n){let{envPath:l}=await Y.prompt([{type:"input",name:"envPath",message:"Enter path to environment variables file:",validate:a=>{try{return L(a),!0}catch{return`File not found: ${a}`}}}]);n=l}}let s=e.output;if(!s&&(s=se.join(process.cwd(),"docker-compose.yml"),Q.existsSync(s))){let{confirmOverwrite:m}=await Y.prompt([{type:"confirm",name:"confirmOverwrite",message:`File ${s} already exists. Overwrite?`,default:!1}]);if(!m){let{customPath:p}=await Y.prompt([{type:"input",name:"customPath",message:"Enter alternative output path:",default:se.join(process.cwd(),"docker-generated-compose.yml")}]);s=p}}let i=new S("",r.username,r.registry);n?o.info(`Generating Docker Compose file for ${t} using env file: ${n}`):o.info(`Generating Docker Compose file for ${t} without env file`);let c=await i.buildComposeFile(t,n,e.template);if(c!==s){let m=se.dirname(s);Q.existsSync(m)||(o.info(`Creating directory: ${m}`),Q.mkdirSync(m,{recursive:!0})),Q.copyFileSync(c,s)}o.success(`Docker Compose file generated successfully: ${s}`)}catch(r){o.error(`Failed to generate Docker Compose file: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});var Ir=new zt().name("docker").description("Login to Docker Hub and manage Docker images").addCommand(Er).addCommand(kr).addCommand(Sr).addCommand($r);import{Command as Yt}from"commander";import{Command as Wt}from"commander";var Dr=new Wt().name("start").description("Start the TEE simulator").option("-p, --port <port>","Simulator port (default: 8090)","8090").option("-v, --verbose","Enable verbose output",!1).action(async e=>{try{if(dr()||await fr(),await z()){o.success("TEE simulator is already running");return}let t=await gr({verbose:e.verbose});o.success("TEE simulator started successfully")}catch(r){o.error(`Failed to start TEE simulator: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as Jt}from"commander";var Pr=new Jt().name("stop").description("Stop the TEE simulator").action(async()=>{try{await hr()||(o.error("Failed to stop TEE simulator"),process.exit(1)),o.success("TEE simulator stopped successfully")}catch(e){o.error(`Failed to stop TEE simulator: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});var _e=new Yt().name("simulator").description("TEE simulator commands").addCommand(Dr).addCommand(Pr);_e.action(async()=>{try{let e=await z(),r=oe();if(e&&r){let t=ne(),n=ne(),s=n.replace(/dstack\.sock$/,"tappd.sock");console.log(`\u2713 TEE simulator is running (PID: ${r})`),console.log(`
52
+ Operation completed. Full log available at: ${p}`),i()):c(new Error(`Process exited with code ${u}. Check log file: ${p}`))}),m.on("error",u=>{l.end(),c(u)})})}setCredentials(r,t){this.username=r,t&&(this.registry=t)}async buildImage(r,t){try{let n=this.getSystemArchitecture(),s=`${this.username}/${this.image}:${t}`,i=o.startSpinner(`Building Docker image ${this.username}/${this.image}:${t}`);U(r);let c=["build","-t",s,"-f",r];return n==="arm64"&&(console.log("Detected arm64 architecture, using --platform linux/amd64"),c.push("--platform","linux/amd64")),c.push("."),await this.spawnProcess("docker",c,"build",this.image),i.stop(!0,`Docker image ${s} built successfully`),!0}catch(n){return o.error(`Failed to build Docker image: ${n instanceof Error?n.message:String(n)}`),!1}}async pushImage(r){try{let t=o.startSpinner(`Pushing Docker image ${r} to Docker Hub`);if(!await P())throw t.stop(!1),new Error('Docker credentials not found. Please log in first with "phala docker login"');let s=r;return console.log(`Pushing image ${s} to Docker Hub...`),await this.spawnProcess("docker",["push",s],"push",r.replace(/.*\/+([\w-]+):.*$/g,"$1")),t.stop(!0,`Docker image ${s} pushed successfully`),!0}catch(t){return o.error(`Failed to push Docker image: ${t instanceof Error?t.message:String(t)}`),!1}}async login(r,t,n){try{let s=o.startSpinner(`Logging in to Docker Hub as ${r}`);if(await this.checkLogin())return s.stop(!0,"Already logged in to Docker Hub"),this.setCredentials(r,n),!0;if(!t)throw s.stop(!1),new Error("Password is required for Docker login");try{await Mt("docker",["login",...n?[n]:[],"-u",r,"--password-stdin"],{input:t,timeout:1e4})}catch(c){throw c.timedOut?(s.stop(!1),new Error("Docker login timed out. Please check your credentials and try again.")):c}return s.stop(!0,"Logged in to Docker Hub successfully"),this.setCredentials(r,n),!0}catch(s){return o.error(`Failed to login to Docker Hub: ${s instanceof Error?s.message:String(s)}`),!1}}async checkLogin(){try{let r=yr.homedir(),t=W.join(r,".docker","config.json");if(!F.existsSync(t))return!1;let n=JSON.parse(F.readFileSync(t,"utf-8"));return!!(n?.auths&&Object.keys(n.auths).length>0)}catch(r){return o.debug(`Docker login check failed: ${r instanceof Error?r.message:String(r)}`),!1}}async buildComposeFile(r,t,n){if(!this.username)throw new Error("Docker Hub username is required for building compose file");let s=n==="eliza"?Le:Ue,i=Ve.parse({template:s}),c=W.resolve(Ot);F.existsSync(c)||(o.info(`Creating directory: ${c}`),F.mkdirSync(c,{recursive:!0}));let m=[];t&&(m=F.readFileSync(t,"utf-8").split(`
53
+ `).filter(d=>d&&!d.startsWith("#")).map(d=>{let y=d.indexOf("#");return y>0&&(d=d.substring(0,y).trim()),d.trim()}).filter(d=>d.includes("=")).map(d=>{let[y,g]=d.split("=",2),C=y.trim();return(g?g.trim():"")===""?null:`${C}=${C}`}).filter(Boolean));let p=r,a=Nt.compile(i.template,{noEscape:!0})({imageName:p,envVars:m.map(u=>u.replace(/=.*/,`=\${${u.split("=")[0]}}`))}),f=W.join(c,`${r.replace(/.*\/+([\w-]+):.*$/g,"$1")}-tee-compose.yaml`);return F.writeFileSync(f,a),o.success(`Backup of docker compose file created at: ${f}`),f}async runComposeLocally(r,t){try{let n=o.startSpinner(`Running Docker Compose file at ${r}`);U(r);let s=["-f",r,"up","-d"];return t&&(U(t),s.splice(2,0,"--env-file",t)),await J(`docker compose ${s.join(" ")}`),n.stop(!0,"Docker Compose file running successfully"),!0}catch(n){return o.error(`Failed to run Docker Compose file: ${n instanceof Error?n.message:String(n)}`),!1}}async runSimulator(r,t){try{o.info(`Running TEE simulator with image ${r}`),o.info("Pulling latest simulator image..."),await J(`docker pull ${r}`),o.info("Starting simulator in background...");let{stdout:n}=await J(`docker run -d --name tee-simulator --rm -p ${t}:${t} ${r}`),s=n.trim();return o.success(`TEE simulator running successfully. Container ID: ${s}`),o.break(),o.break(),o.info("Useful commands:"),o.info(`- View logs: docker logs -f ${s}`),o.info(`- Stop simulator: docker stop ${s}`),Ee(`http://localhost:${t}`),!0}catch(n){return o.error(`Failed to run TEE simulator: ${n instanceof Error?n.message:String(n)}`),!1}}async stopSimulator(){try{let r=o.startSpinner("Stopping TEE simulator...");return await J("docker stop tee-simulator"),await V(),r.stop(!0,"TEE simulator stopped successfully"),!0}catch(r){return o.error(`Failed to stop TEE simulator: ${r instanceof Error?r.message:String(r)}`),!1}}static async listLocalImages(){try{let{stdout:r}=await J('docker images --format "{{.Repository}}:{{.Tag}}"'),n=(await P())?.username;return r.split(`
54
+ `).filter(i=>i&&!i.includes("<none>")).filter(i=>i.includes(`${n}/`)).map(i=>({imageName:i}))}catch(r){return o.error(`Failed to list local Docker images: ${r instanceof Error?r.message:String(r)}`),[]}}};import Cr from"prompts";var Er=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 e=>{try{let r=e.username,t=e.password,n=e.registry;if(!r){o.info("First we need your Docker Hub username to check if you are already logged in.");let m=await Cr({type:"text",name:"username",message:"Enter your Docker Hub username:",validate:p=>p.length>0?!0:"Username cannot be empty"});m.username||(o.error("Username is required"),process.exit(1)),r=m.username}let s=new S("",r,n);if(await s.login(r)){o.success(`${r} is logged in to Docker Hub`),await fe({username:r,registry:n||null});return}if(!t){let m=await Cr({type:"password",name:"password",message:"Enter your Docker Hub password:",validate:p=>p.length>0?!0:"Password cannot be empty"});m.password||(o.error("Password is required"),process.exit(1)),t=m.password}await s.login(r,t,n)||(o.error("Failed to login to Docker Hub"),process.exit(1)),await fe({username:r,registry:n||null}),o.success("Logged in to Docker Hub successfully")}catch(r){o.error(`Failed to login to Docker Hub: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as jt}from"commander";import _r from"node:path";import br from"inquirer";import Bt from"node:fs";var kr=new jt().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 e=>{try{let r=await P();if(r||(o.error('Docker information not found. Please login first with "phala docker login"'),process.exit(1)),!e.image){let c=await br.prompt([{type:"input",name:"image",message:"Enter the Docker image name:",validate:m=>m.trim()?!0:"Image name is required"}]);e.image=c.image}if(!e.tag){let c=await br.prompt([{type:"input",name:"tag",message:"Enter the Docker image tag:",default:"latest",validate:m=>m.trim()?!0:"Tag is required"}]);e.tag=c.tag}let t=_r.resolve(process.cwd(),e.file);Bt.existsSync(t)||(o.info(`Default Dockerfile not found at ${t}`),e.file=await I("Enter the path to your Dockerfile:","Dockerfile","file"));let n=_r.resolve(process.cwd(),e.file);await new S(e.image,r.username,r.registry).buildImage(n,e.tag)||(o.error("Failed to build Docker image"),process.exit(1)),o.success(`Docker image ${r.username}/${e.image}:${e.tag} built successfully`)}catch(r){o.error(`Failed to build Docker image: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as qt}from"commander";import Gt from"inquirer";var Sr=new qt().name("push").description("Push a Docker image to Docker Hub").option("-i, --image <image>","Full image name (e.g. username/image:tag)").action(async e=>{try{let r=await P();r||(o.error('Docker information not found. Please login first with "phala docker login"'),process.exit(1));let t=e.image;if(!t){let i=await S.listLocalImages();if(i.length===0&&(o.error('No local Docker images found. Please build an image first with "phala docker build"'),process.exit(1)),!t){let c=Array.from(new Set(i.map(p=>p.imageName))),{selectedImage:m}=await Gt.prompt([{type:"list",name:"selectedImage",message:"Select an image to push:",choices:c}]);t=m}}await new S("",r.username,r.registry).pushImage(t)||(o.error("Failed to push Docker image"),process.exit(1)),o.success(`Docker image ${t} pushed successfully`)}catch(r){o.error(`Failed to push Docker image: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as Ht}from"commander";import Y from"inquirer";import Q from"node:fs";import se from"node:path";var $r=new Ht().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 e=>{try{let r=await P();(!r||!r.username)&&(o.error("Docker Hub username not found. Please login first with `phala docker login`"),process.exit(1));let t=e.image;if(!t){let m=await S.listLocalImages();if(m.length===0&&(o.error('No local Docker images found. Please build an image first with "phala docker build"'),process.exit(1)),!t){let p=Array.from(new Set(m.map(a=>a.imageName))),{selectedImage:l}=await Y.prompt([{type:"list",name:"selectedImage",message:"Select an image to use in the compose file:",choices:p}]);t=l}}let n=e.envFile;if(n)try{U(n)}catch{o.error(`File not found: ${n}`),process.exit(1)}else{let m=se.join(process.cwd(),".env");if(Q.existsSync(m)){let{useDefault:l}=await Y.prompt([{type:"confirm",name:"useDefault",message:"Use .env file in current directory?",default:!0}]);l&&(n=m)}if(!n){let{envPath:l}=await Y.prompt([{type:"input",name:"envPath",message:"Enter path to environment variables file:",validate:a=>{try{return U(a),!0}catch{return`File not found: ${a}`}}}]);n=l}}let s=e.output;if(!s&&(s=se.join(process.cwd(),"docker-compose.yml"),Q.existsSync(s))){let{confirmOverwrite:m}=await Y.prompt([{type:"confirm",name:"confirmOverwrite",message:`File ${s} already exists. Overwrite?`,default:!1}]);if(!m){let{customPath:p}=await Y.prompt([{type:"input",name:"customPath",message:"Enter alternative output path:",default:se.join(process.cwd(),"docker-generated-compose.yml")}]);s=p}}let i=new S("",r.username,r.registry);n?o.info(`Generating Docker Compose file for ${t} using env file: ${n}`):o.info(`Generating Docker Compose file for ${t} without env file`);let c=await i.buildComposeFile(t,n,e.template);if(c!==s){let m=se.dirname(s);Q.existsSync(m)||(o.info(`Creating directory: ${m}`),Q.mkdirSync(m,{recursive:!0})),Q.copyFileSync(c,s)}o.success(`Docker Compose file generated successfully: ${s}`)}catch(r){o.error(`Failed to generate Docker Compose file: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});var Ir=new zt().name("docker").description("Login to Docker Hub and manage Docker images").addCommand(Er).addCommand(kr).addCommand(Sr).addCommand($r);import{Command as Yt}from"commander";import{Command as Wt}from"commander";var Dr=new Wt().name("start").description("Start the TEE simulator").option("-p, --port <port>","Simulator port (default: 8090)","8090").option("-v, --verbose","Enable verbose output",!1).action(async e=>{try{if(dr()||await fr(),await z()){o.success("TEE simulator is already running");return}let t=await gr({verbose:e.verbose});o.success("TEE simulator started successfully")}catch(r){o.error(`Failed to start TEE simulator: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as Jt}from"commander";var Pr=new Jt().name("stop").description("Stop the TEE simulator").action(async()=>{try{await hr()||(o.error("Failed to stop TEE simulator"),process.exit(1)),o.success("TEE simulator stopped successfully")}catch(e){o.error(`Failed to stop TEE simulator: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});var _e=new Yt().name("simulator").description("TEE simulator commands").addCommand(Dr).addCommand(Pr);_e.action(async()=>{try{let e=await z(),r=oe();if(e&&r){let t=ne(),n=ne(),s=n.replace(/dstack\.sock$/,"tappd.sock");console.log(`\u2713 TEE simulator is running (PID: ${r})`),console.log(`
55
55
  Set these environment variables to use the simulator:`),console.log(` export DSTACK_SIMULATOR_ENDPOINT=${n}`),console.log(` export TAPPD_SIMULATOR_ENDPOINT=${s}`)}else console.log("TEE simulator is not running"),console.log(`
56
- To start the simulator, run:`),console.log(" phala simulator start")}catch(e){console.error("Error checking simulator status:",e)}});import{Command as mn}from"commander";import{Command as Qt}from"commander";import be from"chalk";var Ar=new Qt().name("list").alias("ls").description("List all CVMs").option("-j, --json","Output in JSON format").action(async e=>{try{let r=o.startSpinner("Fetching CVMs"),t=await Oe();if(r.stop(!0),!t||t.length===0){o.info("No CVMs found");return}if(e.json){console.log(JSON.stringify(t,null,2));return}for(let n of t)o.keyValueTable({Name:n.name,"App ID":`app_${n.hosted.app_id}`,"CVM ID":n.hosted.id.replace(/-/g,""),Region:n.node.region_identifier,Status:n.status==="running"?be.green(n.status):n.status==="stopped"?be.red(n.status):be.yellow(n.status),"Node Info URL":n.hosted.app_url,"App URL":`${v}/dashboard/cvms/${n.hosted.id.replace(/-/g,"")}`}),o.break();o.success(`Found ${t.length} CVMs`),o.break(),o.info(`Go to ${v}/dashboard/ to view your CVMs`)}catch(r){o.error(`Failed to list CVMs: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as Xt}from"commander";import ke from"chalk";async function b(e){if(!e){let r=await te();return r||void 0}return await re(e)}var Fr=new Xt().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(e,r)=>{try{let t=await b(e),n=o.startSpinner(`Fetching CVM with App ID app_${t}`),s=await O(t);if(n.stop(!0),o.break(),s||(o.error(`CVM with App ID app_${t} not found`),process.exit(1)),r.json){console.log(JSON.stringify(s,null,2));return}o.keyValueTable({Name:s.name,"App ID":`app_${s.app_id}`,Status:s.status==="running"?ke.green(s.status):s.status==="stopped"?ke.red(s.status):ke.yellow(s.status),vCPU:s.vcpu,Memory:`${s.memory} MB`,"Disk Size":`${s.disk_size} GB`,"Dstack Image":s.base_image,"App URL":`${v}/dashboard/cvms/app_${s.app_id}`})}catch(t){o.error(`Failed to get CVM details: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as Zt}from"commander";var Tr=new Zt().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 e=>{try{let r=await b(e),t=o.startSpinner(`Starting CVM with App ID app_${r}`),n=await Be(r);t.stop(!0),o.break();let s={"CVM ID":n.id,Name:n.name,Status:n.status,"App ID":`app_${n.app_id}`};o.keyValueTable(s,{borderStyle:"rounded"}),o.break(),o.success(`Your CVM is being started. You can check the dashboard for more details:
56
+ To start the simulator, run:`),console.log(" phala simulator start")}catch(e){console.error("Error checking simulator status:",e)}});import{Command as mn}from"commander";import{Command as Qt}from"commander";import be from"chalk";var Ar=new Qt().name("list").alias("ls").description("List all CVMs").option("-j, --json","Output in JSON format").action(async e=>{try{let r=o.startSpinner("Fetching CVMs"),t=await Oe();if(r.stop(!0),!t||t.length===0){o.info("No CVMs found");return}if(e.json){console.log(JSON.stringify(t,null,2));return}for(let n of t)o.keyValueTable({Name:n.name,"App ID":`app_${n.hosted.app_id}`,"CVM ID":n.hosted.id.replace(/-/g,""),Region:n.node.region_identifier,Status:n.status==="running"?be.green(n.status):n.status==="stopped"?be.red(n.status):be.yellow(n.status),"Node Info URL":n.hosted.app_url,"App URL":`${v}/dashboard/cvms/${n.hosted.id.replace(/-/g,"")}`}),o.break();o.success(`Found ${t.length} CVMs`),o.break(),o.info(`Go to ${v}/dashboard/ to view your CVMs`)}catch(r){o.error(`Failed to list CVMs: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as Xt}from"commander";import ke from"chalk";async function b(e){if(!e){let r=await te();return r||void 0}return await re(e)}var Fr=new Xt().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(e,r)=>{try{let t=await b(e),n=o.startSpinner(`Fetching CVM with App ID app_${t}`),s=await K(t);if(n.stop(!0),o.break(),s||(o.error(`CVM with App ID app_${t} not found`),process.exit(1)),r.json){console.log(JSON.stringify(s,null,2));return}o.keyValueTable({Name:s.name,"App ID":`app_${s.app_id}`,Status:s.status==="running"?ke.green(s.status):s.status==="stopped"?ke.red(s.status):ke.yellow(s.status),vCPU:s.vcpu,Memory:`${s.memory} MB`,"Disk Size":`${s.disk_size} GB`,"Dstack Image":s.base_image,"App URL":`${v}/dashboard/cvms/app_${s.app_id}`})}catch(t){o.error(`Failed to get CVM details: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as Zt}from"commander";var Tr=new Zt().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 e=>{try{let r=await b(e),t=o.startSpinner(`Starting CVM with App ID app_${r}`),n=await Be(r);t.stop(!0),o.break();let s={"CVM ID":n.id,Name:n.name,Status:n.status,"App ID":`app_${n.app_id}`};o.keyValueTable(s,{borderStyle:"rounded"}),o.break(),o.success(`Your CVM is being started. You can check the dashboard for more details:
57
57
  ${v}/dashboard/cvms/app_${n.app_id}`)}catch(r){o.error(`Failed to start CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as eo}from"commander";var xr=new eo().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 e=>{try{let r=await b(e),t=o.startSpinner(`Stopping CVM with App ID app_${r}`),n=await qe(r);t.stop(!0),o.break();let s={"CVM ID":n.id,Name:n.name,Status:n.status,"App ID":`app_${n.app_id}`};o.keyValueTable(s,{borderStyle:"rounded"}),o.break(),o.success(`Your CVM is being stopped. You can check the dashboard for more details:
58
58
  ${v}/dashboard/cvms/app_${n.app_id}`)}catch(r){o.error(`Failed to stop CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as ro}from"commander";var Rr=new ro().name("restart").description("Restart a CVM").argument("[app-id]","App ID of the CVM (if not provided, a selection prompt will appear)").action(async e=>{try{let r=await b(e),t=o.startSpinner(`Restarting CVM with App ID app_${r}`),n=await Ge(r);t.stop(!0),o.break();let s={"CVM ID":n.id,Name:n.name,Status:n.status,"App ID":`app_${n.app_id}`,"App URL":n.app_url?n.app_url:`${v}/dashboard/cvms/app_${n.app_id}`};o.keyValueTable(s,{borderStyle:"rounded"}),o.break(),o.success(`Your CVM is being restarted. You can check the dashboard for more details:
59
- ${v}/dashboard/cvms/app_${n.app_id}`)}catch(r){o.error(`Failed to restart CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as to}from"commander";import ie from"chalk";var Mr=new to().name("attestation").description("Get attestation information for a CVM").argument("[app-id]","CVM app ID (will prompt for selection if not provided)").option("-j, --json","Output in JSON format").action(async(e,r)=>{try{let t;if(e)t=await re(e);else{o.info("No CVM specified, fetching available CVMs...");let s=await te();if(!s)return;t=s}let n=o.startSpinner(`Fetching attestation information for CVM app_${t}...`);try{let s=await We(t);if(n.stop(!0),!s||Object.keys(s).length===0){o.info("No attestation information found");return}if(r?.json){o.info(JSON.stringify(s,null,2));return}o.success("Attestation Summary:");let i={Status:s.is_online?ie.green("Online"):ie.red("Offline"),"Public Access":s.is_public?ie.green("Enabled"):ie.yellow("Disabled"),Error:s.error||"None",Certificates:`${s.app_certificates?.length||0} found`};if(o.keyValueTable(i,{borderStyle:"rounded"}),s.app_certificates&&s.app_certificates.length>0&&s.app_certificates.forEach((c,m)=>{o.break(),o.success(`Certificate #${m+1} (${c.position_in_chain===0?"End Entity":"CA"}):`);let p={Subject:`${c.subject.common_name||"Unknown"}${c.subject.organization?` (${c.subject.organization})`:""}`,Issuer:`${c.issuer.common_name||"Unknown"}${c.issuer.organization?` (${c.issuer.organization})`:""}`,"Serial Number":c.serial_number,Validity:`${new Date(c.not_before).toLocaleString()} to ${new Date(c.not_after).toLocaleString()}`,Fingerprint:c.fingerprint,"Signature Algorithm":c.signature_algorithm,"Is CA":c.is_ca?"Yes":"No","Position in Chain":c.position_in_chain};o.keyValueTable(p,{borderStyle:"rounded"})}),s.tcb_info){o.break(),o.success("Trusted Computing Base (TCB) Information:");let c={Mrtd:s.tcb_info.mrtd,"Rootfs Hash":s.tcb_info.rootfs_hash,Rtmr0:s.tcb_info.rtmr0,Rtmr1:s.tcb_info.rtmr1,Rtmr2:s.tcb_info.rtmr2,Rtmr3:s.tcb_info.rtmr3,"Event Log Entries":`${s.tcb_info.event_log.length} entries`};if(o.keyValueTable(c,{borderStyle:"rounded"}),s.tcb_info.event_log&&s.tcb_info.event_log.length>0){o.break(),o.success("Event Log (Showing entries to reproduce RTMR3):");let m=5,p=s.tcb_info.event_log.filter(l=>l.event!==null&&l.event!=="").map(l=>({Event:l.event,IMR:l.imr.toString(),"Event Type":l.event_type.toString(),Payload:l.event_payload}));o.table(p,[{key:"Event",header:"Event",minWidth:8},{key:"IMR",header:"IMR",minWidth:3},{key:"Event Type",header:"Type",minWidth:8},{key:"Payload",header:"Payload",minWidth:25}]),s.tcb_info.event_log.length>m&&o.info("To see all full attestation data, use --json"),o.break(),o.success("To reproduce RTMR3, use the tool at https://rtmr3-calculator.vercel.app/")}}}catch(s){throw n.stop(!1),s}}catch(t){o.error(`Failed to get attestation information: ${t instanceof Error?t.message:String(t)}`)}});import{Command as oo}from"commander";import{encryptEnvVars as no}from"@phala/cloud";import Lr from"node:fs";import so from"node:path";import Ur from"inquirer";import*as Nr from"node:fs";var X=(e,r)=>{let t={};if(e){for(let n of e)if(n.includes("=")){let[s,...i]=n.split("="),c=i.join("=");s&&(t[s]=c)}}if(r){let n=Nr.readFileSync(r,"utf8");for(let s of n.split(`
59
+ ${v}/dashboard/cvms/app_${n.app_id}`)}catch(r){o.error(`Failed to restart CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as to}from"commander";import ie from"chalk";var Mr=new to().name("attestation").description("Get attestation information for a CVM").argument("[app-id]","CVM app ID (will prompt for selection if not provided)").option("-j, --json","Output in JSON format").action(async(e,r)=>{try{let t;if(e)t=await re(e);else{o.info("No CVM specified, fetching available CVMs...");let s=await te();if(!s)return;t=s}let n=o.startSpinner(`Fetching attestation information for CVM app_${t}...`);try{let s=await We(t);if(n.stop(!0),!s||Object.keys(s).length===0){o.info("No attestation information found");return}if(r?.json){o.info(JSON.stringify(s,null,2));return}o.success("Attestation Summary:");let i={Status:s.is_online?ie.green("Online"):ie.red("Offline"),"Public Access":s.is_public?ie.green("Enabled"):ie.yellow("Disabled"),Error:s.error||"None",Certificates:`${s.app_certificates?.length||0} found`};if(o.keyValueTable(i,{borderStyle:"rounded"}),s.app_certificates&&s.app_certificates.length>0&&s.app_certificates.forEach((c,m)=>{o.break(),o.success(`Certificate #${m+1} (${c.position_in_chain===0?"End Entity":"CA"}):`);let p={Subject:`${c.subject.common_name||"Unknown"}${c.subject.organization?` (${c.subject.organization})`:""}`,Issuer:`${c.issuer.common_name||"Unknown"}${c.issuer.organization?` (${c.issuer.organization})`:""}`,"Serial Number":c.serial_number,Validity:`${new Date(c.not_before).toLocaleString()} to ${new Date(c.not_after).toLocaleString()}`,Fingerprint:c.fingerprint,"Signature Algorithm":c.signature_algorithm,"Is CA":c.is_ca?"Yes":"No","Position in Chain":c.position_in_chain};o.keyValueTable(p,{borderStyle:"rounded"})}),s.tcb_info){o.break(),o.success("Trusted Computing Base (TCB) Information:");let c={Mrtd:s.tcb_info.mrtd,"Rootfs Hash":s.tcb_info.rootfs_hash,Rtmr0:s.tcb_info.rtmr0,Rtmr1:s.tcb_info.rtmr1,Rtmr2:s.tcb_info.rtmr2,Rtmr3:s.tcb_info.rtmr3,"Event Log Entries":`${s.tcb_info.event_log.length} entries`};if(o.keyValueTable(c,{borderStyle:"rounded"}),s.tcb_info.event_log&&s.tcb_info.event_log.length>0){o.break(),o.success("Event Log (Showing entries to reproduce RTMR3):");let m=5,p=s.tcb_info.event_log.filter(l=>l.event!==null&&l.event!=="").map(l=>({Event:l.event,IMR:l.imr.toString(),"Event Type":l.event_type.toString(),Payload:l.event_payload}));o.table(p,[{key:"Event",header:"Event",minWidth:8},{key:"IMR",header:"IMR",minWidth:3},{key:"Event Type",header:"Type",minWidth:8},{key:"Payload",header:"Payload",minWidth:25}]),s.tcb_info.event_log.length>m&&o.info("To see all full attestation data, use --json"),o.break(),o.success("To reproduce RTMR3, use the tool at https://rtmr3-calculator.vercel.app/")}}}catch(s){throw n.stop(!1),s}}catch(t){o.error(`Failed to get attestation information: ${t instanceof Error?t.message:String(t)}`)}});import{Command as Jo}from"commander";import Bo from"node:http";import qo from"node:https";var T=!!globalThis.process?.env?.FORCE_NODE_FETCH,Se=!T&&globalThis.fetch||sr,Ba=!T&&globalThis.Blob||Xe,qa=!T&&globalThis.File||Ze,Ga=!T&&globalThis.FormData||er,Nr=!T&&globalThis.Headers||rr,Ha=!T&&globalThis.Request||or,za=!T&&globalThis.Response||tr,Lr=!T&&globalThis.AbortController||nr;var oo=/"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/,no=/"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/,so=/^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/;function io(e,r){if(e==="__proto__"||e==="constructor"&&r&&typeof r=="object"&&"prototype"in r){ao(e);return}return r}function ao(e){console.warn(`[destr] Dropping "${e}" key to prevent prototype pollution.`)}function Ur(e,r={}){if(typeof e!="string")return e;if(e[0]==='"'&&e[e.length-1]==='"'&&e.indexOf("\\")===-1)return e.slice(1,-1);let t=e.trim();if(t.length<=9)switch(t.toLowerCase()){case"true":return!0;case"false":return!1;case"undefined":return;case"null":return null;case"nan":return Number.NaN;case"infinity":return Number.POSITIVE_INFINITY;case"-infinity":return Number.NEGATIVE_INFINITY}if(!so.test(e)){if(r.strict)throw new SyntaxError("[destr] Invalid JSON");return e}try{if(oo.test(e)||no.test(e)){if(r.strict)throw new Error("[destr] Possible prototype pollution");return JSON.parse(e,io)}return JSON.parse(e)}catch(n){if(r.strict)throw n;return e}}var Qa=String.fromCharCode;var co=/#/g,mo=/&/g,lo=/\//g,po=/=/g;var Pe=/\+/g,uo=/%5e/gi,fo=/%60/gi;var go=/%7c/gi;var ho=/%20/gi;function yo(e){return encodeURI(""+e).replace(go,"|")}function Ie(e){return yo(typeof e=="string"?e:JSON.stringify(e)).replace(Pe,"%2B").replace(ho,"+").replace(co,"%23").replace(mo,"%26").replace(fo,"`").replace(uo,"^").replace(lo,"%2F")}function $e(e){return Ie(e).replace(po,"%3D")}function Or(e=""){try{return decodeURIComponent(""+e)}catch{return""+e}}function vo(e){return Or(e.replace(Pe," "))}function wo(e){return Or(e.replace(Pe," "))}function Co(e=""){let r=Object.create(null);e[0]==="?"&&(e=e.slice(1));for(let t of e.split("&")){let n=t.match(/([^=]+)=?(.*)/)||[];if(n.length<2)continue;let s=vo(n[1]);if(s==="__proto__"||s==="constructor")continue;let i=wo(n[2]||"");r[s]===void 0?r[s]=i:Array.isArray(r[s])?r[s].push(i):r[s]=[r[s],i]}return r}function Eo(e,r){return(typeof r=="number"||typeof r=="boolean")&&(r=String(r)),r?Array.isArray(r)?r.map(t=>`${$e(e)}=${Ie(t)}`).join("&"):`${$e(e)}=${Ie(r)}`:$e(e)}function _o(e){return Object.keys(e).filter(r=>e[r]!==void 0).map(r=>Eo(r,e[r])).filter(Boolean).join("&")}var bo=/^[\s\w\0+.-]{2,}:([/\\]{1,2})/,ko=/^[\s\w\0+.-]{2,}:([/\\]{2})?/,So=/^([/\\]\s*){2,}[^/\\]/;var $o=/\/$|\/\?|\/#/,Io=/^\.?\//;function Kr(e,r={}){return typeof r=="boolean"&&(r={acceptRelative:r}),r.strict?bo.test(e):ko.test(e)||(r.acceptRelative?So.test(e):!1)}function De(e="",r){return r?$o.test(e):e.endsWith("/")}function Do(e="",r){if(!r)return(De(e)?e.slice(0,-1):e)||"/";if(!De(e,!0))return e||"/";let t=e,n="",s=e.indexOf("#");s!==-1&&(t=e.slice(0,s),n=e.slice(s));let[i,...c]=t.split("?");return((i.endsWith("/")?i.slice(0,-1):i)||"/")+(c.length>0?`?${c.join("?")}`:"")+n}function Po(e="",r){if(!r)return e.endsWith("/")?e:e+"/";if(De(e,!0))return e||"/";let t=e,n="",s=e.indexOf("#");if(s!==-1&&(t=e.slice(0,s),n=e.slice(s),!t))return n;let[i,...c]=t.split("?");return i+"/"+(c.length>0?`?${c.join("?")}`:"")+n}function jr(e,r){if(Ao(r)||Kr(e))return e;let t=Do(r);return e.startsWith(t)?e:To(t,e)}function Br(e,r){let t=Gr(e),n={...Co(t.search),...r};return t.search=_o(n),xo(t)}function Ao(e){return!e||e==="/"}function Fo(e){return e&&e!=="/"}function To(e,...r){let t=e||"";for(let n of r.filter(s=>Fo(s)))if(t){let s=n.replace(Io,"");t=Po(t)+s}else t=n;return t}var qr=Symbol.for("ufo:protocolRelative");function Gr(e="",r){let t=e.match(/^[\s\0]*(blob:|data:|javascript:|vbscript:)(.*)/i);if(t){let[,f,u=""]=t;return{protocol:f.toLowerCase(),pathname:u,href:f+u,auth:"",host:"",search:"",hash:""}}if(!Kr(e,{acceptRelative:!0}))return r?Gr(r+e):Vr(e);let[,n="",s,i=""]=e.replace(/\\/g,"/").match(/^[\s\0]*([\w+.-]{2,}:)?\/\/([^/@]+@)?(.*)/)||[],[,c="",m=""]=i.match(/([^#/?]*)(.*)?/)||[];n==="file:"&&(m=m.replace(/\/(?=[A-Za-z]:)/,""));let{pathname:p,search:l,hash:a}=Vr(m);return{protocol:n.toLowerCase(),auth:s?s.slice(0,Math.max(0,s.length-1)):"",host:c,pathname:p,search:l,hash:a,[qr]:!n}}function Vr(e=""){let[r="",t="",n=""]=(e.match(/([^#?]*)(\?[^#]*)?(#.*)?/)||[]).splice(1);return{pathname:r,search:t,hash:n}}function xo(e){let r=e.pathname||"",t=e.search?(e.search.startsWith("?")?"":"?")+e.search:"",n=e.hash||"",s=e.auth?e.auth+"@":"",i=e.host||"";return(e.protocol||e[qr]?(e.protocol||"")+"//":"")+s+i+r+t+n}var x=class extends Error{constructor(r,t){super(r,t),this.name="FetchError",t?.cause&&!this.cause&&(this.cause=t.cause)}};function zr(e){let r=e.error?.message||e.error?.toString()||"",t=e.request?.method||e.options?.method||"GET",n=e.request?.url||String(e.request)||"/",s=`[${t}] ${JSON.stringify(n)}`,i=e.response?`${e.response.status} ${e.response.statusText}`:"<no response>",c=`${s}: ${i}${r?` ${r}`:""}`,m=new x(c,e.error?{cause:e.error}:void 0);for(let p of["request","options","response"])Object.defineProperty(m,p,{get(){return e[p]}});for(let[p,l]of[["data","_data"],["status","status"],["statusCode","status"],["statusText","statusText"],["statusMessage","statusText"]])Object.defineProperty(m,p,{get(){return e.response&&e.response[l]}});return m}var Ro=new Set(Object.freeze(["PATCH","POST","PUT","DELETE"]));function Hr(e="GET"){return Ro.has(e.toUpperCase())}function Mo(e){if(e===void 0)return!1;let r=typeof e;return r==="string"||r==="number"||r==="boolean"||r===null?!0:r!=="object"?!1:Array.isArray(e)?!0:e.buffer?!1:e.constructor&&e.constructor.name==="Object"||typeof e.toJSON=="function"}var No=new Set(["image/svg","application/xml","application/xhtml","application/html"]),Lo=/^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;function Uo(e=""){if(!e)return"json";let r=e.split(";").shift()||"";return Lo.test(r)?"json":No.has(r)||r.startsWith("text/")?"text":"blob"}function Vo(e,r,t,n){let s=Oo(r?.headers??e?.headers,t?.headers,n),i;return(t?.query||t?.params||r?.params||r?.query)&&(i={...t?.params,...t?.query,...r?.params,...r?.query}),{...t,...r,query:i,params:i,headers:s}}function Oo(e,r,t){if(!r)return new t(e);let n=new t(r);if(e)for(let[s,i]of Symbol.iterator in e||Array.isArray(e)?e:new t(e))n.set(s,i);return n}async function ae(e,r){if(r)if(Array.isArray(r))for(let t of r)await t(e);else await r(e)}var Ko=new Set([408,409,425,429,500,502,503,504]),jo=new Set([101,204,205,304]);function Ae(e={}){let{fetch:r=globalThis.fetch,Headers:t=globalThis.Headers,AbortController:n=globalThis.AbortController}=e;async function s(m){let p=m.error&&m.error.name==="AbortError"&&!m.options.timeout||!1;if(m.options.retry!==!1&&!p){let a;typeof m.options.retry=="number"?a=m.options.retry:a=Hr(m.options.method)?0:1;let f=m.response&&m.response.status||500;if(a>0&&(Array.isArray(m.options.retryStatusCodes)?m.options.retryStatusCodes.includes(f):Ko.has(f))){let u=typeof m.options.retryDelay=="function"?m.options.retryDelay(m):m.options.retryDelay||0;return u>0&&await new Promise(d=>setTimeout(d,u)),i(m.request,{...m.options,retry:a-1})}}let l=zr(m);throw Error.captureStackTrace&&Error.captureStackTrace(l,i),l}let i=async function(p,l={}){let a={request:p,options:Vo(p,l,e.defaults,t),response:void 0,error:void 0};a.options.method&&(a.options.method=a.options.method.toUpperCase()),a.options.onRequest&&await ae(a,a.options.onRequest),typeof a.request=="string"&&(a.options.baseURL&&(a.request=jr(a.request,a.options.baseURL)),a.options.query&&(a.request=Br(a.request,a.options.query),delete a.options.query),"query"in a.options&&delete a.options.query,"params"in a.options&&delete a.options.params),a.options.body&&Hr(a.options.method)&&(Mo(a.options.body)?(a.options.body=typeof a.options.body=="string"?a.options.body:JSON.stringify(a.options.body),a.options.headers=new t(a.options.headers||{}),a.options.headers.has("content-type")||a.options.headers.set("content-type","application/json"),a.options.headers.has("accept")||a.options.headers.set("accept","application/json")):("pipeTo"in a.options.body&&typeof a.options.body.pipeTo=="function"||typeof a.options.body.pipe=="function")&&("duplex"in a.options||(a.options.duplex="half")));let f;if(!a.options.signal&&a.options.timeout){let d=new n;f=setTimeout(()=>{let y=new Error("[TimeoutError]: The operation was aborted due to timeout");y.name="TimeoutError",y.code=23,d.abort(y)},a.options.timeout),a.options.signal=d.signal}try{a.response=await r(a.request,a.options)}catch(d){return a.error=d,a.options.onRequestError&&await ae(a,a.options.onRequestError),await s(a)}finally{f&&clearTimeout(f)}if((a.response.body||a.response._bodyInit)&&!jo.has(a.response.status)&&a.options.method!=="HEAD"){let d=(a.options.parseResponse?"json":a.options.responseType)||Uo(a.response.headers.get("content-type")||"");switch(d){case"json":{let y=await a.response.text(),g=a.options.parseResponse||Ur;a.response._data=g(y);break}case"stream":{a.response._data=a.response.body||a.response._bodyInit;break}default:a.response._data=await a.response[d]()}}return a.options.onResponse&&await ae(a,a.options.onResponse),!a.options.ignoreResponseError&&a.response.status>=400&&a.response.status<600?(a.options.onResponseError&&await ae(a,a.options.onResponseError),await s(a)):a.response},c=async function(p,l){return(await i(p,l))._data};return c.raw=i,c.native=(...m)=>r(...m),c.create=(m={},p={})=>Ae({...e,...p,defaults:{...e.defaults,...p.defaults,...m}}),c}function Go(){if(!JSON.parse(process.env.FETCH_KEEP_ALIVE||"false"))return Se;let r={keepAlive:!0},t=new Bo.Agent(r),n=new qo.Agent(r),s={agent(i){return i.protocol==="http:"?t:n}};return function(c,m){return Se(c,{...s,...m})}}var Ho=globalThis.fetch?(...e)=>globalThis.fetch(...e):Go(),zo=globalThis.Headers||Nr,Wo=globalThis.AbortController||Lr,ic=Ae({fetch:Ho,Headers:zo,AbortController:Wo});import{encryptEnvVars as Yo}from"@phala/cloud";import Jr from"node:fs";import Qo from"node:path";import Yr from"inquirer";import*as Wr from"node:fs";var X=(e,r)=>{let t={};if(e){for(let n of e)if(n.includes("=")){let[s,...i]=n.split("="),c=i.join("=");s&&(t[s]=c)}}if(r){let n=Wr.readFileSync(r,"utf8");for(let s of n.split(`
60
60
  `)){if(!s.trim()||s.trim().startsWith("#"))continue;let i=-1,c=!1,m="";for(let g=0;g<s.length;g++)if((s[g]==='"'||s[g]==="'"||s[g]==="`")&&(g===0||s[g-1]!=="\\"))c&&s[g]===m?(c=!1,m=""):c||(c=!0,m=s[g]);else if(s[g]==="="&&!c){i=g;break}else if(s[g]==="#"&&!c)break;if(i===-1){s.trim().startsWith("#");continue}let p=s.substring(0,i).trim(),l=s.substring(i+1),a=!1,f="",u=-1;for(let g=0;g<l.length;g++)if((l[g]==='"'||l[g]==="'"||l[g]==="`")&&(g===0||l[g-1]!=="\\"))a&&l[g]===f?(a=!1,f=""):a||(a=!0,f=l[g]);else if(l[g]==="#"&&!a&&g>0&&l[g-1]===" "){u=g-1;break}else if(l[g]==="#"&&!a&&g===0){u=g;break}u!==-1&&(l=l.substring(0,u)),l===void 0&&(l="");let d=l.charAt(0),y=l.charAt(l.length-1);d==='"'&&y==='"'||d==="'"&&y==="'"||d==="`"&&y==="`"?(l=l.substring(1,l.length-1),d==='"'&&(l=l.replace(/\\\\n/g,`
61
- `))):l=l.trim(),p&&(t[p]=l)}}return Object.entries(t).map(([n,s])=>({key:n,value:s}))};var Vr=new oo().name("create").description("Create a new CVM").option("-n, --name <name>","Name of the CVM").option("-c, --compose <compose>","Path to Docker Compose file").option("--vcpu <vcpu>",`Number of vCPUs, default is ${R}`).option("--memory <memory>",`Memory in MB, default is ${M}`).option("--disk-size <diskSize>",`Disk size in GB, default is ${N}`).option("--teepod-id <teepodId>","TEEPod ID to use. If not provided, it will be selected from the list of available TEEPods.").option("--image <image>","Version of dstack image to use. If not provided, it will be selected from the list of available images for the selected TEEPod.").option("-e, --env-file <envFile>","Path to environment file").option("--skip-env","Skip environment variable prompt",!1).option("--debug","Enable debug mode",!1).action(async e=>{try{if(!e.name){let{name:_}=await Ur.prompt([{type:"input",name:"name",message:"Enter a name for the CVM:",validate:$=>$.trim()?$.trim().length>20?"CVM name must be less than 20 characters":$.trim().length<3?"CVM name must be at least 3 characters":/^[a-zA-Z0-9_-]+$/.test($)?!0:"CVM name must contain only letters, numbers, underscores, and hyphens":"CVM name is required"}]);e.name=_}if(!e.compose){let $=j(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");e.compose=await I("Enter the path to your Docker Compose file:",$,"file")}let r=so.resolve(e.compose);Lr.existsSync(r)||(o.error(`Docker Compose file not found: ${r}`),process.exit(1));let t=Lr.readFileSync(r,"utf8");await U(),process.env.DSTACK_DOCKER_USERNAME&&process.env.DSTACK_DOCKER_PASSWORD?o.info("\u{1F510} Using private DockerHub registry credentials..."):process.env.DSTACK_AWS_ACCESS_KEY_ID&&process.env.DSTACK_AWS_SECRET_ACCESS_KEY&&process.env.DSTACK_AWS_REGION&&process.env.DSTACK_AWS_ECR_REGISTRY?o.info(`\u{1F510} Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`):o.info("\u{1F510} Using public DockerHub registry...");let n=[];if(e.envFile)try{n=X([],e.envFile)}catch(_){o.error(`Failed to read environment file: ${_ instanceof Error?_.message:String(_)}`),process.exit(1)}else if(!e.skipEnv){let{shouldSkip:_}=await Ur.prompt([{type:"confirm",name:"shouldSkip",message:"Do you want to skip environment variable prompt?",default:!0}]);if(_)o.info("Skipping environment variable prompt");else{let $=await I("Enter the path to your environment file:",".env","file");n=X([],$)}}let s=Number(e.vcpu)||R,i=Number(e.memory)||M,c=Number(e.diskSize)||N;(Number.isNaN(s)||s<=0)&&(o.error(`Invalid number of vCPUs: ${s}`),process.exit(1)),(Number.isNaN(i)||i<=0)&&(o.error(`Invalid memory: ${i}`),process.exit(1)),(Number.isNaN(c)||c<=0)&&(o.error(`Invalid disk size: ${c}`),process.exit(1));let m=o.startSpinner("Fetching available TEEPods"),p=await K();m.stop(!0),p.nodes.length===0&&(o.error("No TEEPods available. Please try again later."),process.exit(1));let l;e.teepodId?(l=p.nodes.find(_=>_.teepod_id===Number(e.teepodId)),l||(o.error("Failed to find selected TEEPod"),process.exit(1))):(l=p.nodes[0],l||(o.error("Failed to find default TEEPod"),process.exit(1)));let a;e.image?(a=l.images?.find(_=>_.name===e.image),a||(o.error(`Failed to find selected image: ${e.image}`),process.exit(1))):(a=l.images?.find(_=>_.name===ge),a||(o.error(`Failed to find default image ${ge}`),process.exit(1)));let f={teepod_id:l.teepod_id,name:e.name,image:a.name,vcpu:s,memory:i,disk_size:c,compose_manifest:{docker_compose_file:t,docker_config:{url:"",username:"",password:""},features:["kms","tproxy-net"],kms_enabled:!0,manifest_version:2,name:e.name,public_logs:!0,public_sysinfo:!0,tproxy_enabled:!0},listed:!1},u=o.startSpinner("Getting public key from CVM"),d=await Ke(f);u.stop(!0),d||(o.error("Failed to get public key from CVM"),process.exit(1));let y=o.startSpinner("Encrypting environment variables"),g=await no(n,d.app_env_encrypt_pubkey);y.stop(!0),e.debug&&(o.debug("Public key:",d.app_env_encrypt_pubkey),o.debug("Encrypted environment variables:",g),o.debug("Environment variables:",JSON.stringify(n)));let C=o.startSpinner("Creating CVM"),w=await je({...f,encrypted_env:g,app_env_encrypt_pubkey:d.app_env_encrypt_pubkey,app_id_salt:d.app_id_salt});C.stop(!0),w||(o.error("Failed to create CVM"),process.exit(1)),o.success("CVM created successfully"),o.break();let me={"CVM ID":w.id,Name:w.name,Status:w.status,"App ID":`app_${w.app_id}`,"App URL":w.app_url?w.app_url:`${v}/dashboard/cvms/app_${w.app_id}`};o.keyValueTable(me,{borderStyle:"rounded"}),o.info(""),o.success(`Your CVM is being created. You can check its status with:
62
- phala cvms get app_${w.app_id}`)}catch(r){o.error(`Failed to create CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as io}from"commander";import ao from"inquirer";var Or=new io().name("delete").description("Delete a CVM").argument("[app-id]","App ID of the CVM to delete (if not provided, a selection prompt will appear)").option("-f, --force","Skip confirmation prompt",!1).action(async(e,r)=>{try{let t=await b(e);if(!r.force){let{confirm:i}=await ao.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete CVM with App ID app_${t}? This action cannot be undone.`,default:!1}]);if(!i){o.info("Deletion cancelled");return}}let n=o.startSpinner(`Deleting CVM app_${t}`),s=await ze(t);n.stop(!0),s||(o.error(`Failed to delete CVM app_${t}`),process.exit(1)),o.success(`CVM app_${t} deleted successfully`)}catch(t){o.error(`Failed to delete CVM: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as en}from"commander";import Wo from"node:http";import Jo from"node:https";var T=!!globalThis.process?.env?.FORCE_NODE_FETCH,Se=!T&&globalThis.fetch||sr,pc=!T&&globalThis.Blob||Xe,uc=!T&&globalThis.File||Ze,dc=!T&&globalThis.FormData||er,Kr=!T&&globalThis.Headers||rr,fc=!T&&globalThis.Request||or,gc=!T&&globalThis.Response||tr,jr=!T&&globalThis.AbortController||nr;var co=/"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/,mo=/"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/,lo=/^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/;function po(e,r){if(e==="__proto__"||e==="constructor"&&r&&typeof r=="object"&&"prototype"in r){uo(e);return}return r}function uo(e){console.warn(`[destr] Dropping "${e}" key to prevent prototype pollution.`)}function Br(e,r={}){if(typeof e!="string")return e;if(e[0]==='"'&&e[e.length-1]==='"'&&e.indexOf("\\")===-1)return e.slice(1,-1);let t=e.trim();if(t.length<=9)switch(t.toLowerCase()){case"true":return!0;case"false":return!1;case"undefined":return;case"null":return null;case"nan":return Number.NaN;case"infinity":return Number.POSITIVE_INFINITY;case"-infinity":return Number.NEGATIVE_INFINITY}if(!lo.test(e)){if(r.strict)throw new SyntaxError("[destr] Invalid JSON");return e}try{if(co.test(e)||mo.test(e)){if(r.strict)throw new Error("[destr] Possible prototype pollution");return JSON.parse(e,po)}return JSON.parse(e)}catch(n){if(r.strict)throw n;return e}}var wc=String.fromCharCode;var fo=/#/g,go=/&/g,ho=/\//g,yo=/=/g;var Pe=/\+/g,vo=/%5e/gi,wo=/%60/gi;var Co=/%7c/gi;var Eo=/%20/gi;function _o(e){return encodeURI(""+e).replace(Co,"|")}function Ie(e){return _o(typeof e=="string"?e:JSON.stringify(e)).replace(Pe,"%2B").replace(Eo,"+").replace(fo,"%23").replace(go,"%26").replace(wo,"`").replace(vo,"^").replace(ho,"%2F")}function $e(e){return Ie(e).replace(yo,"%3D")}function Gr(e=""){try{return decodeURIComponent(""+e)}catch{return""+e}}function bo(e){return Gr(e.replace(Pe," "))}function ko(e){return Gr(e.replace(Pe," "))}function So(e=""){let r=Object.create(null);e[0]==="?"&&(e=e.slice(1));for(let t of e.split("&")){let n=t.match(/([^=]+)=?(.*)/)||[];if(n.length<2)continue;let s=bo(n[1]);if(s==="__proto__"||s==="constructor")continue;let i=ko(n[2]||"");r[s]===void 0?r[s]=i:Array.isArray(r[s])?r[s].push(i):r[s]=[r[s],i]}return r}function $o(e,r){return(typeof r=="number"||typeof r=="boolean")&&(r=String(r)),r?Array.isArray(r)?r.map(t=>`${$e(e)}=${Ie(t)}`).join("&"):`${$e(e)}=${Ie(r)}`:$e(e)}function Io(e){return Object.keys(e).filter(r=>e[r]!==void 0).map(r=>$o(r,e[r])).filter(Boolean).join("&")}var Do=/^[\s\w\0+.-]{2,}:([/\\]{1,2})/,Po=/^[\s\w\0+.-]{2,}:([/\\]{2})?/,Ao=/^([/\\]\s*){2,}[^/\\]/;var Fo=/\/$|\/\?|\/#/,To=/^\.?\//;function Hr(e,r={}){return typeof r=="boolean"&&(r={acceptRelative:r}),r.strict?Do.test(e):Po.test(e)||(r.acceptRelative?Ao.test(e):!1)}function De(e="",r){return r?Fo.test(e):e.endsWith("/")}function xo(e="",r){if(!r)return(De(e)?e.slice(0,-1):e)||"/";if(!De(e,!0))return e||"/";let t=e,n="",s=e.indexOf("#");s!==-1&&(t=e.slice(0,s),n=e.slice(s));let[i,...c]=t.split("?");return((i.endsWith("/")?i.slice(0,-1):i)||"/")+(c.length>0?`?${c.join("?")}`:"")+n}function Ro(e="",r){if(!r)return e.endsWith("/")?e:e+"/";if(De(e,!0))return e||"/";let t=e,n="",s=e.indexOf("#");if(s!==-1&&(t=e.slice(0,s),n=e.slice(s),!t))return n;let[i,...c]=t.split("?");return i+"/"+(c.length>0?`?${c.join("?")}`:"")+n}function zr(e,r){if(Mo(r)||Hr(e))return e;let t=xo(r);return e.startsWith(t)?e:Lo(t,e)}function Wr(e,r){let t=Yr(e),n={...So(t.search),...r};return t.search=Io(n),Uo(t)}function Mo(e){return!e||e==="/"}function No(e){return e&&e!=="/"}function Lo(e,...r){let t=e||"";for(let n of r.filter(s=>No(s)))if(t){let s=n.replace(To,"");t=Ro(t)+s}else t=n;return t}var Jr=Symbol.for("ufo:protocolRelative");function Yr(e="",r){let t=e.match(/^[\s\0]*(blob:|data:|javascript:|vbscript:)(.*)/i);if(t){let[,f,u=""]=t;return{protocol:f.toLowerCase(),pathname:u,href:f+u,auth:"",host:"",search:"",hash:""}}if(!Hr(e,{acceptRelative:!0}))return r?Yr(r+e):qr(e);let[,n="",s,i=""]=e.replace(/\\/g,"/").match(/^[\s\0]*([\w+.-]{2,}:)?\/\/([^/@]+@)?(.*)/)||[],[,c="",m=""]=i.match(/([^#/?]*)(.*)?/)||[];n==="file:"&&(m=m.replace(/\/(?=[A-Za-z]:)/,""));let{pathname:p,search:l,hash:a}=qr(m);return{protocol:n.toLowerCase(),auth:s?s.slice(0,Math.max(0,s.length-1)):"",host:c,pathname:p,search:l,hash:a,[Jr]:!n}}function qr(e=""){let[r="",t="",n=""]=(e.match(/([^#?]*)(\?[^#]*)?(#.*)?/)||[]).splice(1);return{pathname:r,search:t,hash:n}}function Uo(e){let r=e.pathname||"",t=e.search?(e.search.startsWith("?")?"":"?")+e.search:"",n=e.hash||"",s=e.auth?e.auth+"@":"",i=e.host||"";return(e.protocol||e[Jr]?(e.protocol||"")+"//":"")+s+i+r+t+n}var B=class extends Error{constructor(r,t){super(r,t),this.name="FetchError",t?.cause&&!this.cause&&(this.cause=t.cause)}};function Xr(e){let r=e.error?.message||e.error?.toString()||"",t=e.request?.method||e.options?.method||"GET",n=e.request?.url||String(e.request)||"/",s=`[${t}] ${JSON.stringify(n)}`,i=e.response?`${e.response.status} ${e.response.statusText}`:"<no response>",c=`${s}: ${i}${r?` ${r}`:""}`,m=new B(c,e.error?{cause:e.error}:void 0);for(let p of["request","options","response"])Object.defineProperty(m,p,{get(){return e[p]}});for(let[p,l]of[["data","_data"],["status","status"],["statusCode","status"],["statusText","statusText"],["statusMessage","statusText"]])Object.defineProperty(m,p,{get(){return e.response&&e.response[l]}});return m}var Vo=new Set(Object.freeze(["PATCH","POST","PUT","DELETE"]));function Qr(e="GET"){return Vo.has(e.toUpperCase())}function Oo(e){if(e===void 0)return!1;let r=typeof e;return r==="string"||r==="number"||r==="boolean"||r===null?!0:r!=="object"?!1:Array.isArray(e)?!0:e.buffer?!1:e.constructor&&e.constructor.name==="Object"||typeof e.toJSON=="function"}var Ko=new Set(["image/svg","application/xml","application/xhtml","application/html"]),jo=/^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;function Bo(e=""){if(!e)return"json";let r=e.split(";").shift()||"";return jo.test(r)?"json":Ko.has(r)||r.startsWith("text/")?"text":"blob"}function qo(e,r,t,n){let s=Go(r?.headers??e?.headers,t?.headers,n),i;return(t?.query||t?.params||r?.params||r?.query)&&(i={...t?.params,...t?.query,...r?.params,...r?.query}),{...t,...r,query:i,params:i,headers:s}}function Go(e,r,t){if(!r)return new t(e);let n=new t(r);if(e)for(let[s,i]of Symbol.iterator in e||Array.isArray(e)?e:new t(e))n.set(s,i);return n}async function ae(e,r){if(r)if(Array.isArray(r))for(let t of r)await t(e);else await r(e)}var Ho=new Set([408,409,425,429,500,502,503,504]),zo=new Set([101,204,205,304]);function Ae(e={}){let{fetch:r=globalThis.fetch,Headers:t=globalThis.Headers,AbortController:n=globalThis.AbortController}=e;async function s(m){let p=m.error&&m.error.name==="AbortError"&&!m.options.timeout||!1;if(m.options.retry!==!1&&!p){let a;typeof m.options.retry=="number"?a=m.options.retry:a=Qr(m.options.method)?0:1;let f=m.response&&m.response.status||500;if(a>0&&(Array.isArray(m.options.retryStatusCodes)?m.options.retryStatusCodes.includes(f):Ho.has(f))){let u=typeof m.options.retryDelay=="function"?m.options.retryDelay(m):m.options.retryDelay||0;return u>0&&await new Promise(d=>setTimeout(d,u)),i(m.request,{...m.options,retry:a-1})}}let l=Xr(m);throw Error.captureStackTrace&&Error.captureStackTrace(l,i),l}let i=async function(p,l={}){let a={request:p,options:qo(p,l,e.defaults,t),response:void 0,error:void 0};a.options.method&&(a.options.method=a.options.method.toUpperCase()),a.options.onRequest&&await ae(a,a.options.onRequest),typeof a.request=="string"&&(a.options.baseURL&&(a.request=zr(a.request,a.options.baseURL)),a.options.query&&(a.request=Wr(a.request,a.options.query),delete a.options.query),"query"in a.options&&delete a.options.query,"params"in a.options&&delete a.options.params),a.options.body&&Qr(a.options.method)&&(Oo(a.options.body)?(a.options.body=typeof a.options.body=="string"?a.options.body:JSON.stringify(a.options.body),a.options.headers=new t(a.options.headers||{}),a.options.headers.has("content-type")||a.options.headers.set("content-type","application/json"),a.options.headers.has("accept")||a.options.headers.set("accept","application/json")):("pipeTo"in a.options.body&&typeof a.options.body.pipeTo=="function"||typeof a.options.body.pipe=="function")&&("duplex"in a.options||(a.options.duplex="half")));let f;if(!a.options.signal&&a.options.timeout){let d=new n;f=setTimeout(()=>{let y=new Error("[TimeoutError]: The operation was aborted due to timeout");y.name="TimeoutError",y.code=23,d.abort(y)},a.options.timeout),a.options.signal=d.signal}try{a.response=await r(a.request,a.options)}catch(d){return a.error=d,a.options.onRequestError&&await ae(a,a.options.onRequestError),await s(a)}finally{f&&clearTimeout(f)}if((a.response.body||a.response._bodyInit)&&!zo.has(a.response.status)&&a.options.method!=="HEAD"){let d=(a.options.parseResponse?"json":a.options.responseType)||Bo(a.response.headers.get("content-type")||"");switch(d){case"json":{let y=await a.response.text(),g=a.options.parseResponse||Br;a.response._data=g(y);break}case"stream":{a.response._data=a.response.body||a.response._bodyInit;break}default:a.response._data=await a.response[d]()}}return a.options.onResponse&&await ae(a,a.options.onResponse),!a.options.ignoreResponseError&&a.response.status>=400&&a.response.status<600?(a.options.onResponseError&&await ae(a,a.options.onResponseError),await s(a)):a.response},c=async function(p,l){return(await i(p,l))._data};return c.raw=i,c.native=(...m)=>r(...m),c.create=(m={},p={})=>Ae({...e,...p,defaults:{...e.defaults,...p.defaults,...m}}),c}function Yo(){if(!JSON.parse(process.env.FETCH_KEEP_ALIVE||"false"))return Se;let r={keepAlive:!0},t=new Wo.Agent(r),n=new Jo.Agent(r),s={agent(i){return i.protocol==="http:"?t:n}};return function(c,m){return Se(c,{...s,...m})}}var Qo=globalThis.fetch?(...e)=>globalThis.fetch(...e):Yo(),Xo=globalThis.Headers||Kr,Zo=globalThis.AbortController||jr,Dc=Ae({fetch:Qo,Headers:Xo,AbortController:Zo});import rn from"node:fs";import{encryptEnvVars as tn}from"@phala/cloud";var Zr=new en().name("upgrade").description("Upgrade a CVM to a new version").argument("[app-id]","CVM app ID to upgrade (will prompt for selection if not provided)").option("-c, --compose <compose>","Path to new Docker Compose file").option("-e, --env-file <envFile>","Path to environment file").option("--debug","Enable debug mode",!1).action(async(e,r)=>{try{let t=await b(e),n=o.startSpinner(`Fetching current configuration for CVM app_${t}`),s=await O(t);if(n.stop(!0),s||(o.error(`CVM with App ID app_${t} not found`),process.exit(1)),!r.compose){let u=j(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");r.compose=await I("Enter the path to your Docker Compose file:",u,"file")}let i="",c=[];if(r.compose)try{i=rn.readFileSync(r.compose,"utf8")}catch(f){o.error(`Failed to read Docker Compose file: ${f instanceof Error?f.message:String(f)}`),process.exit(1)}await U(),process.env.DSTACK_DOCKER_USERNAME&&process.env.DSTACK_DOCKER_PASSWORD?o.info("\u{1F510} Using private DockerHub registry credentials..."):process.env.DSTACK_AWS_ACCESS_KEY_ID&&process.env.DSTACK_AWS_SECRET_ACCESS_KEY&&process.env.DSTACK_AWS_REGION&&process.env.DSTACK_AWS_ECR_REGISTRY?o.info(`\u{1F510} Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`):o.info("\u{1F510} Using public DockerHub registry...");let m;if(r.envFile){let f=[];if(r.envFile)try{f=X([],r.envFile),m=await tn(f,s.encrypted_env_pubkey),c=f.map(u=>u.key)}catch(u){o.error(`Failed to read environment file: ${u instanceof Error?u.message:String(u)}`),process.exit(1)}}let p={compose_manifest:{docker_compose_file:i,manifest_version:1,runner:"docker-compose",version:"1.0.0",features:["kms","tproxy-net"],name:`app_${t}`},encrypted_env:m,allow_restart:!0,env_keys:c},l=o.startSpinner(`Upgrading CVM app_${t}`),a=await He(t,p);a||(l.stop(!1),o.error("Failed to upgrade CVM"),process.exit(1)),l.stop(!0),a.detail&&o.info(`Details: ${a.detail}`),o.break(),o.success(`Your CVM is being upgraded. You can check the dashboard for more details:
63
- ${v}/dashboard/cvms/app_${t}`)}catch(t){if(o.error(`Failed to upgrade CVM: ${t instanceof Error?t.message:String(t)}`),t instanceof B||t?.constructor?.name==="FetchError"||t&&typeof t=="object"&&"status"in t&&"statusText"in t&&"data"in t){let s=t;o.error("=== HTTP Error Details ==="),o.error("Status:",s.status),o.error("Status Text:",s.statusText),o.error("URL:",s.request),o.error("Response Body:",JSON.stringify(s.data,null,2)),r.debug&&o.error("Full Error Object:",t)}else r.debug&&o.error("Full Error:",t);process.exit(1)}});import{Command as on}from"commander";import Z from"inquirer";import x from"chalk";var et=new on().name("resize").description("Resize resources for a CVM").argument("[app-id]","App ID of the CVM (if not provided, a selection prompt will appear)").option("-v, --vcpu <vcpu>","Number of virtual CPUs").option("-m, --memory <memory>","Memory size in MB").option("-d, --disk-size <diskSize>","Disk size in GB").option("-r, --allow-restart <allowRestart>","Allow restart of the CVM if needed for resizing").option("-y, --yes","Automatically confirm the resize operation").action(async(e,r)=>{try{let t=await b(e),n=await O(t),s=r.vcpu,i=r.memory,c=r.diskSize,m=r.allowRestart;s||(s=(await Z.prompt([{type:"input",name:"vcpu",message:"Enter number of vCPUs:",validate:u=>{let d=parseInt(u);return isNaN(d)||d<0?"Please enter a valid non-negative number":!0},default:n.vcpu,filter:u=>parseInt(u)}])).vcpu),i||(i=(await Z.prompt([{type:"input",name:"memory",message:"Enter memory in MB:",validate:u=>{let d=parseInt(u);return isNaN(d)||d<0?"Please enter a valid non-negative number":!0},default:n.memory,filter:u=>parseInt(u)}])).memory),c||(c=(await Z.prompt([{type:"input",name:"diskSize",message:"Enter disk size in GB:",validate:u=>{let d=parseInt(u);return isNaN(d)||d<0?"Please enter a valid non-negative number":!0},default:n.disk_size,filter:u=>parseInt(u)}])).diskSize),m||(m=(await Z.prompt([{type:"confirm",name:"allowRestart",message:"Allow restart of the CVM if needed for resizing?",default:!1}])).allowRestart);let p=`Are you sure you want to resize CVM app_${t} with the following changes:
64
- `;if(o.keyValueTable({vCPUs:n.vcpu!==s?`${x.red(n.vcpu)} -> ${x.green(s)}`:n.vcpu,Memory:n.memory!==i?`${x.red(n.memory)} MB -> ${x.green(i)} MB`:n.memory,"Disk Size":n.disk_size!==c?`${x.red(n.disk_size)} GB -> ${x.green(c)} GB`:n.disk_size,"Allow Restart":m?x.green("Yes"):x.red("No")}),!r.yes){let{confirm:f}=await Z.prompt([{type:"confirm",name:"confirm",message:p,default:!1}]);if(!f){o.info("Resize operation cancelled");return}}let l=o.startSpinner(`Resizing CVM with App ID app_${t}`);await Qe(t,s,i,c,m?1:0),l.stop(!0),o.break(),o.success(`Your CVM is being resized. You can check the dashboard for more details:
65
- ${v}/dashboard/cvms/app_${t}`)}catch(t){o.error(`Failed to resize CVM: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as nn}from"commander";var rt=new nn().name("list-nodes").description("List all available worker nodes.").action(async()=>{try{let{nodes:e,kms_list:r}=await K();if(e.length===0){o.info("No available nodes found.");return}o.info("Available Nodes:"),e.forEach(t=>{o.info("----------------------------------------"),o.info(` ID: ${t.teepod_id}`),o.info(` Name: ${t.name}`),o.info(` Region: ${t.region_identifier}`),o.info(` FMSPC: ${t.fmspc||"N/A"}`),o.info(` Device ID: ${t.device_id||"N/A"}`),o.info(` Support Onchain KMS: ${t.support_onchain_kms}`),o.info(" Images:"),t.images&&t.images.length>0?t.images.forEach(n=>{o.info(` - ${n.name}`),o.info(` Hash: ${n.os_image_hash||"N/A"}`)}):o.info(" N/A")}),r&&r.length>0&&(o.info(`
61
+ `))):l=l.trim(),p&&(t[p]=l)}}return Object.entries(t).map(([n,s])=>({key:n,value:s}))};var Qr=new Jo().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 ${M}`).option("--memory <memory>",`Memory in MB, default is ${N}`).option("--disk-size <diskSize>",`Disk size in GB, default is ${L}`).option("--teepod-id <teepodId>","TEEPod ID to use. If not provided, it will be selected from the list of available TEEPods.").option("--image <image>","Version of dstack image to use. If not provided, it will be selected from the list of available images for the selected TEEPod.").option("-e, --env-file <envFile>","Path to environment file").option("--skip-env","Skip environment variable prompt",!1).option("--debug","Enable debug mode",!1).action(async e=>{try{if(!e.name){let{name:_}=await Yr.prompt([{type:"input",name:"name",message:"Enter a name for the CVM:",validate:$=>$.trim()?$.trim().length>20?"CVM name must be less than 20 characters":$.trim().length<3?"CVM name must be at least 3 characters":/^[a-zA-Z0-9_-]+$/.test($)?!0:"CVM name must contain only letters, numbers, underscores, and hyphens":"CVM name is required"}]);e.name=_}if(!e.compose){let $=B(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");e.compose=await I("Enter the path to your Docker Compose file:",$,"file")}let r=Qo.resolve(e.compose);Jr.existsSync(r)||(o.error(`Docker Compose file not found: ${r}`),process.exit(1));let t=Jr.readFileSync(r,"utf8");await V(),process.env.DSTACK_DOCKER_USERNAME&&process.env.DSTACK_DOCKER_PASSWORD?o.info("\u{1F510} Using private DockerHub registry credentials..."):process.env.DSTACK_AWS_ACCESS_KEY_ID&&process.env.DSTACK_AWS_SECRET_ACCESS_KEY&&process.env.DSTACK_AWS_REGION&&process.env.DSTACK_AWS_ECR_REGISTRY?o.info(`\u{1F510} Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`):o.info("\u{1F510} Using public DockerHub registry...");let n=[];if(e.envFile)try{n=X([],e.envFile)}catch(_){o.error(`Failed to read environment file: ${_ instanceof Error?_.message:String(_)}`),process.exit(1)}else if(!e.skipEnv){let{shouldSkip:_}=await Yr.prompt([{type:"confirm",name:"shouldSkip",message:"Do you want to skip environment variable prompt?",default:!0}]);if(_)o.info("Skipping environment variable prompt");else{let $=await I("Enter the path to your environment file:",".env","file");n=X([],$)}}let s=Number(e.vcpu)||M,i=Number(e.memory)||N,c=Number(e.diskSize)||L;(Number.isNaN(s)||s<=0)&&(o.error(`Invalid number of vCPUs: ${s}`),process.exit(1)),(Number.isNaN(i)||i<=0)&&(o.error(`Invalid memory: ${i}`),process.exit(1)),(Number.isNaN(c)||c<=0)&&(o.error(`Invalid disk size: ${c}`),process.exit(1));let m=o.startSpinner("Fetching available TEEPods"),p=await j(!0);m.stop(!0),p.nodes.length===0&&(o.error("No TEEPods available. Please try again later."),process.exit(1));let l;e.teepodId?(l=p.nodes.find(_=>_.teepod_id===Number(e.teepodId)),l||(o.error("Failed to find selected TEEPod"),process.exit(1))):(l=p.nodes[0],l||(o.error("Failed to find default TEEPod"),process.exit(1)));let a;e.image?(a=l.images?.find(_=>_.name===e.image),a||(o.error(`Failed to find selected image: ${e.image}`),process.exit(1))):(a=l.images?.find(_=>_.name===ge),a||(o.error(`Failed to find default image ${ge}`),process.exit(1)));let f={teepod_id:l.teepod_id,name:e.name,image:a.name,vcpu:s,memory:i,disk_size:c,compose_manifest:{docker_compose_file:t,docker_config:{url:"",username:"",password:""},features:["kms","tproxy-net"],kms_enabled:!0,manifest_version:2,name:e.name,public_logs:!0,public_sysinfo:!0,tproxy_enabled:!0},listed:!1},u=o.startSpinner("Getting public key from CVM"),d=await Ke(f);u.stop(!0),d||(o.error("Failed to get public key from CVM"),process.exit(1));let y=o.startSpinner("Encrypting environment variables"),g=await Yo(n,d.app_env_encrypt_pubkey);y.stop(!0),e.debug&&(o.debug("Public key:",d.app_env_encrypt_pubkey),o.debug("Encrypted environment variables:",g),o.debug("Environment variables:",JSON.stringify(n)));let C=o.startSpinner("Creating CVM"),w=await je({...f,encrypted_env:g,app_env_encrypt_pubkey:d.app_env_encrypt_pubkey,app_id_salt:d.app_id_salt});C.stop(!0),w||(o.error("Failed to create CVM"),process.exit(1)),o.success("CVM created successfully"),o.break();let me={"CVM ID":w.id,Name:w.name,Status:w.status,"App ID":`app_${w.app_id}`,"App URL":w.app_url?w.app_url:`${v}/dashboard/cvms/app_${w.app_id}`};o.keyValueTable(me,{borderStyle:"rounded"}),o.info(""),o.success(`Your CVM is being created. You can check its status with:
62
+ phala cvms get app_${w.app_id}`)}catch(r){console.log(""),r instanceof x?(console.error("Status:",r.status),console.error("Status Text:",r.statusText),console.error(r.data)):console.error(r),process.exit(1)}});import{Command as Xo}from"commander";import Zo from"inquirer";var Xr=new Xo().name("delete").description("Delete a CVM").argument("[app-id]","App ID of the CVM to delete (if not provided, a selection prompt will appear)").option("-f, --force","Skip confirmation prompt",!1).action(async(e,r)=>{try{let t=await b(e);if(!r.force){let{confirm:i}=await Zo.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete CVM with App ID app_${t}? This action cannot be undone.`,default:!1}]);if(!i){o.info("Deletion cancelled");return}}let n=o.startSpinner(`Deleting CVM app_${t}`),s=await ze(t);n.stop(!0),s||(o.error(`Failed to delete CVM app_${t}`),process.exit(1)),o.success(`CVM app_${t} deleted successfully`)}catch(t){o.error(`Failed to delete CVM: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as en}from"commander";import rn from"node:fs";import{encryptEnvVars as tn}from"@phala/cloud";var Zr=new en().name("upgrade").description("Upgrade a CVM to a new version").argument("[app-id]","CVM app ID to upgrade (will prompt for selection if not provided)").option("-c, --compose <compose>","Path to new Docker Compose file").option("-e, --env-file <envFile>","Path to environment file").option("--debug","Enable debug mode",!1).action(async(e,r)=>{try{let t=await b(e),n=o.startSpinner(`Fetching current configuration for CVM app_${t}`),s=await K(t);if(n.stop(!0),s||(o.error(`CVM with App ID app_${t} not found`),process.exit(1)),!r.compose){let u=B(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");r.compose=await I("Enter the path to your Docker Compose file:",u,"file")}let i="",c=[];if(r.compose)try{i=rn.readFileSync(r.compose,"utf8")}catch(f){o.error(`Failed to read Docker Compose file: ${f instanceof Error?f.message:String(f)}`),process.exit(1)}await V(),process.env.DSTACK_DOCKER_USERNAME&&process.env.DSTACK_DOCKER_PASSWORD?o.info("\u{1F510} Using private DockerHub registry credentials..."):process.env.DSTACK_AWS_ACCESS_KEY_ID&&process.env.DSTACK_AWS_SECRET_ACCESS_KEY&&process.env.DSTACK_AWS_REGION&&process.env.DSTACK_AWS_ECR_REGISTRY?o.info(`\u{1F510} Using private AWS ECR registry: ${process.env.DSTACK_AWS_ECR_REGISTRY}`):o.info("\u{1F510} Using public DockerHub registry...");let m;if(r.envFile){let f=[];if(r.envFile)try{f=X([],r.envFile),m=await tn(f,s.encrypted_env_pubkey),c=f.map(u=>u.key)}catch(u){o.error(`Failed to read environment file: ${u instanceof Error?u.message:String(u)}`),process.exit(1)}}let p={compose_manifest:{docker_compose_file:i,manifest_version:1,runner:"docker-compose",version:"1.0.0",features:["kms","tproxy-net"],name:`app_${t}`,allowed_envs:c},encrypted_env:m,allow_restart:!0,env_keys:c},l=o.startSpinner(`Upgrading CVM app_${t}`),a=await He(t,p);a||(l.stop(!1),o.error("Failed to upgrade CVM"),process.exit(1)),l.stop(!0),a.detail&&o.info(`Details: ${a.detail}`),o.break(),o.success(`Your CVM is being upgraded. You can check the dashboard for more details:
63
+ ${v}/dashboard/cvms/app_${t}`)}catch(t){if(o.error(`Failed to upgrade CVM: ${t instanceof Error?t.message:String(t)}`),t instanceof x||t?.constructor?.name==="FetchError"||t&&typeof t=="object"&&"status"in t&&"statusText"in t&&"data"in t){let s=t;o.error("=== HTTP Error Details ==="),o.error("Status:",s.status),o.error("Status Text:",s.statusText),o.error("URL:",s.request),o.error("Response Body:",JSON.stringify(s.data,null,2)),r.debug&&o.error("Full Error Object:",t)}else r.debug&&o.error("Full Error:",t);process.exit(1)}});import{Command as on}from"commander";import Z from"inquirer";import R from"chalk";var et=new on().name("resize").description("Resize resources for a CVM").argument("[app-id]","App ID of the CVM (if not provided, a selection prompt will appear)").option("-v, --vcpu <vcpu>","Number of virtual CPUs").option("-m, --memory <memory>","Memory size in MB").option("-d, --disk-size <diskSize>","Disk size in GB").option("-r, --allow-restart <allowRestart>","Allow restart of the CVM if needed for resizing").option("-y, --yes","Automatically confirm the resize operation").action(async(e,r)=>{try{let t=await b(e),n=await K(t),s=r.vcpu,i=r.memory,c=r.diskSize,m=r.allowRestart;s||(s=(await Z.prompt([{type:"input",name:"vcpu",message:"Enter number of vCPUs:",validate:u=>{let d=parseInt(u);return isNaN(d)||d<0?"Please enter a valid non-negative number":!0},default:n.vcpu,filter:u=>parseInt(u)}])).vcpu),i||(i=(await Z.prompt([{type:"input",name:"memory",message:"Enter memory in MB:",validate:u=>{let d=parseInt(u);return isNaN(d)||d<0?"Please enter a valid non-negative number":!0},default:n.memory,filter:u=>parseInt(u)}])).memory),c||(c=(await Z.prompt([{type:"input",name:"diskSize",message:"Enter disk size in GB:",validate:u=>{let d=parseInt(u);return isNaN(d)||d<0?"Please enter a valid non-negative number":!0},default:n.disk_size,filter:u=>parseInt(u)}])).diskSize),m||(m=(await Z.prompt([{type:"confirm",name:"allowRestart",message:"Allow restart of the CVM if needed for resizing?",default:!1}])).allowRestart);let p=`Are you sure you want to resize CVM app_${t} with the following changes:
64
+ `;if(o.keyValueTable({vCPUs:n.vcpu!==s?`${R.red(n.vcpu)} -> ${R.green(s)}`:n.vcpu,Memory:n.memory!==i?`${R.red(n.memory)} MB -> ${R.green(i)} MB`:n.memory,"Disk Size":n.disk_size!==c?`${R.red(n.disk_size)} GB -> ${R.green(c)} GB`:n.disk_size,"Allow Restart":m?R.green("Yes"):R.red("No")}),!r.yes){let{confirm:f}=await Z.prompt([{type:"confirm",name:"confirm",message:p,default:!1}]);if(!f){o.info("Resize operation cancelled");return}}let l=o.startSpinner(`Resizing CVM with App ID app_${t}`);await Qe(t,s,i,c,m?1:0),l.stop(!0),o.break(),o.success(`Your CVM is being resized. You can check the dashboard for more details:
65
+ ${v}/dashboard/cvms/app_${t}`)}catch(t){o.error(`Failed to resize CVM: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import{Command as nn}from"commander";var rt=new nn().name("list-nodes").description("List all available worker nodes.").action(async()=>{try{let{nodes:e,kms_list:r}=await j();if(e.length===0){o.info("No available nodes found.");return}o.info("Available Nodes:"),e.forEach(t=>{o.info("----------------------------------------"),o.info(` ID: ${t.teepod_id}`),o.info(` Name: ${t.name}`),o.info(` Region: ${t.region_identifier}`),o.info(` FMSPC: ${t.fmspc||"N/A"}`),o.info(` Device ID: ${t.device_id||"N/A"}`),o.info(` Support Onchain KMS: ${t.support_onchain_kms}`),o.info(" Images:"),t.images&&t.images.length>0?t.images.forEach(n=>{o.info(` - ${n.name}`),o.info(` Hash: ${n.os_image_hash||"N/A"}`)}):o.info(" N/A")}),r&&r.length>0&&(o.info(`
66
66
  Available KMS Instances:`),r.forEach(t=>{o.info("----------------------------------------"),o.info(` ID: ${t.id}`),o.info(` URL: ${t.url}`),o.info(` Version: ${t.version}`),o.info(` Chain ID: ${t.chain_id}`),o.info(` Contract Address: ${t.kms_contract_address}`),o.info(` Gateway App ID: ${t.gateway_app_id}`)}))}catch(e){o.error(`Failed to list available nodes: ${e instanceof Error?e.message:String(e)}`)}});import{Command as sn}from"commander";import{encryptEnvVars as an}from"@phala/cloud";import tt from"node:fs";import cn from"node:path";var ot=new sn().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(e,r)=>{try{let t;if(e=e.replace(/-/g,""),r.envFile){let c=cn.resolve(process.cwd(),r.envFile);if(!tt.existsSync(c))throw new Error(`Environment file not found: ${c}`);let p=tt.readFileSync(c,"utf-8").split(`
67
67
  `).filter(f=>f.trim()!==""&&!f.trim().startsWith("#")).map(f=>{let[u,...d]=f.split("=");return{key:u.trim(),value:d.join("=").trim()}}),l=await Je(e);o.info("Encrypting environment variables..."),t=await an(p,l.env_pubkey)}let n={};r.teepodId&&(n.teepod_id=parseInt(r.teepodId,10)),t&&(n.encrypted_env=t);let s=await Ye(e,n);o.success(`Successfully created replica of CVM UUID: ${e} with App ID: ${s.app_id}`);let i={"CVM UUID":s.vm_uuid.replace(/-/g,""),"App ID":s.app_id,Name:s.name,Status:s.status,TEEPod:`${s.teepod.name} (ID: ${s.teepod_id})`,vCPUs:s.vcpu,Memory:`${s.memory} MB`,"Disk Size":`${s.disk_size} GB`,"App URL":s.app_url||`${process.env.CLOUD_URL||"https://cloud.phala.network"}/dashboard/cvms/${s.vm_uuid.replace(/-/g,"")}`};o.keyValueTable(i,{borderStyle:"rounded"}),o.success(`Your CVM replica is being created. You can check its status with:
68
- phala cvms get ${s.app_id}`)}catch(t){o.error("Failed to create CVM replica:",t instanceof Error?t.message:t),process.exit(1)}});var nt=new mn().name("cvms").description("Manage Phala Confidential Virtual Machines (CVMs)").addCommand(Mr).addCommand(Vr).addCommand(Or).addCommand(Fr).addCommand(Ar).addCommand(Tr).addCommand(xr).addCommand(et).addCommand(Rr).addCommand(Zr).addCommand(rt).addCommand(ot);import{Command as st}from"commander";async function Fe(){try{let{nodes:e,kms_list:r}=await K();if(e.length===0){o.info("No available nodes found.");return}o.info("Available Nodes:"),e.forEach(t=>{o.info("----------------------------------------"),o.info(` ID: ${t.teepod_id}`),o.info(` Name: ${t.name}`),o.info(` Region: ${t.region_identifier}`),o.info(` FMSPC: ${t.fmspc||"N/A"}`),o.info(` Device ID: ${t.device_id||"N/A"}`),o.info(` Support Onchain KMS: ${t.support_onchain_kms}`),o.info(" Images:"),t.images&&t.images.length>0?t.images.forEach(n=>{o.info(` - ${n.name}`),o.info(` Hash: ${n.os_image_hash||"N/A"}`)}):o.info(" N/A")}),r&&r.length>0&&(o.info(`
69
- Available KMS Instances:`),r.forEach(t=>{o.info("----------------------------------------"),o.info(` Slug: ${t.slug}`),o.info(` URL: ${t.url}`),o.info(` Version: ${t.version}`),t.chain_id&&(o.info(` Chain ID: ${t.chain_id}`),o.info(` Contract Address: ${t.kms_contract_address}`),o.info(` Gateway App ID: ${t.gateway_app_id}`))}))}catch(e){throw o.error(`Failed to list available nodes: ${e instanceof Error?e.message:String(e)}`),e}}var it=new st().name("nodes").description("List and manage TEE nodes").action(Fe).addCommand(new st("list").description("List all available worker nodes").alias("ls").action(Fe));import{createClient as ln}from"@phala/cloud";import{Command as pn}from"commander";import{safeGetCurrentUser as un}from"@phala/cloud";async function dn(e={}){try{let r=e.debug||process.env.DEBUG?.toLowerCase()==="true",t=e.apiKey||V();if(!t){o.warn('Not authenticated. Please set an API key with "phala auth login"');return}r&&o.debug(`Using API key: ${t.substring(0,5)}...`);try{let n=ln({apiKey:t}),s=await un(n);if(!s.success){o.error("Failed to get user information"),s.error&&o.error(`Error: ${s.error.message}`);return}let i=s.data,c=process.env.PHALA_CLOUD_API_PREFIX||"https://cloud-api.phala.network/api/v1";if(e.json){console.log(JSON.stringify({apiUrl:c,username:i.username,team_name:i.team_name},null,2));return}console.log(`Integrated API: ${c}`),console.log(`Logged in as: ${i.username}`),console.log(`Current Workspace: ${i.team_name}`)}catch(n){console.error("Authentication failed. Your API key may be invalid or expired."),console.log('Please set a new API key with "phala auth login"'),r&&o.debug(`Error details: ${n instanceof Error?n.message:String(n)}`)}}catch(r){o.error(`Failed to check authentication status: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}}var at=new pn().name("status").description("Check Phala Cloud status and authentication").option("--api-key <apiKey>","API key for authentication").option("-j, --json","Output in JSON format").option("-d, --debug","Enable debug output").action(dn);import{Command as yn,Option as vn}from"commander";import Me from"dedent";import xe from"fs-extra";import q from"inquirer";import wn from"path";import{createClient as ce,encryptEnvVars as Re,parseEnvVars as Cn,safeAddComposeHash as En,safeCommitCvmComposeFileUpdate as _n,safeCommitCvmProvision as yt,safeDeployAppAuth as bn,safeGetAppEnvEncryptPubKey as kn,safeGetAvailableNodes as Sn,safeGetCvmComposeFile as $n,safeGetCvmInfo as In,safeGetKmsList as Dn,safeProvisionCvm as Pn,safeProvisionCvmComposeFileUpdate as An}from"@phala/cloud";function ct(e,r="B"){if(!e||typeof e!="string")throw new Error("Invalid input: must be a non-empty string");let t=e.trim().match(/^(\d+(?:\.\d+)?)\s*([KkMmGgTt][Bb]?)?$/);if(!t)throw new Error(`Invalid format: ${e}. Expected format: <number>[unit] (e.g., 2G, 500MB, 1T)`);let n=parseFloat(t[1]),s=(t[2]||r).toUpperCase().replace("B",""),i={K:1024,M:1024*1024,G:1024*1024*1024,T:1024*1024*1024*1024,"":1};if(!(s in i))throw new Error(`Unsupported unit: ${s}. Supported units: B, K/KB, M/MB, G/GB, T/TB`);return Math.round(n*i[s])}function mt(e){let r=ct(e,"MB"),t=Math.round(r/(1024*1024));if(t%1024!==0)throw new Error(`Memory must be a multiple of 1GB (1024MB). Got: ${t}MB`);return t}function lt(e){let r=ct(e,"GB"),t=Math.round(r/(1024*1024*1024));if(t%1!==0)throw new Error(`Disk size must be a multiple of 1GB. Got: ${t}GB`);let n=250;if(t>n)throw new Error(`Maximum disk size is ${n}GB. Got: ${t}GB`);return t}import ee from"fs-extra";import pt from"node:path";import fn from"node:os";import{join as ut}from"path";var gn=pt.join(fn.homedir(),".phala-cloud"),Km=pt.join(gn,"config.json");function Te(){return ut(process.cwd(),".phala","config")}function dt(){let e=Te(),r=ut(process.cwd(),".phala");ee.ensureDirSync(r),ee.pathExistsSync(e)||ee.writeJsonSync(e,{},{spaces:2})}function ft(){return dt(),ee.readJsonSync(Te())}function hn(e){dt(),ee.writeJsonSync(Te(),e,{spaces:2})}function gt(e){let r=ft();r.cvmUuid=e,hn(r)}function ht(){return process.env.PHALA_CLOUD_CVM_UUID?process.env.PHALA_CLOUD_CVM_UUID:ft().cvmUuid}async function Fn({apiKey:e,interactive:r}){if(!e&&!process.env.PHALA_CLOUD_API_KEY)if(r){let{apiKey:t}=await q.prompt([{type:"password",name:"apiKey",message:"Enter your API key:",validate:n=>n.trim()?!0:"API key is required"}]);return ce({apiKey:t})}else{let t=V();if(!t)throw new Error("API key is required. Please provide it via --api-key or PHALA_CLOUD_API_KEY environment variable");return ce({apiKey:t})}else if(e)return ce({apiKey:e});return ce()}async function Tn({dockerComposePath:e,interactive:r}){if(!e)if(r){let n=j(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");e=await I("Enter the path to your Docker Compose file:",n,"file")}else throw new Error(Me(`
68
+ phala cvms get ${s.app_id}`)}catch(t){o.error("Failed to create CVM replica:",t instanceof Error?t.message:t),process.exit(1)}});var nt=new mn().name("cvms").description("Manage Phala Confidential Virtual Machines (CVMs)").addCommand(Mr).addCommand(Qr).addCommand(Xr).addCommand(Fr).addCommand(Ar).addCommand(Tr).addCommand(xr).addCommand(et).addCommand(Rr).addCommand(Zr).addCommand(rt).addCommand(ot);import{Command as st}from"commander";async function Fe(){try{let{nodes:e,kms_list:r}=await j();if(e.length===0){o.info("No available nodes found.");return}o.info("Available Nodes:"),e.forEach(t=>{o.info("----------------------------------------"),o.info(` ID: ${t.teepod_id}`),o.info(` Name: ${t.name}`),o.info(` Region: ${t.region_identifier}`),o.info(` FMSPC: ${t.fmspc||"N/A"}`),o.info(` Device ID: ${t.device_id||"N/A"}`),o.info(` Support Onchain KMS: ${t.support_onchain_kms}`),o.info(" Images:"),t.images&&t.images.length>0?t.images.forEach(n=>{o.info(` - ${n.name}`),o.info(` Hash: ${n.os_image_hash||"N/A"}`)}):o.info(" N/A")}),r&&r.length>0&&(o.info(`
69
+ Available KMS Instances:`),r.forEach(t=>{o.info("----------------------------------------"),o.info(` Slug: ${t.slug}`),o.info(` URL: ${t.url}`),o.info(` Version: ${t.version}`),t.chain_id&&(o.info(` Chain ID: ${t.chain_id}`),o.info(` Contract Address: ${t.kms_contract_address}`),o.info(` Gateway App ID: ${t.gateway_app_id}`))}))}catch(e){throw o.error(`Failed to list available nodes: ${e instanceof Error?e.message:String(e)}`),e}}var it=new st().name("nodes").description("List and manage TEE nodes").action(Fe).addCommand(new st("list").description("List all available worker nodes").alias("ls").action(Fe));import{createClient as ln}from"@phala/cloud";import{Command as pn}from"commander";import{safeGetCurrentUser as un}from"@phala/cloud";async function dn(e={}){try{let r=e.debug||process.env.DEBUG?.toLowerCase()==="true",t=e.apiKey||O();if(!t){o.warn('Not authenticated. Please set an API key with "phala auth login"');return}r&&o.debug(`Using API key: ${t.substring(0,5)}...`);try{let n=ln({apiKey:t}),s=await un(n);if(!s.success){o.error("Failed to get user information"),s.error&&o.error(`Error: ${s.error.message}`);return}let i=s.data,c=process.env.PHALA_CLOUD_API_PREFIX||"https://cloud-api.phala.network/api/v1";if(e.json){console.log(JSON.stringify({apiUrl:c,username:i.username,team_name:i.team_name},null,2));return}console.log(`Integrated API: ${c}`),console.log(`Logged in as: ${i.username}`),console.log(`Current Workspace: ${i.team_name}`)}catch(n){console.error("Authentication failed. Your API key may be invalid or expired."),console.log('Please set a new API key with "phala auth login"'),r&&o.debug(`Error details: ${n instanceof Error?n.message:String(n)}`)}}catch(r){o.error(`Failed to check authentication status: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}}var at=new pn().name("status").description("Check Phala Cloud status and authentication").option("--api-key <apiKey>","API key for authentication").option("-j, --json","Output in JSON format").option("-d, --debug","Enable debug output").action(dn);import{Command as yn,Option as vn}from"commander";import Me from"dedent";import xe from"fs-extra";import q from"inquirer";import wn from"path";import{createClient as ce,encryptEnvVars as Re,parseEnvVars as Cn,safeAddComposeHash as En,safeCommitCvmComposeFileUpdate as _n,safeCommitCvmProvision as yt,safeDeployAppAuth as bn,safeGetAppEnvEncryptPubKey as kn,safeGetAvailableNodes as Sn,safeGetCvmComposeFile as $n,safeGetCvmInfo as In,safeGetKmsList as Dn,safeProvisionCvm as Pn,safeProvisionCvmComposeFileUpdate as An}from"@phala/cloud";function ct(e,r="B"){if(!e||typeof e!="string")throw new Error("Invalid input: must be a non-empty string");let t=e.trim().match(/^(\d+(?:\.\d+)?)\s*([KkMmGgTt][Bb]?)?$/);if(!t)throw new Error(`Invalid format: ${e}. Expected format: <number>[unit] (e.g., 2G, 500MB, 1T)`);let n=parseFloat(t[1]),s=(t[2]||r).toUpperCase().replace("B",""),i={K:1024,M:1024*1024,G:1024*1024*1024,T:1024*1024*1024*1024,"":1};if(!(s in i))throw new Error(`Unsupported unit: ${s}. Supported units: B, K/KB, M/MB, G/GB, T/TB`);return Math.round(n*i[s])}function mt(e){let r=ct(e,"MB"),t=Math.round(r/(1024*1024));if(t%1024!==0)throw new Error(`Memory must be a multiple of 1GB (1024MB). Got: ${t}MB`);return t}function lt(e){let r=ct(e,"GB"),t=Math.round(r/(1024*1024*1024));if(t%1!==0)throw new Error(`Disk size must be a multiple of 1GB. Got: ${t}GB`);let n=250;if(t>n)throw new Error(`Maximum disk size is ${n}GB. Got: ${t}GB`);return t}import ee from"fs-extra";import pt from"node:path";import fn from"node:os";import{join as ut}from"path";var gn=pt.join(fn.homedir(),".phala-cloud"),jm=pt.join(gn,"config.json");function Te(){return ut(process.cwd(),".phala","config")}function dt(){let e=Te(),r=ut(process.cwd(),".phala");ee.ensureDirSync(r),ee.pathExistsSync(e)||ee.writeJsonSync(e,{},{spaces:2})}function ft(){return dt(),ee.readJsonSync(Te())}function hn(e){dt(),ee.writeJsonSync(Te(),e,{spaces:2})}function gt(e){let r=ft();r.cvmUuid=e,hn(r)}function ht(){return process.env.PHALA_CLOUD_CVM_UUID?process.env.PHALA_CLOUD_CVM_UUID:ft().cvmUuid}async function Fn({apiKey:e,interactive:r}){if(!e&&!process.env.PHALA_CLOUD_API_KEY)if(r){let{apiKey:t}=await q.prompt([{type:"password",name:"apiKey",message:"Enter your API key:",validate:n=>n.trim()?!0:"API key is required"}]);return ce({apiKey:t})}else{let t=O();if(!t)throw new Error("API key is required. Please provide it via --api-key or PHALA_CLOUD_API_KEY environment variable");return ce({apiKey:t})}else if(e)return ce({apiKey:e});return ce()}async function Tn({dockerComposePath:e,interactive:r}){if(!e)if(r){let n=B(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");e=await I("Enter the path to your Docker Compose file:",n,"file")}else throw new Error(Me(`
70
70
  Docker Compose file is required.
71
71
 
72
72
  Usage examples:
@@ -81,13 +81,13 @@ Available KMS Instances:`),r.forEach(t=>{o.info("-------------------------------
81
81
  --private-key <key> Private key for deployment
82
82
 
83
83
  Run with --interactive for guided setup
84
- `));if(!xe.existsSync(e))throw new Error(`Docker compose file not found: ${e}`);return xe.readFileSync(e,"utf8")}function xn({uuid:e}={}){return e||ht()}var Rn=async(e,r)=>{let t=e.privateKey||process.env.PRIVATE_KEY;if(e.kmsId&&r&&!e.privateKey)if(e.interactive)t=(await q.prompt([{type:"password",name:"privateKey",message:"Enter your private key:",validate:s=>s.trim()?!0:"Private key is required"}])).privateKey;else throw new Error("When using on-chain KMS, either --private-key (or PRIVATE_KEY env) must be provided");return t},Mn=async e=>{let r=e.name;if(!e.name){let t=wn.basename(process.cwd()).toLowerCase().replace(/[^a-z0-9_-]/g,"-");t.length<3&&(t=t+"-cvm");let n=t.slice(0,20);e.interactive?r=(await q.prompt([{type:"input",name:"name",message:"Enter a name for the CVM:",default:n,validate:i=>i.trim()?i.trim().length>20?"CVM name must be less than 20 characters":i.trim().length<3?"CVM name must be at least 3 characters":/^[a-zA-Z0-9_-]+$/.test(i)?!0:"CVM name must contain only letters, numbers, underscores, and hyphens":"CVM name is required"}])).name:r=n}return r},Nn=async e=>{let r,t=e.envFile;if(e.interactive&&(!e.envFile||t===!0)&&(t=await I("Enter the path to your environment file:",".env","file")),t&&t!==!0)try{let n=xe.readFileSync(t,{encoding:"utf8"});r=Cn(n)}catch(n){throw new Error(`Error reading environment file ${t}:`,n)}return r},Ln=async e=>{let r=R;if(e.vcpu)try{r=Number(e.vcpu)}catch{throw new Error(`Invalid vCPU format '${e.vcpu}'. Using default: ${R}`)}let t=M;if(e.memory)try{t=mt(e.memory)}catch{throw new Error(`Invalid memory format '${e.memory}'. Using default: ${M}MB`)}let n=N;if(e.diskSize)try{n=lt(e.diskSize)}catch{throw new Error(`Invalid disk size format '${e.diskSize}'. Using default: ${N}GB`)}return{vcpu:r,memoryMB:t,diskSizeGB:n}},Un=async(e,r)=>{let t=await Sn(r);if(!t.success)throw"isRequestError"in t.error?new Error(`HTTP ${t.error.status}: ${t.error.message}`):new Error(`Validation error: ${t.error.issues}`);let n=t.data,s=null,i=null,c=e.privateKey;if(e.nodeId){if(s=n.nodes.find(p=>p.teepod_id===Number(e.nodeId)),!s)throw new Error(`Node ${e.nodeId} not found, available nodes: ${n.nodes.map(p=>p.teepod_id).join(", ")}`)}else if(e.interactive){let{node:p}=await q.prompt([{type:"list",name:"node",message:"Select a Node to use:",choices:n.nodes.map(l=>({name:`${l.name} (Region: ${l.region_identifier})`,value:l}))}]);s=p}else s=n.nodes[0];if(!s)throw new Error(`No available nodes found, available nodes: ${n.nodes.map(p=>p.teepod_id).join(", ")}`);if(s.support_onchain_kms){let p=await Dn(r);if(!p.success)throw"isRequestError"in p.error?new Error(`HTTP ${p.error.status}: ${p.error.message}`):new Error(`Validation error: ${p.error.issues}`);let l=p.data;if(e.kmsId)i=l.items.find(a=>a.slug===e.kmsId||a.id===e.kmsId);else if(e.interactive){let{kmsChoice:a}=await q.prompt([{type:"list",name:"kmsChoice",message:"Select a KMS to use:",choices:l.items.map(f=>({name:f.chain_id?`${f.slug} (Chain ID: ${f.chain_id})`:`${f.slug} (No chain required)`,value:f}))}]);i=a}else throw new Error(`Node ${s.name} requires a KMS ID for Contract Owned CVM, available kms: ${l.items.map(a=>a.slug).join(", ")}`);if(i)c=await Rn({...e,kmsId:i.id},i.chain_id);else throw new Error(`KMS ${e.kmsId} not found, available kms: ${l.items.map(a=>a.slug).join(", ")}`)}let m=s.images[0];if(e.image){if(m=s.images.find(p=>p.name===e.image),!m)throw new Error(`Image ${e.image} not found in the node ${s.name}, available images: ${s.images.map(p=>p.name).join(", ")}.`)}else if(e.interactive){let{imageChoice:p}=await q.prompt([{type:"list",name:"imageChoice",message:"Select an image to use:",choices:s.images.map(l=>({name:`${l.name}`,value:l}))}]);m=p}if(!m)throw new Error(`No available OS images found in the node ${s.name}, available images: ${s.images.map(p=>p.name).join(", ")}.`);return{target:s,kms:i,image:m,privateKey:c}},Vn=async(e,r,t,n)=>{let s=await Mn(e),{vcpu:i,memoryMB:c,diskSizeGB:m}=await Ln(e),{target:p,kms:l,image:a,privateKey:f}=await Un(e,n),u={name:s,compose_file:{docker_compose_file:r,allowed_envs:t.map(w=>w.key)},vcpu:i,memory:c,disk_size:m,node_id:p.teepod_id,image:a.name,kms_id:l?.slug};console.log(`Deploying CVM ${s}...`);let d=await Pn(n,u);if(!d.success)throw new Error("Failed to provision CVM:",d.error);let y=d.data,g;if(y.app_env_encrypt_pubkey&&y.app_id||!l?.chain_id){let w=await Re(t,y.app_env_encrypt_pubkey);g=await yt(n,{app_id:y.app_id,encrypted_env:w,compose_hash:y.compose_hash,kms_id:l?.slug})}else{let w=l.slug,me=l.kms_contract_address,_=l.chain,$=y.compose_hash,wt=p.device_id,Ct=e.rpcUrl,le=await bn({chain:_,rpcUrl:Ct,kmsContractAddress:me,privateKey:f,deviceId:wt,composeHash:$});if(!le.success){let bt=le?.error?.message;throw new Error(`Deployment contract failed: ${bt}`)}let pe=le.data,Ne=pe.appId,ue=await kn(n,{app_id:Ne,kms:w});if(!ue.success)throw new Error(`Failed to get app env encrypt pubkey: ${ue.error.message}`);let Et=ue.data,_t=await Re(t,Et.public_key);g=await yt(n,{app_id:Ne,encrypted_env:_t,compose_hash:y.compose_hash,kms_id:w,contract_address:pe.appAuthAddress,deployer_address:pe.deployer})}if(!g.success)throw"isRequestError"in g.error?new Error(`HTTP ${g.error.status}: ${g.error.message}`):new Error(`Validation error: ${g.error.issues}`);let C=g.data;if(gt(C.vm_uuid),e?.json!==!1)console.log(JSON.stringify({success:!0,vm_uuid:C.vm_uuid,name:C.name,app_id:C.app_id,dashboard_url:`${v}/dashboard/cvms/${C.vm_uuid}`},null,2));else{let w=Me`
84
+ `));if(!xe.existsSync(e))throw new Error(`Docker compose file not found: ${e}`);return xe.readFileSync(e,"utf8")}function xn({uuid:e}={}){return e||ht()}var Rn=async(e,r)=>{let t=e.privateKey||process.env.PRIVATE_KEY;if(e.kmsId&&r&&!e.privateKey)if(e.interactive)t=(await q.prompt([{type:"password",name:"privateKey",message:"Enter your private key:",validate:s=>s.trim()?!0:"Private key is required"}])).privateKey;else throw new Error("When using on-chain KMS, either --private-key (or PRIVATE_KEY env) must be provided");return t},Mn=async e=>{let r=e.name;if(!e.name){let t=wn.basename(process.cwd()).toLowerCase().replace(/[^a-z0-9_-]/g,"-");t.length<3&&(t=t+"-cvm");let n=t.slice(0,20);e.interactive?r=(await q.prompt([{type:"input",name:"name",message:"Enter a name for the CVM:",default:n,validate:i=>i.trim()?i.trim().length>20?"CVM name must be less than 20 characters":i.trim().length<3?"CVM name must be at least 3 characters":/^[a-zA-Z0-9_-]+$/.test(i)?!0:"CVM name must contain only letters, numbers, underscores, and hyphens":"CVM name is required"}])).name:r=n}return r},Nn=async e=>{let r,t=e.envFile;if(e.interactive&&(!e.envFile||t===!0)&&(t=await I("Enter the path to your environment file:",".env","file")),t&&t!==!0)try{let n=xe.readFileSync(t,{encoding:"utf8"});r=Cn(n)}catch(n){throw new Error(`Error reading environment file ${t}:`,n)}return r},Ln=async e=>{let r=M;if(e.vcpu)try{r=Number(e.vcpu)}catch{throw new Error(`Invalid vCPU format '${e.vcpu}'. Using default: ${M}`)}let t=N;if(e.memory)try{t=mt(e.memory)}catch{throw new Error(`Invalid memory format '${e.memory}'. Using default: ${N}MB`)}let n=L;if(e.diskSize)try{n=lt(e.diskSize)}catch{throw new Error(`Invalid disk size format '${e.diskSize}'. Using default: ${L}GB`)}return{vcpu:r,memoryMB:t,diskSizeGB:n}},Un=async(e,r)=>{let t=await Sn(r);if(!t.success)throw"isRequestError"in t.error?new Error(`HTTP ${t.error.status}: ${t.error.message}`):new Error(`Validation error: ${t.error.issues}`);let n=t.data,s=null,i=null,c=e.privateKey;if(e.nodeId){if(s=n.nodes.find(p=>p.teepod_id===Number(e.nodeId)),!s)throw new Error(`Node ${e.nodeId} not found, available nodes: ${n.nodes.map(p=>p.teepod_id).join(", ")}`)}else if(e.interactive){let{node:p}=await q.prompt([{type:"list",name:"node",message:"Select a Node to use:",choices:n.nodes.map(l=>({name:`${l.name} (Region: ${l.region_identifier})`,value:l}))}]);s=p}else s=n.nodes[0];if(!s)throw new Error(`No available nodes found, available nodes: ${n.nodes.map(p=>p.teepod_id).join(", ")}`);if(s.support_onchain_kms){let p=await Dn(r);if(!p.success)throw"isRequestError"in p.error?new Error(`HTTP ${p.error.status}: ${p.error.message}`):new Error(`Validation error: ${p.error.issues}`);let l=p.data;if(e.kmsId)i=l.items.find(a=>a.slug===e.kmsId||a.id===e.kmsId);else if(e.interactive){let{kmsChoice:a}=await q.prompt([{type:"list",name:"kmsChoice",message:"Select a KMS to use:",choices:l.items.map(f=>({name:f.chain_id?`${f.slug} (Chain ID: ${f.chain_id})`:`${f.slug} (No chain required)`,value:f}))}]);i=a}else throw new Error(`Node ${s.name} requires a KMS ID for Contract Owned CVM, available kms: ${l.items.map(a=>a.slug).join(", ")}`);if(i)c=await Rn({...e,kmsId:i.id},i.chain_id);else throw new Error(`KMS ${e.kmsId} not found, available kms: ${l.items.map(a=>a.slug).join(", ")}`)}let m=s.images[0];if(e.image){if(m=s.images.find(p=>p.name===e.image),!m)throw new Error(`Image ${e.image} not found in the node ${s.name}, available images: ${s.images.map(p=>p.name).join(", ")}.`)}else if(e.interactive){let{imageChoice:p}=await q.prompt([{type:"list",name:"imageChoice",message:"Select an image to use:",choices:s.images.map(l=>({name:`${l.name}`,value:l}))}]);m=p}if(!m)throw new Error(`No available OS images found in the node ${s.name}, available images: ${s.images.map(p=>p.name).join(", ")}.`);return{target:s,kms:i,image:m,privateKey:c}},Vn=async(e,r,t,n)=>{let s=await Mn(e),{vcpu:i,memoryMB:c,diskSizeGB:m}=await Ln(e),{target:p,kms:l,image:a,privateKey:f}=await Un(e,n),u={name:s,compose_file:{docker_compose_file:r,allowed_envs:t.map(w=>w.key)},vcpu:i,memory:c,disk_size:m,node_id:p.teepod_id,image:a.name,kms_id:l?.slug};console.log(`Deploying CVM ${s}...`);let d=await Pn(n,u);if(!d.success)throw new Error("Failed to provision CVM:",d.error);let y=d.data,g;if(y.app_env_encrypt_pubkey&&y.app_id||!l?.chain_id){let w=await Re(t,y.app_env_encrypt_pubkey);g=await yt(n,{app_id:y.app_id,encrypted_env:w,compose_hash:y.compose_hash,kms_id:l?.slug})}else{let w=l.slug,me=l.kms_contract_address,_=l.chain,$=y.compose_hash,wt=p.device_id,Ct=e.rpcUrl,le=await bn({chain:_,rpcUrl:Ct,kmsContractAddress:me,privateKey:f,deviceId:wt,composeHash:$});if(!le.success){let bt=le?.error?.message;throw new Error(`Deployment contract failed: ${bt}`)}let pe=le.data,Ne=pe.appId,ue=await kn(n,{app_id:Ne,kms:w});if(!ue.success)throw new Error(`Failed to get app env encrypt pubkey: ${ue.error.message}`);let Et=ue.data,_t=await Re(t,Et.public_key);g=await yt(n,{app_id:Ne,encrypted_env:_t,compose_hash:y.compose_hash,kms_id:w,contract_address:pe.appAuthAddress,deployer_address:pe.deployer})}if(!g.success)throw"isRequestError"in g.error?new Error(`HTTP ${g.error.status}: ${g.error.message}`):new Error(`Validation error: ${g.error.issues}`);let C=g.data;if(gt(C.vm_uuid),e?.json!==!1)console.log(JSON.stringify({success:!0,vm_uuid:C.vm_uuid,name:C.name,app_id:C.app_id,dashboard_url:`${v}/dashboard/cvms/${C.vm_uuid}`},null,2));else{let w=Me`
85
85
  CVM created successfully!
86
86
 
87
87
  CVM ID: ${C.vm_uuid}
88
88
  Name: ${C.name}
89
89
  App ID: ${C.app_id}
90
90
  Dashboard URL: ${v}/dashboard/cvms/${C.vm_uuid}
91
- `;console.log(w)}},On=async(e,r,t,n)=>{let[s,i]=await Promise.all([In(n,{uuid:e.uuid}),$n(n,{uuid:e.uuid})]);if(!s.success)throw new Error(`Failed to get cvm info: ${s.error.message}`);if(!i.success)throw new Error(`Failed to get cvm compose file: ${i.error.message}`);let c=s.data,m=i.data;m.docker_compose_file=r,t&&(m.allowed_envs=t.map(d=>d.key)),console.log(`Preparing update for CVM ${e.uuid}...`);let p=await An(n,{uuid:e.uuid,app_compose:m});if(!p.success)throw"isRequestError"in p.error&&(console.error("HTTP Error:",p.error.status,p.error.statusText),console.error("Error message:",p.error.message),console.error("Response body:",JSON.stringify(p.error.data,null,2))),new Error(`Failed to provision cvm compose file: ${p.error.message}`);let l=p.data,a;if(c.kms_info?.chain_id){if(!e.privateKey)throw new Error("Private key is required for contract DstackApp");let d=await En({chain:c.kms_info?.chain,rpcUrl:e.rpcUrl,appId:c.app_id,composeHash:l.compose_hash,privateKey:e.privateKey});if(!d.success){let y=d?.error?.message;throw new Error(`Failed to add compose hash: ${y}`)}}else t&&t.length>0&&(a=await Re(t,c.encrypted_env_pubkey));let f={id:e.uuid,compose_hash:l.compose_hash,encrypted_env:a,env_keys:t?.length?t.map(d=>d.key):void 0},u=await _n(n,f);if(!u.success)throw"isRequestError"in u.error&&(console.error("HTTP Error:",u.error.status,u.error.statusText),console.error("Error message:",u.error.message),console.error("Response body:",JSON.stringify(u.error.data,null,2))),new Error(`Failed to commit CVM compose file update: ${u.error.message}`);e?.json!==!1?console.log(JSON.stringify({success:!0,vm_uuid:e.uuid,name:c.name,app_id:c.app_id,dashboard_url:`${v}/dashboard/cvms/${e.uuid}`},null,2)):console.log("CVM compose file updated successfully!")},vt=new yn().command("deploy [compose]").description("Create a new CVM with on-chain KMS in one step.").option("--json","Output in JSON format",!1).option("--no-json","Disable JSON output format").option("--debug","Enable debug logging",!1).option("--api-key <apiKey>","API key for authentication").option("-n, --name <name>","Name of the CVM").option("-c, --compose <compose>","Path to Docker Compose file (default: docker-compose.yml in current directory)").option("--vcpu <vcpu>",`Number of vCPUs, default is ${R}`).option("--memory <memory>",`Memory with optional unit (e.g., 2G, 1024MB), default is ${M}MB`).option("--disk-size <diskSize>",`Disk size with optional unit (e.g., 50G, 100GB), default is ${N}GB`).option("--image <image>","Version of dstack image to use").option("--node-id <nodeId>","Node ID to use").option("-e, --env-file <envFile>","Prompt for environment variables and save to file (optional)").option("-i, --interactive","Enable interactive mode for required parameters",!1).option("--kms-id <kmsId>","KMS ID to use.").option("--uuid <uuid>","UUID of the CVM to upgrade").addOption(new vn("--custom-app-id <customAppId>","Custom App ID to use.").hideHelp()).option("--pre-launch-script <preLaunchScript>","Path to pre-launch script").option("--private-key <privateKey>","Private key for signing transactions.").option("--rpc-url <rpcUrl>","RPC URL for the blockchain.").action(async(e,r)=>{try{let t=e||r.compose,n=await Fn({apiKey:r.apiKey,interactive:r.interactive}),s=await Tn({dockerComposePath:t,interactive:r.interactive}),i=xn({uuid:r.uuid}),c=await Nn(r);!!i?await On({...r,uuid:i},s,c,n):await Vn({...r,uuid:i},s,c,n)}catch(t){r.json!==!1?console.error(JSON.stringify({success:!1,error:t.message,stack:r.debug&&t instanceof Error?t.stack:void 0},null,2)):console.error(Me`${t.message}`),process.exit(1)}});import{readFileSync as jn}from"fs";import{join as Bn,dirname as qn}from"path";import{fileURLToPath as Gn}from"url";var Hn=Gn(import.meta.url),zn=qn(Hn),Wn=Bn(zn,"../package.json"),Jn=JSON.parse(jn(Wn,"utf-8")),Yn=`v${Jn.version}`;process.on("SIGINT",()=>process.exit(0));process.on("SIGTERM",()=>process.exit(0));async function Qn(){new Kn().name("phala").alias("pha").description(`${cr}
91
+ `;console.log(w)}},On=async(e,r,t,n)=>{let[s,i]=await Promise.all([In(n,{uuid:e.uuid}),$n(n,{uuid:e.uuid})]);if(!s.success)throw new Error(`Failed to get cvm info: ${s.error.message}`);if(!i.success)throw new Error(`Failed to get cvm compose file: ${i.error.message}`);let c=s.data,m=i.data;m.docker_compose_file=r,t&&(m.allowed_envs=t.map(d=>d.key)),console.log(`Preparing update for CVM ${e.uuid}...`);let p=await An(n,{uuid:e.uuid,app_compose:m});if(!p.success)throw"isRequestError"in p.error&&(console.error("HTTP Error:",p.error.status,p.error.statusText),console.error("Error message:",p.error.message),console.error("Response body:",JSON.stringify(p.error.data,null,2))),new Error(`Failed to provision cvm compose file: ${p.error.message}`);let l=p.data,a;if(c.kms_info?.chain_id){if(!e.privateKey)throw new Error("Private key is required for contract DstackApp");let d=await En({chain:c.kms_info?.chain,rpcUrl:e.rpcUrl,appId:c.app_id,composeHash:l.compose_hash,privateKey:e.privateKey});if(!d.success){let y=d?.error?.message;throw new Error(`Failed to add compose hash: ${y}`)}}else t&&t.length>0&&(a=await Re(t,c.encrypted_env_pubkey));let f={id:e.uuid,compose_hash:l.compose_hash,encrypted_env:a,env_keys:t?.length?t.map(d=>d.key):void 0},u=await _n(n,f);if(!u.success)throw"isRequestError"in u.error&&(console.error("HTTP Error:",u.error.status,u.error.statusText),console.error("Error message:",u.error.message),console.error("Response body:",JSON.stringify(u.error.data,null,2))),new Error(`Failed to commit CVM compose file update: ${u.error.message}`);e?.json!==!1?console.log(JSON.stringify({success:!0,vm_uuid:e.uuid,name:c.name,app_id:c.app_id,dashboard_url:`${v}/dashboard/cvms/${e.uuid}`},null,2)):console.log("CVM compose file updated successfully!")},vt=new yn().command("deploy [compose]").description("Create a new CVM with on-chain KMS in one step.").option("--json","Output in JSON format",!1).option("--no-json","Disable JSON output format").option("--debug","Enable debug logging",!1).option("--api-key <apiKey>","API key for authentication").option("-n, --name <name>","Name of the CVM").option("-c, --compose <compose>","Path to Docker Compose file (default: docker-compose.yml in current directory)").option("--vcpu <vcpu>",`Number of vCPUs, default is ${M}`).option("--memory <memory>",`Memory with optional unit (e.g., 2G, 1024MB), default is ${N}MB`).option("--disk-size <diskSize>",`Disk size with optional unit (e.g., 50G, 100GB), default is ${L}GB`).option("--image <image>","Version of dstack image to use").option("--node-id <nodeId>","Node ID to use").option("-e, --env-file <envFile>","Prompt for environment variables and save to file (optional)").option("-i, --interactive","Enable interactive mode for required parameters",!1).option("--kms-id <kmsId>","KMS ID to use.").option("--uuid <uuid>","UUID of the CVM to upgrade").addOption(new vn("--custom-app-id <customAppId>","Custom App ID to use.").hideHelp()).option("--pre-launch-script <preLaunchScript>","Path to pre-launch script").option("--private-key <privateKey>","Private key for signing transactions.").option("--rpc-url <rpcUrl>","RPC URL for the blockchain.").action(async(e,r)=>{try{let t=e||r.compose,n=await Fn({apiKey:r.apiKey,interactive:r.interactive}),s=await Tn({dockerComposePath:t,interactive:r.interactive}),i=xn({uuid:r.uuid}),c=await Nn(r);!!i?await On({...r,uuid:i},s,c,n):await Vn({...r,uuid:i},s,c,n)}catch(t){r.json!==!1?console.error(JSON.stringify({success:!1,error:t.message,stack:r.debug&&t instanceof Error?t.stack:void 0},null,2)):console.error(Me`${t.message}`),process.exit(1)}});import{readFileSync as jn}from"fs";import{join as Bn,dirname as qn}from"path";import{fileURLToPath as Gn}from"url";var Hn=Gn(import.meta.url),zn=qn(Hn),Wn=Bn(zn,"../package.json"),Jn=JSON.parse(jn(Wn,"utf-8")),Yn=`v${Jn.version}`;process.on("SIGINT",()=>process.exit(0));process.on("SIGTERM",()=>process.exit(0));async function Qn(){new Kn().name("phala").alias("pha").description(`${cr}
92
92
  Phala Cloud CLI - Manage your Phala Cloud Deployments`).version(Yn).addCommand(at).addCommand(ur).addCommand(nt).addCommand(Ir).addCommand(_e).addCommand(it).addCommand(vt).parse(process.argv)}Qn().catch(e=>{o.error("An error occurred:",e),process.exit(1)});
93
93
  //# sourceMappingURL=index.js.map