@okx_ai/okx-trade-cli 1.3.1-beta.6 → 1.3.1-beta.8

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
@@ -21,23 +21,26 @@ import {
21
21
  import { homedir as homedir2 } from "os";
22
22
  import { join as join2, dirname } from "path";
23
23
  import { createHmac } from "crypto";
24
+ import { spawn, execFile as execFile2 } from "child_process";
25
+ import { homedir as homedir3 } from "os";
26
+ import { join as join3 } from "path";
24
27
  import fs from "fs";
25
28
  import path from "path";
26
29
  import os from "os";
27
30
  import { writeFileSync as writeFileSync2, renameSync as renameSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync2 } from "fs";
28
- import { join as join3, resolve, basename, sep } from "path";
31
+ import { join as join4, resolve, basename, sep } from "path";
29
32
  import { randomUUID } from "crypto";
30
33
  import yauzl from "yauzl";
31
34
  import { createWriteStream, mkdirSync as mkdirSync3 } from "fs";
32
35
  import { resolve as resolve2, dirname as dirname2 } from "path";
33
36
  import { readFileSync as readFileSync2, existsSync } from "fs";
34
- import { join as join4 } from "path";
37
+ import { join as join5 } from "path";
35
38
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync2 } from "fs";
36
- import { join as join5, dirname as dirname3 } from "path";
37
- import { homedir as homedir3 } from "os";
38
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync3 } from "fs";
39
- import { join as join6, dirname as dirname4 } from "path";
39
+ import { join as join6, dirname as dirname3 } from "path";
40
40
  import { homedir as homedir4 } from "os";
41
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync3 } from "fs";
42
+ import { join as join7, dirname as dirname4 } from "path";
43
+ import { homedir as homedir5 } from "os";
41
44
 
42
45
  // ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/error.js
43
46
  function getLineColFromPtr(string, ptr) {
@@ -867,8 +870,8 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
867
870
 
868
871
  // ../core/dist/index.js
869
872
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync4 } from "fs";
870
- import { join as join7 } from "path";
871
- import { homedir as homedir5 } from "os";
873
+ import { join as join8 } from "path";
874
+ import { homedir as homedir6 } from "os";
872
875
  import fs2 from "fs";
873
876
  import path2 from "path";
874
877
  import os2 from "os";
@@ -876,6 +879,18 @@ import * as fs3 from "fs";
876
879
  import * as path3 from "path";
877
880
  import * as os3 from "os";
878
881
  import { execFileSync } from "child_process";
882
+ import {
883
+ createWriteStream as createWriteStream3,
884
+ mkdirSync as mkdirSync9,
885
+ chmodSync as chmodSync2,
886
+ existsSync as existsSync7,
887
+ unlinkSync as unlinkSync4,
888
+ renameSync as renameSync4
889
+ } from "fs";
890
+ import { homedir as homedir9, platform as platform2 } from "os";
891
+ import { join as join11, dirname as dirname7 } from "path";
892
+ import { get as httpsGet2 } from "https";
893
+ import { get as httpGet2 } from "http";
879
894
  import {
880
895
  readFileSync as readFileSync7,
881
896
  createWriteStream as createWriteStream2,
@@ -886,8 +901,8 @@ import {
886
901
  renameSync as renameSync3
887
902
  } from "fs";
888
903
  import { createHash } from "crypto";
889
- import { homedir as homedir7, platform, arch } from "os";
890
- import { join as join9, dirname as dirname6 } from "path";
904
+ import { homedir as homedir8, platform, arch } from "os";
905
+ import { join as join10, dirname as dirname6 } from "path";
891
906
  import { get as httpsGet } from "https";
892
907
  import { get as httpGet } from "http";
893
908
  var EXEC_TIMEOUT_MS = 3e4;
@@ -1201,6 +1216,11 @@ var ConfigError = class extends OkxMcpError {
1201
1216
  super("ConfigError", message, { suggestion });
1202
1217
  }
1203
1218
  };
1219
+ var NotLoggedInError = class extends ConfigError {
1220
+ constructor(suggestion = "Run `okx auth login` to authenticate.") {
1221
+ super("Not logged in.", suggestion);
1222
+ }
1223
+ };
1204
1224
  var ValidationError = class extends OkxMcpError {
1205
1225
  constructor(message, suggestion) {
1206
1226
  super("ValidationError", message, { suggestion });
@@ -1253,6 +1273,97 @@ function toToolErrorPayload(error, fallbackEndpoint) {
1253
1273
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1254
1274
  };
1255
1275
  }
1276
+ var EXIT_CODES = {
1277
+ SUCCESS: 0,
1278
+ UNAUTHORIZED_CALLER: 1,
1279
+ NOT_LOGGED_IN: 2,
1280
+ REFRESH_FAILED: 3
1281
+ };
1282
+ var EXEC_TIMEOUT_MS2 = 5e3;
1283
+ var AUTH_BIN_DIR = join3(homedir3(), ".okx", "bin");
1284
+ function getAuthBinaryPath() {
1285
+ if (process.env.OKX_AUTH_BIN) {
1286
+ return process.env.OKX_AUTH_BIN;
1287
+ }
1288
+ const ext = process.platform === "win32" ? ".exe" : "";
1289
+ return join3(AUTH_BIN_DIR, `okx-auth${ext}`);
1290
+ }
1291
+ function execAuthToken() {
1292
+ const binPath = getAuthBinaryPath();
1293
+ return new Promise((resolve3, reject) => {
1294
+ const child = spawn(binPath, ["token"], {
1295
+ stdio: ["ignore", "ignore", "inherit", "pipe"]
1296
+ // stdin stdout stderr fd3 (pipe)
1297
+ });
1298
+ const chunks = [];
1299
+ const fd3 = child.stdio[3];
1300
+ fd3.on("data", (chunk) => chunks.push(chunk));
1301
+ child.on("error", (err) => {
1302
+ reject(new ConfigError(
1303
+ `Failed to spawn okx-auth: ${err.message}`,
1304
+ "Ensure the okx-auth binary exists and is executable."
1305
+ ));
1306
+ });
1307
+ child.on("close", (code) => {
1308
+ if (code === EXIT_CODES.SUCCESS) {
1309
+ const token = Buffer.concat(chunks).toString("utf-8").trim();
1310
+ if (!token) {
1311
+ reject(new AuthenticationError(
1312
+ "okx-auth returned empty token.",
1313
+ "Run `okx auth login` to re-authenticate."
1314
+ ));
1315
+ return;
1316
+ }
1317
+ resolve3(token);
1318
+ return;
1319
+ }
1320
+ if (code === EXIT_CODES.NOT_LOGGED_IN) {
1321
+ reject(new NotLoggedInError());
1322
+ return;
1323
+ }
1324
+ if (code === EXIT_CODES.UNAUTHORIZED_CALLER) {
1325
+ reject(new AuthenticationError(
1326
+ "okx-auth rejected the caller (unauthorized).",
1327
+ "Ensure you are running from a trusted OKX tool."
1328
+ ));
1329
+ return;
1330
+ }
1331
+ if (code === EXIT_CODES.REFRESH_FAILED) {
1332
+ reject(new AuthenticationError(
1333
+ "Token refresh failed.",
1334
+ "Run `okx auth login` to re-authenticate."
1335
+ ));
1336
+ return;
1337
+ }
1338
+ reject(new AuthenticationError(
1339
+ `okx-auth token exited with code ${code}.`,
1340
+ "Run `okx auth login` to re-authenticate."
1341
+ ));
1342
+ });
1343
+ });
1344
+ }
1345
+ function execAuthStatus() {
1346
+ const binPath = getAuthBinaryPath();
1347
+ return new Promise((resolve3) => {
1348
+ execFile2(
1349
+ binPath,
1350
+ ["status", "--json"],
1351
+ { timeout: EXEC_TIMEOUT_MS2, encoding: "utf-8" },
1352
+ (error, stdout) => {
1353
+ if (error) {
1354
+ resolve3(null);
1355
+ return;
1356
+ }
1357
+ try {
1358
+ const result = JSON.parse(stdout);
1359
+ resolve3(result);
1360
+ } catch {
1361
+ resolve3(null);
1362
+ }
1363
+ }
1364
+ );
1365
+ });
1366
+ }
1256
1367
  function sleep(ms) {
1257
1368
  return new Promise((resolve3) => {
1258
1369
  setTimeout(resolve3, ms);
@@ -1384,6 +1495,7 @@ function maskKey(key) {
1384
1495
  if (key.length <= 8) return "***";
1385
1496
  return `${key.slice(0, 3)}***${key.slice(-3)}`;
1386
1497
  }
1498
+ var TOKEN_CACHE_TTL_MS = 6e4;
1387
1499
  function vlog2(message) {
1388
1500
  process.stderr.write(`[verbose] ${message}
1389
1501
  `);
@@ -1392,6 +1504,8 @@ var OkxRestClient = class _OkxRestClient {
1392
1504
  config;
1393
1505
  rateLimiter;
1394
1506
  dispatcher;
1507
+ cachedAccessToken;
1508
+ cachedAccessTokenAt = 0;
1395
1509
  doh;
1396
1510
  constructor(config) {
1397
1511
  this.config = config;
@@ -1406,6 +1520,51 @@ var OkxRestClient = class _OkxRestClient {
1406
1520
  hasCustomProxy: !!config.proxyUrl
1407
1521
  });
1408
1522
  }
1523
+ /**
1524
+ * Resolve OAuth access token via the okx-auth binary (fd3 pipe).
1525
+ * Caches the token for 60 s to avoid spawning the binary on every
1526
+ * request. The binary handles refresh internally (300s TTL lead),
1527
+ * so periodic re-calls let it serve a fresh token when needed.
1528
+ * Returns null when not logged in.
1529
+ */
1530
+ async resolveAccessToken() {
1531
+ if (this.cachedAccessToken && Date.now() - this.cachedAccessTokenAt < TOKEN_CACHE_TTL_MS) {
1532
+ return this.cachedAccessToken;
1533
+ }
1534
+ try {
1535
+ const token = await execAuthToken();
1536
+ this.cachedAccessToken = token;
1537
+ this.cachedAccessTokenAt = Date.now();
1538
+ return token;
1539
+ } catch (e) {
1540
+ if (e instanceof NotLoggedInError) {
1541
+ return null;
1542
+ }
1543
+ throw e;
1544
+ }
1545
+ }
1546
+ /**
1547
+ * Dynamic auth — determines auth method per request.
1548
+ *
1549
+ * 1. API key in config → HMAC signing (no OAuth fallback)
1550
+ * 2. OAuth token via okx-auth binary → Bearer token
1551
+ * 3. Neither → throw ConfigError
1552
+ */
1553
+ async applyAuth(headers, method, requestPath, bodyJson, timestamp) {
1554
+ if (this.config.apiKey && this.config.secretKey && this.config.passphrase) {
1555
+ this.setAuthHeaders(headers, method, requestPath, bodyJson, timestamp);
1556
+ return;
1557
+ }
1558
+ const accessToken = await this.resolveAccessToken();
1559
+ if (accessToken) {
1560
+ headers.set("Authorization", `Bearer ${accessToken}`);
1561
+ return;
1562
+ }
1563
+ throw new ConfigError(
1564
+ "No credentials found.",
1565
+ "Run `okx auth login` to authenticate, or configure API key credentials."
1566
+ );
1567
+ }
1409
1568
  /** The canonical base URL for this client (e.g. https://www.okx.com). */
1410
1569
  get baseUrl() {
1411
1570
  return this.config.baseUrl;
@@ -1463,18 +1622,6 @@ var OkxRestClient = class _OkxRestClient {
1463
1622
  });
1464
1623
  }
1465
1624
  setAuthHeaders(headers, method, requestPath, bodyJson, timestamp) {
1466
- if (!this.config.hasAuth) {
1467
- throw new ConfigError(
1468
- "Private endpoint requires API credentials.",
1469
- "Configure OKX_API_KEY, OKX_SECRET_KEY and OKX_PASSPHRASE."
1470
- );
1471
- }
1472
- if (!this.config.apiKey || !this.config.secretKey || !this.config.passphrase) {
1473
- throw new ConfigError(
1474
- "Invalid private API credentials state.",
1475
- "Ensure all OKX credentials are set."
1476
- );
1477
- }
1478
1625
  const payload = `${timestamp}${method.toUpperCase()}${requestPath}${bodyJson}`;
1479
1626
  const signature = signOkxPayload(payload, this.config.secretKey);
1480
1627
  headers.set("OK-ACCESS-KEY", this.config.apiKey);
@@ -1589,7 +1736,7 @@ var OkxRestClient = class _OkxRestClient {
1589
1736
  const conn = this.doh.getConnectionParams();
1590
1737
  this.logRequest("POST", `${conn.baseUrl}${path42}`, "private");
1591
1738
  const reqConfig = { method: "POST", path: path42, auth: "private" };
1592
- const headers = this.buildHeaders(reqConfig, path42, bodyJson, getNow());
1739
+ const headers = await this.buildHeaders(reqConfig, path42, bodyJson, getNow());
1593
1740
  if (conn.userAgent) {
1594
1741
  headers.set("User-Agent", conn.userAgent);
1595
1742
  }
@@ -1706,7 +1853,7 @@ var OkxRestClient = class _OkxRestClient {
1706
1853
  // Header building
1707
1854
  // ---------------------------------------------------------------------------
1708
1855
  /** Build HTTP headers. reqConfig.extraHeaders must NOT contain auth keys (OK-ACCESS-*). */
1709
- buildHeaders(reqConfig, requestPath, bodyJson, timestamp) {
1856
+ async buildHeaders(reqConfig, requestPath, bodyJson, timestamp) {
1710
1857
  const headers = new Headers({
1711
1858
  "Content-Type": "application/json",
1712
1859
  Accept: "application/json"
@@ -1715,7 +1862,7 @@ var OkxRestClient = class _OkxRestClient {
1715
1862
  headers.set("User-Agent", this.config.userAgent);
1716
1863
  }
1717
1864
  if (reqConfig.auth === "private") {
1718
- this.setAuthHeaders(headers, reqConfig.method, requestPath, bodyJson, timestamp);
1865
+ await this.applyAuth(headers, reqConfig.method, requestPath, bodyJson, timestamp);
1719
1866
  }
1720
1867
  const useSimulated = reqConfig.simulatedTrading !== void 0 ? reqConfig.simulatedTrading : this.config.demo;
1721
1868
  if (useSimulated) {
@@ -1769,7 +1916,7 @@ var OkxRestClient = class _OkxRestClient {
1769
1916
  if (reqConfig.rateLimit) {
1770
1917
  await this.rateLimiter.consume(reqConfig.rateLimit);
1771
1918
  }
1772
- const headers = this.buildHeaders(reqConfig, requestPath, bodyJson, timestamp);
1919
+ const headers = await this.buildHeaders(reqConfig, requestPath, bodyJson, timestamp);
1773
1920
  if (conn.userAgent) {
1774
1921
  headers.set("User-Agent", conn.userAgent);
1775
1922
  }
@@ -2192,7 +2339,7 @@ var OKX_SITES = {
2192
2339
  },
2193
2340
  us: {
2194
2341
  label: "US",
2195
- apiBaseUrl: "https://app.okx.com",
2342
+ apiBaseUrl: "https://us.okx.com",
2196
2343
  webUrl: "https://app.okx.com"
2197
2344
  }
2198
2345
  };
@@ -3722,7 +3869,7 @@ function safeWriteFile(targetDir, fileName, data) {
3722
3869
  throw new Error(`Invalid file name: "${fileName}"`);
3723
3870
  }
3724
3871
  const resolvedDir = resolve(targetDir);
3725
- const filePath = join3(resolvedDir, safeName);
3872
+ const filePath = join4(resolvedDir, safeName);
3726
3873
  const resolvedPath = resolve(filePath);
3727
3874
  if (!resolvedPath.startsWith(resolvedDir + sep)) {
3728
3875
  throw new Error(`Path traversal detected: "${fileName}" resolves outside target directory`);
@@ -3850,7 +3997,7 @@ async function extractSkillZip(zipPath, targetDir, limits) {
3850
3997
  });
3851
3998
  }
3852
3999
  function readMetaJson(contentDir) {
3853
- const metaPath = join4(contentDir, "_meta.json");
4000
+ const metaPath = join5(contentDir, "_meta.json");
3854
4001
  if (!existsSync(metaPath)) {
3855
4002
  throw new Error(`_meta.json not found in ${contentDir}. Invalid skill package.`);
3856
4003
  }
@@ -3876,12 +4023,12 @@ function readMetaJson(contentDir) {
3876
4023
  };
3877
4024
  }
3878
4025
  function validateSkillMdExists(contentDir) {
3879
- const skillMdPath = join4(contentDir, "SKILL.md");
4026
+ const skillMdPath = join5(contentDir, "SKILL.md");
3880
4027
  if (!existsSync(skillMdPath)) {
3881
4028
  throw new Error(`SKILL.md not found in ${contentDir}. Invalid skill package.`);
3882
4029
  }
3883
4030
  }
3884
- var DEFAULT_REGISTRY_PATH = join5(homedir3(), ".okx", "skills", "registry.json");
4031
+ var DEFAULT_REGISTRY_PATH = join6(homedir4(), ".okx", "skills", "registry.json");
3885
4032
  function readRegistry(registryPath = DEFAULT_REGISTRY_PATH) {
3886
4033
  if (!existsSync2(registryPath)) {
3887
4034
  return { version: 1, skills: {} };
@@ -9646,7 +9793,7 @@ function createToolRunner(client, config) {
9646
9793
  };
9647
9794
  }
9648
9795
  function configFilePath() {
9649
- return join6(homedir4(), ".okx", "config.toml");
9796
+ return join7(homedir5(), ".okx", "config.toml");
9650
9797
  }
9651
9798
  function readFullConfig() {
9652
9799
  const path42 = configFilePath();
@@ -9665,11 +9812,6 @@ Or re-run: okx config init`
9665
9812
  );
9666
9813
  }
9667
9814
  }
9668
- function readTomlProfile(profileName) {
9669
- const config = readFullConfig();
9670
- const name = profileName ?? config.default_profile ?? "default";
9671
- return config.profiles?.[name] ?? {};
9672
- }
9673
9815
  var CONFIG_HEADER = `# OKX Trade Kit Configuration
9674
9816
  # If editing manually, wrap values containing special chars in quotes:
9675
9817
  # passphrase = 'value' (if value contains # \\ ")
@@ -9718,18 +9860,24 @@ function parseModuleList(rawModules) {
9718
9860
  }
9719
9861
  return Array.from(deduped);
9720
9862
  }
9721
- function loadCredentials(toml) {
9863
+ async function loadCredentials(toml) {
9722
9864
  const apiKey = process.env.OKX_API_KEY?.trim() ?? toml.api_key;
9723
9865
  const secretKey = process.env.OKX_SECRET_KEY?.trim() ?? toml.secret_key;
9724
9866
  const passphrase = process.env.OKX_PASSPHRASE?.trim() ?? toml.passphrase;
9725
- const hasAuth = Boolean(apiKey && secretKey && passphrase);
9867
+ const hasApiKey = Boolean(apiKey && secretKey && passphrase);
9726
9868
  const partialAuth = Boolean(apiKey) || Boolean(secretKey) || Boolean(passphrase);
9727
- if (partialAuth && !hasAuth) {
9869
+ if (partialAuth && !hasApiKey) {
9728
9870
  throw new ConfigError(
9729
9871
  "Partial API credentials detected.",
9730
9872
  "Set OKX_API_KEY, OKX_SECRET_KEY and OKX_PASSPHRASE together (env vars or config.toml profile)."
9731
9873
  );
9732
9874
  }
9875
+ let hasOAuth = false;
9876
+ if (!hasApiKey) {
9877
+ const status = await execAuthStatus();
9878
+ hasOAuth = status?.status === "logged_in";
9879
+ }
9880
+ const hasAuth = hasOAuth || hasApiKey;
9733
9881
  return { apiKey, secretKey, passphrase, hasAuth };
9734
9882
  }
9735
9883
  function resolveSite(cliSite, tomlSite) {
@@ -9763,9 +9911,11 @@ function resolveDemo(cli, toml) {
9763
9911
  if (cli.demo === true) return true;
9764
9912
  return process.env.OKX_DEMO === "1" || process.env.OKX_DEMO === "true" || (toml.demo ?? false);
9765
9913
  }
9766
- function loadConfig(cli) {
9767
- const toml = readTomlProfile(cli.profile);
9768
- const creds = loadCredentials(toml);
9914
+ async function loadConfig(cli) {
9915
+ const config = readFullConfig();
9916
+ const profileName = cli.profile ?? config.default_profile ?? "default";
9917
+ const toml = config.profiles?.[profileName] ?? {};
9918
+ const creds = await loadCredentials(toml);
9769
9919
  const demo = resolveDemo(cli, toml);
9770
9920
  const site = resolveSite(cli.site, toml.site);
9771
9921
  const baseUrl = resolveBaseUrl(site, toml.base_url);
@@ -9785,6 +9935,7 @@ function loadConfig(cli) {
9785
9935
  }
9786
9936
  return {
9787
9937
  ...creds,
9938
+ profile: profileName,
9788
9939
  baseUrl,
9789
9940
  timeoutMs: Math.floor(rawTimeout),
9790
9941
  modules: parseModuleList(cli.modules),
@@ -9797,7 +9948,7 @@ function loadConfig(cli) {
9797
9948
  verbose: cli.verbose ?? false
9798
9949
  };
9799
9950
  }
9800
- var CACHE_FILE = join7(homedir5(), ".okx", "update-check.json");
9951
+ var CACHE_FILE = join8(homedir6(), ".okx", "update-check.json");
9801
9952
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
9802
9953
  function readCache2() {
9803
9954
  try {
@@ -9810,7 +9961,7 @@ function readCache2() {
9810
9961
  }
9811
9962
  function writeCache2(cache) {
9812
9963
  try {
9813
- mkdirSync6(join7(homedir5(), ".okx"), { recursive: true });
9964
+ mkdirSync6(join8(homedir6(), ".okx"), { recursive: true });
9814
9965
  writeFileSync5(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
9815
9966
  } catch {
9816
9967
  }
@@ -9980,13 +10131,13 @@ function findMsStoreClaudePath() {
9980
10131
  }
9981
10132
  function getConfigPath(client) {
9982
10133
  const home = os3.homedir();
9983
- const platform2 = process.platform;
10134
+ const platform3 = process.platform;
9984
10135
  switch (client) {
9985
10136
  case "claude-desktop":
9986
- if (platform2 === "win32") {
10137
+ if (platform3 === "win32") {
9987
10138
  return findMsStoreClaudePath() ?? path3.join(appData(), "Claude", CLAUDE_CONFIG_FILE);
9988
10139
  }
9989
- if (platform2 === "darwin") {
10140
+ if (platform3 === "darwin") {
9990
10141
  return path3.join(home, "Library", "Application Support", "Claude", CLAUDE_CONFIG_FILE);
9991
10142
  }
9992
10143
  return path3.join(process.env.XDG_CONFIG_HOME ?? path3.join(home, ".config"), "Claude", CLAUDE_CONFIG_FILE);
@@ -10228,7 +10379,7 @@ async function installDohBinary(destPath, sources = CDN_SOURCES, onProgress) {
10228
10379
  if (earlyResult) return earlyResult;
10229
10380
  const platformDir = getPlatformDir();
10230
10381
  const binaryName = getBinaryName();
10231
- const resolvedDest = destPath ?? join9(homedir7(), ".okx", "bin", binaryName);
10382
+ const resolvedDest = destPath ?? join10(homedir8(), ".okx", "bin", binaryName);
10232
10383
  const tmpPath = resolvedDest + ".tmp";
10233
10384
  mkdirSync8(dirname6(resolvedDest), { recursive: true });
10234
10385
  const localHash = existsSync6(resolvedDest) ? hashFile(resolvedDest) : null;
@@ -10351,16 +10502,224 @@ function downloadText(url, timeoutMs) {
10351
10502
  })
10352
10503
  );
10353
10504
  }
10505
+ var AUTH_CDN_PATH_PREFIX = "/upgradeapp/tools/oauth";
10506
+ function getAuthBinaryName() {
10507
+ return platform2() === "win32" ? "okx-auth.exe" : "okx-auth";
10508
+ }
10509
+ function getAuthStatus(binaryPath, opts) {
10510
+ const resolvedPath = binaryPath ?? getAuthBinaryPath();
10511
+ const platformDir = getPlatformDir();
10512
+ if (!existsSync7(resolvedPath)) {
10513
+ return { binaryPath: resolvedPath, exists: false, platform: platformDir };
10514
+ }
10515
+ if (opts?.skipHash) {
10516
+ return { binaryPath: resolvedPath, exists: true, platform: platformDir };
10517
+ }
10518
+ const { size, sha256 } = hashFile(resolvedPath);
10519
+ return { binaryPath: resolvedPath, exists: true, platform: platformDir, fileSize: size, sha256 };
10520
+ }
10521
+ async function fetchAuthCdnChecksum(sources = CDN_SOURCES, timeoutMs = DOWNLOAD_TIMEOUT_MS) {
10522
+ const platformDir = getPlatformDir();
10523
+ if (!platformDir) return null;
10524
+ const checksumPath = `${AUTH_CDN_PATH_PREFIX}/${platformDir}/checksum.json`;
10525
+ for (const { host, protocol } of sources) {
10526
+ try {
10527
+ const url = `${protocol}://${host}${checksumPath}`;
10528
+ const raw = await downloadText2(url, timeoutMs);
10529
+ const data = JSON.parse(raw);
10530
+ if (typeof data.sha256 !== "string" || typeof data.size !== "number" || typeof data.target !== "string") {
10531
+ continue;
10532
+ }
10533
+ return { sha256: data.sha256, size: data.size, target: data.target, source: host };
10534
+ } catch {
10535
+ }
10536
+ }
10537
+ return null;
10538
+ }
10539
+ async function fetchAndValidateChecksum2(host, protocol, checksumPath, platformDir, timeoutMs, onProgress) {
10540
+ const checksumUrl = `${protocol}://${host}${checksumPath}`;
10541
+ onProgress?.(`Fetching checksum from ${host}...`);
10542
+ const raw = await downloadText2(checksumUrl, timeoutMs);
10543
+ const checksum = JSON.parse(raw);
10544
+ if (typeof checksum.sha256 !== "string" || typeof checksum.size !== "number" || typeof checksum.target !== "string") {
10545
+ throw new Error("Invalid checksum.json: missing sha256, size, or target");
10546
+ }
10547
+ if (checksum.target !== platformDir) {
10548
+ throw new Error(`Target mismatch: expected ${platformDir}, got ${checksum.target}`);
10549
+ }
10550
+ return { sha256: checksum.sha256, size: checksum.size, target: checksum.target };
10551
+ }
10552
+ async function downloadAndVerify2(host, protocol, binaryPath, tmpPath, checksum, timeoutMs, onProgress) {
10553
+ const binaryUrl = `${protocol}://${host}${binaryPath}`;
10554
+ onProgress?.(`Downloading binary from ${host}...`);
10555
+ await download2(binaryUrl, tmpPath, timeoutMs);
10556
+ const actual = hashFile(tmpPath);
10557
+ if (actual.size !== checksum.size) {
10558
+ throw new Error(`Size mismatch: expected ${checksum.size}, got ${actual.size}`);
10559
+ }
10560
+ if (actual.sha256 !== checksum.sha256) {
10561
+ throw new Error(`SHA-256 mismatch: expected ${checksum.sha256}, got ${actual.sha256}`);
10562
+ }
10563
+ }
10564
+ function atomicReplace2(tmpPath, resolvedDest) {
10565
+ if (platform2() === "win32") {
10566
+ try {
10567
+ unlinkSync4(resolvedDest);
10568
+ } catch {
10569
+ }
10570
+ }
10571
+ renameSync4(tmpPath, resolvedDest);
10572
+ if (platform2() !== "win32") {
10573
+ chmodSync2(resolvedDest, 493);
10574
+ }
10575
+ }
10576
+ function installPreChecks2(destPath, sources) {
10577
+ if (!destPath && process.env.OKX_AUTH_BIN) {
10578
+ return { status: "up-to-date", source: "(env override)" };
10579
+ }
10580
+ if (!getPlatformDir()) {
10581
+ return { status: "failed", error: "Unsupported platform" };
10582
+ }
10583
+ if (sources.length === 0) {
10584
+ return { status: "failed", error: "No CDN sources available" };
10585
+ }
10586
+ return null;
10587
+ }
10588
+ function isLocalUpToDate2(localHash, checksum) {
10589
+ return localHash !== null && localHash.size === checksum.size && localHash.sha256 === checksum.sha256;
10590
+ }
10591
+ async function installAuthBinary(destPath, sources = CDN_SOURCES, onProgress) {
10592
+ const earlyResult = installPreChecks2(destPath, sources);
10593
+ if (earlyResult) return earlyResult;
10594
+ const platformDir = getPlatformDir();
10595
+ const binaryName = getAuthBinaryName();
10596
+ const resolvedDest = destPath ?? join11(homedir9(), ".okx", "bin", binaryName);
10597
+ const tmpPath = resolvedDest + ".tmp";
10598
+ mkdirSync9(dirname7(resolvedDest), { recursive: true });
10599
+ const localHash = existsSync7(resolvedDest) ? hashFile(resolvedDest) : null;
10600
+ const checksumPath = `${AUTH_CDN_PATH_PREFIX}/${platformDir}/checksum.json`;
10601
+ const binaryPath = `${AUTH_CDN_PATH_PREFIX}/${platformDir}/${binaryName}`;
10602
+ const errors = [];
10603
+ for (const { host, protocol } of sources) {
10604
+ try {
10605
+ const checksum = await fetchAndValidateChecksum2(
10606
+ host,
10607
+ protocol,
10608
+ checksumPath,
10609
+ platformDir,
10610
+ DOWNLOAD_TIMEOUT_MS,
10611
+ onProgress
10612
+ );
10613
+ if (isLocalUpToDate2(localHash, checksum)) {
10614
+ onProgress?.("Already up to date (checksum match)");
10615
+ return { status: "up-to-date", source: host };
10616
+ }
10617
+ await downloadAndVerify2(host, protocol, binaryPath, tmpPath, checksum, DOWNLOAD_TIMEOUT_MS, onProgress);
10618
+ atomicReplace2(tmpPath, resolvedDest);
10619
+ onProgress?.(`Downloaded and verified from ${host}`);
10620
+ return { status: "installed", source: host };
10621
+ } catch (err) {
10622
+ try {
10623
+ unlinkSync4(tmpPath);
10624
+ } catch {
10625
+ }
10626
+ const msg = err instanceof Error ? err.message : String(err);
10627
+ errors.push(`${host}: ${msg}`);
10628
+ onProgress?.(`${host} failed: ${msg}`);
10629
+ }
10630
+ }
10631
+ return { status: "failed", error: `All CDN sources failed:
10632
+ ${errors.join("\n")}` };
10633
+ }
10634
+ function removeAuthBinary(binaryPath) {
10635
+ const resolvedPath = binaryPath ?? getAuthBinaryPath();
10636
+ try {
10637
+ unlinkSync4(resolvedPath);
10638
+ return { status: "removed" };
10639
+ } catch (err) {
10640
+ if (err.code === "ENOENT") {
10641
+ return { status: "not-found" };
10642
+ }
10643
+ const msg = err instanceof Error ? err.message : String(err);
10644
+ throw new Error(`Failed to remove ${resolvedPath}: ${msg}`);
10645
+ }
10646
+ }
10647
+ function isRedirect2(statusCode) {
10648
+ return statusCode !== void 0 && statusCode >= 300 && statusCode < 400;
10649
+ }
10650
+ function validateRedirect2(res, requestUrl, redirectCount, maxRedirects) {
10651
+ if (redirectCount > maxRedirects) {
10652
+ throw new Error(`Too many redirects (${maxRedirects})`);
10653
+ }
10654
+ const location = res.headers.location;
10655
+ if (requestUrl.startsWith("https") && !location.startsWith("https")) {
10656
+ throw new Error("Refused HTTPS \u2192 HTTP redirect downgrade");
10657
+ }
10658
+ return location;
10659
+ }
10660
+ function fetchResponse2(url, timeoutMs) {
10661
+ return new Promise((resolve3, reject) => {
10662
+ let redirects = 0;
10663
+ const maxRedirects = 5;
10664
+ function doRequest(requestUrl) {
10665
+ const reqFn = requestUrl.startsWith("https") ? httpsGet2 : httpGet2;
10666
+ const req = reqFn(requestUrl, { timeout: timeoutMs }, (res) => {
10667
+ if (isRedirect2(res.statusCode) && res.headers.location) {
10668
+ redirects++;
10669
+ try {
10670
+ const location = validateRedirect2(res, requestUrl, redirects, maxRedirects);
10671
+ res.resume();
10672
+ doRequest(location);
10673
+ } catch (err) {
10674
+ reject(err);
10675
+ }
10676
+ return;
10677
+ }
10678
+ if (res.statusCode !== 200) {
10679
+ reject(new Error(`HTTP ${res.statusCode ?? "unknown"}`));
10680
+ return;
10681
+ }
10682
+ resolve3(res);
10683
+ });
10684
+ req.on("error", reject);
10685
+ req.on("timeout", () => {
10686
+ req.destroy();
10687
+ reject(new Error("Download timed out"));
10688
+ });
10689
+ }
10690
+ doRequest(url);
10691
+ });
10692
+ }
10693
+ function download2(url, destPath, timeoutMs) {
10694
+ return fetchResponse2(url, timeoutMs).then(
10695
+ (res) => new Promise((resolve3, reject) => {
10696
+ const file = createWriteStream3(destPath);
10697
+ res.pipe(file);
10698
+ file.on("finish", () => file.close(() => resolve3()));
10699
+ file.on("error", (err) => {
10700
+ try {
10701
+ unlinkSync4(destPath);
10702
+ } catch {
10703
+ }
10704
+ reject(err);
10705
+ });
10706
+ })
10707
+ );
10708
+ }
10709
+ function downloadText2(url, timeoutMs) {
10710
+ return fetchResponse2(url, timeoutMs).then(
10711
+ (res) => new Promise((resolve3, reject) => {
10712
+ const chunks = [];
10713
+ res.on("data", (chunk) => chunks.push(chunk));
10714
+ res.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
10715
+ res.on("error", reject);
10716
+ })
10717
+ );
10718
+ }
10354
10719
 
10355
- // src/commands/diagnose.ts
10356
- import dns from "dns/promises";
10357
- import net from "net";
10358
- import os5 from "os";
10359
- import tls from "tls";
10360
-
10361
- // src/commands/diagnose-utils.ts
10362
- import fs4 from "fs";
10363
- import { createRequire } from "module";
10720
+ // src/commands/auth.ts
10721
+ import { spawn as spawn2 } from "child_process";
10722
+ import readline from "readline";
10364
10723
 
10365
10724
  // src/formatter.ts
10366
10725
  import { EOL } from "os";
@@ -10451,7 +10810,249 @@ function markFailedIfSCodeError(data) {
10451
10810
  }
10452
10811
  }
10453
10812
 
10813
+ // src/commands/auth.ts
10814
+ function runOkxAuth(args) {
10815
+ const binPath = getAuthBinaryPath();
10816
+ return new Promise((resolve3, reject) => {
10817
+ const child = spawn2(binPath, args, {
10818
+ stdio: "inherit"
10819
+ });
10820
+ child.on("error", (err) => {
10821
+ reject(new Error(`Failed to spawn okx-auth: ${err.message}`));
10822
+ });
10823
+ child.on("close", (code) => {
10824
+ resolve3(code ?? 1);
10825
+ });
10826
+ });
10827
+ }
10828
+ function runOkxAuthCapture(args) {
10829
+ const binPath = getAuthBinaryPath();
10830
+ return new Promise((resolve3, reject) => {
10831
+ const child = spawn2(binPath, args, {
10832
+ stdio: ["inherit", "pipe", "inherit"]
10833
+ });
10834
+ const chunks = [];
10835
+ child.stdout.on("data", (chunk) => chunks.push(chunk));
10836
+ child.on("error", (err) => {
10837
+ reject(new Error(`Failed to spawn okx-auth: ${err.message}`));
10838
+ });
10839
+ child.on("close", (code) => {
10840
+ resolve3({
10841
+ code: code ?? 1,
10842
+ stdout: Buffer.concat(chunks).toString("utf-8")
10843
+ });
10844
+ });
10845
+ });
10846
+ }
10847
+ async function cmdAuthLogin(args) {
10848
+ const cliArgs = ["login"];
10849
+ if (args.site) cliArgs.push("--site", args.site);
10850
+ if (args.manual) cliArgs.push("--manual");
10851
+ const code = await runOkxAuth(cliArgs);
10852
+ if (code !== 0) {
10853
+ process.exitCode = code;
10854
+ }
10855
+ }
10856
+ async function cmdAuthLogout() {
10857
+ const code = await runOkxAuth(["logout"]);
10858
+ if (code !== 0) {
10859
+ process.exitCode = code;
10860
+ }
10861
+ }
10862
+ async function cmdAuthStatus(args) {
10863
+ const cliArgs = ["status"];
10864
+ if (args.json) cliArgs.push("--json");
10865
+ const result = await runOkxAuthCapture(cliArgs);
10866
+ if (result.stdout) {
10867
+ process.stdout.write(result.stdout);
10868
+ }
10869
+ if (result.code !== 0) {
10870
+ process.exitCode = result.code;
10871
+ }
10872
+ }
10873
+ function resolveChecksumMatch(local, cdnChecksum, cdnError) {
10874
+ if (!local.exists) return "not-installed";
10875
+ if (cdnError || !cdnChecksum) return "unavailable";
10876
+ if (cdnChecksum.sha256 === local.sha256) return "match";
10877
+ return "mismatch";
10878
+ }
10879
+ function checksumMatchLabel(match) {
10880
+ if (match === "match") return "\u2713 match";
10881
+ if (match === "mismatch") return "\u2717 mismatch (update available)";
10882
+ return "CDN unreachable";
10883
+ }
10884
+ function formatBytes(bytes) {
10885
+ if (bytes < 1024) return `${bytes} B`;
10886
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
10887
+ return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
10888
+ }
10889
+ async function cmdAuthInstallStatus(json) {
10890
+ const local = getAuthStatus();
10891
+ let cdnChecksum = null;
10892
+ let cdnError = null;
10893
+ if (local.exists) {
10894
+ try {
10895
+ cdnChecksum = await fetchAuthCdnChecksum(void 0, 5e3);
10896
+ } catch (err) {
10897
+ cdnError = err instanceof Error ? err.message : String(err);
10898
+ }
10899
+ }
10900
+ const checksumMatch = resolveChecksumMatch(local, cdnChecksum, cdnError);
10901
+ if (json) {
10902
+ outputLine(
10903
+ JSON.stringify({
10904
+ binaryPath: local.binaryPath,
10905
+ exists: local.exists,
10906
+ platform: local.platform,
10907
+ fileSize: local.fileSize ?? null,
10908
+ sha256: local.sha256 ?? null,
10909
+ cdnMatch: checksumMatch,
10910
+ cdnSha256: cdnChecksum?.sha256 ?? null,
10911
+ cdnSource: cdnChecksum?.source ?? null
10912
+ })
10913
+ );
10914
+ return;
10915
+ }
10916
+ outputLine("");
10917
+ outputLine(" okx-auth Binary Status");
10918
+ outputLine(" " + "\u2500".repeat(40));
10919
+ outputLine(` Binary path : ${local.binaryPath}`);
10920
+ outputLine(` Installed : ${local.exists ? "yes" : "no"}`);
10921
+ outputLine(` Platform : ${local.platform ?? "(unsupported)"}`);
10922
+ if (local.exists) {
10923
+ outputLine(` File size : ${formatBytes(local.fileSize)}`);
10924
+ outputLine(` SHA-256 : ${local.sha256 ?? "(unknown)"}`);
10925
+ outputLine(` CDN check : ${checksumMatchLabel(checksumMatch)}`);
10926
+ if (cdnChecksum) {
10927
+ outputLine(` CDN source : ${cdnChecksum.source}`);
10928
+ }
10929
+ }
10930
+ outputLine("");
10931
+ }
10932
+ async function cmdAuthInstall(json) {
10933
+ const messages2 = [];
10934
+ const onProgress = (msg) => {
10935
+ if (!json) {
10936
+ outputLine(` ${msg}`);
10937
+ }
10938
+ messages2.push(msg);
10939
+ };
10940
+ if (!json) {
10941
+ outputLine("");
10942
+ outputLine(" Installing okx-auth...");
10943
+ }
10944
+ const result = await installAuthBinary(void 0, void 0, onProgress);
10945
+ if (json) {
10946
+ outputLine(JSON.stringify({ status: result.status, source: result.source ?? null, error: result.error ?? null, messages: messages2 }));
10947
+ if (result.status === "failed") {
10948
+ process.exitCode = 1;
10949
+ }
10950
+ return;
10951
+ }
10952
+ if (result.status === "installed") {
10953
+ outputLine(` \u2713 okx-auth installed successfully (${result.source ?? ""})`);
10954
+ } else if (result.status === "up-to-date") {
10955
+ outputLine(" \u2713 okx-auth is already up to date");
10956
+ } else {
10957
+ errorLine(` \u2717 Installation failed: ${result.error ?? "unknown error"}`);
10958
+ errorLine(" Hint: check network connectivity or try again later");
10959
+ process.exitCode = 1;
10960
+ }
10961
+ outputLine("");
10962
+ }
10963
+ async function cmdAuthRemove(force, json) {
10964
+ const local = getAuthStatus(void 0, { skipHash: true });
10965
+ if (!local.exists) {
10966
+ if (json) {
10967
+ outputLine(JSON.stringify({ status: "not-installed" }));
10968
+ } else {
10969
+ outputLine(" okx-auth is not installed.");
10970
+ }
10971
+ return;
10972
+ }
10973
+ if (!force) {
10974
+ if (!process.stdin.isTTY) {
10975
+ errorLine(" Error: stdin is not a TTY. Use --force to skip confirmation.");
10976
+ process.exitCode = 1;
10977
+ return;
10978
+ }
10979
+ const confirmed = await askConfirmation(
10980
+ ` Remove okx-auth at ${local.binaryPath}? [y/N] `
10981
+ );
10982
+ if (!confirmed) {
10983
+ outputLine(" Cancelled.");
10984
+ return;
10985
+ }
10986
+ }
10987
+ let result;
10988
+ try {
10989
+ result = removeAuthBinary();
10990
+ } catch (err) {
10991
+ const msg = err instanceof Error ? err.message : String(err);
10992
+ if (json) {
10993
+ outputLine(JSON.stringify({ status: "failed", error: msg }));
10994
+ } else {
10995
+ errorLine(` \u2717 Failed to remove: ${msg}`);
10996
+ }
10997
+ process.exitCode = 1;
10998
+ return;
10999
+ }
11000
+ if (json) {
11001
+ outputLine(JSON.stringify({ status: result.status, path: local.binaryPath }));
11002
+ return;
11003
+ }
11004
+ if (result.status === "removed") {
11005
+ outputLine(` \u2713 Removed: ${local.binaryPath}`);
11006
+ } else {
11007
+ outputLine(" okx-auth is not installed.");
11008
+ }
11009
+ }
11010
+ function askConfirmation(prompt2) {
11011
+ return new Promise((resolve3) => {
11012
+ const rl = readline.createInterface({
11013
+ input: process.stdin,
11014
+ output: process.stdout
11015
+ });
11016
+ rl.question(prompt2, (answer) => {
11017
+ rl.close();
11018
+ resolve3(answer.trim().toLowerCase() === "y");
11019
+ });
11020
+ });
11021
+ }
11022
+ function handleAuthCommand(action, _rest, v) {
11023
+ const site = v.site;
11024
+ const json = v.json;
11025
+ const manual = v.manual;
11026
+ const force = v.force;
11027
+ switch (action) {
11028
+ case "login":
11029
+ return cmdAuthLogin({ site, manual });
11030
+ case "logout":
11031
+ return cmdAuthLogout();
11032
+ case "status":
11033
+ return cmdAuthStatus({ json });
11034
+ case "install":
11035
+ return cmdAuthInstall(json ?? false);
11036
+ case "install-status":
11037
+ return cmdAuthInstallStatus(json ?? false);
11038
+ case "remove":
11039
+ return cmdAuthRemove(force ?? false, json ?? false);
11040
+ default:
11041
+ errorLine(`Unknown auth command: ${action}`);
11042
+ errorLine("Available: login, logout, status, install, install-status, remove");
11043
+ process.exitCode = 1;
11044
+ }
11045
+ }
11046
+
11047
+ // src/commands/diagnose.ts
11048
+ import dns from "dns/promises";
11049
+ import net from "net";
11050
+ import os5 from "os";
11051
+ import tls from "tls";
11052
+
10454
11053
  // src/commands/diagnose-utils.ts
11054
+ import fs4 from "fs";
11055
+ import { createRequire } from "module";
10455
11056
  var _require = createRequire(import.meta.url);
10456
11057
  function readCliVersion() {
10457
11058
  for (const rel of ["../package.json", "../../package.json"]) {
@@ -10537,7 +11138,7 @@ function sanitize2(value) {
10537
11138
  import fs5 from "fs";
10538
11139
  import path4 from "path";
10539
11140
  import os4 from "os";
10540
- import { spawnSync, spawn } from "child_process";
11141
+ import { spawnSync, spawn as spawn3 } from "child_process";
10541
11142
  import { createRequire as createRequire2 } from "module";
10542
11143
  import { fileURLToPath } from "url";
10543
11144
  var _require2 = createRequire2(import.meta.url);
@@ -10871,7 +11472,7 @@ async function checkStdioHandshake(entryPath, report) {
10871
11472
  clearTimeout(timer);
10872
11473
  resolve3(passed);
10873
11474
  };
10874
- const child = spawn(process.execPath, [entryPath], {
11475
+ const child = spawn3(process.execPath, [entryPath], {
10875
11476
  stdio: ["pipe", "pipe", "pipe"],
10876
11477
  env: { ...process.env }
10877
11478
  });
@@ -10990,7 +11591,7 @@ async function cmdDiagnoseMcp(options = {}) {
10990
11591
 
10991
11592
  // src/commands/diagnose.ts
10992
11593
  var CLI_VERSION = readCliVersion();
10993
- var GIT_HASH = true ? "7458dd1" : "dev";
11594
+ var GIT_HASH = true ? "1431fd4" : "dev";
10994
11595
  function maskKey2(key) {
10995
11596
  if (!key) return "(not set)";
10996
11597
  if (key.length <= 8) return "****";
@@ -11326,13 +11927,13 @@ async function runCliChecks(config, profile, outputPath) {
11326
11927
 
11327
11928
  // src/commands/upgrade.ts
11328
11929
  import { spawnSync as spawnSync2 } from "child_process";
11329
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync9 } from "fs";
11330
- import { dirname as dirname7, join as join10 } from "path";
11331
- import { homedir as homedir8 } from "os";
11930
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync10 } from "fs";
11931
+ import { dirname as dirname8, join as join12 } from "path";
11932
+ import { homedir as homedir10 } from "os";
11332
11933
  var PACKAGES = ["@okx_ai/okx-trade-mcp", "@okx_ai/okx-trade-cli"];
11333
- var CACHE_FILE2 = join10(homedir8(), ".okx", "last_check");
11934
+ var CACHE_FILE2 = join12(homedir10(), ".okx", "last_check");
11334
11935
  var THROTTLE_MS = 12 * 60 * 60 * 1e3;
11335
- var NPM_BIN = join10(dirname7(process.execPath), process.platform === "win32" ? "npm.cmd" : "npm");
11936
+ var NPM_BIN = join12(dirname8(process.execPath), process.platform === "win32" ? "npm.cmd" : "npm");
11336
11937
  function readLastCheck() {
11337
11938
  try {
11338
11939
  return parseInt(readFileSync8(CACHE_FILE2, "utf-8").trim(), 10) || 0;
@@ -11342,7 +11943,7 @@ function readLastCheck() {
11342
11943
  }
11343
11944
  function writeLastCheck() {
11344
11945
  try {
11345
- mkdirSync9(join10(homedir8(), ".okx"), { recursive: true });
11946
+ mkdirSync10(join12(homedir10(), ".okx"), { recursive: true });
11346
11947
  writeFileSync7(CACHE_FILE2, String(Math.floor(Date.now() / 1e3)), "utf-8");
11347
11948
  } catch {
11348
11949
  }
@@ -12763,7 +13364,7 @@ async function cmdNewsSentimentRank(run, opts) {
12763
13364
  }
12764
13365
 
12765
13366
  // src/config/loader.ts
12766
- function loadProfileConfig(opts) {
13367
+ async function loadProfileConfig(opts) {
12767
13368
  return loadConfig({
12768
13369
  profile: opts.profile,
12769
13370
  modules: opts.modules,
@@ -13081,6 +13682,9 @@ var CLI_OPTIONS = {
13081
13682
  dir: { type: "string" },
13082
13683
  page: { type: "string" },
13083
13684
  format: { type: "string" },
13685
+ // auth
13686
+ site: { type: "string" },
13687
+ manual: { type: "boolean", default: false },
13084
13688
  // event contract
13085
13689
  underlying: { type: "string" },
13086
13690
  seriesId: { type: "string" },
@@ -16095,14 +16699,14 @@ async function cmdDcdQuoteAndBuy(run, opts) {
16095
16699
  }
16096
16700
 
16097
16701
  // src/commands/skill.ts
16098
- import { tmpdir, homedir as homedir10 } from "os";
16099
- import { join as join12, dirname as dirname8 } from "path";
16100
- import { mkdirSync as mkdirSync10, rmSync, existsSync as existsSync8, copyFileSync as copyFileSync2 } from "fs";
16702
+ import { tmpdir, homedir as homedir12 } from "os";
16703
+ import { join as join14, dirname as dirname9 } from "path";
16704
+ import { mkdirSync as mkdirSync11, rmSync, existsSync as existsSync9, copyFileSync as copyFileSync2 } from "fs";
16101
16705
  import { execFileSync as execFileSync2 } from "child_process";
16102
16706
  import { randomUUID as randomUUID2 } from "crypto";
16103
16707
  function resolveNpx() {
16104
- const sibling = join12(dirname8(process.execPath), "npx");
16105
- if (existsSync8(sibling)) return sibling;
16708
+ const sibling = join14(dirname9(process.execPath), "npx");
16709
+ if (existsSync9(sibling)) return sibling;
16106
16710
  return "npx";
16107
16711
  }
16108
16712
  var THIRD_PARTY_INSTALL_NOTICE = "Note: This skill was created by a third-party developer, not by OKX. Review SKILL.md before use.";
@@ -16155,13 +16759,13 @@ async function cmdSkillCategories(run, json) {
16155
16759
  outputLine("");
16156
16760
  }
16157
16761
  async function cmdSkillAdd(name, config, json) {
16158
- const tmpBase = join12(tmpdir(), `okx-skill-${randomUUID2()}`);
16159
- mkdirSync10(tmpBase, { recursive: true });
16762
+ const tmpBase = join14(tmpdir(), `okx-skill-${randomUUID2()}`);
16763
+ mkdirSync11(tmpBase, { recursive: true });
16160
16764
  try {
16161
16765
  outputLine(`Downloading ${name}...`);
16162
16766
  const client = new OkxRestClient(config);
16163
16767
  const zipPath = await downloadSkillZip(client, name, tmpBase);
16164
- const contentDir = await extractSkillZip(zipPath, join12(tmpBase, "content"));
16768
+ const contentDir = await extractSkillZip(zipPath, join14(tmpBase, "content"));
16165
16769
  const meta = readMetaJson(contentDir);
16166
16770
  validateSkillMdExists(contentDir);
16167
16771
  outputLine("Installing to detected agents...");
@@ -16171,7 +16775,7 @@ async function cmdSkillAdd(name, config, json) {
16171
16775
  timeout: 6e4
16172
16776
  });
16173
16777
  } catch (e) {
16174
- const savedZip = join12(process.cwd(), `${name}.zip`);
16778
+ const savedZip = join14(process.cwd(), `${name}.zip`);
16175
16779
  try {
16176
16780
  copyFileSync2(zipPath, savedZip);
16177
16781
  } catch {
@@ -16210,7 +16814,7 @@ function cmdSkillRemove(name, json) {
16210
16814
  timeout: 6e4
16211
16815
  });
16212
16816
  } catch {
16213
- const agentsPath = join12(homedir10(), ".agents", "skills", name);
16817
+ const agentsPath = join14(homedir12(), ".agents", "skills", name);
16214
16818
  try {
16215
16819
  rmSync(agentsPath, { recursive: true, force: true });
16216
16820
  } catch {
@@ -16284,14 +16888,14 @@ function printSkillInstallResult(meta, json) {
16284
16888
  }
16285
16889
 
16286
16890
  // src/commands/doh.ts
16287
- import readline from "readline";
16288
- function resolveChecksumMatch(local, cdnChecksum, cdnError) {
16891
+ import readline2 from "readline";
16892
+ function resolveChecksumMatch2(local, cdnChecksum, cdnError) {
16289
16893
  if (!local.exists) return "not-installed";
16290
16894
  if (cdnError || !cdnChecksum) return "unavailable";
16291
16895
  if (cdnChecksum.sha256 === local.sha256) return "match";
16292
16896
  return "mismatch";
16293
16897
  }
16294
- function checksumMatchLabel(match) {
16898
+ function checksumMatchLabel2(match) {
16295
16899
  if (match === "match") return "\u2713 match";
16296
16900
  if (match === "mismatch") return "\u2717 mismatch (update available)";
16297
16901
  return "CDN unreachable";
@@ -16304,9 +16908,9 @@ function formatStatusText(local, checksumMatch, cdnChecksum, runtimeMode) {
16304
16908
  outputLine(` Installed : ${local.exists ? "yes" : "no"}`);
16305
16909
  outputLine(` Platform : ${local.platform ?? "(unsupported)"}`);
16306
16910
  if (local.exists) {
16307
- outputLine(` File size : ${formatBytes(local.fileSize)}`);
16911
+ outputLine(` File size : ${formatBytes2(local.fileSize)}`);
16308
16912
  outputLine(` SHA-256 : ${local.sha256 ?? "(unknown)"}`);
16309
- outputLine(` CDN check : ${checksumMatchLabel(checksumMatch)}`);
16913
+ outputLine(` CDN check : ${checksumMatchLabel2(checksumMatch)}`);
16310
16914
  if (cdnChecksum) {
16311
16915
  outputLine(` CDN source : ${cdnChecksum.source}`);
16312
16916
  }
@@ -16333,7 +16937,7 @@ async function cmdDohStatus(json, binaryPath) {
16333
16937
  cdnError = err instanceof Error ? err.message : String(err);
16334
16938
  }
16335
16939
  }
16336
- const checksumMatch = resolveChecksumMatch(local, cdnChecksum, cdnError);
16940
+ const checksumMatch = resolveChecksumMatch2(local, cdnChecksum, cdnError);
16337
16941
  if (json) {
16338
16942
  outputLine(
16339
16943
  JSON.stringify({
@@ -16399,7 +17003,7 @@ async function cmdDohRemove(force, json, binaryPath) {
16399
17003
  process.exitCode = 1;
16400
17004
  return;
16401
17005
  }
16402
- const confirmed = await askConfirmation(
17006
+ const confirmed = await askConfirmation2(
16403
17007
  ` Remove DoH resolver at ${local.binaryPath}? [y/N] `
16404
17008
  );
16405
17009
  if (!confirmed) {
@@ -16418,14 +17022,14 @@ async function cmdDohRemove(force, json, binaryPath) {
16418
17022
  outputLine(" DoH resolver is not installed.");
16419
17023
  }
16420
17024
  }
16421
- function formatBytes(bytes) {
17025
+ function formatBytes2(bytes) {
16422
17026
  if (bytes < 1024) return `${bytes} B`;
16423
17027
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
16424
17028
  return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
16425
17029
  }
16426
- function askConfirmation(prompt2) {
17030
+ function askConfirmation2(prompt2) {
16427
17031
  return new Promise((resolve3) => {
16428
- const rl = readline.createInterface({
17032
+ const rl = readline2.createInterface({
16429
17033
  input: process.stdin,
16430
17034
  output: process.stdout
16431
17035
  });
@@ -16882,7 +17486,7 @@ async function cmdEventCancel(run, opts) {
16882
17486
  // src/index.ts
16883
17487
  var _require3 = createRequire3(import.meta.url);
16884
17488
  var CLI_VERSION2 = _require3("../package.json").version;
16885
- var GIT_HASH2 = true ? "7458dd1" : "dev";
17489
+ var GIT_HASH2 = true ? "1431fd4" : "dev";
16886
17490
  function handleDohCommand(action, json, force, binaryPath) {
16887
17491
  if (action === "status") return cmdDohStatus(json, binaryPath);
16888
17492
  if (action === "install") return cmdDohInstall(json, binaryPath);
@@ -17857,7 +18461,7 @@ function wrapRunnerWithLogger(baseRunner, logger, verbose = false) {
17857
18461
  async function runDiagnose(v) {
17858
18462
  let config;
17859
18463
  try {
17860
- config = loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
18464
+ config = await loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
17861
18465
  } catch {
17862
18466
  }
17863
18467
  return cmdDiagnose(config, v.profile ?? "default", { mcp: v.mcp, cli: v.cli, all: v.all, output: v.output });
@@ -17874,6 +18478,7 @@ function printVersion() {
17874
18478
  function routeManagementCommand(module, action, rest, json, v) {
17875
18479
  if (module === "config") return handleConfigCommand(action, rest, json, v.lang, v.force);
17876
18480
  if (module === "setup") return handleSetupCommand(v);
18481
+ if (module === "auth") return handleAuthCommand(action, rest, v);
17877
18482
  if (module === "upgrade") return cmdUpgrade(CLI_VERSION2, { beta: v.beta, check: v.check, force: v.force }, json);
17878
18483
  if (module === "doh") return handleDohCommand(action, json, v.force ?? false);
17879
18484
  if (module === "diagnose") return runDiagnose(v);
@@ -17900,7 +18505,7 @@ async function main() {
17900
18505
  const json = v.json ?? false;
17901
18506
  const mgmt = routeManagementCommand(module, action, rest, json, v);
17902
18507
  if (mgmt) return mgmt;
17903
- const config = loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
18508
+ const config = await loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
17904
18509
  setEnvContext({ demo: config.demo, profile: v.profile ?? "default" });
17905
18510
  setJsonEnvEnabled(v.env ?? false);
17906
18511
  const client = new OkxRestClient(config);