polkadot-cli 1.22.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +20 -0
  2. package/dist/cli.mjs +82 -22
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -81,6 +81,24 @@ To pull the latest skill updates:
81
81
  /plugin marketplace update polkadot-cli
82
82
  ```
83
83
 
84
+ ## Plugins
85
+
86
+ `dot` supports git/cargo-style external subcommands: any executable named `dot-<name>` on your PATH runs as `dot <name>`, with the remaining arguments forwarded verbatim, stdio inherited, and the plugin's exit code passed through.
87
+
88
+ ```bash
89
+ npm install -g dot-example # ships a `dot-example` binary
90
+ dot example status --json # runs: dot-example status --json
91
+ ```
92
+
93
+ This is how domain-specific tooling extends `dot` without the CLI loading third-party code into its own process. Plugins are ordinary child processes — the intended pattern is that a plugin invokes `dot` itself for anything chain- or signing-related (e.g. `dot tx.… --from <account>`), so key handling stays inside `dot`.
94
+
95
+ Plugins receive a `DOT_BIN` environment variable pointing at the entry script of the `dot` that dispatched them (the same convention as cargo's `CARGO`), so they can invoke the exact same installation rather than whatever `dot` is first on PATH.
96
+
97
+ Notes:
98
+
99
+ - Only a bare first token dispatches: `dot foo.bar` is always dot-path syntax, `./file.yaml` is always file input — neither will hit the plugin lookup.
100
+ - Built-in commands and categories always win over a plugin of the same name.
101
+
84
102
  ## Usage
85
103
 
86
104
  ### Manage chains
@@ -797,6 +815,8 @@ dot polkadot.const.Balances.ExistentialDeposit --json | jq
797
815
 
798
816
  Works offline from cached metadata after the first fetch. The chain is required. Prefer the chain-prefix-on-target form (`dot inspect polkadot.System`); `--chain` is equivalent. Note that `dot polkadot.inspect.X` does **not** parse — `inspect` is a top-level command, not a dotpath category.
799
817
 
818
+ `inspect` is **forgiving**: it accepts the same dot-paths you use to invoke a call and degrades to discovery rather than erroring. A `kind` segment (`tx`/`query`/`const`/`events`/`errors`/…) is tolerated and ignored — so `dot inspect polkadot.tx.System.remark` describes the `System.remark` call just like `dot inspect polkadot.System.remark` does. Partial paths list rather than fail: `dot inspect polkadot.query.System` (and the bare `dot inspect System`) list the pallet's items.
819
+
800
820
  Output is **width-aware**: short type signatures stay on a single line, longer ones expand across multiple lines with field names aligned. Composite struct fields, enum variants, and call arguments are color-coded (cyan field names, yellow primitives, magenta container keywords like `Vec`/`Option`, green enum variants) when stdout is a TTY; piped output stays plain.
801
821
 
802
822
  ```bash
package/dist/cli.mjs CHANGED
@@ -3819,8 +3819,8 @@ var exports_complete = {};
3819
3819
  __export(exports_complete, {
3820
3820
  generateCompletions: () => generateCompletions
3821
3821
  });
3822
- function matchCategory2(s) {
3823
- return CATEGORY_ALIASES2[s.toLowerCase()];
3822
+ function matchCategory3(s) {
3823
+ return CATEGORY_ALIASES3[s.toLowerCase()];
3824
3824
  }
3825
3825
  async function loadPallets(_config, chainName) {
3826
3826
  const raw = await loadMetadata(chainName);
@@ -3951,7 +3951,7 @@ function detectCategory(words, _knownChains) {
3951
3951
  continue;
3952
3952
  const parts = w.split(".");
3953
3953
  for (const part of parts) {
3954
- const cat = matchCategory2(part);
3954
+ const cat = matchCategory3(part);
3955
3955
  if (cat)
3956
3956
  return cat;
3957
3957
  }
@@ -3973,11 +3973,11 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
3973
3973
  return filterPrefix(candidates, partial);
3974
3974
  }
3975
3975
  const first = completeSegments[0] ?? "";
3976
- const firstIsCategory = matchCategory2(first) !== undefined;
3976
+ const firstIsCategory = matchCategory3(first) !== undefined;
3977
3977
  const firstIsChain = knownChains.some((c) => c.toLowerCase() === first.toLowerCase());
3978
3978
  const chainFromFlag = resolveChainFromArgs(precedingWords, config);
3979
3979
  if (firstIsCategory) {
3980
- const category = matchCategory2(first);
3980
+ const category = matchCategory3(first);
3981
3981
  if (category === "apis") {
3982
3982
  return completeApisCategory(first, numComplete, endsWithDot, completeSegments, currentWord, config, chainFromFlag);
3983
3983
  }
@@ -4037,7 +4037,7 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
4037
4037
  return filterPrefix(candidates, currentWord);
4038
4038
  }
4039
4039
  if (numComplete === 2) {
4040
- const category = matchCategory2(completeSegments[1]);
4040
+ const category = matchCategory3(completeSegments[1]);
4041
4041
  if (!category)
4042
4042
  return [];
4043
4043
  if (category === "apis") {
@@ -4058,7 +4058,7 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
4058
4058
  return filterPrefix(candidates, endsWithDot ? currentWord.slice(0, -1) : currentWord);
4059
4059
  }
4060
4060
  if (numComplete === 3) {
4061
- const category = matchCategory2(completeSegments[1]);
4061
+ const category = matchCategory3(completeSegments[1]);
4062
4062
  if (!category)
4063
4063
  return [];
4064
4064
  if (category === "apis") {
@@ -4140,7 +4140,7 @@ async function completeRpcCategory(prefix, numComplete, endsWithDot, currentWord
4140
4140
  }
4141
4141
  return [];
4142
4142
  }
4143
- var CATEGORIES2, CATEGORY_ALIASES2, NAMED_COMMANDS, CHAIN_SUBCOMMANDS, ACCOUNT_SUBCOMMANDS, GLOBAL_OPTIONS, TX_OPTIONS, QUERY_OPTIONS;
4143
+ var CATEGORIES2, CATEGORY_ALIASES3, NAMED_COMMANDS, CHAIN_SUBCOMMANDS, ACCOUNT_SUBCOMMANDS, GLOBAL_OPTIONS, TX_OPTIONS, QUERY_OPTIONS;
4144
4144
  var init_complete = __esm(() => {
4145
4145
  init_accounts_store();
4146
4146
  init_store();
@@ -4158,7 +4158,7 @@ var init_complete = __esm(() => {
4158
4158
  "extensions",
4159
4159
  "rpc"
4160
4160
  ];
4161
- CATEGORY_ALIASES2 = {
4161
+ CATEGORY_ALIASES3 = {
4162
4162
  query: "query",
4163
4163
  tx: "tx",
4164
4164
  const: "const",
@@ -4216,7 +4216,7 @@ var init_complete = __esm(() => {
4216
4216
  // src/cli.ts
4217
4217
  import cac from "cac";
4218
4218
  // package.json
4219
- var version = "1.22.0";
4219
+ var version = "1.23.0";
4220
4220
 
4221
4221
  // src/commands/account.ts
4222
4222
  init_accounts_store();
@@ -6964,10 +6964,42 @@ init_output();
6964
6964
  init_pretty_type();
6965
6965
  init_cli();
6966
6966
 
6967
+ // src/utils/parse-dot-path.ts
6968
+ var CATEGORY_ALIASES = {
6969
+ query: "query",
6970
+ tx: "tx",
6971
+ const: "const",
6972
+ consts: "const",
6973
+ constants: "const",
6974
+ events: "events",
6975
+ event: "events",
6976
+ errors: "errors",
6977
+ error: "errors",
6978
+ apis: "apis",
6979
+ api: "apis",
6980
+ extensions: "extensions",
6981
+ extension: "extensions",
6982
+ ext: "extensions",
6983
+ rpc: "rpc"
6984
+ };
6985
+ function matchCategory(segment) {
6986
+ return CATEGORY_ALIASES[segment.toLowerCase()];
6987
+ }
6988
+
6967
6989
  // src/utils/parse-target.ts
6990
+ function stripKindSegment(parts, knownChains) {
6991
+ if (parts.length >= 3 && parts[0] && knownChains.some((c) => c.toLowerCase() === parts[0].toLowerCase()) && parts[1] && matchCategory(parts[1])) {
6992
+ return [parts[0], ...parts.slice(2)];
6993
+ }
6994
+ if (parts.length >= 2 && parts[0] && matchCategory(parts[0])) {
6995
+ return parts.slice(1);
6996
+ }
6997
+ return parts;
6998
+ }
6968
6999
  function parseTarget(input, options) {
6969
- const parts = input.split(".");
7000
+ let parts = input.split(".");
6970
7001
  if (options?.allowPalletOnly) {
7002
+ parts = stripKindSegment(parts, options.knownChains ?? []);
6971
7003
  switch (parts.length) {
6972
7004
  case 1:
6973
7005
  if (!parts[0]) {
@@ -6988,7 +7020,7 @@ function parseTarget(input, options) {
6988
7020
  }
6989
7021
  return { chain: parts[0], pallet: parts[1], item: parts[2] };
6990
7022
  default:
6991
- throw new Error(`Invalid target "${input}". Expected format: Pallet, Pallet.Item, or Chain.Pallet.Item`);
7023
+ throw new Error(`Invalid target "${input}". Expected format: Pallet, Pallet.Item, Chain.Pallet.Item, ` + `or a dot-path with a kind segment (e.g. polkadot.tx.System.remark)`);
6992
7024
  }
6993
7025
  }
6994
7026
  switch (parts.length) {
@@ -9522,6 +9554,24 @@ function printGlobalDryRunHint() {
9522
9554
  `);
9523
9555
  }
9524
9556
 
9557
+ // src/core/external-command.ts
9558
+ var PLUGIN_PREFIX = "dot-";
9559
+ function isExternalCommandCandidate(name) {
9560
+ return /^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(name);
9561
+ }
9562
+ function findExternalCommand(name) {
9563
+ if (!isExternalCommandCandidate(name))
9564
+ return null;
9565
+ return Bun.which(`${PLUGIN_PREFIX}${name}`, { PATH: process.env.PATH ?? "" });
9566
+ }
9567
+ function runExternalCommand(binPath, args) {
9568
+ const result = Bun.spawnSync([binPath, ...args], {
9569
+ stdio: ["inherit", "inherit", "inherit"],
9570
+ env: { ...process.env, DOT_BIN: process.argv[1] ?? "dot" }
9571
+ });
9572
+ return result.exitCode ?? 1;
9573
+ }
9574
+
9525
9575
  // src/core/file-loader.ts
9526
9576
  init_errors();
9527
9577
  import { access as access4, readFile as readFile7 } from "node:fs/promises";
@@ -9936,7 +9986,7 @@ function formatRuntimeError2(err) {
9936
9986
  }
9937
9987
 
9938
9988
  // src/utils/parse-dot-path.ts
9939
- var CATEGORY_ALIASES = {
9989
+ var CATEGORY_ALIASES2 = {
9940
9990
  query: "query",
9941
9991
  tx: "tx",
9942
9992
  const: "const",
@@ -9953,8 +10003,8 @@ var CATEGORY_ALIASES = {
9953
10003
  ext: "extensions",
9954
10004
  rpc: "rpc"
9955
10005
  };
9956
- function matchCategory(segment) {
9957
- return CATEGORY_ALIASES[segment.toLowerCase()];
10006
+ function matchCategory2(segment) {
10007
+ return CATEGORY_ALIASES2[segment.toLowerCase()];
9958
10008
  }
9959
10009
  function matchChain(segment, knownChains) {
9960
10010
  return knownChains.some((c) => c.toLowerCase() === segment.toLowerCase());
@@ -9963,35 +10013,35 @@ function parseDotPath(input, knownChains = []) {
9963
10013
  const parts = input.split(".");
9964
10014
  switch (parts.length) {
9965
10015
  case 1: {
9966
- const cat = matchCategory(parts[0]);
10016
+ const cat = matchCategory2(parts[0]);
9967
10017
  if (cat)
9968
10018
  return { category: cat };
9969
10019
  throw new Error(`Unknown command "${parts[0]}". Expected a category (query, tx, const, events, errors, apis, extensions, rpc) or a named command.`);
9970
10020
  }
9971
10021
  case 2: {
9972
- const cat = matchCategory(parts[0]);
10022
+ const cat = matchCategory2(parts[0]);
9973
10023
  if (cat) {
9974
10024
  return { category: cat, pallet: parts[1] };
9975
10025
  }
9976
- const cat2 = matchCategory(parts[1]);
10026
+ const cat2 = matchCategory2(parts[1]);
9977
10027
  if (cat2 && matchChain(parts[0], knownChains)) {
9978
10028
  return { chain: parts[0], category: cat2 };
9979
10029
  }
9980
10030
  throw new Error(`Unknown command "${input}". Expected format: category.Pallet or Chain.category (e.g. query.System or polkadot.query)`);
9981
10031
  }
9982
10032
  case 3: {
9983
- const cat = matchCategory(parts[0]);
10033
+ const cat = matchCategory2(parts[0]);
9984
10034
  if (cat) {
9985
10035
  return { category: cat, pallet: parts[1], item: parts[2] };
9986
10036
  }
9987
- const cat2 = matchCategory(parts[1]);
10037
+ const cat2 = matchCategory2(parts[1]);
9988
10038
  if (cat2 && matchChain(parts[0], knownChains)) {
9989
10039
  return { chain: parts[0], category: cat2, pallet: parts[2] };
9990
10040
  }
9991
10041
  throw new Error(`Unknown command "${input}". Expected format: category.Pallet.Item or Chain.category.Pallet`);
9992
10042
  }
9993
10043
  case 4: {
9994
- const cat = matchCategory(parts[1]);
10044
+ const cat = matchCategory2(parts[1]);
9995
10045
  if (cat && matchChain(parts[0], knownChains)) {
9996
10046
  return { chain: parts[0], category: cat, pallet: parts[2], item: parts[3] };
9997
10047
  }
@@ -10082,6 +10132,9 @@ if (process.argv[2] === "__complete") {
10082
10132
  console.log(" init Initialize a local .polkadot workspace in this directory");
10083
10133
  console.log(" which Show the active config root (workspace, DOT_HOME, or global)");
10084
10134
  console.log();
10135
+ console.log("Plugins:");
10136
+ console.log(' dot <name> \u2026 Runs a "dot-<name>" executable found on PATH (git/cargo-style)');
10137
+ console.log();
10085
10138
  console.log("Global options:");
10086
10139
  console.log(" --chain <name> Target chain (required)");
10087
10140
  console.log(" --rpc <url> Override RPC endpoint");
@@ -10175,7 +10228,14 @@ if (process.argv[2] === "__complete") {
10175
10228
  try {
10176
10229
  parsed = parseDotPath(dotpath, knownChains);
10177
10230
  } catch {
10178
- throw new CliError2(`Unknown command "${dotpath}". Run "dot --help" for available commands.`);
10231
+ if (process.argv[2] === dotpath) {
10232
+ const externalBin = findExternalCommand(dotpath);
10233
+ if (externalBin) {
10234
+ process.exit(runExternalCommand(externalBin, process.argv.slice(3)));
10235
+ }
10236
+ }
10237
+ const pluginHint = isExternalCommandCandidate(dotpath) ? ` No "dot-${dotpath}" plugin found on PATH.` : "";
10238
+ throw new CliError2(`Unknown command "${dotpath}". Run "dot --help" for available commands.${pluginHint}`);
10179
10239
  }
10180
10240
  const isFlatCategory = parsed.category === "rpc" || parsed.category === "extensions";
10181
10241
  if (!parsed.pallet && args.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polkadot-cli",
3
- "version": "1.22.0",
3
+ "version": "1.23.0",
4
4
  "description": "CLI tool for querying Polkadot-ecosystem on-chain state",
5
5
  "type": "module",
6
6
  "bin": {