@layr-labs/ecloud-cli 0.4.3-dev → 0.5.0-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/VERSION +2 -2
  2. package/dist/commands/auth/login.js +84 -54
  3. package/dist/commands/auth/login.js.map +1 -1
  4. package/dist/commands/auth/migrate.js +66 -30
  5. package/dist/commands/auth/migrate.js.map +1 -1
  6. package/dist/commands/auth/whoami.js.map +1 -1
  7. package/dist/commands/billing/__tests__/status.test.js +9 -0
  8. package/dist/commands/billing/__tests__/status.test.js.map +1 -1
  9. package/dist/commands/billing/__tests__/subscribe.test.js +9 -0
  10. package/dist/commands/billing/__tests__/subscribe.test.js.map +1 -1
  11. package/dist/commands/billing/__tests__/top-up.test.js +9 -0
  12. package/dist/commands/billing/__tests__/top-up.test.js.map +1 -1
  13. package/dist/commands/billing/cancel.js +9 -0
  14. package/dist/commands/billing/cancel.js.map +1 -1
  15. package/dist/commands/billing/status.js +9 -0
  16. package/dist/commands/billing/status.js.map +1 -1
  17. package/dist/commands/billing/subscribe.js +9 -0
  18. package/dist/commands/billing/subscribe.js.map +1 -1
  19. package/dist/commands/billing/top-up.js +9 -0
  20. package/dist/commands/billing/top-up.js.map +1 -1
  21. package/dist/commands/compute/app/configure/tls.js +138 -50
  22. package/dist/commands/compute/app/configure/tls.js.map +1 -1
  23. package/dist/commands/compute/app/create.js.map +1 -1
  24. package/dist/commands/compute/app/deploy.js +71 -18
  25. package/dist/commands/compute/app/deploy.js.map +1 -1
  26. package/dist/commands/compute/app/info.js +15 -8
  27. package/dist/commands/compute/app/info.js.map +1 -1
  28. package/dist/commands/compute/app/list.js +10 -1
  29. package/dist/commands/compute/app/list.js.map +1 -1
  30. package/dist/commands/compute/app/logs.js +15 -8
  31. package/dist/commands/compute/app/logs.js.map +1 -1
  32. package/dist/commands/compute/app/profile/set.js +16 -8
  33. package/dist/commands/compute/app/profile/set.js.map +1 -1
  34. package/dist/commands/compute/app/releases.js +15 -8
  35. package/dist/commands/compute/app/releases.js.map +1 -1
  36. package/dist/commands/compute/app/start.js +27 -11
  37. package/dist/commands/compute/app/start.js.map +1 -1
  38. package/dist/commands/compute/app/stop.js +27 -11
  39. package/dist/commands/compute/app/stop.js.map +1 -1
  40. package/dist/commands/compute/app/terminate.js +20 -8
  41. package/dist/commands/compute/app/terminate.js.map +1 -1
  42. package/dist/commands/compute/app/upgrade.js +110 -21
  43. package/dist/commands/compute/app/upgrade.js.map +1 -1
  44. package/dist/commands/compute/build/info.js +10 -1
  45. package/dist/commands/compute/build/info.js.map +1 -1
  46. package/dist/commands/compute/build/list.js +10 -1
  47. package/dist/commands/compute/build/list.js.map +1 -1
  48. package/dist/commands/compute/build/logs.js +10 -1
  49. package/dist/commands/compute/build/logs.js.map +1 -1
  50. package/dist/commands/compute/build/status.js +10 -1
  51. package/dist/commands/compute/build/status.js.map +1 -1
  52. package/dist/commands/compute/build/submit.js +11 -1
  53. package/dist/commands/compute/build/submit.js.map +1 -1
  54. package/dist/commands/compute/build/verify.js +10 -1
  55. package/dist/commands/compute/build/verify.js.map +1 -1
  56. package/dist/commands/compute/environment/set.js +8 -0
  57. package/dist/commands/compute/environment/set.js.map +1 -1
  58. package/dist/commands/compute/undelegate.js +10 -1
  59. package/dist/commands/compute/undelegate.js.map +1 -1
  60. package/dist/hooks/init/__tests__/version-check.test.js +1 -1
  61. package/dist/hooks/init/__tests__/version-check.test.js.map +1 -1
  62. package/dist/hooks/init/version-check.js +1 -1
  63. package/dist/hooks/init/version-check.js.map +1 -1
  64. package/package.json +26 -21
@@ -305,7 +305,7 @@ function findAvailableName(environment, baseName) {
305
305
 
306
306
  // src/utils/version.ts
307
307
  function getCliVersion() {
308
- return true ? "0.4.3-dev" : "0.0.0";
308
+ return true ? "0.5.0-dev.2" : "0.0.0";
309
309
  }
310
310
  function getClientId() {
311
311
  return `ecloud-cli/v${getCliVersion()}`;
@@ -313,6 +313,13 @@ function getClientId() {
313
313
 
314
314
  // src/utils/prompts.ts
315
315
  import { execSync } from "child_process";
316
+ function ensureInteractive(missingFlagHint) {
317
+ if (!process.stdin.isTTY) {
318
+ throw new Error(
319
+ `Cannot prompt in non-interactive mode. Provide ${missingFlagHint} via CLI flags or environment variables.`
320
+ );
321
+ }
322
+ }
316
323
  async function getDockerfileInteractive(dockerfilePath) {
317
324
  if (dockerfilePath) {
318
325
  return dockerfilePath;
@@ -322,6 +329,7 @@ async function getDockerfileInteractive(dockerfilePath) {
322
329
  if (!fs3.existsSync(dockerfilePath_resolved)) {
323
330
  return "";
324
331
  }
332
+ ensureInteractive("--dockerfile or --image-ref");
325
333
  console.log(`
326
334
  Found Dockerfile in ${cwd}`);
327
335
  const choice = await select({
@@ -368,6 +376,7 @@ async function promptUseVerifiableBuild() {
368
376
  return confirmWithDefault("Build from verifiable source?", false);
369
377
  }
370
378
  async function promptVerifiableSourceType() {
379
+ ensureInteractive("--verifiable with --repo/--commit or --image-ref");
371
380
  return select({
372
381
  message: "Choose verifiable source type:",
373
382
  choices: [
@@ -377,6 +386,7 @@ async function promptVerifiableSourceType() {
377
386
  });
378
387
  }
379
388
  async function promptVerifiableGitSourceInputs() {
389
+ ensureInteractive("--repo, --commit");
380
390
  const detected = detectGitRepoInfo();
381
391
  const repoUrl = (await input({
382
392
  message: "Enter public git repository URL:",
@@ -458,6 +468,7 @@ async function promptVerifiableGitSourceInputs() {
458
468
  };
459
469
  }
460
470
  async function promptVerifiablePrebuiltImageRef() {
471
+ ensureInteractive("--image-ref");
461
472
  const ref = await input({
462
473
  message: "Enter prebuilt verifiable image ref:",
463
474
  default: "docker.io/eigenlayer/eigencloud-containers:",
@@ -548,6 +559,7 @@ async function getAvailableRegistries() {
548
559
  const auths = config.auths || {};
549
560
  const credsStore = config.credsStore;
550
561
  const gcrProjects = /* @__PURE__ */ new Map();
562
+ const dockerhubUsers = /* @__PURE__ */ new Map();
551
563
  const registries = [];
552
564
  for (const [registry, auth] of Object.entries(auths)) {
553
565
  const authData = auth;
@@ -588,8 +600,17 @@ async function getAvailableRegistries() {
588
600
  }
589
601
  continue;
590
602
  }
603
+ if (registryType === "dockerhub") {
604
+ if (!dockerhubUsers.has(username)) {
605
+ dockerhubUsers.set(username, info);
606
+ }
607
+ continue;
608
+ }
591
609
  registries.push(info);
592
610
  }
611
+ for (const dhInfo of Array.from(dockerhubUsers.values())) {
612
+ registries.push(dhInfo);
613
+ }
593
614
  for (const gcrInfo of Array.from(gcrProjects.values())) {
594
615
  registries.push(gcrInfo);
595
616
  }
@@ -692,6 +713,7 @@ async function getImageReferenceInteractive(imageRef, buildFromDockerfile = fals
692
713
  if (imageRef) {
693
714
  return imageRef;
694
715
  }
716
+ ensureInteractive("--image-ref");
695
717
  const registries = await getAvailableRegistries();
696
718
  const appName = getDefaultAppName();
697
719
  if (buildFromDockerfile) {
@@ -721,6 +743,7 @@ async function getImageReferenceInteractive(imageRef, buildFromDockerfile = fals
721
743
  return imageRefInput;
722
744
  }
723
745
  async function getAvailableAppNameInteractive(environment, imageRef, suggestedBaseName, skipDefaultName) {
746
+ ensureInteractive("--name");
724
747
  const baseName = skipDefaultName ? void 0 : suggestedBaseName || extractAppNameFromImage(imageRef);
725
748
  const suggestedName = baseName ? findAvailableName(environment, baseName) : void 0;
726
749
  while (true) {
@@ -768,6 +791,7 @@ async function getEnvFileInteractive(envFilePath) {
768
791
  if (fs3.existsSync(".env")) {
769
792
  return ".env";
770
793
  }
794
+ ensureInteractive("--env-file");
771
795
  console.log("\nEnvironment file not found.");
772
796
  console.log("Environment files contain variables like RPC_URL, etc.");
773
797
  const choice = await select({
@@ -819,14 +843,19 @@ async function getInstanceTypeInteractive(instanceType, defaultSKU, availableTyp
819
843
  const validSKUs = availableTypes.map((t) => t.sku).join(", ");
820
844
  throw new Error(`Invalid instance-type: ${instanceType} (must be one of: ${validSKUs})`);
821
845
  }
846
+ ensureInteractive("--instance-type");
822
847
  const isCurrentType = defaultSKU !== "";
823
848
  const hasPricing = availableTypes.some((t) => t.monthly_price_usd != null);
824
849
  if (hasPricing) {
825
850
  console.log("\nPay for what you use \u2014 no upfront costs, per-hour billing.\n");
826
851
  console.log(` ${chalk.bold("Shielded VM (vTPM)")}: Verified boot and runtime attestation.`);
827
- console.log(` ${chalk.bold("SEV-SNP (TEE)")}: Verified boot, runtime attestation, and hardware-encrypted memory (AMD).`);
828
- console.log(` ${chalk.bold("TDX (TEE)")}: Verified boot, runtime attestation, and hardware-encrypted memory (Intel).
829
- `);
852
+ console.log(
853
+ ` ${chalk.bold("SEV-SNP (TEE)")}: Verified boot, runtime attestation, and hardware-encrypted memory (AMD).`
854
+ );
855
+ console.log(
856
+ ` ${chalk.bold("TDX (TEE)")}: Verified boot, runtime attestation, and hardware-encrypted memory (Intel).
857
+ `
858
+ );
830
859
  }
831
860
  if (isCurrentType && defaultSKU) {
832
861
  console.log(`Current instance type: ${defaultSKU}
@@ -860,6 +889,7 @@ async function getLogSettingsInteractive(logVisibility) {
860
889
  );
861
890
  }
862
891
  }
892
+ ensureInteractive("--log-visibility");
863
893
  const choice = await select({
864
894
  message: "Do you want to view your app's logs?",
865
895
  choices: [
@@ -891,6 +921,7 @@ async function getResourceUsageMonitoringInteractive(resourceUsageMonitoring) {
891
921
  );
892
922
  }
893
923
  }
924
+ ensureInteractive("--resource-usage-monitoring");
894
925
  const choice = await select({
895
926
  message: "Show resource usage (CPU/memory) for your app?",
896
927
  choices: [
@@ -904,6 +935,11 @@ async function confirm(prompt) {
904
935
  return confirmWithDefault(prompt, false);
905
936
  }
906
937
  async function confirmWithDefault(prompt, defaultValue = false) {
938
+ if (!process.stdin.isTTY) {
939
+ throw new Error(
940
+ `Cannot confirm "${prompt}" in non-interactive mode. Use --force to skip confirmation prompts.`
941
+ );
942
+ }
907
943
  return await inquirerConfirm({
908
944
  message: prompt,
909
945
  default: defaultValue
@@ -921,6 +957,7 @@ async function getPrivateKeyInteractive(privateKey) {
921
957
  if (result) {
922
958
  return result.key;
923
959
  }
960
+ ensureInteractive("--private-key or ECLOUD_PRIVATE_KEY");
924
961
  const key = await password({
925
962
  message: "Enter private key:",
926
963
  mask: true,
@@ -947,6 +984,7 @@ async function getEnvironmentInteractive(environment) {
947
984
  } catch {
948
985
  }
949
986
  }
987
+ ensureInteractive("--environment or ECLOUD_ENV");
950
988
  const availableEnvs = getAvailableEnvironments();
951
989
  let defaultEnv;
952
990
  const configDefaultEnv = getDefaultEnvironment();
@@ -1049,6 +1087,7 @@ function validateImagePath(filePath) {
1049
1087
  return void 0;
1050
1088
  }
1051
1089
  async function getAppProfileInteractive(defaultName = "", allowRetry = true) {
1090
+ ensureInteractive("--skip-profile or --website/--description/--x-url/--image");
1052
1091
  while (true) {
1053
1092
  const name = await getAppNameForProfile(defaultName);
1054
1093
  const website = await getAppWebsiteInteractive();
@@ -1686,6 +1725,10 @@ var AppDeploy = class _AppDeploy extends Command {
1686
1725
  description: "Optional path to Caddyfile inside the repo (relative to build context). If omitted, auto-detected from env file TLS settings",
1687
1726
  required: false,
1688
1727
  env: "ECLOUD_BUILD_CADDYFILE"
1728
+ }),
1729
+ force: Flags2.boolean({
1730
+ description: "Skip all confirmation prompts",
1731
+ default: false
1689
1732
  })
1690
1733
  };
1691
1734
  async run() {
@@ -1705,12 +1748,12 @@ var AppDeploy = class _AppDeploy extends Command {
1705
1748
  if (balance === 0n) {
1706
1749
  const isSepolia = environmentConfig.chainID === BigInt(11155111);
1707
1750
  this.log(
1708
- chalk2.yellow(`
1709
- Warning: Wallet ${chalk2.bold(address)} has zero balance on ${environment}.`)
1710
- );
1711
- this.log(
1712
- chalk2.yellow(`You will need ETH to pay for deployment gas fees.`)
1751
+ chalk2.yellow(
1752
+ `
1753
+ Warning: Wallet ${chalk2.bold(address)} has zero balance on ${environment}.`
1754
+ )
1713
1755
  );
1756
+ this.log(chalk2.yellow(`You will need ETH to pay for deployment gas fees.`));
1714
1757
  if (isSepolia) {
1715
1758
  this.log(
1716
1759
  chalk2.yellow(
@@ -1909,15 +1952,19 @@ Warning: Wallet ${chalk2.bold(address)} has zero balance on ${environment}.`)
1909
1952
  });
1910
1953
  const finalTx = await applyTxOverrides(gasEstimate, flags, { publicClient, address });
1911
1954
  if (flags["max-fee-per-gas"] || flags["max-priority-fee"]) {
1912
- this.log(chalk2.yellow(`
1913
- Gas override active \u2014 max fee: ${flags["max-fee-per-gas"] || "estimated"} gwei, priority fee: ${flags["max-priority-fee"] || "estimated"} gwei`));
1955
+ this.log(
1956
+ chalk2.yellow(
1957
+ `
1958
+ Gas override active \u2014 max fee: ${flags["max-fee-per-gas"] || "estimated"} gwei, priority fee: ${flags["max-priority-fee"] || "estimated"} gwei`
1959
+ )
1960
+ );
1914
1961
  }
1915
1962
  if (finalTx.nonce != null) {
1916
1963
  this.log(chalk2.yellow(`Nonce override active \u2014 nonce: ${finalTx.nonce}`));
1917
1964
  }
1918
1965
  this.log(`
1919
1966
  Estimated transaction cost: ${chalk2.cyan(finalTx.maxCostEth)} ETH`);
1920
- if (isMainnet(environmentConfig)) {
1967
+ if (isMainnet(environmentConfig) && !flags.force) {
1921
1968
  const confirmed = await confirm(`Continue with deployment?`);
1922
1969
  if (!confirmed) {
1923
1970
  this.log(`
@@ -1982,6 +2029,15 @@ ${chalk2.gray(`Deployment cancelled`)}`);
1982
2029
  const dashboardUrl = getDashboardUrl(environment, res.appId);
1983
2030
  this.log(`
1984
2031
  ${chalk2.gray("View your app:")} ${chalk2.blue.underline(dashboardUrl)}`);
2032
+ if (ipAddress) {
2033
+ this.log(
2034
+ chalk2.gray(
2035
+ `
2036
+ Note: "Running" means the container started \u2014 verify it is serving traffic with:`
2037
+ )
2038
+ );
2039
+ this.log(chalk2.gray(` curl -s -o /dev/null -w "%{http_code}" http://${ipAddress}/`));
2040
+ }
1985
2041
  });
1986
2042
  }
1987
2043
  };
@@ -1992,12 +2048,9 @@ async function fetchAvailableInstanceTypes(environment, environmentConfig, priva
1992
2048
  rpcUrl,
1993
2049
  environment
1994
2050
  });
1995
- const userApiClient = new UserApiClient3(
1996
- environmentConfig,
1997
- walletClient,
1998
- publicClient,
1999
- { clientId: getClientId() }
2000
- );
2051
+ const userApiClient = new UserApiClient3(environmentConfig, walletClient, publicClient, {
2052
+ clientId: getClientId()
2053
+ });
2001
2054
  const skuList = await userApiClient.getSKUs();
2002
2055
  if (skuList.skus.length === 0) {
2003
2056
  throw new Error("No instance types available from server");