@ascendkit/cli 0.3.1 → 0.3.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 (2) hide show
  1. package/dist/cli.js +142 -20
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -338,6 +338,65 @@ function printSurveySummary(data) {
338
338
  if (questions != null)
339
339
  console.log(`Questions: ${questions}`);
340
340
  }
341
+ function printEnvironmentSummary(data) {
342
+ console.log(`${data.name} (${data.id})`);
343
+ console.log(`Tier: ${data.tier}`);
344
+ if (data.description)
345
+ console.log(`Description: ${data.description}`);
346
+ console.log(`Public key: ${data.publicKey}`);
347
+ if (data.secretKey) {
348
+ const masked = data.secretKey.slice(0, 10) + "****";
349
+ console.log(`Secret key: ${masked}`);
350
+ }
351
+ const vars = data.variables && typeof data.variables === "object" ? Object.entries(data.variables) : [];
352
+ if (vars.length > 0) {
353
+ console.log(`Variables:`);
354
+ for (const [k, v] of vars)
355
+ console.log(` ${k}=${v}`);
356
+ }
357
+ }
358
+ function printPromotionSummary(result) {
359
+ const src = result.source ?? {};
360
+ const tgt = result.target ?? {};
361
+ console.log(`Promoted ${src.tier} → ${tgt.tier} (${tgt.envId})`);
362
+ console.log("");
363
+ const changes = result.changes ?? {};
364
+ const rows = [];
365
+ for (const [key, val] of Object.entries(changes)) {
366
+ const label = key.padEnd(14);
367
+ if (val.action === "unchanged") {
368
+ rows.push([label, "unchanged"]);
369
+ }
370
+ else if (val.action === "skip") {
371
+ rows.push([label, `skipped — ${val.reason}`]);
372
+ }
373
+ else if (val.action === "update" || val.action === "add_only") {
374
+ const fields = Array.isArray(val.fields) && val.fields.length ? ` (${val.fields.join(", ")})` : "";
375
+ rows.push([label, `updated${fields}`]);
376
+ }
377
+ else if (val.items) {
378
+ const counts = Object.entries(val.counts ?? {}).map(([k, v]) => `${v} ${k}`).join(", ");
379
+ rows.push([label, counts || "unchanged"]);
380
+ }
381
+ else {
382
+ rows.push([label, val.action ?? "—"]);
383
+ }
384
+ }
385
+ for (const [label, status] of rows) {
386
+ console.log(` ${label} ${status}`);
387
+ }
388
+ // Only show warnings not already conveyed by a skipped row in the table
389
+ const skippedKeys = new Set(Object.entries(changes)
390
+ .filter(([, v]) => v.action === "skip")
391
+ .map(([k]) => k.toUpperCase()));
392
+ const warnings = (Array.isArray(result.warnings) ? result.warnings : [])
393
+ .filter((w) => !skippedKeys.size || !Array.from(skippedKeys).some(k => w.code?.toUpperCase().includes(k)));
394
+ if (warnings.length > 0) {
395
+ console.log("");
396
+ for (const w of warnings)
397
+ console.log(`⚠ ${w.message}`);
398
+ }
399
+ }
341
400
  function printProjectSummary(data) {
342
401
  console.log(`Project: ${data.id}`);
343
402
  console.log(`Name: ${data.name}`);
@@ -756,7 +815,7 @@ async function runEnvironment(action, rest) {
756
815
  }
757
816
  switch (action) {
758
817
  case "show":
759
- output(await platform.getEnvironment(ctx.projectId, ctx.environmentId));
818
+ printEnvironmentSummary(await platform.getEnvironment(ctx.projectId, ctx.environmentId));
760
819
  return;
761
820
  case "promote": {
762
821
  const envId = rest[0] && !rest[0].startsWith("--") ? rest[0] : ctx.environmentId;
@@ -767,8 +826,7 @@ async function runEnvironment(action, rest) {
767
826
  }
768
827
  try {
769
828
  const result = await platform.promoteEnvironment(envId, target);
770
- console.log("Promotion successful:");
771
- console.log(JSON.stringify(result, null, 2));
829
+ printPromotionSummary(result);
772
830
  }
773
831
  catch (err) {
774
832
  let message = err instanceof Error ? err.message : String(err);
@@ -1895,7 +1953,8 @@ async function runEmail(client, action, rest) {
1895
1953
  break;
1896
1954
  }
1897
1955
  case "remove-domain":
1898
- output(await email.removeDomain(client));
1956
+ await email.removeDomain(client);
1957
+ console.log("Domain removed.");
1899
1958
  break;
1900
1959
  case "list": {
1901
1960
  const result = await email.listIdentities(client);
@@ -1908,10 +1967,12 @@ async function runEmail(client, action, rest) {
1908
1967
  console.error("Usage: ascendkit email-identity add <email> [--display-name <name>]");
1909
1968
  return await exitCli(1);
1910
1969
  }
1911
- output(await email.createIdentity(client, {
1970
+ const added = await email.createIdentity(client, {
1912
1971
  email: identityEmail,
1913
1972
  displayName: flags["display-name"],
1914
- }));
1973
+ });
1974
+ printEmailIdentities(added.identities ?? []);
1975
+ console.log("Verification email sent.");
1915
1976
  break;
1916
1977
  }
1917
1978
  case "resend": {
@@ -1920,7 +1981,8 @@ async function runEmail(client, action, rest) {
1920
1981
  console.error("Usage: ascendkit email-identity resend <email>");
1921
1982
  return await exitCli(1);
1922
1983
  }
1923
- output(await email.resendIdentityVerification(client, identityEmail));
1984
+ await email.resendIdentityVerification(client, identityEmail);
1985
+ console.log(`Verification email sent to ${identityEmail}.`);
1924
1986
  break;
1925
1987
  }
1926
1988
  case "set-default": {
@@ -1929,10 +1991,11 @@ async function runEmail(client, action, rest) {
1929
1991
  console.error("Usage: ascendkit email-identity set-default <email> [--display-name <name>]");
1930
1992
  return await exitCli(1);
1931
1993
  }
1932
- output(await email.setDefaultIdentity(client, {
1994
+ const updated = await email.setDefaultIdentity(client, {
1933
1995
  email: identityEmail,
1934
1996
  displayName: flags["display-name"],
1935
- }));
1997
+ });
1998
+ printEmailIdentities(updated.identities ?? []);
1936
1999
  break;
1937
2000
  }
1938
2001
  case "remove":
@@ -1942,7 +2005,9 @@ async function runEmail(client, action, rest) {
1942
2005
  console.error("Usage: ascendkit email-identity remove <email>");
1943
2006
  return await exitCli(1);
1944
2007
  }
1945
- output(await email.removeIdentity(client, identityEmail));
2008
+ const remaining = await email.removeIdentity(client, identityEmail);
2009
+ console.log("Identity removed.");
2010
+ printEmailIdentities(remaining.identities ?? []);
1946
2011
  break;
1947
2012
  }
1948
2013
  case "test": {
@@ -1951,10 +2016,11 @@ async function runEmail(client, action, rest) {
1951
2016
  console.error("Usage: ascendkit email-identity test <email> --to <recipient>");
1952
2017
  return await exitCli(1);
1953
2018
  }
1954
- output(await email.sendTestEmail(client, {
2019
+ const testResult = await email.sendTestEmail(client, {
1955
2020
  to: flags.to,
1956
2021
  fromIdentityEmail: identityEmail,
1957
- }));
2022
+ });
2023
+ console.log(testResult.message ?? "Test email sent.");
1958
2024
  break;
1959
2025
  }
1960
2026
  default:
@@ -1967,12 +2033,12 @@ run().catch((err) => {
1967
2033
  exitCli(1, err instanceof Error ? err : new Error(String(err)));
1968
2034
  });
1969
2035
  async function printEmailSetup(settings) {
1970
- output(settings);
1971
2036
  if (!settings.domain)
1972
2037
  return;
1973
2038
  const provider = settings.dnsProvider;
2039
+ console.log(`Domain: ${settings.domain}`);
1974
2040
  if (provider?.name) {
1975
- console.log(`\nDetected DNS provider: ${provider.name} (${provider.confidence ?? "unknown"})`);
2041
+ console.log(`DNS provider: ${provider.name} (${provider.confidence ?? "unknown"})`);
1976
2042
  }
1977
2043
  if (provider?.portalUrl) {
1978
2044
  console.log(`Provider console: ${provider.portalUrl}`);
@@ -1980,10 +2046,54 @@ async function printEmailSetup(settings) {
1980
2046
  if (provider?.assistantSetupUrl) {
1981
2047
  console.log(`Guided setup: ${provider.assistantSetupUrl}`);
1982
2048
  }
1983
- if (Array.isArray(settings.dnsRecords) && settings.dnsRecords.length > 0) {
1984
- console.log("\nAdd these DNS records:");
1985
- for (const rec of settings.dnsRecords) {
1986
- console.log(` ${rec.type}\t${rec.name}\t${rec.value}`);
2049
+ const records = Array.isArray(settings.dnsRecords) ? settings.dnsRecords : [];
2050
+ if (records.length > 0) {
2051
+ console.log("\nDNS records to add:");
2052
+ for (const rec of records) {
2053
+ console.log(` ${rec.type.padEnd(6)} ${rec.name} ${rec.value}`);
2054
+ }
2055
+ if (process.stdin.isTTY && process.stdout.isTTY) {
2056
+ const defaultFile = `dns-records-${settings.domain}.txt`;
2057
+ const { createInterface } = await import("node:readline/promises");
2058
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
2059
+ try {
2060
+ const answer = (await rl.question(`\nSave records to file [${defaultFile}]: `)).trim();
2061
+ const filename = answer || defaultFile;
2062
+ const { existsSync, writeFileSync } = await import("node:fs");
2063
+ if (existsSync(filename)) {
2064
+ const overwrite = (await rl.question(`${filename} already exists. Overwrite? [y/N] `)).trim().toLowerCase();
2065
+ if (overwrite !== "y" && overwrite !== "yes") {
2066
+ console.log("Skipped.");
2067
+ return;
2068
+ }
2069
+ }
2070
+ const lines = [
2071
+ `; DNS records for ${settings.domain}`,
2072
+ `; Generated by AscendKit CLI`,
2073
+ "",
2074
+ ...records.map(rec => {
2075
+ let value;
2076
+ if (rec.type === "TXT") {
2077
+ value = `"${rec.value}"`;
2078
+ }
2079
+ else if (rec.type === "CNAME" || rec.type === "MX") {
2080
+ // Ensure absolute FQDN with trailing dot to prevent zone-relative expansion
2081
+ const target = rec.type === "MX" ? rec.value.replace(/^(\d+)\s+/, "$1 ") : rec.value;
2082
+ value = target.endsWith(".") ? target : `${target}.`;
2083
+ }
2084
+ else {
2085
+ value = rec.value;
2086
+ }
2087
+ const name = rec.name.endsWith(".") ? rec.name : `${rec.name}.`;
2088
+ return `${name}\t3600\tIN\t${rec.type}\t${value} ; cf_tags=cf-proxied:false`;
2089
+ }),
2090
+ ];
2091
+ writeFileSync(filename, lines.join("\n") + "\n");
2092
+ console.log(`Saved to ${filename}`);
2093
+ }
2094
+ finally {
2095
+ rl.close();
2096
+ }
1987
2097
  }
1988
2098
  }
1989
2099
  }
@@ -2015,8 +2125,20 @@ function printEmailStatusSummary(settings, domainStatus, dnsCheck, identities) {
2015
2125
  return;
2016
2126
  }
2017
2127
  console.log(`Domain: ${settings.domain} (${domainStatus.status || settings.verificationStatus || "unknown"})`);
2018
- if (dnsCheck?.summary) {
2019
- console.log(`DNS: ${dnsCheck.summary.found}/${dnsCheck.summary.total} verified`);
2128
+ if (dnsCheck) {
2129
+ const { summary, records } = dnsCheck;
2130
+ if (summary.notFound === 0 && summary.mismatch === 0 && summary.errored === 0) {
2131
+ console.log("DNS: all records verified");
2132
+ }
2133
+ else {
2134
+ console.log(`DNS: ${summary.found}/${summary.total} verified`);
2135
+ const pending = records.filter(r => !r.found || r.mismatch);
2136
+ if (pending.length > 0) {
2137
+ console.log("Pending:");
2138
+ for (const r of pending)
2139
+ console.log(` ${r.type.padEnd(6)} ${r.name}`);
2140
+ }
2141
+ }
2020
2142
  }
2021
2143
  console.log("");
2022
2144
  printEmailIdentities(identities);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ascendkit/cli",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "AscendKit CLI and MCP server",
5
5
  "author": "ascendkit.dev",
6
6
  "license": "MIT",