@okx_ai/okx-trade-cli 1.3.2-beta.4 → 1.3.2-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +151 -811
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/postinstall-download.js +152 -0
- 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,13 +886,10 @@ 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
|
-
import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync10, unlinkSync as unlinkSync5, existsSync as existsSync8 } from "fs";
|
|
909
|
-
import { join as join12 } from "path";
|
|
910
|
-
import { homedir as homedir10 } from "os";
|
|
911
893
|
var EXEC_TIMEOUT_MS = 3e4;
|
|
912
894
|
var ALLOWED_DOMAIN_RE = /^[\w.-]+\.okx\.com$/;
|
|
913
895
|
var PILOT_BIN_DIR = join(homedir(), ".okx", "bin");
|
|
@@ -1219,11 +1201,6 @@ var ConfigError = class extends OkxMcpError {
|
|
|
1219
1201
|
super("ConfigError", message, { suggestion });
|
|
1220
1202
|
}
|
|
1221
1203
|
};
|
|
1222
|
-
var NotLoggedInError = class extends ConfigError {
|
|
1223
|
-
constructor(suggestion = "Run `okx auth login` to authenticate.") {
|
|
1224
|
-
super("Not logged in.", suggestion);
|
|
1225
|
-
}
|
|
1226
|
-
};
|
|
1227
1204
|
var ValidationError = class extends OkxMcpError {
|
|
1228
1205
|
constructor(message, suggestion) {
|
|
1229
1206
|
super("ValidationError", message, { suggestion });
|
|
@@ -1276,97 +1253,6 @@ function toToolErrorPayload(error, fallbackEndpoint) {
|
|
|
1276
1253
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1277
1254
|
};
|
|
1278
1255
|
}
|
|
1279
|
-
var EXIT_CODES = {
|
|
1280
|
-
SUCCESS: 0,
|
|
1281
|
-
UNAUTHORIZED_CALLER: 1,
|
|
1282
|
-
NOT_LOGGED_IN: 2,
|
|
1283
|
-
REFRESH_FAILED: 3
|
|
1284
|
-
};
|
|
1285
|
-
var EXEC_TIMEOUT_MS2 = 5e3;
|
|
1286
|
-
var AUTH_BIN_DIR = join3(homedir3(), ".okx", "bin");
|
|
1287
|
-
function getAuthBinaryPath() {
|
|
1288
|
-
if (process.env.OKX_AUTH_BIN) {
|
|
1289
|
-
return process.env.OKX_AUTH_BIN;
|
|
1290
|
-
}
|
|
1291
|
-
const ext = process.platform === "win32" ? ".exe" : "";
|
|
1292
|
-
return join3(AUTH_BIN_DIR, `okx-auth${ext}`);
|
|
1293
|
-
}
|
|
1294
|
-
function execAuthToken() {
|
|
1295
|
-
const binPath = getAuthBinaryPath();
|
|
1296
|
-
return new Promise((resolve3, reject) => {
|
|
1297
|
-
const child = spawn(binPath, ["token"], {
|
|
1298
|
-
stdio: ["ignore", "ignore", "inherit", "pipe"]
|
|
1299
|
-
// stdin stdout stderr fd3 (pipe)
|
|
1300
|
-
});
|
|
1301
|
-
const chunks = [];
|
|
1302
|
-
const fd3 = child.stdio[3];
|
|
1303
|
-
fd3.on("data", (chunk) => chunks.push(chunk));
|
|
1304
|
-
child.on("error", (err) => {
|
|
1305
|
-
reject(new ConfigError(
|
|
1306
|
-
`Failed to spawn okx-auth: ${err.message}`,
|
|
1307
|
-
"Ensure the okx-auth binary exists and is executable."
|
|
1308
|
-
));
|
|
1309
|
-
});
|
|
1310
|
-
child.on("close", (code) => {
|
|
1311
|
-
if (code === EXIT_CODES.SUCCESS) {
|
|
1312
|
-
const token = Buffer.concat(chunks).toString("utf-8").trim();
|
|
1313
|
-
if (!token) {
|
|
1314
|
-
reject(new AuthenticationError(
|
|
1315
|
-
"okx-auth returned empty token.",
|
|
1316
|
-
"Run `okx auth login` to re-authenticate."
|
|
1317
|
-
));
|
|
1318
|
-
return;
|
|
1319
|
-
}
|
|
1320
|
-
resolve3(token);
|
|
1321
|
-
return;
|
|
1322
|
-
}
|
|
1323
|
-
if (code === EXIT_CODES.NOT_LOGGED_IN) {
|
|
1324
|
-
reject(new NotLoggedInError());
|
|
1325
|
-
return;
|
|
1326
|
-
}
|
|
1327
|
-
if (code === EXIT_CODES.UNAUTHORIZED_CALLER) {
|
|
1328
|
-
reject(new AuthenticationError(
|
|
1329
|
-
"okx-auth rejected the caller (unauthorized).",
|
|
1330
|
-
"Ensure you are running from a trusted OKX tool."
|
|
1331
|
-
));
|
|
1332
|
-
return;
|
|
1333
|
-
}
|
|
1334
|
-
if (code === EXIT_CODES.REFRESH_FAILED) {
|
|
1335
|
-
reject(new AuthenticationError(
|
|
1336
|
-
"Token refresh failed.",
|
|
1337
|
-
"Run `okx auth login` to re-authenticate."
|
|
1338
|
-
));
|
|
1339
|
-
return;
|
|
1340
|
-
}
|
|
1341
|
-
reject(new AuthenticationError(
|
|
1342
|
-
`okx-auth token exited with code ${code}.`,
|
|
1343
|
-
"Run `okx auth login` to re-authenticate."
|
|
1344
|
-
));
|
|
1345
|
-
});
|
|
1346
|
-
});
|
|
1347
|
-
}
|
|
1348
|
-
function execAuthStatus() {
|
|
1349
|
-
const binPath = getAuthBinaryPath();
|
|
1350
|
-
return new Promise((resolve3) => {
|
|
1351
|
-
execFile2(
|
|
1352
|
-
binPath,
|
|
1353
|
-
["status", "--json"],
|
|
1354
|
-
{ timeout: EXEC_TIMEOUT_MS2, encoding: "utf-8" },
|
|
1355
|
-
(error, stdout) => {
|
|
1356
|
-
if (error) {
|
|
1357
|
-
resolve3(null);
|
|
1358
|
-
return;
|
|
1359
|
-
}
|
|
1360
|
-
try {
|
|
1361
|
-
const result = JSON.parse(stdout);
|
|
1362
|
-
resolve3(result);
|
|
1363
|
-
} catch {
|
|
1364
|
-
resolve3(null);
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
);
|
|
1368
|
-
});
|
|
1369
|
-
}
|
|
1370
1256
|
function sleep(ms) {
|
|
1371
1257
|
return new Promise((resolve3) => {
|
|
1372
1258
|
setTimeout(resolve3, ms);
|
|
@@ -1498,7 +1384,6 @@ function maskKey(key) {
|
|
|
1498
1384
|
if (key.length <= 8) return "***";
|
|
1499
1385
|
return `${key.slice(0, 3)}***${key.slice(-3)}`;
|
|
1500
1386
|
}
|
|
1501
|
-
var TOKEN_CACHE_TTL_MS = 6e4;
|
|
1502
1387
|
function vlog2(message) {
|
|
1503
1388
|
process.stderr.write(`[verbose] ${message}
|
|
1504
1389
|
`);
|
|
@@ -1507,8 +1392,6 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1507
1392
|
config;
|
|
1508
1393
|
rateLimiter;
|
|
1509
1394
|
dispatcher;
|
|
1510
|
-
cachedAccessToken;
|
|
1511
|
-
cachedAccessTokenAt = 0;
|
|
1512
1395
|
pilot;
|
|
1513
1396
|
constructor(config) {
|
|
1514
1397
|
this.config = config;
|
|
@@ -1523,51 +1406,6 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1523
1406
|
hasCustomProxy: !!config.proxyUrl
|
|
1524
1407
|
});
|
|
1525
1408
|
}
|
|
1526
|
-
/**
|
|
1527
|
-
* Resolve OAuth access token via the okx-auth binary (fd3 pipe).
|
|
1528
|
-
* Caches the token for 60 s to avoid spawning the binary on every
|
|
1529
|
-
* request. The binary handles refresh internally (300s TTL lead),
|
|
1530
|
-
* so periodic re-calls let it serve a fresh token when needed.
|
|
1531
|
-
* Returns null when not logged in.
|
|
1532
|
-
*/
|
|
1533
|
-
async resolveAccessToken() {
|
|
1534
|
-
if (this.cachedAccessToken && Date.now() - this.cachedAccessTokenAt < TOKEN_CACHE_TTL_MS) {
|
|
1535
|
-
return this.cachedAccessToken;
|
|
1536
|
-
}
|
|
1537
|
-
try {
|
|
1538
|
-
const token = await execAuthToken();
|
|
1539
|
-
this.cachedAccessToken = token;
|
|
1540
|
-
this.cachedAccessTokenAt = Date.now();
|
|
1541
|
-
return token;
|
|
1542
|
-
} catch (e) {
|
|
1543
|
-
if (e instanceof NotLoggedInError) {
|
|
1544
|
-
return null;
|
|
1545
|
-
}
|
|
1546
|
-
throw e;
|
|
1547
|
-
}
|
|
1548
|
-
}
|
|
1549
|
-
/**
|
|
1550
|
-
* Dynamic auth — determines auth method per request.
|
|
1551
|
-
*
|
|
1552
|
-
* 1. API key in config → HMAC signing (no OAuth fallback)
|
|
1553
|
-
* 2. OAuth token via okx-auth binary → Bearer token
|
|
1554
|
-
* 3. Neither → throw ConfigError
|
|
1555
|
-
*/
|
|
1556
|
-
async applyAuth(headers, method, requestPath, bodyJson, timestamp) {
|
|
1557
|
-
if (this.config.apiKey && this.config.secretKey && this.config.passphrase) {
|
|
1558
|
-
this.setAuthHeaders(headers, method, requestPath, bodyJson, timestamp);
|
|
1559
|
-
return;
|
|
1560
|
-
}
|
|
1561
|
-
const accessToken = await this.resolveAccessToken();
|
|
1562
|
-
if (accessToken) {
|
|
1563
|
-
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
1564
|
-
return;
|
|
1565
|
-
}
|
|
1566
|
-
throw new ConfigError(
|
|
1567
|
-
"No credentials found.",
|
|
1568
|
-
"Run `okx auth login` to authenticate, or configure API key credentials."
|
|
1569
|
-
);
|
|
1570
|
-
}
|
|
1571
1409
|
/** The canonical base URL for this client (e.g. https://www.okx.com). */
|
|
1572
1410
|
get baseUrl() {
|
|
1573
1411
|
return this.config.baseUrl;
|
|
@@ -1626,6 +1464,18 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1626
1464
|
});
|
|
1627
1465
|
}
|
|
1628
1466
|
setAuthHeaders(headers, method, requestPath, bodyJson, timestamp) {
|
|
1467
|
+
if (!this.config.hasAuth) {
|
|
1468
|
+
throw new ConfigError(
|
|
1469
|
+
"Private endpoint requires API credentials.",
|
|
1470
|
+
"Configure OKX_API_KEY, OKX_SECRET_KEY and OKX_PASSPHRASE."
|
|
1471
|
+
);
|
|
1472
|
+
}
|
|
1473
|
+
if (!this.config.apiKey || !this.config.secretKey || !this.config.passphrase) {
|
|
1474
|
+
throw new ConfigError(
|
|
1475
|
+
"Invalid private API credentials state.",
|
|
1476
|
+
"Ensure all OKX credentials are set."
|
|
1477
|
+
);
|
|
1478
|
+
}
|
|
1629
1479
|
const payload = `${timestamp}${method.toUpperCase()}${requestPath}${bodyJson}`;
|
|
1630
1480
|
const signature = signOkxPayload(payload, this.config.secretKey);
|
|
1631
1481
|
headers.set("OK-ACCESS-KEY", this.config.apiKey);
|
|
@@ -1740,7 +1590,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1740
1590
|
const conn = this.pilot.getConnectionParams();
|
|
1741
1591
|
this.logRequest("POST", `${conn.baseUrl}${path42}`, "private");
|
|
1742
1592
|
const reqConfig = { method: "POST", path: path42, auth: "private" };
|
|
1743
|
-
const headers =
|
|
1593
|
+
const headers = this.buildHeaders(reqConfig, path42, bodyJson, getNow());
|
|
1744
1594
|
if (conn.userAgent) {
|
|
1745
1595
|
headers.set("User-Agent", conn.userAgent);
|
|
1746
1596
|
}
|
|
@@ -1861,7 +1711,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1861
1711
|
// Header building
|
|
1862
1712
|
// ---------------------------------------------------------------------------
|
|
1863
1713
|
/** Build HTTP headers. reqConfig.extraHeaders must NOT contain auth keys (OK-ACCESS-*). */
|
|
1864
|
-
|
|
1714
|
+
buildHeaders(reqConfig, requestPath, bodyJson, timestamp) {
|
|
1865
1715
|
const headers = new Headers({
|
|
1866
1716
|
"Content-Type": "application/json",
|
|
1867
1717
|
Accept: "application/json"
|
|
@@ -1870,7 +1720,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1870
1720
|
headers.set("User-Agent", this.config.userAgent);
|
|
1871
1721
|
}
|
|
1872
1722
|
if (reqConfig.auth === "private") {
|
|
1873
|
-
|
|
1723
|
+
this.setAuthHeaders(headers, reqConfig.method, requestPath, bodyJson, timestamp);
|
|
1874
1724
|
}
|
|
1875
1725
|
const useSimulated = reqConfig.simulatedTrading !== void 0 ? reqConfig.simulatedTrading : this.config.demo;
|
|
1876
1726
|
if (useSimulated) {
|
|
@@ -1924,7 +1774,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1924
1774
|
if (reqConfig.rateLimit) {
|
|
1925
1775
|
await this.rateLimiter.consume(reqConfig.rateLimit);
|
|
1926
1776
|
}
|
|
1927
|
-
const headers =
|
|
1777
|
+
const headers = this.buildHeaders(reqConfig, requestPath, bodyJson, timestamp);
|
|
1928
1778
|
if (conn.userAgent) {
|
|
1929
1779
|
headers.set("User-Agent", conn.userAgent);
|
|
1930
1780
|
}
|
|
@@ -2351,6 +2201,8 @@ function registerIndicatorTools() {
|
|
|
2351
2201
|
];
|
|
2352
2202
|
}
|
|
2353
2203
|
var DEFAULT_SOURCE_TAG = "MCP";
|
|
2204
|
+
var TOKEN_REGEX = /^[A-Z2-7]{12}$/;
|
|
2205
|
+
var TAG_JOIN = "";
|
|
2354
2206
|
var OKX_SITES = {
|
|
2355
2207
|
global: {
|
|
2356
2208
|
label: "Global",
|
|
@@ -2364,7 +2216,7 @@ var OKX_SITES = {
|
|
|
2364
2216
|
},
|
|
2365
2217
|
us: {
|
|
2366
2218
|
label: "US",
|
|
2367
|
-
apiBaseUrl: "https://
|
|
2219
|
+
apiBaseUrl: "https://app.okx.com",
|
|
2368
2220
|
webUrl: "https://app.okx.com"
|
|
2369
2221
|
}
|
|
2370
2222
|
};
|
|
@@ -3308,7 +3160,8 @@ function registerAlgoTradeTools() {
|
|
|
3308
3160
|
callBackSpread: readString(args, "callbackSpread"),
|
|
3309
3161
|
activePx: readString(args, "activePx"),
|
|
3310
3162
|
reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
|
|
3311
|
-
clOrdId: readString(args, "clOrdId")
|
|
3163
|
+
clOrdId: readString(args, "clOrdId"),
|
|
3164
|
+
tag: context.config.sourceTag
|
|
3312
3165
|
}),
|
|
3313
3166
|
privateRateLimit("swap_place_move_stop_order", 20)
|
|
3314
3167
|
);
|
|
@@ -3653,7 +3506,8 @@ function registerFuturesAlgoTools() {
|
|
|
3653
3506
|
callBackSpread: readString(args, "callbackSpread"),
|
|
3654
3507
|
activePx: readString(args, "activePx"),
|
|
3655
3508
|
reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
|
|
3656
|
-
clOrdId: readString(args, "clOrdId")
|
|
3509
|
+
clOrdId: readString(args, "clOrdId"),
|
|
3510
|
+
tag: context.config.sourceTag
|
|
3657
3511
|
}),
|
|
3658
3512
|
privateRateLimit("futures_place_move_stop_order", 20)
|
|
3659
3513
|
);
|
|
@@ -3911,7 +3765,7 @@ function safeWriteFile(targetDir, fileName, data) {
|
|
|
3911
3765
|
throw new Error(`Invalid file name: "${fileName}"`);
|
|
3912
3766
|
}
|
|
3913
3767
|
const resolvedDir = resolve(targetDir);
|
|
3914
|
-
const filePath =
|
|
3768
|
+
const filePath = join3(resolvedDir, safeName);
|
|
3915
3769
|
const resolvedPath = resolve(filePath);
|
|
3916
3770
|
if (!resolvedPath.startsWith(resolvedDir + sep)) {
|
|
3917
3771
|
throw new Error(`Path traversal detected: "${fileName}" resolves outside target directory`);
|
|
@@ -4039,7 +3893,7 @@ async function extractSkillZip(zipPath, targetDir, limits) {
|
|
|
4039
3893
|
});
|
|
4040
3894
|
}
|
|
4041
3895
|
function readMetaJson(contentDir) {
|
|
4042
|
-
const metaPath =
|
|
3896
|
+
const metaPath = join4(contentDir, "_meta.json");
|
|
4043
3897
|
if (!existsSync(metaPath)) {
|
|
4044
3898
|
throw new Error(`_meta.json not found in ${contentDir}. Invalid skill package.`);
|
|
4045
3899
|
}
|
|
@@ -4065,12 +3919,12 @@ function readMetaJson(contentDir) {
|
|
|
4065
3919
|
};
|
|
4066
3920
|
}
|
|
4067
3921
|
function validateSkillMdExists(contentDir) {
|
|
4068
|
-
const skillMdPath =
|
|
3922
|
+
const skillMdPath = join4(contentDir, "SKILL.md");
|
|
4069
3923
|
if (!existsSync(skillMdPath)) {
|
|
4070
3924
|
throw new Error(`SKILL.md not found in ${contentDir}. Invalid skill package.`);
|
|
4071
3925
|
}
|
|
4072
3926
|
}
|
|
4073
|
-
var DEFAULT_REGISTRY_PATH =
|
|
3927
|
+
var DEFAULT_REGISTRY_PATH = join5(homedir3(), ".okx", "skills", "registry.json");
|
|
4074
3928
|
function readRegistry(registryPath = DEFAULT_REGISTRY_PATH) {
|
|
4075
3929
|
if (!existsSync2(registryPath)) {
|
|
4076
3930
|
return { version: 1, skills: {} };
|
|
@@ -10485,7 +10339,7 @@ function createToolRunner(client, config) {
|
|
|
10485
10339
|
};
|
|
10486
10340
|
}
|
|
10487
10341
|
function configFilePath() {
|
|
10488
|
-
return
|
|
10342
|
+
return join6(homedir4(), ".okx", "config.toml");
|
|
10489
10343
|
}
|
|
10490
10344
|
function readFullConfig() {
|
|
10491
10345
|
const path42 = configFilePath();
|
|
@@ -10504,6 +10358,11 @@ Or re-run: okx config init`
|
|
|
10504
10358
|
);
|
|
10505
10359
|
}
|
|
10506
10360
|
}
|
|
10361
|
+
function readTomlProfile(profileName) {
|
|
10362
|
+
const config = readFullConfig();
|
|
10363
|
+
const name = profileName ?? config.default_profile ?? "default";
|
|
10364
|
+
return config.profiles?.[name] ?? {};
|
|
10365
|
+
}
|
|
10507
10366
|
var CONFIG_HEADER = `# OKX Trade Kit Configuration
|
|
10508
10367
|
# If editing manually, wrap values containing special chars in quotes:
|
|
10509
10368
|
# passphrase = 'value' (if value contains # \\ ")
|
|
@@ -10552,24 +10411,18 @@ function parseModuleList(rawModules) {
|
|
|
10552
10411
|
}
|
|
10553
10412
|
return Array.from(deduped);
|
|
10554
10413
|
}
|
|
10555
|
-
|
|
10414
|
+
function loadCredentials(toml) {
|
|
10556
10415
|
const apiKey = process.env.OKX_API_KEY?.trim() ?? toml.api_key;
|
|
10557
10416
|
const secretKey = process.env.OKX_SECRET_KEY?.trim() ?? toml.secret_key;
|
|
10558
10417
|
const passphrase = process.env.OKX_PASSPHRASE?.trim() ?? toml.passphrase;
|
|
10559
|
-
const
|
|
10418
|
+
const hasAuth = Boolean(apiKey && secretKey && passphrase);
|
|
10560
10419
|
const partialAuth = Boolean(apiKey) || Boolean(secretKey) || Boolean(passphrase);
|
|
10561
|
-
if (partialAuth && !
|
|
10420
|
+
if (partialAuth && !hasAuth) {
|
|
10562
10421
|
throw new ConfigError(
|
|
10563
10422
|
"Partial API credentials detected.",
|
|
10564
10423
|
"Set OKX_API_KEY, OKX_SECRET_KEY and OKX_PASSPHRASE together (env vars or config.toml profile)."
|
|
10565
10424
|
);
|
|
10566
10425
|
}
|
|
10567
|
-
let hasOAuth = false;
|
|
10568
|
-
if (!hasApiKey) {
|
|
10569
|
-
const status = await execAuthStatus();
|
|
10570
|
-
hasOAuth = status?.status === "logged_in";
|
|
10571
|
-
}
|
|
10572
|
-
const hasAuth = hasOAuth || hasApiKey;
|
|
10573
10426
|
return { apiKey, secretKey, passphrase, hasAuth };
|
|
10574
10427
|
}
|
|
10575
10428
|
function resolveSite(cliSite, tomlSite) {
|
|
@@ -10592,6 +10445,30 @@ function resolveBaseUrl(site, tomlBaseUrl) {
|
|
|
10592
10445
|
}
|
|
10593
10446
|
return rawBaseUrl.replace(/\/+$/, "");
|
|
10594
10447
|
}
|
|
10448
|
+
function resolveSourceTag(cli, defaultTag, opts = {}) {
|
|
10449
|
+
const readEnv = opts.readEnv !== false;
|
|
10450
|
+
const cliSkill = cli.skill?.trim();
|
|
10451
|
+
if (cliSkill) {
|
|
10452
|
+
if (isValidToken(cliSkill)) return composeTag(defaultTag, cliSkill);
|
|
10453
|
+
console.warn("--skill value format invalid (expected 12-char Base32), ignoring");
|
|
10454
|
+
}
|
|
10455
|
+
if (readEnv) {
|
|
10456
|
+
const envToken = process.env.OKX_SKILL_TOKEN?.trim();
|
|
10457
|
+
if (envToken) {
|
|
10458
|
+
if (isValidToken(envToken)) return composeTag(defaultTag, envToken);
|
|
10459
|
+
console.warn("OKX_SKILL_TOKEN format invalid, ignoring");
|
|
10460
|
+
}
|
|
10461
|
+
}
|
|
10462
|
+
const sourceTag = cli.sourceTag?.trim();
|
|
10463
|
+
if (sourceTag) return sourceTag;
|
|
10464
|
+
return defaultTag;
|
|
10465
|
+
}
|
|
10466
|
+
function composeTag(defaultTag, token) {
|
|
10467
|
+
return `${defaultTag}${TAG_JOIN}${token}`;
|
|
10468
|
+
}
|
|
10469
|
+
function isValidToken(s) {
|
|
10470
|
+
return TOKEN_REGEX.test(s);
|
|
10471
|
+
}
|
|
10595
10472
|
function resolveDemo(cli, toml) {
|
|
10596
10473
|
if (cli.demo && cli.live) {
|
|
10597
10474
|
throw new ConfigError(
|
|
@@ -10603,11 +10480,9 @@ function resolveDemo(cli, toml) {
|
|
|
10603
10480
|
if (cli.demo === true) return true;
|
|
10604
10481
|
return process.env.OKX_DEMO === "1" || process.env.OKX_DEMO === "true" || (toml.demo ?? false);
|
|
10605
10482
|
}
|
|
10606
|
-
|
|
10607
|
-
const
|
|
10608
|
-
const
|
|
10609
|
-
const toml = config.profiles?.[profileName] ?? {};
|
|
10610
|
-
const creds = await loadCredentials(toml);
|
|
10483
|
+
function loadConfig(cli, opts = {}) {
|
|
10484
|
+
const toml = readTomlProfile(cli.profile);
|
|
10485
|
+
const creds = loadCredentials(toml);
|
|
10611
10486
|
const demo = resolveDemo(cli, toml);
|
|
10612
10487
|
const site = resolveSite(cli.site, toml.site);
|
|
10613
10488
|
const baseUrl = resolveBaseUrl(site, toml.base_url);
|
|
@@ -10625,9 +10500,9 @@ async function loadConfig(cli) {
|
|
|
10625
10500
|
"proxy_url must start with http:// or https://. SOCKS proxies are not supported."
|
|
10626
10501
|
);
|
|
10627
10502
|
}
|
|
10503
|
+
const defaultTag = opts.entryPrefix ?? DEFAULT_SOURCE_TAG;
|
|
10628
10504
|
return {
|
|
10629
10505
|
...creds,
|
|
10630
|
-
profile: profileName,
|
|
10631
10506
|
baseUrl,
|
|
10632
10507
|
timeoutMs: Math.floor(rawTimeout),
|
|
10633
10508
|
modules: parseModuleList(cli.modules),
|
|
@@ -10635,12 +10510,14 @@ async function loadConfig(cli) {
|
|
|
10635
10510
|
demo,
|
|
10636
10511
|
site,
|
|
10637
10512
|
userAgent: cli.userAgent,
|
|
10638
|
-
sourceTag:
|
|
10513
|
+
// sourceTag resolution: --skill > OKX_SKILL_TOKEN > --source-tag > defaultTag
|
|
10514
|
+
// MCP entry passes { readEnv: false } to honour the "MCP path not attributed" contract.
|
|
10515
|
+
sourceTag: resolveSourceTag(cli, defaultTag, { readEnv: opts.readEnv }),
|
|
10639
10516
|
proxyUrl: rawProxyUrl || void 0,
|
|
10640
10517
|
verbose: cli.verbose ?? false
|
|
10641
10518
|
};
|
|
10642
10519
|
}
|
|
10643
|
-
var CACHE_FILE =
|
|
10520
|
+
var CACHE_FILE = join7(homedir5(), ".okx", "update-check.json");
|
|
10644
10521
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
10645
10522
|
function readCache2() {
|
|
10646
10523
|
try {
|
|
@@ -10653,7 +10530,7 @@ function readCache2() {
|
|
|
10653
10530
|
}
|
|
10654
10531
|
function writeCache2(cache) {
|
|
10655
10532
|
try {
|
|
10656
|
-
mkdirSync6(
|
|
10533
|
+
mkdirSync6(join7(homedir5(), ".okx"), { recursive: true });
|
|
10657
10534
|
writeFileSync5(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
|
|
10658
10535
|
} catch {
|
|
10659
10536
|
}
|
|
@@ -10823,13 +10700,13 @@ function findMsStoreClaudePath() {
|
|
|
10823
10700
|
}
|
|
10824
10701
|
function getConfigPath(client) {
|
|
10825
10702
|
const home = os3.homedir();
|
|
10826
|
-
const
|
|
10703
|
+
const platform2 = process.platform;
|
|
10827
10704
|
switch (client) {
|
|
10828
10705
|
case "claude-desktop":
|
|
10829
|
-
if (
|
|
10706
|
+
if (platform2 === "win32") {
|
|
10830
10707
|
return findMsStoreClaudePath() ?? path3.join(appData(), "Claude", CLAUDE_CONFIG_FILE);
|
|
10831
10708
|
}
|
|
10832
|
-
if (
|
|
10709
|
+
if (platform2 === "darwin") {
|
|
10833
10710
|
return path3.join(home, "Library", "Application Support", "Claude", CLAUDE_CONFIG_FILE);
|
|
10834
10711
|
}
|
|
10835
10712
|
return path3.join(process.env.XDG_CONFIG_HOME ?? path3.join(home, ".config"), "Claude", CLAUDE_CONFIG_FILE);
|
|
@@ -10941,7 +10818,7 @@ var DOWNLOAD_TIMEOUT_MS = 3e4;
|
|
|
10941
10818
|
var PLATFORM_MAP = {
|
|
10942
10819
|
"darwin-arm64": "darwin-arm64",
|
|
10943
10820
|
"darwin-x64": "darwin-x64",
|
|
10944
|
-
"linux-arm64": "linux-
|
|
10821
|
+
"linux-arm64": "linux-arm64",
|
|
10945
10822
|
"linux-x64": "linux-x64",
|
|
10946
10823
|
"win32-arm64": "win32-arm64",
|
|
10947
10824
|
"win32-x64": "win32-x64"
|
|
@@ -11073,7 +10950,7 @@ async function installPilotBinary(destPath, sources = CDN_SOURCES, onProgress) {
|
|
|
11073
10950
|
if (earlyResult) return earlyResult;
|
|
11074
10951
|
const platformDir = getPlatformDir();
|
|
11075
10952
|
const binaryName = getBinaryName();
|
|
11076
|
-
const resolvedDest = destPath ??
|
|
10953
|
+
const resolvedDest = destPath ?? join9(homedir7(), ".okx", "bin", binaryName);
|
|
11077
10954
|
const tmpPath = resolvedDest + ".tmp";
|
|
11078
10955
|
mkdirSync8(dirname6(resolvedDest), { recursive: true });
|
|
11079
10956
|
const localHash = existsSync6(resolvedDest) ? hashFile(resolvedDest) : null;
|
|
@@ -11196,276 +11073,16 @@ function downloadText(url, timeoutMs) {
|
|
|
11196
11073
|
})
|
|
11197
11074
|
);
|
|
11198
11075
|
}
|
|
11199
|
-
var AUTH_CDN_PATH_PREFIX = "/upgradeapp/tools/oauth";
|
|
11200
|
-
function getAuthBinaryName() {
|
|
11201
|
-
return platform2() === "win32" ? "okx-auth.exe" : "okx-auth";
|
|
11202
|
-
}
|
|
11203
|
-
function getAuthStatus(binaryPath, opts) {
|
|
11204
|
-
const resolvedPath = binaryPath ?? getAuthBinaryPath();
|
|
11205
|
-
const platformDir = getPlatformDir();
|
|
11206
|
-
if (!existsSync7(resolvedPath)) {
|
|
11207
|
-
return { binaryPath: resolvedPath, exists: false, platform: platformDir };
|
|
11208
|
-
}
|
|
11209
|
-
if (opts?.skipHash) {
|
|
11210
|
-
return { binaryPath: resolvedPath, exists: true, platform: platformDir };
|
|
11211
|
-
}
|
|
11212
|
-
const { size, sha256 } = hashFile(resolvedPath);
|
|
11213
|
-
return { binaryPath: resolvedPath, exists: true, platform: platformDir, fileSize: size, sha256 };
|
|
11214
|
-
}
|
|
11215
|
-
async function fetchAuthCdnChecksum(sources = CDN_SOURCES, timeoutMs = DOWNLOAD_TIMEOUT_MS) {
|
|
11216
|
-
const platformDir = getPlatformDir();
|
|
11217
|
-
if (!platformDir) return null;
|
|
11218
|
-
const checksumPath = `${AUTH_CDN_PATH_PREFIX}/${platformDir}/checksum.json`;
|
|
11219
|
-
for (const { host, protocol } of sources) {
|
|
11220
|
-
try {
|
|
11221
|
-
const url = `${protocol}://${host}${checksumPath}`;
|
|
11222
|
-
const raw = await downloadText2(url, timeoutMs);
|
|
11223
|
-
const data = JSON.parse(raw);
|
|
11224
|
-
if (typeof data.sha256 !== "string" || typeof data.size !== "number" || typeof data.target !== "string") {
|
|
11225
|
-
continue;
|
|
11226
|
-
}
|
|
11227
|
-
return { sha256: data.sha256, size: data.size, target: data.target, source: host };
|
|
11228
|
-
} catch {
|
|
11229
|
-
}
|
|
11230
|
-
}
|
|
11231
|
-
return null;
|
|
11232
|
-
}
|
|
11233
|
-
async function fetchAndValidateChecksum2(host, protocol, checksumPath, platformDir, timeoutMs, onProgress) {
|
|
11234
|
-
const checksumUrl = `${protocol}://${host}${checksumPath}`;
|
|
11235
|
-
onProgress?.(`Fetching checksum from ${host}...`);
|
|
11236
|
-
const raw = await downloadText2(checksumUrl, timeoutMs);
|
|
11237
|
-
const checksum = JSON.parse(raw);
|
|
11238
|
-
if (typeof checksum.sha256 !== "string" || typeof checksum.size !== "number" || typeof checksum.target !== "string") {
|
|
11239
|
-
throw new Error("Invalid checksum.json: missing sha256, size, or target");
|
|
11240
|
-
}
|
|
11241
|
-
if (checksum.target !== platformDir) {
|
|
11242
|
-
throw new Error(`Target mismatch: expected ${platformDir}, got ${checksum.target}`);
|
|
11243
|
-
}
|
|
11244
|
-
return { sha256: checksum.sha256, size: checksum.size, target: checksum.target };
|
|
11245
|
-
}
|
|
11246
|
-
async function downloadAndVerify2(host, protocol, binaryPath, tmpPath, checksum, timeoutMs, onProgress) {
|
|
11247
|
-
const binaryUrl = `${protocol}://${host}${binaryPath}`;
|
|
11248
|
-
onProgress?.(`Downloading binary from ${host}...`);
|
|
11249
|
-
await download2(binaryUrl, tmpPath, timeoutMs);
|
|
11250
|
-
const actual = hashFile(tmpPath);
|
|
11251
|
-
if (actual.size !== checksum.size) {
|
|
11252
|
-
throw new Error(`Size mismatch: expected ${checksum.size}, got ${actual.size}`);
|
|
11253
|
-
}
|
|
11254
|
-
if (actual.sha256 !== checksum.sha256) {
|
|
11255
|
-
throw new Error(`SHA-256 mismatch: expected ${checksum.sha256}, got ${actual.sha256}`);
|
|
11256
|
-
}
|
|
11257
|
-
}
|
|
11258
|
-
function atomicReplace2(tmpPath, resolvedDest) {
|
|
11259
|
-
if (platform2() === "win32") {
|
|
11260
|
-
try {
|
|
11261
|
-
unlinkSync4(resolvedDest);
|
|
11262
|
-
} catch {
|
|
11263
|
-
}
|
|
11264
|
-
}
|
|
11265
|
-
renameSync4(tmpPath, resolvedDest);
|
|
11266
|
-
if (platform2() !== "win32") {
|
|
11267
|
-
chmodSync2(resolvedDest, 493);
|
|
11268
|
-
}
|
|
11269
|
-
}
|
|
11270
|
-
function installPreChecks2(destPath, sources) {
|
|
11271
|
-
if (!destPath && process.env.OKX_AUTH_BIN) {
|
|
11272
|
-
return { status: "up-to-date", source: "(env override)" };
|
|
11273
|
-
}
|
|
11274
|
-
if (!getPlatformDir()) {
|
|
11275
|
-
return { status: "failed", error: "Unsupported platform" };
|
|
11276
|
-
}
|
|
11277
|
-
if (sources.length === 0) {
|
|
11278
|
-
return { status: "failed", error: "No CDN sources available" };
|
|
11279
|
-
}
|
|
11280
|
-
return null;
|
|
11281
|
-
}
|
|
11282
|
-
function isLocalUpToDate2(localHash, checksum) {
|
|
11283
|
-
return localHash !== null && localHash.size === checksum.size && localHash.sha256 === checksum.sha256;
|
|
11284
|
-
}
|
|
11285
|
-
async function installAuthBinary(destPath, sources = CDN_SOURCES, onProgress) {
|
|
11286
|
-
const earlyResult = installPreChecks2(destPath, sources);
|
|
11287
|
-
if (earlyResult) return earlyResult;
|
|
11288
|
-
const platformDir = getPlatformDir();
|
|
11289
|
-
const binaryName = getAuthBinaryName();
|
|
11290
|
-
const resolvedDest = destPath ?? join11(homedir9(), ".okx", "bin", binaryName);
|
|
11291
|
-
const tmpPath = resolvedDest + ".tmp";
|
|
11292
|
-
mkdirSync9(dirname7(resolvedDest), { recursive: true });
|
|
11293
|
-
const localHash = existsSync7(resolvedDest) ? hashFile(resolvedDest) : null;
|
|
11294
|
-
const checksumPath = `${AUTH_CDN_PATH_PREFIX}/${platformDir}/checksum.json`;
|
|
11295
|
-
const binaryPath = `${AUTH_CDN_PATH_PREFIX}/${platformDir}/${binaryName}`;
|
|
11296
|
-
const errors = [];
|
|
11297
|
-
for (const { host, protocol } of sources) {
|
|
11298
|
-
try {
|
|
11299
|
-
const checksum = await fetchAndValidateChecksum2(
|
|
11300
|
-
host,
|
|
11301
|
-
protocol,
|
|
11302
|
-
checksumPath,
|
|
11303
|
-
platformDir,
|
|
11304
|
-
DOWNLOAD_TIMEOUT_MS,
|
|
11305
|
-
onProgress
|
|
11306
|
-
);
|
|
11307
|
-
if (isLocalUpToDate2(localHash, checksum)) {
|
|
11308
|
-
onProgress?.("Already up to date (checksum match)");
|
|
11309
|
-
return { status: "up-to-date", source: host };
|
|
11310
|
-
}
|
|
11311
|
-
await downloadAndVerify2(host, protocol, binaryPath, tmpPath, checksum, DOWNLOAD_TIMEOUT_MS, onProgress);
|
|
11312
|
-
atomicReplace2(tmpPath, resolvedDest);
|
|
11313
|
-
onProgress?.(`Downloaded and verified from ${host}`);
|
|
11314
|
-
return { status: "installed", source: host };
|
|
11315
|
-
} catch (err) {
|
|
11316
|
-
try {
|
|
11317
|
-
unlinkSync4(tmpPath);
|
|
11318
|
-
} catch {
|
|
11319
|
-
}
|
|
11320
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
11321
|
-
errors.push(`${host}: ${msg}`);
|
|
11322
|
-
onProgress?.(`${host} failed: ${msg}`);
|
|
11323
|
-
}
|
|
11324
|
-
}
|
|
11325
|
-
return { status: "failed", error: `All CDN sources failed:
|
|
11326
|
-
${errors.join("\n")}` };
|
|
11327
|
-
}
|
|
11328
|
-
function removeAuthBinary(binaryPath) {
|
|
11329
|
-
const resolvedPath = binaryPath ?? getAuthBinaryPath();
|
|
11330
|
-
try {
|
|
11331
|
-
unlinkSync4(resolvedPath);
|
|
11332
|
-
return { status: "removed" };
|
|
11333
|
-
} catch (err) {
|
|
11334
|
-
if (err.code === "ENOENT") {
|
|
11335
|
-
return { status: "not-found" };
|
|
11336
|
-
}
|
|
11337
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
11338
|
-
throw new Error(`Failed to remove ${resolvedPath}: ${msg}`);
|
|
11339
|
-
}
|
|
11340
|
-
}
|
|
11341
|
-
function isRedirect2(statusCode) {
|
|
11342
|
-
return statusCode !== void 0 && statusCode >= 300 && statusCode < 400;
|
|
11343
|
-
}
|
|
11344
|
-
function validateRedirect2(res, requestUrl, redirectCount, maxRedirects) {
|
|
11345
|
-
if (redirectCount > maxRedirects) {
|
|
11346
|
-
throw new Error(`Too many redirects (${maxRedirects})`);
|
|
11347
|
-
}
|
|
11348
|
-
const location = res.headers.location;
|
|
11349
|
-
if (requestUrl.startsWith("https") && !location.startsWith("https")) {
|
|
11350
|
-
throw new Error("Refused HTTPS \u2192 HTTP redirect downgrade");
|
|
11351
|
-
}
|
|
11352
|
-
return location;
|
|
11353
|
-
}
|
|
11354
|
-
function fetchResponse2(url, timeoutMs) {
|
|
11355
|
-
return new Promise((resolve3, reject) => {
|
|
11356
|
-
let redirects = 0;
|
|
11357
|
-
const maxRedirects = 5;
|
|
11358
|
-
function doRequest(requestUrl) {
|
|
11359
|
-
const reqFn = requestUrl.startsWith("https") ? httpsGet2 : httpGet2;
|
|
11360
|
-
const req = reqFn(requestUrl, { timeout: timeoutMs }, (res) => {
|
|
11361
|
-
if (isRedirect2(res.statusCode) && res.headers.location) {
|
|
11362
|
-
redirects++;
|
|
11363
|
-
try {
|
|
11364
|
-
const location = validateRedirect2(res, requestUrl, redirects, maxRedirects);
|
|
11365
|
-
res.resume();
|
|
11366
|
-
doRequest(location);
|
|
11367
|
-
} catch (err) {
|
|
11368
|
-
reject(err);
|
|
11369
|
-
}
|
|
11370
|
-
return;
|
|
11371
|
-
}
|
|
11372
|
-
if (res.statusCode !== 200) {
|
|
11373
|
-
reject(new Error(`HTTP ${res.statusCode ?? "unknown"}`));
|
|
11374
|
-
return;
|
|
11375
|
-
}
|
|
11376
|
-
resolve3(res);
|
|
11377
|
-
});
|
|
11378
|
-
req.on("error", reject);
|
|
11379
|
-
req.on("timeout", () => {
|
|
11380
|
-
req.destroy();
|
|
11381
|
-
reject(new Error("Download timed out"));
|
|
11382
|
-
});
|
|
11383
|
-
}
|
|
11384
|
-
doRequest(url);
|
|
11385
|
-
});
|
|
11386
|
-
}
|
|
11387
|
-
function download2(url, destPath, timeoutMs) {
|
|
11388
|
-
return fetchResponse2(url, timeoutMs).then(
|
|
11389
|
-
(res) => new Promise((resolve3, reject) => {
|
|
11390
|
-
const file = createWriteStream3(destPath);
|
|
11391
|
-
res.pipe(file);
|
|
11392
|
-
file.on("finish", () => file.close(() => resolve3()));
|
|
11393
|
-
file.on("error", (err) => {
|
|
11394
|
-
try {
|
|
11395
|
-
unlinkSync4(destPath);
|
|
11396
|
-
} catch {
|
|
11397
|
-
}
|
|
11398
|
-
reject(err);
|
|
11399
|
-
});
|
|
11400
|
-
})
|
|
11401
|
-
);
|
|
11402
|
-
}
|
|
11403
|
-
function downloadText2(url, timeoutMs) {
|
|
11404
|
-
return fetchResponse2(url, timeoutMs).then(
|
|
11405
|
-
(res) => new Promise((resolve3, reject) => {
|
|
11406
|
-
const chunks = [];
|
|
11407
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
11408
|
-
res.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
|
|
11409
|
-
res.on("error", reject);
|
|
11410
|
-
})
|
|
11411
|
-
);
|
|
11412
|
-
}
|
|
11413
|
-
var CACHE_PATH = join12(homedir10(), ".okx", "auth-binary-check.json");
|
|
11414
|
-
var CHECK_INTERVAL_MS2 = 2 * 60 * 60 * 1e3;
|
|
11415
|
-
function readCache3() {
|
|
11416
|
-
try {
|
|
11417
|
-
if (!existsSync8(CACHE_PATH)) return null;
|
|
11418
|
-
const data = JSON.parse(readFileSync8(CACHE_PATH, "utf-8"));
|
|
11419
|
-
if (typeof data.cdnSha256 !== "string" || typeof data.checkedAt !== "number") return null;
|
|
11420
|
-
return { cdnSha256: data.cdnSha256, checkedAt: data.checkedAt };
|
|
11421
|
-
} catch {
|
|
11422
|
-
return null;
|
|
11423
|
-
}
|
|
11424
|
-
}
|
|
11425
|
-
function writeCache3(cdnSha256) {
|
|
11426
|
-
try {
|
|
11427
|
-
mkdirSync10(join12(homedir10(), ".okx"), { recursive: true });
|
|
11428
|
-
writeFileSync7(CACHE_PATH, JSON.stringify({ cdnSha256, checkedAt: Date.now() }, null, 2), "utf-8");
|
|
11429
|
-
} catch {
|
|
11430
|
-
}
|
|
11431
|
-
}
|
|
11432
|
-
async function ensureAuthBinaryLatest(onProgress) {
|
|
11433
|
-
if (process.env.OKX_AUTH_BIN) return;
|
|
11434
|
-
const cache = readCache3();
|
|
11435
|
-
if (cache && Date.now() - cache.checkedAt < CHECK_INTERVAL_MS2) return;
|
|
11436
|
-
try {
|
|
11437
|
-
const cdn = await fetchAuthCdnChecksum(void 0, 5e3);
|
|
11438
|
-
if (!cdn) return;
|
|
11439
|
-
const local = getAuthStatus();
|
|
11440
|
-
if (local.exists && local.sha256 === cdn.sha256) {
|
|
11441
|
-
writeCache3(cdn.sha256);
|
|
11442
|
-
return;
|
|
11443
|
-
}
|
|
11444
|
-
onProgress?.("Updating okx-auth binary...");
|
|
11445
|
-
const result = await installAuthBinary(void 0, void 0, onProgress);
|
|
11446
|
-
if (result.status === "installed" || result.status === "up-to-date") {
|
|
11447
|
-
const updated = getAuthStatus();
|
|
11448
|
-
if (updated.sha256) writeCache3(updated.sha256);
|
|
11449
|
-
if (result.status === "installed") {
|
|
11450
|
-
onProgress?.("\u2713 okx-auth updated successfully");
|
|
11451
|
-
}
|
|
11452
|
-
}
|
|
11453
|
-
} catch {
|
|
11454
|
-
}
|
|
11455
|
-
}
|
|
11456
|
-
function updateAuthBinaryCache(sha256) {
|
|
11457
|
-
writeCache3(sha256);
|
|
11458
|
-
}
|
|
11459
|
-
function clearAuthBinaryCache() {
|
|
11460
|
-
try {
|
|
11461
|
-
unlinkSync5(CACHE_PATH);
|
|
11462
|
-
} catch {
|
|
11463
|
-
}
|
|
11464
|
-
}
|
|
11465
11076
|
|
|
11466
|
-
// src/commands/
|
|
11467
|
-
import
|
|
11468
|
-
import
|
|
11077
|
+
// src/commands/diagnose.ts
|
|
11078
|
+
import dns from "dns/promises";
|
|
11079
|
+
import net from "net";
|
|
11080
|
+
import os5 from "os";
|
|
11081
|
+
import tls from "tls";
|
|
11082
|
+
|
|
11083
|
+
// src/commands/diagnose-utils.ts
|
|
11084
|
+
import fs4 from "fs";
|
|
11085
|
+
import { createRequire } from "module";
|
|
11469
11086
|
|
|
11470
11087
|
// src/formatter.ts
|
|
11471
11088
|
import { EOL } from "os";
|
|
@@ -11556,286 +11173,7 @@ function markFailedIfSCodeError(data) {
|
|
|
11556
11173
|
}
|
|
11557
11174
|
}
|
|
11558
11175
|
|
|
11559
|
-
// src/commands/auth.ts
|
|
11560
|
-
function runOkxAuth(args) {
|
|
11561
|
-
const binPath = getAuthBinaryPath();
|
|
11562
|
-
return new Promise((resolve3, reject) => {
|
|
11563
|
-
const child = spawn2(binPath, args, {
|
|
11564
|
-
stdio: "inherit"
|
|
11565
|
-
});
|
|
11566
|
-
child.on("error", (err) => {
|
|
11567
|
-
reject(new Error(`Failed to spawn okx-auth: ${err.message}`));
|
|
11568
|
-
});
|
|
11569
|
-
child.on("close", (code) => {
|
|
11570
|
-
resolve3(code ?? 1);
|
|
11571
|
-
});
|
|
11572
|
-
});
|
|
11573
|
-
}
|
|
11574
|
-
function runOkxAuthCapture(args) {
|
|
11575
|
-
const binPath = getAuthBinaryPath();
|
|
11576
|
-
return new Promise((resolve3, reject) => {
|
|
11577
|
-
const child = spawn2(binPath, args, {
|
|
11578
|
-
stdio: ["inherit", "pipe", "inherit"]
|
|
11579
|
-
});
|
|
11580
|
-
const chunks = [];
|
|
11581
|
-
child.stdout.on("data", (chunk) => chunks.push(chunk));
|
|
11582
|
-
child.on("error", (err) => {
|
|
11583
|
-
reject(new Error(`Failed to spawn okx-auth: ${err.message}`));
|
|
11584
|
-
});
|
|
11585
|
-
child.on("close", (code) => {
|
|
11586
|
-
resolve3({
|
|
11587
|
-
code: code ?? 1,
|
|
11588
|
-
stdout: Buffer.concat(chunks).toString("utf-8")
|
|
11589
|
-
});
|
|
11590
|
-
});
|
|
11591
|
-
});
|
|
11592
|
-
}
|
|
11593
|
-
function findApiKeyProfile() {
|
|
11594
|
-
let config;
|
|
11595
|
-
try {
|
|
11596
|
-
config = readFullConfig();
|
|
11597
|
-
} catch {
|
|
11598
|
-
return null;
|
|
11599
|
-
}
|
|
11600
|
-
for (const [name, profile] of Object.entries(config.profiles ?? {})) {
|
|
11601
|
-
if (profile?.api_key) return name;
|
|
11602
|
-
}
|
|
11603
|
-
return null;
|
|
11604
|
-
}
|
|
11605
|
-
async function cmdAuthLogin(args) {
|
|
11606
|
-
const apiKeyProfile = findApiKeyProfile();
|
|
11607
|
-
if (apiKeyProfile) {
|
|
11608
|
-
if (args.manual) {
|
|
11609
|
-
outputLine(JSON.stringify({
|
|
11610
|
-
status: "skipped",
|
|
11611
|
-
reason: "api_key_configured",
|
|
11612
|
-
profile: apiKeyProfile,
|
|
11613
|
-
message: `API key already configured (profile: ${apiKeyProfile}). OAuth login skipped \u2014 API key will be used automatically.`
|
|
11614
|
-
}));
|
|
11615
|
-
} else {
|
|
11616
|
-
outputLine(`API key already configured (profile: ${apiKeyProfile}). OAuth login skipped \u2014 API key will be used automatically.`);
|
|
11617
|
-
}
|
|
11618
|
-
return;
|
|
11619
|
-
}
|
|
11620
|
-
const cliArgs = ["login"];
|
|
11621
|
-
if (args.site) cliArgs.push("--site", args.site);
|
|
11622
|
-
if (args.manual) cliArgs.push("--manual");
|
|
11623
|
-
const code = await runOkxAuth(cliArgs);
|
|
11624
|
-
if (code !== 0) {
|
|
11625
|
-
process.exitCode = code;
|
|
11626
|
-
}
|
|
11627
|
-
}
|
|
11628
|
-
async function cmdAuthLogout() {
|
|
11629
|
-
const code = await runOkxAuth(["logout"]);
|
|
11630
|
-
if (code !== 0) {
|
|
11631
|
-
process.exitCode = code;
|
|
11632
|
-
}
|
|
11633
|
-
}
|
|
11634
|
-
async function cmdAuthStatus(args) {
|
|
11635
|
-
const cliArgs = ["status"];
|
|
11636
|
-
if (args.json) cliArgs.push("--json");
|
|
11637
|
-
const result = await runOkxAuthCapture(cliArgs);
|
|
11638
|
-
if (result.stdout) {
|
|
11639
|
-
process.stdout.write(result.stdout);
|
|
11640
|
-
}
|
|
11641
|
-
if (result.code !== 0) {
|
|
11642
|
-
process.exitCode = result.code;
|
|
11643
|
-
}
|
|
11644
|
-
}
|
|
11645
|
-
function resolveChecksumMatch(local, cdnChecksum, cdnError) {
|
|
11646
|
-
if (!local.exists) return "not-installed";
|
|
11647
|
-
if (cdnError || !cdnChecksum) return "unavailable";
|
|
11648
|
-
if (cdnChecksum.sha256 === local.sha256) return "match";
|
|
11649
|
-
return "mismatch";
|
|
11650
|
-
}
|
|
11651
|
-
function checksumMatchLabel(match) {
|
|
11652
|
-
if (match === "match") return "\u2713 match";
|
|
11653
|
-
if (match === "mismatch") return "\u2717 mismatch (update available)";
|
|
11654
|
-
return "CDN unreachable";
|
|
11655
|
-
}
|
|
11656
|
-
function formatBytes(bytes) {
|
|
11657
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
11658
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
11659
|
-
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
11660
|
-
}
|
|
11661
|
-
async function cmdAuthInstallStatus(json) {
|
|
11662
|
-
const local = getAuthStatus();
|
|
11663
|
-
let cdnChecksum = null;
|
|
11664
|
-
let cdnError = null;
|
|
11665
|
-
if (local.exists) {
|
|
11666
|
-
try {
|
|
11667
|
-
cdnChecksum = await fetchAuthCdnChecksum(void 0, 5e3);
|
|
11668
|
-
} catch (err) {
|
|
11669
|
-
cdnError = err instanceof Error ? err.message : String(err);
|
|
11670
|
-
}
|
|
11671
|
-
}
|
|
11672
|
-
const checksumMatch = resolveChecksumMatch(local, cdnChecksum, cdnError);
|
|
11673
|
-
if (json) {
|
|
11674
|
-
outputLine(
|
|
11675
|
-
JSON.stringify({
|
|
11676
|
-
binaryPath: local.binaryPath,
|
|
11677
|
-
exists: local.exists,
|
|
11678
|
-
platform: local.platform,
|
|
11679
|
-
fileSize: local.fileSize ?? null,
|
|
11680
|
-
sha256: local.sha256 ?? null,
|
|
11681
|
-
cdnMatch: checksumMatch,
|
|
11682
|
-
cdnSha256: cdnChecksum?.sha256 ?? null,
|
|
11683
|
-
cdnSource: cdnChecksum?.source ?? null
|
|
11684
|
-
})
|
|
11685
|
-
);
|
|
11686
|
-
return;
|
|
11687
|
-
}
|
|
11688
|
-
outputLine("");
|
|
11689
|
-
outputLine(" okx-auth Binary Status");
|
|
11690
|
-
outputLine(" " + "\u2500".repeat(40));
|
|
11691
|
-
outputLine(` Binary path : ${local.binaryPath}`);
|
|
11692
|
-
outputLine(` Installed : ${local.exists ? "yes" : "no"}`);
|
|
11693
|
-
outputLine(` Platform : ${local.platform ?? "(unsupported)"}`);
|
|
11694
|
-
if (local.exists) {
|
|
11695
|
-
outputLine(` File size : ${formatBytes(local.fileSize)}`);
|
|
11696
|
-
outputLine(` SHA-256 : ${local.sha256 ?? "(unknown)"}`);
|
|
11697
|
-
outputLine(` CDN check : ${checksumMatchLabel(checksumMatch)}`);
|
|
11698
|
-
if (cdnChecksum) {
|
|
11699
|
-
outputLine(` CDN source : ${cdnChecksum.source}`);
|
|
11700
|
-
}
|
|
11701
|
-
}
|
|
11702
|
-
outputLine("");
|
|
11703
|
-
}
|
|
11704
|
-
async function cmdAuthInstall(json) {
|
|
11705
|
-
const messages2 = [];
|
|
11706
|
-
const onProgress = (msg) => {
|
|
11707
|
-
if (!json) {
|
|
11708
|
-
outputLine(` ${msg}`);
|
|
11709
|
-
}
|
|
11710
|
-
messages2.push(msg);
|
|
11711
|
-
};
|
|
11712
|
-
if (!json) {
|
|
11713
|
-
outputLine("");
|
|
11714
|
-
outputLine(" Installing okx-auth...");
|
|
11715
|
-
}
|
|
11716
|
-
const result = await installAuthBinary(void 0, void 0, onProgress);
|
|
11717
|
-
if (json) {
|
|
11718
|
-
outputLine(JSON.stringify({ status: result.status, source: result.source ?? null, error: result.error ?? null, messages: messages2 }));
|
|
11719
|
-
if (result.status === "failed") {
|
|
11720
|
-
process.exitCode = 1;
|
|
11721
|
-
}
|
|
11722
|
-
return;
|
|
11723
|
-
}
|
|
11724
|
-
if (result.status === "installed" || result.status === "up-to-date") {
|
|
11725
|
-
const local = getAuthStatus();
|
|
11726
|
-
if (local.sha256) updateAuthBinaryCache(local.sha256);
|
|
11727
|
-
}
|
|
11728
|
-
if (result.status === "installed") {
|
|
11729
|
-
outputLine(` \u2713 okx-auth installed successfully (${result.source ?? ""})`);
|
|
11730
|
-
} else if (result.status === "up-to-date") {
|
|
11731
|
-
outputLine(" \u2713 okx-auth is already up to date");
|
|
11732
|
-
} else {
|
|
11733
|
-
errorLine(` \u2717 Installation failed: ${result.error ?? "unknown error"}`);
|
|
11734
|
-
errorLine(" Hint: check network connectivity or try again later");
|
|
11735
|
-
process.exitCode = 1;
|
|
11736
|
-
}
|
|
11737
|
-
outputLine("");
|
|
11738
|
-
}
|
|
11739
|
-
async function cmdAuthRemove(force, json) {
|
|
11740
|
-
const local = getAuthStatus(void 0, { skipHash: true });
|
|
11741
|
-
if (!local.exists) {
|
|
11742
|
-
if (json) {
|
|
11743
|
-
outputLine(JSON.stringify({ status: "not-installed" }));
|
|
11744
|
-
} else {
|
|
11745
|
-
outputLine(" okx-auth is not installed.");
|
|
11746
|
-
}
|
|
11747
|
-
return;
|
|
11748
|
-
}
|
|
11749
|
-
if (!await confirmRemoval(force, local.binaryPath)) return;
|
|
11750
|
-
let result;
|
|
11751
|
-
try {
|
|
11752
|
-
result = removeAuthBinary();
|
|
11753
|
-
} catch (err) {
|
|
11754
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
11755
|
-
if (json) {
|
|
11756
|
-
outputLine(JSON.stringify({ status: "failed", error: msg }));
|
|
11757
|
-
} else {
|
|
11758
|
-
errorLine(` \u2717 Failed to remove: ${msg}`);
|
|
11759
|
-
}
|
|
11760
|
-
process.exitCode = 1;
|
|
11761
|
-
return;
|
|
11762
|
-
}
|
|
11763
|
-
if (json) {
|
|
11764
|
-
outputLine(JSON.stringify({ status: result.status, path: local.binaryPath }));
|
|
11765
|
-
return;
|
|
11766
|
-
}
|
|
11767
|
-
if (result.status === "removed") {
|
|
11768
|
-
clearAuthBinaryCache();
|
|
11769
|
-
outputLine(` \u2713 Removed: ${local.binaryPath}`);
|
|
11770
|
-
} else {
|
|
11771
|
-
outputLine(" okx-auth is not installed.");
|
|
11772
|
-
}
|
|
11773
|
-
}
|
|
11774
|
-
async function confirmRemoval(force, binaryPath) {
|
|
11775
|
-
if (force) return true;
|
|
11776
|
-
if (!process.stdin.isTTY) {
|
|
11777
|
-
errorLine(" Error: stdin is not a TTY. Use --force to skip confirmation.");
|
|
11778
|
-
process.exitCode = 1;
|
|
11779
|
-
return false;
|
|
11780
|
-
}
|
|
11781
|
-
const confirmed = await askConfirmation(
|
|
11782
|
-
` Remove okx-auth at ${binaryPath}? [y/N] `
|
|
11783
|
-
);
|
|
11784
|
-
if (!confirmed) {
|
|
11785
|
-
outputLine(" Cancelled.");
|
|
11786
|
-
return false;
|
|
11787
|
-
}
|
|
11788
|
-
return true;
|
|
11789
|
-
}
|
|
11790
|
-
function askConfirmation(prompt2) {
|
|
11791
|
-
return new Promise((resolve3) => {
|
|
11792
|
-
const rl = readline.createInterface({
|
|
11793
|
-
input: process.stdin,
|
|
11794
|
-
output: process.stdout
|
|
11795
|
-
});
|
|
11796
|
-
rl.question(prompt2, (answer) => {
|
|
11797
|
-
rl.close();
|
|
11798
|
-
resolve3(answer.trim().toLowerCase() === "y");
|
|
11799
|
-
});
|
|
11800
|
-
});
|
|
11801
|
-
}
|
|
11802
|
-
async function handleAuthCommand(action, _rest, v) {
|
|
11803
|
-
const site = v.site;
|
|
11804
|
-
const json = v.json;
|
|
11805
|
-
const manual = v.manual;
|
|
11806
|
-
const force = v.force;
|
|
11807
|
-
if (["login", "logout", "status"].includes(action)) {
|
|
11808
|
-
await ensureAuthBinaryLatest((msg) => errorLine(` ${msg}`));
|
|
11809
|
-
}
|
|
11810
|
-
switch (action) {
|
|
11811
|
-
case "login":
|
|
11812
|
-
return cmdAuthLogin({ site, manual });
|
|
11813
|
-
case "logout":
|
|
11814
|
-
return cmdAuthLogout();
|
|
11815
|
-
case "status":
|
|
11816
|
-
return cmdAuthStatus({ json });
|
|
11817
|
-
case "install":
|
|
11818
|
-
return cmdAuthInstall(json ?? false);
|
|
11819
|
-
case "install-status":
|
|
11820
|
-
return cmdAuthInstallStatus(json ?? false);
|
|
11821
|
-
case "remove":
|
|
11822
|
-
return cmdAuthRemove(force ?? false, json ?? false);
|
|
11823
|
-
default:
|
|
11824
|
-
errorLine(`Unknown auth command: ${action}`);
|
|
11825
|
-
errorLine("Available: login, logout, status, install, install-status, remove");
|
|
11826
|
-
process.exitCode = 1;
|
|
11827
|
-
}
|
|
11828
|
-
}
|
|
11829
|
-
|
|
11830
|
-
// src/commands/diagnose.ts
|
|
11831
|
-
import dns from "dns/promises";
|
|
11832
|
-
import net from "net";
|
|
11833
|
-
import os5 from "os";
|
|
11834
|
-
import tls from "tls";
|
|
11835
|
-
|
|
11836
11176
|
// src/commands/diagnose-utils.ts
|
|
11837
|
-
import fs4 from "fs";
|
|
11838
|
-
import { createRequire } from "module";
|
|
11839
11177
|
var _require = createRequire(import.meta.url);
|
|
11840
11178
|
function readCliVersion() {
|
|
11841
11179
|
for (const rel of ["../package.json", "../../package.json"]) {
|
|
@@ -11921,7 +11259,7 @@ function sanitize2(value) {
|
|
|
11921
11259
|
import fs5 from "fs";
|
|
11922
11260
|
import path4 from "path";
|
|
11923
11261
|
import os4 from "os";
|
|
11924
|
-
import { spawnSync, spawn
|
|
11262
|
+
import { spawnSync, spawn } from "child_process";
|
|
11925
11263
|
import { createRequire as createRequire2 } from "module";
|
|
11926
11264
|
import { fileURLToPath } from "url";
|
|
11927
11265
|
var _require2 = createRequire2(import.meta.url);
|
|
@@ -12255,7 +11593,7 @@ async function checkStdioHandshake(entryPath, report) {
|
|
|
12255
11593
|
clearTimeout(timer);
|
|
12256
11594
|
resolve3(passed);
|
|
12257
11595
|
};
|
|
12258
|
-
const child =
|
|
11596
|
+
const child = spawn(process.execPath, [entryPath], {
|
|
12259
11597
|
stdio: ["pipe", "pipe", "pipe"],
|
|
12260
11598
|
env: { ...process.env }
|
|
12261
11599
|
});
|
|
@@ -12374,7 +11712,7 @@ async function cmdDiagnoseMcp(options = {}) {
|
|
|
12374
11712
|
|
|
12375
11713
|
// src/commands/diagnose.ts
|
|
12376
11714
|
var CLI_VERSION = readCliVersion();
|
|
12377
|
-
var GIT_HASH = true ? "
|
|
11715
|
+
var GIT_HASH = true ? "7acf49fb" : "dev";
|
|
12378
11716
|
function maskKey2(key) {
|
|
12379
11717
|
if (!key) return "(not set)";
|
|
12380
11718
|
if (key.length <= 8) return "****";
|
|
@@ -12735,24 +12073,24 @@ function suggestSubcommand(action, knownActions) {
|
|
|
12735
12073
|
|
|
12736
12074
|
// src/commands/upgrade.ts
|
|
12737
12075
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
12738
|
-
import { readFileSync as
|
|
12739
|
-
import { dirname as
|
|
12740
|
-
import { homedir as
|
|
12076
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync9 } from "fs";
|
|
12077
|
+
import { dirname as dirname7, join as join10 } from "path";
|
|
12078
|
+
import { homedir as homedir8 } from "os";
|
|
12741
12079
|
var PACKAGES = ["@okx_ai/okx-trade-mcp", "@okx_ai/okx-trade-cli"];
|
|
12742
|
-
var CACHE_FILE2 =
|
|
12080
|
+
var CACHE_FILE2 = join10(homedir8(), ".okx", "last_check");
|
|
12743
12081
|
var THROTTLE_MS = 12 * 60 * 60 * 1e3;
|
|
12744
|
-
var NPM_BIN =
|
|
12082
|
+
var NPM_BIN = join10(dirname7(process.execPath), process.platform === "win32" ? "npm.cmd" : "npm");
|
|
12745
12083
|
function readLastCheck() {
|
|
12746
12084
|
try {
|
|
12747
|
-
return parseInt(
|
|
12085
|
+
return parseInt(readFileSync8(CACHE_FILE2, "utf-8").trim(), 10) || 0;
|
|
12748
12086
|
} catch {
|
|
12749
12087
|
return 0;
|
|
12750
12088
|
}
|
|
12751
12089
|
}
|
|
12752
12090
|
function writeLastCheck() {
|
|
12753
12091
|
try {
|
|
12754
|
-
|
|
12755
|
-
|
|
12092
|
+
mkdirSync9(join10(homedir8(), ".okx"), { recursive: true });
|
|
12093
|
+
writeFileSync7(CACHE_FILE2, String(Math.floor(Date.now() / 1e3)), "utf-8");
|
|
12756
12094
|
} catch {
|
|
12757
12095
|
}
|
|
12758
12096
|
}
|
|
@@ -14217,18 +13555,22 @@ async function cmdNewsSentimentRank(run, opts) {
|
|
|
14217
13555
|
}
|
|
14218
13556
|
|
|
14219
13557
|
// src/config/loader.ts
|
|
14220
|
-
|
|
14221
|
-
return loadConfig(
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
13558
|
+
function loadProfileConfig(opts) {
|
|
13559
|
+
return loadConfig(
|
|
13560
|
+
{
|
|
13561
|
+
profile: opts.profile,
|
|
13562
|
+
modules: opts.modules,
|
|
13563
|
+
readOnly: opts.readOnly ?? false,
|
|
13564
|
+
demo: opts.demo,
|
|
13565
|
+
live: opts.live,
|
|
13566
|
+
site: opts.site,
|
|
13567
|
+
userAgent: opts.userAgent,
|
|
13568
|
+
sourceTag: opts.sourceTag,
|
|
13569
|
+
skill: opts.skill,
|
|
13570
|
+
verbose: opts.verbose
|
|
13571
|
+
},
|
|
13572
|
+
{ entryPrefix: opts.entryPrefix, readEnv: opts.readEnv }
|
|
13573
|
+
);
|
|
14232
13574
|
}
|
|
14233
13575
|
|
|
14234
13576
|
// src/help.ts
|
|
@@ -14237,12 +13579,13 @@ var HELP_TREE = generateHelpTree();
|
|
|
14237
13579
|
function printGlobalHelp() {
|
|
14238
13580
|
const lines = [
|
|
14239
13581
|
"",
|
|
14240
|
-
`Usage: okx [--profile <name>] [--demo | --live] [--json] <module> <action> [args...]`,
|
|
13582
|
+
`Usage: okx [--profile <name>] [--demo | --live] [--skill <token>] [--json] <module> <action> [args...]`,
|
|
14241
13583
|
"",
|
|
14242
13584
|
"Global Options:",
|
|
14243
13585
|
` --profile <name> Use a named profile from ${configFilePath()}`,
|
|
14244
13586
|
" --demo Use simulated trading (demo) mode",
|
|
14245
13587
|
" --live Force live trading mode (overrides profile demo=true; mutually exclusive with --demo)",
|
|
13588
|
+
" --skill <token> OKX skill token for order tagging (from SKILL.md)",
|
|
14246
13589
|
" --json Output raw JSON",
|
|
14247
13590
|
" --env With --json, wrap output as {env, profile, data}",
|
|
14248
13591
|
" --verbose Show detailed network request/response info (stderr)",
|
|
@@ -14375,6 +13718,7 @@ import { parseArgs } from "util";
|
|
|
14375
13718
|
var CLI_OPTIONS = {
|
|
14376
13719
|
profile: { type: "string" },
|
|
14377
13720
|
demo: { type: "boolean", default: false },
|
|
13721
|
+
skill: { type: "string" },
|
|
14378
13722
|
json: { type: "boolean", default: false },
|
|
14379
13723
|
env: { type: "boolean", default: false },
|
|
14380
13724
|
help: { type: "boolean", default: false },
|
|
@@ -14554,9 +13898,6 @@ var CLI_OPTIONS = {
|
|
|
14554
13898
|
dir: { type: "string" },
|
|
14555
13899
|
page: { type: "string" },
|
|
14556
13900
|
format: { type: "string" },
|
|
14557
|
-
// auth
|
|
14558
|
-
site: { type: "string" },
|
|
14559
|
-
manual: { type: "boolean", default: false },
|
|
14560
13901
|
// event contract
|
|
14561
13902
|
underlying: { type: "string" },
|
|
14562
13903
|
seriesId: { type: "string" },
|
|
@@ -17780,14 +17121,14 @@ async function cmdDcdQuoteAndBuy(run, opts) {
|
|
|
17780
17121
|
}
|
|
17781
17122
|
|
|
17782
17123
|
// src/commands/skill.ts
|
|
17783
|
-
import { tmpdir, homedir as
|
|
17784
|
-
import { join as
|
|
17785
|
-
import { mkdirSync as
|
|
17124
|
+
import { tmpdir, homedir as homedir10 } from "os";
|
|
17125
|
+
import { join as join12, dirname as dirname8 } from "path";
|
|
17126
|
+
import { mkdirSync as mkdirSync10, rmSync, existsSync as existsSync8, copyFileSync as copyFileSync2 } from "fs";
|
|
17786
17127
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
17787
17128
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
17788
17129
|
function resolveNpx() {
|
|
17789
|
-
const sibling =
|
|
17790
|
-
if (
|
|
17130
|
+
const sibling = join12(dirname8(process.execPath), "npx");
|
|
17131
|
+
if (existsSync8(sibling)) return sibling;
|
|
17791
17132
|
return "npx";
|
|
17792
17133
|
}
|
|
17793
17134
|
var THIRD_PARTY_INSTALL_NOTICE = "Note: This skill was created by a third-party developer, not by OKX. Review SKILL.md before use.";
|
|
@@ -17840,13 +17181,13 @@ async function cmdSkillCategories(run, json) {
|
|
|
17840
17181
|
outputLine("");
|
|
17841
17182
|
}
|
|
17842
17183
|
async function cmdSkillAdd(name, config, json) {
|
|
17843
|
-
const tmpBase =
|
|
17844
|
-
|
|
17184
|
+
const tmpBase = join12(tmpdir(), `okx-skill-${randomUUID2()}`);
|
|
17185
|
+
mkdirSync10(tmpBase, { recursive: true });
|
|
17845
17186
|
try {
|
|
17846
17187
|
outputLine(`Downloading ${name}...`);
|
|
17847
17188
|
const client = new OkxRestClient(config);
|
|
17848
17189
|
const zipPath = await downloadSkillZip(client, name, tmpBase);
|
|
17849
|
-
const contentDir = await extractSkillZip(zipPath,
|
|
17190
|
+
const contentDir = await extractSkillZip(zipPath, join12(tmpBase, "content"));
|
|
17850
17191
|
const meta = readMetaJson(contentDir);
|
|
17851
17192
|
validateSkillMdExists(contentDir);
|
|
17852
17193
|
outputLine("Installing to detected agents...");
|
|
@@ -17856,7 +17197,7 @@ async function cmdSkillAdd(name, config, json) {
|
|
|
17856
17197
|
timeout: 6e4
|
|
17857
17198
|
});
|
|
17858
17199
|
} catch (e) {
|
|
17859
|
-
const savedZip =
|
|
17200
|
+
const savedZip = join12(process.cwd(), `${name}.zip`);
|
|
17860
17201
|
try {
|
|
17861
17202
|
copyFileSync2(zipPath, savedZip);
|
|
17862
17203
|
} catch {
|
|
@@ -17895,7 +17236,7 @@ function cmdSkillRemove(name, json) {
|
|
|
17895
17236
|
timeout: 6e4
|
|
17896
17237
|
});
|
|
17897
17238
|
} catch {
|
|
17898
|
-
const agentsPath =
|
|
17239
|
+
const agentsPath = join12(homedir10(), ".agents", "skills", name);
|
|
17899
17240
|
try {
|
|
17900
17241
|
rmSync(agentsPath, { recursive: true, force: true });
|
|
17901
17242
|
} catch {
|
|
@@ -17969,14 +17310,14 @@ function printSkillInstallResult(meta, json) {
|
|
|
17969
17310
|
}
|
|
17970
17311
|
|
|
17971
17312
|
// src/commands/pilot.ts
|
|
17972
|
-
import
|
|
17973
|
-
function
|
|
17313
|
+
import readline from "readline";
|
|
17314
|
+
function resolveChecksumMatch(local, cdnChecksum, cdnError) {
|
|
17974
17315
|
if (!local.exists) return "not-installed";
|
|
17975
17316
|
if (cdnError || !cdnChecksum) return "unavailable";
|
|
17976
17317
|
if (cdnChecksum.sha256 === local.sha256) return "match";
|
|
17977
17318
|
return "mismatch";
|
|
17978
17319
|
}
|
|
17979
|
-
function
|
|
17320
|
+
function checksumMatchLabel(match) {
|
|
17980
17321
|
if (match === "match") return "\u2713 match";
|
|
17981
17322
|
if (match === "mismatch") return "\u2717 mismatch (update available)";
|
|
17982
17323
|
return "CDN unreachable";
|
|
@@ -17989,9 +17330,9 @@ function formatStatusText(local, checksumMatch, cdnChecksum, runtimeMode) {
|
|
|
17989
17330
|
outputLine(` Installed : ${local.exists ? "yes" : "no"}`);
|
|
17990
17331
|
outputLine(` Platform : ${local.platform ?? "(unsupported)"}`);
|
|
17991
17332
|
if (local.exists) {
|
|
17992
|
-
outputLine(` File size : ${
|
|
17333
|
+
outputLine(` File size : ${formatBytes(local.fileSize)}`);
|
|
17993
17334
|
outputLine(` SHA-256 : ${local.sha256 ?? "(unknown)"}`);
|
|
17994
|
-
outputLine(` CDN check : ${
|
|
17335
|
+
outputLine(` CDN check : ${checksumMatchLabel(checksumMatch)}`);
|
|
17995
17336
|
if (cdnChecksum) {
|
|
17996
17337
|
outputLine(` CDN source : ${cdnChecksum.source}`);
|
|
17997
17338
|
}
|
|
@@ -18018,7 +17359,7 @@ async function cmdPilotStatus(json, binaryPath) {
|
|
|
18018
17359
|
cdnError = err instanceof Error ? err.message : String(err);
|
|
18019
17360
|
}
|
|
18020
17361
|
}
|
|
18021
|
-
const checksumMatch =
|
|
17362
|
+
const checksumMatch = resolveChecksumMatch(local, cdnChecksum, cdnError);
|
|
18022
17363
|
if (json) {
|
|
18023
17364
|
outputLine(
|
|
18024
17365
|
JSON.stringify({
|
|
@@ -18084,7 +17425,7 @@ async function cmdPilotRemove(force, json, binaryPath) {
|
|
|
18084
17425
|
process.exitCode = 1;
|
|
18085
17426
|
return;
|
|
18086
17427
|
}
|
|
18087
|
-
const confirmed = await
|
|
17428
|
+
const confirmed = await askConfirmation(
|
|
18088
17429
|
` Remove Pilot at ${local.binaryPath}? [y/N] `
|
|
18089
17430
|
);
|
|
18090
17431
|
if (!confirmed) {
|
|
@@ -18103,14 +17444,14 @@ async function cmdPilotRemove(force, json, binaryPath) {
|
|
|
18103
17444
|
outputLine(" Pilot is not installed.");
|
|
18104
17445
|
}
|
|
18105
17446
|
}
|
|
18106
|
-
function
|
|
17447
|
+
function formatBytes(bytes) {
|
|
18107
17448
|
if (bytes < 1024) return `${bytes} B`;
|
|
18108
17449
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
18109
17450
|
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
18110
17451
|
}
|
|
18111
|
-
function
|
|
17452
|
+
function askConfirmation(prompt2) {
|
|
18112
17453
|
return new Promise((resolve3) => {
|
|
18113
|
-
const rl =
|
|
17454
|
+
const rl = readline.createInterface({
|
|
18114
17455
|
input: process.stdin,
|
|
18115
17456
|
output: process.stdout
|
|
18116
17457
|
});
|
|
@@ -18579,7 +17920,7 @@ async function cmdEventCancel(run, opts) {
|
|
|
18579
17920
|
// src/index.ts
|
|
18580
17921
|
var _require3 = createRequire3(import.meta.url);
|
|
18581
17922
|
var CLI_VERSION2 = _require3("../package.json").version;
|
|
18582
|
-
var GIT_HASH2 = true ? "
|
|
17923
|
+
var GIT_HASH2 = true ? "7acf49fb" : "dev";
|
|
18583
17924
|
function handlePilotCommand(action, json, force, binaryPath) {
|
|
18584
17925
|
if (action === "status") return cmdPilotStatus(json, binaryPath);
|
|
18585
17926
|
if (action === "install") return cmdPilotInstall(json, binaryPath);
|
|
@@ -19622,13 +18963,13 @@ function handleNewsCommand(run, action, rest, v, json) {
|
|
|
19622
18963
|
const period = v.period;
|
|
19623
18964
|
const points = v.points !== void 0 ? Number(v.points) : 24;
|
|
19624
18965
|
const sortBy = v["sort-by"];
|
|
19625
|
-
const
|
|
19626
|
-
const searchOpts = { coins: v.coins, importance: v.importance, platform:
|
|
19627
|
-
const listOpts = { coins: v.coins, importance: v.importance, platform:
|
|
18966
|
+
const platform2 = v.platform;
|
|
18967
|
+
const searchOpts = { coins: v.coins, importance: v.importance, platform: platform2, sentiment: v.sentiment, sortBy, begin, end, language, detailLvl, limit, after, json };
|
|
18968
|
+
const listOpts = { coins: v.coins, importance: v.importance, platform: platform2, begin, end, language, detailLvl, limit, after, json };
|
|
19628
18969
|
const dispatch = {
|
|
19629
18970
|
latest: () => cmdNewsLatest(run, listOpts),
|
|
19630
|
-
important: () => cmdNewsImportant(run, { coins: v.coins, platform:
|
|
19631
|
-
"by-coin": () => cmdNewsByCoin(run, v.coins ?? rest[0], { importance: v.importance, platform:
|
|
18971
|
+
important: () => cmdNewsImportant(run, { coins: v.coins, platform: platform2, begin, end, language, detailLvl, limit, json }),
|
|
18972
|
+
"by-coin": () => cmdNewsByCoin(run, v.coins ?? rest[0], { importance: v.importance, platform: platform2, begin, end, language, detailLvl, limit, json }),
|
|
19632
18973
|
search: () => cmdNewsSearch(run, v.keyword ?? rest[0], searchOpts),
|
|
19633
18974
|
detail: () => cmdNewsDetail(run, rest[0], { language, json }),
|
|
19634
18975
|
platforms: () => cmdNewsPlatforms(run, { json }),
|
|
@@ -19769,7 +19110,7 @@ function wrapRunnerWithLogger(baseRunner, logger, verbose = false) {
|
|
|
19769
19110
|
async function runDiagnose(v) {
|
|
19770
19111
|
let config;
|
|
19771
19112
|
try {
|
|
19772
|
-
config =
|
|
19113
|
+
config = loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI", skill: v.skill, entryPrefix: "CLI" });
|
|
19773
19114
|
} catch {
|
|
19774
19115
|
}
|
|
19775
19116
|
return cmdDiagnose(config, v.profile ?? "default", { mcp: v.mcp, cli: v.cli, all: v.all, output: v.output });
|
|
@@ -19792,7 +19133,6 @@ function routeManagementCommand(module, action, rest, json, v) {
|
|
|
19792
19133
|
handleSetupCommand(v);
|
|
19793
19134
|
return true;
|
|
19794
19135
|
}
|
|
19795
|
-
if (module === "auth") return handleAuthCommand(action, rest, v);
|
|
19796
19136
|
if (module === "upgrade") return cmdUpgrade(CLI_VERSION2, { beta: v.beta, check: v.check, force: v.force }, json);
|
|
19797
19137
|
if (module === "pilot") {
|
|
19798
19138
|
const r = handlePilotCommand(action, json, v.force ?? false);
|
|
@@ -19825,7 +19165,7 @@ async function main() {
|
|
|
19825
19165
|
const json = v.json ?? false;
|
|
19826
19166
|
const mgmt = routeManagementCommand(module, action, rest, json, v);
|
|
19827
19167
|
if (mgmt !== void 0) return mgmt === true ? void 0 : mgmt;
|
|
19828
|
-
const config =
|
|
19168
|
+
const config = loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI", skill: v.skill, entryPrefix: "CLI" });
|
|
19829
19169
|
setEnvContext({ demo: config.demo, profile: v.profile ?? "default" });
|
|
19830
19170
|
setJsonEnvEnabled(v.env ?? false);
|
|
19831
19171
|
const client = new OkxRestClient(config);
|