@okx_ai/okx-trade-cli 1.3.1-beta.4 → 1.3.1-beta.5

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.
package/dist/index.js CHANGED
@@ -876,6 +876,20 @@ import * as fs3 from "fs";
876
876
  import * as path3 from "path";
877
877
  import * as os3 from "os";
878
878
  import { execFileSync } from "child_process";
879
+ import {
880
+ readFileSync as readFileSync7,
881
+ createWriteStream as createWriteStream2,
882
+ mkdirSync as mkdirSync8,
883
+ chmodSync,
884
+ existsSync as existsSync6,
885
+ unlinkSync as unlinkSync3,
886
+ renameSync as renameSync3
887
+ } from "fs";
888
+ import { createHash } from "crypto";
889
+ import { homedir as homedir7, platform, arch } from "os";
890
+ import { join as join9, dirname as dirname6 } from "path";
891
+ import { get as httpsGet } from "https";
892
+ import { get as httpGet } from "http";
879
893
  var EXEC_TIMEOUT_MS = 3e4;
880
894
  var ALLOWED_DOMAIN_RE = /^[\w.-]+\.okx\.com$/;
881
895
  var DOH_BIN_DIR = join(homedir(), ".okx", "bin");
@@ -2116,6 +2130,30 @@ var MODULES = [
2116
2130
  "skills"
2117
2131
  ];
2118
2132
  var DEFAULT_MODULES = ["spot", "swap", "option", "account", ...BOT_DEFAULT_SUB_MODULES, "skills"];
2133
+ var SKILLS_MARKETPLACE_DESC = "OKX Skills Marketplace \u2014 search, install, and manage agent skills";
2134
+ var MODULE_DESCRIPTIONS = {
2135
+ market: "Market data (ticker, orderbook, candles, trades)",
2136
+ spot: "Spot trading (orders, algo orders)",
2137
+ swap: "Perpetual swap trading (orders, algo orders)",
2138
+ futures: "Futures trading (orders, positions, algo orders, leverage)",
2139
+ option: "Options trading (orders, positions, greeks)",
2140
+ account: "Account balance, positions, bills, and configuration",
2141
+ "earn.savings": "Simple Earn \u2014 flexible savings, fixed-term, and lending",
2142
+ "earn.onchain": "On-chain Earn \u2014 staking and DeFi products",
2143
+ "earn.dcd": "DCD (Dual Currency Deposit) \u2014 structured products with fixed yield",
2144
+ "earn.autoearn": "Auto-earn \u2014 automatically lend, stake, or earn on idle assets",
2145
+ "bot.grid": "Grid trading bot \u2014 create, monitor, and stop grid orders",
2146
+ "bot.dca": "DCA (Martingale) bot \u2014 spot or contract recurring buys",
2147
+ skills: SKILLS_MARKETPLACE_DESC,
2148
+ earn: "Earn products \u2014 Simple Earn, On-chain Earn, and DCD (Dual Currency Deposit)",
2149
+ bot: "Trading bot strategies (grid, dca)",
2150
+ config: "Manage CLI configuration profiles",
2151
+ setup: "Set up client integrations (Cursor, Windsurf, Claude, etc.)",
2152
+ doh: "Manage DoH (DNS-over-HTTPS) resolver binary",
2153
+ diagnose: "Run network / MCP server diagnostics",
2154
+ upgrade: "Upgrade okx CLI and MCP server to the latest stable version",
2155
+ skill: SKILLS_MARKETPLACE_DESC
2156
+ };
2119
2157
  function registerAccountTools() {
2120
2158
  return [
2121
2159
  {
@@ -8449,13 +8487,13 @@ function findMsStoreClaudePath() {
8449
8487
  }
8450
8488
  function getConfigPath(client) {
8451
8489
  const home = os3.homedir();
8452
- const platform = process.platform;
8490
+ const platform2 = process.platform;
8453
8491
  switch (client) {
8454
8492
  case "claude-desktop":
8455
- if (platform === "win32") {
8493
+ if (platform2 === "win32") {
8456
8494
  return findMsStoreClaudePath() ?? path3.join(appData(), "Claude", CLAUDE_CONFIG_FILE);
8457
8495
  }
8458
- if (platform === "darwin") {
8496
+ if (platform2 === "darwin") {
8459
8497
  return path3.join(home, "Library", "Application Support", "Claude", CLAUDE_CONFIG_FILE);
8460
8498
  }
8461
8499
  return path3.join(process.env.XDG_CONFIG_HOME ?? path3.join(home, ".config"), "Claude", CLAUDE_CONFIG_FILE);
@@ -8557,6 +8595,269 @@ function runSetup(options) {
8557
8595
  `);
8558
8596
  }
8559
8597
  }
8598
+ var CDN_SOURCES = [
8599
+ { host: "static.jingyunyilian.com", protocol: "https" },
8600
+ { host: "static.okx.com", protocol: "https" },
8601
+ { host: "static.coinall.ltd", protocol: "https" }
8602
+ ];
8603
+ var CDN_PATH_PREFIX = "/upgradeapp/doh";
8604
+ var DOWNLOAD_TIMEOUT_MS = 3e4;
8605
+ function getPlatformDir() {
8606
+ const p = platform();
8607
+ const a = arch();
8608
+ const map = {
8609
+ "darwin-arm64": "darwin-arm64",
8610
+ "darwin-x64": "darwin-x64",
8611
+ "linux-x64": "linux-x64",
8612
+ "win32-x64": "win32-x64"
8613
+ };
8614
+ return map[`${p}-${a}`] ?? null;
8615
+ }
8616
+ function getBinaryName() {
8617
+ return platform() === "win32" ? "okx-doh-resolver.exe" : "okx-doh-resolver";
8618
+ }
8619
+ function hashFile(filePath) {
8620
+ const buf = readFileSync7(filePath);
8621
+ return {
8622
+ size: buf.byteLength,
8623
+ sha256: createHash("sha256").update(buf).digest("hex")
8624
+ };
8625
+ }
8626
+ function getDohStatus(binaryPath, opts) {
8627
+ const resolvedPath = binaryPath ?? getDohBinaryPath();
8628
+ const platformDir = getPlatformDir();
8629
+ if (!existsSync6(resolvedPath)) {
8630
+ return {
8631
+ binaryPath: resolvedPath,
8632
+ exists: false,
8633
+ platform: platformDir
8634
+ };
8635
+ }
8636
+ if (opts?.skipHash) {
8637
+ return {
8638
+ binaryPath: resolvedPath,
8639
+ exists: true,
8640
+ platform: platformDir
8641
+ };
8642
+ }
8643
+ const { size, sha256 } = hashFile(resolvedPath);
8644
+ return {
8645
+ binaryPath: resolvedPath,
8646
+ exists: true,
8647
+ platform: platformDir,
8648
+ fileSize: size,
8649
+ sha256
8650
+ };
8651
+ }
8652
+ async function fetchCdnChecksum(sources = CDN_SOURCES, timeoutMs = DOWNLOAD_TIMEOUT_MS) {
8653
+ const platformDir = getPlatformDir();
8654
+ if (!platformDir) return null;
8655
+ const checksumPath = `${CDN_PATH_PREFIX}/${platformDir}/checksum.json`;
8656
+ for (const { host, protocol } of sources) {
8657
+ try {
8658
+ const url = `${protocol}://${host}${checksumPath}`;
8659
+ const raw = await downloadText(url, timeoutMs);
8660
+ const data = JSON.parse(raw);
8661
+ if (typeof data.sha256 !== "string" || typeof data.size !== "number" || typeof data.target !== "string") {
8662
+ continue;
8663
+ }
8664
+ return {
8665
+ sha256: data.sha256,
8666
+ size: data.size,
8667
+ target: data.target,
8668
+ source: host
8669
+ };
8670
+ } catch {
8671
+ }
8672
+ }
8673
+ return null;
8674
+ }
8675
+ async function fetchAndValidateChecksum(host, protocol, checksumPath, platformDir, timeoutMs, onProgress) {
8676
+ const checksumUrl = `${protocol}://${host}${checksumPath}`;
8677
+ onProgress?.(`Fetching checksum from ${host}...`);
8678
+ const raw = await downloadText(checksumUrl, timeoutMs);
8679
+ const checksum = JSON.parse(raw);
8680
+ if (typeof checksum.sha256 !== "string" || typeof checksum.size !== "number" || typeof checksum.target !== "string") {
8681
+ throw new Error("Invalid checksum.json: missing sha256, size, or target");
8682
+ }
8683
+ if (checksum.target !== platformDir) {
8684
+ throw new Error(
8685
+ `Target mismatch: expected ${platformDir}, got ${checksum.target}`
8686
+ );
8687
+ }
8688
+ return { sha256: checksum.sha256, size: checksum.size, target: checksum.target };
8689
+ }
8690
+ async function downloadAndVerify(host, protocol, binaryPath, tmpPath, checksum, timeoutMs, onProgress) {
8691
+ const binaryUrl = `${protocol}://${host}${binaryPath}`;
8692
+ onProgress?.(`Downloading binary from ${host}...`);
8693
+ await download(binaryUrl, tmpPath, timeoutMs);
8694
+ const actual = hashFile(tmpPath);
8695
+ if (actual.size !== checksum.size) {
8696
+ throw new Error(
8697
+ `Size mismatch: expected ${checksum.size}, got ${actual.size}`
8698
+ );
8699
+ }
8700
+ if (actual.sha256 !== checksum.sha256) {
8701
+ throw new Error(
8702
+ `SHA-256 mismatch: expected ${checksum.sha256}, got ${actual.sha256}`
8703
+ );
8704
+ }
8705
+ }
8706
+ function atomicReplace(tmpPath, resolvedDest) {
8707
+ if (platform() === "win32") {
8708
+ try {
8709
+ unlinkSync3(resolvedDest);
8710
+ } catch {
8711
+ }
8712
+ }
8713
+ renameSync3(tmpPath, resolvedDest);
8714
+ if (platform() !== "win32") {
8715
+ chmodSync(resolvedDest, 493);
8716
+ }
8717
+ }
8718
+ function installPreChecks(destPath, sources) {
8719
+ if (!destPath && process.env.OKX_DOH_BINARY_PATH) {
8720
+ return { status: "up-to-date", source: "(env override)" };
8721
+ }
8722
+ if (!getPlatformDir()) {
8723
+ return { status: "failed", error: "Unsupported platform" };
8724
+ }
8725
+ if (sources.length === 0) {
8726
+ return { status: "failed", error: "No CDN sources available" };
8727
+ }
8728
+ return null;
8729
+ }
8730
+ function isLocalUpToDate(localHash, checksum) {
8731
+ return localHash !== null && localHash.size === checksum.size && localHash.sha256 === checksum.sha256;
8732
+ }
8733
+ async function installDohBinary(destPath, sources = CDN_SOURCES, onProgress) {
8734
+ const earlyResult = installPreChecks(destPath, sources);
8735
+ if (earlyResult) return earlyResult;
8736
+ const platformDir = getPlatformDir();
8737
+ const binaryName = getBinaryName();
8738
+ const resolvedDest = destPath ?? join9(homedir7(), ".okx", "bin", binaryName);
8739
+ const tmpPath = resolvedDest + ".tmp";
8740
+ mkdirSync8(dirname6(resolvedDest), { recursive: true });
8741
+ const localHash = existsSync6(resolvedDest) ? hashFile(resolvedDest) : null;
8742
+ const checksumPath = `${CDN_PATH_PREFIX}/${platformDir}/checksum.json`;
8743
+ const binaryPath = `${CDN_PATH_PREFIX}/${platformDir}/${binaryName}`;
8744
+ const errors = [];
8745
+ for (const { host, protocol } of sources) {
8746
+ try {
8747
+ const checksum = await fetchAndValidateChecksum(
8748
+ host,
8749
+ protocol,
8750
+ checksumPath,
8751
+ platformDir,
8752
+ DOWNLOAD_TIMEOUT_MS,
8753
+ onProgress
8754
+ );
8755
+ if (isLocalUpToDate(localHash, checksum)) {
8756
+ onProgress?.("Already up to date (checksum match)");
8757
+ return { status: "up-to-date", source: host };
8758
+ }
8759
+ await downloadAndVerify(host, protocol, binaryPath, tmpPath, checksum, DOWNLOAD_TIMEOUT_MS, onProgress);
8760
+ atomicReplace(tmpPath, resolvedDest);
8761
+ onProgress?.(`Downloaded and verified from ${host}`);
8762
+ return { status: "installed", source: host };
8763
+ } catch (err) {
8764
+ try {
8765
+ unlinkSync3(tmpPath);
8766
+ } catch {
8767
+ }
8768
+ const msg = err instanceof Error ? err.message : String(err);
8769
+ errors.push(`${host}: ${msg}`);
8770
+ onProgress?.(`${host} failed: ${msg}`);
8771
+ }
8772
+ }
8773
+ return { status: "failed", error: `All CDN sources failed:
8774
+ ${errors.join("\n")}` };
8775
+ }
8776
+ function removeDohBinary(binaryPath) {
8777
+ const resolvedPath = binaryPath ?? getDohBinaryPath();
8778
+ try {
8779
+ unlinkSync3(resolvedPath);
8780
+ return { status: "removed" };
8781
+ } catch (err) {
8782
+ if (err.code === "ENOENT") {
8783
+ return { status: "not-found" };
8784
+ }
8785
+ const msg = err instanceof Error ? err.message : String(err);
8786
+ throw new Error(`Failed to remove ${resolvedPath}: ${msg}`);
8787
+ }
8788
+ }
8789
+ function isRedirect(statusCode) {
8790
+ return statusCode !== void 0 && statusCode >= 300 && statusCode < 400;
8791
+ }
8792
+ function validateRedirect(res, requestUrl, redirectCount, maxRedirects) {
8793
+ if (redirectCount > maxRedirects) {
8794
+ throw new Error(`Too many redirects (${maxRedirects})`);
8795
+ }
8796
+ const location = res.headers.location;
8797
+ if (requestUrl.startsWith("https") && !location.startsWith("https")) {
8798
+ throw new Error("Refused HTTPS \u2192 HTTP redirect downgrade");
8799
+ }
8800
+ return location;
8801
+ }
8802
+ function fetchResponse(url, timeoutMs) {
8803
+ return new Promise((resolve3, reject) => {
8804
+ let redirects = 0;
8805
+ const maxRedirects = 5;
8806
+ function doRequest(requestUrl) {
8807
+ const reqFn = requestUrl.startsWith("https") ? httpsGet : httpGet;
8808
+ const req = reqFn(requestUrl, { timeout: timeoutMs }, (res) => {
8809
+ if (isRedirect(res.statusCode) && res.headers.location) {
8810
+ redirects++;
8811
+ try {
8812
+ const location = validateRedirect(res, requestUrl, redirects, maxRedirects);
8813
+ res.resume();
8814
+ doRequest(location);
8815
+ } catch (err) {
8816
+ reject(err);
8817
+ }
8818
+ return;
8819
+ }
8820
+ if (res.statusCode !== 200) {
8821
+ reject(new Error(`HTTP ${res.statusCode ?? "unknown"}`));
8822
+ return;
8823
+ }
8824
+ resolve3(res);
8825
+ });
8826
+ req.on("error", reject);
8827
+ req.on("timeout", () => {
8828
+ req.destroy();
8829
+ reject(new Error("Download timed out"));
8830
+ });
8831
+ }
8832
+ doRequest(url);
8833
+ });
8834
+ }
8835
+ function download(url, destPath, timeoutMs) {
8836
+ return fetchResponse(url, timeoutMs).then(
8837
+ (res) => new Promise((resolve3, reject) => {
8838
+ const file = createWriteStream2(destPath);
8839
+ res.pipe(file);
8840
+ file.on("finish", () => file.close(() => resolve3()));
8841
+ file.on("error", (err) => {
8842
+ try {
8843
+ unlinkSync3(destPath);
8844
+ } catch {
8845
+ }
8846
+ reject(err);
8847
+ });
8848
+ })
8849
+ );
8850
+ }
8851
+ function downloadText(url, timeoutMs) {
8852
+ return fetchResponse(url, timeoutMs).then(
8853
+ (res) => new Promise((resolve3, reject) => {
8854
+ const chunks = [];
8855
+ res.on("data", (chunk) => chunks.push(chunk));
8856
+ res.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
8857
+ res.on("error", reject);
8858
+ })
8859
+ );
8860
+ }
8560
8861
 
8561
8862
  // src/commands/diagnose.ts
8562
8863
  import dns from "dns/promises";
@@ -9189,7 +9490,7 @@ async function cmdDiagnoseMcp(options = {}) {
9189
9490
 
9190
9491
  // src/commands/diagnose.ts
9191
9492
  var CLI_VERSION = readCliVersion();
9192
- var GIT_HASH = true ? "980de10" : "dev";
9493
+ var GIT_HASH = true ? "63a5613" : "dev";
9193
9494
  function maskKey2(key) {
9194
9495
  if (!key) return "(not set)";
9195
9496
  if (key.length <= 8) return "****";
@@ -9431,6 +9732,44 @@ async function cmdDiagnose(config, profile, options = {}) {
9431
9732
  }
9432
9733
  return runCliChecks(config, profile, options.output);
9433
9734
  }
9735
+ async function checkDoh(report) {
9736
+ section("DoH Resolver");
9737
+ const local = getDohStatus();
9738
+ if (!local.exists) {
9739
+ fail("DoH binary", "not installed", [
9740
+ "Run: okx doh install",
9741
+ "Or wait for the next npm install to auto-download"
9742
+ ]);
9743
+ report.add("doh_binary", "not installed");
9744
+ return;
9745
+ }
9746
+ ok("DoH binary", local.binaryPath);
9747
+ report.add("doh_binary", `installed (${local.platform ?? "unknown"})`);
9748
+ const cdnChecksum = await fetchCdnChecksum(void 0, 5e3);
9749
+ if (!cdnChecksum) {
9750
+ warn("DoH checksum", "CDN unreachable \u2014 cannot verify");
9751
+ report.add("doh_checksum", "CDN unreachable");
9752
+ } else if (cdnChecksum.sha256 === local.sha256) {
9753
+ ok("DoH checksum", `match (${cdnChecksum.source})`);
9754
+ report.add("doh_checksum", `match (${cdnChecksum.source})`);
9755
+ } else {
9756
+ warn("DoH checksum", "mismatch \u2014 update available", ["Run: okx doh install"]);
9757
+ report.add("doh_checksum", "mismatch");
9758
+ }
9759
+ try {
9760
+ const cacheEntry = readCache("www.okx.com");
9761
+ if (cacheEntry) {
9762
+ ok("DoH mode", cacheEntry.mode);
9763
+ report.add("doh_mode", cacheEntry.mode);
9764
+ } else {
9765
+ ok("DoH mode", "no cache (will auto-detect on next request)");
9766
+ report.add("doh_mode", "no cache");
9767
+ }
9768
+ } catch {
9769
+ ok("DoH mode", "no cache");
9770
+ report.add("doh_mode", "no cache");
9771
+ }
9772
+ }
9434
9773
  function checkConfigFile(report) {
9435
9774
  section("Config File");
9436
9775
  const path6 = configFilePath();
@@ -9459,6 +9798,7 @@ async function runCliChecks(config, profile, outputPath) {
9459
9798
  report.add("ts", (/* @__PURE__ */ new Date()).toISOString());
9460
9799
  const configFilePassed = checkConfigFile(report);
9461
9800
  const envPassed = checkEnvironment(report);
9801
+ await checkDoh(report);
9462
9802
  if (!config) {
9463
9803
  fail("Config", "Could not load config (see Config File check above)", []);
9464
9804
  report.add("result", "FAIL");
@@ -9486,23 +9826,23 @@ async function runCliChecks(config, profile, outputPath) {
9486
9826
 
9487
9827
  // src/commands/upgrade.ts
9488
9828
  import { spawnSync as spawnSync2 } from "child_process";
9489
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync7, mkdirSync as mkdirSync8 } from "fs";
9490
- import { dirname as dirname6, join as join9 } from "path";
9491
- import { homedir as homedir7 } from "os";
9829
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync9 } from "fs";
9830
+ import { dirname as dirname7, join as join10 } from "path";
9831
+ import { homedir as homedir8 } from "os";
9492
9832
  var PACKAGES = ["@okx_ai/okx-trade-mcp", "@okx_ai/okx-trade-cli"];
9493
- var CACHE_FILE2 = join9(homedir7(), ".okx", "last_check");
9833
+ var CACHE_FILE2 = join10(homedir8(), ".okx", "last_check");
9494
9834
  var THROTTLE_MS = 12 * 60 * 60 * 1e3;
9495
- var NPM_BIN = join9(dirname6(process.execPath), process.platform === "win32" ? "npm.cmd" : "npm");
9835
+ var NPM_BIN = join10(dirname7(process.execPath), process.platform === "win32" ? "npm.cmd" : "npm");
9496
9836
  function readLastCheck() {
9497
9837
  try {
9498
- return parseInt(readFileSync7(CACHE_FILE2, "utf-8").trim(), 10) || 0;
9838
+ return parseInt(readFileSync8(CACHE_FILE2, "utf-8").trim(), 10) || 0;
9499
9839
  } catch {
9500
9840
  return 0;
9501
9841
  }
9502
9842
  }
9503
9843
  function writeLastCheck() {
9504
9844
  try {
9505
- mkdirSync8(join9(homedir7(), ".okx"), { recursive: true });
9845
+ mkdirSync9(join10(homedir8(), ".okx"), { recursive: true });
9506
9846
  writeFileSync7(CACHE_FILE2, String(Math.floor(Date.now() / 1e3)), "utf-8");
9507
9847
  } catch {
9508
9848
  }
@@ -9587,24 +9927,6 @@ async function cmdUpgrade(currentVersion, options, json) {
9587
9927
  }
9588
9928
  }
9589
9929
 
9590
- // src/config/loader.ts
9591
- function loadProfileConfig(opts) {
9592
- return loadConfig({
9593
- profile: opts.profile,
9594
- modules: opts.modules,
9595
- readOnly: opts.readOnly ?? false,
9596
- demo: opts.demo,
9597
- live: opts.live,
9598
- site: opts.site,
9599
- userAgent: opts.userAgent,
9600
- sourceTag: opts.sourceTag,
9601
- verbose: opts.verbose
9602
- });
9603
- }
9604
-
9605
- // src/help.ts
9606
- import { EOL as EOL2 } from "os";
9607
-
9608
9930
  // src/commands/client-setup.ts
9609
9931
  import * as fs6 from "fs";
9610
9932
  var DETECTABLE_CLIENTS = ["claude-desktop", "cursor", "windsurf"];
@@ -9629,154 +9951,213 @@ function cmdSetupClients() {
9629
9951
  printSetupUsage();
9630
9952
  }
9631
9953
 
9632
- // src/help.ts
9633
- var HELP_TREE = {
9954
+ // src/cli-registry.ts
9955
+ var CLI_REGISTRY = {
9956
+ // ── market ─────────────────────────────────────────────────────────────────
9634
9957
  market: {
9635
9958
  description: "Market data (ticker, orderbook, candles, trades)",
9636
9959
  commands: {
9637
9960
  ticker: {
9961
+ toolName: "market_get_ticker",
9638
9962
  usage: "okx market ticker <instId>",
9639
9963
  description: "Get latest ticker data for an instrument"
9640
9964
  },
9641
9965
  tickers: {
9966
+ toolName: "market_get_tickers",
9642
9967
  usage: "okx market tickers <instType>",
9643
9968
  description: "Get all tickers for an instrument type (SPOT|SWAP|FUTURES|OPTION)"
9644
9969
  },
9645
9970
  orderbook: {
9971
+ toolName: "market_get_orderbook",
9646
9972
  usage: "okx market orderbook <instId> [--sz <n>]",
9647
9973
  description: "Get order book depth for an instrument"
9648
9974
  },
9649
9975
  candles: {
9976
+ toolName: "market_get_candles",
9650
9977
  usage: "okx market candles <instId> [--bar <bar>] [--limit <n>]",
9651
9978
  description: "Get candlestick (OHLCV) data"
9652
9979
  },
9653
9980
  instruments: {
9981
+ toolName: "market_get_instruments",
9654
9982
  usage: "okx market instruments --instType <type> [--instId <id>]",
9655
9983
  description: "List tradable instruments of a given type"
9656
9984
  },
9657
9985
  "funding-rate": {
9986
+ toolName: "market_get_funding_rate",
9658
9987
  usage: "okx market funding-rate <instId> [--history] [--limit <n>]",
9659
9988
  description: "Get current or historical funding rate for perpetual swaps"
9660
9989
  },
9661
9990
  "mark-price": {
9991
+ toolName: "market_get_mark_price",
9662
9992
  usage: "okx market mark-price --instType <MARGIN|SWAP|FUTURES|OPTION> [--instId <id>]",
9663
9993
  description: "Get mark price for instruments"
9664
9994
  },
9665
9995
  trades: {
9996
+ toolName: "market_get_trades",
9666
9997
  usage: "okx market trades <instId> [--limit <n>]",
9667
9998
  description: "Get recent trades for an instrument"
9668
9999
  },
9669
10000
  "index-ticker": {
10001
+ toolName: "market_get_index_ticker",
9670
10002
  usage: "okx market index-ticker [--instId <id>] [--quoteCcy <ccy>]",
9671
10003
  description: "Get index ticker data"
9672
10004
  },
9673
10005
  "index-candles": {
10006
+ toolName: "market_get_index_candles",
9674
10007
  usage: "okx market index-candles <instId> [--bar <bar>] [--limit <n>] [--history]",
9675
10008
  description: "Get index candlestick data"
9676
10009
  },
9677
10010
  "price-limit": {
10011
+ toolName: "market_get_price_limit",
9678
10012
  usage: "okx market price-limit <instId>",
9679
10013
  description: "Get price limit for an instrument"
9680
10014
  },
9681
10015
  "open-interest": {
10016
+ toolName: "market_get_open_interest",
9682
10017
  usage: "okx market open-interest --instType <SWAP|FUTURES|OPTION> [--instId <id>]",
9683
10018
  description: "Get open interest for instruments"
9684
10019
  },
9685
10020
  "stock-tokens": {
10021
+ toolName: "market_get_stock_tokens",
9686
10022
  usage: "okx market stock-tokens [--instType <SPOT|SWAP>] [--instId <id>]",
9687
10023
  description: "[Deprecated: use instruments-by-category --instCategory 3] List all stock token instruments (instCategory=3, e.g. AAPL-USDT-SWAP)"
9688
10024
  },
9689
10025
  "instruments-by-category": {
10026
+ toolName: "market_get_instruments_by_category",
9690
10027
  usage: "okx market instruments-by-category --instCategory <4|5|6|7> [--instType <SPOT|SWAP>] [--instId <id>]",
9691
10028
  description: "List instruments by asset category: 4=Metals (gold/silver), 5=Commodities (oil/gas), 6=Forex (EUR/USD), 7=Bonds"
9692
10029
  }
10030
+ },
10031
+ subgroups: {
10032
+ indicator: {
10033
+ description: "Technical indicators and chart patterns",
10034
+ commands: {
10035
+ list: {
10036
+ toolName: "market_list_indicators",
10037
+ usage: "okx market indicator list",
10038
+ description: "List all supported technical indicators"
10039
+ },
10040
+ "<instId> <indicator>": {
10041
+ toolName: "market_get_indicator",
10042
+ usage: "okx market indicator <instId> <indicator> [--bar <bar>] [--limit <n>] [--backtest-time <ts>] [--params <json>]",
10043
+ description: "Get indicator values for an instrument (e.g. okx market indicator BTC-USDT-SWAP rsi)"
10044
+ }
10045
+ }
10046
+ }
9693
10047
  }
9694
10048
  },
10049
+ // ── account ────────────────────────────────────────────────────────────────
9695
10050
  account: {
9696
10051
  description: "Account balance, positions, bills, and configuration",
9697
10052
  commands: {
9698
10053
  balance: {
10054
+ toolName: "account_get_balance",
9699
10055
  usage: "okx account balance [<ccy>]",
9700
10056
  description: "Get trading account balance"
9701
10057
  },
9702
10058
  "asset-balance": {
10059
+ toolName: "account_get_asset_balance",
9703
10060
  usage: "okx account asset-balance [--ccy <ccy>]",
9704
10061
  description: "Get funding account asset balance"
9705
10062
  },
9706
10063
  positions: {
10064
+ toolName: "account_get_positions",
9707
10065
  usage: "okx account positions [--instType <type>] [--instId <id>]",
9708
10066
  description: "Get current open positions"
9709
10067
  },
9710
10068
  "positions-history": {
10069
+ toolName: "account_get_positions_history",
9711
10070
  usage: "okx account positions-history [--instType <type>] [--instId <id>] [--limit <n>]",
9712
10071
  description: "Get historical positions"
9713
10072
  },
9714
10073
  bills: {
10074
+ toolName: "account_get_bills",
10075
+ alternateTools: ["account_get_bills_archive"],
9715
10076
  usage: "okx account bills [--instType <type>] [--ccy <ccy>] [--limit <n>] [--archive]",
9716
10077
  description: "Get account bill history"
9717
10078
  },
9718
10079
  fees: {
10080
+ toolName: "account_get_trade_fee",
9719
10081
  usage: "okx account fees --instType <type> [--instId <id>]",
9720
10082
  description: "Get trading fee rates"
9721
10083
  },
9722
10084
  config: {
10085
+ toolName: "account_get_config",
9723
10086
  usage: "okx account config",
9724
10087
  description: "Get account configuration"
9725
10088
  },
9726
10089
  "set-position-mode": {
10090
+ toolName: "account_set_position_mode",
9727
10091
  usage: "okx account set-position-mode --posMode <long_short_mode|net_mode>",
9728
10092
  description: "Set position mode (long/short or net)"
9729
10093
  },
9730
10094
  "max-size": {
10095
+ toolName: "account_get_max_size",
9731
10096
  usage: "okx account max-size --instId <id> --tdMode <cross|isolated> [--px <price>]",
9732
10097
  description: "Get maximum order size for an instrument"
9733
10098
  },
9734
10099
  "max-avail-size": {
10100
+ toolName: "account_get_max_avail_size",
9735
10101
  usage: "okx account max-avail-size --instId <id> --tdMode <cross|isolated|cash>",
9736
10102
  description: "Get maximum available tradable amount"
9737
10103
  },
9738
10104
  "max-withdrawal": {
10105
+ toolName: "account_get_max_withdrawal",
9739
10106
  usage: "okx account max-withdrawal [--ccy <ccy>]",
9740
10107
  description: "Get maximum withdrawable amount"
9741
10108
  },
9742
10109
  transfer: {
10110
+ toolName: "account_transfer",
9743
10111
  usage: "okx account transfer --ccy <ccy> --amt <n> --from <acct> --to <acct> [--transferType <0|1|2|3>]",
9744
10112
  description: "Transfer funds between accounts"
9745
10113
  },
9746
10114
  audit: {
10115
+ // trade_get_history ToolSpec reads the same local log files as cmdAccountAudit.
10116
+ // CLI reads files directly without routing through ToolRunner for performance,
10117
+ // but conceptually this command is the CLI representation of the ToolSpec.
10118
+ toolName: "trade_get_history",
9747
10119
  usage: "okx account audit [--tool <name>] [--since <ISO-date>] [--limit <n>]",
9748
10120
  description: "Audit account activity and tool call history"
9749
10121
  }
9750
10122
  }
9751
10123
  },
10124
+ // ── spot ───────────────────────────────────────────────────────────────────
9752
10125
  spot: {
9753
10126
  description: "Spot trading (orders, algo orders)",
9754
10127
  commands: {
9755
10128
  orders: {
10129
+ toolName: "spot_get_orders",
9756
10130
  usage: "okx spot orders [--instId <id>] [--history]",
9757
10131
  description: "List open or historical spot orders"
9758
10132
  },
9759
10133
  get: {
10134
+ toolName: "spot_get_order",
9760
10135
  usage: "okx spot get --instId <id> --ordId <id>",
9761
10136
  description: "Get details of a specific spot order"
9762
10137
  },
9763
10138
  fills: {
10139
+ toolName: "spot_get_fills",
9764
10140
  usage: "okx spot fills [--instId <id>] [--ordId <id>]",
9765
10141
  description: "Get trade fill history for spot orders"
9766
10142
  },
9767
10143
  place: {
10144
+ toolName: "spot_place_order",
9768
10145
  usage: "okx spot place --instId <id> --side <buy|sell> --ordType <type> --sz <n> [--px <price>] [--tdMode <cash|cross|isolated>] [--tpTriggerPx <price>] [--tpOrdPx <price|-1>] [--slTriggerPx <price>] [--slOrdPx <price|-1>]",
9769
10146
  description: "Place a new spot order (supports attached TP/SL)"
9770
10147
  },
9771
10148
  amend: {
10149
+ toolName: "spot_amend_order",
9772
10150
  usage: "okx spot amend --instId <id> --ordId <id> [--newSz <n>] [--newPx <price>]",
9773
10151
  description: "Amend a pending spot order"
9774
10152
  },
9775
10153
  cancel: {
10154
+ toolName: "spot_cancel_order",
9776
10155
  usage: "okx spot cancel <instId> --ordId <id>",
9777
10156
  description: "Cancel a pending spot order"
9778
10157
  },
9779
10158
  batch: {
10159
+ toolName: "spot_batch_orders",
10160
+ alternateTools: ["spot_batch_amend", "spot_batch_cancel"],
9780
10161
  usage: "okx spot batch --action <place|amend|cancel> --orders '<json>'",
9781
10162
  description: "Batch place, amend, or cancel spot orders"
9782
10163
  }
@@ -9786,18 +10167,27 @@ var HELP_TREE = {
9786
10167
  description: "Spot algo orders (conditional, OCO, take-profit/stop-loss)",
9787
10168
  commands: {
9788
10169
  orders: {
10170
+ toolName: "spot_get_algo_orders",
9789
10171
  usage: "okx spot algo orders [--instId <id>] [--history] [--ordType <conditional|oco>]",
9790
10172
  description: "List spot algo orders"
9791
10173
  },
9792
10174
  place: {
10175
+ toolName: "spot_place_algo_order",
9793
10176
  usage: "okx spot algo place --instId <id> --side <buy|sell> --sz <n> [--ordType <conditional|oco>]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>] [--tdMode <cash|cross|isolated>]",
9794
10177
  description: "Place a spot algo order (take-profit/stop-loss)"
9795
10178
  },
10179
+ trail: {
10180
+ toolName: "spot_place_algo_order",
10181
+ usage: "okx spot algo trail --instId <id> --side <buy|sell> --sz <n> --callbackRatio <ratio>\n [--activePx <price>] [--tdMode <cash|cross|isolated>]",
10182
+ description: "Place a trailing stop algo order for spot"
10183
+ },
9796
10184
  amend: {
10185
+ toolName: "spot_amend_algo_order",
9797
10186
  usage: "okx spot algo amend --instId <id> --algoId <id> [--newSz <n>]\n [--newTpTriggerPx <price>] [--newTpOrdPx <price|-1>]\n [--newSlTriggerPx <price>] [--newSlOrdPx <price|-1>]",
9798
10187
  description: "Amend a pending spot algo order"
9799
10188
  },
9800
10189
  cancel: {
10190
+ toolName: "spot_cancel_algo_order",
9801
10191
  usage: "okx spot algo cancel --instId <id> --algoId <id>",
9802
10192
  description: "Cancel a pending spot algo order"
9803
10193
  }
@@ -9805,50 +10195,64 @@ var HELP_TREE = {
9805
10195
  }
9806
10196
  }
9807
10197
  },
10198
+ // ── swap ───────────────────────────────────────────────────────────────────
9808
10199
  swap: {
9809
10200
  description: "Perpetual swap trading (orders, algo orders)",
9810
10201
  commands: {
9811
10202
  positions: {
10203
+ toolName: "swap_get_positions",
9812
10204
  usage: "okx swap positions [<instId>]",
9813
10205
  description: "Get current perpetual swap positions"
9814
10206
  },
9815
10207
  orders: {
10208
+ toolName: "swap_get_orders",
9816
10209
  usage: "okx swap orders [--instId <id>] [--history] [--archive]",
9817
10210
  description: "List open or historical swap orders"
9818
10211
  },
9819
10212
  get: {
10213
+ toolName: "swap_get_order",
9820
10214
  usage: "okx swap get --instId <id> --ordId <id>",
9821
10215
  description: "Get details of a specific swap order"
9822
10216
  },
9823
10217
  fills: {
10218
+ toolName: "swap_get_fills",
9824
10219
  usage: "okx swap fills [--instId <id>] [--ordId <id>] [--archive]",
9825
10220
  description: "Get trade fill history for swap orders"
9826
10221
  },
9827
10222
  place: {
10223
+ toolName: "swap_place_order",
9828
10224
  usage: "okx swap place --instId <id> --side <buy|sell> --ordType <type> --sz <n> [--posSide <side>] [--px <price>] [--tdMode <cross|isolated>] [--tpTriggerPx <price>] [--tpOrdPx <price|-1>] [--slTriggerPx <price>] [--slOrdPx <price|-1>]",
9829
10225
  description: "Place a new perpetual swap order (supports attached TP/SL)"
9830
10226
  },
9831
10227
  cancel: {
10228
+ toolName: "swap_cancel_order",
9832
10229
  usage: "okx swap cancel <instId> --ordId <id>",
9833
10230
  description: "Cancel a pending swap order"
9834
10231
  },
9835
10232
  amend: {
10233
+ // swap amend uses spot_amend_order (same OKX /trade/amend-order endpoint works for all types)
10234
+ toolName: "spot_amend_order",
9836
10235
  usage: "okx swap amend --instId <id> --ordId <id> [--newSz <n>] [--newPx <price>]",
9837
10236
  description: "Amend a pending swap order"
9838
10237
  },
9839
10238
  close: {
10239
+ toolName: "swap_close_position",
9840
10240
  usage: "okx swap close --instId <id> --mgnMode <cross|isolated> [--posSide <net|long|short>] [--autoCxl]",
9841
10241
  description: "Close a swap position"
9842
10242
  },
9843
10243
  leverage: {
10244
+ toolName: "swap_set_leverage",
9844
10245
  usage: "okx swap leverage --instId <id> --lever <n> --mgnMode <cross|isolated> [--posSide <side>]",
9845
10246
  description: "Set leverage for a swap instrument"
9846
10247
  },
9847
10248
  "get-leverage": {
10249
+ toolName: "swap_get_leverage",
9848
10250
  usage: "okx swap get-leverage --instId <id> --mgnMode <cross|isolated>",
9849
10251
  description: "Get current leverage setting for a swap instrument"
9850
10252
  },
9851
10253
  batch: {
10254
+ toolName: "swap_batch_orders",
10255
+ alternateTools: ["swap_batch_amend", "swap_batch_cancel"],
9852
10256
  usage: "okx swap batch --action <place|amend|cancel> --orders '<json>'",
9853
10257
  description: "Batch place, amend, or cancel swap orders"
9854
10258
  }
@@ -9858,22 +10262,27 @@ var HELP_TREE = {
9858
10262
  description: "Perpetual swap algo orders (trailing stop, conditional, OCO)",
9859
10263
  commands: {
9860
10264
  orders: {
10265
+ toolName: "swap_get_algo_orders",
9861
10266
  usage: "okx swap algo orders [--instId <id>] [--history] [--ordType <conditional|oco>]",
9862
10267
  description: "List swap algo orders"
9863
10268
  },
9864
10269
  trail: {
10270
+ toolName: "swap_place_move_stop_order",
9865
10271
  usage: "okx swap algo trail --instId <id> --side <buy|sell> --sz <n> --callbackRatio <ratio>\n [--activePx <price>] [--posSide <net|long|short>] [--tdMode <cross|isolated>] [--reduceOnly]",
9866
10272
  description: "Place a trailing stop algo order for perpetual swap"
9867
10273
  },
9868
10274
  place: {
10275
+ toolName: "swap_place_algo_order",
9869
10276
  usage: "okx swap algo place --instId <id> --side <buy|sell> --sz <n> [--ordType <conditional|oco>]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>]\n [--posSide <net|long|short>] [--tdMode <cross|isolated>] [--reduceOnly]",
9870
10277
  description: "Place a swap algo order (take-profit/stop-loss)"
9871
10278
  },
9872
10279
  amend: {
10280
+ toolName: "swap_amend_algo_order",
9873
10281
  usage: "okx swap algo amend --instId <id> --algoId <id> [--newSz <n>]\n [--newTpTriggerPx <price>] [--newTpOrdPx <price|-1>]\n [--newSlTriggerPx <price>] [--newSlOrdPx <price|-1>]",
9874
10282
  description: "Amend a pending swap algo order"
9875
10283
  },
9876
10284
  cancel: {
10285
+ toolName: "swap_cancel_algo_orders",
9877
10286
  usage: "okx swap algo cancel --instId <id> --algoId <id>",
9878
10287
  description: "Cancel a pending swap algo order"
9879
10288
  }
@@ -9881,50 +10290,63 @@ var HELP_TREE = {
9881
10290
  }
9882
10291
  }
9883
10292
  },
10293
+ // ── futures ────────────────────────────────────────────────────────────────
9884
10294
  futures: {
9885
10295
  description: "Futures trading (orders, positions, algo orders, leverage)",
9886
10296
  commands: {
9887
10297
  orders: {
10298
+ toolName: "futures_get_orders",
9888
10299
  usage: "okx futures orders [--instId <id>] [--history] [--archive]",
9889
10300
  description: "List open or historical futures orders"
9890
10301
  },
9891
10302
  positions: {
10303
+ toolName: "futures_get_positions",
9892
10304
  usage: "okx futures positions [--instId <id>]",
9893
10305
  description: "Get current futures positions"
9894
10306
  },
9895
10307
  fills: {
10308
+ toolName: "futures_get_fills",
9896
10309
  usage: "okx futures fills [--instId <id>] [--ordId <id>] [--archive]",
9897
10310
  description: "Get trade fill history for futures orders"
9898
10311
  },
9899
10312
  place: {
10313
+ toolName: "futures_place_order",
9900
10314
  usage: "okx futures place --instId <id> --side <buy|sell> --ordType <type> --sz <n>\n [--tdMode <cross|isolated>] [--posSide <net|long|short>] [--px <price>] [--reduceOnly]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>] [--slTriggerPx <price>] [--slOrdPx <price|-1>]",
9901
10315
  description: "Place a new futures order (supports attached TP/SL)"
9902
10316
  },
9903
10317
  cancel: {
10318
+ toolName: "futures_cancel_order",
9904
10319
  usage: "okx futures cancel <instId> --ordId <id>",
9905
10320
  description: "Cancel a pending futures order"
9906
10321
  },
9907
10322
  amend: {
10323
+ toolName: "futures_amend_order",
9908
10324
  usage: "okx futures amend --instId <id> [--ordId <id>] [--clOrdId <id>] [--newSz <n>] [--newPx <price>]",
9909
10325
  description: "Amend a pending futures order"
9910
10326
  },
9911
10327
  get: {
10328
+ toolName: "futures_get_order",
9912
10329
  usage: "okx futures get --instId <id> --ordId <id>",
9913
10330
  description: "Get details of a specific futures order"
9914
10331
  },
9915
10332
  close: {
10333
+ toolName: "futures_close_position",
9916
10334
  usage: "okx futures close --instId <id> --mgnMode <cross|isolated> [--posSide <net|long|short>] [--autoCxl]",
9917
10335
  description: "Close a futures position"
9918
10336
  },
9919
10337
  "get-leverage": {
10338
+ toolName: "futures_get_leverage",
9920
10339
  usage: "okx futures get-leverage --instId <id> --mgnMode <cross|isolated>",
9921
10340
  description: "Get current leverage for a futures instrument"
9922
10341
  },
9923
10342
  leverage: {
10343
+ toolName: "futures_set_leverage",
9924
10344
  usage: "okx futures leverage --instId <id> --lever <n> --mgnMode <cross|isolated> [--posSide <net|long|short>]",
9925
10345
  description: "Set leverage for a futures instrument"
9926
10346
  },
9927
10347
  batch: {
10348
+ toolName: "futures_batch_orders",
10349
+ alternateTools: ["futures_batch_amend", "futures_batch_cancel"],
9928
10350
  usage: "okx futures batch --action <place|amend|cancel> --orders '<json>'",
9929
10351
  description: "Batch place, amend, or cancel futures orders"
9930
10352
  }
@@ -9934,22 +10356,27 @@ var HELP_TREE = {
9934
10356
  description: "Futures algo orders (trailing stop, conditional, OCO)",
9935
10357
  commands: {
9936
10358
  orders: {
10359
+ toolName: "futures_get_algo_orders",
9937
10360
  usage: "okx futures algo orders [--instId <id>] [--history] [--ordType <conditional|oco>]",
9938
10361
  description: "List futures algo orders"
9939
10362
  },
9940
10363
  trail: {
10364
+ toolName: "futures_place_move_stop_order",
9941
10365
  usage: "okx futures algo trail --instId <id> --side <buy|sell> --sz <n> --callbackRatio <ratio>\n [--activePx <price>] [--posSide <net|long|short>] [--tdMode <cross|isolated>] [--reduceOnly]",
9942
10366
  description: "Place a trailing stop algo order for futures"
9943
10367
  },
9944
10368
  place: {
10369
+ toolName: "futures_place_algo_order",
9945
10370
  usage: "okx futures algo place --instId <id> --side <buy|sell> --sz <n> [--ordType <conditional|oco>]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>]\n [--posSide <net|long|short>] [--tdMode <cross|isolated>] [--reduceOnly]",
9946
10371
  description: "Place a futures algo order (take-profit/stop-loss)"
9947
10372
  },
9948
10373
  amend: {
10374
+ toolName: "futures_amend_algo_order",
9949
10375
  usage: "okx futures algo amend --instId <id> --algoId <id> [--newSz <n>]\n [--newTpTriggerPx <price>] [--newTpOrdPx <price|-1>]\n [--newSlTriggerPx <price>] [--newSlOrdPx <price|-1>]",
9950
10376
  description: "Amend a pending futures algo order"
9951
10377
  },
9952
10378
  cancel: {
10379
+ toolName: "futures_cancel_algo_orders",
9953
10380
  usage: "okx futures algo cancel --instId <id> --algoId <id>",
9954
10381
  description: "Cancel a pending futures algo order"
9955
10382
  }
@@ -9957,51 +10384,90 @@ var HELP_TREE = {
9957
10384
  }
9958
10385
  }
9959
10386
  },
10387
+ // ── option ─────────────────────────────────────────────────────────────────
9960
10388
  option: {
9961
10389
  description: "Options trading (orders, positions, greeks)",
9962
10390
  commands: {
9963
10391
  orders: {
10392
+ toolName: "option_get_orders",
9964
10393
  usage: "okx option orders [--instId <id>] [--uly <uly>] [--history] [--archive]",
9965
10394
  description: "List open or historical option orders"
9966
10395
  },
9967
10396
  get: {
10397
+ toolName: "option_get_order",
9968
10398
  usage: "okx option get --instId <id> [--ordId <id>] [--clOrdId <id>]",
9969
10399
  description: "Get details of a specific option order"
9970
10400
  },
9971
10401
  positions: {
10402
+ toolName: "option_get_positions",
9972
10403
  usage: "okx option positions [--instId <id>] [--uly <uly>]",
9973
10404
  description: "Get current option positions"
9974
10405
  },
9975
10406
  fills: {
10407
+ toolName: "option_get_fills",
9976
10408
  usage: "okx option fills [--instId <id>] [--ordId <id>] [--archive]",
9977
10409
  description: "Get trade fill history for option orders"
9978
10410
  },
9979
10411
  instruments: {
10412
+ toolName: "option_get_instruments",
9980
10413
  usage: "okx option instruments --uly <uly> [--expTime <date>]",
9981
10414
  description: "List tradable option instruments for an underlying"
9982
10415
  },
9983
10416
  greeks: {
10417
+ toolName: "option_get_greeks",
9984
10418
  usage: "okx option greeks --uly <uly> [--expTime <date>]",
9985
10419
  description: "Get option greeks (delta, gamma, theta, vega)"
9986
10420
  },
9987
10421
  place: {
10422
+ toolName: "option_place_order",
9988
10423
  usage: "okx option place --instId <id> --tdMode <cash|cross|isolated> --side <buy|sell> --ordType <type> --sz <n>\n [--px <price>] [--reduceOnly] [--clOrdId <id>]",
9989
10424
  description: "Place a new option order"
9990
10425
  },
9991
10426
  cancel: {
10427
+ toolName: "option_cancel_order",
9992
10428
  usage: "okx option cancel --instId <id> [--ordId <id>] [--clOrdId <id>]",
9993
10429
  description: "Cancel a pending option order"
9994
10430
  },
9995
10431
  amend: {
10432
+ toolName: "option_amend_order",
9996
10433
  usage: "okx option amend --instId <id> [--ordId <id>] [--clOrdId <id>] [--newSz <n>] [--newPx <price>]",
9997
10434
  description: "Amend a pending option order"
9998
10435
  },
9999
10436
  "batch-cancel": {
10437
+ toolName: "option_batch_cancel",
10000
10438
  usage: "okx option batch-cancel --orders '<json>'",
10001
10439
  description: "Batch cancel option orders"
10002
10440
  }
10441
+ },
10442
+ subgroups: {
10443
+ algo: {
10444
+ description: "Option algo orders (conditional, TP/SL)",
10445
+ commands: {
10446
+ orders: {
10447
+ toolName: "option_get_algo_orders",
10448
+ usage: "okx option algo orders [--instId <id>] [--history] [--ordType <conditional|oco>]",
10449
+ description: "List option algo orders"
10450
+ },
10451
+ place: {
10452
+ toolName: "option_place_algo_order",
10453
+ usage: "okx option algo place --instId <id> --tdMode <cash|cross|isolated> --side <buy|sell> --sz <n>\n [--ordType <conditional|oco>] [--tpTriggerPx <price>] [--tpOrdPx <price|-1>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>] [--reduceOnly] [--clOrdId <id>]",
10454
+ description: "Place an option algo order (take-profit/stop-loss)"
10455
+ },
10456
+ amend: {
10457
+ toolName: "option_amend_algo_order",
10458
+ usage: "okx option algo amend --instId <id> --algoId <id> [--newSz <n>]\n [--newTpTriggerPx <price>] [--newTpOrdPx <price|-1>]\n [--newSlTriggerPx <price>] [--newSlOrdPx <price|-1>]",
10459
+ description: "Amend a pending option algo order"
10460
+ },
10461
+ cancel: {
10462
+ toolName: "option_cancel_algo_orders",
10463
+ usage: "okx option algo cancel --instId <id> --algoId <id>",
10464
+ description: "Cancel a pending option algo order"
10465
+ }
10466
+ }
10467
+ }
10003
10468
  }
10004
10469
  },
10470
+ // ── earn ───────────────────────────────────────────────────────────────────
10005
10471
  earn: {
10006
10472
  description: "Earn products \u2014 Simple Earn, On-chain Earn, and DCD (Dual Currency Deposit)",
10007
10473
  subgroups: {
@@ -10009,38 +10475,47 @@ var HELP_TREE = {
10009
10475
  description: "Simple Earn \u2014 flexible savings, fixed-term, and lending",
10010
10476
  commands: {
10011
10477
  balance: {
10478
+ toolName: "earn_get_savings_balance",
10012
10479
  usage: "okx earn savings balance [<ccy>]",
10013
10480
  description: "Get savings balance (optionally filter by currency)"
10014
10481
  },
10015
10482
  purchase: {
10483
+ toolName: "earn_savings_purchase",
10016
10484
  usage: "okx earn savings purchase --ccy <ccy> --amt <n> [--rate <rate>]",
10017
10485
  description: "Purchase Simple Earn (flexible savings). Rate defaults to 0.01 (1%)"
10018
10486
  },
10019
10487
  redeem: {
10488
+ toolName: "earn_savings_redeem",
10020
10489
  usage: "okx earn savings redeem --ccy <ccy> --amt <n>",
10021
10490
  description: "Redeem Simple Earn (flexible savings)"
10022
10491
  },
10023
10492
  "set-rate": {
10493
+ toolName: "earn_set_lending_rate",
10024
10494
  usage: "okx earn savings set-rate --ccy <ccy> --rate <rate>",
10025
10495
  description: "Set lending rate for a currency"
10026
10496
  },
10027
10497
  "lending-history": {
10498
+ toolName: "earn_get_lending_history",
10028
10499
  usage: "okx earn savings lending-history [--ccy <ccy>] [--limit <n>]",
10029
10500
  description: "Get personal lending records (requires auth)"
10030
10501
  },
10031
10502
  "rate-history": {
10503
+ toolName: "earn_get_lending_rate_history",
10032
10504
  usage: "okx earn savings rate-history [--ccy <ccy>] [--limit <n>]",
10033
10505
  description: "Query Simple Earn lending rates and fixed-term offers (requires auth)"
10034
10506
  },
10035
10507
  "fixed-orders": {
10508
+ toolName: "earn_get_fixed_order_list",
10036
10509
  usage: "okx earn savings fixed-orders [--ccy <ccy>] [--state <pending|earning|expired|settled|cancelled>]",
10037
10510
  description: "List fixed-term earn orders"
10038
10511
  },
10039
10512
  "fixed-purchase": {
10513
+ toolName: "earn_fixed_purchase",
10040
10514
  usage: "okx earn savings fixed-purchase --ccy <ccy> --amt <n> --term <term> [--confirm]",
10041
10515
  description: "Purchase Simple Earn Fixed (\u5B9A\u671F). Preview by default; add --confirm to execute. Funds locked until maturity"
10042
10516
  },
10043
10517
  "fixed-redeem": {
10518
+ toolName: "earn_fixed_redeem",
10044
10519
  usage: "okx earn savings fixed-redeem <reqId>",
10045
10520
  description: "Redeem a fixed-term earn order (full amount)"
10046
10521
  }
@@ -10050,26 +10525,32 @@ var HELP_TREE = {
10050
10525
  description: "On-chain Earn \u2014 staking and DeFi products",
10051
10526
  commands: {
10052
10527
  offers: {
10528
+ toolName: "onchain_earn_get_offers",
10053
10529
  usage: "okx earn onchain offers [--productId <id>] [--protocolType <type>] [--ccy <ccy>]",
10054
10530
  description: "Browse available on-chain earn products (staking, DeFi)"
10055
10531
  },
10056
10532
  purchase: {
10533
+ toolName: "onchain_earn_purchase",
10057
10534
  usage: "okx earn onchain purchase --productId <id> --ccy <ccy> --amt <n> [--term <term>] [--tag <tag>]",
10058
10535
  description: "Purchase an on-chain earn product (stake/deposit)"
10059
10536
  },
10060
10537
  redeem: {
10538
+ toolName: "onchain_earn_redeem",
10061
10539
  usage: "okx earn onchain redeem --ordId <id> --protocolType <type> [--allowEarlyRedeem]",
10062
10540
  description: "Redeem an on-chain earn position"
10063
10541
  },
10064
10542
  cancel: {
10543
+ toolName: "onchain_earn_cancel",
10065
10544
  usage: "okx earn onchain cancel --ordId <id> --protocolType <type>",
10066
10545
  description: "Cancel a pending on-chain earn order"
10067
10546
  },
10068
10547
  orders: {
10548
+ toolName: "onchain_earn_get_active_orders",
10069
10549
  usage: "okx earn onchain orders [--productId <id>] [--protocolType <type>] [--ccy <ccy>] [--state <state>]",
10070
10550
  description: "List active on-chain earn orders"
10071
10551
  },
10072
10552
  history: {
10553
+ toolName: "onchain_earn_get_order_history",
10073
10554
  usage: "okx earn onchain history [--productId <id>] [--protocolType <type>] [--ccy <ccy>]",
10074
10555
  description: "Get on-chain earn order history"
10075
10556
  }
@@ -10079,14 +10560,19 @@ var HELP_TREE = {
10079
10560
  description: "Auto-earn \u2014 automatically lend, stake, or earn on idle assets",
10080
10561
  commands: {
10081
10562
  status: {
10563
+ // CLI reads from account_get_balance; earn_auto_set is covered by 'on' command below
10564
+ toolName: null,
10082
10565
  usage: "okx earn auto-earn status [<ccy>]",
10083
10566
  description: "Query auto-earn status for all or a specific currency"
10084
10567
  },
10085
10568
  on: {
10569
+ toolName: "earn_auto_set",
10086
10570
  usage: "okx earn auto-earn on <ccy>",
10087
10571
  description: "Enable auto-earn for a currency (auto-detects lend/stake vs USDG earn)"
10088
10572
  },
10089
10573
  off: {
10574
+ // same tool as 'on'; earn_auto_set already registered above
10575
+ toolName: "earn_auto_set",
10090
10576
  usage: "okx earn auto-earn off <ccy>",
10091
10577
  description: "Disable auto-earn for a currency"
10092
10578
  }
@@ -10096,26 +10582,32 @@ var HELP_TREE = {
10096
10582
  description: "DCD (Dual Currency Deposit) \u2014 structured products with fixed yield",
10097
10583
  commands: {
10098
10584
  pairs: {
10585
+ toolName: "dcd_get_currency_pairs",
10099
10586
  usage: "okx earn dcd pairs",
10100
10587
  description: "List available DCD currency pairs"
10101
10588
  },
10102
10589
  products: {
10590
+ toolName: "dcd_get_products",
10103
10591
  usage: "okx earn dcd products --baseCcy <ccy> --quoteCcy <ccy> --optType <C|P>\n [--minYield <n>] [--strikeNear <price>]\n [--termDays <n>] [--minTermDays <n>] [--maxTermDays <n>]\n [--expDate <YYYY-MM-DD|YYYY-MM-DDTHH:mm>]",
10104
10592
  description: "List active DCD products (baseCcy, quoteCcy, optType required). Client-side filters: minYield (e.g. 0.05=5%), strikeNear (\xB110%), term range, expDate"
10105
10593
  },
10106
10594
  "quote-and-buy": {
10595
+ toolName: "dcd_subscribe",
10107
10596
  usage: "okx earn dcd quote-and-buy --productId <id> --sz <n> --notionalCcy <ccy> [--clOrdId <id>] [--minAnnualizedYield <pct>]",
10108
10597
  description: "[CAUTION] Subscribe to a DCD product atomically (quote + execute in one step)"
10109
10598
  },
10110
10599
  "redeem-execute": {
10600
+ toolName: "dcd_redeem",
10111
10601
  usage: "okx earn dcd redeem-execute --ordId <id>",
10112
10602
  description: "[CAUTION] Re-quote and execute early redemption in one step (recommended for AI agent use)"
10113
10603
  },
10114
10604
  order: {
10605
+ toolName: "dcd_get_order_state",
10115
10606
  usage: "okx earn dcd order --ordId <id>",
10116
10607
  description: "Query current state of a DCD order"
10117
10608
  },
10118
10609
  orders: {
10610
+ toolName: "dcd_get_orders",
10119
10611
  usage: "okx earn dcd orders [--ordId <id>] [--productId <id>] [--uly <uly>] [--state <state>] [--limit <n>]",
10120
10612
  description: "Get DCD order history. State: initial|live|pending_settle|settled|pending_redeem|redeemed|rejected"
10121
10613
  }
@@ -10123,6 +10615,7 @@ var HELP_TREE = {
10123
10615
  }
10124
10616
  }
10125
10617
  },
10618
+ // ── bot ────────────────────────────────────────────────────────────────────
10126
10619
  bot: {
10127
10620
  description: "Trading bot strategies (grid, dca)",
10128
10621
  subgroups: {
@@ -10130,22 +10623,27 @@ var HELP_TREE = {
10130
10623
  description: "Grid trading bot \u2014 create, monitor, and stop grid orders",
10131
10624
  commands: {
10132
10625
  orders: {
10626
+ toolName: "grid_get_orders",
10133
10627
  usage: "okx bot grid orders --algoOrdType <grid|contract_grid|moon_grid> [--instId <id>] [--algoId <id>] [--history]",
10134
10628
  description: "List active or historical grid bot orders"
10135
10629
  },
10136
10630
  details: {
10631
+ toolName: "grid_get_order_details",
10137
10632
  usage: "okx bot grid details --algoOrdType <type> --algoId <id>",
10138
10633
  description: "Get details of a specific grid bot order"
10139
10634
  },
10140
10635
  "sub-orders": {
10636
+ toolName: "grid_get_sub_orders",
10141
10637
  usage: "okx bot grid sub-orders --algoOrdType <type> --algoId <id> [--live]",
10142
10638
  description: "List sub-orders of a grid bot (filled or live)"
10143
10639
  },
10144
10640
  create: {
10641
+ toolName: "grid_create_order",
10145
10642
  usage: "okx bot grid create --instId <id> --algoOrdType <grid|contract_grid> --maxPx <px> --minPx <px> --gridNum <n>\n [--runType <1|2>] [--quoteSz <n>] [--baseSz <n>]\n [--direction <long|short|neutral>] [--lever <n>] [--sz <n>] [--basePos] [--no-basePos]\n [--tpTriggerPx <px>] [--slTriggerPx <px>] [--tpRatio <n>] [--slRatio <n>] [--algoClOrdId <id>]",
10146
10643
  description: "Create a new grid bot order (contract grid opens base position by default)"
10147
10644
  },
10148
10645
  stop: {
10646
+ toolName: "grid_stop_order",
10149
10647
  usage: "okx bot grid stop --algoId <id> --algoOrdType <type> --instId <id> [--stopType <1|2|3|5|6>]",
10150
10648
  description: "Stop a running grid bot order"
10151
10649
  }
@@ -10155,22 +10653,27 @@ var HELP_TREE = {
10155
10653
  description: "DCA (Martingale) bot \u2014 spot or contract recurring buys",
10156
10654
  commands: {
10157
10655
  orders: {
10656
+ toolName: "dca_get_orders",
10158
10657
  usage: "okx bot dca orders [--algoOrdType <spot_dca|contract_dca>] [--algoId <id>] [--instId <id>] [--history]",
10159
10658
  description: "List DCA bots (spot and/or contract)"
10160
10659
  },
10161
10660
  details: {
10661
+ toolName: "dca_get_order_details",
10162
10662
  usage: "okx bot dca details --algoOrdType <spot_dca|contract_dca> --algoId <id>",
10163
10663
  description: "Get DCA bot details (spot or contract)"
10164
10664
  },
10165
10665
  "sub-orders": {
10666
+ toolName: "dca_get_sub_orders",
10166
10667
  usage: "okx bot dca sub-orders --algoOrdType <spot_dca|contract_dca> --algoId <id> [--cycleId <id>]",
10167
10668
  description: "Get DCA cycles/orders (spot or contract)"
10168
10669
  },
10169
10670
  create: {
10671
+ toolName: "dca_create_order",
10170
10672
  usage: "okx bot dca create --algoOrdType <spot_dca|contract_dca> --instId <id> --direction <long|short>\n --initOrdAmt <n> --maxSafetyOrds <n> --tpPct <n>\n [--lever <n>] [--safetyOrdAmt <n>] [--pxSteps <n>] [--pxStepsMult <n>] [--volMult <n>]\n [--slPct <n>] [--slMode <limit|market>] [--allowReinvest <true|false>]\n [--triggerStrategy <instant|price|rsi>] [--triggerPx <price>]\n [--triggerCond <cross_up|cross_down>] [--thold <n>] [--timeframe <tf>] [--timePeriod <n>]\n [--algoClOrdId <id>] [--reserveFunds <true|false>] [--tradeQuoteCcy <ccy>]\n Note: --lever required for contract_dca; safetyOrdAmt, pxSteps, pxStepsMult, volMult required when maxSafetyOrds > 0\n triggerStrategy: contract_dca supports instant|price|rsi; spot_dca supports instant|rsi",
10171
10673
  description: "Create a DCA (Martingale) bot (spot or contract)"
10172
10674
  },
10173
10675
  stop: {
10676
+ toolName: "dca_stop_order",
10174
10677
  usage: "okx bot dca stop --algoOrdType <spot_dca|contract_dca> --algoId <id> [--stopType <1|2>]\n Note: --stopType required for spot_dca (1=sell all, 2=keep tokens)",
10175
10678
  description: "Stop a DCA bot (spot or contract)"
10176
10679
  }
@@ -10178,73 +10681,254 @@ var HELP_TREE = {
10178
10681
  }
10179
10682
  }
10180
10683
  },
10684
+ // ── config ─────────────────────────────────────────────────────────────────
10181
10685
  config: {
10182
10686
  description: "Manage CLI configuration profiles",
10183
10687
  commands: {
10184
10688
  init: {
10689
+ toolName: null,
10185
10690
  usage: "okx config init [--lang zh]",
10186
10691
  description: "Initialize a new configuration profile interactively"
10187
10692
  },
10188
10693
  show: {
10694
+ toolName: null,
10189
10695
  usage: "okx config show",
10190
10696
  description: `Show current configuration (file: ${configFilePath()})`
10191
10697
  },
10192
10698
  set: {
10699
+ toolName: null,
10193
10700
  usage: "okx config set <key> <value>",
10194
10701
  description: "Set a configuration value"
10195
10702
  },
10196
10703
  "setup-clients": {
10704
+ toolName: null,
10197
10705
  usage: "okx config setup-clients",
10198
10706
  description: "Set up MCP client integrations (Cursor, Windsurf, etc.)"
10199
10707
  }
10200
10708
  }
10201
10709
  },
10710
+ // ── setup ──────────────────────────────────────────────────────────────────
10202
10711
  setup: {
10203
10712
  description: "Set up client integrations (Cursor, Windsurf, Claude, etc.)",
10204
10713
  usage: `okx setup --client <${SUPPORTED_CLIENTS.join("|")}> [--profile <name>] [--modules <list>]`
10205
10714
  },
10715
+ // ── doh ────────────────────────────────────────────────────────────────────
10716
+ doh: {
10717
+ description: "Manage DoH (DNS-over-HTTPS) resolver binary",
10718
+ commands: {
10719
+ status: {
10720
+ toolName: null,
10721
+ usage: "okx doh status [--json]",
10722
+ description: "Show DoH binary info, checksum, and CDN match status"
10723
+ },
10724
+ install: {
10725
+ toolName: null,
10726
+ usage: "okx doh install [--json]",
10727
+ description: "Download or update the DoH resolver binary"
10728
+ },
10729
+ remove: {
10730
+ toolName: null,
10731
+ usage: "okx doh remove [--force] [--json]",
10732
+ description: "Remove the DoH resolver binary (prompts for confirmation without --force)"
10733
+ }
10734
+ }
10735
+ },
10736
+ // ── diagnose ───────────────────────────────────────────────────────────────
10206
10737
  diagnose: {
10207
10738
  description: "Run network / MCP server diagnostics",
10208
10739
  usage: "okx diagnose [--cli | --mcp | --all] [--profile <name>] [--demo | --live] [--output <file>]"
10209
10740
  },
10741
+ // ── skill ──────────────────────────────────────────────────────────────────
10210
10742
  skill: {
10211
10743
  description: "OKX Skills Marketplace \u2014 search, install, and manage agent skills",
10212
10744
  commands: {
10213
10745
  search: {
10746
+ toolName: "skills_search",
10214
10747
  usage: "okx skill search [--keyword <kw>] [--categories <id>] [--page <n>] [--limit <n>]",
10215
10748
  description: "Search for skills in the marketplace"
10216
10749
  },
10217
10750
  categories: {
10751
+ toolName: "skills_get_categories",
10218
10752
  usage: "okx skill categories",
10219
10753
  description: "List available skill categories"
10220
10754
  },
10221
10755
  add: {
10756
+ // Composite: downloads + installs via npx; no single ToolSpec
10757
+ toolName: null,
10222
10758
  usage: "okx skill add <name>",
10223
10759
  description: "Download and install a skill to detected agents"
10224
10760
  },
10225
10761
  download: {
10762
+ // CLI calls downloadSkillZip directly (same capability as skills_download ToolSpec)
10763
+ toolName: "skills_download",
10226
10764
  usage: "okx skill download <name> [--dir <path>] [--format zip|skill]",
10227
10765
  description: "Download a skill package without installing"
10228
10766
  },
10229
10767
  remove: {
10768
+ toolName: null,
10230
10769
  usage: "okx skill remove <name>",
10231
10770
  description: "Remove an installed skill"
10232
10771
  },
10233
10772
  check: {
10773
+ // Uses skills_search internally; skills_search already registered above
10774
+ toolName: null,
10234
10775
  usage: "okx skill check <name>",
10235
10776
  description: "Check if an installed skill has a newer version"
10236
10777
  },
10237
10778
  list: {
10779
+ toolName: null,
10238
10780
  usage: "okx skill list",
10239
10781
  description: "List all locally installed skills"
10240
10782
  }
10241
10783
  }
10242
10784
  },
10785
+ // ── upgrade ────────────────────────────────────────────────────────────────
10243
10786
  upgrade: {
10244
10787
  description: "Upgrade okx CLI and MCP server to the latest stable version",
10245
10788
  usage: "okx upgrade [--check] [--beta] [--force] [--json]"
10246
10789
  }
10247
10790
  };
10791
+
10792
+ // src/help-generator.ts
10793
+ function buildSpecMap() {
10794
+ return new Map(allToolSpecs().map((s) => [s.name, s]));
10795
+ }
10796
+ function resolveCommandDescription(entry, specMap, fallback = "(no description)") {
10797
+ if (entry.description) return entry.description;
10798
+ if (entry.toolName != null) {
10799
+ const spec = specMap.get(entry.toolName);
10800
+ if (spec?.description) return spec.description.split(/\.\s/)[0] + ".";
10801
+ }
10802
+ return fallback;
10803
+ }
10804
+ function buildCommands(commands, specMap) {
10805
+ const result = {};
10806
+ for (const [name, entry] of Object.entries(commands)) {
10807
+ result[name] = {
10808
+ usage: entry.usage,
10809
+ description: resolveCommandDescription(entry, specMap)
10810
+ };
10811
+ }
10812
+ return result;
10813
+ }
10814
+ function buildGroupInfo(key, mod, specMap) {
10815
+ const description = mod.description ?? MODULE_DESCRIPTIONS[key] ?? key;
10816
+ return {
10817
+ description,
10818
+ usage: mod.usage,
10819
+ commands: mod.commands ? buildCommands(mod.commands, specMap) : void 0,
10820
+ subgroups: mod.subgroups ? buildSubgroups(mod.subgroups, specMap) : void 0
10821
+ };
10822
+ }
10823
+ function buildSubgroups(subgroups, specMap) {
10824
+ const result = {};
10825
+ for (const [name, entry] of Object.entries(subgroups)) {
10826
+ result[name] = buildGroupInfo(name, entry, specMap);
10827
+ }
10828
+ return result;
10829
+ }
10830
+ var _cached = null;
10831
+ function generateHelpTree() {
10832
+ if (_cached) return _cached;
10833
+ const specMap = buildSpecMap();
10834
+ const tree = {};
10835
+ for (const [key, mod] of Object.entries(CLI_REGISTRY)) {
10836
+ tree[key] = buildGroupInfo(key, mod, specMap);
10837
+ }
10838
+ _cached = tree;
10839
+ return tree;
10840
+ }
10841
+
10842
+ // src/commands/discovery.ts
10843
+ function extractParameters(toolName, specMap) {
10844
+ if (toolName == null) return [];
10845
+ const spec = specMap.get(toolName);
10846
+ if (!spec?.inputSchema) return [];
10847
+ const schema = spec.inputSchema;
10848
+ if (!schema.properties) return [];
10849
+ const required = new Set(schema.required ?? []);
10850
+ return Object.entries(schema.properties).map(([name, prop]) => ({
10851
+ name,
10852
+ type: prop.type ?? "string",
10853
+ required: required.has(name),
10854
+ description: prop.description
10855
+ }));
10856
+ }
10857
+ function collectCommands(modulePath, mod, specMap, commands) {
10858
+ for (const [cmdName, entry] of Object.entries(mod.commands ?? {})) {
10859
+ commands.push({
10860
+ path: `${modulePath} ${cmdName}`,
10861
+ toolName: entry.toolName,
10862
+ description: resolveCommandDescription(entry, specMap, ""),
10863
+ parameters: extractParameters(entry.toolName, specMap)
10864
+ });
10865
+ }
10866
+ for (const [sgName, sg] of Object.entries(mod.subgroups ?? {})) {
10867
+ collectCommands(`${modulePath} ${sgName}`, sg, specMap, commands);
10868
+ }
10869
+ }
10870
+ function getDiscoveryOutput() {
10871
+ const specs = allToolSpecs();
10872
+ const specMap = new Map(specs.map((s) => [s.name, s]));
10873
+ const moduleDescMap = new Map(specs.map((s) => [s.module, s.description]));
10874
+ const version = readCliVersion();
10875
+ const modules = [];
10876
+ for (const [moduleKey, moduleEntry] of Object.entries(CLI_REGISTRY)) {
10877
+ const commands = [];
10878
+ collectCommands(`okx ${moduleKey}`, moduleEntry, specMap, commands);
10879
+ const description = moduleEntry.description ?? MODULE_DESCRIPTIONS[moduleKey] ?? moduleDescMap.get(moduleKey) ?? moduleKey;
10880
+ modules.push({
10881
+ name: moduleKey,
10882
+ description,
10883
+ commands
10884
+ });
10885
+ }
10886
+ const totalTools = modules.reduce(
10887
+ (sum, m) => sum + m.commands.filter((c) => c.toolName !== null).length,
10888
+ 0
10889
+ );
10890
+ return { version, totalTools, modules };
10891
+ }
10892
+ function cmdListTools(json) {
10893
+ const data = getDiscoveryOutput();
10894
+ if (json) {
10895
+ output(JSON.stringify(data, null, 2) + "\n");
10896
+ return;
10897
+ }
10898
+ const lines = [
10899
+ "",
10900
+ `OKX CLI v${data.version} \u2014 ${data.totalTools} tool-backed commands across ${data.modules.length} modules`,
10901
+ "",
10902
+ "Modules:"
10903
+ ];
10904
+ for (const mod of data.modules) {
10905
+ const toolCmds = mod.commands.filter((c) => c.toolName !== null).length;
10906
+ if (toolCmds > 0) {
10907
+ lines.push(` ${mod.name.padEnd(14)}${toolCmds} commands`);
10908
+ }
10909
+ }
10910
+ lines.push("", 'Use "okx list-tools --json" for machine-readable output.', "");
10911
+ output(lines.join("\n"));
10912
+ }
10913
+
10914
+ // src/config/loader.ts
10915
+ function loadProfileConfig(opts) {
10916
+ return loadConfig({
10917
+ profile: opts.profile,
10918
+ modules: opts.modules,
10919
+ readOnly: opts.readOnly ?? false,
10920
+ demo: opts.demo,
10921
+ live: opts.live,
10922
+ site: opts.site,
10923
+ userAgent: opts.userAgent,
10924
+ sourceTag: opts.sourceTag,
10925
+ verbose: opts.verbose
10926
+ });
10927
+ }
10928
+
10929
+ // src/help.ts
10930
+ import { EOL as EOL2 } from "os";
10931
+ var HELP_TREE = generateHelpTree();
10248
10932
  function printGlobalHelp() {
10249
10933
  const lines = [
10250
10934
  "",
@@ -13366,14 +14050,14 @@ async function cmdDcdQuoteAndBuy(run, opts) {
13366
14050
  }
13367
14051
 
13368
14052
  // src/commands/skill.ts
13369
- import { tmpdir, homedir as homedir9 } from "os";
13370
- import { join as join11, dirname as dirname7 } from "path";
13371
- import { mkdirSync as mkdirSync9, rmSync, existsSync as existsSync7, copyFileSync as copyFileSync2 } from "fs";
14053
+ import { tmpdir, homedir as homedir10 } from "os";
14054
+ import { join as join12, dirname as dirname8 } from "path";
14055
+ import { mkdirSync as mkdirSync10, rmSync, existsSync as existsSync8, copyFileSync as copyFileSync2 } from "fs";
13372
14056
  import { execFileSync as execFileSync2 } from "child_process";
13373
14057
  import { randomUUID as randomUUID2 } from "crypto";
13374
14058
  function resolveNpx() {
13375
- const sibling = join11(dirname7(process.execPath), "npx");
13376
- if (existsSync7(sibling)) return sibling;
14059
+ const sibling = join12(dirname8(process.execPath), "npx");
14060
+ if (existsSync8(sibling)) return sibling;
13377
14061
  return "npx";
13378
14062
  }
13379
14063
  var THIRD_PARTY_INSTALL_NOTICE = "Note: This skill was created by a third-party developer, not by OKX. Review SKILL.md before use.";
@@ -13426,13 +14110,13 @@ async function cmdSkillCategories(run, json) {
13426
14110
  outputLine("");
13427
14111
  }
13428
14112
  async function cmdSkillAdd(name, config, json) {
13429
- const tmpBase = join11(tmpdir(), `okx-skill-${randomUUID2()}`);
13430
- mkdirSync9(tmpBase, { recursive: true });
14113
+ const tmpBase = join12(tmpdir(), `okx-skill-${randomUUID2()}`);
14114
+ mkdirSync10(tmpBase, { recursive: true });
13431
14115
  try {
13432
14116
  outputLine(`Downloading ${name}...`);
13433
14117
  const client = new OkxRestClient(config);
13434
14118
  const zipPath = await downloadSkillZip(client, name, tmpBase);
13435
- const contentDir = await extractSkillZip(zipPath, join11(tmpBase, "content"));
14119
+ const contentDir = await extractSkillZip(zipPath, join12(tmpBase, "content"));
13436
14120
  const meta = readMetaJson(contentDir);
13437
14121
  validateSkillMdExists(contentDir);
13438
14122
  outputLine("Installing to detected agents...");
@@ -13442,7 +14126,7 @@ async function cmdSkillAdd(name, config, json) {
13442
14126
  timeout: 6e4
13443
14127
  });
13444
14128
  } catch (e) {
13445
- const savedZip = join11(process.cwd(), `${name}.zip`);
14129
+ const savedZip = join12(process.cwd(), `${name}.zip`);
13446
14130
  try {
13447
14131
  copyFileSync2(zipPath, savedZip);
13448
14132
  } catch {
@@ -13481,7 +14165,7 @@ function cmdSkillRemove(name, json) {
13481
14165
  timeout: 6e4
13482
14166
  });
13483
14167
  } catch {
13484
- const agentsPath = join11(homedir9(), ".agents", "skills", name);
14168
+ const agentsPath = join12(homedir10(), ".agents", "skills", name);
13485
14169
  try {
13486
14170
  rmSync(agentsPath, { recursive: true, force: true });
13487
14171
  } catch {
@@ -13554,10 +14238,171 @@ function printSkillInstallResult(meta, json) {
13554
14238
  }
13555
14239
  }
13556
14240
 
14241
+ // src/commands/doh.ts
14242
+ import readline from "readline";
14243
+ function resolveChecksumMatch(local, cdnChecksum, cdnError) {
14244
+ if (!local.exists) return "not-installed";
14245
+ if (cdnError || !cdnChecksum) return "unavailable";
14246
+ if (cdnChecksum.sha256 === local.sha256) return "match";
14247
+ return "mismatch";
14248
+ }
14249
+ function checksumMatchLabel(match) {
14250
+ if (match === "match") return "\u2713 match";
14251
+ if (match === "mismatch") return "\u2717 mismatch (update available)";
14252
+ return "CDN unreachable";
14253
+ }
14254
+ function formatStatusText(local, checksumMatch, cdnChecksum, runtimeMode) {
14255
+ outputLine("");
14256
+ outputLine(" DoH Resolver Status");
14257
+ outputLine(" " + "\u2500".repeat(40));
14258
+ outputLine(` Binary path : ${local.binaryPath}`);
14259
+ outputLine(` Installed : ${local.exists ? "yes" : "no"}`);
14260
+ outputLine(` Platform : ${local.platform ?? "(unsupported)"}`);
14261
+ if (local.exists) {
14262
+ outputLine(` File size : ${formatBytes(local.fileSize)}`);
14263
+ outputLine(` SHA-256 : ${local.sha256 ?? "(unknown)"}`);
14264
+ outputLine(` CDN check : ${checksumMatchLabel(checksumMatch)}`);
14265
+ if (cdnChecksum) {
14266
+ outputLine(` CDN source : ${cdnChecksum.source}`);
14267
+ }
14268
+ }
14269
+ outputLine(` Runtime mode: ${runtimeMode}`);
14270
+ outputLine("");
14271
+ }
14272
+ async function cmdDohStatus(json, binaryPath) {
14273
+ const local = getDohStatus(binaryPath);
14274
+ let runtimeMode = "no cache";
14275
+ try {
14276
+ const cacheEntry = readCache("www.okx.com");
14277
+ if (cacheEntry) {
14278
+ runtimeMode = cacheEntry.mode;
14279
+ }
14280
+ } catch {
14281
+ }
14282
+ let cdnChecksum = null;
14283
+ let cdnError = null;
14284
+ if (local.exists) {
14285
+ try {
14286
+ cdnChecksum = await fetchCdnChecksum(void 0, 5e3);
14287
+ } catch (err) {
14288
+ cdnError = err instanceof Error ? err.message : String(err);
14289
+ }
14290
+ }
14291
+ const checksumMatch = resolveChecksumMatch(local, cdnChecksum, cdnError);
14292
+ if (json) {
14293
+ outputLine(
14294
+ JSON.stringify({
14295
+ binaryPath: local.binaryPath,
14296
+ exists: local.exists,
14297
+ platform: local.platform,
14298
+ fileSize: local.fileSize ?? null,
14299
+ sha256: local.sha256 ?? null,
14300
+ cdnMatch: checksumMatch,
14301
+ cdnSha256: cdnChecksum?.sha256 ?? null,
14302
+ cdnSource: cdnChecksum?.source ?? null,
14303
+ runtimeMode
14304
+ })
14305
+ );
14306
+ return;
14307
+ }
14308
+ formatStatusText(local, checksumMatch, cdnChecksum, runtimeMode);
14309
+ }
14310
+ async function cmdDohInstall(json, binaryPath) {
14311
+ const messages2 = [];
14312
+ const onProgress = (msg) => {
14313
+ if (!json) {
14314
+ outputLine(` ${msg}`);
14315
+ }
14316
+ messages2.push(msg);
14317
+ };
14318
+ if (!json) {
14319
+ outputLine("");
14320
+ outputLine(" Installing DoH resolver...");
14321
+ }
14322
+ const result = await installDohBinary(binaryPath, void 0, onProgress);
14323
+ if (json) {
14324
+ outputLine(JSON.stringify({ status: result.status, source: result.source ?? null, error: result.error ?? null, messages: messages2 }));
14325
+ if (result.status === "failed") {
14326
+ process.exitCode = 1;
14327
+ }
14328
+ return;
14329
+ }
14330
+ if (result.status === "installed") {
14331
+ outputLine(` \u2713 DoH resolver installed successfully (${result.source ?? ""})`);
14332
+ } else if (result.status === "up-to-date") {
14333
+ outputLine(" \u2713 DoH resolver is already up to date");
14334
+ } else {
14335
+ errorLine(` \u2717 Installation failed: ${result.error ?? "unknown error"}`);
14336
+ errorLine(" Hint: check network connectivity or try again later");
14337
+ process.exitCode = 1;
14338
+ }
14339
+ outputLine("");
14340
+ }
14341
+ async function cmdDohRemove(force, json, binaryPath) {
14342
+ const local = getDohStatus(binaryPath);
14343
+ if (!local.exists) {
14344
+ if (json) {
14345
+ outputLine(JSON.stringify({ status: "not-installed" }));
14346
+ } else {
14347
+ outputLine(" DoH resolver is not installed.");
14348
+ }
14349
+ return;
14350
+ }
14351
+ if (!force) {
14352
+ if (!process.stdin.isTTY) {
14353
+ errorLine(" Error: stdin is not a TTY. Use --force to skip confirmation.");
14354
+ process.exitCode = 1;
14355
+ return;
14356
+ }
14357
+ const confirmed = await askConfirmation(
14358
+ ` Remove DoH resolver at ${local.binaryPath}? [y/N] `
14359
+ );
14360
+ if (!confirmed) {
14361
+ outputLine(" Cancelled.");
14362
+ return;
14363
+ }
14364
+ }
14365
+ const result = removeDohBinary(binaryPath);
14366
+ if (json) {
14367
+ outputLine(JSON.stringify({ status: result.status, path: local.binaryPath }));
14368
+ return;
14369
+ }
14370
+ if (result.status === "removed") {
14371
+ outputLine(` \u2713 Removed: ${local.binaryPath}`);
14372
+ } else {
14373
+ outputLine(" DoH resolver is not installed.");
14374
+ }
14375
+ }
14376
+ function formatBytes(bytes) {
14377
+ if (bytes < 1024) return `${bytes} B`;
14378
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
14379
+ return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
14380
+ }
14381
+ function askConfirmation(prompt2) {
14382
+ return new Promise((resolve3) => {
14383
+ const rl = readline.createInterface({
14384
+ input: process.stdin,
14385
+ output: process.stdout
14386
+ });
14387
+ rl.question(prompt2, (answer) => {
14388
+ rl.close();
14389
+ resolve3(answer.trim().toLowerCase() === "y");
14390
+ });
14391
+ });
14392
+ }
14393
+
13557
14394
  // src/index.ts
13558
14395
  var _require3 = createRequire3(import.meta.url);
13559
14396
  var CLI_VERSION2 = _require3("../package.json").version;
13560
- var GIT_HASH2 = true ? "980de10" : "dev";
14397
+ var GIT_HASH2 = true ? "63a5613" : "dev";
14398
+ function handleDohCommand(action, json, force, binaryPath) {
14399
+ if (action === "status") return cmdDohStatus(json, binaryPath);
14400
+ if (action === "install") return cmdDohInstall(json, binaryPath);
14401
+ if (action === "remove") return cmdDohRemove(force, json, binaryPath);
14402
+ errorLine(`Unknown doh command: ${action}`);
14403
+ errorLine("Usage: okx doh <status|install|remove>");
14404
+ process.exitCode = 1;
14405
+ }
13561
14406
  function handleConfigCommand(action, rest, json, lang, force) {
13562
14407
  if (action === "init") return cmdConfigInit(lang === "zh" ? "zh" : "en");
13563
14408
  if (action === "show") return cmdConfigShow(json);
@@ -14409,6 +15254,24 @@ async function runDiagnose(v) {
14409
15254
  }
14410
15255
  return cmdDiagnose(config, v.profile ?? "default", { mcp: v.mcp, cli: v.cli, all: v.all, output: v.output });
14411
15256
  }
15257
+ function printVersion() {
15258
+ outputLine(`${CLI_VERSION2} (${GIT_HASH2})`);
15259
+ const dohStatus = getDohStatus(void 0, { skipHash: true });
15260
+ if (dohStatus.exists) {
15261
+ outputLine(`DoH resolver: installed (${dohStatus.platform ?? "unknown"})`);
15262
+ } else {
15263
+ outputLine("DoH resolver: not installed");
15264
+ }
15265
+ }
15266
+ function routeManagementCommand(module, action, rest, json, v) {
15267
+ if (module === "config") return handleConfigCommand(action, rest, json, v.lang, v.force);
15268
+ if (module === "setup") return handleSetupCommand(v);
15269
+ if (module === "upgrade") return cmdUpgrade(CLI_VERSION2, { beta: v.beta, check: v.check, force: v.force }, json);
15270
+ if (module === "doh") return handleDohCommand(action, json, v.force ?? false);
15271
+ if (module === "diagnose") return runDiagnose(v);
15272
+ if (module === "list-tools") return cmdListTools(json);
15273
+ return void 0;
15274
+ }
14412
15275
  async function main() {
14413
15276
  setOutput({
14414
15277
  out: (m) => process.stdout.write(m),
@@ -14417,7 +15280,7 @@ async function main() {
14417
15280
  checkForUpdates("@okx_ai/okx-trade-cli", CLI_VERSION2);
14418
15281
  const { values, positionals } = parseCli(process.argv.slice(2));
14419
15282
  if (values.version) {
14420
- outputLine(`${CLI_VERSION2} (${GIT_HASH2})`);
15283
+ printVersion();
14421
15284
  return;
14422
15285
  }
14423
15286
  if (values.help || positionals.length === 0) {
@@ -14427,10 +15290,8 @@ async function main() {
14427
15290
  const [module, action, ...rest] = positionals;
14428
15291
  const v = values;
14429
15292
  const json = v.json ?? false;
14430
- if (module === "config") return handleConfigCommand(action, rest, json, v.lang, v.force);
14431
- if (module === "setup") return handleSetupCommand(v);
14432
- if (module === "upgrade") return cmdUpgrade(CLI_VERSION2, { beta: v.beta, check: v.check, force: v.force }, json);
14433
- if (module === "diagnose") return runDiagnose(v);
15293
+ const mgmt = routeManagementCommand(module, action, rest, json, v);
15294
+ if (mgmt) return mgmt;
14434
15295
  const config = loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
14435
15296
  setEnvContext({ demo: config.demo, profile: v.profile ?? "default" });
14436
15297
  setJsonEnvEnabled(v.env ?? false);
@@ -14468,6 +15329,7 @@ export {
14468
15329
  handleBotDcaCommand,
14469
15330
  handleBotGridCommand,
14470
15331
  handleConfigCommand,
15332
+ handleDohCommand,
14471
15333
  handleEarnCommand,
14472
15334
  handleFuturesAlgoCommand,
14473
15335
  handleFuturesCommand,