polkadot-cli 1.15.1 → 1.17.0

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 (3) hide show
  1. package/README.md +544 -147
  2. package/dist/cli.mjs +944 -242
  3. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -16,7 +16,31 @@ var __export = (target, all) => {
16
16
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
17
 
18
18
  // src/utils/errors.ts
19
- var CliError, ConnectionError, MetadataError;
19
+ function isLikelyStaleMetadataError(err) {
20
+ const msg = err instanceof Error ? err.message : typeof err === "string" ? err : "";
21
+ if (!msg)
22
+ return false;
23
+ return STALE_METADATA_PATTERNS.some((re) => re.test(msg));
24
+ }
25
+ function formatRuntimeError(err) {
26
+ const msg = err instanceof Error ? err.message : String(err);
27
+ if (/wasm trap|wasm `?unreachable`? instruction|Execution aborted due to trap/i.test(msg)) {
28
+ const frames = Array.from(msg.matchAll(/\.wasm!([A-Za-z_]\w+)/g)).map((m) => m[1]);
29
+ const fn = [...frames].reverse().find((name) => !/^(?:__rustc|core::panicking|rust_begin_unwind|panic_fmt)/.test(name));
30
+ const where = fn?.includes("validate_transaction") ? "the runtime's validate_transaction step" : fn ? `runtime function ${fn}` : "the runtime";
31
+ return [
32
+ `The runtime rejected this transaction in ${where}.`,
33
+ " Cause: a runtime invariant failed — typically the call's arguments are out of range, reference an unknown id, or violate a precondition.",
34
+ " Tip: re-check the arguments and the signing account's permissions; --dry-run will surface the same error before signing."
35
+ ].join(`
36
+ `);
37
+ }
38
+ if (/Invalid Transaction/i.test(msg)) {
39
+ return `Transaction rejected as invalid by the runtime: ${msg}`;
40
+ }
41
+ return msg;
42
+ }
43
+ var CliError, ConnectionError, MetadataError, STALE_METADATA_PATTERNS;
20
44
  var init_errors = __esm(() => {
21
45
  CliError = class CliError extends Error {
22
46
  constructor(message) {
@@ -36,8 +60,28 @@ var init_errors = __esm(() => {
36
60
  this.name = "MetadataError";
37
61
  }
38
62
  };
63
+ STALE_METADATA_PATTERNS = [
64
+ /wasm trap/i,
65
+ /wasm `?unreachable`? instruction/i,
66
+ /Execution aborted due to trap/i,
67
+ /codec/i,
68
+ /decod(e|ing)/i,
69
+ /Lookup failed/i,
70
+ /metadata.*mismatch/i
71
+ ];
39
72
  });
40
73
 
74
+ // src/utils/runtime-fingerprint.ts
75
+ function fingerprintsMatch(a, b) {
76
+ return a.codeHash === b.codeHash && a.specVersion === b.specVersion && a.transactionVersion === b.transactionVersion;
77
+ }
78
+ function isRuntimeFingerprint(value) {
79
+ if (!value || typeof value !== "object")
80
+ return false;
81
+ const v = value;
82
+ return typeof v.specName === "string" && typeof v.specVersion === "number" && typeof v.transactionVersion === "number" && typeof v.implName === "string" && typeof v.implVersion === "number" && typeof v.authoringVersion === "number" && typeof v.codeHash === "string" && typeof v.fetchedAt === "string";
83
+ }
84
+
41
85
  // src/config/types.ts
42
86
  function primaryRpc(rpc) {
43
87
  return Array.isArray(rpc) ? rpc[0] : rpc;
@@ -193,6 +237,9 @@ function getChainDir(chainName) {
193
237
  function getMetadataPath(chainName) {
194
238
  return join(getChainDir(chainName), "metadata.bin");
195
239
  }
240
+ function getMetadataFingerprintPath(chainName) {
241
+ return join(getChainDir(chainName), "metadata.fingerprint.json");
242
+ }
196
243
  function getConfigPath() {
197
244
  return join(getConfigDir(), "config.json");
198
245
  }
@@ -238,10 +285,25 @@ async function loadMetadata(chainName) {
238
285
  }
239
286
  return null;
240
287
  }
241
- async function saveMetadata(chainName, data) {
288
+ async function saveMetadata(chainName, data, fingerprint) {
242
289
  const dir = getChainDir(chainName);
243
290
  await ensureDir(dir);
244
291
  await writeFile(getMetadataPath(chainName), data);
292
+ if (fingerprint) {
293
+ await writeFile(getMetadataFingerprintPath(chainName), `${JSON.stringify(fingerprint, null, 2)}
294
+ `);
295
+ }
296
+ }
297
+ async function loadMetadataFingerprint(chainName) {
298
+ const path = getMetadataFingerprintPath(chainName);
299
+ if (!await fileExists(path))
300
+ return null;
301
+ try {
302
+ const parsed = JSON.parse(await readFile(path, "utf-8"));
303
+ return isRuntimeFingerprint(parsed) ? parsed : null;
304
+ } catch {
305
+ return null;
306
+ }
245
307
  }
246
308
  async function removeChainData(chainName) {
247
309
  const dir = getChainDir(chainName);
@@ -612,6 +674,11 @@ function printResult(data, format = "pretty") {
612
674
  function isJsonOutput(opts) {
613
675
  return opts.json === true || opts.output === "json";
614
676
  }
677
+ function writeStdout(text) {
678
+ return new Promise((resolve) => {
679
+ process.stdout.write(text, () => resolve());
680
+ });
681
+ }
615
682
  function printJsonLine(data) {
616
683
  console.log(JSON.stringify(data, replacer));
617
684
  }
@@ -791,6 +858,324 @@ var init_client = __esm(() => {
791
858
  init_errors();
792
859
  });
793
860
 
861
+ // src/core/pretty-type.ts
862
+ function visualWidth(s) {
863
+ return s.replace(ANSI_RE, "").length;
864
+ }
865
+ function paint(color, code, text) {
866
+ return color ? `${code}${text}${RESET2}` : text;
867
+ }
868
+ function defaultWidth() {
869
+ return process.stdout.columns ?? 80;
870
+ }
871
+ function resolveOpts(opts) {
872
+ return {
873
+ indent: opts.indent ?? 0,
874
+ prefix: opts.prefix ?? 0,
875
+ width: opts.width ?? defaultWidth(),
876
+ color: opts.color ?? isTTY
877
+ };
878
+ }
879
+ function compactEntry(entry, color) {
880
+ if (!entry)
881
+ return "";
882
+ switch (entry.type) {
883
+ case "primitive":
884
+ return paint(color, YELLOW2, entry.value);
885
+ case "compact": {
886
+ const inner = entry.isBig ? "u128" : "u64";
887
+ return `${paint(color, MAGENTA2, "Compact")}<${paint(color, YELLOW2, inner)}>`;
888
+ }
889
+ case "AccountId32":
890
+ return paint(color, GREEN2, "AccountId32");
891
+ case "bitSequence":
892
+ return paint(color, MAGENTA2, "BitSequence");
893
+ case "sequence":
894
+ return `${paint(color, MAGENTA2, "Vec")}<${compactEntry(entry.value, color)}>`;
895
+ case "array":
896
+ return `[${compactEntry(entry.value, color)}; ${entry.len}]`;
897
+ case "tuple":
898
+ return `(${entry.value.map((v) => compactEntry(v, color)).join(", ")})`;
899
+ case "struct": {
900
+ const fields = Object.entries(entry.value);
901
+ if (fields.length === 0)
902
+ return "{}";
903
+ const inner = fields.map(([k, v]) => `${paint(color, CYAN2, k)}: ${compactEntry(v, color)}`).join(", ");
904
+ return `{ ${inner} }`;
905
+ }
906
+ case "option":
907
+ return `${paint(color, MAGENTA2, "Option")}<${compactEntry(entry.value, color)}>`;
908
+ case "result":
909
+ return `${paint(color, MAGENTA2, "Result")}<${compactEntry(entry.value.ok, color)}, ${compactEntry(entry.value.ko, color)}>`;
910
+ case "enum": {
911
+ const variants = Object.keys(entry.value);
912
+ if (variants.length > ENUM_COMPACT_LIMIT) {
913
+ return `enum(${variants.length} variants)`;
914
+ }
915
+ return variants.map((v) => paint(color, GREEN2, v)).join(" | ");
916
+ }
917
+ case "void":
918
+ return "()";
919
+ case "lookupEntry":
920
+ return compactEntry(entry.value, color);
921
+ default:
922
+ return "unknown";
923
+ }
924
+ }
925
+ function expandEntry(entry, indent, width, color, prefix = 0) {
926
+ const compact = compactEntry(entry, color);
927
+ if (visualWidth(compact) + indent + prefix <= width)
928
+ return compact;
929
+ switch (entry.type) {
930
+ case "struct":
931
+ return expandStruct(entry.value, indent, width, color);
932
+ case "tuple":
933
+ return expandTuple(entry.value, indent, width, color);
934
+ case "sequence":
935
+ return wrapMultiline("Vec", "<", ">", entry.value, indent, width, color);
936
+ case "array": {
937
+ const inner = expandEntry(entry.value, indent + 1, width, color);
938
+ return `[${inner}; ${entry.len}]`;
939
+ }
940
+ case "option":
941
+ return wrapMultiline("Option", "<", ">", entry.value, indent, width, color);
942
+ case "result": {
943
+ const innerIndent = indent + 2;
944
+ const padding = " ".repeat(innerIndent);
945
+ const closePadding = " ".repeat(indent);
946
+ const ok = expandEntry(entry.value.ok, innerIndent, width, color);
947
+ const ko = expandEntry(entry.value.ko, innerIndent, width, color);
948
+ return `${paint(color, MAGENTA2, "Result")}<
949
+ ${padding}${ok},
950
+ ${padding}${ko}
951
+ ${closePadding}>`;
952
+ }
953
+ case "enum": {
954
+ const variants = Object.keys(entry.value);
955
+ if (variants.length > ENUM_COMPACT_LIMIT)
956
+ return `enum(${variants.length} variants)`;
957
+ return expandEnum(variants, indent, color);
958
+ }
959
+ case "lookupEntry":
960
+ return expandEntry(entry.value, indent, width, color);
961
+ default:
962
+ return compact;
963
+ }
964
+ }
965
+ function expandStruct(fields, indent, width, color) {
966
+ const entries = Object.entries(fields);
967
+ if (entries.length === 0)
968
+ return "{}";
969
+ return renderFieldList(entries, "{", "}", indent, width, color);
970
+ }
971
+ function expandTuple(items, indent, width, color) {
972
+ if (items.length === 0)
973
+ return "()";
974
+ const inner = " ".repeat(indent + 2);
975
+ const close = " ".repeat(indent);
976
+ const lines = items.map((v) => `${inner}${expandEntry(v, indent + 2, width, color)}`);
977
+ return `(
978
+ ${lines.join(`,
979
+ `)},
980
+ ${close})`;
981
+ }
982
+ function wrapMultiline(name, open, close, inner, indent, width, color) {
983
+ const innerIndent = indent + 2;
984
+ const padding = " ".repeat(innerIndent);
985
+ const closePadding = " ".repeat(indent);
986
+ const innerStr = expandEntry(inner, innerIndent, width, color);
987
+ return `${paint(color, MAGENTA2, name)}${open}
988
+ ${padding}${innerStr}
989
+ ${closePadding}${close}`;
990
+ }
991
+ function expandEnum(variants, indent, color) {
992
+ const prefix = `
993
+ ${" ".repeat(indent)}| `;
994
+ const [first, ...rest] = variants;
995
+ const head = paint(color, GREEN2, first ?? "");
996
+ if (rest.length === 0)
997
+ return head;
998
+ const tail = rest.map((v) => paint(color, GREEN2, v)).join(prefix);
999
+ return `${head}${prefix}${tail}`;
1000
+ }
1001
+ function renderFieldList(fields, open, close, indent, width, color) {
1002
+ const innerIndent = indent + 2;
1003
+ const maxNameLen = Math.max(...fields.map(([k]) => k.length));
1004
+ const align = maxNameLen <= ALIGN_PADDING_LIMIT;
1005
+ const padTo = align ? maxNameLen : 0;
1006
+ const padding = " ".repeat(innerIndent);
1007
+ const closePadding = " ".repeat(indent);
1008
+ const lines = fields.map(([k, v]) => {
1009
+ const paddedName = align ? k.padEnd(padTo) : k;
1010
+ const fieldPrefix = (align ? padTo : k.length) + 2;
1011
+ const value = expandEntry(v, innerIndent, width, color, fieldPrefix);
1012
+ return `${padding}${paint(color, CYAN2, paddedName)}: ${value}`;
1013
+ });
1014
+ return `${open}
1015
+ ${lines.join(`,
1016
+ `)},
1017
+ ${closePadding}${close}`;
1018
+ }
1019
+ function prettyType(entry, opts = {}) {
1020
+ const { indent, prefix, width, color } = resolveOpts(opts);
1021
+ const compact = compactEntry(entry, color);
1022
+ if (visualWidth(compact) + indent + prefix <= width)
1023
+ return compact;
1024
+ return expandEntry(entry, indent, width, color);
1025
+ }
1026
+ function prettyTypeById(lookup, typeId, opts = {}) {
1027
+ try {
1028
+ const entry = lookup(typeId);
1029
+ if (!entry || typeof entry.type !== "string")
1030
+ return `type(${typeId})`;
1031
+ return prettyType(entry, opts);
1032
+ } catch {
1033
+ return `type(${typeId})`;
1034
+ }
1035
+ }
1036
+ function prettyCallArgs(meta, palletName, callName, opts = {}) {
1037
+ const fields = getCallFields(meta, palletName, callName);
1038
+ if (fields === null)
1039
+ return "";
1040
+ return renderArgsFromFields(fields, opts);
1041
+ }
1042
+ function prettyEventFields(meta, palletName, eventName, opts = {}) {
1043
+ const fields = getEventFields(meta, palletName, eventName);
1044
+ if (fields === null)
1045
+ return "";
1046
+ return renderArgsFromFields(fields, opts);
1047
+ }
1048
+ function prettyRuntimeApiArgs(lookup, inputs, opts = {}) {
1049
+ if (inputs.length === 0)
1050
+ return "()";
1051
+ const namedFields = inputs.map((i) => {
1052
+ let entry;
1053
+ try {
1054
+ entry = lookup(i.type);
1055
+ if (!entry || typeof entry.type !== "string")
1056
+ entry = { type: "unknown" };
1057
+ } catch {
1058
+ entry = { type: "unknown" };
1059
+ }
1060
+ return [i.name, entry];
1061
+ });
1062
+ return renderArgsFromFields({ kind: "named", fields: namedFields }, opts);
1063
+ }
1064
+ function unwrapVariant(variant) {
1065
+ if (!variant)
1066
+ return null;
1067
+ if (variant.type === "void")
1068
+ return { kind: "void" };
1069
+ if (variant.type === "struct") {
1070
+ return {
1071
+ kind: "named",
1072
+ fields: Object.entries(variant.value)
1073
+ };
1074
+ }
1075
+ if (variant.type === "tuple") {
1076
+ return { kind: "positional", types: variant.value };
1077
+ }
1078
+ if (variant.type === "lookupEntry") {
1079
+ const inner = variant.value;
1080
+ if (inner.type === "void")
1081
+ return { kind: "void" };
1082
+ if (inner.type === "struct") {
1083
+ return {
1084
+ kind: "named",
1085
+ fields: Object.entries(inner.value)
1086
+ };
1087
+ }
1088
+ return { kind: "single", type: inner };
1089
+ }
1090
+ return null;
1091
+ }
1092
+ function getCallFields(meta, palletName, callName) {
1093
+ try {
1094
+ const palletMeta = meta.unified.pallets.find((p) => p.name === palletName);
1095
+ if (!palletMeta?.calls)
1096
+ return null;
1097
+ const callsEntry = meta.lookup(palletMeta.calls.type);
1098
+ if (callsEntry.type !== "enum")
1099
+ return null;
1100
+ const variant = callsEntry.value[callName];
1101
+ return unwrapVariant(variant);
1102
+ } catch {
1103
+ return null;
1104
+ }
1105
+ }
1106
+ function getEventFields(meta, palletName, eventName) {
1107
+ try {
1108
+ const palletMeta = meta.unified.pallets.find((p) => p.name === palletName);
1109
+ if (!palletMeta?.events)
1110
+ return null;
1111
+ const eventsEntry = meta.lookup(palletMeta.events.type);
1112
+ if (eventsEntry.type !== "enum")
1113
+ return null;
1114
+ const variant = eventsEntry.value[eventName];
1115
+ return unwrapVariant(variant);
1116
+ } catch {
1117
+ return null;
1118
+ }
1119
+ }
1120
+ function renderArgsFromFields(fields, opts) {
1121
+ const { indent, prefix, width, color } = resolveOpts(opts);
1122
+ const lead = indent + prefix;
1123
+ switch (fields.kind) {
1124
+ case "void":
1125
+ return "()";
1126
+ case "named": {
1127
+ const compact = `(${fields.fields.map(([k, v]) => `${paint(color, CYAN2, k)}: ${compactEntry(v, color)}`).join(", ")})`;
1128
+ if (visualWidth(compact) + lead <= width)
1129
+ return compact;
1130
+ return renderFieldList(fields.fields, "(", ")", indent, width, color);
1131
+ }
1132
+ case "positional": {
1133
+ const compact = `(${fields.types.map((t) => compactEntry(t, color)).join(", ")})`;
1134
+ if (visualWidth(compact) + lead <= width)
1135
+ return compact;
1136
+ const innerIndent = indent + 2;
1137
+ const padding = " ".repeat(innerIndent);
1138
+ const closePadding = " ".repeat(indent);
1139
+ const lines = fields.types.map((t) => `${padding}${expandEntry(t, innerIndent, width, color)}`);
1140
+ return `(
1141
+ ${lines.join(`,
1142
+ `)},
1143
+ ${closePadding})`;
1144
+ }
1145
+ case "single": {
1146
+ const compact = `(${compactEntry(fields.type, color)})`;
1147
+ if (visualWidth(compact) + lead <= width)
1148
+ return compact;
1149
+ const inner = expandEntry(fields.type, indent + 2, width, color);
1150
+ return `(
1151
+ ${" ".repeat(indent + 2)}${inner},
1152
+ ${" ".repeat(indent)})`;
1153
+ }
1154
+ }
1155
+ }
1156
+ function compactTypeString(entry) {
1157
+ return compactEntry(entry, false);
1158
+ }
1159
+ function compactArgsString(fields) {
1160
+ if (fields === null)
1161
+ return "";
1162
+ switch (fields.kind) {
1163
+ case "void":
1164
+ return "()";
1165
+ case "named":
1166
+ return `(${fields.fields.map(([k, v]) => `${k}: ${compactEntry(v, false)}`).join(", ")})`;
1167
+ case "positional":
1168
+ return `(${fields.types.map((t) => compactEntry(t, false)).join(", ")})`;
1169
+ case "single":
1170
+ return `(${compactEntry(fields.type, false)})`;
1171
+ }
1172
+ }
1173
+ var RESET2 = "\x1B[0m", CYAN2 = "\x1B[36m", GREEN2 = "\x1B[32m", YELLOW2 = "\x1B[33m", MAGENTA2 = "\x1B[35m", ANSI_RE, ENUM_COMPACT_LIMIT = 24, ALIGN_PADDING_LIMIT = 16;
1174
+ var init_pretty_type = __esm(() => {
1175
+ init_output();
1176
+ ANSI_RE = /\x1b\[[0-9;]*m/g;
1177
+ });
1178
+
794
1179
  // src/core/metadata.ts
795
1180
  import { getDynamicBuilder, getLookupFn } from "@polkadot-api/metadata-builders";
796
1181
  import {
@@ -809,28 +1194,52 @@ function parseMetadata(raw) {
809
1194
  const builder = getDynamicBuilder(lookup);
810
1195
  return { unified, lookup, builder, version: version2 };
811
1196
  }
1197
+ async function getRuntimeFingerprint(clientHandle, chainName) {
1198
+ const { client } = clientHandle;
1199
+ const [version2, codeHash] = await Promise.all([
1200
+ withTimeout(client._request("state_getRuntimeVersion", []), chainName),
1201
+ withTimeout(client._request("state_getStorageHash", ["0x3a636f6465"]), chainName)
1202
+ ]);
1203
+ return {
1204
+ specName: version2.specName,
1205
+ specVersion: version2.specVersion,
1206
+ transactionVersion: version2.transactionVersion,
1207
+ implName: version2.implName,
1208
+ implVersion: version2.implVersion,
1209
+ authoringVersion: version2.authoringVersion,
1210
+ codeHash,
1211
+ fetchedAt: new Date().toISOString()
1212
+ };
1213
+ }
812
1214
  async function fetchMetadataFromChain(clientHandle, chainName) {
813
1215
  const { client } = clientHandle;
1216
+ let bytes;
814
1217
  try {
815
1218
  const hex = await withTimeout(client._request("state_call", ["Metadata_metadata_at_version", v15Arg]), chainName);
816
1219
  const raw = hexToBytes(hex);
817
1220
  const decoded = optionalOpaqueBytes.dec(raw);
818
1221
  if (decoded !== undefined) {
819
- const bytes = new Uint8Array(decoded);
820
- await saveMetadata(chainName, bytes);
821
- return bytes;
1222
+ bytes = new Uint8Array(decoded);
822
1223
  }
823
1224
  } catch {}
1225
+ if (!bytes) {
1226
+ try {
1227
+ const hex = await withTimeout(client._request("state_getMetadata", []), chainName);
1228
+ bytes = hexToBytes(hex);
1229
+ } catch (err) {
1230
+ if (err instanceof ConnectionError)
1231
+ throw err;
1232
+ throw new ConnectionError(`Failed to fetch metadata for "${chainName}": ${err instanceof Error ? err.message : err}. ` + "Check that the RPC endpoint is correct and reachable.");
1233
+ }
1234
+ }
1235
+ let fingerprint;
824
1236
  try {
825
- const hex = await withTimeout(client._request("state_getMetadata", []), chainName);
826
- const bytes = hexToBytes(hex);
827
- await saveMetadata(chainName, bytes);
828
- return bytes;
829
- } catch (err) {
830
- if (err instanceof ConnectionError)
831
- throw err;
832
- throw new ConnectionError(`Failed to fetch metadata for "${chainName}": ${err instanceof Error ? err.message : err}. ` + "Check that the RPC endpoint is correct and reachable.");
1237
+ fingerprint = await getRuntimeFingerprint(clientHandle, chainName);
1238
+ } catch {
1239
+ fingerprint = undefined;
833
1240
  }
1241
+ await saveMetadata(chainName, bytes, fingerprint);
1242
+ return bytes;
834
1243
  }
835
1244
  function withTimeout(promise, chainName) {
836
1245
  return Promise.race([
@@ -838,6 +1247,33 @@ function withTimeout(promise, chainName) {
838
1247
  new Promise((_, reject) => setTimeout(() => reject(new ConnectionError(`Timed out fetching metadata for "${chainName}" after ${METADATA_TIMEOUT_MS / 1000}s. ` + "Check that the RPC endpoint is correct and reachable.")), METADATA_TIMEOUT_MS))
839
1248
  ]);
840
1249
  }
1250
+ async function withStalenessSuggestion(chainName, clientHandle, task) {
1251
+ try {
1252
+ return await task();
1253
+ } catch (err) {
1254
+ if (process.env.DOT_TRUST_CACHED_METADATA === "1")
1255
+ throw err;
1256
+ if (!isLikelyStaleMetadataError(err))
1257
+ throw err;
1258
+ let live;
1259
+ try {
1260
+ live = await getRuntimeFingerprint(clientHandle, chainName);
1261
+ } catch {
1262
+ throw err;
1263
+ }
1264
+ const cached = await loadMetadataFingerprint(chainName);
1265
+ if (!cached)
1266
+ throw err;
1267
+ if (fingerprintsMatch(cached, live))
1268
+ throw err;
1269
+ const original = err instanceof Error ? formatRuntimeError(err) : String(err);
1270
+ const versionNote = cached.specVersion !== live.specVersion ? `spec ${cached.specVersion} → ${live.specVersion}` : `runtime code hash changed (same spec ${live.specVersion}; likely a node restart with new wasm)`;
1271
+ throw new CliError(`${original}
1272
+
1273
+ ` + `⚠ Local metadata for "${chainName}" is out of date (${versionNote}).
1274
+ ` + ` Run: dot chain update ${chainName}`);
1275
+ }
1276
+ }
841
1277
  async function getOrFetchMetadata(chainName, clientHandle) {
842
1278
  let raw = await loadMetadata(chainName);
843
1279
  if (!raw) {
@@ -954,114 +1390,18 @@ function describeRuntimeApiMethodArgs(meta, method) {
954
1390
  function describeType(lookup, typeId) {
955
1391
  try {
956
1392
  const entry = lookup(typeId);
957
- return formatLookupEntry(entry);
1393
+ if (!entry || typeof entry.type !== "string")
1394
+ return `type(${typeId})`;
1395
+ return compactTypeString(entry);
958
1396
  } catch {
959
1397
  return `type(${typeId})`;
960
1398
  }
961
1399
  }
962
- function formatLookupEntry(entry) {
963
- switch (entry.type) {
964
- case "primitive":
965
- return entry.value;
966
- case "compact":
967
- return `Compact<${formatLookupEntry(entry.isBig ? { type: "primitive", value: "u128" } : { type: "primitive", value: "u64" })}>`;
968
- case "AccountId32":
969
- return "AccountId32";
970
- case "bitSequence":
971
- return "BitSequence";
972
- case "sequence":
973
- return `Vec<${formatLookupEntry(entry.value)}>`;
974
- case "array":
975
- return `[${formatLookupEntry(entry.value)}; ${entry.len}]`;
976
- case "tuple":
977
- return `(${entry.value.map(formatLookupEntry).join(", ")})`;
978
- case "struct":
979
- return `{ ${Object.entries(entry.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ")} }`;
980
- case "option":
981
- return `Option<${formatLookupEntry(entry.value)}>`;
982
- case "result":
983
- return `Result<${formatLookupEntry(entry.value.ok)}, ${formatLookupEntry(entry.value.ko)}>`;
984
- case "enum": {
985
- const variants = Object.keys(entry.value);
986
- if (variants.length <= 4)
987
- return variants.join(" | ");
988
- return `enum(${variants.length} variants)`;
989
- }
990
- default:
991
- return "unknown";
992
- }
993
- }
994
1400
  function describeCallArgs(meta, palletName, callName) {
995
- try {
996
- const palletMeta = meta.unified.pallets.find((p) => p.name === palletName);
997
- if (!palletMeta?.calls)
998
- return "";
999
- const callsEntry = meta.lookup(palletMeta.calls.type);
1000
- if (callsEntry.type !== "enum")
1001
- return "";
1002
- const variant = callsEntry.value[callName];
1003
- if (!variant)
1004
- return "";
1005
- if (variant.type === "void")
1006
- return "()";
1007
- if (variant.type === "struct") {
1008
- const fields = Object.entries(variant.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
1009
- return `(${fields})`;
1010
- }
1011
- if (variant.type === "lookupEntry") {
1012
- const inner = variant.value;
1013
- if (inner.type === "void")
1014
- return "()";
1015
- if (inner.type === "struct") {
1016
- const fields = Object.entries(inner.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
1017
- return `(${fields})`;
1018
- }
1019
- return `(${formatLookupEntry(inner)})`;
1020
- }
1021
- if (variant.type === "tuple") {
1022
- const types = variant.value.map(formatLookupEntry).join(", ");
1023
- return `(${types})`;
1024
- }
1025
- return "";
1026
- } catch {
1027
- return "";
1028
- }
1401
+ return compactArgsString(getCallFields(meta, palletName, callName));
1029
1402
  }
1030
1403
  function describeEventFields(meta, palletName, eventName) {
1031
- try {
1032
- const palletMeta = meta.unified.pallets.find((p) => p.name === palletName);
1033
- if (!palletMeta?.events)
1034
- return "";
1035
- const eventsEntry = meta.lookup(palletMeta.events.type);
1036
- if (eventsEntry.type !== "enum")
1037
- return "";
1038
- const variant = eventsEntry.value[eventName];
1039
- if (!variant)
1040
- return "";
1041
- if (variant.type === "void")
1042
- return "()";
1043
- if (variant.type === "struct") {
1044
- const fields = Object.entries(variant.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
1045
- return `(${fields})`;
1046
- }
1047
- if (variant.type === "lookupEntry") {
1048
- const inner = variant.value;
1049
- if (inner.type === "void")
1050
- return "()";
1051
- if (inner.type === "struct") {
1052
- const fields = Object.entries(inner.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
1053
- return `(${fields})`;
1054
- }
1055
- return `(${formatLookupEntry(inner)})`;
1056
- }
1057
- if (variant.type === "tuple") {
1058
- const types = variant.value.map(formatLookupEntry).join(", ");
1059
- return `(${types})`;
1060
- }
1061
- return "";
1062
- } catch {
1063
- return "";
1064
- }
1404
+ return compactArgsString(getEventFields(meta, palletName, eventName));
1065
1405
  }
1066
1406
  function hexToBytes(hex) {
1067
1407
  const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
@@ -1075,6 +1415,7 @@ var METADATA_TIMEOUT_MS = 15000, optionalOpaqueBytes, v15Arg, PAPI_BUILTIN_EXTEN
1075
1415
  var init_metadata = __esm(() => {
1076
1416
  init_store();
1077
1417
  init_errors();
1418
+ init_pretty_type();
1078
1419
  optionalOpaqueBytes = Option(Bytes());
1079
1420
  v15Arg = toHex(u32.enc(15));
1080
1421
  PAPI_BUILTIN_EXTENSIONS = new Set([
@@ -1471,6 +1812,7 @@ var init_tx = __esm(() => {
1471
1812
  init_client();
1472
1813
  init_metadata();
1473
1814
  init_output();
1815
+ init_pretty_type();
1474
1816
  init_resolve_address();
1475
1817
  init_binary_display();
1476
1818
  init_errors();
@@ -1686,8 +2028,11 @@ async function handleCalls(target, opts) {
1686
2028
  }
1687
2029
  printHeading(`${pallet.name} Calls`);
1688
2030
  for (const c of pallet.calls) {
1689
- const args2 = describeCallArgs(meta, pallet.name, c.name);
1690
- console.log(` ${CYAN}${c.name}${RESET}${DIM}${args2}${RESET}`);
2031
+ const args2 = prettyCallArgs(meta, pallet.name, c.name, {
2032
+ indent: 2,
2033
+ prefix: c.name.length
2034
+ });
2035
+ console.log(` ${CYAN}${c.name}${RESET}${args2}`);
1691
2036
  const summary = firstSentence(c.docs);
1692
2037
  if (summary) {
1693
2038
  console.log(` ${DIM}${summary}${RESET}`);
@@ -1713,7 +2058,10 @@ async function handleCalls(target, opts) {
1713
2058
  return;
1714
2059
  }
1715
2060
  printHeading(`${pallet.name}.${callItem.name} (Call)`);
1716
- const args = describeCallArgs(meta, pallet.name, callItem.name);
2061
+ const args = prettyCallArgs(meta, pallet.name, callItem.name, {
2062
+ indent: 2,
2063
+ prefix: 6
2064
+ });
1717
2065
  console.log(` ${BOLD}Args:${RESET} ${args}`);
1718
2066
  if (callItem.docs.length) {
1719
2067
  console.log();
@@ -1772,8 +2120,11 @@ async function handleEvents(target, opts) {
1772
2120
  }
1773
2121
  printHeading(`${pallet.name} Events`);
1774
2122
  for (const e of pallet.events) {
1775
- const fields2 = describeEventFields(meta, pallet.name, e.name);
1776
- console.log(` ${CYAN}${e.name}${RESET}${DIM}${fields2}${RESET}`);
2123
+ const fields2 = prettyEventFields(meta, pallet.name, e.name, {
2124
+ indent: 2,
2125
+ prefix: e.name.length
2126
+ });
2127
+ console.log(` ${CYAN}${e.name}${RESET}${fields2}`);
1777
2128
  const summary = firstSentence(e.docs);
1778
2129
  if (summary) {
1779
2130
  console.log(` ${DIM}${summary}${RESET}`);
@@ -1799,7 +2150,10 @@ async function handleEvents(target, opts) {
1799
2150
  return;
1800
2151
  }
1801
2152
  printHeading(`${pallet.name}.${eventItem.name} (Event)`);
1802
- const fields = describeEventFields(meta, pallet.name, eventItem.name);
2153
+ const fields = prettyEventFields(meta, pallet.name, eventItem.name, {
2154
+ indent: 2,
2155
+ prefix: 8
2156
+ });
1803
2157
  console.log(` ${BOLD}Fields:${RESET} ${fields}`);
1804
2158
  if (eventItem.docs.length) {
1805
2159
  console.log();
@@ -1926,24 +2280,30 @@ async function handleStorage(target, opts) {
1926
2280
  chain: chainName,
1927
2281
  pallet: pallet.name,
1928
2282
  storage: pallet.storage.map((s) => {
1929
- const valueType = describeType(meta.lookup, s.valueTypeId);
2283
+ const valueType2 = describeType(meta.lookup, s.valueTypeId);
1930
2284
  const keyType = s.keyTypeId != null ? describeType(meta.lookup, s.keyTypeId) : undefined;
1931
- return { name: s.name, type: s.type, valueType, keyType, docs: firstSentence(s.docs) };
2285
+ return { name: s.name, type: s.type, valueType: valueType2, keyType, docs: firstSentence(s.docs) };
1932
2286
  })
1933
2287
  }));
1934
2288
  return;
1935
2289
  }
1936
2290
  printHeading(`${pallet.name} Storage`);
1937
2291
  for (const s of pallet.storage) {
1938
- const valueType = describeType(meta.lookup, s.valueTypeId);
1939
- let typeSuffix;
1940
- if (s.keyTypeId != null) {
1941
- const keyType = describeType(meta.lookup, s.keyTypeId);
1942
- typeSuffix = `: ${keyType} → ${valueType} [map]`;
1943
- } else {
1944
- typeSuffix = `: ${valueType}`;
2292
+ const isMap = s.keyTypeId != null;
2293
+ const tag = isMap ? `${DIM} [map]${RESET}` : "";
2294
+ console.log(` ${CYAN}${s.name}${RESET}${tag}`);
2295
+ if (isMap) {
2296
+ const keyType = prettyTypeById(meta.lookup, s.keyTypeId, {
2297
+ indent: 4,
2298
+ prefix: 5
2299
+ });
2300
+ console.log(` ${DIM}Key:${RESET} ${keyType}`);
1945
2301
  }
1946
- console.log(` ${CYAN}${s.name}${RESET}${DIM}${typeSuffix}${RESET}`);
2302
+ const valueType2 = prettyTypeById(meta.lookup, s.valueTypeId, {
2303
+ indent: 4,
2304
+ prefix: 7
2305
+ });
2306
+ console.log(` ${DIM}Value:${RESET} ${valueType2}`);
1947
2307
  const summary = firstSentence(s.docs);
1948
2308
  if (summary) {
1949
2309
  console.log(` ${DIM}${summary}${RESET}`);
@@ -1958,7 +2318,7 @@ async function handleStorage(target, opts) {
1958
2318
  throw new Error(suggestMessage(`storage item in ${pallet.name}`, itemName, names));
1959
2319
  }
1960
2320
  if (isJsonOutput(opts)) {
1961
- const valueType = describeType(meta.lookup, storageItem.valueTypeId);
2321
+ const valueType2 = describeType(meta.lookup, storageItem.valueTypeId);
1962
2322
  const keyType = storageItem.keyTypeId != null ? describeType(meta.lookup, storageItem.keyTypeId) : undefined;
1963
2323
  console.log(formatJson({
1964
2324
  chain: chainName,
@@ -1966,18 +2326,26 @@ async function handleStorage(target, opts) {
1966
2326
  item: storageItem.name,
1967
2327
  category: "storage",
1968
2328
  type: storageItem.type,
1969
- valueType,
2329
+ valueType: valueType2,
1970
2330
  keyType,
1971
2331
  docs: storageItem.docs
1972
2332
  }));
1973
2333
  return;
1974
2334
  }
1975
2335
  printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
1976
- console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
1977
- console.log(` ${BOLD}Value:${RESET} ${describeType(meta.lookup, storageItem.valueTypeId)}`);
2336
+ console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
1978
2337
  if (storageItem.keyTypeId != null) {
1979
- console.log(` ${BOLD}Key:${RESET} ${describeType(meta.lookup, storageItem.keyTypeId)}`);
2338
+ const keyType = prettyTypeById(meta.lookup, storageItem.keyTypeId, {
2339
+ indent: 2,
2340
+ prefix: 7
2341
+ });
2342
+ console.log(` ${BOLD}Key:${RESET} ${keyType}`);
1980
2343
  }
2344
+ const valueType = prettyTypeById(meta.lookup, storageItem.valueTypeId, {
2345
+ indent: 2,
2346
+ prefix: 7
2347
+ });
2348
+ console.log(` ${BOLD}Value:${RESET} ${valueType}`);
1981
2349
  if (storageItem.docs.length) {
1982
2350
  console.log();
1983
2351
  printDocs(storageItem.docs);
@@ -2008,9 +2376,15 @@ async function showItemHelp(category, target, opts) {
2008
2376
  throw new Error(suggestMessage(`method in ${api.name}`, methodName, names));
2009
2377
  }
2010
2378
  printHeading(`${api.name}.${method.name} (Runtime API)`);
2011
- const argStr = describeRuntimeApiMethodArgs(meta, method);
2012
- const retStr = describeType(meta.lookup, method.output);
2013
- console.log(` ${BOLD}Args:${RESET} ${argStr}`);
2379
+ const argStr = prettyRuntimeApiArgs(meta.lookup, method.inputs, {
2380
+ indent: 2,
2381
+ prefix: 9
2382
+ });
2383
+ const retStr = prettyTypeById(meta.lookup, method.output, {
2384
+ indent: 2,
2385
+ prefix: 9
2386
+ });
2387
+ console.log(` ${BOLD}Args:${RESET} ${argStr}`);
2014
2388
  console.log(` ${BOLD}Returns:${RESET} ${retStr}`);
2015
2389
  if (method.docs.length) {
2016
2390
  console.log();
@@ -2053,7 +2427,10 @@ async function showItemHelp(category, target, opts) {
2053
2427
  throw new Error(suggestMessage(`call in ${pallet.name}`, itemName, names));
2054
2428
  }
2055
2429
  printHeading(`${pallet.name}.${callItem.name} (Call)`);
2056
- const args = describeCallArgs(meta, pallet.name, callItem.name);
2430
+ const args = prettyCallArgs(meta, pallet.name, callItem.name, {
2431
+ indent: 2,
2432
+ prefix: 6
2433
+ });
2057
2434
  console.log(` ${BOLD}Args:${RESET} ${args}`);
2058
2435
  if (callItem.docs.length) {
2059
2436
  console.log();
@@ -2080,11 +2457,19 @@ async function showItemHelp(category, target, opts) {
2080
2457
  throw new Error(suggestMessage(`storage item in ${pallet.name}`, itemName, names));
2081
2458
  }
2082
2459
  printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
2083
- console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
2084
- console.log(` ${BOLD}Value:${RESET} ${describeType(meta.lookup, storageItem.valueTypeId)}`);
2460
+ console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
2085
2461
  if (storageItem.keyTypeId != null) {
2086
- console.log(` ${BOLD}Key:${RESET} ${describeType(meta.lookup, storageItem.keyTypeId)}`);
2462
+ const keyType = prettyTypeById(meta.lookup, storageItem.keyTypeId, {
2463
+ indent: 2,
2464
+ prefix: 7
2465
+ });
2466
+ console.log(` ${BOLD}Key:${RESET} ${keyType}`);
2087
2467
  }
2468
+ const valueType = prettyTypeById(meta.lookup, storageItem.valueTypeId, {
2469
+ indent: 2,
2470
+ prefix: 7
2471
+ });
2472
+ console.log(` ${BOLD}Value:${RESET} ${valueType}`);
2088
2473
  if (storageItem.docs.length) {
2089
2474
  console.log();
2090
2475
  printDocs(storageItem.docs);
@@ -2111,7 +2496,11 @@ async function showItemHelp(category, target, opts) {
2111
2496
  throw new Error(suggestMessage(`constant in ${pallet.name}`, itemName, names));
2112
2497
  }
2113
2498
  printHeading(`${pallet.name}.${constItem.name} (Constant)`);
2114
- console.log(` ${BOLD}Type:${RESET} ${describeType(meta.lookup, constItem.typeId)}`);
2499
+ const constType = prettyTypeById(meta.lookup, constItem.typeId, {
2500
+ indent: 2,
2501
+ prefix: 6
2502
+ });
2503
+ console.log(` ${BOLD}Type:${RESET} ${constType}`);
2115
2504
  if (constItem.docs.length) {
2116
2505
  console.log();
2117
2506
  printDocs(constItem.docs);
@@ -2129,7 +2518,10 @@ async function showItemHelp(category, target, opts) {
2129
2518
  throw new Error(suggestMessage(`event in ${pallet.name}`, itemName, names));
2130
2519
  }
2131
2520
  printHeading(`${pallet.name}.${eventItem.name} (Event)`);
2132
- const fields = describeEventFields(meta, pallet.name, eventItem.name);
2521
+ const fields = prettyEventFields(meta, pallet.name, eventItem.name, {
2522
+ indent: 2,
2523
+ prefix: 8
2524
+ });
2133
2525
  console.log(` ${BOLD}Fields:${RESET} ${fields}`);
2134
2526
  if (eventItem.docs.length) {
2135
2527
  console.log();
@@ -2164,6 +2556,7 @@ var init_focused_inspect = __esm(() => {
2164
2556
  init_client();
2165
2557
  init_metadata();
2166
2558
  init_output();
2559
+ init_pretty_type();
2167
2560
  });
2168
2561
 
2169
2562
  // src/core/hash.ts
@@ -2553,7 +2946,7 @@ var init_complete = __esm(() => {
2553
2946
  ext: "extensions"
2554
2947
  };
2555
2948
  NAMED_COMMANDS = ["chain", "account", "inspect", "hash", "sign", "parachain", "completions"];
2556
- CHAIN_SUBCOMMANDS = ["add", "remove", "update", "list"];
2949
+ CHAIN_SUBCOMMANDS = ["add", "info", "list", "remove", "update"];
2557
2950
  ACCOUNT_SUBCOMMANDS = [
2558
2951
  "add",
2559
2952
  "create",
@@ -2584,7 +2977,7 @@ var init_complete = __esm(() => {
2584
2977
  // src/cli.ts
2585
2978
  import cac from "cac";
2586
2979
  // package.json
2587
- var version = "1.15.1";
2980
+ var version = "1.17.0";
2588
2981
 
2589
2982
  // src/commands/account.ts
2590
2983
  init_accounts_store();
@@ -3427,6 +3820,8 @@ ${BOLD}Usage:${RESET}
3427
3820
  $ dot chain update <name> Re-fetch metadata for a chain
3428
3821
  $ dot chain update --all Re-fetch metadata for all configured chains
3429
3822
  $ dot chain list List configured chains
3823
+ $ dot chain info <name> Show details for a single chain
3824
+ $ dot chain <name> Shortcut for \`chain info <name>\`
3430
3825
  $ dot chain export [names...] Export chain configuration to stdout
3431
3826
  $ dot chain import <file> Import chain configuration from a file
3432
3827
 
@@ -3436,6 +3831,9 @@ ${BOLD}Examples:${RESET}
3436
3831
  $ dot chain add my-para --rpc wss://rpc.example.com --relay polkadot
3437
3832
  $ dot chain add my-para --rpc wss://rpc.example.com --relay polkadot --parachain-id 2000
3438
3833
  $ dot chain list
3834
+ $ dot chains -v
3835
+ $ dot chain info polkadot
3836
+ $ dot chain polkadot
3439
3837
  $ dot chain update kusama
3440
3838
  $ dot chain update --all
3441
3839
  $ dot chain remove kusama
@@ -3448,7 +3846,7 @@ ${BOLD}Examples:${RESET}
3448
3846
  $ dot chain import my-chains.json --no-metadata
3449
3847
  `.trimStart();
3450
3848
  function registerChainCommands(cli) {
3451
- cli.command("chain [action] [...names]", "Manage chains (add, remove, update, list, export, import)").alias("chains").option("--all", "Update/export all configured chains").option("--relay <name>", "Parent relay chain for this parachain").option("--parachain-id <id>", "Parachain ID (auto-detected if omitted with --relay)").option("--file <path>", "Output/input file for export/import").option("--overwrite", "Overwrite existing chains on import").option("--dry-run", "Preview import without applying changes").option("--no-metadata", "Skip automatic metadata fetch after import").action(async (action, names, opts) => {
3849
+ cli.command("chain [action] [...names]", "Manage chains (add, remove, update, list, export, import)").alias("chains").option("--all", "Update/export all configured chains").option("--relay <name>", "Parent relay chain for this parachain").option("--parachain-id <id>", "Parachain ID (auto-detected if omitted with --relay)").option("--file <path>", "Output/input file for export/import").option("--overwrite", "Overwrite existing chains on import").option("--dry-run", "Preview import without applying changes").option("--no-metadata", "Skip automatic metadata fetch after import").option("-v, --verbose", "Show RPC endpoints in `chains` list output").action(async (action, names, opts) => {
3452
3850
  if (!action) {
3453
3851
  if (process.argv[2] === "chains")
3454
3852
  return chainList(opts);
@@ -3462,17 +3860,24 @@ function registerChainCommands(cli) {
3462
3860
  return chainRemove(names[0], opts);
3463
3861
  case "list":
3464
3862
  return chainList(opts);
3863
+ case "info":
3864
+ return chainInfo(names[0], opts);
3465
3865
  case "update":
3466
3866
  return chainUpdate(names[0], opts);
3467
3867
  case "export":
3468
3868
  return chainExport(names, opts);
3469
3869
  case "import":
3470
3870
  return chainImport(names[0], opts);
3471
- default:
3871
+ default: {
3872
+ const config = await loadConfig();
3873
+ if (findChainName(config, action)) {
3874
+ return chainInfo(action, opts);
3875
+ }
3472
3876
  console.error(`Unknown action "${action}".
3473
3877
  `);
3474
3878
  console.log(CHAIN_HELP);
3475
3879
  process.exit(1);
3880
+ }
3476
3881
  }
3477
3882
  });
3478
3883
  }
@@ -3582,6 +3987,7 @@ async function chainList(opts = {}) {
3582
3987
  console.log(formatJson({ chains }));
3583
3988
  return;
3584
3989
  }
3990
+ const verbose = opts.verbose === true;
3585
3991
  printHeading("Configured Chains");
3586
3992
  const parachainsByRelay = new Map;
3587
3993
  const standalone = [];
@@ -3603,7 +4009,7 @@ async function chainList(opts = {}) {
3603
4009
  for (const relayName of relayNames) {
3604
4010
  const relayConfig = config.chains[relayName];
3605
4011
  if (relayConfig) {
3606
- printChainLine(" ", relayName, relayConfig);
4012
+ printChainLine(" ", relayName, relayConfig, "", verbose);
3607
4013
  }
3608
4014
  const paras = parachainsByRelay.get(relayName) ?? [];
3609
4015
  for (let i = 0;i < paras.length; i++) {
@@ -3611,17 +4017,21 @@ async function chainList(opts = {}) {
3611
4017
  const isLast = i === paras.length - 1;
3612
4018
  const prefix = isLast ? " └─ " : " ├─ ";
3613
4019
  const idSuffix = chainConfig.parachainId != null ? ` ${DIM}[${chainConfig.parachainId}]${RESET}` : "";
3614
- printChainLine(prefix, name, chainConfig, idSuffix);
4020
+ printChainLine(prefix, name, chainConfig, idSuffix, verbose);
3615
4021
  }
3616
4022
  console.log();
3617
4023
  }
3618
4024
  for (const [name, chainConfig] of standalone) {
3619
- printChainLine(" ", name, chainConfig);
4025
+ printChainLine(" ", name, chainConfig, "", verbose);
3620
4026
  }
3621
4027
  if (standalone.length > 0)
3622
4028
  console.log();
3623
4029
  }
3624
- function printChainLine(prefix, name, chainConfig, suffix = "") {
4030
+ function printChainLine(prefix, name, chainConfig, suffix = "", verbose = false) {
4031
+ if (!verbose) {
4032
+ console.log(`${prefix}${CYAN}${name}${RESET}${suffix}`);
4033
+ return;
4034
+ }
3625
4035
  const rpcs = Array.isArray(chainConfig.rpc) ? chainConfig.rpc : [chainConfig.rpc];
3626
4036
  console.log(`${prefix}${CYAN}${name}${RESET}${suffix} ${DIM}${rpcs[0]}${RESET}`);
3627
4037
  const indent = prefix.replace(/[^\s]/g, " ");
@@ -3629,6 +4039,56 @@ function printChainLine(prefix, name, chainConfig, suffix = "") {
3629
4039
  console.log(`${indent} ${DIM}${rpcs[i]}${RESET}`);
3630
4040
  }
3631
4041
  }
4042
+ async function chainInfo(name, opts = {}) {
4043
+ if (!name) {
4044
+ console.error("Usage: dot chain info <name>");
4045
+ process.exit(1);
4046
+ }
4047
+ const config = await loadConfig();
4048
+ const { name: resolved, chain } = resolveChain(config, name);
4049
+ const rpcs = Array.isArray(chain.rpc) ? chain.rpc : [chain.rpc];
4050
+ const parachains = Object.entries(config.chains).filter(([, c]) => c.relay === resolved).map(([n, c]) => ({ name: n, parachainId: c.parachainId }));
4051
+ const fingerprint = await loadMetadataFingerprint(resolved);
4052
+ if (isJsonOutput(opts)) {
4053
+ console.log(formatJson({
4054
+ name: resolved,
4055
+ rpc: rpcs,
4056
+ ...chain.relay && { relay: chain.relay },
4057
+ ...chain.parachainId != null && { parachainId: chain.parachainId },
4058
+ ...parachains.length > 0 && { parachains },
4059
+ metadata: fingerprint ? {
4060
+ specName: fingerprint.specName,
4061
+ specVersion: fingerprint.specVersion,
4062
+ fetchedAt: fingerprint.fetchedAt
4063
+ } : null
4064
+ }));
4065
+ return;
4066
+ }
4067
+ printHeading(resolved);
4068
+ console.log(` ${CYAN}rpc:${RESET}`);
4069
+ for (const rpc of rpcs) {
4070
+ console.log(` ${DIM}${rpc}${RESET}`);
4071
+ }
4072
+ if (chain.relay) {
4073
+ console.log(` ${CYAN}relay:${RESET} ${chain.relay}`);
4074
+ }
4075
+ if (chain.parachainId != null) {
4076
+ console.log(` ${CYAN}parachain id:${RESET} ${chain.parachainId}`);
4077
+ }
4078
+ if (parachains.length > 0) {
4079
+ console.log(` ${CYAN}parachains:${RESET}`);
4080
+ for (const p of parachains) {
4081
+ const idSuffix = p.parachainId != null ? ` ${DIM}[${p.parachainId}]${RESET}` : "";
4082
+ console.log(` ${p.name}${idSuffix}`);
4083
+ }
4084
+ }
4085
+ console.log(` ${CYAN}metadata:${RESET}`);
4086
+ if (fingerprint) {
4087
+ console.log(` ${fingerprint.specName} v${fingerprint.specVersion} ${DIM}(cached ${fingerprint.fetchedAt})${RESET}`);
4088
+ } else {
4089
+ console.log(` ${DIM}not cached — run \`dot chain update ${resolved}\`${RESET}`);
4090
+ }
4091
+ }
3632
4092
  async function chainUpdate(name, opts) {
3633
4093
  const config = await loadConfig();
3634
4094
  if (opts.all) {
@@ -4005,6 +4465,7 @@ init_store();
4005
4465
  init_client();
4006
4466
  init_metadata();
4007
4467
  init_output();
4468
+ init_pretty_type();
4008
4469
  async function loadMeta2(chainName, chainConfig, rpcOverride) {
4009
4470
  if (rpcOverride) {
4010
4471
  process.stderr.write(`Fetching metadata from ${chainName}...
@@ -4089,8 +4550,11 @@ async function handleCalls2(target, opts) {
4089
4550
  }
4090
4551
  printHeading(`${pallet.name} Calls`);
4091
4552
  for (const c of pallet.calls) {
4092
- const args2 = describeCallArgs(meta, pallet.name, c.name);
4093
- console.log(` ${CYAN}${c.name}${RESET}${DIM}${args2}${RESET}`);
4553
+ const args2 = prettyCallArgs(meta, pallet.name, c.name, {
4554
+ indent: 2,
4555
+ prefix: c.name.length
4556
+ });
4557
+ console.log(` ${CYAN}${c.name}${RESET}${args2}`);
4094
4558
  const summary = firstSentence(c.docs);
4095
4559
  if (summary) {
4096
4560
  console.log(` ${DIM}${summary}${RESET}`);
@@ -4116,7 +4580,10 @@ async function handleCalls2(target, opts) {
4116
4580
  return;
4117
4581
  }
4118
4582
  printHeading(`${pallet.name}.${callItem.name} (Call)`);
4119
- const args = describeCallArgs(meta, pallet.name, callItem.name);
4583
+ const args = prettyCallArgs(meta, pallet.name, callItem.name, {
4584
+ indent: 2,
4585
+ prefix: 6
4586
+ });
4120
4587
  console.log(` ${BOLD}Args:${RESET} ${args}`);
4121
4588
  if (callItem.docs.length) {
4122
4589
  console.log();
@@ -4175,8 +4642,11 @@ async function handleEvents2(target, opts) {
4175
4642
  }
4176
4643
  printHeading(`${pallet.name} Events`);
4177
4644
  for (const e of pallet.events) {
4178
- const fields2 = describeEventFields(meta, pallet.name, e.name);
4179
- console.log(` ${CYAN}${e.name}${RESET}${DIM}${fields2}${RESET}`);
4645
+ const fields2 = prettyEventFields(meta, pallet.name, e.name, {
4646
+ indent: 2,
4647
+ prefix: e.name.length
4648
+ });
4649
+ console.log(` ${CYAN}${e.name}${RESET}${fields2}`);
4180
4650
  const summary = firstSentence(e.docs);
4181
4651
  if (summary) {
4182
4652
  console.log(` ${DIM}${summary}${RESET}`);
@@ -4202,7 +4672,10 @@ async function handleEvents2(target, opts) {
4202
4672
  return;
4203
4673
  }
4204
4674
  printHeading(`${pallet.name}.${eventItem.name} (Event)`);
4205
- const fields = describeEventFields(meta, pallet.name, eventItem.name);
4675
+ const fields = prettyEventFields(meta, pallet.name, eventItem.name, {
4676
+ indent: 2,
4677
+ prefix: 8
4678
+ });
4206
4679
  console.log(` ${BOLD}Fields:${RESET} ${fields}`);
4207
4680
  if (eventItem.docs.length) {
4208
4681
  console.log();
@@ -4329,24 +4802,30 @@ async function handleStorage2(target, opts) {
4329
4802
  chain: chainName,
4330
4803
  pallet: pallet.name,
4331
4804
  storage: pallet.storage.map((s) => {
4332
- const valueType = describeType(meta.lookup, s.valueTypeId);
4805
+ const valueType2 = describeType(meta.lookup, s.valueTypeId);
4333
4806
  const keyType = s.keyTypeId != null ? describeType(meta.lookup, s.keyTypeId) : undefined;
4334
- return { name: s.name, type: s.type, valueType, keyType, docs: firstSentence(s.docs) };
4807
+ return { name: s.name, type: s.type, valueType: valueType2, keyType, docs: firstSentence(s.docs) };
4335
4808
  })
4336
4809
  }));
4337
4810
  return;
4338
4811
  }
4339
4812
  printHeading(`${pallet.name} Storage`);
4340
4813
  for (const s of pallet.storage) {
4341
- const valueType = describeType(meta.lookup, s.valueTypeId);
4342
- let typeSuffix;
4343
- if (s.keyTypeId != null) {
4344
- const keyType = describeType(meta.lookup, s.keyTypeId);
4345
- typeSuffix = `: ${keyType} → ${valueType} [map]`;
4346
- } else {
4347
- typeSuffix = `: ${valueType}`;
4814
+ const isMap = s.keyTypeId != null;
4815
+ const tag = isMap ? `${DIM} [map]${RESET}` : "";
4816
+ console.log(` ${CYAN}${s.name}${RESET}${tag}`);
4817
+ if (isMap) {
4818
+ const keyType = prettyTypeById(meta.lookup, s.keyTypeId, {
4819
+ indent: 4,
4820
+ prefix: 5
4821
+ });
4822
+ console.log(` ${DIM}Key:${RESET} ${keyType}`);
4348
4823
  }
4349
- console.log(` ${CYAN}${s.name}${RESET}${DIM}${typeSuffix}${RESET}`);
4824
+ const valueType2 = prettyTypeById(meta.lookup, s.valueTypeId, {
4825
+ indent: 4,
4826
+ prefix: 7
4827
+ });
4828
+ console.log(` ${DIM}Value:${RESET} ${valueType2}`);
4350
4829
  const summary = firstSentence(s.docs);
4351
4830
  if (summary) {
4352
4831
  console.log(` ${DIM}${summary}${RESET}`);
@@ -4361,7 +4840,7 @@ async function handleStorage2(target, opts) {
4361
4840
  throw new Error(suggestMessage(`storage item in ${pallet.name}`, itemName, names));
4362
4841
  }
4363
4842
  if (isJsonOutput(opts)) {
4364
- const valueType = describeType(meta.lookup, storageItem.valueTypeId);
4843
+ const valueType2 = describeType(meta.lookup, storageItem.valueTypeId);
4365
4844
  const keyType = storageItem.keyTypeId != null ? describeType(meta.lookup, storageItem.keyTypeId) : undefined;
4366
4845
  console.log(formatJson({
4367
4846
  chain: chainName,
@@ -4369,18 +4848,26 @@ async function handleStorage2(target, opts) {
4369
4848
  item: storageItem.name,
4370
4849
  category: "storage",
4371
4850
  type: storageItem.type,
4372
- valueType,
4851
+ valueType: valueType2,
4373
4852
  keyType,
4374
4853
  docs: storageItem.docs
4375
4854
  }));
4376
4855
  return;
4377
4856
  }
4378
4857
  printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
4379
- console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
4380
- console.log(` ${BOLD}Value:${RESET} ${describeType(meta.lookup, storageItem.valueTypeId)}`);
4858
+ console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
4381
4859
  if (storageItem.keyTypeId != null) {
4382
- console.log(` ${BOLD}Key:${RESET} ${describeType(meta.lookup, storageItem.keyTypeId)}`);
4860
+ const keyType = prettyTypeById(meta.lookup, storageItem.keyTypeId, {
4861
+ indent: 2,
4862
+ prefix: 7
4863
+ });
4864
+ console.log(` ${BOLD}Key:${RESET} ${keyType}`);
4383
4865
  }
4866
+ const valueType = prettyTypeById(meta.lookup, storageItem.valueTypeId, {
4867
+ indent: 2,
4868
+ prefix: 7
4869
+ });
4870
+ console.log(` ${BOLD}Value:${RESET} ${valueType}`);
4384
4871
  if (storageItem.docs.length) {
4385
4872
  console.log();
4386
4873
  printDocs(storageItem.docs);
@@ -4411,9 +4898,15 @@ async function showItemHelp2(category, target, opts) {
4411
4898
  throw new Error(suggestMessage(`method in ${api.name}`, methodName, names));
4412
4899
  }
4413
4900
  printHeading(`${api.name}.${method.name} (Runtime API)`);
4414
- const argStr = describeRuntimeApiMethodArgs(meta, method);
4415
- const retStr = describeType(meta.lookup, method.output);
4416
- console.log(` ${BOLD}Args:${RESET} ${argStr}`);
4901
+ const argStr = prettyRuntimeApiArgs(meta.lookup, method.inputs, {
4902
+ indent: 2,
4903
+ prefix: 9
4904
+ });
4905
+ const retStr = prettyTypeById(meta.lookup, method.output, {
4906
+ indent: 2,
4907
+ prefix: 9
4908
+ });
4909
+ console.log(` ${BOLD}Args:${RESET} ${argStr}`);
4417
4910
  console.log(` ${BOLD}Returns:${RESET} ${retStr}`);
4418
4911
  if (method.docs.length) {
4419
4912
  console.log();
@@ -4456,7 +4949,10 @@ async function showItemHelp2(category, target, opts) {
4456
4949
  throw new Error(suggestMessage(`call in ${pallet.name}`, itemName, names));
4457
4950
  }
4458
4951
  printHeading(`${pallet.name}.${callItem.name} (Call)`);
4459
- const args = describeCallArgs(meta, pallet.name, callItem.name);
4952
+ const args = prettyCallArgs(meta, pallet.name, callItem.name, {
4953
+ indent: 2,
4954
+ prefix: 6
4955
+ });
4460
4956
  console.log(` ${BOLD}Args:${RESET} ${args}`);
4461
4957
  if (callItem.docs.length) {
4462
4958
  console.log();
@@ -4483,11 +4979,19 @@ async function showItemHelp2(category, target, opts) {
4483
4979
  throw new Error(suggestMessage(`storage item in ${pallet.name}`, itemName, names));
4484
4980
  }
4485
4981
  printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
4486
- console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
4487
- console.log(` ${BOLD}Value:${RESET} ${describeType(meta.lookup, storageItem.valueTypeId)}`);
4982
+ console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
4488
4983
  if (storageItem.keyTypeId != null) {
4489
- console.log(` ${BOLD}Key:${RESET} ${describeType(meta.lookup, storageItem.keyTypeId)}`);
4984
+ const keyType = prettyTypeById(meta.lookup, storageItem.keyTypeId, {
4985
+ indent: 2,
4986
+ prefix: 7
4987
+ });
4988
+ console.log(` ${BOLD}Key:${RESET} ${keyType}`);
4490
4989
  }
4990
+ const valueType = prettyTypeById(meta.lookup, storageItem.valueTypeId, {
4991
+ indent: 2,
4992
+ prefix: 7
4993
+ });
4994
+ console.log(` ${BOLD}Value:${RESET} ${valueType}`);
4491
4995
  if (storageItem.docs.length) {
4492
4996
  console.log();
4493
4997
  printDocs(storageItem.docs);
@@ -4514,7 +5018,11 @@ async function showItemHelp2(category, target, opts) {
4514
5018
  throw new Error(suggestMessage(`constant in ${pallet.name}`, itemName, names));
4515
5019
  }
4516
5020
  printHeading(`${pallet.name}.${constItem.name} (Constant)`);
4517
- console.log(` ${BOLD}Type:${RESET} ${describeType(meta.lookup, constItem.typeId)}`);
5021
+ const constType = prettyTypeById(meta.lookup, constItem.typeId, {
5022
+ indent: 2,
5023
+ prefix: 6
5024
+ });
5025
+ console.log(` ${BOLD}Type:${RESET} ${constType}`);
4518
5026
  if (constItem.docs.length) {
4519
5027
  console.log();
4520
5028
  printDocs(constItem.docs);
@@ -4532,7 +5040,10 @@ async function showItemHelp2(category, target, opts) {
4532
5040
  throw new Error(suggestMessage(`event in ${pallet.name}`, itemName, names));
4533
5041
  }
4534
5042
  printHeading(`${pallet.name}.${eventItem.name} (Event)`);
4535
- const fields = describeEventFields(meta, pallet.name, eventItem.name);
5043
+ const fields = prettyEventFields(meta, pallet.name, eventItem.name, {
5044
+ indent: 2,
5045
+ prefix: 8
5046
+ });
4536
5047
  console.log(` ${BOLD}Fields:${RESET} ${fields}`);
4537
5048
  if (eventItem.docs.length) {
4538
5049
  console.log();
@@ -4607,8 +5118,16 @@ async function handleExtensions(target, opts) {
4607
5118
  return;
4608
5119
  }
4609
5120
  printHeading(`${described.identifier} (Transaction Extension)`);
4610
- console.log(` ${BOLD}Value type:${RESET} ${described.valueType}`);
4611
- console.log(` ${BOLD}AdditionalSigned:${RESET} ${described.additionalSignedType}`);
5121
+ const valueType = prettyTypeById(meta.lookup, described.valueTypeId, {
5122
+ indent: 2,
5123
+ prefix: 18
5124
+ });
5125
+ const addSigType = prettyTypeById(meta.lookup, described.additionalSignedTypeId, {
5126
+ indent: 2,
5127
+ prefix: 18
5128
+ });
5129
+ console.log(` ${BOLD}Value type:${RESET} ${valueType}`);
5130
+ console.log(` ${BOLD}AdditionalSigned:${RESET} ${addSigType}`);
4612
5131
  console.log(` ${BOLD}Handled by:${RESET} ${described.isBuiltin ? "polkadot-api (builtin)" : "user (custom — provide via --ext)"}`);
4613
5132
  if (!described.isBuiltin) {
4614
5133
  console.log();
@@ -4692,6 +5211,7 @@ init_store();
4692
5211
  init_client();
4693
5212
  init_metadata();
4694
5213
  init_output();
5214
+ init_pretty_type();
4695
5215
 
4696
5216
  // src/utils/parse-target.ts
4697
5217
  function parseTarget(input, options) {
@@ -4868,15 +5388,21 @@ function registerInspectCommand(cli) {
4868
5388
  if (pallet2.storage.length) {
4869
5389
  console.log(` ${BOLD}Storage Items:${RESET}`);
4870
5390
  for (const s of pallet2.storage) {
4871
- const valueType = describeType(meta.lookup, s.valueTypeId);
4872
- let typeSuffix;
4873
- if (s.keyTypeId != null) {
4874
- const keyType = describeType(meta.lookup, s.keyTypeId);
4875
- typeSuffix = `: ${keyType} → ${valueType} [map]`;
4876
- } else {
4877
- typeSuffix = `: ${valueType}`;
5391
+ const isMap = s.keyTypeId != null;
5392
+ const tag = isMap ? `${DIM} [map]${RESET}` : "";
5393
+ console.log(` ${CYAN}${s.name}${RESET}${tag}`);
5394
+ if (isMap) {
5395
+ const keyType = prettyTypeById(meta.lookup, s.keyTypeId, {
5396
+ indent: 6,
5397
+ prefix: 7
5398
+ });
5399
+ console.log(` ${DIM}Key:${RESET} ${keyType}`);
4878
5400
  }
4879
- console.log(` ${CYAN}${s.name}${RESET}${DIM}${typeSuffix}${RESET}`);
5401
+ const valueType = prettyTypeById(meta.lookup, s.valueTypeId, {
5402
+ indent: 6,
5403
+ prefix: 7
5404
+ });
5405
+ console.log(` ${DIM}Value:${RESET} ${valueType}`);
4880
5406
  const summary = firstSentence(s.docs);
4881
5407
  if (summary) {
4882
5408
  console.log(` ${DIM}${summary}${RESET}`);
@@ -4887,8 +5413,11 @@ function registerInspectCommand(cli) {
4887
5413
  if (pallet2.constants.length) {
4888
5414
  console.log(` ${BOLD}Constants:${RESET}`);
4889
5415
  for (const c of pallet2.constants) {
4890
- const typeStr = describeType(meta.lookup, c.typeId);
4891
- console.log(` ${CYAN}${c.name}${RESET}${DIM}: ${typeStr}${RESET}`);
5416
+ const typeStr = prettyTypeById(meta.lookup, c.typeId, {
5417
+ indent: 4,
5418
+ prefix: c.name.length + 2
5419
+ });
5420
+ console.log(` ${CYAN}${c.name}${RESET}: ${typeStr}`);
4892
5421
  const summary = firstSentence(c.docs);
4893
5422
  if (summary) {
4894
5423
  console.log(` ${DIM}${summary}${RESET}`);
@@ -4899,8 +5428,11 @@ function registerInspectCommand(cli) {
4899
5428
  if (pallet2.calls.length) {
4900
5429
  console.log(` ${BOLD}Calls:${RESET}`);
4901
5430
  for (const c of pallet2.calls) {
4902
- const args = describeCallArgs(meta, pallet2.name, c.name);
4903
- console.log(` ${CYAN}${c.name}${RESET}${DIM}${args}${RESET}`);
5431
+ const args = prettyCallArgs(meta, pallet2.name, c.name, {
5432
+ indent: 4,
5433
+ prefix: c.name.length
5434
+ });
5435
+ console.log(` ${CYAN}${c.name}${RESET}${args}`);
4904
5436
  const summary = firstSentence(c.docs);
4905
5437
  if (summary) {
4906
5438
  console.log(` ${DIM}${summary}${RESET}`);
@@ -4911,8 +5443,11 @@ function registerInspectCommand(cli) {
4911
5443
  if (pallet2.events.length) {
4912
5444
  console.log(` ${BOLD}Events:${RESET}`);
4913
5445
  for (const e of pallet2.events) {
4914
- const fields = describeEventFields(meta, pallet2.name, e.name);
4915
- console.log(` ${CYAN}${e.name}${RESET}${DIM}${fields}${RESET}`);
5446
+ const fields = prettyEventFields(meta, pallet2.name, e.name, {
5447
+ indent: 4,
5448
+ prefix: e.name.length
5449
+ });
5450
+ console.log(` ${CYAN}${e.name}${RESET}${fields}`);
4916
5451
  const summary = firstSentence(e.docs);
4917
5452
  if (summary) {
4918
5453
  console.log(` ${DIM}${summary}${RESET}`);
@@ -5014,11 +5549,19 @@ function registerInspectCommand(cli) {
5014
5549
  const storageItem = pallet.storage.find((s) => s.name.toLowerCase() === itemName.toLowerCase());
5015
5550
  if (storageItem) {
5016
5551
  printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
5017
- console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
5018
- console.log(` ${BOLD}Value:${RESET} ${describeType(meta.lookup, storageItem.valueTypeId)}`);
5552
+ console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
5019
5553
  if (storageItem.keyTypeId != null) {
5020
- console.log(` ${BOLD}Key:${RESET} ${describeType(meta.lookup, storageItem.keyTypeId)}`);
5554
+ const keyType = prettyTypeById(meta.lookup, storageItem.keyTypeId, {
5555
+ indent: 2,
5556
+ prefix: 7
5557
+ });
5558
+ console.log(` ${BOLD}Key:${RESET} ${keyType}`);
5021
5559
  }
5560
+ const valueType = prettyTypeById(meta.lookup, storageItem.valueTypeId, {
5561
+ indent: 2,
5562
+ prefix: 7
5563
+ });
5564
+ console.log(` ${BOLD}Value:${RESET} ${valueType}`);
5022
5565
  if (storageItem.docs.length) {
5023
5566
  console.log();
5024
5567
  printDocs(storageItem.docs);
@@ -5029,7 +5572,11 @@ function registerInspectCommand(cli) {
5029
5572
  const constantItem = pallet.constants.find((c) => c.name.toLowerCase() === itemName.toLowerCase());
5030
5573
  if (constantItem) {
5031
5574
  printHeading(`${pallet.name}.${constantItem.name} (Constant)`);
5032
- console.log(` ${BOLD}Type:${RESET} ${describeType(meta.lookup, constantItem.typeId)}`);
5575
+ const typeStr = prettyTypeById(meta.lookup, constantItem.typeId, {
5576
+ indent: 2,
5577
+ prefix: 6
5578
+ });
5579
+ console.log(` ${BOLD}Type:${RESET} ${typeStr}`);
5033
5580
  if (constantItem.docs.length) {
5034
5581
  console.log();
5035
5582
  printDocs(constantItem.docs);
@@ -5040,7 +5587,10 @@ function registerInspectCommand(cli) {
5040
5587
  const callItem = pallet.calls.find((c) => c.name.toLowerCase() === itemName.toLowerCase());
5041
5588
  if (callItem) {
5042
5589
  printHeading(`${pallet.name}.${callItem.name} (Call)`);
5043
- const args = describeCallArgs(meta, pallet.name, callItem.name);
5590
+ const args = prettyCallArgs(meta, pallet.name, callItem.name, {
5591
+ indent: 2,
5592
+ prefix: 6
5593
+ });
5044
5594
  console.log(` ${BOLD}Args:${RESET} ${args}`);
5045
5595
  if (callItem.docs.length) {
5046
5596
  console.log();
@@ -5052,7 +5602,10 @@ function registerInspectCommand(cli) {
5052
5602
  const eventItem = pallet.events.find((e) => e.name.toLowerCase() === itemName.toLowerCase());
5053
5603
  if (eventItem) {
5054
5604
  printHeading(`${pallet.name}.${eventItem.name} (Event)`);
5055
- const fields = describeEventFields(meta, pallet.name, eventItem.name);
5605
+ const fields = prettyEventFields(meta, pallet.name, eventItem.name, {
5606
+ indent: 2,
5607
+ prefix: 8
5608
+ });
5056
5609
  console.log(` ${BOLD}Fields:${RESET} ${fields}`);
5057
5610
  if (eventItem.docs.length) {
5058
5611
  console.log();
@@ -5081,6 +5634,56 @@ function registerInspectCommand(cli) {
5081
5634
  });
5082
5635
  }
5083
5636
 
5637
+ // src/commands/metadata.ts
5638
+ init_store();
5639
+ init_client();
5640
+ init_metadata();
5641
+ init_output();
5642
+ init_errors();
5643
+ function buildMetadataPayload(chainName, meta, fingerprint) {
5644
+ return {
5645
+ chain: chainName,
5646
+ runtime: { ...fingerprint ?? {}, metadataVersion: meta.version },
5647
+ pallets: listPallets(meta),
5648
+ runtimeApis: listRuntimeApis(meta),
5649
+ transactionExtensions: getSignedExtensions(meta)
5650
+ };
5651
+ }
5652
+ async function handleMetadata(chain, opts) {
5653
+ const config = await loadConfig();
5654
+ const { name: chainName, chain: chainConfig } = resolveChain(config, chain);
5655
+ let rawBytes;
5656
+ if (opts.cached) {
5657
+ rawBytes = await loadMetadata(chainName);
5658
+ if (!rawBytes) {
5659
+ throw new CliError(`No cached metadata for "${chainName}". Run \`dot chain update ${chainName}\` first, or omit --cached to fetch fresh.`);
5660
+ }
5661
+ } else {
5662
+ const clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
5663
+ try {
5664
+ await fetchMetadataFromChain(clientHandle, chainName);
5665
+ } finally {
5666
+ clientHandle.destroy();
5667
+ }
5668
+ rawBytes = await loadMetadata(chainName);
5669
+ if (!rawBytes) {
5670
+ throw new CliError(`Failed to load metadata for "${chainName}" after fetch.`);
5671
+ }
5672
+ }
5673
+ if (opts.raw) {
5674
+ await writeStdout(`0x${Buffer.from(rawBytes).toString("hex")}
5675
+ `);
5676
+ return;
5677
+ }
5678
+ const meta = parseMetadata(rawBytes);
5679
+ const fingerprint = await loadMetadataFingerprint(chainName);
5680
+ await writeStdout(`${formatJson(buildMetadataPayload(chainName, meta, fingerprint))}
5681
+ `);
5682
+ }
5683
+ function registerMetadataCommand(cli) {
5684
+ cli.command("metadata <chain>", "Fetch chain metadata (decoded JSON; --raw for SCALE hex)").option("--raw", "Print SCALE-encoded metadata bytes as hex instead of decoded JSON").option("--cached", "Use cached metadata instead of fetching fresh from the chain").option("--rpc <url>", "Override RPC endpoint(s)").action((chain, opts) => handleMetadata(chain, opts));
5685
+ }
5686
+
5084
5687
  // src/commands/parachain.ts
5085
5688
  init_accounts();
5086
5689
  init_output();
@@ -5176,6 +5779,7 @@ init_store();
5176
5779
  init_client();
5177
5780
  init_metadata();
5178
5781
  init_output();
5782
+ init_pretty_type();
5179
5783
  init_focused_inspect();
5180
5784
  init_tx();
5181
5785
  async function handleQuery(target, keys, opts) {
@@ -5186,10 +5790,11 @@ async function handleQuery(target, keys, opts) {
5186
5790
  const pallets = listPallets(meta);
5187
5791
  const withStorage = pallets.filter((p) => p.storage.length > 0);
5188
5792
  if (isJsonOutput(opts)) {
5189
- console.log(formatJson({
5793
+ await writeStdout(`${formatJson({
5190
5794
  chain: chainName2,
5191
5795
  pallets: withStorage.map((p) => ({ name: p.name, storage: p.storage.length }))
5192
- }));
5796
+ })}
5797
+ `);
5193
5798
  return;
5194
5799
  }
5195
5800
  printHeading(`Pallets with storage on ${chainName2} (${withStorage.length})`);
@@ -5207,14 +5812,15 @@ async function handleQuery(target, keys, opts) {
5207
5812
  const pallet2 = resolvePallet(meta, palletName(target));
5208
5813
  if (pallet2.storage.length === 0) {
5209
5814
  if (isJsonOutput(opts)) {
5210
- console.log(formatJson({ chain: chainName2, pallet: pallet2.name, storage: [] }));
5815
+ await writeStdout(`${formatJson({ chain: chainName2, pallet: pallet2.name, storage: [] })}
5816
+ `);
5211
5817
  } else {
5212
5818
  console.log(`No storage items in ${pallet2.name}.`);
5213
5819
  }
5214
5820
  return;
5215
5821
  }
5216
5822
  if (isJsonOutput(opts)) {
5217
- console.log(formatJson({
5823
+ await writeStdout(`${formatJson({
5218
5824
  chain: chainName2,
5219
5825
  pallet: pallet2.name,
5220
5826
  storage: pallet2.storage.map((s) => {
@@ -5222,20 +5828,27 @@ async function handleQuery(target, keys, opts) {
5222
5828
  const keyType = s.keyTypeId != null ? describeType(meta.lookup, s.keyTypeId) : undefined;
5223
5829
  return { name: s.name, type: s.type, valueType, keyType, docs: firstSentence(s.docs) };
5224
5830
  })
5225
- }));
5831
+ })}
5832
+ `);
5226
5833
  return;
5227
5834
  }
5228
5835
  printHeading(`${pallet2.name} Storage`);
5229
5836
  for (const s of pallet2.storage) {
5230
- const valueType = describeType(meta.lookup, s.valueTypeId);
5231
- let typeSuffix;
5232
- if (s.keyTypeId != null) {
5233
- const keyType = describeType(meta.lookup, s.keyTypeId);
5234
- typeSuffix = `: ${keyType} → ${valueType} [map]`;
5235
- } else {
5236
- typeSuffix = `: ${valueType}`;
5837
+ const isMap = s.keyTypeId != null;
5838
+ const tag = isMap ? `${DIM} [map]${RESET}` : "";
5839
+ console.log(` ${CYAN}${s.name}${RESET}${tag}`);
5840
+ if (isMap) {
5841
+ const keyType = prettyTypeById(meta.lookup, s.keyTypeId, {
5842
+ indent: 4,
5843
+ prefix: 5
5844
+ });
5845
+ console.log(` ${DIM}Key:${RESET} ${keyType}`);
5237
5846
  }
5238
- console.log(` ${CYAN}${s.name}${RESET}${DIM}${typeSuffix}${RESET}`);
5847
+ const valueType = prettyTypeById(meta.lookup, s.valueTypeId, {
5848
+ indent: 4,
5849
+ prefix: 7
5850
+ });
5851
+ console.log(` ${DIM}Value:${RESET} ${valueType}`);
5239
5852
  const summary = firstSentence(s.docs);
5240
5853
  if (summary) {
5241
5854
  console.log(` ${DIM}${summary}${RESET}`);
@@ -5276,14 +5889,19 @@ async function handleQuery(target, keys, opts) {
5276
5889
  console.log(`${DIM}Hint: use --dump to fetch all entries${RESET}`);
5277
5890
  return;
5278
5891
  }
5279
- const entries = await storageApi.getEntries(...parsedKeys);
5280
- printResult(entries.map((e) => ({
5892
+ const entries = await withStalenessSuggestion(chainName, clientHandle, () => storageApi.getEntries(...parsedKeys));
5893
+ const rows = entries.map((e) => ({
5281
5894
  keys: e.keyArgs,
5282
5895
  value: e.value
5283
- })), format);
5896
+ }));
5897
+ const text = format === "json" ? formatJson(rows) : formatPretty(rows);
5898
+ await writeStdout(`${text}
5899
+ `);
5284
5900
  } else {
5285
- const result = await storageApi.getValue(...parsedKeys);
5286
- printResult(result, format);
5901
+ const result = await withStalenessSuggestion(chainName, clientHandle, () => storageApi.getValue(...parsedKeys));
5902
+ const text = format === "json" ? formatJson(result) : formatPretty(result);
5903
+ await writeStdout(`${text}
5904
+ `);
5287
5905
  }
5288
5906
  } finally {
5289
5907
  clientHandle.destroy();
@@ -5430,6 +6048,7 @@ init_accounts();
5430
6048
  init_client();
5431
6049
  init_metadata();
5432
6050
  init_output();
6051
+ init_pretty_type();
5433
6052
  init_resolve_address();
5434
6053
  init_binary_display();
5435
6054
  init_errors();
@@ -5562,8 +6181,11 @@ async function handleTx(target, args, opts) {
5562
6181
  }
5563
6182
  printHeading(`${pallet2.name} Calls`);
5564
6183
  for (const c of pallet2.calls) {
5565
- const callArgs = describeCallArgs(meta, pallet2.name, c.name);
5566
- console.log(` ${CYAN}${c.name}${RESET}${DIM}${callArgs}${RESET}`);
6184
+ const callArgs = prettyCallArgs(meta, pallet2.name, c.name, {
6185
+ indent: 2,
6186
+ prefix: c.name.length
6187
+ });
6188
+ console.log(` ${CYAN}${c.name}${RESET}${callArgs}`);
5567
6189
  const summary = firstSentence(c.docs);
5568
6190
  if (summary) {
5569
6191
  console.log(` ${DIM}${summary}${RESET}`);
@@ -5714,6 +6336,7 @@ async function handleTx(target, args, opts) {
5714
6336
  callHex = Binary3.toHex(encodedCall);
5715
6337
  }
5716
6338
  const decodedStr = decodeCall(meta, callHex);
6339
+ const decodedObj = decodeCallObject(meta, callHex);
5717
6340
  if (opts.dryRun && opts.unsigned) {
5718
6341
  if (isJsonOutput(opts)) {
5719
6342
  console.log(formatJson({
@@ -5728,17 +6351,18 @@ async function handleTx(target, args, opts) {
5728
6351
  console.log(` ${BOLD}Chain:${RESET} ${chainName}`);
5729
6352
  console.log(` ${BOLD}Type:${RESET} unsigned (bare)`);
5730
6353
  console.log(` ${BOLD}Call:${RESET} ${callHex}`);
5731
- console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
6354
+ printDecodedCall(decodedObj, decodedStr);
5732
6355
  console.log(` ${BOLD}Fees:${RESET} ${DIM}N/A (unsigned transaction)${RESET}`);
5733
6356
  return;
5734
6357
  }
5735
6358
  if (opts.dryRun) {
5736
6359
  const signerAddress = toSs58(signer.publicKey);
5737
6360
  let estimatedFees;
6361
+ let estimationError;
5738
6362
  try {
5739
- estimatedFees = String(await tx.getEstimatedFees(signer?.publicKey, txOptions));
5740
- } catch {
5741
- estimatedFees = undefined;
6363
+ estimatedFees = String(await withStalenessSuggestion(chainName, clientHandle, () => tx.getEstimatedFees(signer?.publicKey, txOptions)));
6364
+ } catch (err) {
6365
+ estimationError = err instanceof Error ? err.message : String(err);
5742
6366
  }
5743
6367
  if (isJsonOutput(opts)) {
5744
6368
  const result2 = {
@@ -5748,6 +6372,8 @@ async function handleTx(target, args, opts) {
5748
6372
  decoded: decodedStr,
5749
6373
  estimatedFees
5750
6374
  };
6375
+ if (estimationError !== undefined)
6376
+ result2.estimationError = estimationError;
5751
6377
  if (nonce !== undefined)
5752
6378
  result2.nonce = nonce;
5753
6379
  if (tip !== undefined)
@@ -5764,7 +6390,7 @@ async function handleTx(target, args, opts) {
5764
6390
  console.log(` ${BOLD}Chain:${RESET} ${chainName}`);
5765
6391
  console.log(` ${BOLD}From:${RESET} ${opts.from} (${signerAddress})`);
5766
6392
  console.log(` ${BOLD}Call:${RESET} ${callHex}`);
5767
- console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
6393
+ printDecodedCall(decodedObj, decodedStr);
5768
6394
  if (nonce !== undefined)
5769
6395
  console.log(` ${BOLD}Nonce:${RESET} ${nonce}`);
5770
6396
  if (tip !== undefined)
@@ -5779,6 +6405,12 @@ async function handleTx(target, args, opts) {
5779
6405
  console.log(` ${BOLD}Estimated fees:${RESET} ${estimatedFees}`);
5780
6406
  } else {
5781
6407
  console.log(` ${BOLD}Estimated fees:${RESET} ${YELLOW}unable to estimate${RESET}`);
6408
+ if (estimationError) {
6409
+ const formatted = formatRuntimeError(estimationError).replace(/\n/g, `
6410
+ `);
6411
+ console.log(` ${YELLOW}⚠${RESET} ${formatted}`);
6412
+ console.log(` ${DIM}Submitting this transaction is likely to fail.${RESET}`);
6413
+ }
5782
6414
  }
5783
6415
  return;
5784
6416
  }
@@ -5798,7 +6430,7 @@ async function handleTx(target, args, opts) {
5798
6430
  }
5799
6431
  const observable = clientHandle.client.submitAndWatch(generalTx, at);
5800
6432
  if (isJsonOutput(opts)) {
5801
- const result3 = await watchTransactionJson(observable, waitLevel, { unsigned: true });
6433
+ const result3 = await withStalenessSuggestion(chainName, clientHandle, () => watchTransactionJson(observable, waitLevel, { unsigned: true }));
5802
6434
  const rpcUrl3 = primaryRpc(opts.rpc ?? chainConfig.rpc);
5803
6435
  if (result3.type === "broadcasted") {
5804
6436
  printJsonLine({ event: "broadcasted", txHash: result3.txHash });
@@ -5830,12 +6462,12 @@ async function handleTx(target, args, opts) {
5830
6462
  }
5831
6463
  return;
5832
6464
  }
5833
- const result2 = await watchTransaction(observable, waitLevel, { unsigned: true });
6465
+ const result2 = await withStalenessSuggestion(chainName, clientHandle, () => watchTransaction(observable, waitLevel, { unsigned: true }));
5834
6466
  console.log();
5835
6467
  console.log(` ${BOLD}Chain:${RESET} ${chainName}`);
5836
6468
  console.log(` ${BOLD}Type:${RESET} unsigned (bare)`);
5837
6469
  console.log(` ${BOLD}Call:${RESET} ${callHex}`);
5838
- console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
6470
+ printDecodedCall(decodedObj, decodedStr);
5839
6471
  console.log(` ${BOLD}Tx:${RESET} ${result2.txHash}`);
5840
6472
  if (result2.type === "broadcasted") {
5841
6473
  console.log(` ${BOLD}Status:${RESET} ${GREEN}broadcasted${RESET}`);
@@ -5879,7 +6511,7 @@ async function handleTx(target, args, opts) {
5879
6511
  return;
5880
6512
  }
5881
6513
  if (isJsonOutput(opts)) {
5882
- const result2 = await watchTransactionJson(tx.signSubmitAndWatch(signer, txOptions), waitLevel);
6514
+ const result2 = await withStalenessSuggestion(chainName, clientHandle, () => watchTransactionJson(tx.signSubmitAndWatch(signer, txOptions), waitLevel));
5883
6515
  const rpcUrl2 = primaryRpc(opts.rpc ?? chainConfig.rpc);
5884
6516
  if (result2.type === "broadcasted") {
5885
6517
  printJsonLine({ event: "broadcasted", txHash: result2.txHash });
@@ -5910,11 +6542,11 @@ async function handleTx(target, args, opts) {
5910
6542
  }
5911
6543
  return;
5912
6544
  }
5913
- const result = await watchTransaction(tx.signSubmitAndWatch(signer, txOptions), waitLevel);
6545
+ const result = await withStalenessSuggestion(chainName, clientHandle, () => watchTransaction(tx.signSubmitAndWatch(signer, txOptions), waitLevel));
5914
6546
  console.log();
5915
6547
  console.log(` ${BOLD}Chain:${RESET} ${chainName}`);
5916
6548
  console.log(` ${BOLD}Call:${RESET} ${callHex}`);
5917
- console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
6549
+ printDecodedCall(decodedObj, decodedStr);
5918
6550
  if (nonce !== undefined)
5919
6551
  console.log(` ${BOLD}Nonce:${RESET} ${nonce}`);
5920
6552
  if (tip !== undefined)
@@ -6001,6 +6633,39 @@ function decodeCall(meta, callHex) {
6001
6633
  return "(unable to decode)";
6002
6634
  }
6003
6635
  }
6636
+ function decodeCallObject(meta, callHex) {
6637
+ try {
6638
+ const callTypeId = meta.lookup.call;
6639
+ if (callTypeId == null)
6640
+ return null;
6641
+ const codec = meta.builder.buildDefinition(callTypeId);
6642
+ const decoded = codec.dec(Binary3.fromHex(callHex));
6643
+ return {
6644
+ palletName: decoded.type,
6645
+ callName: decoded.value.type,
6646
+ args: sanitizeForSerialization(decoded.value.value)
6647
+ };
6648
+ } catch {
6649
+ return null;
6650
+ }
6651
+ }
6652
+ function printDecodedCall(obj, fallback) {
6653
+ if (!obj) {
6654
+ console.log(` ${BOLD}Decode:${RESET} ${fallback}`);
6655
+ return;
6656
+ }
6657
+ const header = `${CYAN}${obj.palletName}${RESET}.${CYAN}${obj.callName}${RESET}`;
6658
+ const hasArgs = obj.args !== null && obj.args !== undefined && !(typeof obj.args === "object" && Object.keys(obj.args).length === 0);
6659
+ if (!hasArgs) {
6660
+ console.log(` ${BOLD}Decode:${RESET} ${header}`);
6661
+ return;
6662
+ }
6663
+ console.log(` ${BOLD}Decode:${RESET} ${header}`);
6664
+ const indented = formatPretty(obj.args).split(`
6665
+ `).map((l) => ` ${l}`).join(`
6666
+ `);
6667
+ console.log(indented);
6668
+ }
6004
6669
  function decodeCallFallback(meta, callHex) {
6005
6670
  const callTypeId = meta.lookup.call;
6006
6671
  if (callTypeId == null)
@@ -7144,13 +7809,13 @@ function isNewerVersion(current, latest) {
7144
7809
  return compareSemver(current, latest) < 0;
7145
7810
  }
7146
7811
  function buildNotificationBox(current, latest) {
7147
- const YELLOW2 = "\x1B[33m";
7148
- const GREEN2 = "\x1B[32m";
7149
- const CYAN2 = "\x1B[36m";
7150
- const RESET2 = "\x1B[0m";
7812
+ const YELLOW3 = "\x1B[33m";
7813
+ const GREEN3 = "\x1B[32m";
7814
+ const CYAN3 = "\x1B[36m";
7815
+ const RESET3 = "\x1B[0m";
7151
7816
  const BOLD2 = "\x1B[1m";
7152
- const line1 = `Update available! ${YELLOW2}${current}${RESET2} → ${GREEN2}${BOLD2}${latest}${RESET2}`;
7153
- const line2 = `Run ${CYAN2}npm i -g polkadot-cli${RESET2} to update`;
7817
+ const line1 = `Update available! ${YELLOW3}${current}${RESET3} → ${GREEN3}${BOLD2}${latest}${RESET3}`;
7818
+ const line2 = `Run ${CYAN3}npm i -g polkadot-cli${RESET3} to update`;
7154
7819
  const visibleLine1 = `Update available! ${current} → ${latest}`;
7155
7820
  const visibleLine2 = `Run npm i -g polkadot-cli to update`;
7156
7821
  const innerWidth = Math.max(visibleLine1.length, visibleLine2.length) + 4;
@@ -7237,6 +7902,34 @@ class CliError2 extends Error {
7237
7902
  this.name = "CliError";
7238
7903
  }
7239
7904
  }
7905
+ var PAPI_CLEANUP_PATTERNS = [
7906
+ /^Not connected$/,
7907
+ /DisjointError/,
7908
+ /ChainHead.*(aborted|stopped)/i
7909
+ ];
7910
+ function isPapiCleanupError(err) {
7911
+ if (!(err instanceof Error))
7912
+ return false;
7913
+ return PAPI_CLEANUP_PATTERNS.some((re) => re.test(err.message));
7914
+ }
7915
+ function formatRuntimeError2(err) {
7916
+ const msg = err instanceof Error ? err.message : String(err);
7917
+ if (/wasm trap|wasm `?unreachable`? instruction|Execution aborted due to trap/i.test(msg)) {
7918
+ const frames = Array.from(msg.matchAll(/\.wasm!([A-Za-z_]\w+)/g)).map((m) => m[1]);
7919
+ const fn = [...frames].reverse().find((name) => !/^(?:__rustc|core::panicking|rust_begin_unwind|panic_fmt)/.test(name));
7920
+ const where = fn?.includes("validate_transaction") ? "the runtime's validate_transaction step" : fn ? `runtime function ${fn}` : "the runtime";
7921
+ return [
7922
+ `The runtime rejected this transaction in ${where}.`,
7923
+ " Cause: a runtime invariant failed — typically the call's arguments are out of range, reference an unknown id, or violate a precondition.",
7924
+ " Tip: re-check the arguments and the signing account's permissions; --dry-run will surface the same error before signing."
7925
+ ].join(`
7926
+ `);
7927
+ }
7928
+ if (/Invalid Transaction/i.test(msg)) {
7929
+ return `Transaction rejected as invalid by the runtime: ${msg}`;
7930
+ }
7931
+ return msg;
7932
+ }
7240
7933
 
7241
7934
  // src/utils/parse-dot-path.ts
7242
7935
  var CATEGORY_ALIASES = {
@@ -7359,6 +8052,7 @@ if (process.argv[2] === "__complete") {
7359
8052
  console.log(" dot polkadot.const.Balances.ExistentialDeposit");
7360
8053
  console.log(" dot polkadot.events.Balances List events in Balances");
7361
8054
  console.log(" dot polkadot.apis.Core.version Call a runtime API");
8055
+ console.log(" dot metadata polkadot Dump runtime metadata as JSON");
7362
8056
  console.log(" dot polkadot.extensions List transaction extensions");
7363
8057
  console.log(" dot polkadot.extensions.CheckMortality Inspect one extension");
7364
8058
  console.log(" dot query.System.Number --chain polkadot --chain flag form");
@@ -7369,6 +8063,7 @@ if (process.argv[2] === "__complete") {
7369
8063
  console.log();
7370
8064
  console.log("Commands:");
7371
8065
  console.log(" inspect [target] Inspect chain metadata (alias: explore)");
8066
+ console.log(" metadata <chain> Dump runtime metadata as JSON (--raw for SCALE hex)");
7372
8067
  console.log(" chain Manage chain configurations");
7373
8068
  console.log(" account Manage accounts");
7374
8069
  console.log(" hash Hash utilities");
@@ -7395,6 +8090,7 @@ if (process.argv[2] === "__complete") {
7395
8090
  cli.option("--json", "Output as JSON (shorthand for --output json)");
7396
8091
  registerChainCommands(cli);
7397
8092
  registerInspectCommand(cli);
8093
+ registerMetadataCommand(cli);
7398
8094
  registerAccountCommands(cli);
7399
8095
  registerHashCommand(cli);
7400
8096
  registerSignCommand(cli);
@@ -7551,12 +8247,18 @@ if (process.argv[2] === "__complete") {
7551
8247
  if (err instanceof CliError2) {
7552
8248
  console.error(`Error: ${err.message}`);
7553
8249
  } else if (err instanceof Error) {
7554
- console.error(`Error: ${err.message}`);
8250
+ console.error(`Error: ${formatRuntimeError2(err)}`);
7555
8251
  } else {
7556
8252
  console.error("An unexpected error occurred:", err);
7557
8253
  }
7558
8254
  return showUpdateAndExit(1);
7559
8255
  }
8256
+ process.on("unhandledRejection", (reason) => {
8257
+ if (isPapiCleanupError(reason))
8258
+ return;
8259
+ console.error(`Error: ${formatRuntimeError2(reason)}`);
8260
+ process.exit(1);
8261
+ });
7560
8262
  async function main() {
7561
8263
  try {
7562
8264
  cli.parse(process.argv, { run: false });