@okx_ai/okx-trade-cli 1.3.1-beta.11 → 1.3.1-beta.13
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 +802 -138
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/scripts/postinstall.js +78 -1
- package/LICENSE +0 -21
- package/scripts/postinstall-download.js +0 -152
package/dist/index.js
CHANGED
|
@@ -21,25 +21,28 @@ 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
|
|
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
|
|
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
|
|
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
|
-
// ../../node_modules
|
|
45
|
+
// ../../node_modules/smol-toml/dist/error.js
|
|
43
46
|
function getLineColFromPtr(string, ptr) {
|
|
44
47
|
let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
|
|
45
48
|
return [lines.length, lines.pop().length + 1];
|
|
@@ -79,7 +82,7 @@ ${codeblock}`, options);
|
|
|
79
82
|
}
|
|
80
83
|
};
|
|
81
84
|
|
|
82
|
-
// ../../node_modules
|
|
85
|
+
// ../../node_modules/smol-toml/dist/util.js
|
|
83
86
|
function isEscaped(str, ptr) {
|
|
84
87
|
let i = 0;
|
|
85
88
|
while (str[ptr - ++i] === "\\")
|
|
@@ -110,9 +113,14 @@ function skipComment(str, ptr) {
|
|
|
110
113
|
}
|
|
111
114
|
function skipVoid(str, ptr, banNewLines, banComments) {
|
|
112
115
|
let c;
|
|
113
|
-
while (
|
|
114
|
-
ptr
|
|
115
|
-
|
|
116
|
+
while (1) {
|
|
117
|
+
while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n"))
|
|
118
|
+
ptr++;
|
|
119
|
+
if (banComments || c !== "#")
|
|
120
|
+
break;
|
|
121
|
+
ptr = skipComment(str, ptr);
|
|
122
|
+
}
|
|
123
|
+
return ptr;
|
|
116
124
|
}
|
|
117
125
|
function skipUntil(str, ptr, sep2, end, banNewLines = false) {
|
|
118
126
|
if (!end) {
|
|
@@ -153,7 +161,7 @@ function getStringEnd(str, seek) {
|
|
|
153
161
|
return seek;
|
|
154
162
|
}
|
|
155
163
|
|
|
156
|
-
// ../../node_modules
|
|
164
|
+
// ../../node_modules/smol-toml/dist/date.js
|
|
157
165
|
var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
|
|
158
166
|
var TomlDate = class _TomlDate extends Date {
|
|
159
167
|
#hasDate = false;
|
|
@@ -245,7 +253,7 @@ var TomlDate = class _TomlDate extends Date {
|
|
|
245
253
|
}
|
|
246
254
|
};
|
|
247
255
|
|
|
248
|
-
// ../../node_modules
|
|
256
|
+
// ../../node_modules/smol-toml/dist/primitive.js
|
|
249
257
|
var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
|
|
250
258
|
var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
|
|
251
259
|
var LEADING_ZERO = /^[+-]?0[0-9_]/;
|
|
@@ -384,7 +392,7 @@ function parseValue(value, toml, ptr, integersAsBigInt) {
|
|
|
384
392
|
return date;
|
|
385
393
|
}
|
|
386
394
|
|
|
387
|
-
// ../../node_modules
|
|
395
|
+
// ../../node_modules/smol-toml/dist/extract.js
|
|
388
396
|
function sliceAndTrimEndOf(str, startPtr, endPtr) {
|
|
389
397
|
let value = str.slice(startPtr, endPtr);
|
|
390
398
|
let commentIdx = value.indexOf("#");
|
|
@@ -451,7 +459,7 @@ function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
|
|
451
459
|
];
|
|
452
460
|
}
|
|
453
461
|
|
|
454
|
-
// ../../node_modules
|
|
462
|
+
// ../../node_modules/smol-toml/dist/struct.js
|
|
455
463
|
var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
|
|
456
464
|
function parseKey(str, ptr, end = "=") {
|
|
457
465
|
let dot = ptr - 1;
|
|
@@ -599,7 +607,7 @@ function parseArray(str, ptr, depth, integersAsBigInt) {
|
|
|
599
607
|
return [res, ptr];
|
|
600
608
|
}
|
|
601
609
|
|
|
602
|
-
// ../../node_modules
|
|
610
|
+
// ../../node_modules/smol-toml/dist/parse.js
|
|
603
611
|
function peekTable(key, table, meta, type) {
|
|
604
612
|
let t = table;
|
|
605
613
|
let m = meta;
|
|
@@ -724,7 +732,7 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
|
724
732
|
return res;
|
|
725
733
|
}
|
|
726
734
|
|
|
727
|
-
// ../../node_modules
|
|
735
|
+
// ../../node_modules/smol-toml/dist/stringify.js
|
|
728
736
|
var BARE_KEY = /^[a-z0-9-_]+$/i;
|
|
729
737
|
function extendedTypeOf(obj) {
|
|
730
738
|
let type = typeof obj;
|
|
@@ -867,8 +875,8 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
|
867
875
|
|
|
868
876
|
// ../core/dist/index.js
|
|
869
877
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync4 } from "fs";
|
|
870
|
-
import { join as
|
|
871
|
-
import { homedir as
|
|
878
|
+
import { join as join8 } from "path";
|
|
879
|
+
import { homedir as homedir6 } from "os";
|
|
872
880
|
import fs2 from "fs";
|
|
873
881
|
import path2 from "path";
|
|
874
882
|
import os2 from "os";
|
|
@@ -876,6 +884,18 @@ import * as fs3 from "fs";
|
|
|
876
884
|
import * as path3 from "path";
|
|
877
885
|
import * as os3 from "os";
|
|
878
886
|
import { execFileSync } from "child_process";
|
|
887
|
+
import {
|
|
888
|
+
createWriteStream as createWriteStream3,
|
|
889
|
+
mkdirSync as mkdirSync9,
|
|
890
|
+
chmodSync as chmodSync2,
|
|
891
|
+
existsSync as existsSync7,
|
|
892
|
+
unlinkSync as unlinkSync4,
|
|
893
|
+
renameSync as renameSync4
|
|
894
|
+
} from "fs";
|
|
895
|
+
import { homedir as homedir9, platform as platform2 } from "os";
|
|
896
|
+
import { join as join11, dirname as dirname7 } from "path";
|
|
897
|
+
import { get as httpsGet2 } from "https";
|
|
898
|
+
import { get as httpGet2 } from "http";
|
|
879
899
|
import {
|
|
880
900
|
readFileSync as readFileSync7,
|
|
881
901
|
createWriteStream as createWriteStream2,
|
|
@@ -886,10 +906,13 @@ import {
|
|
|
886
906
|
renameSync as renameSync3
|
|
887
907
|
} from "fs";
|
|
888
908
|
import { createHash } from "crypto";
|
|
889
|
-
import { homedir as
|
|
890
|
-
import { join as
|
|
909
|
+
import { homedir as homedir8, platform, arch } from "os";
|
|
910
|
+
import { join as join10, dirname as dirname6 } from "path";
|
|
891
911
|
import { get as httpsGet } from "https";
|
|
892
912
|
import { get as httpGet } from "http";
|
|
913
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync10, unlinkSync as unlinkSync5, existsSync as existsSync8 } from "fs";
|
|
914
|
+
import { join as join12 } from "path";
|
|
915
|
+
import { homedir as homedir10 } from "os";
|
|
893
916
|
var EXEC_TIMEOUT_MS = 3e4;
|
|
894
917
|
var ALLOWED_DOMAIN_RE = /^[\w.-]+\.okx\.com$/;
|
|
895
918
|
var DOH_BIN_DIR = join(homedir(), ".okx", "bin");
|
|
@@ -898,7 +921,7 @@ function getDohBinaryPath() {
|
|
|
898
921
|
return process.env.OKX_DOH_BINARY_PATH;
|
|
899
922
|
}
|
|
900
923
|
const ext = process.platform === "win32" ? ".exe" : "";
|
|
901
|
-
return join(DOH_BIN_DIR, `okx-
|
|
924
|
+
return join(DOH_BIN_DIR, `okx-doh-resolver${ext}`);
|
|
902
925
|
}
|
|
903
926
|
function execDohBinary(domain, exclude = [], userAgent) {
|
|
904
927
|
if (!ALLOWED_DOMAIN_RE.test(domain)) {
|
|
@@ -969,7 +992,7 @@ function classifyAndCache(node, hostname, failedNodes, cachePath) {
|
|
|
969
992
|
if (!node) {
|
|
970
993
|
return { mode: null, node: null };
|
|
971
994
|
}
|
|
972
|
-
if (node.ip === hostname
|
|
995
|
+
if (node.ip === hostname || node.host === hostname) {
|
|
973
996
|
writeCache(hostname, {
|
|
974
997
|
mode: "direct",
|
|
975
998
|
node: null,
|
|
@@ -1201,6 +1224,11 @@ var ConfigError = class extends OkxMcpError {
|
|
|
1201
1224
|
super("ConfigError", message, { suggestion });
|
|
1202
1225
|
}
|
|
1203
1226
|
};
|
|
1227
|
+
var NotLoggedInError = class extends ConfigError {
|
|
1228
|
+
constructor(suggestion = "Run `okx auth login` to authenticate.") {
|
|
1229
|
+
super("Not logged in.", suggestion);
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1204
1232
|
var ValidationError = class extends OkxMcpError {
|
|
1205
1233
|
constructor(message, suggestion) {
|
|
1206
1234
|
super("ValidationError", message, { suggestion });
|
|
@@ -1253,6 +1281,97 @@ function toToolErrorPayload(error, fallbackEndpoint) {
|
|
|
1253
1281
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1254
1282
|
};
|
|
1255
1283
|
}
|
|
1284
|
+
var EXIT_CODES = {
|
|
1285
|
+
SUCCESS: 0,
|
|
1286
|
+
UNAUTHORIZED_CALLER: 1,
|
|
1287
|
+
NOT_LOGGED_IN: 2,
|
|
1288
|
+
REFRESH_FAILED: 3
|
|
1289
|
+
};
|
|
1290
|
+
var EXEC_TIMEOUT_MS2 = 5e3;
|
|
1291
|
+
var AUTH_BIN_DIR = join3(homedir3(), ".okx", "bin");
|
|
1292
|
+
function getAuthBinaryPath() {
|
|
1293
|
+
if (process.env.OKX_AUTH_BIN) {
|
|
1294
|
+
return process.env.OKX_AUTH_BIN;
|
|
1295
|
+
}
|
|
1296
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
1297
|
+
return join3(AUTH_BIN_DIR, `okx-auth${ext}`);
|
|
1298
|
+
}
|
|
1299
|
+
function execAuthToken() {
|
|
1300
|
+
const binPath = getAuthBinaryPath();
|
|
1301
|
+
return new Promise((resolve3, reject) => {
|
|
1302
|
+
const child = spawn(binPath, ["token"], {
|
|
1303
|
+
stdio: ["ignore", "ignore", "inherit", "pipe"]
|
|
1304
|
+
// stdin stdout stderr fd3 (pipe)
|
|
1305
|
+
});
|
|
1306
|
+
const chunks = [];
|
|
1307
|
+
const fd3 = child.stdio[3];
|
|
1308
|
+
fd3.on("data", (chunk) => chunks.push(chunk));
|
|
1309
|
+
child.on("error", (err) => {
|
|
1310
|
+
reject(new ConfigError(
|
|
1311
|
+
`Failed to spawn okx-auth: ${err.message}`,
|
|
1312
|
+
"Ensure the okx-auth binary exists and is executable."
|
|
1313
|
+
));
|
|
1314
|
+
});
|
|
1315
|
+
child.on("close", (code) => {
|
|
1316
|
+
if (code === EXIT_CODES.SUCCESS) {
|
|
1317
|
+
const token = Buffer.concat(chunks).toString("utf-8").trim();
|
|
1318
|
+
if (!token) {
|
|
1319
|
+
reject(new AuthenticationError(
|
|
1320
|
+
"okx-auth returned empty token.",
|
|
1321
|
+
"Run `okx auth login` to re-authenticate."
|
|
1322
|
+
));
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
resolve3(token);
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1328
|
+
if (code === EXIT_CODES.NOT_LOGGED_IN) {
|
|
1329
|
+
reject(new NotLoggedInError());
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
if (code === EXIT_CODES.UNAUTHORIZED_CALLER) {
|
|
1333
|
+
reject(new AuthenticationError(
|
|
1334
|
+
"okx-auth rejected the caller (unauthorized).",
|
|
1335
|
+
"Ensure you are running from a trusted OKX tool."
|
|
1336
|
+
));
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1339
|
+
if (code === EXIT_CODES.REFRESH_FAILED) {
|
|
1340
|
+
reject(new AuthenticationError(
|
|
1341
|
+
"Token refresh failed.",
|
|
1342
|
+
"Run `okx auth login` to re-authenticate."
|
|
1343
|
+
));
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
reject(new AuthenticationError(
|
|
1347
|
+
`okx-auth token exited with code ${code}.`,
|
|
1348
|
+
"Run `okx auth login` to re-authenticate."
|
|
1349
|
+
));
|
|
1350
|
+
});
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
function execAuthStatus() {
|
|
1354
|
+
const binPath = getAuthBinaryPath();
|
|
1355
|
+
return new Promise((resolve3) => {
|
|
1356
|
+
execFile2(
|
|
1357
|
+
binPath,
|
|
1358
|
+
["status", "--json"],
|
|
1359
|
+
{ timeout: EXEC_TIMEOUT_MS2, encoding: "utf-8" },
|
|
1360
|
+
(error, stdout) => {
|
|
1361
|
+
if (error) {
|
|
1362
|
+
resolve3(null);
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
try {
|
|
1366
|
+
const result = JSON.parse(stdout);
|
|
1367
|
+
resolve3(result);
|
|
1368
|
+
} catch {
|
|
1369
|
+
resolve3(null);
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
);
|
|
1373
|
+
});
|
|
1374
|
+
}
|
|
1256
1375
|
function sleep(ms) {
|
|
1257
1376
|
return new Promise((resolve3) => {
|
|
1258
1377
|
setTimeout(resolve3, ms);
|
|
@@ -1331,10 +1450,10 @@ var OKX_CODE_BEHAVIORS = {
|
|
|
1331
1450
|
"50011": { retry: true, suggestion: "Rate limited. Back off and retry after a delay." },
|
|
1332
1451
|
"50061": { retry: true, suggestion: "Too many connections. Reduce request frequency and retry." },
|
|
1333
1452
|
// Server temporarily unavailable → retryable
|
|
1334
|
-
"50001": { retry: true, suggestion: "
|
|
1335
|
-
"50004": { retry: true, suggestion: "Endpoint
|
|
1453
|
+
"50001": { retry: true, suggestion: "OKX system upgrade in progress. Retry in a few minutes." },
|
|
1454
|
+
"50004": { retry: true, suggestion: "Endpoint temporarily unavailable. Retry later." },
|
|
1336
1455
|
"50013": { retry: true, suggestion: "System busy. Retry after 1-2 seconds." },
|
|
1337
|
-
"50026": { retry: true, suggestion: "
|
|
1456
|
+
"50026": { retry: true, suggestion: "Order book system upgrading. Retry in a few minutes." },
|
|
1338
1457
|
// Region / compliance restriction → do not retry
|
|
1339
1458
|
"51155": { retry: false, suggestion: "Feature unavailable in your region (site: {site}). Verify your site setting matches your account registration region. Available sites: global, eea, us. Do not retry." },
|
|
1340
1459
|
"51734": { retry: false, suggestion: "Feature not supported for your KYC country (site: {site}). Verify your site setting matches your account registration region. Available sites: global, eea, us. Do not retry." },
|
|
@@ -1384,6 +1503,7 @@ function maskKey(key) {
|
|
|
1384
1503
|
if (key.length <= 8) return "***";
|
|
1385
1504
|
return `${key.slice(0, 3)}***${key.slice(-3)}`;
|
|
1386
1505
|
}
|
|
1506
|
+
var TOKEN_CACHE_TTL_MS = 6e4;
|
|
1387
1507
|
function vlog2(message) {
|
|
1388
1508
|
process.stderr.write(`[verbose] ${message}
|
|
1389
1509
|
`);
|
|
@@ -1392,6 +1512,8 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1392
1512
|
config;
|
|
1393
1513
|
rateLimiter;
|
|
1394
1514
|
dispatcher;
|
|
1515
|
+
cachedAccessToken;
|
|
1516
|
+
cachedAccessTokenAt = 0;
|
|
1395
1517
|
doh;
|
|
1396
1518
|
constructor(config) {
|
|
1397
1519
|
this.config = config;
|
|
@@ -1406,6 +1528,51 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1406
1528
|
hasCustomProxy: !!config.proxyUrl
|
|
1407
1529
|
});
|
|
1408
1530
|
}
|
|
1531
|
+
/**
|
|
1532
|
+
* Resolve OAuth access token via the okx-auth binary (fd3 pipe).
|
|
1533
|
+
* Caches the token for 60 s to avoid spawning the binary on every
|
|
1534
|
+
* request. The binary handles refresh internally (300s TTL lead),
|
|
1535
|
+
* so periodic re-calls let it serve a fresh token when needed.
|
|
1536
|
+
* Returns null when not logged in.
|
|
1537
|
+
*/
|
|
1538
|
+
async resolveAccessToken() {
|
|
1539
|
+
if (this.cachedAccessToken && Date.now() - this.cachedAccessTokenAt < TOKEN_CACHE_TTL_MS) {
|
|
1540
|
+
return this.cachedAccessToken;
|
|
1541
|
+
}
|
|
1542
|
+
try {
|
|
1543
|
+
const token = await execAuthToken();
|
|
1544
|
+
this.cachedAccessToken = token;
|
|
1545
|
+
this.cachedAccessTokenAt = Date.now();
|
|
1546
|
+
return token;
|
|
1547
|
+
} catch (e) {
|
|
1548
|
+
if (e instanceof NotLoggedInError) {
|
|
1549
|
+
return null;
|
|
1550
|
+
}
|
|
1551
|
+
throw e;
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
/**
|
|
1555
|
+
* Dynamic auth — determines auth method per request.
|
|
1556
|
+
*
|
|
1557
|
+
* 1. API key in config → HMAC signing (no OAuth fallback)
|
|
1558
|
+
* 2. OAuth token via okx-auth binary → Bearer token
|
|
1559
|
+
* 3. Neither → throw ConfigError
|
|
1560
|
+
*/
|
|
1561
|
+
async applyAuth(headers, method, requestPath, bodyJson, timestamp) {
|
|
1562
|
+
if (this.config.apiKey && this.config.secretKey && this.config.passphrase) {
|
|
1563
|
+
this.setAuthHeaders(headers, method, requestPath, bodyJson, timestamp);
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
const accessToken = await this.resolveAccessToken();
|
|
1567
|
+
if (accessToken) {
|
|
1568
|
+
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1571
|
+
throw new ConfigError(
|
|
1572
|
+
"No credentials found.",
|
|
1573
|
+
"Run `okx auth login` to authenticate, or configure API key credentials."
|
|
1574
|
+
);
|
|
1575
|
+
}
|
|
1409
1576
|
/** The canonical base URL for this client (e.g. https://www.okx.com). */
|
|
1410
1577
|
get baseUrl() {
|
|
1411
1578
|
return this.config.baseUrl;
|
|
@@ -1463,18 +1630,6 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1463
1630
|
});
|
|
1464
1631
|
}
|
|
1465
1632
|
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
1633
|
const payload = `${timestamp}${method.toUpperCase()}${requestPath}${bodyJson}`;
|
|
1479
1634
|
const signature = signOkxPayload(payload, this.config.secretKey);
|
|
1480
1635
|
headers.set("OK-ACCESS-KEY", this.config.apiKey);
|
|
@@ -1589,7 +1744,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1589
1744
|
const conn = this.doh.getConnectionParams();
|
|
1590
1745
|
this.logRequest("POST", `${conn.baseUrl}${path42}`, "private");
|
|
1591
1746
|
const reqConfig = { method: "POST", path: path42, auth: "private" };
|
|
1592
|
-
const headers = this.buildHeaders(reqConfig, path42, bodyJson, getNow());
|
|
1747
|
+
const headers = await this.buildHeaders(reqConfig, path42, bodyJson, getNow());
|
|
1593
1748
|
if (conn.userAgent) {
|
|
1594
1749
|
headers.set("User-Agent", conn.userAgent);
|
|
1595
1750
|
}
|
|
@@ -1706,7 +1861,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1706
1861
|
// Header building
|
|
1707
1862
|
// ---------------------------------------------------------------------------
|
|
1708
1863
|
/** Build HTTP headers. reqConfig.extraHeaders must NOT contain auth keys (OK-ACCESS-*). */
|
|
1709
|
-
buildHeaders(reqConfig, requestPath, bodyJson, timestamp) {
|
|
1864
|
+
async buildHeaders(reqConfig, requestPath, bodyJson, timestamp) {
|
|
1710
1865
|
const headers = new Headers({
|
|
1711
1866
|
"Content-Type": "application/json",
|
|
1712
1867
|
Accept: "application/json"
|
|
@@ -1715,7 +1870,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1715
1870
|
headers.set("User-Agent", this.config.userAgent);
|
|
1716
1871
|
}
|
|
1717
1872
|
if (reqConfig.auth === "private") {
|
|
1718
|
-
this.
|
|
1873
|
+
await this.applyAuth(headers, reqConfig.method, requestPath, bodyJson, timestamp);
|
|
1719
1874
|
}
|
|
1720
1875
|
const useSimulated = reqConfig.simulatedTrading !== void 0 ? reqConfig.simulatedTrading : this.config.demo;
|
|
1721
1876
|
if (useSimulated) {
|
|
@@ -1769,7 +1924,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1769
1924
|
if (reqConfig.rateLimit) {
|
|
1770
1925
|
await this.rateLimiter.consume(reqConfig.rateLimit);
|
|
1771
1926
|
}
|
|
1772
|
-
const headers = this.buildHeaders(reqConfig, requestPath, bodyJson, timestamp);
|
|
1927
|
+
const headers = await this.buildHeaders(reqConfig, requestPath, bodyJson, timestamp);
|
|
1773
1928
|
if (conn.userAgent) {
|
|
1774
1929
|
headers.set("User-Agent", conn.userAgent);
|
|
1775
1930
|
}
|
|
@@ -2192,7 +2347,7 @@ var OKX_SITES = {
|
|
|
2192
2347
|
},
|
|
2193
2348
|
us: {
|
|
2194
2349
|
label: "US",
|
|
2195
|
-
apiBaseUrl: "https://
|
|
2350
|
+
apiBaseUrl: "https://us.okx.com",
|
|
2196
2351
|
webUrl: "https://app.okx.com"
|
|
2197
2352
|
}
|
|
2198
2353
|
};
|
|
@@ -3722,7 +3877,7 @@ function safeWriteFile(targetDir, fileName, data) {
|
|
|
3722
3877
|
throw new Error(`Invalid file name: "${fileName}"`);
|
|
3723
3878
|
}
|
|
3724
3879
|
const resolvedDir = resolve(targetDir);
|
|
3725
|
-
const filePath =
|
|
3880
|
+
const filePath = join4(resolvedDir, safeName);
|
|
3726
3881
|
const resolvedPath = resolve(filePath);
|
|
3727
3882
|
if (!resolvedPath.startsWith(resolvedDir + sep)) {
|
|
3728
3883
|
throw new Error(`Path traversal detected: "${fileName}" resolves outside target directory`);
|
|
@@ -3850,7 +4005,7 @@ async function extractSkillZip(zipPath, targetDir, limits) {
|
|
|
3850
4005
|
});
|
|
3851
4006
|
}
|
|
3852
4007
|
function readMetaJson(contentDir) {
|
|
3853
|
-
const metaPath =
|
|
4008
|
+
const metaPath = join5(contentDir, "_meta.json");
|
|
3854
4009
|
if (!existsSync(metaPath)) {
|
|
3855
4010
|
throw new Error(`_meta.json not found in ${contentDir}. Invalid skill package.`);
|
|
3856
4011
|
}
|
|
@@ -3876,12 +4031,12 @@ function readMetaJson(contentDir) {
|
|
|
3876
4031
|
};
|
|
3877
4032
|
}
|
|
3878
4033
|
function validateSkillMdExists(contentDir) {
|
|
3879
|
-
const skillMdPath =
|
|
4034
|
+
const skillMdPath = join5(contentDir, "SKILL.md");
|
|
3880
4035
|
if (!existsSync(skillMdPath)) {
|
|
3881
4036
|
throw new Error(`SKILL.md not found in ${contentDir}. Invalid skill package.`);
|
|
3882
4037
|
}
|
|
3883
4038
|
}
|
|
3884
|
-
var DEFAULT_REGISTRY_PATH =
|
|
4039
|
+
var DEFAULT_REGISTRY_PATH = join6(homedir4(), ".okx", "skills", "registry.json");
|
|
3885
4040
|
function readRegistry(registryPath = DEFAULT_REGISTRY_PATH) {
|
|
3886
4041
|
if (!existsSync2(registryPath)) {
|
|
3887
4042
|
return { version: 1, skills: {} };
|
|
@@ -5219,7 +5374,7 @@ function registerOnchainEarnTools() {
|
|
|
5219
5374
|
];
|
|
5220
5375
|
}
|
|
5221
5376
|
var DCD_CODE_BEHAVIORS = {
|
|
5222
|
-
"50001": { retry: true, suggestion: "
|
|
5377
|
+
"50001": { retry: true, suggestion: "DCD service is down. Retry in a few minutes." },
|
|
5223
5378
|
"50002": { retry: false, suggestion: "Invalid JSON in request body. This is likely a bug \u2014 check request parameters." },
|
|
5224
5379
|
"50014": { retry: false, suggestion: "Missing required parameter. Check that all required fields are provided." },
|
|
5225
5380
|
"50016": { retry: false, suggestion: "notionalCcy does not match productId option type. Use baseCcy for CALL, quoteCcy for PUT." },
|
|
@@ -7837,10 +7992,10 @@ var NEWS_DETAIL = "/api/v5/orbit/news-detail";
|
|
|
7837
7992
|
var NEWS_DOMAINS = "/api/v5/orbit/news-platform";
|
|
7838
7993
|
var SENTIMENT_QUERY = "/api/v5/orbit/currency-sentiment-query";
|
|
7839
7994
|
var SENTIMENT_RANKING = "/api/v5/orbit/currency-sentiment-ranking";
|
|
7840
|
-
var NEWS_LANGUAGE = ["
|
|
7995
|
+
var NEWS_LANGUAGE = ["en_US", "zh_CN"];
|
|
7841
7996
|
function langHeader(lang) {
|
|
7842
|
-
|
|
7843
|
-
return { "Accept-Language":
|
|
7997
|
+
const resolved = lang === "zh_CN" ? "zh_CN" : "en_US";
|
|
7998
|
+
return { "Accept-Language": resolved };
|
|
7844
7999
|
}
|
|
7845
8000
|
var NEWS_DETAIL_LVL = ["brief", "summary", "full"];
|
|
7846
8001
|
var NEWS_IMPORTANCE = ["high", "medium", "low"];
|
|
@@ -7849,7 +8004,7 @@ var NEWS_SORT = ["latest", "relevant"];
|
|
|
7849
8004
|
var SENTIMENT_PERIOD = ["1h", "4h", "24h"];
|
|
7850
8005
|
var D_COINS_NEWS = 'Comma-separated uppercase ticker symbols (e.g. "BTC,ETH"). Normalize names/aliases to standard tickers.';
|
|
7851
8006
|
var D_COINS_SENTIMENT = 'Comma-separated uppercase ticker symbols, max 20 (e.g. "BTC,ETH"). Normalize names/aliases to standard tickers.';
|
|
7852
|
-
var D_LANGUAGE = "Content language:
|
|
8007
|
+
var D_LANGUAGE = "Content language: zh_CN or en_US. Infer from user's message. No server default.";
|
|
7853
8008
|
var D_BEGIN = "Start time, Unix epoch milliseconds. Parse relative time if given (e.g. 'yesterday', 'last 7 days').";
|
|
7854
8009
|
var D_END = "End time, Unix epoch milliseconds. Parse relative time if given. Omit for no upper bound.";
|
|
7855
8010
|
var D_IMPORTANCE = "Importance filter: high (server default), medium, low. Omit unless user wants broader coverage.";
|
|
@@ -9646,7 +9801,7 @@ function createToolRunner(client, config) {
|
|
|
9646
9801
|
};
|
|
9647
9802
|
}
|
|
9648
9803
|
function configFilePath() {
|
|
9649
|
-
return
|
|
9804
|
+
return join7(homedir5(), ".okx", "config.toml");
|
|
9650
9805
|
}
|
|
9651
9806
|
function readFullConfig() {
|
|
9652
9807
|
const path42 = configFilePath();
|
|
@@ -9665,11 +9820,6 @@ Or re-run: okx config init`
|
|
|
9665
9820
|
);
|
|
9666
9821
|
}
|
|
9667
9822
|
}
|
|
9668
|
-
function readTomlProfile(profileName) {
|
|
9669
|
-
const config = readFullConfig();
|
|
9670
|
-
const name = profileName ?? config.default_profile ?? "default";
|
|
9671
|
-
return config.profiles?.[name] ?? {};
|
|
9672
|
-
}
|
|
9673
9823
|
var CONFIG_HEADER = `# OKX Trade Kit Configuration
|
|
9674
9824
|
# If editing manually, wrap values containing special chars in quotes:
|
|
9675
9825
|
# passphrase = 'value' (if value contains # \\ ")
|
|
@@ -9718,18 +9868,24 @@ function parseModuleList(rawModules) {
|
|
|
9718
9868
|
}
|
|
9719
9869
|
return Array.from(deduped);
|
|
9720
9870
|
}
|
|
9721
|
-
function loadCredentials(toml) {
|
|
9871
|
+
async function loadCredentials(toml) {
|
|
9722
9872
|
const apiKey = process.env.OKX_API_KEY?.trim() ?? toml.api_key;
|
|
9723
9873
|
const secretKey = process.env.OKX_SECRET_KEY?.trim() ?? toml.secret_key;
|
|
9724
9874
|
const passphrase = process.env.OKX_PASSPHRASE?.trim() ?? toml.passphrase;
|
|
9725
|
-
const
|
|
9875
|
+
const hasApiKey = Boolean(apiKey && secretKey && passphrase);
|
|
9726
9876
|
const partialAuth = Boolean(apiKey) || Boolean(secretKey) || Boolean(passphrase);
|
|
9727
|
-
if (partialAuth && !
|
|
9877
|
+
if (partialAuth && !hasApiKey) {
|
|
9728
9878
|
throw new ConfigError(
|
|
9729
9879
|
"Partial API credentials detected.",
|
|
9730
9880
|
"Set OKX_API_KEY, OKX_SECRET_KEY and OKX_PASSPHRASE together (env vars or config.toml profile)."
|
|
9731
9881
|
);
|
|
9732
9882
|
}
|
|
9883
|
+
let hasOAuth = false;
|
|
9884
|
+
if (!hasApiKey) {
|
|
9885
|
+
const status = await execAuthStatus();
|
|
9886
|
+
hasOAuth = status?.status === "logged_in";
|
|
9887
|
+
}
|
|
9888
|
+
const hasAuth = hasOAuth || hasApiKey;
|
|
9733
9889
|
return { apiKey, secretKey, passphrase, hasAuth };
|
|
9734
9890
|
}
|
|
9735
9891
|
function resolveSite(cliSite, tomlSite) {
|
|
@@ -9763,9 +9919,11 @@ function resolveDemo(cli, toml) {
|
|
|
9763
9919
|
if (cli.demo === true) return true;
|
|
9764
9920
|
return process.env.OKX_DEMO === "1" || process.env.OKX_DEMO === "true" || (toml.demo ?? false);
|
|
9765
9921
|
}
|
|
9766
|
-
function loadConfig(cli) {
|
|
9767
|
-
const
|
|
9768
|
-
const
|
|
9922
|
+
async function loadConfig(cli) {
|
|
9923
|
+
const config = readFullConfig();
|
|
9924
|
+
const profileName = cli.profile ?? config.default_profile ?? "default";
|
|
9925
|
+
const toml = config.profiles?.[profileName] ?? {};
|
|
9926
|
+
const creds = await loadCredentials(toml);
|
|
9769
9927
|
const demo = resolveDemo(cli, toml);
|
|
9770
9928
|
const site = resolveSite(cli.site, toml.site);
|
|
9771
9929
|
const baseUrl = resolveBaseUrl(site, toml.base_url);
|
|
@@ -9785,6 +9943,7 @@ function loadConfig(cli) {
|
|
|
9785
9943
|
}
|
|
9786
9944
|
return {
|
|
9787
9945
|
...creds,
|
|
9946
|
+
profile: profileName,
|
|
9788
9947
|
baseUrl,
|
|
9789
9948
|
timeoutMs: Math.floor(rawTimeout),
|
|
9790
9949
|
modules: parseModuleList(cli.modules),
|
|
@@ -9797,7 +9956,7 @@ function loadConfig(cli) {
|
|
|
9797
9956
|
verbose: cli.verbose ?? false
|
|
9798
9957
|
};
|
|
9799
9958
|
}
|
|
9800
|
-
var CACHE_FILE =
|
|
9959
|
+
var CACHE_FILE = join8(homedir6(), ".okx", "update-check.json");
|
|
9801
9960
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
9802
9961
|
function readCache2() {
|
|
9803
9962
|
try {
|
|
@@ -9810,7 +9969,7 @@ function readCache2() {
|
|
|
9810
9969
|
}
|
|
9811
9970
|
function writeCache2(cache) {
|
|
9812
9971
|
try {
|
|
9813
|
-
mkdirSync6(
|
|
9972
|
+
mkdirSync6(join8(homedir6(), ".okx"), { recursive: true });
|
|
9814
9973
|
writeFileSync5(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
|
|
9815
9974
|
} catch {
|
|
9816
9975
|
}
|
|
@@ -9980,13 +10139,13 @@ function findMsStoreClaudePath() {
|
|
|
9980
10139
|
}
|
|
9981
10140
|
function getConfigPath(client) {
|
|
9982
10141
|
const home = os3.homedir();
|
|
9983
|
-
const
|
|
10142
|
+
const platform3 = process.platform;
|
|
9984
10143
|
switch (client) {
|
|
9985
10144
|
case "claude-desktop":
|
|
9986
|
-
if (
|
|
10145
|
+
if (platform3 === "win32") {
|
|
9987
10146
|
return findMsStoreClaudePath() ?? path3.join(appData(), "Claude", CLAUDE_CONFIG_FILE);
|
|
9988
10147
|
}
|
|
9989
|
-
if (
|
|
10148
|
+
if (platform3 === "darwin") {
|
|
9990
10149
|
return path3.join(home, "Library", "Application Support", "Claude", CLAUDE_CONFIG_FILE);
|
|
9991
10150
|
}
|
|
9992
10151
|
return path3.join(process.env.XDG_CONFIG_HOME ?? path3.join(home, ".config"), "Claude", CLAUDE_CONFIG_FILE);
|
|
@@ -10107,7 +10266,7 @@ function getPlatformDir() {
|
|
|
10107
10266
|
return map[`${p}-${a}`] ?? null;
|
|
10108
10267
|
}
|
|
10109
10268
|
function getBinaryName() {
|
|
10110
|
-
return platform() === "win32" ? "okx-
|
|
10269
|
+
return platform() === "win32" ? "okx-doh-resolver.exe" : "okx-doh-resolver";
|
|
10111
10270
|
}
|
|
10112
10271
|
function hashFile(filePath) {
|
|
10113
10272
|
const buf = readFileSync7(filePath);
|
|
@@ -10228,7 +10387,7 @@ async function installDohBinary(destPath, sources = CDN_SOURCES, onProgress) {
|
|
|
10228
10387
|
if (earlyResult) return earlyResult;
|
|
10229
10388
|
const platformDir = getPlatformDir();
|
|
10230
10389
|
const binaryName = getBinaryName();
|
|
10231
|
-
const resolvedDest = destPath ??
|
|
10390
|
+
const resolvedDest = destPath ?? join10(homedir8(), ".okx", "bin", binaryName);
|
|
10232
10391
|
const tmpPath = resolvedDest + ".tmp";
|
|
10233
10392
|
mkdirSync8(dirname6(resolvedDest), { recursive: true });
|
|
10234
10393
|
const localHash = existsSync6(resolvedDest) ? hashFile(resolvedDest) : null;
|
|
@@ -10351,16 +10510,276 @@ function downloadText(url, timeoutMs) {
|
|
|
10351
10510
|
})
|
|
10352
10511
|
);
|
|
10353
10512
|
}
|
|
10513
|
+
var AUTH_CDN_PATH_PREFIX = "/upgradeapp/tools/oauth";
|
|
10514
|
+
function getAuthBinaryName() {
|
|
10515
|
+
return platform2() === "win32" ? "okx-auth.exe" : "okx-auth";
|
|
10516
|
+
}
|
|
10517
|
+
function getAuthStatus(binaryPath, opts) {
|
|
10518
|
+
const resolvedPath = binaryPath ?? getAuthBinaryPath();
|
|
10519
|
+
const platformDir = getPlatformDir();
|
|
10520
|
+
if (!existsSync7(resolvedPath)) {
|
|
10521
|
+
return { binaryPath: resolvedPath, exists: false, platform: platformDir };
|
|
10522
|
+
}
|
|
10523
|
+
if (opts?.skipHash) {
|
|
10524
|
+
return { binaryPath: resolvedPath, exists: true, platform: platformDir };
|
|
10525
|
+
}
|
|
10526
|
+
const { size, sha256 } = hashFile(resolvedPath);
|
|
10527
|
+
return { binaryPath: resolvedPath, exists: true, platform: platformDir, fileSize: size, sha256 };
|
|
10528
|
+
}
|
|
10529
|
+
async function fetchAuthCdnChecksum(sources = CDN_SOURCES, timeoutMs = DOWNLOAD_TIMEOUT_MS) {
|
|
10530
|
+
const platformDir = getPlatformDir();
|
|
10531
|
+
if (!platformDir) return null;
|
|
10532
|
+
const checksumPath = `${AUTH_CDN_PATH_PREFIX}/${platformDir}/checksum.json`;
|
|
10533
|
+
for (const { host, protocol } of sources) {
|
|
10534
|
+
try {
|
|
10535
|
+
const url = `${protocol}://${host}${checksumPath}`;
|
|
10536
|
+
const raw = await downloadText2(url, timeoutMs);
|
|
10537
|
+
const data = JSON.parse(raw);
|
|
10538
|
+
if (typeof data.sha256 !== "string" || typeof data.size !== "number" || typeof data.target !== "string") {
|
|
10539
|
+
continue;
|
|
10540
|
+
}
|
|
10541
|
+
return { sha256: data.sha256, size: data.size, target: data.target, source: host };
|
|
10542
|
+
} catch {
|
|
10543
|
+
}
|
|
10544
|
+
}
|
|
10545
|
+
return null;
|
|
10546
|
+
}
|
|
10547
|
+
async function fetchAndValidateChecksum2(host, protocol, checksumPath, platformDir, timeoutMs, onProgress) {
|
|
10548
|
+
const checksumUrl = `${protocol}://${host}${checksumPath}`;
|
|
10549
|
+
onProgress?.(`Fetching checksum from ${host}...`);
|
|
10550
|
+
const raw = await downloadText2(checksumUrl, timeoutMs);
|
|
10551
|
+
const checksum = JSON.parse(raw);
|
|
10552
|
+
if (typeof checksum.sha256 !== "string" || typeof checksum.size !== "number" || typeof checksum.target !== "string") {
|
|
10553
|
+
throw new Error("Invalid checksum.json: missing sha256, size, or target");
|
|
10554
|
+
}
|
|
10555
|
+
if (checksum.target !== platformDir) {
|
|
10556
|
+
throw new Error(`Target mismatch: expected ${platformDir}, got ${checksum.target}`);
|
|
10557
|
+
}
|
|
10558
|
+
return { sha256: checksum.sha256, size: checksum.size, target: checksum.target };
|
|
10559
|
+
}
|
|
10560
|
+
async function downloadAndVerify2(host, protocol, binaryPath, tmpPath, checksum, timeoutMs, onProgress) {
|
|
10561
|
+
const binaryUrl = `${protocol}://${host}${binaryPath}`;
|
|
10562
|
+
onProgress?.(`Downloading binary from ${host}...`);
|
|
10563
|
+
await download2(binaryUrl, tmpPath, timeoutMs);
|
|
10564
|
+
const actual = hashFile(tmpPath);
|
|
10565
|
+
if (actual.size !== checksum.size) {
|
|
10566
|
+
throw new Error(`Size mismatch: expected ${checksum.size}, got ${actual.size}`);
|
|
10567
|
+
}
|
|
10568
|
+
if (actual.sha256 !== checksum.sha256) {
|
|
10569
|
+
throw new Error(`SHA-256 mismatch: expected ${checksum.sha256}, got ${actual.sha256}`);
|
|
10570
|
+
}
|
|
10571
|
+
}
|
|
10572
|
+
function atomicReplace2(tmpPath, resolvedDest) {
|
|
10573
|
+
if (platform2() === "win32") {
|
|
10574
|
+
try {
|
|
10575
|
+
unlinkSync4(resolvedDest);
|
|
10576
|
+
} catch {
|
|
10577
|
+
}
|
|
10578
|
+
}
|
|
10579
|
+
renameSync4(tmpPath, resolvedDest);
|
|
10580
|
+
if (platform2() !== "win32") {
|
|
10581
|
+
chmodSync2(resolvedDest, 493);
|
|
10582
|
+
}
|
|
10583
|
+
}
|
|
10584
|
+
function installPreChecks2(destPath, sources) {
|
|
10585
|
+
if (!destPath && process.env.OKX_AUTH_BIN) {
|
|
10586
|
+
return { status: "up-to-date", source: "(env override)" };
|
|
10587
|
+
}
|
|
10588
|
+
if (!getPlatformDir()) {
|
|
10589
|
+
return { status: "failed", error: "Unsupported platform" };
|
|
10590
|
+
}
|
|
10591
|
+
if (sources.length === 0) {
|
|
10592
|
+
return { status: "failed", error: "No CDN sources available" };
|
|
10593
|
+
}
|
|
10594
|
+
return null;
|
|
10595
|
+
}
|
|
10596
|
+
function isLocalUpToDate2(localHash, checksum) {
|
|
10597
|
+
return localHash !== null && localHash.size === checksum.size && localHash.sha256 === checksum.sha256;
|
|
10598
|
+
}
|
|
10599
|
+
async function installAuthBinary(destPath, sources = CDN_SOURCES, onProgress) {
|
|
10600
|
+
const earlyResult = installPreChecks2(destPath, sources);
|
|
10601
|
+
if (earlyResult) return earlyResult;
|
|
10602
|
+
const platformDir = getPlatformDir();
|
|
10603
|
+
const binaryName = getAuthBinaryName();
|
|
10604
|
+
const resolvedDest = destPath ?? join11(homedir9(), ".okx", "bin", binaryName);
|
|
10605
|
+
const tmpPath = resolvedDest + ".tmp";
|
|
10606
|
+
mkdirSync9(dirname7(resolvedDest), { recursive: true });
|
|
10607
|
+
const localHash = existsSync7(resolvedDest) ? hashFile(resolvedDest) : null;
|
|
10608
|
+
const checksumPath = `${AUTH_CDN_PATH_PREFIX}/${platformDir}/checksum.json`;
|
|
10609
|
+
const binaryPath = `${AUTH_CDN_PATH_PREFIX}/${platformDir}/${binaryName}`;
|
|
10610
|
+
const errors = [];
|
|
10611
|
+
for (const { host, protocol } of sources) {
|
|
10612
|
+
try {
|
|
10613
|
+
const checksum = await fetchAndValidateChecksum2(
|
|
10614
|
+
host,
|
|
10615
|
+
protocol,
|
|
10616
|
+
checksumPath,
|
|
10617
|
+
platformDir,
|
|
10618
|
+
DOWNLOAD_TIMEOUT_MS,
|
|
10619
|
+
onProgress
|
|
10620
|
+
);
|
|
10621
|
+
if (isLocalUpToDate2(localHash, checksum)) {
|
|
10622
|
+
onProgress?.("Already up to date (checksum match)");
|
|
10623
|
+
return { status: "up-to-date", source: host };
|
|
10624
|
+
}
|
|
10625
|
+
await downloadAndVerify2(host, protocol, binaryPath, tmpPath, checksum, DOWNLOAD_TIMEOUT_MS, onProgress);
|
|
10626
|
+
atomicReplace2(tmpPath, resolvedDest);
|
|
10627
|
+
onProgress?.(`Downloaded and verified from ${host}`);
|
|
10628
|
+
return { status: "installed", source: host };
|
|
10629
|
+
} catch (err) {
|
|
10630
|
+
try {
|
|
10631
|
+
unlinkSync4(tmpPath);
|
|
10632
|
+
} catch {
|
|
10633
|
+
}
|
|
10634
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10635
|
+
errors.push(`${host}: ${msg}`);
|
|
10636
|
+
onProgress?.(`${host} failed: ${msg}`);
|
|
10637
|
+
}
|
|
10638
|
+
}
|
|
10639
|
+
return { status: "failed", error: `All CDN sources failed:
|
|
10640
|
+
${errors.join("\n")}` };
|
|
10641
|
+
}
|
|
10642
|
+
function removeAuthBinary(binaryPath) {
|
|
10643
|
+
const resolvedPath = binaryPath ?? getAuthBinaryPath();
|
|
10644
|
+
try {
|
|
10645
|
+
unlinkSync4(resolvedPath);
|
|
10646
|
+
return { status: "removed" };
|
|
10647
|
+
} catch (err) {
|
|
10648
|
+
if (err.code === "ENOENT") {
|
|
10649
|
+
return { status: "not-found" };
|
|
10650
|
+
}
|
|
10651
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10652
|
+
throw new Error(`Failed to remove ${resolvedPath}: ${msg}`);
|
|
10653
|
+
}
|
|
10654
|
+
}
|
|
10655
|
+
function isRedirect2(statusCode) {
|
|
10656
|
+
return statusCode !== void 0 && statusCode >= 300 && statusCode < 400;
|
|
10657
|
+
}
|
|
10658
|
+
function validateRedirect2(res, requestUrl, redirectCount, maxRedirects) {
|
|
10659
|
+
if (redirectCount > maxRedirects) {
|
|
10660
|
+
throw new Error(`Too many redirects (${maxRedirects})`);
|
|
10661
|
+
}
|
|
10662
|
+
const location = res.headers.location;
|
|
10663
|
+
if (requestUrl.startsWith("https") && !location.startsWith("https")) {
|
|
10664
|
+
throw new Error("Refused HTTPS \u2192 HTTP redirect downgrade");
|
|
10665
|
+
}
|
|
10666
|
+
return location;
|
|
10667
|
+
}
|
|
10668
|
+
function fetchResponse2(url, timeoutMs) {
|
|
10669
|
+
return new Promise((resolve3, reject) => {
|
|
10670
|
+
let redirects = 0;
|
|
10671
|
+
const maxRedirects = 5;
|
|
10672
|
+
function doRequest(requestUrl) {
|
|
10673
|
+
const reqFn = requestUrl.startsWith("https") ? httpsGet2 : httpGet2;
|
|
10674
|
+
const req = reqFn(requestUrl, { timeout: timeoutMs }, (res) => {
|
|
10675
|
+
if (isRedirect2(res.statusCode) && res.headers.location) {
|
|
10676
|
+
redirects++;
|
|
10677
|
+
try {
|
|
10678
|
+
const location = validateRedirect2(res, requestUrl, redirects, maxRedirects);
|
|
10679
|
+
res.resume();
|
|
10680
|
+
doRequest(location);
|
|
10681
|
+
} catch (err) {
|
|
10682
|
+
reject(err);
|
|
10683
|
+
}
|
|
10684
|
+
return;
|
|
10685
|
+
}
|
|
10686
|
+
if (res.statusCode !== 200) {
|
|
10687
|
+
reject(new Error(`HTTP ${res.statusCode ?? "unknown"}`));
|
|
10688
|
+
return;
|
|
10689
|
+
}
|
|
10690
|
+
resolve3(res);
|
|
10691
|
+
});
|
|
10692
|
+
req.on("error", reject);
|
|
10693
|
+
req.on("timeout", () => {
|
|
10694
|
+
req.destroy();
|
|
10695
|
+
reject(new Error("Download timed out"));
|
|
10696
|
+
});
|
|
10697
|
+
}
|
|
10698
|
+
doRequest(url);
|
|
10699
|
+
});
|
|
10700
|
+
}
|
|
10701
|
+
function download2(url, destPath, timeoutMs) {
|
|
10702
|
+
return fetchResponse2(url, timeoutMs).then(
|
|
10703
|
+
(res) => new Promise((resolve3, reject) => {
|
|
10704
|
+
const file = createWriteStream3(destPath);
|
|
10705
|
+
res.pipe(file);
|
|
10706
|
+
file.on("finish", () => file.close(() => resolve3()));
|
|
10707
|
+
file.on("error", (err) => {
|
|
10708
|
+
try {
|
|
10709
|
+
unlinkSync4(destPath);
|
|
10710
|
+
} catch {
|
|
10711
|
+
}
|
|
10712
|
+
reject(err);
|
|
10713
|
+
});
|
|
10714
|
+
})
|
|
10715
|
+
);
|
|
10716
|
+
}
|
|
10717
|
+
function downloadText2(url, timeoutMs) {
|
|
10718
|
+
return fetchResponse2(url, timeoutMs).then(
|
|
10719
|
+
(res) => new Promise((resolve3, reject) => {
|
|
10720
|
+
const chunks = [];
|
|
10721
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
10722
|
+
res.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
|
|
10723
|
+
res.on("error", reject);
|
|
10724
|
+
})
|
|
10725
|
+
);
|
|
10726
|
+
}
|
|
10727
|
+
var CACHE_PATH = join12(homedir10(), ".okx", "auth-binary-check.json");
|
|
10728
|
+
var CHECK_INTERVAL_MS2 = 2 * 60 * 60 * 1e3;
|
|
10729
|
+
function readCache3() {
|
|
10730
|
+
try {
|
|
10731
|
+
if (!existsSync8(CACHE_PATH)) return null;
|
|
10732
|
+
const data = JSON.parse(readFileSync8(CACHE_PATH, "utf-8"));
|
|
10733
|
+
if (typeof data.cdnSha256 !== "string" || typeof data.checkedAt !== "number") return null;
|
|
10734
|
+
return { cdnSha256: data.cdnSha256, checkedAt: data.checkedAt };
|
|
10735
|
+
} catch {
|
|
10736
|
+
return null;
|
|
10737
|
+
}
|
|
10738
|
+
}
|
|
10739
|
+
function writeCache3(cdnSha256) {
|
|
10740
|
+
try {
|
|
10741
|
+
mkdirSync10(join12(homedir10(), ".okx"), { recursive: true });
|
|
10742
|
+
writeFileSync7(CACHE_PATH, JSON.stringify({ cdnSha256, checkedAt: Date.now() }, null, 2), "utf-8");
|
|
10743
|
+
} catch {
|
|
10744
|
+
}
|
|
10745
|
+
}
|
|
10746
|
+
async function ensureAuthBinaryLatest(onProgress) {
|
|
10747
|
+
if (process.env.OKX_AUTH_BIN) return;
|
|
10748
|
+
const cache = readCache3();
|
|
10749
|
+
if (cache && Date.now() - cache.checkedAt < CHECK_INTERVAL_MS2) return;
|
|
10750
|
+
try {
|
|
10751
|
+
const cdn = await fetchAuthCdnChecksum(void 0, 5e3);
|
|
10752
|
+
if (!cdn) return;
|
|
10753
|
+
const local = getAuthStatus();
|
|
10754
|
+
if (local.exists && local.sha256 === cdn.sha256) {
|
|
10755
|
+
writeCache3(cdn.sha256);
|
|
10756
|
+
return;
|
|
10757
|
+
}
|
|
10758
|
+
onProgress?.("Updating okx-auth binary...");
|
|
10759
|
+
const result = await installAuthBinary(void 0, void 0, onProgress);
|
|
10760
|
+
if (result.status === "installed" || result.status === "up-to-date") {
|
|
10761
|
+
const updated = getAuthStatus();
|
|
10762
|
+
if (updated.sha256) writeCache3(updated.sha256);
|
|
10763
|
+
if (result.status === "installed") {
|
|
10764
|
+
onProgress?.("\u2713 okx-auth updated successfully");
|
|
10765
|
+
}
|
|
10766
|
+
}
|
|
10767
|
+
} catch {
|
|
10768
|
+
}
|
|
10769
|
+
}
|
|
10770
|
+
function updateAuthBinaryCache(sha256) {
|
|
10771
|
+
writeCache3(sha256);
|
|
10772
|
+
}
|
|
10773
|
+
function clearAuthBinaryCache() {
|
|
10774
|
+
try {
|
|
10775
|
+
unlinkSync5(CACHE_PATH);
|
|
10776
|
+
} catch {
|
|
10777
|
+
}
|
|
10778
|
+
}
|
|
10354
10779
|
|
|
10355
|
-
// src/commands/
|
|
10356
|
-
import
|
|
10357
|
-
import
|
|
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";
|
|
10780
|
+
// src/commands/auth.ts
|
|
10781
|
+
import { spawn as spawn2 } from "child_process";
|
|
10782
|
+
import readline from "readline";
|
|
10364
10783
|
|
|
10365
10784
|
// src/formatter.ts
|
|
10366
10785
|
import { EOL } from "os";
|
|
@@ -10451,7 +10870,260 @@ function markFailedIfSCodeError(data) {
|
|
|
10451
10870
|
}
|
|
10452
10871
|
}
|
|
10453
10872
|
|
|
10873
|
+
// src/commands/auth.ts
|
|
10874
|
+
function runOkxAuth(args) {
|
|
10875
|
+
const binPath = getAuthBinaryPath();
|
|
10876
|
+
return new Promise((resolve3, reject) => {
|
|
10877
|
+
const child = spawn2(binPath, args, {
|
|
10878
|
+
stdio: "inherit"
|
|
10879
|
+
});
|
|
10880
|
+
child.on("error", (err) => {
|
|
10881
|
+
reject(new Error(`Failed to spawn okx-auth: ${err.message}`));
|
|
10882
|
+
});
|
|
10883
|
+
child.on("close", (code) => {
|
|
10884
|
+
resolve3(code ?? 1);
|
|
10885
|
+
});
|
|
10886
|
+
});
|
|
10887
|
+
}
|
|
10888
|
+
function runOkxAuthCapture(args) {
|
|
10889
|
+
const binPath = getAuthBinaryPath();
|
|
10890
|
+
return new Promise((resolve3, reject) => {
|
|
10891
|
+
const child = spawn2(binPath, args, {
|
|
10892
|
+
stdio: ["inherit", "pipe", "inherit"]
|
|
10893
|
+
});
|
|
10894
|
+
const chunks = [];
|
|
10895
|
+
child.stdout.on("data", (chunk) => chunks.push(chunk));
|
|
10896
|
+
child.on("error", (err) => {
|
|
10897
|
+
reject(new Error(`Failed to spawn okx-auth: ${err.message}`));
|
|
10898
|
+
});
|
|
10899
|
+
child.on("close", (code) => {
|
|
10900
|
+
resolve3({
|
|
10901
|
+
code: code ?? 1,
|
|
10902
|
+
stdout: Buffer.concat(chunks).toString("utf-8")
|
|
10903
|
+
});
|
|
10904
|
+
});
|
|
10905
|
+
});
|
|
10906
|
+
}
|
|
10907
|
+
async function cmdAuthLogin(args) {
|
|
10908
|
+
const cliArgs = ["login"];
|
|
10909
|
+
if (args.site) cliArgs.push("--site", args.site);
|
|
10910
|
+
if (args.manual) cliArgs.push("--manual");
|
|
10911
|
+
const code = await runOkxAuth(cliArgs);
|
|
10912
|
+
if (code !== 0) {
|
|
10913
|
+
process.exitCode = code;
|
|
10914
|
+
}
|
|
10915
|
+
}
|
|
10916
|
+
async function cmdAuthLogout() {
|
|
10917
|
+
const code = await runOkxAuth(["logout"]);
|
|
10918
|
+
if (code !== 0) {
|
|
10919
|
+
process.exitCode = code;
|
|
10920
|
+
}
|
|
10921
|
+
}
|
|
10922
|
+
async function cmdAuthStatus(args) {
|
|
10923
|
+
const cliArgs = ["status"];
|
|
10924
|
+
if (args.json) cliArgs.push("--json");
|
|
10925
|
+
const result = await runOkxAuthCapture(cliArgs);
|
|
10926
|
+
if (result.stdout) {
|
|
10927
|
+
process.stdout.write(result.stdout);
|
|
10928
|
+
}
|
|
10929
|
+
if (result.code !== 0) {
|
|
10930
|
+
process.exitCode = result.code;
|
|
10931
|
+
}
|
|
10932
|
+
}
|
|
10933
|
+
function resolveChecksumMatch(local, cdnChecksum, cdnError) {
|
|
10934
|
+
if (!local.exists) return "not-installed";
|
|
10935
|
+
if (cdnError || !cdnChecksum) return "unavailable";
|
|
10936
|
+
if (cdnChecksum.sha256 === local.sha256) return "match";
|
|
10937
|
+
return "mismatch";
|
|
10938
|
+
}
|
|
10939
|
+
function checksumMatchLabel(match) {
|
|
10940
|
+
if (match === "match") return "\u2713 match";
|
|
10941
|
+
if (match === "mismatch") return "\u2717 mismatch (update available)";
|
|
10942
|
+
return "CDN unreachable";
|
|
10943
|
+
}
|
|
10944
|
+
function formatBytes(bytes) {
|
|
10945
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
10946
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
10947
|
+
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
10948
|
+
}
|
|
10949
|
+
async function cmdAuthInstallStatus(json) {
|
|
10950
|
+
const local = getAuthStatus();
|
|
10951
|
+
let cdnChecksum = null;
|
|
10952
|
+
let cdnError = null;
|
|
10953
|
+
if (local.exists) {
|
|
10954
|
+
try {
|
|
10955
|
+
cdnChecksum = await fetchAuthCdnChecksum(void 0, 5e3);
|
|
10956
|
+
} catch (err) {
|
|
10957
|
+
cdnError = err instanceof Error ? err.message : String(err);
|
|
10958
|
+
}
|
|
10959
|
+
}
|
|
10960
|
+
const checksumMatch = resolveChecksumMatch(local, cdnChecksum, cdnError);
|
|
10961
|
+
if (json) {
|
|
10962
|
+
outputLine(
|
|
10963
|
+
JSON.stringify({
|
|
10964
|
+
binaryPath: local.binaryPath,
|
|
10965
|
+
exists: local.exists,
|
|
10966
|
+
platform: local.platform,
|
|
10967
|
+
fileSize: local.fileSize ?? null,
|
|
10968
|
+
sha256: local.sha256 ?? null,
|
|
10969
|
+
cdnMatch: checksumMatch,
|
|
10970
|
+
cdnSha256: cdnChecksum?.sha256 ?? null,
|
|
10971
|
+
cdnSource: cdnChecksum?.source ?? null
|
|
10972
|
+
})
|
|
10973
|
+
);
|
|
10974
|
+
return;
|
|
10975
|
+
}
|
|
10976
|
+
outputLine("");
|
|
10977
|
+
outputLine(" okx-auth Binary Status");
|
|
10978
|
+
outputLine(" " + "\u2500".repeat(40));
|
|
10979
|
+
outputLine(` Binary path : ${local.binaryPath}`);
|
|
10980
|
+
outputLine(` Installed : ${local.exists ? "yes" : "no"}`);
|
|
10981
|
+
outputLine(` Platform : ${local.platform ?? "(unsupported)"}`);
|
|
10982
|
+
if (local.exists) {
|
|
10983
|
+
outputLine(` File size : ${formatBytes(local.fileSize)}`);
|
|
10984
|
+
outputLine(` SHA-256 : ${local.sha256 ?? "(unknown)"}`);
|
|
10985
|
+
outputLine(` CDN check : ${checksumMatchLabel(checksumMatch)}`);
|
|
10986
|
+
if (cdnChecksum) {
|
|
10987
|
+
outputLine(` CDN source : ${cdnChecksum.source}`);
|
|
10988
|
+
}
|
|
10989
|
+
}
|
|
10990
|
+
outputLine("");
|
|
10991
|
+
}
|
|
10992
|
+
async function cmdAuthInstall(json) {
|
|
10993
|
+
const messages2 = [];
|
|
10994
|
+
const onProgress = (msg) => {
|
|
10995
|
+
if (!json) {
|
|
10996
|
+
outputLine(` ${msg}`);
|
|
10997
|
+
}
|
|
10998
|
+
messages2.push(msg);
|
|
10999
|
+
};
|
|
11000
|
+
if (!json) {
|
|
11001
|
+
outputLine("");
|
|
11002
|
+
outputLine(" Installing okx-auth...");
|
|
11003
|
+
}
|
|
11004
|
+
const result = await installAuthBinary(void 0, void 0, onProgress);
|
|
11005
|
+
if (json) {
|
|
11006
|
+
outputLine(JSON.stringify({ status: result.status, source: result.source ?? null, error: result.error ?? null, messages: messages2 }));
|
|
11007
|
+
if (result.status === "failed") {
|
|
11008
|
+
process.exitCode = 1;
|
|
11009
|
+
}
|
|
11010
|
+
return;
|
|
11011
|
+
}
|
|
11012
|
+
if (result.status === "installed" || result.status === "up-to-date") {
|
|
11013
|
+
const local = getAuthStatus();
|
|
11014
|
+
if (local.sha256) updateAuthBinaryCache(local.sha256);
|
|
11015
|
+
}
|
|
11016
|
+
if (result.status === "installed") {
|
|
11017
|
+
outputLine(` \u2713 okx-auth installed successfully (${result.source ?? ""})`);
|
|
11018
|
+
} else if (result.status === "up-to-date") {
|
|
11019
|
+
outputLine(" \u2713 okx-auth is already up to date");
|
|
11020
|
+
} else {
|
|
11021
|
+
errorLine(` \u2717 Installation failed: ${result.error ?? "unknown error"}`);
|
|
11022
|
+
errorLine(" Hint: check network connectivity or try again later");
|
|
11023
|
+
process.exitCode = 1;
|
|
11024
|
+
}
|
|
11025
|
+
outputLine("");
|
|
11026
|
+
}
|
|
11027
|
+
async function cmdAuthRemove(force, json) {
|
|
11028
|
+
const local = getAuthStatus(void 0, { skipHash: true });
|
|
11029
|
+
if (!local.exists) {
|
|
11030
|
+
if (json) {
|
|
11031
|
+
outputLine(JSON.stringify({ status: "not-installed" }));
|
|
11032
|
+
} else {
|
|
11033
|
+
outputLine(" okx-auth is not installed.");
|
|
11034
|
+
}
|
|
11035
|
+
return;
|
|
11036
|
+
}
|
|
11037
|
+
if (!await confirmRemoval(force, local.binaryPath)) return;
|
|
11038
|
+
let result;
|
|
11039
|
+
try {
|
|
11040
|
+
result = removeAuthBinary();
|
|
11041
|
+
} catch (err) {
|
|
11042
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
11043
|
+
if (json) {
|
|
11044
|
+
outputLine(JSON.stringify({ status: "failed", error: msg }));
|
|
11045
|
+
} else {
|
|
11046
|
+
errorLine(` \u2717 Failed to remove: ${msg}`);
|
|
11047
|
+
}
|
|
11048
|
+
process.exitCode = 1;
|
|
11049
|
+
return;
|
|
11050
|
+
}
|
|
11051
|
+
if (json) {
|
|
11052
|
+
outputLine(JSON.stringify({ status: result.status, path: local.binaryPath }));
|
|
11053
|
+
return;
|
|
11054
|
+
}
|
|
11055
|
+
if (result.status === "removed") {
|
|
11056
|
+
clearAuthBinaryCache();
|
|
11057
|
+
outputLine(` \u2713 Removed: ${local.binaryPath}`);
|
|
11058
|
+
} else {
|
|
11059
|
+
outputLine(" okx-auth is not installed.");
|
|
11060
|
+
}
|
|
11061
|
+
}
|
|
11062
|
+
async function confirmRemoval(force, binaryPath) {
|
|
11063
|
+
if (force) return true;
|
|
11064
|
+
if (!process.stdin.isTTY) {
|
|
11065
|
+
errorLine(" Error: stdin is not a TTY. Use --force to skip confirmation.");
|
|
11066
|
+
process.exitCode = 1;
|
|
11067
|
+
return false;
|
|
11068
|
+
}
|
|
11069
|
+
const confirmed = await askConfirmation(
|
|
11070
|
+
` Remove okx-auth at ${binaryPath}? [y/N] `
|
|
11071
|
+
);
|
|
11072
|
+
if (!confirmed) {
|
|
11073
|
+
outputLine(" Cancelled.");
|
|
11074
|
+
return false;
|
|
11075
|
+
}
|
|
11076
|
+
return true;
|
|
11077
|
+
}
|
|
11078
|
+
function askConfirmation(prompt2) {
|
|
11079
|
+
return new Promise((resolve3) => {
|
|
11080
|
+
const rl = readline.createInterface({
|
|
11081
|
+
input: process.stdin,
|
|
11082
|
+
output: process.stdout
|
|
11083
|
+
});
|
|
11084
|
+
rl.question(prompt2, (answer) => {
|
|
11085
|
+
rl.close();
|
|
11086
|
+
resolve3(answer.trim().toLowerCase() === "y");
|
|
11087
|
+
});
|
|
11088
|
+
});
|
|
11089
|
+
}
|
|
11090
|
+
async function handleAuthCommand(action, _rest, v) {
|
|
11091
|
+
const site = v.site;
|
|
11092
|
+
const json = v.json;
|
|
11093
|
+
const manual = v.manual;
|
|
11094
|
+
const force = v.force;
|
|
11095
|
+
if (["login", "logout", "status"].includes(action)) {
|
|
11096
|
+
await ensureAuthBinaryLatest((msg) => errorLine(` ${msg}`));
|
|
11097
|
+
}
|
|
11098
|
+
switch (action) {
|
|
11099
|
+
case "login":
|
|
11100
|
+
return cmdAuthLogin({ site, manual });
|
|
11101
|
+
case "logout":
|
|
11102
|
+
return cmdAuthLogout();
|
|
11103
|
+
case "status":
|
|
11104
|
+
return cmdAuthStatus({ json });
|
|
11105
|
+
case "install":
|
|
11106
|
+
return cmdAuthInstall(json ?? false);
|
|
11107
|
+
case "install-status":
|
|
11108
|
+
return cmdAuthInstallStatus(json ?? false);
|
|
11109
|
+
case "remove":
|
|
11110
|
+
return cmdAuthRemove(force ?? false, json ?? false);
|
|
11111
|
+
default:
|
|
11112
|
+
errorLine(`Unknown auth command: ${action}`);
|
|
11113
|
+
errorLine("Available: login, logout, status, install, install-status, remove");
|
|
11114
|
+
process.exitCode = 1;
|
|
11115
|
+
}
|
|
11116
|
+
}
|
|
11117
|
+
|
|
11118
|
+
// src/commands/diagnose.ts
|
|
11119
|
+
import dns from "dns/promises";
|
|
11120
|
+
import net from "net";
|
|
11121
|
+
import os5 from "os";
|
|
11122
|
+
import tls from "tls";
|
|
11123
|
+
|
|
10454
11124
|
// src/commands/diagnose-utils.ts
|
|
11125
|
+
import fs4 from "fs";
|
|
11126
|
+
import { createRequire } from "module";
|
|
10455
11127
|
var _require = createRequire(import.meta.url);
|
|
10456
11128
|
function readCliVersion() {
|
|
10457
11129
|
for (const rel of ["../package.json", "../../package.json"]) {
|
|
@@ -10537,7 +11209,7 @@ function sanitize2(value) {
|
|
|
10537
11209
|
import fs5 from "fs";
|
|
10538
11210
|
import path4 from "path";
|
|
10539
11211
|
import os4 from "os";
|
|
10540
|
-
import { spawnSync, spawn } from "child_process";
|
|
11212
|
+
import { spawnSync, spawn as spawn3 } from "child_process";
|
|
10541
11213
|
import { createRequire as createRequire2 } from "module";
|
|
10542
11214
|
import { fileURLToPath } from "url";
|
|
10543
11215
|
var _require2 = createRequire2(import.meta.url);
|
|
@@ -10871,7 +11543,7 @@ async function checkStdioHandshake(entryPath, report) {
|
|
|
10871
11543
|
clearTimeout(timer);
|
|
10872
11544
|
resolve3(passed);
|
|
10873
11545
|
};
|
|
10874
|
-
const child =
|
|
11546
|
+
const child = spawn3(process.execPath, [entryPath], {
|
|
10875
11547
|
stdio: ["pipe", "pipe", "pipe"],
|
|
10876
11548
|
env: { ...process.env }
|
|
10877
11549
|
});
|
|
@@ -10990,7 +11662,7 @@ async function cmdDiagnoseMcp(options = {}) {
|
|
|
10990
11662
|
|
|
10991
11663
|
// src/commands/diagnose.ts
|
|
10992
11664
|
var CLI_VERSION = readCliVersion();
|
|
10993
|
-
var GIT_HASH = true ? "
|
|
11665
|
+
var GIT_HASH = true ? "17e06f4" : "dev";
|
|
10994
11666
|
function maskKey2(key) {
|
|
10995
11667
|
if (!key) return "(not set)";
|
|
10996
11668
|
if (key.length <= 8) return "****";
|
|
@@ -11326,24 +11998,24 @@ async function runCliChecks(config, profile, outputPath) {
|
|
|
11326
11998
|
|
|
11327
11999
|
// src/commands/upgrade.ts
|
|
11328
12000
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
11329
|
-
import { readFileSync as
|
|
11330
|
-
import { dirname as
|
|
11331
|
-
import { homedir as
|
|
12001
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, mkdirSync as mkdirSync11 } from "fs";
|
|
12002
|
+
import { dirname as dirname8, join as join13 } from "path";
|
|
12003
|
+
import { homedir as homedir11 } from "os";
|
|
11332
12004
|
var PACKAGES = ["@okx_ai/okx-trade-mcp", "@okx_ai/okx-trade-cli"];
|
|
11333
|
-
var CACHE_FILE2 =
|
|
12005
|
+
var CACHE_FILE2 = join13(homedir11(), ".okx", "last_check");
|
|
11334
12006
|
var THROTTLE_MS = 12 * 60 * 60 * 1e3;
|
|
11335
|
-
var NPM_BIN =
|
|
12007
|
+
var NPM_BIN = join13(dirname8(process.execPath), process.platform === "win32" ? "npm.cmd" : "npm");
|
|
11336
12008
|
function readLastCheck() {
|
|
11337
12009
|
try {
|
|
11338
|
-
return parseInt(
|
|
12010
|
+
return parseInt(readFileSync9(CACHE_FILE2, "utf-8").trim(), 10) || 0;
|
|
11339
12011
|
} catch {
|
|
11340
12012
|
return 0;
|
|
11341
12013
|
}
|
|
11342
12014
|
}
|
|
11343
12015
|
function writeLastCheck() {
|
|
11344
12016
|
try {
|
|
11345
|
-
|
|
11346
|
-
|
|
12017
|
+
mkdirSync11(join13(homedir11(), ".okx"), { recursive: true });
|
|
12018
|
+
writeFileSync8(CACHE_FILE2, String(Math.floor(Date.now() / 1e3)), "utf-8");
|
|
11347
12019
|
} catch {
|
|
11348
12020
|
}
|
|
11349
12021
|
}
|
|
@@ -12314,24 +12986,24 @@ var CLI_REGISTRY = {
|
|
|
12314
12986
|
commands: {
|
|
12315
12987
|
latest: {
|
|
12316
12988
|
toolName: "news_get_latest",
|
|
12317
|
-
usage: "okx news latest [--coins BTC,ETH] [--lang
|
|
12989
|
+
usage: "okx news latest [--coins BTC,ETH] [--lang zh_CN] [--limit 20]"
|
|
12318
12990
|
},
|
|
12319
12991
|
important: {
|
|
12320
12992
|
toolName: "news_get_latest",
|
|
12321
|
-
usage: "okx news important [--coins BTC,ETH] [--lang
|
|
12993
|
+
usage: "okx news important [--coins BTC,ETH] [--lang zh_CN] [--limit 20]",
|
|
12322
12994
|
description: "Get important/high-impact crypto news"
|
|
12323
12995
|
},
|
|
12324
12996
|
"by-coin": {
|
|
12325
12997
|
toolName: "news_get_by_coin",
|
|
12326
|
-
usage: "okx news by-coin --coins BTC [--importance high] [--lang
|
|
12998
|
+
usage: "okx news by-coin --coins BTC [--importance high] [--lang zh_CN]"
|
|
12327
12999
|
},
|
|
12328
13000
|
search: {
|
|
12329
13001
|
toolName: "news_search",
|
|
12330
|
-
usage: "okx news search --keyword <term> [--coins BTC] [--sentiment bullish] [--lang
|
|
13002
|
+
usage: "okx news search --keyword <term> [--coins BTC] [--sentiment bullish] [--lang zh_CN]"
|
|
12331
13003
|
},
|
|
12332
13004
|
detail: {
|
|
12333
13005
|
toolName: "news_get_detail",
|
|
12334
|
-
usage: "okx news detail <id> [--lang
|
|
13006
|
+
usage: "okx news detail <id> [--lang zh_CN]"
|
|
12335
13007
|
},
|
|
12336
13008
|
domains: {
|
|
12337
13009
|
toolName: "news_get_domains",
|
|
@@ -12763,7 +13435,7 @@ async function cmdNewsSentimentRank(run, opts) {
|
|
|
12763
13435
|
}
|
|
12764
13436
|
|
|
12765
13437
|
// src/config/loader.ts
|
|
12766
|
-
function loadProfileConfig(opts) {
|
|
13438
|
+
async function loadProfileConfig(opts) {
|
|
12767
13439
|
return loadConfig({
|
|
12768
13440
|
profile: opts.profile,
|
|
12769
13441
|
modules: opts.modules,
|
|
@@ -13081,6 +13753,9 @@ var CLI_OPTIONS = {
|
|
|
13081
13753
|
dir: { type: "string" },
|
|
13082
13754
|
page: { type: "string" },
|
|
13083
13755
|
format: { type: "string" },
|
|
13756
|
+
// auth
|
|
13757
|
+
site: { type: "string" },
|
|
13758
|
+
manual: { type: "boolean", default: false },
|
|
13084
13759
|
// event contract
|
|
13085
13760
|
underlying: { type: "string" },
|
|
13086
13761
|
seriesId: { type: "string" },
|
|
@@ -16095,14 +16770,14 @@ async function cmdDcdQuoteAndBuy(run, opts) {
|
|
|
16095
16770
|
}
|
|
16096
16771
|
|
|
16097
16772
|
// src/commands/skill.ts
|
|
16098
|
-
import { tmpdir, homedir as
|
|
16099
|
-
import { join as
|
|
16100
|
-
import { mkdirSync as
|
|
16773
|
+
import { tmpdir, homedir as homedir13 } from "os";
|
|
16774
|
+
import { join as join15, dirname as dirname9 } from "path";
|
|
16775
|
+
import { mkdirSync as mkdirSync12, rmSync, existsSync as existsSync10, copyFileSync as copyFileSync2 } from "fs";
|
|
16101
16776
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
16102
16777
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
16103
16778
|
function resolveNpx() {
|
|
16104
|
-
const sibling =
|
|
16105
|
-
if (
|
|
16779
|
+
const sibling = join15(dirname9(process.execPath), "npx");
|
|
16780
|
+
if (existsSync10(sibling)) return sibling;
|
|
16106
16781
|
return "npx";
|
|
16107
16782
|
}
|
|
16108
16783
|
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 +16830,13 @@ async function cmdSkillCategories(run, json) {
|
|
|
16155
16830
|
outputLine("");
|
|
16156
16831
|
}
|
|
16157
16832
|
async function cmdSkillAdd(name, config, json) {
|
|
16158
|
-
const tmpBase =
|
|
16159
|
-
|
|
16833
|
+
const tmpBase = join15(tmpdir(), `okx-skill-${randomUUID2()}`);
|
|
16834
|
+
mkdirSync12(tmpBase, { recursive: true });
|
|
16160
16835
|
try {
|
|
16161
16836
|
outputLine(`Downloading ${name}...`);
|
|
16162
16837
|
const client = new OkxRestClient(config);
|
|
16163
16838
|
const zipPath = await downloadSkillZip(client, name, tmpBase);
|
|
16164
|
-
const contentDir = await extractSkillZip(zipPath,
|
|
16839
|
+
const contentDir = await extractSkillZip(zipPath, join15(tmpBase, "content"));
|
|
16165
16840
|
const meta = readMetaJson(contentDir);
|
|
16166
16841
|
validateSkillMdExists(contentDir);
|
|
16167
16842
|
outputLine("Installing to detected agents...");
|
|
@@ -16171,7 +16846,7 @@ async function cmdSkillAdd(name, config, json) {
|
|
|
16171
16846
|
timeout: 6e4
|
|
16172
16847
|
});
|
|
16173
16848
|
} catch (e) {
|
|
16174
|
-
const savedZip =
|
|
16849
|
+
const savedZip = join15(process.cwd(), `${name}.zip`);
|
|
16175
16850
|
try {
|
|
16176
16851
|
copyFileSync2(zipPath, savedZip);
|
|
16177
16852
|
} catch {
|
|
@@ -16210,7 +16885,7 @@ function cmdSkillRemove(name, json) {
|
|
|
16210
16885
|
timeout: 6e4
|
|
16211
16886
|
});
|
|
16212
16887
|
} catch {
|
|
16213
|
-
const agentsPath =
|
|
16888
|
+
const agentsPath = join15(homedir13(), ".agents", "skills", name);
|
|
16214
16889
|
try {
|
|
16215
16890
|
rmSync(agentsPath, { recursive: true, force: true });
|
|
16216
16891
|
} catch {
|
|
@@ -16284,14 +16959,14 @@ function printSkillInstallResult(meta, json) {
|
|
|
16284
16959
|
}
|
|
16285
16960
|
|
|
16286
16961
|
// src/commands/doh.ts
|
|
16287
|
-
import
|
|
16288
|
-
function
|
|
16962
|
+
import readline2 from "readline";
|
|
16963
|
+
function resolveChecksumMatch2(local, cdnChecksum, cdnError) {
|
|
16289
16964
|
if (!local.exists) return "not-installed";
|
|
16290
16965
|
if (cdnError || !cdnChecksum) return "unavailable";
|
|
16291
16966
|
if (cdnChecksum.sha256 === local.sha256) return "match";
|
|
16292
16967
|
return "mismatch";
|
|
16293
16968
|
}
|
|
16294
|
-
function
|
|
16969
|
+
function checksumMatchLabel2(match) {
|
|
16295
16970
|
if (match === "match") return "\u2713 match";
|
|
16296
16971
|
if (match === "mismatch") return "\u2717 mismatch (update available)";
|
|
16297
16972
|
return "CDN unreachable";
|
|
@@ -16304,9 +16979,9 @@ function formatStatusText(local, checksumMatch, cdnChecksum, runtimeMode) {
|
|
|
16304
16979
|
outputLine(` Installed : ${local.exists ? "yes" : "no"}`);
|
|
16305
16980
|
outputLine(` Platform : ${local.platform ?? "(unsupported)"}`);
|
|
16306
16981
|
if (local.exists) {
|
|
16307
|
-
outputLine(` File size : ${
|
|
16982
|
+
outputLine(` File size : ${formatBytes2(local.fileSize)}`);
|
|
16308
16983
|
outputLine(` SHA-256 : ${local.sha256 ?? "(unknown)"}`);
|
|
16309
|
-
outputLine(` CDN check : ${
|
|
16984
|
+
outputLine(` CDN check : ${checksumMatchLabel2(checksumMatch)}`);
|
|
16310
16985
|
if (cdnChecksum) {
|
|
16311
16986
|
outputLine(` CDN source : ${cdnChecksum.source}`);
|
|
16312
16987
|
}
|
|
@@ -16333,7 +17008,7 @@ async function cmdDohStatus(json, binaryPath) {
|
|
|
16333
17008
|
cdnError = err instanceof Error ? err.message : String(err);
|
|
16334
17009
|
}
|
|
16335
17010
|
}
|
|
16336
|
-
const checksumMatch =
|
|
17011
|
+
const checksumMatch = resolveChecksumMatch2(local, cdnChecksum, cdnError);
|
|
16337
17012
|
if (json) {
|
|
16338
17013
|
outputLine(
|
|
16339
17014
|
JSON.stringify({
|
|
@@ -16399,7 +17074,7 @@ async function cmdDohRemove(force, json, binaryPath) {
|
|
|
16399
17074
|
process.exitCode = 1;
|
|
16400
17075
|
return;
|
|
16401
17076
|
}
|
|
16402
|
-
const confirmed = await
|
|
17077
|
+
const confirmed = await askConfirmation2(
|
|
16403
17078
|
` Remove DoH resolver at ${local.binaryPath}? [y/N] `
|
|
16404
17079
|
);
|
|
16405
17080
|
if (!confirmed) {
|
|
@@ -16418,14 +17093,14 @@ async function cmdDohRemove(force, json, binaryPath) {
|
|
|
16418
17093
|
outputLine(" DoH resolver is not installed.");
|
|
16419
17094
|
}
|
|
16420
17095
|
}
|
|
16421
|
-
function
|
|
17096
|
+
function formatBytes2(bytes) {
|
|
16422
17097
|
if (bytes < 1024) return `${bytes} B`;
|
|
16423
17098
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
16424
17099
|
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
16425
17100
|
}
|
|
16426
|
-
function
|
|
17101
|
+
function askConfirmation2(prompt2) {
|
|
16427
17102
|
return new Promise((resolve3) => {
|
|
16428
|
-
const rl =
|
|
17103
|
+
const rl = readline2.createInterface({
|
|
16429
17104
|
input: process.stdin,
|
|
16430
17105
|
output: process.stdout
|
|
16431
17106
|
});
|
|
@@ -16882,7 +17557,7 @@ async function cmdEventCancel(run, opts) {
|
|
|
16882
17557
|
// src/index.ts
|
|
16883
17558
|
var _require3 = createRequire3(import.meta.url);
|
|
16884
17559
|
var CLI_VERSION2 = _require3("../package.json").version;
|
|
16885
|
-
var GIT_HASH2 = true ? "
|
|
17560
|
+
var GIT_HASH2 = true ? "17e06f4" : "dev";
|
|
16886
17561
|
function handleDohCommand(action, json, force, binaryPath) {
|
|
16887
17562
|
if (action === "status") return cmdDohStatus(json, binaryPath);
|
|
16888
17563
|
if (action === "install") return cmdDohInstall(json, binaryPath);
|
|
@@ -17726,7 +18401,7 @@ function handleNewsCommand(run, action, rest, v, json) {
|
|
|
17726
18401
|
const limit = v.limit !== void 0 ? Number(v.limit) : void 0;
|
|
17727
18402
|
const begin = v.begin !== void 0 ? Number(v.begin) : void 0;
|
|
17728
18403
|
const end = v.end !== void 0 ? Number(v.end) : void 0;
|
|
17729
|
-
const language = v.lang ?? "
|
|
18404
|
+
const language = v.lang ?? "en_US";
|
|
17730
18405
|
const detailLvl = v["detail-lvl"];
|
|
17731
18406
|
const after = v.after;
|
|
17732
18407
|
const period = v.period;
|
|
@@ -17857,7 +18532,7 @@ function wrapRunnerWithLogger(baseRunner, logger, verbose = false) {
|
|
|
17857
18532
|
async function runDiagnose(v) {
|
|
17858
18533
|
let config;
|
|
17859
18534
|
try {
|
|
17860
|
-
config = loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
|
|
18535
|
+
config = await loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
|
|
17861
18536
|
} catch {
|
|
17862
18537
|
}
|
|
17863
18538
|
return cmdDiagnose(config, v.profile ?? "default", { mcp: v.mcp, cli: v.cli, all: v.all, output: v.output });
|
|
@@ -17872,24 +18547,13 @@ function printVersion() {
|
|
|
17872
18547
|
}
|
|
17873
18548
|
}
|
|
17874
18549
|
function routeManagementCommand(module, action, rest, json, v) {
|
|
17875
|
-
if (module === "config")
|
|
17876
|
-
|
|
17877
|
-
|
|
17878
|
-
}
|
|
17879
|
-
if (module === "setup") {
|
|
17880
|
-
handleSetupCommand(v);
|
|
17881
|
-
return true;
|
|
17882
|
-
}
|
|
18550
|
+
if (module === "config") return handleConfigCommand(action, rest, json, v.lang, v.force);
|
|
18551
|
+
if (module === "setup") return handleSetupCommand(v);
|
|
18552
|
+
if (module === "auth") return handleAuthCommand(action, rest, v);
|
|
17883
18553
|
if (module === "upgrade") return cmdUpgrade(CLI_VERSION2, { beta: v.beta, check: v.check, force: v.force }, json);
|
|
17884
|
-
if (module === "doh")
|
|
17885
|
-
const r = handleDohCommand(action, json, v.force ?? false);
|
|
17886
|
-
return r ?? true;
|
|
17887
|
-
}
|
|
18554
|
+
if (module === "doh") return handleDohCommand(action, json, v.force ?? false);
|
|
17888
18555
|
if (module === "diagnose") return runDiagnose(v);
|
|
17889
|
-
if (module === "list-tools")
|
|
17890
|
-
cmdListTools(json);
|
|
17891
|
-
return true;
|
|
17892
|
-
}
|
|
18556
|
+
if (module === "list-tools") return cmdListTools(json);
|
|
17893
18557
|
return void 0;
|
|
17894
18558
|
}
|
|
17895
18559
|
async function main() {
|
|
@@ -17911,8 +18575,8 @@ async function main() {
|
|
|
17911
18575
|
const v = values;
|
|
17912
18576
|
const json = v.json ?? false;
|
|
17913
18577
|
const mgmt = routeManagementCommand(module, action, rest, json, v);
|
|
17914
|
-
if (mgmt
|
|
17915
|
-
const config = loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
|
|
18578
|
+
if (mgmt) return mgmt;
|
|
18579
|
+
const config = await loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
|
|
17916
18580
|
setEnvContext({ demo: config.demo, profile: v.profile ?? "default" });
|
|
17917
18581
|
setJsonEnvEnabled(v.env ?? false);
|
|
17918
18582
|
const client = new OkxRestClient(config);
|