@layr-labs/ecloud-cli 0.4.3 → 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
@@ -131,6 +131,18 @@ function setProfileCache(environment, profiles) {
131
131
  };
132
132
  saveGlobalConfig(config);
133
133
  }
134
+ function invalidateProfileCache(environment) {
135
+ const config = loadGlobalConfig();
136
+ if (!config.profile_cache) {
137
+ return;
138
+ }
139
+ if (environment) {
140
+ delete config.profile_cache[environment];
141
+ } else {
142
+ config.profile_cache = {};
143
+ }
144
+ saveGlobalConfig(config);
145
+ }
134
146
  function getOrCreateUserUUID() {
135
147
  const config = loadGlobalConfig();
136
148
  if (config.user_uuid) {
@@ -312,7 +324,7 @@ function listApps(environment) {
312
324
 
313
325
  // src/utils/version.ts
314
326
  function getCliVersion() {
315
- return true ? "0.4.3" : "0.0.0";
327
+ return true ? "0.5.0-dev.2" : "0.0.0";
316
328
  }
317
329
  function getClientId() {
318
330
  return `ecloud-cli/v${getCliVersion()}`;
@@ -342,6 +354,13 @@ function addHexPrefix2(value) {
342
354
  }
343
355
  return `0x${value}`;
344
356
  }
357
+ function ensureInteractive(missingFlagHint) {
358
+ if (!process.stdin.isTTY) {
359
+ throw new Error(
360
+ `Cannot prompt in non-interactive mode. Provide ${missingFlagHint} via CLI flags or environment variables.`
361
+ );
362
+ }
363
+ }
345
364
  async function getDockerfileInteractive(dockerfilePath) {
346
365
  if (dockerfilePath) {
347
366
  return dockerfilePath;
@@ -351,6 +370,7 @@ async function getDockerfileInteractive(dockerfilePath) {
351
370
  if (!fs3.existsSync(dockerfilePath_resolved)) {
352
371
  return "";
353
372
  }
373
+ ensureInteractive("--dockerfile or --image-ref");
354
374
  console.log(`
355
375
  Found Dockerfile in ${cwd}`);
356
376
  const choice = await select({
@@ -397,6 +417,7 @@ async function promptUseVerifiableBuild() {
397
417
  return confirmWithDefault("Build from verifiable source?", false);
398
418
  }
399
419
  async function promptVerifiableSourceType() {
420
+ ensureInteractive("--verifiable with --repo/--commit or --image-ref");
400
421
  return select({
401
422
  message: "Choose verifiable source type:",
402
423
  choices: [
@@ -406,6 +427,7 @@ async function promptVerifiableSourceType() {
406
427
  });
407
428
  }
408
429
  async function promptVerifiableGitSourceInputs() {
430
+ ensureInteractive("--repo, --commit");
409
431
  const detected = detectGitRepoInfo();
410
432
  const repoUrl = (await input({
411
433
  message: "Enter public git repository URL:",
@@ -487,6 +509,7 @@ async function promptVerifiableGitSourceInputs() {
487
509
  };
488
510
  }
489
511
  async function promptVerifiablePrebuiltImageRef() {
512
+ ensureInteractive("--image-ref");
490
513
  const ref = await input({
491
514
  message: "Enter prebuilt verifiable image ref:",
492
515
  default: "docker.io/eigenlayer/eigencloud-containers:",
@@ -577,6 +600,7 @@ async function getAvailableRegistries() {
577
600
  const auths = config.auths || {};
578
601
  const credsStore = config.credsStore;
579
602
  const gcrProjects = /* @__PURE__ */ new Map();
603
+ const dockerhubUsers = /* @__PURE__ */ new Map();
580
604
  const registries = [];
581
605
  for (const [registry, auth] of Object.entries(auths)) {
582
606
  const authData = auth;
@@ -617,8 +641,17 @@ async function getAvailableRegistries() {
617
641
  }
618
642
  continue;
619
643
  }
644
+ if (registryType === "dockerhub") {
645
+ if (!dockerhubUsers.has(username)) {
646
+ dockerhubUsers.set(username, info);
647
+ }
648
+ continue;
649
+ }
620
650
  registries.push(info);
621
651
  }
652
+ for (const dhInfo of Array.from(dockerhubUsers.values())) {
653
+ registries.push(dhInfo);
654
+ }
622
655
  for (const gcrInfo of Array.from(gcrProjects.values())) {
623
656
  registries.push(gcrInfo);
624
657
  }
@@ -724,6 +757,7 @@ async function getImageReferenceInteractive(imageRef, buildFromDockerfile = fals
724
757
  if (imageRef) {
725
758
  return imageRef;
726
759
  }
760
+ ensureInteractive("--image-ref");
727
761
  const registries = await getAvailableRegistries();
728
762
  const appName = getDefaultAppName();
729
763
  if (buildFromDockerfile) {
@@ -759,6 +793,7 @@ async function getEnvFileInteractive(envFilePath) {
759
793
  if (fs3.existsSync(".env")) {
760
794
  return ".env";
761
795
  }
796
+ ensureInteractive("--env-file");
762
797
  console.log("\nEnvironment file not found.");
763
798
  console.log("Environment files contain variables like RPC_URL, etc.");
764
799
  const choice = await select({
@@ -810,14 +845,19 @@ async function getInstanceTypeInteractive(instanceType, defaultSKU, availableTyp
810
845
  const validSKUs = availableTypes.map((t) => t.sku).join(", ");
811
846
  throw new Error(`Invalid instance-type: ${instanceType} (must be one of: ${validSKUs})`);
812
847
  }
848
+ ensureInteractive("--instance-type");
813
849
  const isCurrentType = defaultSKU !== "";
814
850
  const hasPricing = availableTypes.some((t) => t.monthly_price_usd != null);
815
851
  if (hasPricing) {
816
852
  console.log("\nPay for what you use \u2014 no upfront costs, per-hour billing.\n");
817
853
  console.log(` ${chalk.bold("Shielded VM (vTPM)")}: Verified boot and runtime attestation.`);
818
- console.log(` ${chalk.bold("SEV-SNP (TEE)")}: Verified boot, runtime attestation, and hardware-encrypted memory (AMD).`);
819
- console.log(` ${chalk.bold("TDX (TEE)")}: Verified boot, runtime attestation, and hardware-encrypted memory (Intel).
820
- `);
854
+ console.log(
855
+ ` ${chalk.bold("SEV-SNP (TEE)")}: Verified boot, runtime attestation, and hardware-encrypted memory (AMD).`
856
+ );
857
+ console.log(
858
+ ` ${chalk.bold("TDX (TEE)")}: Verified boot, runtime attestation, and hardware-encrypted memory (Intel).
859
+ `
860
+ );
821
861
  }
822
862
  if (isCurrentType && defaultSKU) {
823
863
  console.log(`Current instance type: ${defaultSKU}
@@ -851,6 +891,7 @@ async function getLogSettingsInteractive(logVisibility) {
851
891
  );
852
892
  }
853
893
  }
894
+ ensureInteractive("--log-visibility");
854
895
  const choice = await select({
855
896
  message: "Do you want to view your app's logs?",
856
897
  choices: [
@@ -944,9 +985,10 @@ async function getOrPromptAppID(appIDOrOptions, environment) {
944
985
  return addHexPrefix2(foundAppID);
945
986
  }
946
987
  throw new Error(
947
- `App name '${options.appID}' not found in environment '${options.environment}'`
988
+ `App name '${options.appID}' not found in environment '${options.environment}'. Name lookup uses a local cache that may be stale. Try using the app ID (0x...) directly, or run 'ecloud compute app list' to refresh the cache.`
948
989
  );
949
990
  }
991
+ ensureInteractive("app-id argument");
950
992
  return getAppIDInteractive(options);
951
993
  }
952
994
  async function getAppIDInteractive(options) {
@@ -979,12 +1021,9 @@ Select an app to ${action}:
979
1021
  let cachedProfiles = getProfileCache(environment);
980
1022
  if (!cachedProfiles) {
981
1023
  try {
982
- const userApiClient = new UserApiClient2(
983
- environmentConfig,
984
- walletClient,
985
- publicClient,
986
- { clientId: getClientId() }
987
- );
1024
+ const userApiClient = new UserApiClient2(environmentConfig, walletClient, publicClient, {
1025
+ clientId: getClientId()
1026
+ });
988
1027
  const appInfos = await getAppInfosChunked(userApiClient, apps);
989
1028
  const freshProfiles = {};
990
1029
  for (const info of appInfos) {
@@ -1184,6 +1223,7 @@ async function getResourceUsageMonitoringInteractive(resourceUsageMonitoring) {
1184
1223
  );
1185
1224
  }
1186
1225
  }
1226
+ ensureInteractive("--resource-usage-monitoring");
1187
1227
  const choice = await select({
1188
1228
  message: "Show resource usage (CPU/memory) for your app?",
1189
1229
  choices: [
@@ -1197,6 +1237,11 @@ async function confirm(prompt) {
1197
1237
  return confirmWithDefault(prompt, false);
1198
1238
  }
1199
1239
  async function confirmWithDefault(prompt, defaultValue = false) {
1240
+ if (!process.stdin.isTTY) {
1241
+ throw new Error(
1242
+ `Cannot confirm "${prompt}" in non-interactive mode. Use --force to skip confirmation prompts.`
1243
+ );
1244
+ }
1200
1245
  return await inquirerConfirm({
1201
1246
  message: prompt,
1202
1247
  default: defaultValue
@@ -1214,6 +1259,7 @@ async function getPrivateKeyInteractive(privateKey) {
1214
1259
  if (result) {
1215
1260
  return result.key;
1216
1261
  }
1262
+ ensureInteractive("--private-key or ECLOUD_PRIVATE_KEY");
1217
1263
  const key = await password({
1218
1264
  message: "Enter private key:",
1219
1265
  mask: true,
@@ -1240,6 +1286,7 @@ async function getEnvironmentInteractive(environment) {
1240
1286
  } catch {
1241
1287
  }
1242
1288
  }
1289
+ ensureInteractive("--environment or ECLOUD_ENV");
1243
1290
  const availableEnvs = getAvailableEnvironments();
1244
1291
  let defaultEnv;
1245
1292
  const configDefaultEnv = getDefaultEnvironment();
@@ -1655,6 +1702,11 @@ var AppUpgrade = class _AppUpgrade extends Command {
1655
1702
  };
1656
1703
  static flags = {
1657
1704
  ...commonFlags,
1705
+ name: Flags2.string({
1706
+ required: false,
1707
+ description: "Update the app's profile name after upgrade",
1708
+ env: "ECLOUD_NAME"
1709
+ }),
1658
1710
  dockerfile: Flags2.string({
1659
1711
  required: false,
1660
1712
  description: "Path to Dockerfile",
@@ -1724,6 +1776,10 @@ var AppUpgrade = class _AppUpgrade extends Command {
1724
1776
  description: "Optional path to Caddyfile inside the repo (relative to build context). If omitted, auto-detected from env file TLS settings",
1725
1777
  required: false,
1726
1778
  env: "ECLOUD_BUILD_CADDYFILE"
1779
+ }),
1780
+ force: Flags2.boolean({
1781
+ description: "Skip all confirmation prompts",
1782
+ default: false
1727
1783
  })
1728
1784
  };
1729
1785
  async run() {
@@ -1870,12 +1926,9 @@ var AppUpgrade = class _AppUpgrade extends Command {
1870
1926
  });
1871
1927
  let currentInstanceType = "";
1872
1928
  try {
1873
- const userApiClient = new UserApiClient3(
1874
- environmentConfig,
1875
- walletClient,
1876
- publicClient,
1877
- { clientId: getClientId() }
1878
- );
1929
+ const userApiClient = new UserApiClient3(environmentConfig, walletClient, publicClient, {
1930
+ clientId: getClientId()
1931
+ });
1879
1932
  const infos = await userApiClient.getInfos([appID], 1);
1880
1933
  if (infos.length > 0) {
1881
1934
  currentInstanceType = infos[0].machineType || "";
@@ -1917,15 +1970,19 @@ var AppUpgrade = class _AppUpgrade extends Command {
1917
1970
  });
1918
1971
  const finalTx = await applyTxOverrides(gasEstimate, flags, { publicClient, address });
1919
1972
  if (flags["max-fee-per-gas"] || flags["max-priority-fee"]) {
1920
- this.log(chalk2.yellow(`
1921
- Gas override active \u2014 max fee: ${flags["max-fee-per-gas"] || "estimated"} gwei, priority fee: ${flags["max-priority-fee"] || "estimated"} gwei`));
1973
+ this.log(
1974
+ chalk2.yellow(
1975
+ `
1976
+ Gas override active \u2014 max fee: ${flags["max-fee-per-gas"] || "estimated"} gwei, priority fee: ${flags["max-priority-fee"] || "estimated"} gwei`
1977
+ )
1978
+ );
1922
1979
  }
1923
1980
  if (finalTx.nonce != null) {
1924
1981
  this.log(chalk2.yellow(`Nonce override active \u2014 nonce: ${finalTx.nonce}`));
1925
1982
  }
1926
1983
  this.log(`
1927
1984
  Estimated transaction cost: ${chalk2.cyan(finalTx.maxCostEth)} ETH`);
1928
- if (isMainnet(environmentConfig)) {
1985
+ if (isMainnet(environmentConfig) && !flags.force) {
1929
1986
  const confirmed = await confirm(`Continue with upgrade?`);
1930
1987
  if (!confirmed) {
1931
1988
  this.log(`
@@ -1945,9 +2002,39 @@ ${chalk2.gray(`Upgrade cancelled`)}`);
1945
2002
  `
1946
2003
  \u2705 ${chalk2.green(`App upgraded successfully ${chalk2.bold(`(id: ${res.appId}, image: ${res.imageRef})`)}`)}`
1947
2004
  );
2005
+ if (flags.name) {
2006
+ try {
2007
+ const { publicClient: publicClient2, walletClient: walletClient2 } = createViemClients({
2008
+ privateKey,
2009
+ rpcUrl,
2010
+ environment
2011
+ });
2012
+ const userApiClient = new UserApiClient3(environmentConfig, walletClient2, publicClient2, {
2013
+ clientId: getClientId()
2014
+ });
2015
+ const infos = await userApiClient.getInfos([res.appId], 1);
2016
+ const existing = infos[0]?.profile;
2017
+ await compute.app.setProfile(res.appId, {
2018
+ name: flags.name,
2019
+ website: existing?.website,
2020
+ description: existing?.description,
2021
+ xURL: existing?.xURL
2022
+ });
2023
+ invalidateProfileCache(environment);
2024
+ this.log(`\u2713 Profile name updated to "${flags.name}"`);
2025
+ } catch (err) {
2026
+ this.warn(`Upgrade succeeded but failed to update profile name: ${err.message}`);
2027
+ }
2028
+ }
1948
2029
  const dashboardUrl = getDashboardUrl(environment, res.appId);
1949
2030
  this.log(`
1950
2031
  ${chalk2.gray("View your app:")} ${chalk2.blue.underline(dashboardUrl)}`);
2032
+ this.log(
2033
+ chalk2.gray(
2034
+ `
2035
+ Note: "Running" means the container started. Verify your app is serving traffic before considering the upgrade complete.`
2036
+ )
2037
+ );
1951
2038
  });
1952
2039
  }
1953
2040
  };
@@ -1958,7 +2045,9 @@ async function fetchAvailableInstanceTypes(environment, environmentConfig, priva
1958
2045
  rpcUrl,
1959
2046
  environment
1960
2047
  });
1961
- const userApiClient = new UserApiClient3(environmentConfig, walletClient, publicClient, { clientId: getClientId() });
2048
+ const userApiClient = new UserApiClient3(environmentConfig, walletClient, publicClient, {
2049
+ clientId: getClientId()
2050
+ });
1962
2051
  const skuList = await userApiClient.getSKUs();
1963
2052
  if (skuList.skus.length === 0) {
1964
2053
  throw new Error("No instance types available from server");