@okx_ai/okx-trade-cli 1.3.1-beta.8 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +172 -734
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/postinstall.js +1 -78
package/dist/index.js
CHANGED
|
@@ -21,26 +21,23 @@ 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";
|
|
27
24
|
import fs from "fs";
|
|
28
25
|
import path from "path";
|
|
29
26
|
import os from "os";
|
|
30
27
|
import { writeFileSync as writeFileSync2, renameSync as renameSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
31
|
-
import { join as
|
|
28
|
+
import { join as join3, resolve, basename, sep } from "path";
|
|
32
29
|
import { randomUUID } from "crypto";
|
|
33
30
|
import yauzl from "yauzl";
|
|
34
31
|
import { createWriteStream, mkdirSync as mkdirSync3 } from "fs";
|
|
35
32
|
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
36
33
|
import { readFileSync as readFileSync2, existsSync } from "fs";
|
|
37
|
-
import { join as
|
|
34
|
+
import { join as join4 } from "path";
|
|
38
35
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync2 } from "fs";
|
|
39
|
-
import { join as
|
|
40
|
-
import { homedir as
|
|
36
|
+
import { join as join5, dirname as dirname3 } from "path";
|
|
37
|
+
import { homedir as homedir3 } from "os";
|
|
41
38
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync3 } from "fs";
|
|
42
|
-
import { join as
|
|
43
|
-
import { homedir as
|
|
39
|
+
import { join as join6, dirname as dirname4 } from "path";
|
|
40
|
+
import { homedir as homedir4 } from "os";
|
|
44
41
|
|
|
45
42
|
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/error.js
|
|
46
43
|
function getLineColFromPtr(string, ptr) {
|
|
@@ -870,8 +867,8 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
|
870
867
|
|
|
871
868
|
// ../core/dist/index.js
|
|
872
869
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync4 } from "fs";
|
|
873
|
-
import { join as
|
|
874
|
-
import { homedir as
|
|
870
|
+
import { join as join7 } from "path";
|
|
871
|
+
import { homedir as homedir5 } from "os";
|
|
875
872
|
import fs2 from "fs";
|
|
876
873
|
import path2 from "path";
|
|
877
874
|
import os2 from "os";
|
|
@@ -879,18 +876,6 @@ import * as fs3 from "fs";
|
|
|
879
876
|
import * as path3 from "path";
|
|
880
877
|
import * as os3 from "os";
|
|
881
878
|
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";
|
|
894
879
|
import {
|
|
895
880
|
readFileSync as readFileSync7,
|
|
896
881
|
createWriteStream as createWriteStream2,
|
|
@@ -901,8 +886,8 @@ import {
|
|
|
901
886
|
renameSync as renameSync3
|
|
902
887
|
} from "fs";
|
|
903
888
|
import { createHash } from "crypto";
|
|
904
|
-
import { homedir as
|
|
905
|
-
import { join as
|
|
889
|
+
import { homedir as homedir7, platform, arch } from "os";
|
|
890
|
+
import { join as join9, dirname as dirname6 } from "path";
|
|
906
891
|
import { get as httpsGet } from "https";
|
|
907
892
|
import { get as httpGet } from "http";
|
|
908
893
|
var EXEC_TIMEOUT_MS = 3e4;
|
|
@@ -913,7 +898,7 @@ function getDohBinaryPath() {
|
|
|
913
898
|
return process.env.OKX_DOH_BINARY_PATH;
|
|
914
899
|
}
|
|
915
900
|
const ext = process.platform === "win32" ? ".exe" : "";
|
|
916
|
-
return join(DOH_BIN_DIR, `okx-
|
|
901
|
+
return join(DOH_BIN_DIR, `okx-pilot${ext}`);
|
|
917
902
|
}
|
|
918
903
|
function execDohBinary(domain, exclude = [], userAgent) {
|
|
919
904
|
if (!ALLOWED_DOMAIN_RE.test(domain)) {
|
|
@@ -984,7 +969,7 @@ function classifyAndCache(node, hostname, failedNodes, cachePath) {
|
|
|
984
969
|
if (!node) {
|
|
985
970
|
return { mode: null, node: null };
|
|
986
971
|
}
|
|
987
|
-
if (node.ip === hostname
|
|
972
|
+
if (node.ip === hostname && node.host === hostname) {
|
|
988
973
|
writeCache(hostname, {
|
|
989
974
|
mode: "direct",
|
|
990
975
|
node: null,
|
|
@@ -1216,11 +1201,6 @@ var ConfigError = class extends OkxMcpError {
|
|
|
1216
1201
|
super("ConfigError", message, { suggestion });
|
|
1217
1202
|
}
|
|
1218
1203
|
};
|
|
1219
|
-
var NotLoggedInError = class extends ConfigError {
|
|
1220
|
-
constructor(suggestion = "Run `okx auth login` to authenticate.") {
|
|
1221
|
-
super("Not logged in.", suggestion);
|
|
1222
|
-
}
|
|
1223
|
-
};
|
|
1224
1204
|
var ValidationError = class extends OkxMcpError {
|
|
1225
1205
|
constructor(message, suggestion) {
|
|
1226
1206
|
super("ValidationError", message, { suggestion });
|
|
@@ -1273,97 +1253,6 @@ function toToolErrorPayload(error, fallbackEndpoint) {
|
|
|
1273
1253
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1274
1254
|
};
|
|
1275
1255
|
}
|
|
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
|
-
}
|
|
1367
1256
|
function sleep(ms) {
|
|
1368
1257
|
return new Promise((resolve3) => {
|
|
1369
1258
|
setTimeout(resolve3, ms);
|
|
@@ -1442,10 +1331,10 @@ var OKX_CODE_BEHAVIORS = {
|
|
|
1442
1331
|
"50011": { retry: true, suggestion: "Rate limited. Back off and retry after a delay." },
|
|
1443
1332
|
"50061": { retry: true, suggestion: "Too many connections. Reduce request frequency and retry." },
|
|
1444
1333
|
// Server temporarily unavailable → retryable
|
|
1445
|
-
"50001": { retry: true, suggestion: "
|
|
1446
|
-
"50004": { retry: true, suggestion: "Endpoint
|
|
1334
|
+
"50001": { retry: true, suggestion: "Service temporarily unavailable. Retry in a few minutes." },
|
|
1335
|
+
"50004": { retry: true, suggestion: "Endpoint request timeout. Retry later." },
|
|
1447
1336
|
"50013": { retry: true, suggestion: "System busy. Retry after 1-2 seconds." },
|
|
1448
|
-
"50026": { retry: true, suggestion: "
|
|
1337
|
+
"50026": { retry: true, suggestion: "System error. Retry in a few minutes." },
|
|
1449
1338
|
// Region / compliance restriction → do not retry
|
|
1450
1339
|
"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." },
|
|
1451
1340
|
"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." },
|
|
@@ -1495,7 +1384,6 @@ function maskKey(key) {
|
|
|
1495
1384
|
if (key.length <= 8) return "***";
|
|
1496
1385
|
return `${key.slice(0, 3)}***${key.slice(-3)}`;
|
|
1497
1386
|
}
|
|
1498
|
-
var TOKEN_CACHE_TTL_MS = 6e4;
|
|
1499
1387
|
function vlog2(message) {
|
|
1500
1388
|
process.stderr.write(`[verbose] ${message}
|
|
1501
1389
|
`);
|
|
@@ -1504,8 +1392,6 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1504
1392
|
config;
|
|
1505
1393
|
rateLimiter;
|
|
1506
1394
|
dispatcher;
|
|
1507
|
-
cachedAccessToken;
|
|
1508
|
-
cachedAccessTokenAt = 0;
|
|
1509
1395
|
doh;
|
|
1510
1396
|
constructor(config) {
|
|
1511
1397
|
this.config = config;
|
|
@@ -1520,51 +1406,6 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1520
1406
|
hasCustomProxy: !!config.proxyUrl
|
|
1521
1407
|
});
|
|
1522
1408
|
}
|
|
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
|
-
}
|
|
1568
1409
|
/** The canonical base URL for this client (e.g. https://www.okx.com). */
|
|
1569
1410
|
get baseUrl() {
|
|
1570
1411
|
return this.config.baseUrl;
|
|
@@ -1622,6 +1463,18 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1622
1463
|
});
|
|
1623
1464
|
}
|
|
1624
1465
|
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
|
+
}
|
|
1625
1478
|
const payload = `${timestamp}${method.toUpperCase()}${requestPath}${bodyJson}`;
|
|
1626
1479
|
const signature = signOkxPayload(payload, this.config.secretKey);
|
|
1627
1480
|
headers.set("OK-ACCESS-KEY", this.config.apiKey);
|
|
@@ -1736,7 +1589,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1736
1589
|
const conn = this.doh.getConnectionParams();
|
|
1737
1590
|
this.logRequest("POST", `${conn.baseUrl}${path42}`, "private");
|
|
1738
1591
|
const reqConfig = { method: "POST", path: path42, auth: "private" };
|
|
1739
|
-
const headers =
|
|
1592
|
+
const headers = this.buildHeaders(reqConfig, path42, bodyJson, getNow());
|
|
1740
1593
|
if (conn.userAgent) {
|
|
1741
1594
|
headers.set("User-Agent", conn.userAgent);
|
|
1742
1595
|
}
|
|
@@ -1853,7 +1706,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1853
1706
|
// Header building
|
|
1854
1707
|
// ---------------------------------------------------------------------------
|
|
1855
1708
|
/** Build HTTP headers. reqConfig.extraHeaders must NOT contain auth keys (OK-ACCESS-*). */
|
|
1856
|
-
|
|
1709
|
+
buildHeaders(reqConfig, requestPath, bodyJson, timestamp) {
|
|
1857
1710
|
const headers = new Headers({
|
|
1858
1711
|
"Content-Type": "application/json",
|
|
1859
1712
|
Accept: "application/json"
|
|
@@ -1862,7 +1715,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1862
1715
|
headers.set("User-Agent", this.config.userAgent);
|
|
1863
1716
|
}
|
|
1864
1717
|
if (reqConfig.auth === "private") {
|
|
1865
|
-
|
|
1718
|
+
this.setAuthHeaders(headers, reqConfig.method, requestPath, bodyJson, timestamp);
|
|
1866
1719
|
}
|
|
1867
1720
|
const useSimulated = reqConfig.simulatedTrading !== void 0 ? reqConfig.simulatedTrading : this.config.demo;
|
|
1868
1721
|
if (useSimulated) {
|
|
@@ -1916,7 +1769,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1916
1769
|
if (reqConfig.rateLimit) {
|
|
1917
1770
|
await this.rateLimiter.consume(reqConfig.rateLimit);
|
|
1918
1771
|
}
|
|
1919
|
-
const headers =
|
|
1772
|
+
const headers = this.buildHeaders(reqConfig, requestPath, bodyJson, timestamp);
|
|
1920
1773
|
if (conn.userAgent) {
|
|
1921
1774
|
headers.set("User-Agent", conn.userAgent);
|
|
1922
1775
|
}
|
|
@@ -2339,7 +2192,7 @@ var OKX_SITES = {
|
|
|
2339
2192
|
},
|
|
2340
2193
|
us: {
|
|
2341
2194
|
label: "US",
|
|
2342
|
-
apiBaseUrl: "https://
|
|
2195
|
+
apiBaseUrl: "https://app.okx.com",
|
|
2343
2196
|
webUrl: "https://app.okx.com"
|
|
2344
2197
|
}
|
|
2345
2198
|
};
|
|
@@ -3869,7 +3722,7 @@ function safeWriteFile(targetDir, fileName, data) {
|
|
|
3869
3722
|
throw new Error(`Invalid file name: "${fileName}"`);
|
|
3870
3723
|
}
|
|
3871
3724
|
const resolvedDir = resolve(targetDir);
|
|
3872
|
-
const filePath =
|
|
3725
|
+
const filePath = join3(resolvedDir, safeName);
|
|
3873
3726
|
const resolvedPath = resolve(filePath);
|
|
3874
3727
|
if (!resolvedPath.startsWith(resolvedDir + sep)) {
|
|
3875
3728
|
throw new Error(`Path traversal detected: "${fileName}" resolves outside target directory`);
|
|
@@ -3997,7 +3850,7 @@ async function extractSkillZip(zipPath, targetDir, limits) {
|
|
|
3997
3850
|
});
|
|
3998
3851
|
}
|
|
3999
3852
|
function readMetaJson(contentDir) {
|
|
4000
|
-
const metaPath =
|
|
3853
|
+
const metaPath = join4(contentDir, "_meta.json");
|
|
4001
3854
|
if (!existsSync(metaPath)) {
|
|
4002
3855
|
throw new Error(`_meta.json not found in ${contentDir}. Invalid skill package.`);
|
|
4003
3856
|
}
|
|
@@ -4023,12 +3876,12 @@ function readMetaJson(contentDir) {
|
|
|
4023
3876
|
};
|
|
4024
3877
|
}
|
|
4025
3878
|
function validateSkillMdExists(contentDir) {
|
|
4026
|
-
const skillMdPath =
|
|
3879
|
+
const skillMdPath = join4(contentDir, "SKILL.md");
|
|
4027
3880
|
if (!existsSync(skillMdPath)) {
|
|
4028
3881
|
throw new Error(`SKILL.md not found in ${contentDir}. Invalid skill package.`);
|
|
4029
3882
|
}
|
|
4030
3883
|
}
|
|
4031
|
-
var DEFAULT_REGISTRY_PATH =
|
|
3884
|
+
var DEFAULT_REGISTRY_PATH = join5(homedir3(), ".okx", "skills", "registry.json");
|
|
4032
3885
|
function readRegistry(registryPath = DEFAULT_REGISTRY_PATH) {
|
|
4033
3886
|
if (!existsSync2(registryPath)) {
|
|
4034
3887
|
return { version: 1, skills: {} };
|
|
@@ -5366,7 +5219,7 @@ function registerOnchainEarnTools() {
|
|
|
5366
5219
|
];
|
|
5367
5220
|
}
|
|
5368
5221
|
var DCD_CODE_BEHAVIORS = {
|
|
5369
|
-
"50001": { retry: true, suggestion: "
|
|
5222
|
+
"50001": { retry: true, suggestion: "Service temporarily unavailable. Retry in a few minutes." },
|
|
5370
5223
|
"50002": { retry: false, suggestion: "Invalid JSON in request body. This is likely a bug \u2014 check request parameters." },
|
|
5371
5224
|
"50014": { retry: false, suggestion: "Missing required parameter. Check that all required fields are provided." },
|
|
5372
5225
|
"50016": { retry: false, suggestion: "notionalCcy does not match productId option type. Use baseCcy for CALL, quoteCcy for PUT." },
|
|
@@ -7984,38 +7837,40 @@ var NEWS_DETAIL = "/api/v5/orbit/news-detail";
|
|
|
7984
7837
|
var NEWS_DOMAINS = "/api/v5/orbit/news-platform";
|
|
7985
7838
|
var SENTIMENT_QUERY = "/api/v5/orbit/currency-sentiment-query";
|
|
7986
7839
|
var SENTIMENT_RANKING = "/api/v5/orbit/currency-sentiment-ranking";
|
|
7987
|
-
var NEWS_LANGUAGE = ["
|
|
7840
|
+
var NEWS_LANGUAGE = ["en-US", "zh-CN"];
|
|
7988
7841
|
function langHeader(lang) {
|
|
7989
|
-
|
|
7990
|
-
return { "Accept-Language":
|
|
7842
|
+
if (lang === "zh-CN" || lang === "zh_CN") return { "Accept-Language": "zh-CN" };
|
|
7843
|
+
return { "Accept-Language": "en-US" };
|
|
7991
7844
|
}
|
|
7992
7845
|
var NEWS_DETAIL_LVL = ["brief", "summary", "full"];
|
|
7993
|
-
var NEWS_IMPORTANCE = ["high", "
|
|
7846
|
+
var NEWS_IMPORTANCE = ["high", "low"];
|
|
7994
7847
|
var NEWS_SENTIMENT = ["bullish", "bearish", "neutral"];
|
|
7995
7848
|
var NEWS_SORT = ["latest", "relevant"];
|
|
7996
7849
|
var SENTIMENT_PERIOD = ["1h", "4h", "24h"];
|
|
7997
7850
|
var D_COINS_NEWS = 'Comma-separated uppercase ticker symbols (e.g. "BTC,ETH"). Normalize names/aliases to standard tickers.';
|
|
7998
7851
|
var D_COINS_SENTIMENT = 'Comma-separated uppercase ticker symbols, max 20 (e.g. "BTC,ETH"). Normalize names/aliases to standard tickers.';
|
|
7999
|
-
var D_LANGUAGE = "Content language:
|
|
8000
|
-
var D_BEGIN = "Start time, Unix epoch milliseconds.
|
|
7852
|
+
var D_LANGUAGE = "Content language: zh-CN or en-US. Infer from user's message. No server default.";
|
|
7853
|
+
var D_BEGIN = "Start time, Unix epoch milliseconds. API defaults to 72 hours ago when omitted. Pass explicitly for older topics (e.g. 'last 30 days'). Max range: 180 days. Parse relative time if given.";
|
|
8001
7854
|
var D_END = "End time, Unix epoch milliseconds. Parse relative time if given. Omit for no upper bound.";
|
|
8002
|
-
var D_IMPORTANCE = "Importance filter: high (server default)
|
|
7855
|
+
var D_IMPORTANCE = "Importance filter: high (server default) or low. Omit unless user wants broader coverage.";
|
|
7856
|
+
var D_PLATFORM = "Filter by news source. Use values from news_get_domains (e.g. blockbeats, odaily_flash). Omit for all sources.";
|
|
8003
7857
|
var D_LIMIT = "Number of results (default 10, max 50).";
|
|
8004
7858
|
function registerNewsTools() {
|
|
8005
|
-
|
|
7859
|
+
const tools = [
|
|
8006
7860
|
// -----------------------------------------------------------------------
|
|
8007
7861
|
// News browsing tools
|
|
8008
7862
|
// -----------------------------------------------------------------------
|
|
8009
7863
|
{
|
|
8010
7864
|
name: "news_get_latest",
|
|
8011
7865
|
module: "news",
|
|
8012
|
-
description: "Get crypto news sorted by time. Omitting importance still returns only high-importance news (server default). Pass importance='
|
|
7866
|
+
description: "Get crypto news sorted by time. Omitting importance still returns only high-importance news (server default). Pass importance='low' explicitly to broaden results. Use when user asks 'what happened recently', 'latest news', 'any big news today', or wants to browse without a keyword. For coin-specific news, use news_get_by_coin instead.",
|
|
8013
7867
|
isWrite: false,
|
|
8014
7868
|
inputSchema: {
|
|
8015
7869
|
type: "object",
|
|
8016
7870
|
properties: {
|
|
8017
7871
|
coins: { type: "string", description: D_COINS_NEWS + " Optional." },
|
|
8018
7872
|
importance: { type: "string", enum: [...NEWS_IMPORTANCE], description: D_IMPORTANCE },
|
|
7873
|
+
platform: { type: "string", description: D_PLATFORM },
|
|
8019
7874
|
begin: { type: "number", description: D_BEGIN },
|
|
8020
7875
|
end: { type: "number", description: D_END },
|
|
8021
7876
|
language: { type: "string", enum: [...NEWS_LANGUAGE], description: D_LANGUAGE },
|
|
@@ -8036,6 +7891,7 @@ function registerNewsTools() {
|
|
|
8036
7891
|
compactObject({
|
|
8037
7892
|
sortBy: "latest",
|
|
8038
7893
|
importance: readString(args, "importance"),
|
|
7894
|
+
platform: readString(args, "platform"),
|
|
8039
7895
|
ccyList: readString(args, "coins"),
|
|
8040
7896
|
begin: readNumber(args, "begin"),
|
|
8041
7897
|
end: readNumber(args, "end"),
|
|
@@ -8059,6 +7915,7 @@ function registerNewsTools() {
|
|
|
8059
7915
|
properties: {
|
|
8060
7916
|
coins: { type: "string", description: D_COINS_NEWS + " Required." },
|
|
8061
7917
|
importance: { type: "string", enum: [...NEWS_IMPORTANCE], description: D_IMPORTANCE },
|
|
7918
|
+
platform: { type: "string", description: D_PLATFORM },
|
|
8062
7919
|
begin: { type: "number", description: D_BEGIN },
|
|
8063
7920
|
end: { type: "number", description: D_END },
|
|
8064
7921
|
language: { type: "string", enum: [...NEWS_LANGUAGE], description: D_LANGUAGE },
|
|
@@ -8079,6 +7936,7 @@ function registerNewsTools() {
|
|
|
8079
7936
|
sortBy: "latest",
|
|
8080
7937
|
ccyList: coins,
|
|
8081
7938
|
importance: readString(args, "importance"),
|
|
7939
|
+
platform: readString(args, "platform"),
|
|
8082
7940
|
begin: readNumber(args, "begin"),
|
|
8083
7941
|
end: readNumber(args, "end"),
|
|
8084
7942
|
detailLvl: readString(args, "detailLvl"),
|
|
@@ -8104,6 +7962,7 @@ function registerNewsTools() {
|
|
|
8104
7962
|
},
|
|
8105
7963
|
coins: { type: "string", description: D_COINS_NEWS + " Optional." },
|
|
8106
7964
|
importance: { type: "string", enum: [...NEWS_IMPORTANCE], description: D_IMPORTANCE },
|
|
7965
|
+
platform: { type: "string", description: D_PLATFORM },
|
|
8107
7966
|
sentiment: {
|
|
8108
7967
|
type: "string",
|
|
8109
7968
|
enum: [...NEWS_SENTIMENT],
|
|
@@ -8131,6 +7990,7 @@ function registerNewsTools() {
|
|
|
8131
7990
|
keyword: readString(args, "keyword") || void 0,
|
|
8132
7991
|
sortBy: readString(args, "sortBy") ?? "relevant",
|
|
8133
7992
|
importance: readString(args, "importance"),
|
|
7993
|
+
platform: readString(args, "platform"),
|
|
8134
7994
|
ccyList: readString(args, "coins"),
|
|
8135
7995
|
sentiment: readString(args, "sentiment"),
|
|
8136
7996
|
begin: readNumber(args, "begin"),
|
|
@@ -8276,6 +8136,24 @@ function registerNewsTools() {
|
|
|
8276
8136
|
}
|
|
8277
8137
|
}
|
|
8278
8138
|
];
|
|
8139
|
+
const domainsIdx = tools.findIndex((t) => t.name === "news_get_domains");
|
|
8140
|
+
if (domainsIdx === -1) throw new Error("news_get_domains not found in tools list");
|
|
8141
|
+
const [domainsTool] = tools.splice(domainsIdx, 1);
|
|
8142
|
+
return [...tools.map(withNewsDemoGuard), domainsTool];
|
|
8143
|
+
}
|
|
8144
|
+
var NEWS_DEMO_MESSAGE = "News features are not available in demo/simulated trading mode.";
|
|
8145
|
+
var NEWS_DEMO_SUGGESTION = "Switch to a live profile to use News features.";
|
|
8146
|
+
function withNewsDemoGuard(tool) {
|
|
8147
|
+
const originalHandler = tool.handler;
|
|
8148
|
+
return {
|
|
8149
|
+
...tool,
|
|
8150
|
+
handler: async (args, context) => {
|
|
8151
|
+
if (context.config.demo) {
|
|
8152
|
+
throw new ConfigError(NEWS_DEMO_MESSAGE, NEWS_DEMO_SUGGESTION);
|
|
8153
|
+
}
|
|
8154
|
+
return originalHandler(args, context);
|
|
8155
|
+
}
|
|
8156
|
+
};
|
|
8279
8157
|
}
|
|
8280
8158
|
function registerOptionAlgoTools() {
|
|
8281
8159
|
return [
|
|
@@ -9793,7 +9671,7 @@ function createToolRunner(client, config) {
|
|
|
9793
9671
|
};
|
|
9794
9672
|
}
|
|
9795
9673
|
function configFilePath() {
|
|
9796
|
-
return
|
|
9674
|
+
return join6(homedir4(), ".okx", "config.toml");
|
|
9797
9675
|
}
|
|
9798
9676
|
function readFullConfig() {
|
|
9799
9677
|
const path42 = configFilePath();
|
|
@@ -9812,6 +9690,11 @@ Or re-run: okx config init`
|
|
|
9812
9690
|
);
|
|
9813
9691
|
}
|
|
9814
9692
|
}
|
|
9693
|
+
function readTomlProfile(profileName) {
|
|
9694
|
+
const config = readFullConfig();
|
|
9695
|
+
const name = profileName ?? config.default_profile ?? "default";
|
|
9696
|
+
return config.profiles?.[name] ?? {};
|
|
9697
|
+
}
|
|
9815
9698
|
var CONFIG_HEADER = `# OKX Trade Kit Configuration
|
|
9816
9699
|
# If editing manually, wrap values containing special chars in quotes:
|
|
9817
9700
|
# passphrase = 'value' (if value contains # \\ ")
|
|
@@ -9860,24 +9743,18 @@ function parseModuleList(rawModules) {
|
|
|
9860
9743
|
}
|
|
9861
9744
|
return Array.from(deduped);
|
|
9862
9745
|
}
|
|
9863
|
-
|
|
9746
|
+
function loadCredentials(toml) {
|
|
9864
9747
|
const apiKey = process.env.OKX_API_KEY?.trim() ?? toml.api_key;
|
|
9865
9748
|
const secretKey = process.env.OKX_SECRET_KEY?.trim() ?? toml.secret_key;
|
|
9866
9749
|
const passphrase = process.env.OKX_PASSPHRASE?.trim() ?? toml.passphrase;
|
|
9867
|
-
const
|
|
9750
|
+
const hasAuth = Boolean(apiKey && secretKey && passphrase);
|
|
9868
9751
|
const partialAuth = Boolean(apiKey) || Boolean(secretKey) || Boolean(passphrase);
|
|
9869
|
-
if (partialAuth && !
|
|
9752
|
+
if (partialAuth && !hasAuth) {
|
|
9870
9753
|
throw new ConfigError(
|
|
9871
9754
|
"Partial API credentials detected.",
|
|
9872
9755
|
"Set OKX_API_KEY, OKX_SECRET_KEY and OKX_PASSPHRASE together (env vars or config.toml profile)."
|
|
9873
9756
|
);
|
|
9874
9757
|
}
|
|
9875
|
-
let hasOAuth = false;
|
|
9876
|
-
if (!hasApiKey) {
|
|
9877
|
-
const status = await execAuthStatus();
|
|
9878
|
-
hasOAuth = status?.status === "logged_in";
|
|
9879
|
-
}
|
|
9880
|
-
const hasAuth = hasOAuth || hasApiKey;
|
|
9881
9758
|
return { apiKey, secretKey, passphrase, hasAuth };
|
|
9882
9759
|
}
|
|
9883
9760
|
function resolveSite(cliSite, tomlSite) {
|
|
@@ -9911,11 +9788,9 @@ function resolveDemo(cli, toml) {
|
|
|
9911
9788
|
if (cli.demo === true) return true;
|
|
9912
9789
|
return process.env.OKX_DEMO === "1" || process.env.OKX_DEMO === "true" || (toml.demo ?? false);
|
|
9913
9790
|
}
|
|
9914
|
-
|
|
9915
|
-
const
|
|
9916
|
-
const
|
|
9917
|
-
const toml = config.profiles?.[profileName] ?? {};
|
|
9918
|
-
const creds = await loadCredentials(toml);
|
|
9791
|
+
function loadConfig(cli) {
|
|
9792
|
+
const toml = readTomlProfile(cli.profile);
|
|
9793
|
+
const creds = loadCredentials(toml);
|
|
9919
9794
|
const demo = resolveDemo(cli, toml);
|
|
9920
9795
|
const site = resolveSite(cli.site, toml.site);
|
|
9921
9796
|
const baseUrl = resolveBaseUrl(site, toml.base_url);
|
|
@@ -9935,7 +9810,6 @@ async function loadConfig(cli) {
|
|
|
9935
9810
|
}
|
|
9936
9811
|
return {
|
|
9937
9812
|
...creds,
|
|
9938
|
-
profile: profileName,
|
|
9939
9813
|
baseUrl,
|
|
9940
9814
|
timeoutMs: Math.floor(rawTimeout),
|
|
9941
9815
|
modules: parseModuleList(cli.modules),
|
|
@@ -9948,7 +9822,7 @@ async function loadConfig(cli) {
|
|
|
9948
9822
|
verbose: cli.verbose ?? false
|
|
9949
9823
|
};
|
|
9950
9824
|
}
|
|
9951
|
-
var CACHE_FILE =
|
|
9825
|
+
var CACHE_FILE = join7(homedir5(), ".okx", "update-check.json");
|
|
9952
9826
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
9953
9827
|
function readCache2() {
|
|
9954
9828
|
try {
|
|
@@ -9961,7 +9835,7 @@ function readCache2() {
|
|
|
9961
9835
|
}
|
|
9962
9836
|
function writeCache2(cache) {
|
|
9963
9837
|
try {
|
|
9964
|
-
mkdirSync6(
|
|
9838
|
+
mkdirSync6(join7(homedir5(), ".okx"), { recursive: true });
|
|
9965
9839
|
writeFileSync5(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
|
|
9966
9840
|
} catch {
|
|
9967
9841
|
}
|
|
@@ -10131,13 +10005,13 @@ function findMsStoreClaudePath() {
|
|
|
10131
10005
|
}
|
|
10132
10006
|
function getConfigPath(client) {
|
|
10133
10007
|
const home = os3.homedir();
|
|
10134
|
-
const
|
|
10008
|
+
const platform2 = process.platform;
|
|
10135
10009
|
switch (client) {
|
|
10136
10010
|
case "claude-desktop":
|
|
10137
|
-
if (
|
|
10011
|
+
if (platform2 === "win32") {
|
|
10138
10012
|
return findMsStoreClaudePath() ?? path3.join(appData(), "Claude", CLAUDE_CONFIG_FILE);
|
|
10139
10013
|
}
|
|
10140
|
-
if (
|
|
10014
|
+
if (platform2 === "darwin") {
|
|
10141
10015
|
return path3.join(home, "Library", "Application Support", "Claude", CLAUDE_CONFIG_FILE);
|
|
10142
10016
|
}
|
|
10143
10017
|
return path3.join(process.env.XDG_CONFIG_HOME ?? path3.join(home, ".config"), "Claude", CLAUDE_CONFIG_FILE);
|
|
@@ -10258,7 +10132,7 @@ function getPlatformDir() {
|
|
|
10258
10132
|
return map[`${p}-${a}`] ?? null;
|
|
10259
10133
|
}
|
|
10260
10134
|
function getBinaryName() {
|
|
10261
|
-
return platform() === "win32" ? "okx-
|
|
10135
|
+
return platform() === "win32" ? "okx-pilot.exe" : "okx-pilot";
|
|
10262
10136
|
}
|
|
10263
10137
|
function hashFile(filePath) {
|
|
10264
10138
|
const buf = readFileSync7(filePath);
|
|
@@ -10379,7 +10253,7 @@ async function installDohBinary(destPath, sources = CDN_SOURCES, onProgress) {
|
|
|
10379
10253
|
if (earlyResult) return earlyResult;
|
|
10380
10254
|
const platformDir = getPlatformDir();
|
|
10381
10255
|
const binaryName = getBinaryName();
|
|
10382
|
-
const resolvedDest = destPath ??
|
|
10256
|
+
const resolvedDest = destPath ?? join9(homedir7(), ".okx", "bin", binaryName);
|
|
10383
10257
|
const tmpPath = resolvedDest + ".tmp";
|
|
10384
10258
|
mkdirSync8(dirname6(resolvedDest), { recursive: true });
|
|
10385
10259
|
const localHash = existsSync6(resolvedDest) ? hashFile(resolvedDest) : null;
|
|
@@ -10502,224 +10376,16 @@ function downloadText(url, timeoutMs) {
|
|
|
10502
10376
|
})
|
|
10503
10377
|
);
|
|
10504
10378
|
}
|
|
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
|
-
}
|
|
10719
10379
|
|
|
10720
|
-
// src/commands/
|
|
10721
|
-
import
|
|
10722
|
-
import
|
|
10380
|
+
// src/commands/diagnose.ts
|
|
10381
|
+
import dns from "dns/promises";
|
|
10382
|
+
import net from "net";
|
|
10383
|
+
import os5 from "os";
|
|
10384
|
+
import tls from "tls";
|
|
10385
|
+
|
|
10386
|
+
// src/commands/diagnose-utils.ts
|
|
10387
|
+
import fs4 from "fs";
|
|
10388
|
+
import { createRequire } from "module";
|
|
10723
10389
|
|
|
10724
10390
|
// src/formatter.ts
|
|
10725
10391
|
import { EOL } from "os";
|
|
@@ -10810,249 +10476,7 @@ function markFailedIfSCodeError(data) {
|
|
|
10810
10476
|
}
|
|
10811
10477
|
}
|
|
10812
10478
|
|
|
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
|
-
|
|
11053
10479
|
// src/commands/diagnose-utils.ts
|
|
11054
|
-
import fs4 from "fs";
|
|
11055
|
-
import { createRequire } from "module";
|
|
11056
10480
|
var _require = createRequire(import.meta.url);
|
|
11057
10481
|
function readCliVersion() {
|
|
11058
10482
|
for (const rel of ["../package.json", "../../package.json"]) {
|
|
@@ -11138,7 +10562,7 @@ function sanitize2(value) {
|
|
|
11138
10562
|
import fs5 from "fs";
|
|
11139
10563
|
import path4 from "path";
|
|
11140
10564
|
import os4 from "os";
|
|
11141
|
-
import { spawnSync, spawn
|
|
10565
|
+
import { spawnSync, spawn } from "child_process";
|
|
11142
10566
|
import { createRequire as createRequire2 } from "module";
|
|
11143
10567
|
import { fileURLToPath } from "url";
|
|
11144
10568
|
var _require2 = createRequire2(import.meta.url);
|
|
@@ -11472,7 +10896,7 @@ async function checkStdioHandshake(entryPath, report) {
|
|
|
11472
10896
|
clearTimeout(timer);
|
|
11473
10897
|
resolve3(passed);
|
|
11474
10898
|
};
|
|
11475
|
-
const child =
|
|
10899
|
+
const child = spawn(process.execPath, [entryPath], {
|
|
11476
10900
|
stdio: ["pipe", "pipe", "pipe"],
|
|
11477
10901
|
env: { ...process.env }
|
|
11478
10902
|
});
|
|
@@ -11591,7 +11015,7 @@ async function cmdDiagnoseMcp(options = {}) {
|
|
|
11591
11015
|
|
|
11592
11016
|
// src/commands/diagnose.ts
|
|
11593
11017
|
var CLI_VERSION = readCliVersion();
|
|
11594
|
-
var GIT_HASH = true ? "
|
|
11018
|
+
var GIT_HASH = true ? "e9764c9" : "dev";
|
|
11595
11019
|
function maskKey2(key) {
|
|
11596
11020
|
if (!key) return "(not set)";
|
|
11597
11021
|
if (key.length <= 8) return "****";
|
|
@@ -11927,13 +11351,13 @@ async function runCliChecks(config, profile, outputPath) {
|
|
|
11927
11351
|
|
|
11928
11352
|
// src/commands/upgrade.ts
|
|
11929
11353
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
11930
|
-
import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as
|
|
11931
|
-
import { dirname as
|
|
11932
|
-
import { homedir as
|
|
11354
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync9 } from "fs";
|
|
11355
|
+
import { dirname as dirname7, join as join10 } from "path";
|
|
11356
|
+
import { homedir as homedir8 } from "os";
|
|
11933
11357
|
var PACKAGES = ["@okx_ai/okx-trade-mcp", "@okx_ai/okx-trade-cli"];
|
|
11934
|
-
var CACHE_FILE2 =
|
|
11358
|
+
var CACHE_FILE2 = join10(homedir8(), ".okx", "last_check");
|
|
11935
11359
|
var THROTTLE_MS = 12 * 60 * 60 * 1e3;
|
|
11936
|
-
var NPM_BIN =
|
|
11360
|
+
var NPM_BIN = join10(dirname7(process.execPath), process.platform === "win32" ? "npm.cmd" : "npm");
|
|
11937
11361
|
function readLastCheck() {
|
|
11938
11362
|
try {
|
|
11939
11363
|
return parseInt(readFileSync8(CACHE_FILE2, "utf-8").trim(), 10) || 0;
|
|
@@ -11943,7 +11367,7 @@ function readLastCheck() {
|
|
|
11943
11367
|
}
|
|
11944
11368
|
function writeLastCheck() {
|
|
11945
11369
|
try {
|
|
11946
|
-
|
|
11370
|
+
mkdirSync9(join10(homedir8(), ".okx"), { recursive: true });
|
|
11947
11371
|
writeFileSync7(CACHE_FILE2, String(Math.floor(Date.now() / 1e3)), "utf-8");
|
|
11948
11372
|
} catch {
|
|
11949
11373
|
}
|
|
@@ -12915,29 +12339,29 @@ var CLI_REGISTRY = {
|
|
|
12915
12339
|
commands: {
|
|
12916
12340
|
latest: {
|
|
12917
12341
|
toolName: "news_get_latest",
|
|
12918
|
-
usage: "okx news latest [--coins BTC,ETH] [--lang
|
|
12342
|
+
usage: "okx news latest [--coins BTC,ETH] [--platform blockbeats] [--lang zh-CN] [--limit 20]"
|
|
12919
12343
|
},
|
|
12920
12344
|
important: {
|
|
12921
12345
|
toolName: "news_get_latest",
|
|
12922
|
-
usage: "okx news important [--coins BTC,ETH] [--lang
|
|
12346
|
+
usage: "okx news important [--coins BTC,ETH] [--lang zh-CN] [--limit 20]",
|
|
12923
12347
|
description: "Get important/high-impact crypto news"
|
|
12924
12348
|
},
|
|
12925
12349
|
"by-coin": {
|
|
12926
12350
|
toolName: "news_get_by_coin",
|
|
12927
|
-
usage: "okx news by-coin --coins BTC [--importance high] [--lang
|
|
12351
|
+
usage: "okx news by-coin --coins BTC [--importance high] [--platform blockbeats] [--lang zh-CN]"
|
|
12928
12352
|
},
|
|
12929
12353
|
search: {
|
|
12930
12354
|
toolName: "news_search",
|
|
12931
|
-
usage: "okx news search --keyword <term> [--coins BTC] [--sentiment bullish] [--lang
|
|
12355
|
+
usage: "okx news search --keyword <term> [--coins BTC] [--sentiment bullish] [--platform blockbeats] [--lang zh-CN]"
|
|
12932
12356
|
},
|
|
12933
12357
|
detail: {
|
|
12934
12358
|
toolName: "news_get_detail",
|
|
12935
|
-
usage: "okx news detail <id> [--lang
|
|
12359
|
+
usage: "okx news detail <id> [--lang zh-CN]"
|
|
12936
12360
|
},
|
|
12937
|
-
|
|
12361
|
+
platforms: {
|
|
12938
12362
|
toolName: "news_get_domains",
|
|
12939
|
-
usage: "okx news
|
|
12940
|
-
description: "List available news
|
|
12363
|
+
usage: "okx news platforms",
|
|
12364
|
+
description: "List available news platforms"
|
|
12941
12365
|
},
|
|
12942
12366
|
"coin-sentiment": {
|
|
12943
12367
|
toolName: "news_get_coin_sentiment",
|
|
@@ -12950,7 +12374,7 @@ var CLI_REGISTRY = {
|
|
|
12950
12374
|
},
|
|
12951
12375
|
"by-sentiment": {
|
|
12952
12376
|
toolName: "news_search",
|
|
12953
|
-
usage: "okx news by-sentiment --sentiment bullish [--coins BTC] [--sort-by latest]",
|
|
12377
|
+
usage: "okx news by-sentiment --sentiment bullish [--coins BTC] [--importance high] [--platform <source>] [--sort-by latest] [--begin <ms>] [--end <ms>]",
|
|
12954
12378
|
description: "Browse news filtered by sentiment direction"
|
|
12955
12379
|
},
|
|
12956
12380
|
"sentiment-rank": {
|
|
@@ -13158,6 +12582,7 @@ async function cmdNewsLatest(run, opts) {
|
|
|
13158
12582
|
const result = await run("news_get_latest", {
|
|
13159
12583
|
coins: opts.coins,
|
|
13160
12584
|
importance: opts.importance,
|
|
12585
|
+
platform: opts.platform,
|
|
13161
12586
|
begin: opts.begin,
|
|
13162
12587
|
end: opts.end,
|
|
13163
12588
|
language: opts.language,
|
|
@@ -13184,6 +12609,7 @@ async function cmdNewsImportant(run, opts) {
|
|
|
13184
12609
|
const result = await run("news_get_latest", {
|
|
13185
12610
|
coins: opts.coins,
|
|
13186
12611
|
importance: "high",
|
|
12612
|
+
platform: opts.platform,
|
|
13187
12613
|
begin: opts.begin,
|
|
13188
12614
|
end: opts.end,
|
|
13189
12615
|
language: opts.language,
|
|
@@ -13208,6 +12634,7 @@ async function cmdNewsByCoin(run, coins, opts) {
|
|
|
13208
12634
|
const result = await run("news_get_by_coin", {
|
|
13209
12635
|
coins,
|
|
13210
12636
|
importance: opts.importance,
|
|
12637
|
+
platform: opts.platform,
|
|
13211
12638
|
begin: opts.begin,
|
|
13212
12639
|
end: opts.end,
|
|
13213
12640
|
language: opts.language,
|
|
@@ -13233,6 +12660,7 @@ async function cmdNewsSearch(run, keyword, opts) {
|
|
|
13233
12660
|
keyword: keyword || void 0,
|
|
13234
12661
|
coins: opts.coins,
|
|
13235
12662
|
importance: opts.importance,
|
|
12663
|
+
platform: opts.platform,
|
|
13236
12664
|
sentiment: opts.sentiment,
|
|
13237
12665
|
sortBy: opts.sortBy,
|
|
13238
12666
|
begin: opts.begin,
|
|
@@ -13285,12 +12713,12 @@ async function cmdNewsDetail(run, id, opts) {
|
|
|
13285
12713
|
content
|
|
13286
12714
|
});
|
|
13287
12715
|
}
|
|
13288
|
-
async function
|
|
12716
|
+
async function cmdNewsPlatforms(run, opts) {
|
|
13289
12717
|
const result = await run("news_get_domains", {});
|
|
13290
12718
|
const raw = getData(result);
|
|
13291
12719
|
const items = raw?.[0]?.["platform"] ?? [];
|
|
13292
12720
|
if (opts.json) return printJson(items);
|
|
13293
|
-
outputLine("Available news
|
|
12721
|
+
outputLine("Available news platforms:");
|
|
13294
12722
|
items.forEach((d) => outputLine(` ${d}`));
|
|
13295
12723
|
}
|
|
13296
12724
|
async function cmdNewsCoinSentiment(run, coins, opts) {
|
|
@@ -13364,7 +12792,7 @@ async function cmdNewsSentimentRank(run, opts) {
|
|
|
13364
12792
|
}
|
|
13365
12793
|
|
|
13366
12794
|
// src/config/loader.ts
|
|
13367
|
-
|
|
12795
|
+
function loadProfileConfig(opts) {
|
|
13368
12796
|
return loadConfig({
|
|
13369
12797
|
profile: opts.profile,
|
|
13370
12798
|
modules: opts.modules,
|
|
@@ -13672,6 +13100,7 @@ var CLI_OPTIONS = {
|
|
|
13672
13100
|
coins: { type: "string" },
|
|
13673
13101
|
sentiment: { type: "string" },
|
|
13674
13102
|
importance: { type: "string" },
|
|
13103
|
+
platform: { type: "string" },
|
|
13675
13104
|
keyword: { type: "string" },
|
|
13676
13105
|
"detail-lvl": { type: "string" },
|
|
13677
13106
|
period: { type: "string" },
|
|
@@ -13682,9 +13111,6 @@ var CLI_OPTIONS = {
|
|
|
13682
13111
|
dir: { type: "string" },
|
|
13683
13112
|
page: { type: "string" },
|
|
13684
13113
|
format: { type: "string" },
|
|
13685
|
-
// auth
|
|
13686
|
-
site: { type: "string" },
|
|
13687
|
-
manual: { type: "boolean", default: false },
|
|
13688
13114
|
// event contract
|
|
13689
13115
|
underlying: { type: "string" },
|
|
13690
13116
|
seriesId: { type: "string" },
|
|
@@ -16699,14 +16125,14 @@ async function cmdDcdQuoteAndBuy(run, opts) {
|
|
|
16699
16125
|
}
|
|
16700
16126
|
|
|
16701
16127
|
// src/commands/skill.ts
|
|
16702
|
-
import { tmpdir, homedir as
|
|
16703
|
-
import { join as
|
|
16704
|
-
import { mkdirSync as
|
|
16128
|
+
import { tmpdir, homedir as homedir10 } from "os";
|
|
16129
|
+
import { join as join12, dirname as dirname8 } from "path";
|
|
16130
|
+
import { mkdirSync as mkdirSync10, rmSync, existsSync as existsSync8, copyFileSync as copyFileSync2 } from "fs";
|
|
16705
16131
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
16706
16132
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
16707
16133
|
function resolveNpx() {
|
|
16708
|
-
const sibling =
|
|
16709
|
-
if (
|
|
16134
|
+
const sibling = join12(dirname8(process.execPath), "npx");
|
|
16135
|
+
if (existsSync8(sibling)) return sibling;
|
|
16710
16136
|
return "npx";
|
|
16711
16137
|
}
|
|
16712
16138
|
var THIRD_PARTY_INSTALL_NOTICE = "Note: This skill was created by a third-party developer, not by OKX. Review SKILL.md before use.";
|
|
@@ -16759,13 +16185,13 @@ async function cmdSkillCategories(run, json) {
|
|
|
16759
16185
|
outputLine("");
|
|
16760
16186
|
}
|
|
16761
16187
|
async function cmdSkillAdd(name, config, json) {
|
|
16762
|
-
const tmpBase =
|
|
16763
|
-
|
|
16188
|
+
const tmpBase = join12(tmpdir(), `okx-skill-${randomUUID2()}`);
|
|
16189
|
+
mkdirSync10(tmpBase, { recursive: true });
|
|
16764
16190
|
try {
|
|
16765
16191
|
outputLine(`Downloading ${name}...`);
|
|
16766
16192
|
const client = new OkxRestClient(config);
|
|
16767
16193
|
const zipPath = await downloadSkillZip(client, name, tmpBase);
|
|
16768
|
-
const contentDir = await extractSkillZip(zipPath,
|
|
16194
|
+
const contentDir = await extractSkillZip(zipPath, join12(tmpBase, "content"));
|
|
16769
16195
|
const meta = readMetaJson(contentDir);
|
|
16770
16196
|
validateSkillMdExists(contentDir);
|
|
16771
16197
|
outputLine("Installing to detected agents...");
|
|
@@ -16775,7 +16201,7 @@ async function cmdSkillAdd(name, config, json) {
|
|
|
16775
16201
|
timeout: 6e4
|
|
16776
16202
|
});
|
|
16777
16203
|
} catch (e) {
|
|
16778
|
-
const savedZip =
|
|
16204
|
+
const savedZip = join12(process.cwd(), `${name}.zip`);
|
|
16779
16205
|
try {
|
|
16780
16206
|
copyFileSync2(zipPath, savedZip);
|
|
16781
16207
|
} catch {
|
|
@@ -16814,7 +16240,7 @@ function cmdSkillRemove(name, json) {
|
|
|
16814
16240
|
timeout: 6e4
|
|
16815
16241
|
});
|
|
16816
16242
|
} catch {
|
|
16817
|
-
const agentsPath =
|
|
16243
|
+
const agentsPath = join12(homedir10(), ".agents", "skills", name);
|
|
16818
16244
|
try {
|
|
16819
16245
|
rmSync(agentsPath, { recursive: true, force: true });
|
|
16820
16246
|
} catch {
|
|
@@ -16888,14 +16314,14 @@ function printSkillInstallResult(meta, json) {
|
|
|
16888
16314
|
}
|
|
16889
16315
|
|
|
16890
16316
|
// src/commands/doh.ts
|
|
16891
|
-
import
|
|
16892
|
-
function
|
|
16317
|
+
import readline from "readline";
|
|
16318
|
+
function resolveChecksumMatch(local, cdnChecksum, cdnError) {
|
|
16893
16319
|
if (!local.exists) return "not-installed";
|
|
16894
16320
|
if (cdnError || !cdnChecksum) return "unavailable";
|
|
16895
16321
|
if (cdnChecksum.sha256 === local.sha256) return "match";
|
|
16896
16322
|
return "mismatch";
|
|
16897
16323
|
}
|
|
16898
|
-
function
|
|
16324
|
+
function checksumMatchLabel(match) {
|
|
16899
16325
|
if (match === "match") return "\u2713 match";
|
|
16900
16326
|
if (match === "mismatch") return "\u2717 mismatch (update available)";
|
|
16901
16327
|
return "CDN unreachable";
|
|
@@ -16908,9 +16334,9 @@ function formatStatusText(local, checksumMatch, cdnChecksum, runtimeMode) {
|
|
|
16908
16334
|
outputLine(` Installed : ${local.exists ? "yes" : "no"}`);
|
|
16909
16335
|
outputLine(` Platform : ${local.platform ?? "(unsupported)"}`);
|
|
16910
16336
|
if (local.exists) {
|
|
16911
|
-
outputLine(` File size : ${
|
|
16337
|
+
outputLine(` File size : ${formatBytes(local.fileSize)}`);
|
|
16912
16338
|
outputLine(` SHA-256 : ${local.sha256 ?? "(unknown)"}`);
|
|
16913
|
-
outputLine(` CDN check : ${
|
|
16339
|
+
outputLine(` CDN check : ${checksumMatchLabel(checksumMatch)}`);
|
|
16914
16340
|
if (cdnChecksum) {
|
|
16915
16341
|
outputLine(` CDN source : ${cdnChecksum.source}`);
|
|
16916
16342
|
}
|
|
@@ -16937,7 +16363,7 @@ async function cmdDohStatus(json, binaryPath) {
|
|
|
16937
16363
|
cdnError = err instanceof Error ? err.message : String(err);
|
|
16938
16364
|
}
|
|
16939
16365
|
}
|
|
16940
|
-
const checksumMatch =
|
|
16366
|
+
const checksumMatch = resolveChecksumMatch(local, cdnChecksum, cdnError);
|
|
16941
16367
|
if (json) {
|
|
16942
16368
|
outputLine(
|
|
16943
16369
|
JSON.stringify({
|
|
@@ -17003,7 +16429,7 @@ async function cmdDohRemove(force, json, binaryPath) {
|
|
|
17003
16429
|
process.exitCode = 1;
|
|
17004
16430
|
return;
|
|
17005
16431
|
}
|
|
17006
|
-
const confirmed = await
|
|
16432
|
+
const confirmed = await askConfirmation(
|
|
17007
16433
|
` Remove DoH resolver at ${local.binaryPath}? [y/N] `
|
|
17008
16434
|
);
|
|
17009
16435
|
if (!confirmed) {
|
|
@@ -17022,14 +16448,14 @@ async function cmdDohRemove(force, json, binaryPath) {
|
|
|
17022
16448
|
outputLine(" DoH resolver is not installed.");
|
|
17023
16449
|
}
|
|
17024
16450
|
}
|
|
17025
|
-
function
|
|
16451
|
+
function formatBytes(bytes) {
|
|
17026
16452
|
if (bytes < 1024) return `${bytes} B`;
|
|
17027
16453
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
17028
16454
|
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
17029
16455
|
}
|
|
17030
|
-
function
|
|
16456
|
+
function askConfirmation(prompt2) {
|
|
17031
16457
|
return new Promise((resolve3) => {
|
|
17032
|
-
const rl =
|
|
16458
|
+
const rl = readline.createInterface({
|
|
17033
16459
|
input: process.stdin,
|
|
17034
16460
|
output: process.stdout
|
|
17035
16461
|
});
|
|
@@ -17486,7 +16912,7 @@ async function cmdEventCancel(run, opts) {
|
|
|
17486
16912
|
// src/index.ts
|
|
17487
16913
|
var _require3 = createRequire3(import.meta.url);
|
|
17488
16914
|
var CLI_VERSION2 = _require3("../package.json").version;
|
|
17489
|
-
var GIT_HASH2 = true ? "
|
|
16915
|
+
var GIT_HASH2 = true ? "e9764c9" : "dev";
|
|
17490
16916
|
function handleDohCommand(action, json, force, binaryPath) {
|
|
17491
16917
|
if (action === "status") return cmdDohStatus(json, binaryPath);
|
|
17492
16918
|
if (action === "install") return cmdDohInstall(json, binaryPath);
|
|
@@ -18330,21 +17756,22 @@ function handleNewsCommand(run, action, rest, v, json) {
|
|
|
18330
17756
|
const limit = v.limit !== void 0 ? Number(v.limit) : void 0;
|
|
18331
17757
|
const begin = v.begin !== void 0 ? Number(v.begin) : void 0;
|
|
18332
17758
|
const end = v.end !== void 0 ? Number(v.end) : void 0;
|
|
18333
|
-
const language = v.lang ?? "
|
|
17759
|
+
const language = v.lang ?? "en-US";
|
|
18334
17760
|
const detailLvl = v["detail-lvl"];
|
|
18335
17761
|
const after = v.after;
|
|
18336
17762
|
const period = v.period;
|
|
18337
17763
|
const points = v.points !== void 0 ? Number(v.points) : 24;
|
|
18338
17764
|
const sortBy = v["sort-by"];
|
|
18339
|
-
const
|
|
18340
|
-
const
|
|
17765
|
+
const platform2 = v.platform;
|
|
17766
|
+
const searchOpts = { coins: v.coins, importance: v.importance, platform: platform2, sentiment: v.sentiment, sortBy, begin, end, language, detailLvl, limit, after, json };
|
|
17767
|
+
const listOpts = { coins: v.coins, importance: v.importance, platform: platform2, begin, end, language, detailLvl, limit, after, json };
|
|
18341
17768
|
const dispatch = {
|
|
18342
17769
|
latest: () => cmdNewsLatest(run, listOpts),
|
|
18343
|
-
important: () => cmdNewsImportant(run, { coins: v.coins, begin, end, language, detailLvl, limit, json }),
|
|
18344
|
-
"by-coin": () => cmdNewsByCoin(run, v.coins ?? rest[0], { importance: v.importance, begin, end, language, detailLvl, limit, json }),
|
|
17770
|
+
important: () => cmdNewsImportant(run, { coins: v.coins, platform: platform2, begin, end, language, detailLvl, limit, json }),
|
|
17771
|
+
"by-coin": () => cmdNewsByCoin(run, v.coins ?? rest[0], { importance: v.importance, platform: platform2, begin, end, language, detailLvl, limit, json }),
|
|
18345
17772
|
search: () => cmdNewsSearch(run, v.keyword ?? rest[0], searchOpts),
|
|
18346
17773
|
detail: () => cmdNewsDetail(run, rest[0], { language, json }),
|
|
18347
|
-
|
|
17774
|
+
platforms: () => cmdNewsPlatforms(run, { json }),
|
|
18348
17775
|
"coin-sentiment": () => cmdNewsCoinSentiment(run, v.coins ?? rest[0], { period, json }),
|
|
18349
17776
|
"coin-trend": () => cmdNewsCoinTrend(run, v.coins ?? rest[0], { period, points, json }),
|
|
18350
17777
|
// by-sentiment is a convenience wrapper over news_search (no keyword, sentiment filter only)
|
|
@@ -18461,7 +17888,7 @@ function wrapRunnerWithLogger(baseRunner, logger, verbose = false) {
|
|
|
18461
17888
|
async function runDiagnose(v) {
|
|
18462
17889
|
let config;
|
|
18463
17890
|
try {
|
|
18464
|
-
config =
|
|
17891
|
+
config = loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
|
|
18465
17892
|
} catch {
|
|
18466
17893
|
}
|
|
18467
17894
|
return cmdDiagnose(config, v.profile ?? "default", { mcp: v.mcp, cli: v.cli, all: v.all, output: v.output });
|
|
@@ -18476,13 +17903,24 @@ function printVersion() {
|
|
|
18476
17903
|
}
|
|
18477
17904
|
}
|
|
18478
17905
|
function routeManagementCommand(module, action, rest, json, v) {
|
|
18479
|
-
if (module === "config")
|
|
18480
|
-
|
|
18481
|
-
|
|
17906
|
+
if (module === "config") {
|
|
17907
|
+
const r = handleConfigCommand(action, rest, json, v.lang, v.force);
|
|
17908
|
+
return r ?? true;
|
|
17909
|
+
}
|
|
17910
|
+
if (module === "setup") {
|
|
17911
|
+
handleSetupCommand(v);
|
|
17912
|
+
return true;
|
|
17913
|
+
}
|
|
18482
17914
|
if (module === "upgrade") return cmdUpgrade(CLI_VERSION2, { beta: v.beta, check: v.check, force: v.force }, json);
|
|
18483
|
-
if (module === "doh")
|
|
17915
|
+
if (module === "doh") {
|
|
17916
|
+
const r = handleDohCommand(action, json, v.force ?? false);
|
|
17917
|
+
return r ?? true;
|
|
17918
|
+
}
|
|
18484
17919
|
if (module === "diagnose") return runDiagnose(v);
|
|
18485
|
-
if (module === "list-tools")
|
|
17920
|
+
if (module === "list-tools") {
|
|
17921
|
+
cmdListTools(json);
|
|
17922
|
+
return true;
|
|
17923
|
+
}
|
|
18486
17924
|
return void 0;
|
|
18487
17925
|
}
|
|
18488
17926
|
async function main() {
|
|
@@ -18504,8 +17942,8 @@ async function main() {
|
|
|
18504
17942
|
const v = values;
|
|
18505
17943
|
const json = v.json ?? false;
|
|
18506
17944
|
const mgmt = routeManagementCommand(module, action, rest, json, v);
|
|
18507
|
-
if (mgmt) return mgmt;
|
|
18508
|
-
const config =
|
|
17945
|
+
if (mgmt !== void 0) return mgmt === true ? void 0 : mgmt;
|
|
17946
|
+
const config = loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
|
|
18509
17947
|
setEnvContext({ demo: config.demo, profile: v.profile ?? "default" });
|
|
18510
17948
|
setJsonEnvEnabled(v.env ?? false);
|
|
18511
17949
|
const client = new OkxRestClient(config);
|