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

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 (66) 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 +0 -1
  7. package/dist/commands/auth/whoami.js.map +1 -1
  8. package/dist/commands/billing/__tests__/status.test.js +11 -9
  9. package/dist/commands/billing/__tests__/status.test.js.map +1 -1
  10. package/dist/commands/billing/__tests__/subscribe.test.js +11 -9
  11. package/dist/commands/billing/__tests__/subscribe.test.js.map +1 -1
  12. package/dist/commands/billing/__tests__/top-up.test.js +11 -9
  13. package/dist/commands/billing/__tests__/top-up.test.js.map +1 -1
  14. package/dist/commands/billing/cancel.js +11 -9
  15. package/dist/commands/billing/cancel.js.map +1 -1
  16. package/dist/commands/billing/status.js +11 -9
  17. package/dist/commands/billing/status.js.map +1 -1
  18. package/dist/commands/billing/subscribe.js +11 -9
  19. package/dist/commands/billing/subscribe.js.map +1 -1
  20. package/dist/commands/billing/top-up.js +11 -9
  21. package/dist/commands/billing/top-up.js.map +1 -1
  22. package/dist/commands/compute/app/configure/tls.js +138 -50
  23. package/dist/commands/compute/app/configure/tls.js.map +1 -1
  24. package/dist/commands/compute/app/create.js +0 -1
  25. package/dist/commands/compute/app/create.js.map +1 -1
  26. package/dist/commands/compute/app/deploy.js +76 -29
  27. package/dist/commands/compute/app/deploy.js.map +1 -1
  28. package/dist/commands/compute/app/info.js +17 -17
  29. package/dist/commands/compute/app/info.js.map +1 -1
  30. package/dist/commands/compute/app/list.js +12 -10
  31. package/dist/commands/compute/app/list.js.map +1 -1
  32. package/dist/commands/compute/app/logs.js +17 -17
  33. package/dist/commands/compute/app/logs.js.map +1 -1
  34. package/dist/commands/compute/app/profile/set.js +18 -17
  35. package/dist/commands/compute/app/profile/set.js.map +1 -1
  36. package/dist/commands/compute/app/releases.js +17 -17
  37. package/dist/commands/compute/app/releases.js.map +1 -1
  38. package/dist/commands/compute/app/start.js +29 -20
  39. package/dist/commands/compute/app/start.js.map +1 -1
  40. package/dist/commands/compute/app/stop.js +29 -20
  41. package/dist/commands/compute/app/stop.js.map +1 -1
  42. package/dist/commands/compute/app/terminate.js +22 -17
  43. package/dist/commands/compute/app/terminate.js.map +1 -1
  44. package/dist/commands/compute/app/upgrade.js +115 -32
  45. package/dist/commands/compute/app/upgrade.js.map +1 -1
  46. package/dist/commands/compute/build/info.js +12 -10
  47. package/dist/commands/compute/build/info.js.map +1 -1
  48. package/dist/commands/compute/build/list.js +12 -10
  49. package/dist/commands/compute/build/list.js.map +1 -1
  50. package/dist/commands/compute/build/logs.js +12 -10
  51. package/dist/commands/compute/build/logs.js.map +1 -1
  52. package/dist/commands/compute/build/status.js +12 -10
  53. package/dist/commands/compute/build/status.js.map +1 -1
  54. package/dist/commands/compute/build/submit.js +13 -10
  55. package/dist/commands/compute/build/submit.js.map +1 -1
  56. package/dist/commands/compute/build/verify.js +12 -10
  57. package/dist/commands/compute/build/verify.js.map +1 -1
  58. package/dist/commands/compute/environment/set.js +12 -11
  59. package/dist/commands/compute/environment/set.js.map +1 -1
  60. package/dist/commands/compute/undelegate.js +12 -10
  61. package/dist/commands/compute/undelegate.js.map +1 -1
  62. package/dist/hooks/init/__tests__/version-check.test.js +1 -1
  63. package/dist/hooks/init/__tests__/version-check.test.js.map +1 -1
  64. package/dist/hooks/init/version-check.js +1 -1
  65. package/dist/hooks/init/version-check.js.map +1 -1
  66. package/package.json +26 -21
@@ -190,7 +190,6 @@ import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
190
190
  import {
191
191
  getEnvironmentConfig as getEnvironmentConfig2,
192
192
  getAvailableEnvironments,
193
- isEnvironmentAvailable,
194
193
  getAllAppsByDeveloper as getAllAppsByDeveloper2,
195
194
  getCategoryDescriptions,
196
195
  fetchTemplateCatalog,
@@ -305,7 +304,7 @@ function findAvailableName(environment, baseName) {
305
304
 
306
305
  // src/utils/version.ts
307
306
  function getCliVersion() {
308
- return true ? "0.4.3" : "0.0.0";
307
+ return true ? "0.5.0-dev.3" : "0.0.0";
309
308
  }
310
309
  function getClientId() {
311
310
  return `ecloud-cli/v${getCliVersion()}`;
@@ -313,6 +312,13 @@ function getClientId() {
313
312
 
314
313
  // src/utils/prompts.ts
315
314
  import { execSync } from "child_process";
315
+ function ensureInteractive(missingFlagHint) {
316
+ if (!process.stdin.isTTY) {
317
+ throw new Error(
318
+ `Cannot prompt in non-interactive mode. Provide ${missingFlagHint} via CLI flags or environment variables.`
319
+ );
320
+ }
321
+ }
316
322
  async function getDockerfileInteractive(dockerfilePath) {
317
323
  if (dockerfilePath) {
318
324
  return dockerfilePath;
@@ -322,6 +328,7 @@ async function getDockerfileInteractive(dockerfilePath) {
322
328
  if (!fs3.existsSync(dockerfilePath_resolved)) {
323
329
  return "";
324
330
  }
331
+ ensureInteractive("--dockerfile or --image-ref");
325
332
  console.log(`
326
333
  Found Dockerfile in ${cwd}`);
327
334
  const choice = await select({
@@ -364,10 +371,12 @@ function detectGitRepoInfo() {
364
371
  return {};
365
372
  }
366
373
  }
367
- async function promptUseVerifiableBuild() {
374
+ async function promptUseVerifiableBuild(force = false) {
375
+ if (force) return false;
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,
@@ -938,15 +975,10 @@ async function getPrivateKeyInteractive(privateKey) {
938
975
  }
939
976
  async function getEnvironmentInteractive(environment) {
940
977
  if (environment) {
941
- try {
942
- getEnvironmentConfig2(environment);
943
- if (!isEnvironmentAvailable(environment)) {
944
- throw new Error(`Environment ${environment} is not available in this build`);
945
- }
946
- return environment;
947
- } catch {
948
- }
978
+ getEnvironmentConfig2(environment);
979
+ return environment;
949
980
  }
981
+ ensureInteractive("--environment or ECLOUD_ENV");
950
982
  const availableEnvs = getAvailableEnvironments();
951
983
  let defaultEnv;
952
984
  const configDefaultEnv = getDefaultEnvironment();
@@ -1049,6 +1081,7 @@ function validateImagePath(filePath) {
1049
1081
  return void 0;
1050
1082
  }
1051
1083
  async function getAppProfileInteractive(defaultName = "", allowRetry = true) {
1084
+ ensureInteractive("--skip-profile or --website/--description/--x-url/--image");
1052
1085
  while (true) {
1053
1086
  const name = await getAppNameForProfile(defaultName);
1054
1087
  const website = await getAppWebsiteInteractive();
@@ -1686,6 +1719,10 @@ var AppDeploy = class _AppDeploy extends Command {
1686
1719
  description: "Optional path to Caddyfile inside the repo (relative to build context). If omitted, auto-detected from env file TLS settings",
1687
1720
  required: false,
1688
1721
  env: "ECLOUD_BUILD_CADDYFILE"
1722
+ }),
1723
+ force: Flags2.boolean({
1724
+ description: "Skip all confirmation prompts",
1725
+ default: false
1689
1726
  })
1690
1727
  };
1691
1728
  async run() {
@@ -1705,12 +1742,12 @@ var AppDeploy = class _AppDeploy extends Command {
1705
1742
  if (balance === 0n) {
1706
1743
  const isSepolia = environmentConfig.chainID === BigInt(11155111);
1707
1744
  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.`)
1745
+ chalk2.yellow(
1746
+ `
1747
+ Warning: Wallet ${chalk2.bold(address)} has zero balance on ${environment}.`
1748
+ )
1713
1749
  );
1750
+ this.log(chalk2.yellow(`You will need ETH to pay for deployment gas fees.`));
1714
1751
  if (isSepolia) {
1715
1752
  this.log(
1716
1753
  chalk2.yellow(
@@ -1777,7 +1814,7 @@ Warning: Wallet ${chalk2.bold(address)} has zero balance on ${environment}.`)
1777
1814
  }
1778
1815
  } else {
1779
1816
  if (!flags.dockerfile) {
1780
- const useVerifiable = await promptUseVerifiableBuild();
1817
+ const useVerifiable = await promptUseVerifiableBuild(flags.force);
1781
1818
  if (useVerifiable) {
1782
1819
  const sourceType = await promptVerifiableSourceType();
1783
1820
  verifiableMode = sourceType;
@@ -1909,15 +1946,19 @@ Warning: Wallet ${chalk2.bold(address)} has zero balance on ${environment}.`)
1909
1946
  });
1910
1947
  const finalTx = await applyTxOverrides(gasEstimate, flags, { publicClient, address });
1911
1948
  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`));
1949
+ this.log(
1950
+ chalk2.yellow(
1951
+ `
1952
+ Gas override active \u2014 max fee: ${flags["max-fee-per-gas"] || "estimated"} gwei, priority fee: ${flags["max-priority-fee"] || "estimated"} gwei`
1953
+ )
1954
+ );
1914
1955
  }
1915
1956
  if (finalTx.nonce != null) {
1916
1957
  this.log(chalk2.yellow(`Nonce override active \u2014 nonce: ${finalTx.nonce}`));
1917
1958
  }
1918
1959
  this.log(`
1919
1960
  Estimated transaction cost: ${chalk2.cyan(finalTx.maxCostEth)} ETH`);
1920
- if (isMainnet(environmentConfig)) {
1961
+ if (isMainnet(environmentConfig) && !flags.force) {
1921
1962
  const confirmed = await confirm(`Continue with deployment?`);
1922
1963
  if (!confirmed) {
1923
1964
  this.log(`
@@ -1982,6 +2023,15 @@ ${chalk2.gray(`Deployment cancelled`)}`);
1982
2023
  const dashboardUrl = getDashboardUrl(environment, res.appId);
1983
2024
  this.log(`
1984
2025
  ${chalk2.gray("View your app:")} ${chalk2.blue.underline(dashboardUrl)}`);
2026
+ if (ipAddress) {
2027
+ this.log(
2028
+ chalk2.gray(
2029
+ `
2030
+ Note: "Running" means the container started \u2014 verify it is serving traffic with:`
2031
+ )
2032
+ );
2033
+ this.log(chalk2.gray(` curl -s -o /dev/null -w "%{http_code}" http://${ipAddress}/`));
2034
+ }
1985
2035
  });
1986
2036
  }
1987
2037
  };
@@ -1992,12 +2042,9 @@ async function fetchAvailableInstanceTypes(environment, environmentConfig, priva
1992
2042
  rpcUrl,
1993
2043
  environment
1994
2044
  });
1995
- const userApiClient = new UserApiClient3(
1996
- environmentConfig,
1997
- walletClient,
1998
- publicClient,
1999
- { clientId: getClientId() }
2000
- );
2045
+ const userApiClient = new UserApiClient3(environmentConfig, walletClient, publicClient, {
2046
+ clientId: getClientId()
2047
+ });
2001
2048
  const skuList = await userApiClient.getSKUs();
2002
2049
  if (skuList.skus.length === 0) {
2003
2050
  throw new Error("No instance types available from server");