polkadot-cli 0.14.0 → 1.1.1

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 +22 -0
  2. package/dist/cli.mjs +1250 -543
  3. package/package.json +4 -2
package/dist/cli.mjs CHANGED
@@ -5,7 +5,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
5
5
  // src/cli.ts
6
6
  import cac from "cac";
7
7
  // package.json
8
- var version = "0.14.0";
8
+ var version = "1.1.1";
9
9
 
10
10
  // src/config/accounts-store.ts
11
11
  import { access as access2, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
@@ -830,6 +830,7 @@ async function accountInspect(input, opts) {
830
830
  import { createClient } from "polkadot-api";
831
831
  import { withPolkadotSdkCompat } from "polkadot-api/polkadot-sdk-compat";
832
832
  import { getWsProvider } from "polkadot-api/ws-provider";
833
+ import { WebSocket } from "ws";
833
834
 
834
835
  // src/utils/errors.ts
835
836
  class CliError extends Error {
@@ -891,7 +892,10 @@ async function createChainClient(chainName, chainConfig, rpcOverride) {
891
892
  restoreConsole();
892
893
  throw new ConnectionError(`No RPC endpoint configured for chain "${chainName}". Use --rpc or configure one with: dot chain add ${chainName} --rpc <url>`);
893
894
  }
894
- provider = withPolkadotSdkCompat(getWsProvider(rpc, { timeout: 1e4 }));
895
+ provider = withPolkadotSdkCompat(getWsProvider(rpc, {
896
+ timeout: 1e4,
897
+ websocketClass: WebSocket
898
+ }));
895
899
  }
896
900
  const client = createClient(provider, {
897
901
  getMetadata: async () => loadMetadata(chainName),
@@ -1333,135 +1337,450 @@ function suggestMessage(kind, input, candidates) {
1333
1337
  return `Unknown ${kind} "${input}". Did you mean: ${suggestions.join(", ")}?`;
1334
1338
  }
1335
1339
 
1336
- // src/utils/parse-target.ts
1337
- function parseTarget(input, options) {
1338
- const parts = input.split(".");
1339
- if (options?.allowPalletOnly) {
1340
- switch (parts.length) {
1341
- case 1:
1342
- if (!parts[0]) {
1343
- throw new Error(`Invalid target "${input}". Expected format: Pallet or Pallet.Item (e.g. System or System.Account)`);
1344
- }
1345
- return { pallet: parts[0] };
1346
- case 2:
1347
- if (!parts[0] || !parts[1]) {
1348
- throw new Error(`Invalid target "${input}". Expected format: Pallet.Item or Chain.Pallet (e.g. System.Account or kusama.System)`);
1349
- }
1350
- if (options.knownChains?.some((c) => c.toLowerCase() === parts[0].toLowerCase())) {
1351
- return { chain: parts[0], pallet: parts[1] };
1352
- }
1353
- return { pallet: parts[0], item: parts[1] };
1354
- case 3:
1355
- if (!parts[0] || !parts[1] || !parts[2]) {
1356
- throw new Error(`Invalid target "${input}". Expected format: Chain.Pallet.Item (e.g. kusama.System.Account)`);
1357
- }
1358
- return { chain: parts[0], pallet: parts[1], item: parts[2] };
1359
- default:
1360
- throw new Error(`Invalid target "${input}". Expected format: Pallet, Pallet.Item, or Chain.Pallet.Item`);
1340
+ // src/commands/focused-inspect.ts
1341
+ async function loadMeta(chainName, chainConfig, rpcOverride) {
1342
+ try {
1343
+ return await getOrFetchMetadata(chainName);
1344
+ } catch {
1345
+ console.error(`Fetching metadata from ${chainName}...`);
1346
+ const clientHandle = await createChainClient(chainName, chainConfig, rpcOverride);
1347
+ try {
1348
+ return await getOrFetchMetadata(chainName, clientHandle);
1349
+ } finally {
1350
+ clientHandle.destroy();
1361
1351
  }
1362
1352
  }
1363
- switch (parts.length) {
1364
- case 2:
1365
- if (!parts[0] || !parts[1]) {
1366
- throw new Error(`Invalid target "${input}". Expected format: Pallet.Item (e.g. System.Account)`);
1353
+ }
1354
+ function resolvePallet(meta, palletName) {
1355
+ const palletNames = getPalletNames(meta);
1356
+ const pallet = findPallet(meta, palletName);
1357
+ if (!pallet) {
1358
+ throw new Error(suggestMessage("pallet", palletName, palletNames));
1359
+ }
1360
+ return pallet;
1361
+ }
1362
+ async function handleCalls(target, opts) {
1363
+ if (!target) {
1364
+ const config2 = await loadConfig();
1365
+ const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
1366
+ const meta2 = await loadMeta(chainName2, chainConfig2, opts.rpc);
1367
+ const pallets = listPallets(meta2);
1368
+ const withCalls = pallets.filter((p) => p.calls.length > 0);
1369
+ printHeading(`Pallets with calls on ${chainName2} (${withCalls.length})`);
1370
+ for (const p of withCalls) {
1371
+ printItem(p.name, `${p.calls.length} calls`);
1372
+ }
1373
+ console.log();
1374
+ return;
1375
+ }
1376
+ const config = await loadConfig();
1377
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
1378
+ const meta = await loadMeta(chainName, chainConfig, opts.rpc);
1379
+ const dotIdx = target.indexOf(".");
1380
+ const palletName = dotIdx === -1 ? target : target.slice(0, dotIdx);
1381
+ const itemName = dotIdx === -1 ? undefined : target.slice(dotIdx + 1);
1382
+ const pallet = resolvePallet(meta, palletName);
1383
+ if (!itemName) {
1384
+ if (pallet.calls.length === 0) {
1385
+ console.log(`No calls in ${pallet.name}.`);
1386
+ return;
1387
+ }
1388
+ printHeading(`${pallet.name} Calls`);
1389
+ for (const c of pallet.calls) {
1390
+ const args2 = describeCallArgs(meta, pallet.name, c.name);
1391
+ console.log(` ${CYAN}${c.name}${RESET}${DIM}${args2}${RESET}`);
1392
+ const summary = firstSentence(c.docs);
1393
+ if (summary) {
1394
+ console.log(` ${DIM}${summary}${RESET}`);
1367
1395
  }
1368
- return { pallet: parts[0], item: parts[1] };
1369
- case 3:
1370
- if (!parts[0] || !parts[1] || !parts[2]) {
1371
- throw new Error(`Invalid target "${input}". Expected format: Chain.Pallet.Item (e.g. kusama.System.Account)`);
1396
+ }
1397
+ console.log();
1398
+ return;
1399
+ }
1400
+ const callItem = pallet.calls.find((c) => c.name.toLowerCase() === itemName.toLowerCase());
1401
+ if (!callItem) {
1402
+ const names = pallet.calls.map((c) => c.name);
1403
+ throw new Error(suggestMessage(`call in ${pallet.name}`, itemName, names));
1404
+ }
1405
+ printHeading(`${pallet.name}.${callItem.name} (Call)`);
1406
+ const args = describeCallArgs(meta, pallet.name, callItem.name);
1407
+ console.log(` ${BOLD}Args:${RESET} ${args}`);
1408
+ if (callItem.docs.length) {
1409
+ console.log();
1410
+ printDocs(callItem.docs);
1411
+ }
1412
+ console.log();
1413
+ }
1414
+ async function handleEvents(target, opts) {
1415
+ if (!target) {
1416
+ const config2 = await loadConfig();
1417
+ const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
1418
+ const meta2 = await loadMeta(chainName2, chainConfig2, opts.rpc);
1419
+ const pallets = listPallets(meta2);
1420
+ const withEvents = pallets.filter((p) => p.events.length > 0);
1421
+ printHeading(`Pallets with events on ${chainName2} (${withEvents.length})`);
1422
+ for (const p of withEvents) {
1423
+ printItem(p.name, `${p.events.length} events`);
1424
+ }
1425
+ console.log();
1426
+ return;
1427
+ }
1428
+ const config = await loadConfig();
1429
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
1430
+ const meta = await loadMeta(chainName, chainConfig, opts.rpc);
1431
+ const dotIdx = target.indexOf(".");
1432
+ const palletName = dotIdx === -1 ? target : target.slice(0, dotIdx);
1433
+ const itemName = dotIdx === -1 ? undefined : target.slice(dotIdx + 1);
1434
+ const pallet = resolvePallet(meta, palletName);
1435
+ if (!itemName) {
1436
+ if (pallet.events.length === 0) {
1437
+ console.log(`No events in ${pallet.name}.`);
1438
+ return;
1439
+ }
1440
+ printHeading(`${pallet.name} Events`);
1441
+ for (const e of pallet.events) {
1442
+ const fields2 = describeEventFields(meta, pallet.name, e.name);
1443
+ console.log(` ${CYAN}${e.name}${RESET}${DIM}${fields2}${RESET}`);
1444
+ const summary = firstSentence(e.docs);
1445
+ if (summary) {
1446
+ console.log(` ${DIM}${summary}${RESET}`);
1372
1447
  }
1373
- return { chain: parts[0], pallet: parts[1], item: parts[2] };
1374
- default:
1375
- throw new Error(`Invalid target "${input}". Expected format: Pallet.Item (e.g. System.Account)`);
1448
+ }
1449
+ console.log();
1450
+ return;
1376
1451
  }
1452
+ const eventItem = pallet.events.find((e) => e.name.toLowerCase() === itemName.toLowerCase());
1453
+ if (!eventItem) {
1454
+ const names = pallet.events.map((e) => e.name);
1455
+ throw new Error(suggestMessage(`event in ${pallet.name}`, itemName, names));
1456
+ }
1457
+ printHeading(`${pallet.name}.${eventItem.name} (Event)`);
1458
+ const fields = describeEventFields(meta, pallet.name, eventItem.name);
1459
+ console.log(` ${BOLD}Fields:${RESET} ${fields}`);
1460
+ if (eventItem.docs.length) {
1461
+ console.log();
1462
+ printDocs(eventItem.docs);
1463
+ }
1464
+ console.log();
1377
1465
  }
1378
- function resolveTargetChain(target, chainFlag) {
1379
- if (target.chain && chainFlag) {
1380
- throw new Error(`Chain specified both as prefix ("${target.chain}") and as --chain flag ("${chainFlag}"). Use one or the other.`);
1466
+ async function handleErrors(target, opts) {
1467
+ if (!target) {
1468
+ const config2 = await loadConfig();
1469
+ const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
1470
+ const meta2 = await loadMeta(chainName2, chainConfig2, opts.rpc);
1471
+ const pallets = listPallets(meta2);
1472
+ const withErrors = pallets.filter((p) => p.errors.length > 0);
1473
+ printHeading(`Pallets with errors on ${chainName2} (${withErrors.length})`);
1474
+ for (const p of withErrors) {
1475
+ printItem(p.name, `${p.errors.length} errors`);
1476
+ }
1477
+ console.log();
1478
+ return;
1381
1479
  }
1382
- return target.chain ?? chainFlag;
1480
+ const config = await loadConfig();
1481
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
1482
+ const meta = await loadMeta(chainName, chainConfig, opts.rpc);
1483
+ const dotIdx = target.indexOf(".");
1484
+ const palletName = dotIdx === -1 ? target : target.slice(0, dotIdx);
1485
+ const itemName = dotIdx === -1 ? undefined : target.slice(dotIdx + 1);
1486
+ const pallet = resolvePallet(meta, palletName);
1487
+ if (!itemName) {
1488
+ if (pallet.errors.length === 0) {
1489
+ console.log(`No errors in ${pallet.name}.`);
1490
+ return;
1491
+ }
1492
+ printHeading(`${pallet.name} Errors`);
1493
+ for (const e of pallet.errors) {
1494
+ console.log(` ${CYAN}${e.name}${RESET}`);
1495
+ const summary = firstSentence(e.docs);
1496
+ if (summary) {
1497
+ console.log(` ${DIM}${summary}${RESET}`);
1498
+ }
1499
+ }
1500
+ console.log();
1501
+ return;
1502
+ }
1503
+ const errorItem = pallet.errors.find((e) => e.name.toLowerCase() === itemName.toLowerCase());
1504
+ if (!errorItem) {
1505
+ const names = pallet.errors.map((e) => e.name);
1506
+ throw new Error(suggestMessage(`error in ${pallet.name}`, itemName, names));
1507
+ }
1508
+ printHeading(`${pallet.name}.${errorItem.name} (Error)`);
1509
+ if (errorItem.docs.length) {
1510
+ printDocs(errorItem.docs);
1511
+ }
1512
+ console.log();
1383
1513
  }
1384
-
1385
- // src/commands/const.ts
1386
- function registerConstCommand(cli) {
1387
- cli.command("const [target]", "Look up or list pallet constants (e.g. Balances.ExistentialDeposit)").alias("consts").alias("constants").action(async (target, opts) => {
1388
- if (!target) {
1389
- console.log("Usage: dot const <[Chain.]Pallet[.Constant]> [--chain <name>] [--output json]");
1390
- console.log("");
1391
- console.log("Examples:");
1392
- console.log(" $ dot const Balances # list constants");
1393
- console.log(" $ dot const Balances.ExistentialDeposit # look up value");
1394
- console.log(" $ dot const System.SS58Prefix --chain kusama");
1395
- console.log(" $ dot const kusama.Balances.ExistentialDeposit # chain prefix");
1514
+ async function handleStorage(target, opts) {
1515
+ if (!target) {
1516
+ const config2 = await loadConfig();
1517
+ const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
1518
+ const meta2 = await loadMeta(chainName2, chainConfig2, opts.rpc);
1519
+ const pallets = listPallets(meta2);
1520
+ const withStorage = pallets.filter((p) => p.storage.length > 0);
1521
+ printHeading(`Pallets with storage on ${chainName2} (${withStorage.length})`);
1522
+ for (const p of withStorage) {
1523
+ printItem(p.name, `${p.storage.length} storage`);
1524
+ }
1525
+ console.log();
1526
+ return;
1527
+ }
1528
+ const config = await loadConfig();
1529
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
1530
+ const meta = await loadMeta(chainName, chainConfig, opts.rpc);
1531
+ const dotIdx = target.indexOf(".");
1532
+ const palletName = dotIdx === -1 ? target : target.slice(0, dotIdx);
1533
+ const itemName = dotIdx === -1 ? undefined : target.slice(dotIdx + 1);
1534
+ const pallet = resolvePallet(meta, palletName);
1535
+ if (!itemName) {
1536
+ if (pallet.storage.length === 0) {
1537
+ console.log(`No storage items in ${pallet.name}.`);
1396
1538
  return;
1397
1539
  }
1398
- const config = await loadConfig();
1399
- const knownChains = Object.keys(config.chains);
1400
- const parsed = parseTarget(target, { knownChains, allowPalletOnly: true });
1401
- const effectiveChain = resolveTargetChain(parsed, opts.chain);
1402
- const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
1403
- const pallet = parsed.pallet;
1404
- const item = parsed.item;
1405
- if (!item) {
1406
- let meta;
1407
- try {
1408
- meta = await getOrFetchMetadata(chainName);
1409
- } catch {
1410
- console.error(`Fetching metadata from ${chainName}...`);
1411
- const clientHandle2 = await createChainClient(chainName, chainConfig, opts.rpc);
1412
- try {
1413
- meta = await getOrFetchMetadata(chainName, clientHandle2);
1414
- } finally {
1415
- clientHandle2.destroy();
1416
- }
1540
+ printHeading(`${pallet.name} Storage`);
1541
+ for (const s of pallet.storage) {
1542
+ const valueType = describeType(meta.lookup, s.valueTypeId);
1543
+ let typeSuffix;
1544
+ if (s.keyTypeId != null) {
1545
+ const keyType = describeType(meta.lookup, s.keyTypeId);
1546
+ typeSuffix = `: ${keyType} → ${valueType} [map]`;
1547
+ } else {
1548
+ typeSuffix = `: ${valueType}`;
1417
1549
  }
1418
- const palletNames = getPalletNames(meta);
1419
- const palletInfo = findPallet(meta, pallet);
1420
- if (!palletInfo) {
1421
- throw new Error(suggestMessage("pallet", pallet, palletNames));
1550
+ console.log(` ${CYAN}${s.name}${RESET}${DIM}${typeSuffix}${RESET}`);
1551
+ const summary = firstSentence(s.docs);
1552
+ if (summary) {
1553
+ console.log(` ${DIM}${summary}${RESET}`);
1422
1554
  }
1423
- if (palletInfo.constants.length === 0) {
1424
- console.log(`No constants in ${palletInfo.name}.`);
1555
+ }
1556
+ console.log();
1557
+ return;
1558
+ }
1559
+ const storageItem = pallet.storage.find((s) => s.name.toLowerCase() === itemName.toLowerCase());
1560
+ if (!storageItem) {
1561
+ const names = pallet.storage.map((s) => s.name);
1562
+ throw new Error(suggestMessage(`storage item in ${pallet.name}`, itemName, names));
1563
+ }
1564
+ printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
1565
+ console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
1566
+ console.log(` ${BOLD}Value:${RESET} ${describeType(meta.lookup, storageItem.valueTypeId)}`);
1567
+ if (storageItem.keyTypeId != null) {
1568
+ console.log(` ${BOLD}Key:${RESET} ${describeType(meta.lookup, storageItem.keyTypeId)}`);
1569
+ }
1570
+ if (storageItem.docs.length) {
1571
+ console.log();
1572
+ printDocs(storageItem.docs);
1573
+ }
1574
+ console.log();
1575
+ }
1576
+ async function showItemHelp(category, target, opts) {
1577
+ const config = await loadConfig();
1578
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
1579
+ const meta = await loadMeta(chainName, chainConfig, opts.rpc);
1580
+ const dotIdx = target.indexOf(".");
1581
+ const palletName = dotIdx === -1 ? target : target.slice(0, dotIdx);
1582
+ const itemName = dotIdx === -1 ? undefined : target.slice(dotIdx + 1);
1583
+ const pallet = resolvePallet(meta, palletName);
1584
+ if (!itemName) {
1585
+ switch (category) {
1586
+ case "tx":
1587
+ await handleCalls(target, opts);
1588
+ return;
1589
+ case "query":
1590
+ await handleStorage(target, opts);
1591
+ return;
1592
+ case "const":
1593
+ return;
1594
+ case "events":
1595
+ await handleEvents(target, opts);
1596
+ return;
1597
+ case "errors":
1598
+ await handleErrors(target, opts);
1425
1599
  return;
1600
+ }
1601
+ }
1602
+ switch (category) {
1603
+ case "tx": {
1604
+ const callItem = pallet.calls.find((c) => c.name.toLowerCase() === itemName.toLowerCase());
1605
+ if (!callItem) {
1606
+ const names = pallet.calls.map((c) => c.name);
1607
+ throw new Error(suggestMessage(`call in ${pallet.name}`, itemName, names));
1426
1608
  }
1427
- printHeading(`${palletInfo.name} Constants`);
1428
- for (const c of palletInfo.constants) {
1429
- const typeStr = describeType(meta.lookup, c.typeId);
1430
- console.log(` ${CYAN}${c.name}${RESET}${DIM}: ${typeStr}${RESET}`);
1431
- const summary = firstSentence(c.docs);
1432
- if (summary) {
1433
- console.log(` ${DIM}${summary}${RESET}`);
1434
- }
1609
+ printHeading(`${pallet.name}.${callItem.name} (Call)`);
1610
+ const args = describeCallArgs(meta, pallet.name, callItem.name);
1611
+ console.log(` ${BOLD}Args:${RESET} ${args}`);
1612
+ if (callItem.docs.length) {
1613
+ console.log();
1614
+ printDocs(callItem.docs);
1435
1615
  }
1436
1616
  console.log();
1617
+ console.log(`${BOLD}Usage:${RESET}`);
1618
+ console.log(` dot tx.${pallet.name}.${callItem.name} --from <account>`);
1619
+ console.log(` dot tx.${pallet.name}.${callItem.name} --encode`);
1620
+ console.log();
1621
+ console.log(`${BOLD}Options:${RESET}`);
1622
+ console.log(` --from <name> Account to sign with`);
1623
+ console.log(` --dry-run Estimate fees without submitting`);
1624
+ console.log(` --encode Encode call to hex without signing`);
1625
+ console.log(` --ext <json> Custom signed extension values as JSON`);
1626
+ console.log();
1437
1627
  return;
1438
1628
  }
1439
- const clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
1440
- try {
1441
- const meta = await getOrFetchMetadata(chainName, clientHandle);
1442
- const palletNames = getPalletNames(meta);
1443
- const palletInfo = findPallet(meta, pallet);
1444
- if (!palletInfo) {
1445
- throw new Error(suggestMessage("pallet", pallet, palletNames));
1629
+ case "query": {
1630
+ const storageItem = pallet.storage.find((s) => s.name.toLowerCase() === itemName.toLowerCase());
1631
+ if (!storageItem) {
1632
+ const names = pallet.storage.map((s) => s.name);
1633
+ throw new Error(suggestMessage(`storage item in ${pallet.name}`, itemName, names));
1446
1634
  }
1447
- const constantItem = palletInfo.constants.find((c) => c.name.toLowerCase() === item.toLowerCase());
1448
- if (!constantItem) {
1449
- const constNames = palletInfo.constants.map((c) => c.name);
1450
- throw new Error(suggestMessage(`constant in ${palletInfo.name}`, item, constNames));
1635
+ printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
1636
+ console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
1637
+ console.log(` ${BOLD}Value:${RESET} ${describeType(meta.lookup, storageItem.valueTypeId)}`);
1638
+ if (storageItem.keyTypeId != null) {
1639
+ console.log(` ${BOLD}Key:${RESET} ${describeType(meta.lookup, storageItem.keyTypeId)}`);
1451
1640
  }
1452
- const unsafeApi = clientHandle.client.getUnsafeApi();
1453
- const runtimeToken = await unsafeApi.runtimeToken;
1454
- const result = unsafeApi.constants[palletInfo.name][constantItem.name](runtimeToken);
1455
- const format = opts.output ?? "pretty";
1456
- printResult(result, format);
1457
- } finally {
1458
- clientHandle.destroy();
1641
+ if (storageItem.docs.length) {
1642
+ console.log();
1643
+ printDocs(storageItem.docs);
1644
+ }
1645
+ console.log();
1646
+ if (storageItem.keyTypeId != null) {
1647
+ console.log(`${BOLD}Usage:${RESET}`);
1648
+ console.log(` dot query.${pallet.name}.${storageItem.name} <key>`);
1649
+ console.log(` dot query.${pallet.name}.${storageItem.name} # all entries`);
1650
+ } else {
1651
+ console.log(`${BOLD}Usage:${RESET}`);
1652
+ console.log(` dot query.${pallet.name}.${storageItem.name}`);
1653
+ }
1654
+ console.log();
1655
+ console.log(`${BOLD}Options:${RESET}`);
1656
+ console.log(` --limit <n> Max entries for map queries (0 = unlimited, default: 100)`);
1657
+ console.log();
1658
+ return;
1459
1659
  }
1460
- });
1660
+ case "const": {
1661
+ const constItem = pallet.constants.find((c) => c.name.toLowerCase() === itemName.toLowerCase());
1662
+ if (!constItem) {
1663
+ const names = pallet.constants.map((c) => c.name);
1664
+ throw new Error(suggestMessage(`constant in ${pallet.name}`, itemName, names));
1665
+ }
1666
+ printHeading(`${pallet.name}.${constItem.name} (Constant)`);
1667
+ console.log(` ${BOLD}Type:${RESET} ${describeType(meta.lookup, constItem.typeId)}`);
1668
+ if (constItem.docs.length) {
1669
+ console.log();
1670
+ printDocs(constItem.docs);
1671
+ }
1672
+ console.log();
1673
+ console.log(`${BOLD}Usage:${RESET}`);
1674
+ console.log(` dot const.${pallet.name}.${constItem.name}`);
1675
+ console.log();
1676
+ return;
1677
+ }
1678
+ case "events": {
1679
+ const eventItem = pallet.events.find((e) => e.name.toLowerCase() === itemName.toLowerCase());
1680
+ if (!eventItem) {
1681
+ const names = pallet.events.map((e) => e.name);
1682
+ throw new Error(suggestMessage(`event in ${pallet.name}`, itemName, names));
1683
+ }
1684
+ printHeading(`${pallet.name}.${eventItem.name} (Event)`);
1685
+ const fields = describeEventFields(meta, pallet.name, eventItem.name);
1686
+ console.log(` ${BOLD}Fields:${RESET} ${fields}`);
1687
+ if (eventItem.docs.length) {
1688
+ console.log();
1689
+ printDocs(eventItem.docs);
1690
+ }
1691
+ console.log();
1692
+ console.log(`${BOLD}Usage:${RESET}`);
1693
+ console.log(` dot events.${pallet.name}.${eventItem.name}`);
1694
+ console.log();
1695
+ return;
1696
+ }
1697
+ case "errors": {
1698
+ const errorItem = pallet.errors.find((e) => e.name.toLowerCase() === itemName.toLowerCase());
1699
+ if (!errorItem) {
1700
+ const names = pallet.errors.map((e) => e.name);
1701
+ throw new Error(suggestMessage(`error in ${pallet.name}`, itemName, names));
1702
+ }
1703
+ printHeading(`${pallet.name}.${errorItem.name} (Error)`);
1704
+ if (errorItem.docs.length) {
1705
+ printDocs(errorItem.docs);
1706
+ }
1707
+ console.log();
1708
+ console.log(`${BOLD}Usage:${RESET}`);
1709
+ console.log(` dot errors.${pallet.name}.${errorItem.name}`);
1710
+ console.log();
1711
+ return;
1712
+ }
1713
+ }
1714
+ }
1715
+
1716
+ // src/commands/const.ts
1717
+ async function handleConst(target, opts) {
1718
+ if (!target) {
1719
+ const config2 = await loadConfig();
1720
+ const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
1721
+ const meta = await loadMeta(chainName2, chainConfig2, opts.rpc);
1722
+ const pallets = listPallets(meta);
1723
+ const withConsts = pallets.filter((p) => p.constants.length > 0);
1724
+ printHeading(`Pallets with constants on ${chainName2} (${withConsts.length})`);
1725
+ for (const p of withConsts) {
1726
+ printItem(p.name, `${p.constants.length} constants`);
1727
+ }
1728
+ console.log();
1729
+ return;
1730
+ }
1731
+ const dotIdx = target.indexOf(".");
1732
+ const pallet = dotIdx === -1 ? target : target.slice(0, dotIdx);
1733
+ const item = dotIdx === -1 ? undefined : target.slice(dotIdx + 1);
1734
+ const config = await loadConfig();
1735
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
1736
+ if (!item) {
1737
+ const meta = await loadMeta(chainName, chainConfig, opts.rpc);
1738
+ const palletNames = getPalletNames(meta);
1739
+ const palletInfo = findPallet(meta, pallet);
1740
+ if (!palletInfo) {
1741
+ throw new Error(suggestMessage("pallet", pallet, palletNames));
1742
+ }
1743
+ if (palletInfo.constants.length === 0) {
1744
+ console.log(`No constants in ${palletInfo.name}.`);
1745
+ return;
1746
+ }
1747
+ printHeading(`${palletInfo.name} Constants`);
1748
+ for (const c of palletInfo.constants) {
1749
+ const typeStr = describeType(meta.lookup, c.typeId);
1750
+ console.log(` ${CYAN}${c.name}${RESET}${DIM}: ${typeStr}${RESET}`);
1751
+ const summary = firstSentence(c.docs);
1752
+ if (summary) {
1753
+ console.log(` ${DIM}${summary}${RESET}`);
1754
+ }
1755
+ }
1756
+ console.log();
1757
+ return;
1758
+ }
1759
+ const clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
1760
+ try {
1761
+ const meta = await getOrFetchMetadata(chainName, clientHandle);
1762
+ const palletNames = getPalletNames(meta);
1763
+ const palletInfo = findPallet(meta, pallet);
1764
+ if (!palletInfo) {
1765
+ throw new Error(suggestMessage("pallet", pallet, palletNames));
1766
+ }
1767
+ const constantItem = palletInfo.constants.find((c) => c.name.toLowerCase() === item.toLowerCase());
1768
+ if (!constantItem) {
1769
+ const constNames = palletInfo.constants.map((c) => c.name);
1770
+ throw new Error(suggestMessage(`constant in ${palletInfo.name}`, item, constNames));
1771
+ }
1772
+ const unsafeApi = clientHandle.client.getUnsafeApi();
1773
+ const runtimeToken = await unsafeApi.runtimeToken;
1774
+ const result = unsafeApi.constants[palletInfo.name][constantItem.name](runtimeToken);
1775
+ const format = opts.output ?? "pretty";
1776
+ printResult(result, format);
1777
+ } finally {
1778
+ clientHandle.destroy();
1779
+ }
1461
1780
  }
1462
1781
 
1463
1782
  // src/commands/focused-inspect.ts
1464
- async function loadMeta(chainName, chainConfig, rpcOverride) {
1783
+ async function loadMeta2(chainName, chainConfig, rpcOverride) {
1465
1784
  try {
1466
1785
  return await getOrFetchMetadata(chainName);
1467
1786
  } catch {
@@ -1474,7 +1793,7 @@ async function loadMeta(chainName, chainConfig, rpcOverride) {
1474
1793
  }
1475
1794
  }
1476
1795
  }
1477
- function resolvePallet(meta, palletName) {
1796
+ function resolvePallet2(meta, palletName) {
1478
1797
  const palletNames = getPalletNames(meta);
1479
1798
  const pallet = findPallet(meta, palletName);
1480
1799
  if (!pallet) {
@@ -1482,255 +1801,358 @@ function resolvePallet(meta, palletName) {
1482
1801
  }
1483
1802
  return pallet;
1484
1803
  }
1485
- function registerFocusedInspectCommands(cli) {
1486
- cli.command("call [target]", "List or inspect pallet calls").alias("calls").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
1487
- if (!target) {
1488
- console.log("Usage: dot calls <[Chain.]Pallet[.Call]> [--chain <name>]");
1489
- console.log("");
1490
- console.log("Examples:");
1491
- console.log(" $ dot calls Balances");
1492
- console.log(" $ dot calls Balances.transfer_allow_death");
1493
- return;
1804
+ async function handleCalls2(target, opts) {
1805
+ if (!target) {
1806
+ const config2 = await loadConfig();
1807
+ const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
1808
+ const meta2 = await loadMeta2(chainName2, chainConfig2, opts.rpc);
1809
+ const pallets = listPallets(meta2);
1810
+ const withCalls = pallets.filter((p) => p.calls.length > 0);
1811
+ printHeading(`Pallets with calls on ${chainName2} (${withCalls.length})`);
1812
+ for (const p of withCalls) {
1813
+ printItem(p.name, `${p.calls.length} calls`);
1494
1814
  }
1495
- const config = await loadConfig();
1496
- const knownChains = Object.keys(config.chains);
1497
- const parsed = parseTarget(target, { knownChains, allowPalletOnly: true });
1498
- const effectiveChain = resolveTargetChain(parsed, opts.chain);
1499
- const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
1500
- const meta = await loadMeta(chainName, chainConfig, opts.rpc);
1501
- const pallet = resolvePallet(meta, parsed.pallet);
1502
- if (!parsed.item) {
1503
- if (pallet.calls.length === 0) {
1504
- console.log(`No calls in ${pallet.name}.`);
1505
- return;
1506
- }
1507
- printHeading(`${pallet.name} Calls`);
1508
- for (const c of pallet.calls) {
1509
- const args2 = describeCallArgs(meta, pallet.name, c.name);
1510
- console.log(` ${CYAN}${c.name}${RESET}${DIM}${args2}${RESET}`);
1511
- const summary = firstSentence(c.docs);
1512
- if (summary) {
1513
- console.log(` ${DIM}${summary}${RESET}`);
1514
- }
1515
- }
1516
- console.log();
1815
+ console.log();
1816
+ return;
1817
+ }
1818
+ const config = await loadConfig();
1819
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
1820
+ const meta = await loadMeta2(chainName, chainConfig, opts.rpc);
1821
+ const dotIdx = target.indexOf(".");
1822
+ const palletName = dotIdx === -1 ? target : target.slice(0, dotIdx);
1823
+ const itemName = dotIdx === -1 ? undefined : target.slice(dotIdx + 1);
1824
+ const pallet = resolvePallet2(meta, palletName);
1825
+ if (!itemName) {
1826
+ if (pallet.calls.length === 0) {
1827
+ console.log(`No calls in ${pallet.name}.`);
1517
1828
  return;
1518
1829
  }
1519
- const callItem = pallet.calls.find((c) => c.name.toLowerCase() === parsed.item.toLowerCase());
1520
- if (!callItem) {
1521
- const names = pallet.calls.map((c) => c.name);
1522
- throw new Error(suggestMessage(`call in ${pallet.name}`, parsed.item, names));
1830
+ printHeading(`${pallet.name} Calls`);
1831
+ for (const c of pallet.calls) {
1832
+ const args2 = describeCallArgs(meta, pallet.name, c.name);
1833
+ console.log(` ${CYAN}${c.name}${RESET}${DIM}${args2}${RESET}`);
1834
+ const summary = firstSentence(c.docs);
1835
+ if (summary) {
1836
+ console.log(` ${DIM}${summary}${RESET}`);
1837
+ }
1523
1838
  }
1524
- printHeading(`${pallet.name}.${callItem.name} (Call)`);
1525
- const args = describeCallArgs(meta, pallet.name, callItem.name);
1526
- console.log(` ${BOLD}Args:${RESET} ${args}`);
1527
- if (callItem.docs.length) {
1528
- console.log();
1529
- printDocs(callItem.docs);
1839
+ console.log();
1840
+ return;
1841
+ }
1842
+ const callItem = pallet.calls.find((c) => c.name.toLowerCase() === itemName.toLowerCase());
1843
+ if (!callItem) {
1844
+ const names = pallet.calls.map((c) => c.name);
1845
+ throw new Error(suggestMessage(`call in ${pallet.name}`, itemName, names));
1846
+ }
1847
+ printHeading(`${pallet.name}.${callItem.name} (Call)`);
1848
+ const args = describeCallArgs(meta, pallet.name, callItem.name);
1849
+ console.log(` ${BOLD}Args:${RESET} ${args}`);
1850
+ if (callItem.docs.length) {
1851
+ console.log();
1852
+ printDocs(callItem.docs);
1853
+ }
1854
+ console.log();
1855
+ }
1856
+ async function handleEvents2(target, opts) {
1857
+ if (!target) {
1858
+ const config2 = await loadConfig();
1859
+ const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
1860
+ const meta2 = await loadMeta2(chainName2, chainConfig2, opts.rpc);
1861
+ const pallets = listPallets(meta2);
1862
+ const withEvents = pallets.filter((p) => p.events.length > 0);
1863
+ printHeading(`Pallets with events on ${chainName2} (${withEvents.length})`);
1864
+ for (const p of withEvents) {
1865
+ printItem(p.name, `${p.events.length} events`);
1530
1866
  }
1531
1867
  console.log();
1532
- });
1533
- cli.command("event [target]", "List or inspect pallet events").alias("events").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
1534
- if (!target) {
1535
- console.log("Usage: dot events <[Chain.]Pallet[.Event]> [--chain <name>]");
1536
- console.log("");
1537
- console.log("Examples:");
1538
- console.log(" $ dot events Balances");
1539
- console.log(" $ dot events Balances.Transfer");
1868
+ return;
1869
+ }
1870
+ const config = await loadConfig();
1871
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
1872
+ const meta = await loadMeta2(chainName, chainConfig, opts.rpc);
1873
+ const dotIdx = target.indexOf(".");
1874
+ const palletName = dotIdx === -1 ? target : target.slice(0, dotIdx);
1875
+ const itemName = dotIdx === -1 ? undefined : target.slice(dotIdx + 1);
1876
+ const pallet = resolvePallet2(meta, palletName);
1877
+ if (!itemName) {
1878
+ if (pallet.events.length === 0) {
1879
+ console.log(`No events in ${pallet.name}.`);
1540
1880
  return;
1541
1881
  }
1542
- const config = await loadConfig();
1543
- const knownChains = Object.keys(config.chains);
1544
- const parsed = parseTarget(target, { knownChains, allowPalletOnly: true });
1545
- const effectiveChain = resolveTargetChain(parsed, opts.chain);
1546
- const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
1547
- const meta = await loadMeta(chainName, chainConfig, opts.rpc);
1548
- const pallet = resolvePallet(meta, parsed.pallet);
1549
- if (!parsed.item) {
1550
- if (pallet.events.length === 0) {
1551
- console.log(`No events in ${pallet.name}.`);
1552
- return;
1882
+ printHeading(`${pallet.name} Events`);
1883
+ for (const e of pallet.events) {
1884
+ const fields2 = describeEventFields(meta, pallet.name, e.name);
1885
+ console.log(` ${CYAN}${e.name}${RESET}${DIM}${fields2}${RESET}`);
1886
+ const summary = firstSentence(e.docs);
1887
+ if (summary) {
1888
+ console.log(` ${DIM}${summary}${RESET}`);
1553
1889
  }
1554
- printHeading(`${pallet.name} Events`);
1555
- for (const e of pallet.events) {
1556
- const fields2 = describeEventFields(meta, pallet.name, e.name);
1557
- console.log(` ${CYAN}${e.name}${RESET}${DIM}${fields2}${RESET}`);
1558
- const summary = firstSentence(e.docs);
1559
- if (summary) {
1560
- console.log(` ${DIM}${summary}${RESET}`);
1561
- }
1562
- }
1563
- console.log();
1564
- return;
1565
- }
1566
- const eventItem = pallet.events.find((e) => e.name.toLowerCase() === parsed.item.toLowerCase());
1567
- if (!eventItem) {
1568
- const names = pallet.events.map((e) => e.name);
1569
- throw new Error(suggestMessage(`event in ${pallet.name}`, parsed.item, names));
1570
1890
  }
1571
- printHeading(`${pallet.name}.${eventItem.name} (Event)`);
1572
- const fields = describeEventFields(meta, pallet.name, eventItem.name);
1573
- console.log(` ${BOLD}Fields:${RESET} ${fields}`);
1574
- if (eventItem.docs.length) {
1575
- console.log();
1576
- printDocs(eventItem.docs);
1891
+ console.log();
1892
+ return;
1893
+ }
1894
+ const eventItem = pallet.events.find((e) => e.name.toLowerCase() === itemName.toLowerCase());
1895
+ if (!eventItem) {
1896
+ const names = pallet.events.map((e) => e.name);
1897
+ throw new Error(suggestMessage(`event in ${pallet.name}`, itemName, names));
1898
+ }
1899
+ printHeading(`${pallet.name}.${eventItem.name} (Event)`);
1900
+ const fields = describeEventFields(meta, pallet.name, eventItem.name);
1901
+ console.log(` ${BOLD}Fields:${RESET} ${fields}`);
1902
+ if (eventItem.docs.length) {
1903
+ console.log();
1904
+ printDocs(eventItem.docs);
1905
+ }
1906
+ console.log();
1907
+ }
1908
+ async function handleErrors2(target, opts) {
1909
+ if (!target) {
1910
+ const config2 = await loadConfig();
1911
+ const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
1912
+ const meta2 = await loadMeta2(chainName2, chainConfig2, opts.rpc);
1913
+ const pallets = listPallets(meta2);
1914
+ const withErrors = pallets.filter((p) => p.errors.length > 0);
1915
+ printHeading(`Pallets with errors on ${chainName2} (${withErrors.length})`);
1916
+ for (const p of withErrors) {
1917
+ printItem(p.name, `${p.errors.length} errors`);
1577
1918
  }
1578
1919
  console.log();
1579
- });
1580
- cli.command("error [target]", "List or inspect pallet errors").alias("errors").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
1581
- if (!target) {
1582
- console.log("Usage: dot errors <[Chain.]Pallet[.Error]> [--chain <name>]");
1583
- console.log("");
1584
- console.log("Examples:");
1585
- console.log(" $ dot errors Balances");
1586
- console.log(" $ dot errors Balances.InsufficientBalance");
1920
+ return;
1921
+ }
1922
+ const config = await loadConfig();
1923
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
1924
+ const meta = await loadMeta2(chainName, chainConfig, opts.rpc);
1925
+ const dotIdx = target.indexOf(".");
1926
+ const palletName = dotIdx === -1 ? target : target.slice(0, dotIdx);
1927
+ const itemName = dotIdx === -1 ? undefined : target.slice(dotIdx + 1);
1928
+ const pallet = resolvePallet2(meta, palletName);
1929
+ if (!itemName) {
1930
+ if (pallet.errors.length === 0) {
1931
+ console.log(`No errors in ${pallet.name}.`);
1587
1932
  return;
1588
1933
  }
1589
- const config = await loadConfig();
1590
- const knownChains = Object.keys(config.chains);
1591
- const parsed = parseTarget(target, { knownChains, allowPalletOnly: true });
1592
- const effectiveChain = resolveTargetChain(parsed, opts.chain);
1593
- const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
1594
- const meta = await loadMeta(chainName, chainConfig, opts.rpc);
1595
- const pallet = resolvePallet(meta, parsed.pallet);
1596
- if (!parsed.item) {
1597
- if (pallet.errors.length === 0) {
1598
- console.log(`No errors in ${pallet.name}.`);
1599
- return;
1600
- }
1601
- printHeading(`${pallet.name} Errors`);
1602
- for (const e of pallet.errors) {
1603
- console.log(` ${CYAN}${e.name}${RESET}`);
1604
- const summary = firstSentence(e.docs);
1605
- if (summary) {
1606
- console.log(` ${DIM}${summary}${RESET}`);
1607
- }
1934
+ printHeading(`${pallet.name} Errors`);
1935
+ for (const e of pallet.errors) {
1936
+ console.log(` ${CYAN}${e.name}${RESET}`);
1937
+ const summary = firstSentence(e.docs);
1938
+ if (summary) {
1939
+ console.log(` ${DIM}${summary}${RESET}`);
1608
1940
  }
1609
- console.log();
1610
- return;
1611
- }
1612
- const errorItem = pallet.errors.find((e) => e.name.toLowerCase() === parsed.item.toLowerCase());
1613
- if (!errorItem) {
1614
- const names = pallet.errors.map((e) => e.name);
1615
- throw new Error(suggestMessage(`error in ${pallet.name}`, parsed.item, names));
1616
1941
  }
1617
- printHeading(`${pallet.name}.${errorItem.name} (Error)`);
1618
- if (errorItem.docs.length) {
1619
- printDocs(errorItem.docs);
1942
+ console.log();
1943
+ return;
1944
+ }
1945
+ const errorItem = pallet.errors.find((e) => e.name.toLowerCase() === itemName.toLowerCase());
1946
+ if (!errorItem) {
1947
+ const names = pallet.errors.map((e) => e.name);
1948
+ throw new Error(suggestMessage(`error in ${pallet.name}`, itemName, names));
1949
+ }
1950
+ printHeading(`${pallet.name}.${errorItem.name} (Error)`);
1951
+ if (errorItem.docs.length) {
1952
+ printDocs(errorItem.docs);
1953
+ }
1954
+ console.log();
1955
+ }
1956
+ async function handleStorage2(target, opts) {
1957
+ if (!target) {
1958
+ const config2 = await loadConfig();
1959
+ const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
1960
+ const meta2 = await loadMeta2(chainName2, chainConfig2, opts.rpc);
1961
+ const pallets = listPallets(meta2);
1962
+ const withStorage = pallets.filter((p) => p.storage.length > 0);
1963
+ printHeading(`Pallets with storage on ${chainName2} (${withStorage.length})`);
1964
+ for (const p of withStorage) {
1965
+ printItem(p.name, `${p.storage.length} storage`);
1620
1966
  }
1621
1967
  console.log();
1622
- });
1623
- cli.command("storage [target]", "List or inspect pallet storage items").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
1624
- if (!target) {
1625
- console.log("Usage: dot storage <[Chain.]Pallet[.Item]> [--chain <name>]");
1626
- console.log("");
1627
- console.log("Examples:");
1628
- console.log(" $ dot storage System");
1629
- console.log(" $ dot storage System.Account");
1968
+ return;
1969
+ }
1970
+ const config = await loadConfig();
1971
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
1972
+ const meta = await loadMeta2(chainName, chainConfig, opts.rpc);
1973
+ const dotIdx = target.indexOf(".");
1974
+ const palletName = dotIdx === -1 ? target : target.slice(0, dotIdx);
1975
+ const itemName = dotIdx === -1 ? undefined : target.slice(dotIdx + 1);
1976
+ const pallet = resolvePallet2(meta, palletName);
1977
+ if (!itemName) {
1978
+ if (pallet.storage.length === 0) {
1979
+ console.log(`No storage items in ${pallet.name}.`);
1630
1980
  return;
1631
1981
  }
1632
- const config = await loadConfig();
1633
- const knownChains = Object.keys(config.chains);
1634
- const parsed = parseTarget(target, { knownChains, allowPalletOnly: true });
1635
- const effectiveChain = resolveTargetChain(parsed, opts.chain);
1636
- const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
1637
- const meta = await loadMeta(chainName, chainConfig, opts.rpc);
1638
- const pallet = resolvePallet(meta, parsed.pallet);
1639
- if (!parsed.item) {
1640
- if (pallet.storage.length === 0) {
1641
- console.log(`No storage items in ${pallet.name}.`);
1982
+ printHeading(`${pallet.name} Storage`);
1983
+ for (const s of pallet.storage) {
1984
+ const valueType = describeType(meta.lookup, s.valueTypeId);
1985
+ let typeSuffix;
1986
+ if (s.keyTypeId != null) {
1987
+ const keyType = describeType(meta.lookup, s.keyTypeId);
1988
+ typeSuffix = `: ${keyType} → ${valueType} [map]`;
1989
+ } else {
1990
+ typeSuffix = `: ${valueType}`;
1991
+ }
1992
+ console.log(` ${CYAN}${s.name}${RESET}${DIM}${typeSuffix}${RESET}`);
1993
+ const summary = firstSentence(s.docs);
1994
+ if (summary) {
1995
+ console.log(` ${DIM}${summary}${RESET}`);
1996
+ }
1997
+ }
1998
+ console.log();
1999
+ return;
2000
+ }
2001
+ const storageItem = pallet.storage.find((s) => s.name.toLowerCase() === itemName.toLowerCase());
2002
+ if (!storageItem) {
2003
+ const names = pallet.storage.map((s) => s.name);
2004
+ throw new Error(suggestMessage(`storage item in ${pallet.name}`, itemName, names));
2005
+ }
2006
+ printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
2007
+ console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
2008
+ console.log(` ${BOLD}Value:${RESET} ${describeType(meta.lookup, storageItem.valueTypeId)}`);
2009
+ if (storageItem.keyTypeId != null) {
2010
+ console.log(` ${BOLD}Key:${RESET} ${describeType(meta.lookup, storageItem.keyTypeId)}`);
2011
+ }
2012
+ if (storageItem.docs.length) {
2013
+ console.log();
2014
+ printDocs(storageItem.docs);
2015
+ }
2016
+ console.log();
2017
+ }
2018
+ async function showItemHelp2(category, target, opts) {
2019
+ const config = await loadConfig();
2020
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
2021
+ const meta = await loadMeta2(chainName, chainConfig, opts.rpc);
2022
+ const dotIdx = target.indexOf(".");
2023
+ const palletName = dotIdx === -1 ? target : target.slice(0, dotIdx);
2024
+ const itemName = dotIdx === -1 ? undefined : target.slice(dotIdx + 1);
2025
+ const pallet = resolvePallet2(meta, palletName);
2026
+ if (!itemName) {
2027
+ switch (category) {
2028
+ case "tx":
2029
+ await handleCalls2(target, opts);
2030
+ return;
2031
+ case "query":
2032
+ await handleStorage2(target, opts);
2033
+ return;
2034
+ case "const":
1642
2035
  return;
2036
+ case "events":
2037
+ await handleEvents2(target, opts);
2038
+ return;
2039
+ case "errors":
2040
+ await handleErrors2(target, opts);
2041
+ return;
2042
+ }
2043
+ }
2044
+ switch (category) {
2045
+ case "tx": {
2046
+ const callItem = pallet.calls.find((c) => c.name.toLowerCase() === itemName.toLowerCase());
2047
+ if (!callItem) {
2048
+ const names = pallet.calls.map((c) => c.name);
2049
+ throw new Error(suggestMessage(`call in ${pallet.name}`, itemName, names));
1643
2050
  }
1644
- printHeading(`${pallet.name} Storage`);
1645
- for (const s of pallet.storage) {
1646
- const valueType = describeType(meta.lookup, s.valueTypeId);
1647
- let typeSuffix;
1648
- if (s.keyTypeId != null) {
1649
- const keyType = describeType(meta.lookup, s.keyTypeId);
1650
- typeSuffix = `: ${keyType} → ${valueType} [map]`;
1651
- } else {
1652
- typeSuffix = `: ${valueType}`;
1653
- }
1654
- console.log(` ${CYAN}${s.name}${RESET}${DIM}${typeSuffix}${RESET}`);
1655
- const summary = firstSentence(s.docs);
1656
- if (summary) {
1657
- console.log(` ${DIM}${summary}${RESET}`);
1658
- }
2051
+ printHeading(`${pallet.name}.${callItem.name} (Call)`);
2052
+ const args = describeCallArgs(meta, pallet.name, callItem.name);
2053
+ console.log(` ${BOLD}Args:${RESET} ${args}`);
2054
+ if (callItem.docs.length) {
2055
+ console.log();
2056
+ printDocs(callItem.docs);
1659
2057
  }
1660
2058
  console.log();
2059
+ console.log(`${BOLD}Usage:${RESET}`);
2060
+ console.log(` dot tx.${pallet.name}.${callItem.name} --from <account>`);
2061
+ console.log(` dot tx.${pallet.name}.${callItem.name} --encode`);
2062
+ console.log();
2063
+ console.log(`${BOLD}Options:${RESET}`);
2064
+ console.log(` --from <name> Account to sign with`);
2065
+ console.log(` --dry-run Estimate fees without submitting`);
2066
+ console.log(` --encode Encode call to hex without signing`);
2067
+ console.log(` --ext <json> Custom signed extension values as JSON`);
2068
+ console.log();
1661
2069
  return;
1662
2070
  }
1663
- const storageItem = pallet.storage.find((s) => s.name.toLowerCase() === parsed.item.toLowerCase());
1664
- if (!storageItem) {
1665
- const names = pallet.storage.map((s) => s.name);
1666
- throw new Error(suggestMessage(`storage item in ${pallet.name}`, parsed.item, names));
1667
- }
1668
- printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
1669
- console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
1670
- console.log(` ${BOLD}Value:${RESET} ${describeType(meta.lookup, storageItem.valueTypeId)}`);
1671
- if (storageItem.keyTypeId != null) {
1672
- console.log(` ${BOLD}Key:${RESET} ${describeType(meta.lookup, storageItem.keyTypeId)}`);
1673
- }
1674
- if (storageItem.docs.length) {
2071
+ case "query": {
2072
+ const storageItem = pallet.storage.find((s) => s.name.toLowerCase() === itemName.toLowerCase());
2073
+ if (!storageItem) {
2074
+ const names = pallet.storage.map((s) => s.name);
2075
+ throw new Error(suggestMessage(`storage item in ${pallet.name}`, itemName, names));
2076
+ }
2077
+ printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
2078
+ console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
2079
+ console.log(` ${BOLD}Value:${RESET} ${describeType(meta.lookup, storageItem.valueTypeId)}`);
2080
+ if (storageItem.keyTypeId != null) {
2081
+ console.log(` ${BOLD}Key:${RESET} ${describeType(meta.lookup, storageItem.keyTypeId)}`);
2082
+ }
2083
+ if (storageItem.docs.length) {
2084
+ console.log();
2085
+ printDocs(storageItem.docs);
2086
+ }
1675
2087
  console.log();
1676
- printDocs(storageItem.docs);
1677
- }
1678
- console.log();
1679
- });
1680
- cli.command("pallet [target]", "List all pallets or inspect a specific pallet").alias("pallets").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
1681
- const config = await loadConfig();
1682
- const knownChains = Object.keys(config.chains);
1683
- let effectiveChain = opts.chain;
1684
- let palletName;
1685
- if (target) {
1686
- const parsed = parseTarget(target, { knownChains, allowPalletOnly: true });
1687
- effectiveChain = resolveTargetChain(parsed, opts.chain);
1688
- palletName = parsed.pallet;
2088
+ if (storageItem.keyTypeId != null) {
2089
+ console.log(`${BOLD}Usage:${RESET}`);
2090
+ console.log(` dot query.${pallet.name}.${storageItem.name} <key>`);
2091
+ console.log(` dot query.${pallet.name}.${storageItem.name} # all entries`);
2092
+ } else {
2093
+ console.log(`${BOLD}Usage:${RESET}`);
2094
+ console.log(` dot query.${pallet.name}.${storageItem.name}`);
2095
+ }
2096
+ console.log();
2097
+ console.log(`${BOLD}Options:${RESET}`);
2098
+ console.log(` --limit <n> Max entries for map queries (0 = unlimited, default: 100)`);
2099
+ console.log();
2100
+ return;
1689
2101
  }
1690
- const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
1691
- const meta = await loadMeta(chainName, chainConfig, opts.rpc);
1692
- if (!palletName) {
1693
- const pallets = listPallets(meta);
1694
- printHeading(`Pallets on ${chainName} (${pallets.length})`);
1695
- for (const p of pallets) {
1696
- const counts2 = [];
1697
- if (p.storage.length)
1698
- counts2.push(`${p.storage.length} storage`);
1699
- if (p.constants.length)
1700
- counts2.push(`${p.constants.length} constants`);
1701
- if (p.calls.length)
1702
- counts2.push(`${p.calls.length} calls`);
1703
- if (p.events.length)
1704
- counts2.push(`${p.events.length} events`);
1705
- if (p.errors.length)
1706
- counts2.push(`${p.errors.length} errors`);
1707
- printItem(p.name, counts2.join(", "));
2102
+ case "const": {
2103
+ const constItem = pallet.constants.find((c) => c.name.toLowerCase() === itemName.toLowerCase());
2104
+ if (!constItem) {
2105
+ const names = pallet.constants.map((c) => c.name);
2106
+ throw new Error(suggestMessage(`constant in ${pallet.name}`, itemName, names));
2107
+ }
2108
+ printHeading(`${pallet.name}.${constItem.name} (Constant)`);
2109
+ console.log(` ${BOLD}Type:${RESET} ${describeType(meta.lookup, constItem.typeId)}`);
2110
+ if (constItem.docs.length) {
2111
+ console.log();
2112
+ printDocs(constItem.docs);
1708
2113
  }
1709
2114
  console.log();
2115
+ console.log(`${BOLD}Usage:${RESET}`);
2116
+ console.log(` dot const.${pallet.name}.${constItem.name}`);
2117
+ console.log();
1710
2118
  return;
1711
2119
  }
1712
- const pallet = resolvePallet(meta, palletName);
1713
- printHeading(`${pallet.name} Pallet`);
1714
- if (pallet.docs.length) {
1715
- printDocs(pallet.docs);
2120
+ case "events": {
2121
+ const eventItem = pallet.events.find((e) => e.name.toLowerCase() === itemName.toLowerCase());
2122
+ if (!eventItem) {
2123
+ const names = pallet.events.map((e) => e.name);
2124
+ throw new Error(suggestMessage(`event in ${pallet.name}`, itemName, names));
2125
+ }
2126
+ printHeading(`${pallet.name}.${eventItem.name} (Event)`);
2127
+ const fields = describeEventFields(meta, pallet.name, eventItem.name);
2128
+ console.log(` ${BOLD}Fields:${RESET} ${fields}`);
2129
+ if (eventItem.docs.length) {
2130
+ console.log();
2131
+ printDocs(eventItem.docs);
2132
+ }
2133
+ console.log();
2134
+ console.log(`${BOLD}Usage:${RESET}`);
2135
+ console.log(` dot events.${pallet.name}.${eventItem.name}`);
1716
2136
  console.log();
2137
+ return;
1717
2138
  }
1718
- const counts = [];
1719
- if (pallet.storage.length)
1720
- counts.push(`${pallet.storage.length} storage`);
1721
- if (pallet.constants.length)
1722
- counts.push(`${pallet.constants.length} constants`);
1723
- if (pallet.calls.length)
1724
- counts.push(`${pallet.calls.length} calls`);
1725
- if (pallet.events.length)
1726
- counts.push(`${pallet.events.length} events`);
1727
- if (pallet.errors.length)
1728
- counts.push(`${pallet.errors.length} errors`);
1729
- if (counts.length) {
1730
- console.log(` ${counts.join(", ")}`);
2139
+ case "errors": {
2140
+ const errorItem = pallet.errors.find((e) => e.name.toLowerCase() === itemName.toLowerCase());
2141
+ if (!errorItem) {
2142
+ const names = pallet.errors.map((e) => e.name);
2143
+ throw new Error(suggestMessage(`error in ${pallet.name}`, itemName, names));
2144
+ }
2145
+ printHeading(`${pallet.name}.${errorItem.name} (Error)`);
2146
+ if (errorItem.docs.length) {
2147
+ printDocs(errorItem.docs);
2148
+ }
2149
+ console.log();
2150
+ console.log(`${BOLD}Usage:${RESET}`);
2151
+ console.log(` dot errors.${pallet.name}.${errorItem.name}`);
2152
+ console.log();
2153
+ return;
1731
2154
  }
1732
- console.log();
1733
- });
2155
+ }
1734
2156
  }
1735
2157
 
1736
2158
  // src/core/hash.ts
@@ -1864,9 +2286,58 @@ function registerHashCommand(cli) {
1864
2286
  });
1865
2287
  }
1866
2288
 
2289
+ // src/utils/parse-target.ts
2290
+ function parseTarget(input, options) {
2291
+ const parts = input.split(".");
2292
+ if (options?.allowPalletOnly) {
2293
+ switch (parts.length) {
2294
+ case 1:
2295
+ if (!parts[0]) {
2296
+ throw new Error(`Invalid target "${input}". Expected format: Pallet or Pallet.Item (e.g. System or System.Account)`);
2297
+ }
2298
+ return { pallet: parts[0] };
2299
+ case 2:
2300
+ if (!parts[0] || !parts[1]) {
2301
+ throw new Error(`Invalid target "${input}". Expected format: Pallet.Item or Chain.Pallet (e.g. System.Account or kusama.System)`);
2302
+ }
2303
+ if (options.knownChains?.some((c) => c.toLowerCase() === parts[0].toLowerCase())) {
2304
+ return { chain: parts[0], pallet: parts[1] };
2305
+ }
2306
+ return { pallet: parts[0], item: parts[1] };
2307
+ case 3:
2308
+ if (!parts[0] || !parts[1] || !parts[2]) {
2309
+ throw new Error(`Invalid target "${input}". Expected format: Chain.Pallet.Item (e.g. kusama.System.Account)`);
2310
+ }
2311
+ return { chain: parts[0], pallet: parts[1], item: parts[2] };
2312
+ default:
2313
+ throw new Error(`Invalid target "${input}". Expected format: Pallet, Pallet.Item, or Chain.Pallet.Item`);
2314
+ }
2315
+ }
2316
+ switch (parts.length) {
2317
+ case 2:
2318
+ if (!parts[0] || !parts[1]) {
2319
+ throw new Error(`Invalid target "${input}". Expected format: Pallet.Item (e.g. System.Account)`);
2320
+ }
2321
+ return { pallet: parts[0], item: parts[1] };
2322
+ case 3:
2323
+ if (!parts[0] || !parts[1] || !parts[2]) {
2324
+ throw new Error(`Invalid target "${input}". Expected format: Chain.Pallet.Item (e.g. kusama.System.Account)`);
2325
+ }
2326
+ return { chain: parts[0], pallet: parts[1], item: parts[2] };
2327
+ default:
2328
+ throw new Error(`Invalid target "${input}". Expected format: Pallet.Item (e.g. System.Account)`);
2329
+ }
2330
+ }
2331
+ function resolveTargetChain(target, chainFlag) {
2332
+ if (target.chain && chainFlag) {
2333
+ throw new Error(`Chain specified both as prefix ("${target.chain}") and as --chain flag ("${chainFlag}"). Use one or the other.`);
2334
+ }
2335
+ return target.chain ?? chainFlag;
2336
+ }
2337
+
1867
2338
  // src/commands/inspect.ts
1868
2339
  function registerInspectCommand(cli) {
1869
- cli.command("inspect [target]", "Inspect chain metadata (pallets, storage, constants, calls, events, errors)").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
2340
+ cli.command("inspect [target]", "Inspect chain metadata (pallets, storage, constants, calls, events, errors)").alias("explore").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
1870
2341
  const config = await loadConfig();
1871
2342
  const knownChains = Object.keys(config.chains);
1872
2343
  let effectiveChain = opts.chain;
@@ -2386,77 +2857,101 @@ var PAPI_BUILTIN_EXTENSIONS = new Set([
2386
2857
  var NO_DEFAULT = Symbol("no-default");
2387
2858
 
2388
2859
  // src/commands/query.ts
2389
- var DEFAULT_LIMIT = 100;
2390
- function registerQueryCommand(cli) {
2391
- cli.command("query [target] [...keys]", "Query on-chain storage (e.g. System.Number, System.Account <addr>)").option("--limit <n>", "Max entries to return for map queries (0 = unlimited)", {
2392
- default: DEFAULT_LIMIT
2393
- }).action(async (target, keys, opts) => {
2394
- if (!target) {
2395
- console.log("Usage: dot query <[Chain.]Pallet.Item> [...keys] [--chain <name>] [--output json]");
2396
- console.log("");
2397
- console.log("Examples:");
2398
- console.log(" $ dot query System.Number # plain storage value");
2399
- console.log(" $ dot query System.Account 5Grw... # single map entry");
2400
- console.log(" $ dot query System.Account # all entries (limit 100)");
2401
- console.log(" $ dot query System.Account --limit 10 # first 10 entries");
2402
- console.log(" $ dot query System.Account --limit 0 # all entries (no limit)");
2403
- console.log(" $ dot query Assets.Metadata 42 --chain asset-hub");
2404
- console.log(" $ dot query kusama.System.Account 5Grw... # chain prefix");
2860
+ async function handleQuery(target, keys, opts) {
2861
+ if (!target) {
2862
+ const config2 = await loadConfig();
2863
+ const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
2864
+ const meta = await loadMeta(chainName2, chainConfig2, opts.rpc);
2865
+ const pallets = listPallets(meta);
2866
+ const withStorage = pallets.filter((p) => p.storage.length > 0);
2867
+ printHeading(`Pallets with storage on ${chainName2} (${withStorage.length})`);
2868
+ for (const p of withStorage) {
2869
+ printItem(p.name, `${p.storage.length} storage items`);
2870
+ }
2871
+ console.log();
2872
+ return;
2873
+ }
2874
+ const dotIdx = target.indexOf(".");
2875
+ if (dotIdx === -1) {
2876
+ const config2 = await loadConfig();
2877
+ const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
2878
+ const meta = await loadMeta(chainName2, chainConfig2, opts.rpc);
2879
+ const pallet2 = resolvePallet(meta, palletName(target));
2880
+ if (pallet2.storage.length === 0) {
2881
+ console.log(`No storage items in ${pallet2.name}.`);
2405
2882
  return;
2406
2883
  }
2407
- const config = await loadConfig();
2408
- const knownChains = Object.keys(config.chains);
2409
- const parsed = parseTarget(target, { knownChains });
2410
- const effectiveChain = resolveTargetChain(parsed, opts.chain);
2411
- const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
2412
- const pallet = parsed.pallet;
2413
- const item = parsed.item;
2414
- const clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
2415
- try {
2416
- const meta = await getOrFetchMetadata(chainName, clientHandle);
2417
- const palletNames = getPalletNames(meta);
2418
- const palletInfo = findPallet(meta, pallet);
2419
- if (!palletInfo) {
2420
- throw new Error(suggestMessage("pallet", pallet, palletNames));
2884
+ printHeading(`${pallet2.name} Storage`);
2885
+ for (const s of pallet2.storage) {
2886
+ const valueType = describeType(meta.lookup, s.valueTypeId);
2887
+ let typeSuffix;
2888
+ if (s.keyTypeId != null) {
2889
+ const keyType = describeType(meta.lookup, s.keyTypeId);
2890
+ typeSuffix = `: ${keyType} → ${valueType} [map]`;
2891
+ } else {
2892
+ typeSuffix = `: ${valueType}`;
2421
2893
  }
2422
- const storageItem = palletInfo.storage.find((s) => s.name.toLowerCase() === item.toLowerCase());
2423
- if (!storageItem) {
2424
- const storageNames = palletInfo.storage.map((s) => s.name);
2425
- throw new Error(suggestMessage(`storage item in ${palletInfo.name}`, item, storageNames));
2426
- }
2427
- const unsafeApi = clientHandle.client.getUnsafeApi();
2428
- const storageApi = unsafeApi.query[palletInfo.name][storageItem.name];
2429
- const parsedKeys = parseStorageKeys(meta, palletInfo.name, storageItem, keys);
2430
- const format = opts.output ?? "pretty";
2431
- if (storageItem.type === "map" && parsedKeys.length === 0) {
2432
- const entries = await storageApi.getEntries();
2433
- const limit = Number(opts.limit);
2434
- const truncated = limit > 0 && entries.length > limit;
2435
- const display = truncated ? entries.slice(0, limit) : entries;
2436
- printResult(display.map((e) => ({
2437
- keys: e.keyArgs,
2438
- value: e.value
2439
- })), format);
2440
- if (truncated) {
2441
- console.error(`
2894
+ console.log(` ${CYAN}${s.name}${RESET}${DIM}${typeSuffix}${RESET}`);
2895
+ const summary = firstSentence(s.docs);
2896
+ if (summary) {
2897
+ console.log(` ${DIM}${summary}${RESET}`);
2898
+ }
2899
+ }
2900
+ console.log();
2901
+ return;
2902
+ }
2903
+ const pallet = target.slice(0, dotIdx);
2904
+ const item = target.slice(dotIdx + 1);
2905
+ const config = await loadConfig();
2906
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
2907
+ const clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
2908
+ try {
2909
+ const meta = await getOrFetchMetadata(chainName, clientHandle);
2910
+ const palletNames = getPalletNames(meta);
2911
+ const palletInfo = findPallet(meta, pallet);
2912
+ if (!palletInfo) {
2913
+ throw new Error(suggestMessage("pallet", pallet, palletNames));
2914
+ }
2915
+ const storageItem = palletInfo.storage.find((s) => s.name.toLowerCase() === item.toLowerCase());
2916
+ if (!storageItem) {
2917
+ const storageNames = palletInfo.storage.map((s) => s.name);
2918
+ throw new Error(suggestMessage(`storage item in ${palletInfo.name}`, item, storageNames));
2919
+ }
2920
+ const unsafeApi = clientHandle.client.getUnsafeApi();
2921
+ const storageApi = unsafeApi.query[palletInfo.name][storageItem.name];
2922
+ const parsedKeys = parseStorageKeys(meta, palletInfo.name, storageItem, keys);
2923
+ const format = opts.output ?? "pretty";
2924
+ if (storageItem.type === "map" && parsedKeys.length === 0) {
2925
+ const entries = await storageApi.getEntries();
2926
+ const limit = Number(opts.limit);
2927
+ const truncated = limit > 0 && entries.length > limit;
2928
+ const display = truncated ? entries.slice(0, limit) : entries;
2929
+ printResult(display.map((e) => ({
2930
+ keys: e.keyArgs,
2931
+ value: e.value
2932
+ })), format);
2933
+ if (truncated) {
2934
+ console.error(`
2442
2935
  ${DIM}Showing ${limit} of ${entries.length} entries. Use --limit 0 for all.${RESET}`);
2443
- }
2444
- } else {
2445
- const result = await storageApi.getValue(...parsedKeys);
2446
- printResult(result, format);
2447
2936
  }
2448
- } finally {
2449
- clientHandle.destroy();
2937
+ } else {
2938
+ const result = await storageApi.getValue(...parsedKeys);
2939
+ printResult(result, format);
2450
2940
  }
2451
- });
2941
+ } finally {
2942
+ clientHandle.destroy();
2943
+ }
2944
+ }
2945
+ function palletName(name) {
2946
+ return name;
2452
2947
  }
2453
- function parseStorageKeys(meta, palletName, storageItem, args) {
2948
+ function parseStorageKeys(meta, palletName2, storageItem, args) {
2454
2949
  if (storageItem.type === "plain" || storageItem.keyTypeId == null) {
2455
2950
  return args.map(parseValue);
2456
2951
  }
2457
2952
  if (args.length === 0)
2458
2953
  return [];
2459
- const storageEntry = meta.builder.buildStorage(palletName, storageItem.name);
2954
+ const storageEntry = meta.builder.buildStorage(palletName2, storageItem.name);
2460
2955
  const len = storageEntry.len;
2461
2956
  const keyEntry = meta.lookup(storageItem.keyTypeId);
2462
2957
  if (len === 1) {
@@ -2464,11 +2959,11 @@ function parseStorageKeys(meta, palletName, storageItem, args) {
2464
2959
  return [parseTypedArg(meta, keyEntry, args[0])];
2465
2960
  }
2466
2961
  if (keyEntry.type === "struct") {
2467
- const label = `${palletName}.${storageItem.name} key`;
2962
+ const label = `${palletName2}.${storageItem.name} key`;
2468
2963
  return [parseStructArgs(meta, keyEntry.value, args, label)];
2469
2964
  }
2470
2965
  const typeDesc = describeType(meta.lookup, storageItem.keyTypeId);
2471
- throw new Error(`${palletName}.${storageItem.name} key expects ${typeDesc}
2966
+ throw new Error(`${palletName2}.${storageItem.name} key expects ${typeDesc}
2472
2967
  ` + ` Pass 1 argument. Got ${args.length}.`);
2473
2968
  }
2474
2969
  if (args.length !== len) {
@@ -2478,7 +2973,7 @@ function parseStorageKeys(meta, palletName, storageItem, args) {
2478
2973
  } else {
2479
2974
  typeDesc = describeType(meta.lookup, storageItem.keyTypeId);
2480
2975
  }
2481
- throw new Error(`${palletName}.${storageItem.name} expects ${len} key arg(s): (${typeDesc}). Got ${args.length}.`);
2976
+ throw new Error(`${palletName2}.${storageItem.name} expects ${len} key arg(s): (${typeDesc}). Got ${args.length}.`);
2482
2977
  }
2483
2978
  if (keyEntry.type === "tuple") {
2484
2979
  const entries = keyEntry.value;
@@ -2490,156 +2985,180 @@ function parseStorageKeys(meta, palletName, storageItem, args) {
2490
2985
  // src/commands/tx.ts
2491
2986
  import { getViewBuilder as getViewBuilder2 } from "@polkadot-api/view-builder";
2492
2987
  import { Binary as Binary3 } from "polkadot-api";
2493
- function registerTxCommand(cli) {
2494
- cli.command("tx [target] [...args]", "Submit an extrinsic (e.g. Balances.transferKeepAlive <dest> <amount>)").option("--from <name>", "Account to sign with (required)").option("--dry-run", "Estimate fees without submitting").option("--encode", "Encode call to hex without signing or submitting").option("--ext <json>", `Custom signed extension values as JSON, e.g. '{"ExtName":{"value":...}}'`).action(async (target, args, opts) => {
2495
- if (!target) {
2496
- console.log("Usage: dot tx <[Chain.]Pallet.Call|0xCallHex> [...args] --from <account> [--dry-run] [--encode]");
2497
- console.log("");
2498
- console.log("Examples:");
2499
- console.log(" $ dot tx Balances.transferKeepAlive 5FHn... 1000000000000 --from alice");
2500
- console.log(" $ dot tx System.remark 0xdeadbeef --from alice --dry-run");
2501
- console.log(" $ dot tx 0x0001076465616462656566 --from alice");
2502
- console.log(" $ dot tx Assets.force_create 4 owner true 10 --encode --chain people");
2503
- console.log(" $ dot tx kusama.Balances.transferKeepAlive 5FHn... 1000000000000 --from alice");
2504
- return;
2988
+ async function handleTx(target, args, opts) {
2989
+ if (!target) {
2990
+ const config2 = await loadConfig();
2991
+ const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
2992
+ const meta = await loadMeta(chainName2, chainConfig2, opts.rpc);
2993
+ const pallets = listPallets(meta);
2994
+ const withCalls = pallets.filter((p) => p.calls.length > 0);
2995
+ printHeading(`Pallets with calls on ${chainName2} (${withCalls.length})`);
2996
+ for (const p of withCalls) {
2997
+ printItem(p.name, `${p.calls.length} calls`);
2505
2998
  }
2506
- if (!opts.from && !opts.encode) {
2507
- throw new Error("--from is required (or use --encode to output hex without signing)");
2999
+ console.log();
3000
+ return;
3001
+ }
3002
+ const isRawCall = /^0x[0-9a-fA-F]+$/.test(target);
3003
+ if (!isRawCall && target.indexOf(".") === -1) {
3004
+ const config2 = await loadConfig();
3005
+ const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
3006
+ const meta = await loadMeta(chainName2, chainConfig2, opts.rpc);
3007
+ const pallet2 = resolvePallet(meta, target);
3008
+ if (pallet2.calls.length === 0) {
3009
+ console.log(`No calls in ${pallet2.name}.`);
3010
+ return;
2508
3011
  }
2509
- if (opts.encode && opts.dryRun) {
2510
- throw new Error("--encode and --dry-run are mutually exclusive");
3012
+ printHeading(`${pallet2.name} Calls`);
3013
+ for (const c of pallet2.calls) {
3014
+ const callArgs = describeCallArgs(meta, pallet2.name, c.name);
3015
+ console.log(` ${CYAN}${c.name}${RESET}${DIM}${callArgs}${RESET}`);
3016
+ const summary = firstSentence(c.docs);
3017
+ if (summary) {
3018
+ console.log(` ${DIM}${summary}${RESET}`);
3019
+ }
2511
3020
  }
2512
- const isRawCall = /^0x[0-9a-fA-F]+$/.test(target);
2513
- if (opts.encode && isRawCall) {
2514
- throw new Error("--encode cannot be used with raw call hex (already encoded)");
3021
+ console.log();
3022
+ return;
3023
+ }
3024
+ if (!opts.from && !opts.encode) {
3025
+ if (isRawCall) {
3026
+ throw new Error("--from is required (or use --encode to output hex without signing)");
2515
3027
  }
2516
- const config = await loadConfig();
2517
- let effectiveChain = opts.chain;
2518
- let parsedTarget;
2519
- if (!isRawCall) {
2520
- const knownChains = Object.keys(config.chains);
2521
- parsedTarget = parseTarget(target, { knownChains });
2522
- effectiveChain = resolveTargetChain(parsedTarget, opts.chain);
3028
+ await showItemHelp("tx", target, opts);
3029
+ return;
3030
+ }
3031
+ if (opts.encode && opts.dryRun) {
3032
+ throw new Error("--encode and --dry-run are mutually exclusive");
3033
+ }
3034
+ if (opts.encode && isRawCall) {
3035
+ throw new Error("--encode cannot be used with raw call hex (already encoded)");
3036
+ }
3037
+ const config = await loadConfig();
3038
+ const effectiveChain = opts.chain;
3039
+ let pallet;
3040
+ let callName;
3041
+ if (!isRawCall) {
3042
+ const dotIdx = target.indexOf(".");
3043
+ pallet = target.slice(0, dotIdx);
3044
+ callName = target.slice(dotIdx + 1);
3045
+ }
3046
+ const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
3047
+ const signer = opts.encode ? undefined : await resolveAccountSigner(opts.from);
3048
+ let clientHandle;
3049
+ if (!opts.encode) {
3050
+ clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
3051
+ }
3052
+ try {
3053
+ let meta;
3054
+ if (clientHandle) {
3055
+ meta = await getOrFetchMetadata(chainName, clientHandle);
3056
+ } else {
3057
+ try {
3058
+ meta = await getOrFetchMetadata(chainName);
3059
+ } catch {
3060
+ clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
3061
+ meta = await getOrFetchMetadata(chainName, clientHandle);
3062
+ }
2523
3063
  }
2524
- const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
2525
- const signer = opts.encode ? undefined : await resolveAccountSigner(opts.from);
2526
- let clientHandle;
3064
+ let unsafeApi;
3065
+ let txOptions;
2527
3066
  if (!opts.encode) {
2528
- clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
3067
+ const userExtOverrides = parseExtOption(opts.ext);
3068
+ const customSignedExtensions = buildCustomSignedExtensions(meta, userExtOverrides);
3069
+ txOptions = Object.keys(customSignedExtensions).length > 0 ? { customSignedExtensions } : undefined;
3070
+ unsafeApi = clientHandle?.client.getUnsafeApi();
2529
3071
  }
2530
- try {
2531
- let meta;
2532
- if (clientHandle) {
2533
- meta = await getOrFetchMetadata(chainName, clientHandle);
2534
- } else {
2535
- try {
2536
- meta = await getOrFetchMetadata(chainName);
2537
- } catch {
2538
- clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
2539
- meta = await getOrFetchMetadata(chainName, clientHandle);
2540
- }
2541
- }
2542
- let unsafeApi;
2543
- let txOptions;
2544
- if (!opts.encode) {
2545
- const userExtOverrides = parseExtOption(opts.ext);
2546
- const customSignedExtensions = buildCustomSignedExtensions(meta, userExtOverrides);
2547
- txOptions = Object.keys(customSignedExtensions).length > 0 ? { customSignedExtensions } : undefined;
2548
- unsafeApi = clientHandle?.client.getUnsafeApi();
2549
- }
2550
- let tx;
2551
- let callHex;
2552
- if (isRawCall) {
2553
- if (args.length > 0) {
2554
- throw new Error(`Extra arguments are not allowed when submitting a raw call hex.
3072
+ let tx;
3073
+ let callHex;
3074
+ if (isRawCall) {
3075
+ if (args.length > 0) {
3076
+ throw new Error(`Extra arguments are not allowed when submitting a raw call hex.
2555
3077
  ` + "Usage: dot tx 0x<call_hex> --from <account>");
2556
- }
2557
- const callBinary = Binary3.fromHex(target);
2558
- tx = await unsafeApi.txFromCallData(callBinary);
2559
- callHex = target;
2560
- } else {
2561
- const pallet = parsedTarget.pallet;
2562
- const callName = parsedTarget.item;
2563
- const palletNames = getPalletNames(meta);
2564
- const palletInfo = findPallet(meta, pallet);
2565
- if (!palletInfo) {
2566
- throw new Error(suggestMessage("pallet", pallet, palletNames));
2567
- }
2568
- const callInfo = palletInfo.calls.find((c) => c.name.toLowerCase() === callName.toLowerCase());
2569
- if (!callInfo) {
2570
- const callNames = palletInfo.calls.map((c) => c.name);
2571
- throw new Error(suggestMessage(`call in ${palletInfo.name}`, callName, callNames));
2572
- }
2573
- const callData = parseCallArgs(meta, palletInfo.name, callInfo.name, args);
2574
- if (opts.encode) {
2575
- const { codec, location } = meta.builder.buildCall(palletInfo.name, callInfo.name);
2576
- const encodedArgs = codec.enc(callData);
2577
- const fullCall = new Uint8Array([location[0], location[1], ...encodedArgs]);
2578
- console.log(Binary3.fromBytes(fullCall).asHex());
2579
- return;
2580
- }
2581
- tx = unsafeApi.tx[palletInfo.name][callInfo.name](callData);
2582
- const encodedCall = await tx.getEncodedData();
2583
- callHex = encodedCall.asHex();
2584
- }
2585
- const decodedStr = decodeCall(meta, callHex);
2586
- if (opts.dryRun) {
2587
- const signerAddress = toSs58(signer.publicKey);
2588
- console.log(` ${BOLD}Chain:${RESET} ${chainName}`);
2589
- console.log(` ${BOLD}From:${RESET} ${opts.from} (${signerAddress})`);
2590
- console.log(` ${BOLD}Call:${RESET} ${callHex}`);
2591
- console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
2592
- try {
2593
- const fees = await tx.getEstimatedFees(signer?.publicKey, txOptions);
2594
- console.log(` ${BOLD}Estimated fees:${RESET} ${fees}`);
2595
- } catch (err) {
2596
- console.log(` ${BOLD}Estimated fees:${RESET} ${YELLOW}unable to estimate${RESET}`);
2597
- console.log(` ${DIM}${err.message ?? err}${RESET}`);
2598
- }
3078
+ }
3079
+ const callBinary = Binary3.fromHex(target);
3080
+ tx = await unsafeApi.txFromCallData(callBinary);
3081
+ callHex = target;
3082
+ } else {
3083
+ const palletNames = getPalletNames(meta);
3084
+ const palletInfo = findPallet(meta, pallet);
3085
+ if (!palletInfo) {
3086
+ throw new Error(suggestMessage("pallet", pallet, palletNames));
3087
+ }
3088
+ const callInfo = palletInfo.calls.find((c) => c.name.toLowerCase() === callName.toLowerCase());
3089
+ if (!callInfo) {
3090
+ const callNames = palletInfo.calls.map((c) => c.name);
3091
+ throw new Error(suggestMessage(`call in ${palletInfo.name}`, callName, callNames));
3092
+ }
3093
+ const callData = parseCallArgs(meta, palletInfo.name, callInfo.name, args);
3094
+ if (opts.encode) {
3095
+ const { codec, location } = meta.builder.buildCall(palletInfo.name, callInfo.name);
3096
+ const encodedArgs = codec.enc(callData);
3097
+ const fullCall = new Uint8Array([location[0], location[1], ...encodedArgs]);
3098
+ console.log(Binary3.fromBytes(fullCall).asHex());
2599
3099
  return;
2600
3100
  }
2601
- const result = await watchTransaction(tx.signSubmitAndWatch(signer, txOptions));
2602
- console.log();
3101
+ tx = unsafeApi.tx[palletInfo.name][callInfo.name](callData);
3102
+ const encodedCall = await tx.getEncodedData();
3103
+ callHex = encodedCall.asHex();
3104
+ }
3105
+ const decodedStr = decodeCall(meta, callHex);
3106
+ if (opts.dryRun) {
3107
+ const signerAddress = toSs58(signer.publicKey);
2603
3108
  console.log(` ${BOLD}Chain:${RESET} ${chainName}`);
3109
+ console.log(` ${BOLD}From:${RESET} ${opts.from} (${signerAddress})`);
2604
3110
  console.log(` ${BOLD}Call:${RESET} ${callHex}`);
2605
3111
  console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
2606
- console.log(` ${BOLD}Tx:${RESET} ${result.txHash}`);
2607
- let dispatchErrorMsg;
2608
- if (result.ok) {
2609
- console.log(` ${BOLD}Status:${RESET} ${GREEN}ok${RESET}`);
2610
- } else {
2611
- dispatchErrorMsg = formatDispatchError(result.dispatchError);
2612
- console.log(` ${BOLD}Status:${RESET} ${RED}dispatch error${RESET}`);
2613
- console.log(` ${BOLD}Error:${RESET} ${dispatchErrorMsg}`);
3112
+ try {
3113
+ const fees = await tx.getEstimatedFees(signer?.publicKey, txOptions);
3114
+ console.log(` ${BOLD}Estimated fees:${RESET} ${fees}`);
3115
+ } catch (err) {
3116
+ console.log(` ${BOLD}Estimated fees:${RESET} ${YELLOW}unable to estimate${RESET}`);
3117
+ console.log(` ${DIM}${err.message ?? err}${RESET}`);
2614
3118
  }
2615
- if (result.events && result.events.length > 0) {
2616
- console.log(` ${BOLD}Events:${RESET}`);
2617
- for (const event of result.events) {
2618
- const name = `${CYAN}${event.type}${RESET}.${CYAN}${event.value?.type ?? ""}${RESET}`;
2619
- const payload = event.value?.value;
2620
- if (payload && typeof payload === "object") {
2621
- const fields = Object.entries(payload).map(([k, v]) => `${k}: ${formatEventValue(v)}`).join(", ");
2622
- console.log(` ${name} { ${fields} }`);
2623
- } else {
2624
- console.log(` ${name}`);
2625
- }
3119
+ return;
3120
+ }
3121
+ const result = await watchTransaction(tx.signSubmitAndWatch(signer, txOptions));
3122
+ console.log();
3123
+ console.log(` ${BOLD}Chain:${RESET} ${chainName}`);
3124
+ console.log(` ${BOLD}Call:${RESET} ${callHex}`);
3125
+ console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
3126
+ console.log(` ${BOLD}Tx:${RESET} ${result.txHash}`);
3127
+ let dispatchErrorMsg;
3128
+ if (result.ok) {
3129
+ console.log(` ${BOLD}Status:${RESET} ${GREEN}ok${RESET}`);
3130
+ } else {
3131
+ dispatchErrorMsg = formatDispatchError(result.dispatchError);
3132
+ console.log(` ${BOLD}Status:${RESET} ${RED}dispatch error${RESET}`);
3133
+ console.log(` ${BOLD}Error:${RESET} ${dispatchErrorMsg}`);
3134
+ }
3135
+ if (result.events && result.events.length > 0) {
3136
+ console.log(` ${BOLD}Events:${RESET}`);
3137
+ for (const event of result.events) {
3138
+ const name = `${CYAN}${event.type}${RESET}.${CYAN}${event.value?.type ?? ""}${RESET}`;
3139
+ const payload = event.value?.value;
3140
+ if (payload && typeof payload === "object") {
3141
+ const fields = Object.entries(payload).map(([k, v]) => `${k}: ${formatEventValue(v)}`).join(", ");
3142
+ console.log(` ${name} { ${fields} }`);
3143
+ } else {
3144
+ console.log(` ${name}`);
2626
3145
  }
2627
3146
  }
2628
- const rpcUrl = primaryRpc(opts.rpc ?? chainConfig.rpc);
2629
- if (rpcUrl) {
2630
- const blockHash = result.block.hash;
2631
- console.log(` ${BOLD}Explorer:${RESET}`);
2632
- console.log(` ${DIM}PolkadotJS${RESET} ${pjsAppsLink(rpcUrl, blockHash)}`);
2633
- console.log(` ${DIM}PAPI${RESET} ${papiLink(rpcUrl, blockHash)}`);
2634
- }
2635
- console.log();
2636
- if (!result.ok) {
2637
- throw new CliError(`Transaction dispatch error: ${dispatchErrorMsg}`);
2638
- }
2639
- } finally {
2640
- clientHandle?.destroy();
2641
3147
  }
2642
- });
3148
+ const rpcUrl = primaryRpc(opts.rpc ?? chainConfig.rpc);
3149
+ if (rpcUrl) {
3150
+ const blockHash = result.block.hash;
3151
+ console.log(` ${BOLD}Explorer:${RESET}`);
3152
+ console.log(` ${DIM}PolkadotJS${RESET} ${pjsAppsLink(rpcUrl, blockHash)}`);
3153
+ console.log(` ${DIM}PAPI${RESET} ${papiLink(rpcUrl, blockHash)}`);
3154
+ }
3155
+ console.log();
3156
+ if (!result.ok) {
3157
+ throw new CliError(`Transaction dispatch error: ${dispatchErrorMsg}`);
3158
+ }
3159
+ } finally {
3160
+ clientHandle?.destroy();
3161
+ }
2643
3162
  }
2644
3163
  function formatDispatchError(err) {
2645
3164
  if (err.type === "Module" && err.value && typeof err.value === "object") {
@@ -2662,10 +3181,10 @@ function decodeCall(meta, callHex) {
2662
3181
  try {
2663
3182
  const viewBuilder = getViewBuilder2(meta.lookup);
2664
3183
  const decoded = viewBuilder.callDecoder(callHex);
2665
- const palletName = decoded.pallet.value.name;
3184
+ const palletName2 = decoded.pallet.value.name;
2666
3185
  const callName = decoded.call.value.name;
2667
3186
  const argsStr = formatDecodedArgs(decoded.args.value);
2668
- return `${palletName}.${callName}${argsStr}`;
3187
+ return `${palletName2}.${callName}${argsStr}`;
2669
3188
  } catch {}
2670
3189
  try {
2671
3190
  return decodeCallFallback(meta, callHex);
@@ -2679,15 +3198,15 @@ function decodeCallFallback(meta, callHex) {
2679
3198
  throw new Error("No RuntimeCall type ID");
2680
3199
  const codec = meta.builder.buildDefinition(callTypeId);
2681
3200
  const decoded = codec.dec(Binary3.fromHex(callHex).asBytes());
2682
- const palletName = decoded.type;
3201
+ const palletName2 = decoded.type;
2683
3202
  const call = decoded.value;
2684
3203
  const callName = call.type;
2685
3204
  const args = call.value;
2686
3205
  if (args === undefined || args === null) {
2687
- return `${palletName}.${callName}`;
3206
+ return `${palletName2}.${callName}`;
2688
3207
  }
2689
3208
  const argsStr = formatRawDecoded(args);
2690
- return `${palletName}.${callName} ${argsStr}`;
3209
+ return `${palletName2}.${callName} ${argsStr}`;
2691
3210
  }
2692
3211
  function formatRawDecoded(value) {
2693
3212
  if (value === undefined || value === null)
@@ -2820,8 +3339,8 @@ function formatEventValue(v) {
2820
3339
  }
2821
3340
  return JSON.stringify(v, (_k, val) => typeof val === "bigint" ? val.toString() : val);
2822
3341
  }
2823
- function parseCallArgs(meta, palletName, callName, args) {
2824
- const palletMeta = meta.unified.pallets.find((p) => p.name === palletName);
3342
+ function parseCallArgs(meta, palletName2, callName, args) {
3343
+ const palletMeta = meta.unified.pallets.find((p) => p.name === palletName2);
2825
3344
  if (!palletMeta?.calls)
2826
3345
  return;
2827
3346
  const callsEntry = meta.lookup(palletMeta.calls.type);
@@ -2832,22 +3351,22 @@ function parseCallArgs(meta, palletName, callName, args) {
2832
3351
  return;
2833
3352
  if (variant.type === "void") {
2834
3353
  if (args.length > 0) {
2835
- throw new Error(`${palletName}.${callName} takes no arguments, but ${args.length} provided.`);
3354
+ throw new Error(`${palletName2}.${callName} takes no arguments, but ${args.length} provided.`);
2836
3355
  }
2837
3356
  return;
2838
3357
  }
2839
3358
  if (variant.type === "struct") {
2840
- return parseStructArgs2(meta, variant.value, args, `${palletName}.${callName}`);
3359
+ return parseStructArgs2(meta, variant.value, args, `${palletName2}.${callName}`);
2841
3360
  }
2842
3361
  if (variant.type === "lookupEntry") {
2843
3362
  const inner = variant.value;
2844
3363
  if (inner.type === "struct") {
2845
- return parseStructArgs2(meta, inner.value, args, `${palletName}.${callName}`);
3364
+ return parseStructArgs2(meta, inner.value, args, `${palletName2}.${callName}`);
2846
3365
  }
2847
3366
  if (inner.type === "void")
2848
3367
  return;
2849
3368
  if (args.length !== 1) {
2850
- throw new Error(`${palletName}.${callName} takes 1 argument (${describeType(meta.lookup, inner.id)}), but ${args.length} provided.`);
3369
+ throw new Error(`${palletName2}.${callName} takes 1 argument (${describeType(meta.lookup, inner.id)}), but ${args.length} provided.`);
2851
3370
  }
2852
3371
  try {
2853
3372
  return parseTypedArg2(meta, inner, args[0]);
@@ -2859,7 +3378,7 @@ function parseCallArgs(meta, palletName, callName, args) {
2859
3378
  if (variant.type === "tuple") {
2860
3379
  const entries = variant.value;
2861
3380
  if (args.length !== entries.length) {
2862
- throw new Error(`${palletName}.${callName} takes ${entries.length} arguments, but ${args.length} provided.`);
3381
+ throw new Error(`${palletName2}.${callName} takes ${entries.length} arguments, but ${args.length} provided.`);
2863
3382
  }
2864
3383
  return entries.map((entry, i) => {
2865
3384
  try {
@@ -3252,10 +3771,46 @@ function watchTransaction(observable) {
3252
3771
  });
3253
3772
  }
3254
3773
 
3774
+ // src/config/store.ts
3775
+ import { access as access3, mkdir as mkdir3, readFile as readFile3, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
3776
+ import { homedir as homedir2 } from "node:os";
3777
+ import { join as join3 } from "node:path";
3778
+ var DOT_DIR2 = join3(homedir2(), ".polkadot");
3779
+ var CONFIG_PATH2 = join3(DOT_DIR2, "config.json");
3780
+ var CHAINS_DIR2 = join3(DOT_DIR2, "chains");
3781
+ async function ensureDir3(dir) {
3782
+ await mkdir3(dir, { recursive: true });
3783
+ }
3784
+ async function fileExists3(path) {
3785
+ try {
3786
+ await access3(path);
3787
+ return true;
3788
+ } catch {
3789
+ return false;
3790
+ }
3791
+ }
3792
+ async function loadConfig2() {
3793
+ await ensureDir3(DOT_DIR2);
3794
+ if (await fileExists3(CONFIG_PATH2)) {
3795
+ const saved = JSON.parse(await readFile3(CONFIG_PATH2, "utf-8"));
3796
+ return {
3797
+ ...saved,
3798
+ chains: { ...DEFAULT_CONFIG.chains, ...saved.chains }
3799
+ };
3800
+ }
3801
+ await saveConfig2(DEFAULT_CONFIG);
3802
+ return DEFAULT_CONFIG;
3803
+ }
3804
+ async function saveConfig2(config) {
3805
+ await ensureDir3(DOT_DIR2);
3806
+ await writeFile3(CONFIG_PATH2, `${JSON.stringify(config, null, 2)}
3807
+ `);
3808
+ }
3809
+
3255
3810
  // src/core/update-notifier.ts
3256
3811
  import { readFileSync } from "node:fs";
3257
- import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
3258
- import { join as join3 } from "node:path";
3812
+ import { mkdir as mkdir4, writeFile as writeFile4 } from "node:fs/promises";
3813
+ import { join as join4 } from "node:path";
3259
3814
  var CACHE_FILE = "update-check.json";
3260
3815
  var STALE_MS = 24 * 60 * 60 * 1000;
3261
3816
  var FETCH_TIMEOUT_MS = 5000;
@@ -3311,7 +3866,7 @@ function buildNotificationBox(current, latest) {
3311
3866
  `);
3312
3867
  }
3313
3868
  function getCachePath() {
3314
- return join3(getConfigDir(), CACHE_FILE);
3869
+ return join4(getConfigDir(), CACHE_FILE);
3315
3870
  }
3316
3871
  function readCache() {
3317
3872
  try {
@@ -3323,8 +3878,8 @@ function readCache() {
3323
3878
  }
3324
3879
  async function writeCache(cache) {
3325
3880
  try {
3326
- await mkdir3(getConfigDir(), { recursive: true });
3327
- await writeFile3(getCachePath(), `${JSON.stringify(cache)}
3881
+ await mkdir4(getConfigDir(), { recursive: true });
3882
+ await writeFile4(getCachePath(), `${JSON.stringify(cache)}
3328
3883
  `);
3329
3884
  } catch {}
3330
3885
  }
@@ -3379,6 +3934,67 @@ class CliError2 extends Error {
3379
3934
  }
3380
3935
  }
3381
3936
 
3937
+ // src/utils/parse-dot-path.ts
3938
+ var CATEGORY_ALIASES = {
3939
+ query: "query",
3940
+ tx: "tx",
3941
+ const: "const",
3942
+ consts: "const",
3943
+ constants: "const",
3944
+ events: "events",
3945
+ event: "events",
3946
+ errors: "errors",
3947
+ error: "errors"
3948
+ };
3949
+ function matchCategory(segment) {
3950
+ return CATEGORY_ALIASES[segment.toLowerCase()];
3951
+ }
3952
+ function matchChain(segment, knownChains) {
3953
+ return knownChains.some((c) => c.toLowerCase() === segment.toLowerCase());
3954
+ }
3955
+ function parseDotPath(input, knownChains = []) {
3956
+ const parts = input.split(".");
3957
+ switch (parts.length) {
3958
+ case 1: {
3959
+ const cat = matchCategory(parts[0]);
3960
+ if (cat)
3961
+ return { category: cat };
3962
+ throw new Error(`Unknown command "${parts[0]}". Expected a category (query, tx, const, events, errors) or a named command.`);
3963
+ }
3964
+ case 2: {
3965
+ const cat = matchCategory(parts[0]);
3966
+ if (cat) {
3967
+ return { category: cat, pallet: parts[1] };
3968
+ }
3969
+ const cat2 = matchCategory(parts[1]);
3970
+ if (cat2 && matchChain(parts[0], knownChains)) {
3971
+ return { chain: parts[0], category: cat2 };
3972
+ }
3973
+ throw new Error(`Unknown command "${input}". Expected format: category.Pallet or Chain.category (e.g. query.System or polkadot.query)`);
3974
+ }
3975
+ case 3: {
3976
+ const cat = matchCategory(parts[0]);
3977
+ if (cat) {
3978
+ return { category: cat, pallet: parts[1], item: parts[2] };
3979
+ }
3980
+ const cat2 = matchCategory(parts[1]);
3981
+ if (cat2 && matchChain(parts[0], knownChains)) {
3982
+ return { chain: parts[0], category: cat2, pallet: parts[2] };
3983
+ }
3984
+ throw new Error(`Unknown command "${input}". Expected format: category.Pallet.Item or Chain.category.Pallet`);
3985
+ }
3986
+ case 4: {
3987
+ const cat = matchCategory(parts[1]);
3988
+ if (cat && matchChain(parts[0], knownChains)) {
3989
+ return { chain: parts[0], category: cat, pallet: parts[2], item: parts[3] };
3990
+ }
3991
+ throw new Error(`Unknown command "${input}". Expected format: Chain.category.Pallet.Item (e.g. polkadot.query.System.Account)`);
3992
+ }
3993
+ default:
3994
+ throw new Error(`Unknown command "${input}". Too many segments. Expected format: [Chain.]category[.Pallet[.Item]]`);
3995
+ }
3996
+ }
3997
+
3382
3998
  // src/cli.ts
3383
3999
  startBackgroundCheck(version);
3384
4000
  var cli = cac("dot");
@@ -3390,14 +4006,105 @@ cli.option("--output <format>", "Output format: pretty or json", {
3390
4006
  });
3391
4007
  registerChainCommands(cli);
3392
4008
  registerInspectCommand(cli);
3393
- registerQueryCommand(cli);
3394
- registerConstCommand(cli);
3395
- registerFocusedInspectCommands(cli);
3396
4009
  registerAccountCommands(cli);
3397
- registerTxCommand(cli);
3398
4010
  registerHashCommand(cli);
4011
+ cli.command("[dotpath] [...args]").option("--from <name>", "Account to sign with (for tx)").option("--dry-run", "Estimate fees without submitting (for tx)").option("--encode", "Encode call to hex without signing (for tx)").option("--ext <json>", "Custom signed extension values as JSON (for tx)").option("--limit <n>", "Max entries to return for map queries (0 = unlimited)", {
4012
+ default: 100
4013
+ }).action(async (dotpath, args, opts) => {
4014
+ if (!dotpath) {
4015
+ printHelp();
4016
+ return;
4017
+ }
4018
+ const config = await loadConfig2();
4019
+ const knownChains = Object.keys(config.chains);
4020
+ let parsed;
4021
+ try {
4022
+ parsed = parseDotPath(dotpath, knownChains);
4023
+ } catch {
4024
+ throw new CliError2(`Unknown command "${dotpath}". Run "dot --help" for available commands.`);
4025
+ }
4026
+ if (parsed.chain && opts.chain) {
4027
+ throw new CliError2(`Chain specified both as prefix ("${parsed.chain}") and as --chain flag ("${opts.chain}"). Use one or the other.`);
4028
+ }
4029
+ const effectiveChain = parsed.chain ?? opts.chain;
4030
+ const handlerOpts = { chain: effectiveChain, rpc: opts.rpc, output: opts.output };
4031
+ const target = parsed.pallet ? parsed.item ? `${parsed.pallet}.${parsed.item}` : parsed.pallet : undefined;
4032
+ if (cli.options.help && parsed.pallet && parsed.item) {
4033
+ await showItemHelp2(parsed.category, target, handlerOpts);
4034
+ return;
4035
+ }
4036
+ switch (parsed.category) {
4037
+ case "query":
4038
+ await handleQuery(target, args, { ...handlerOpts, limit: opts.limit });
4039
+ break;
4040
+ case "tx":
4041
+ if (parsed.pallet && /^0x[0-9a-fA-F]+$/.test(parsed.pallet)) {
4042
+ await handleTx(parsed.pallet, args, {
4043
+ ...handlerOpts,
4044
+ from: opts.from,
4045
+ dryRun: opts.dryRun,
4046
+ encode: opts.encode,
4047
+ ext: opts.ext
4048
+ });
4049
+ } else {
4050
+ await handleTx(target, args, {
4051
+ ...handlerOpts,
4052
+ from: opts.from,
4053
+ dryRun: opts.dryRun,
4054
+ encode: opts.encode,
4055
+ ext: opts.ext
4056
+ });
4057
+ }
4058
+ break;
4059
+ case "const":
4060
+ await handleConst(target, handlerOpts);
4061
+ break;
4062
+ case "events":
4063
+ await handleEvents2(target, handlerOpts);
4064
+ break;
4065
+ case "errors":
4066
+ await handleErrors2(target, handlerOpts);
4067
+ break;
4068
+ }
4069
+ });
3399
4070
  cli.option("--help, -h", "Display this message");
3400
4071
  cli.version(version);
4072
+ function printHelp() {
4073
+ console.log(`dot/${version} \u2014 Polkadot CLI`);
4074
+ console.log();
4075
+ console.log("Usage:");
4076
+ console.log(" dot <category>[.Pallet[.Item]] [args] [options]");
4077
+ console.log(" dot [Chain.]<category>[.Pallet[.Item]] [args] [options]");
4078
+ console.log();
4079
+ console.log("Categories:");
4080
+ console.log(" query Query on-chain storage");
4081
+ console.log(" tx Submit an extrinsic");
4082
+ console.log(" const Look up or list pallet constants");
4083
+ console.log(" events List or inspect pallet events");
4084
+ console.log(" errors List or inspect pallet errors");
4085
+ console.log();
4086
+ console.log("Examples:");
4087
+ console.log(" dot query.System.Account <addr> Query a storage item");
4088
+ console.log(" dot query.System List storage items in System");
4089
+ console.log(" dot tx.System.remark 0xdead --from alice");
4090
+ console.log(" dot const.Balances.ExistentialDeposit");
4091
+ console.log(" dot events.Balances List events in Balances");
4092
+ console.log(" dot polkadot.query.System.Number With chain prefix");
4093
+ console.log();
4094
+ console.log("Commands:");
4095
+ console.log(" inspect [target] Inspect chain metadata (alias: explore)");
4096
+ console.log(" chain Manage chain configurations");
4097
+ console.log(" account Manage accounts");
4098
+ console.log(" hash Hash utilities");
4099
+ console.log();
4100
+ console.log("Global options:");
4101
+ console.log(" --chain <name> Target chain (default from config)");
4102
+ console.log(" --rpc <url> Override RPC endpoint");
4103
+ console.log(" --light-client Use Smoldot light client");
4104
+ console.log(" --output <format> Output format: pretty or json");
4105
+ console.log(" --help, -h Display this message");
4106
+ console.log(" --version Show version");
4107
+ }
3401
4108
  async function showUpdateAndExit(code) {
3402
4109
  await waitForPendingCheck();
3403
4110
  const note = getUpdateNotification(version);
@@ -3422,17 +4129,17 @@ async function main() {
3422
4129
  if (cli.options.version) {
3423
4130
  await showUpdateAndExit(0);
3424
4131
  } else if (cli.options.help) {
3425
- if (cli.matchedCommandName) {
4132
+ if (cli.matchedCommand) {
3426
4133
  const result = cli.runMatchedCommand();
3427
4134
  if (result && typeof result.then === "function") {
3428
4135
  await result.then(() => showUpdateAndExit(0), handleError);
3429
4136
  }
3430
4137
  } else {
3431
- cli.outputHelp();
4138
+ printHelp();
3432
4139
  await showUpdateAndExit(0);
3433
4140
  }
3434
- } else if (!cli.matchedCommandName) {
3435
- cli.outputHelp();
4141
+ } else if (!cli.matchedCommand) {
4142
+ printHelp();
3436
4143
  await showUpdateAndExit(0);
3437
4144
  } else {
3438
4145
  const result = cli.runMatchedCommand();