@okx_ai/okx-trade-cli 1.3.2-beta.2 → 1.3.2-beta.4
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 +1016 -250
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/postinstall.js +78 -1
- package/scripts/postinstall-download.js +0 -152
package/dist/index.js
CHANGED
|
@@ -21,23 +21,26 @@ import {
|
|
|
21
21
|
import { homedir as homedir2 } from "os";
|
|
22
22
|
import { join as join2, dirname } from "path";
|
|
23
23
|
import { createHmac } from "crypto";
|
|
24
|
+
import { spawn, execFile as execFile2 } from "child_process";
|
|
25
|
+
import { homedir as homedir3 } from "os";
|
|
26
|
+
import { join as join3 } from "path";
|
|
24
27
|
import fs from "fs";
|
|
25
28
|
import path from "path";
|
|
26
29
|
import os from "os";
|
|
27
30
|
import { writeFileSync as writeFileSync2, renameSync as renameSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
28
|
-
import { join as
|
|
31
|
+
import { join as join4, resolve, basename, sep } from "path";
|
|
29
32
|
import { randomUUID } from "crypto";
|
|
30
33
|
import yauzl from "yauzl";
|
|
31
34
|
import { createWriteStream, mkdirSync as mkdirSync3 } from "fs";
|
|
32
35
|
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
33
36
|
import { readFileSync as readFileSync2, existsSync } from "fs";
|
|
34
|
-
import { join as
|
|
37
|
+
import { join as join5 } from "path";
|
|
35
38
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync2 } from "fs";
|
|
36
|
-
import { join as
|
|
37
|
-
import { homedir as homedir3 } from "os";
|
|
38
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync3 } from "fs";
|
|
39
|
-
import { join as join6, dirname as dirname4 } from "path";
|
|
39
|
+
import { join as join6, dirname as dirname3 } from "path";
|
|
40
40
|
import { homedir as homedir4 } from "os";
|
|
41
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync3 } from "fs";
|
|
42
|
+
import { join as join7, dirname as dirname4 } from "path";
|
|
43
|
+
import { homedir as homedir5 } from "os";
|
|
41
44
|
|
|
42
45
|
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/error.js
|
|
43
46
|
function getLineColFromPtr(string, ptr) {
|
|
@@ -867,8 +870,8 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
|
867
870
|
|
|
868
871
|
// ../core/dist/index.js
|
|
869
872
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync4 } from "fs";
|
|
870
|
-
import { join as
|
|
871
|
-
import { homedir as
|
|
873
|
+
import { join as join8 } from "path";
|
|
874
|
+
import { homedir as homedir6 } from "os";
|
|
872
875
|
import fs2 from "fs";
|
|
873
876
|
import path2 from "path";
|
|
874
877
|
import os2 from "os";
|
|
@@ -876,6 +879,18 @@ import * as fs3 from "fs";
|
|
|
876
879
|
import * as path3 from "path";
|
|
877
880
|
import * as os3 from "os";
|
|
878
881
|
import { execFileSync } from "child_process";
|
|
882
|
+
import {
|
|
883
|
+
createWriteStream as createWriteStream3,
|
|
884
|
+
mkdirSync as mkdirSync9,
|
|
885
|
+
chmodSync as chmodSync2,
|
|
886
|
+
existsSync as existsSync7,
|
|
887
|
+
unlinkSync as unlinkSync4,
|
|
888
|
+
renameSync as renameSync4
|
|
889
|
+
} from "fs";
|
|
890
|
+
import { homedir as homedir9, platform as platform2 } from "os";
|
|
891
|
+
import { join as join11, dirname as dirname7 } from "path";
|
|
892
|
+
import { get as httpsGet2 } from "https";
|
|
893
|
+
import { get as httpGet2 } from "http";
|
|
879
894
|
import {
|
|
880
895
|
readFileSync as readFileSync7,
|
|
881
896
|
createWriteStream as createWriteStream2,
|
|
@@ -886,10 +901,13 @@ import {
|
|
|
886
901
|
renameSync as renameSync3
|
|
887
902
|
} from "fs";
|
|
888
903
|
import { createHash } from "crypto";
|
|
889
|
-
import { homedir as
|
|
890
|
-
import { join as
|
|
904
|
+
import { homedir as homedir8, platform, arch } from "os";
|
|
905
|
+
import { join as join10, dirname as dirname6 } from "path";
|
|
891
906
|
import { get as httpsGet } from "https";
|
|
892
907
|
import { get as httpGet } from "http";
|
|
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";
|
|
893
911
|
var EXEC_TIMEOUT_MS = 3e4;
|
|
894
912
|
var ALLOWED_DOMAIN_RE = /^[\w.-]+\.okx\.com$/;
|
|
895
913
|
var PILOT_BIN_DIR = join(homedir(), ".okx", "bin");
|
|
@@ -1201,6 +1219,11 @@ var ConfigError = class extends OkxMcpError {
|
|
|
1201
1219
|
super("ConfigError", message, { suggestion });
|
|
1202
1220
|
}
|
|
1203
1221
|
};
|
|
1222
|
+
var NotLoggedInError = class extends ConfigError {
|
|
1223
|
+
constructor(suggestion = "Run `okx auth login` to authenticate.") {
|
|
1224
|
+
super("Not logged in.", suggestion);
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1204
1227
|
var ValidationError = class extends OkxMcpError {
|
|
1205
1228
|
constructor(message, suggestion) {
|
|
1206
1229
|
super("ValidationError", message, { suggestion });
|
|
@@ -1253,6 +1276,97 @@ function toToolErrorPayload(error, fallbackEndpoint) {
|
|
|
1253
1276
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1254
1277
|
};
|
|
1255
1278
|
}
|
|
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
|
+
}
|
|
1256
1370
|
function sleep(ms) {
|
|
1257
1371
|
return new Promise((resolve3) => {
|
|
1258
1372
|
setTimeout(resolve3, ms);
|
|
@@ -1384,6 +1498,7 @@ function maskKey(key) {
|
|
|
1384
1498
|
if (key.length <= 8) return "***";
|
|
1385
1499
|
return `${key.slice(0, 3)}***${key.slice(-3)}`;
|
|
1386
1500
|
}
|
|
1501
|
+
var TOKEN_CACHE_TTL_MS = 6e4;
|
|
1387
1502
|
function vlog2(message) {
|
|
1388
1503
|
process.stderr.write(`[verbose] ${message}
|
|
1389
1504
|
`);
|
|
@@ -1392,6 +1507,8 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1392
1507
|
config;
|
|
1393
1508
|
rateLimiter;
|
|
1394
1509
|
dispatcher;
|
|
1510
|
+
cachedAccessToken;
|
|
1511
|
+
cachedAccessTokenAt = 0;
|
|
1395
1512
|
pilot;
|
|
1396
1513
|
constructor(config) {
|
|
1397
1514
|
this.config = config;
|
|
@@ -1406,6 +1523,51 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1406
1523
|
hasCustomProxy: !!config.proxyUrl
|
|
1407
1524
|
});
|
|
1408
1525
|
}
|
|
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
|
+
}
|
|
1409
1571
|
/** The canonical base URL for this client (e.g. https://www.okx.com). */
|
|
1410
1572
|
get baseUrl() {
|
|
1411
1573
|
return this.config.baseUrl;
|
|
@@ -1464,18 +1626,6 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1464
1626
|
});
|
|
1465
1627
|
}
|
|
1466
1628
|
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
|
-
}
|
|
1479
1629
|
const payload = `${timestamp}${method.toUpperCase()}${requestPath}${bodyJson}`;
|
|
1480
1630
|
const signature = signOkxPayload(payload, this.config.secretKey);
|
|
1481
1631
|
headers.set("OK-ACCESS-KEY", this.config.apiKey);
|
|
@@ -1590,7 +1740,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1590
1740
|
const conn = this.pilot.getConnectionParams();
|
|
1591
1741
|
this.logRequest("POST", `${conn.baseUrl}${path42}`, "private");
|
|
1592
1742
|
const reqConfig = { method: "POST", path: path42, auth: "private" };
|
|
1593
|
-
const headers = this.buildHeaders(reqConfig, path42, bodyJson, getNow());
|
|
1743
|
+
const headers = await this.buildHeaders(reqConfig, path42, bodyJson, getNow());
|
|
1594
1744
|
if (conn.userAgent) {
|
|
1595
1745
|
headers.set("User-Agent", conn.userAgent);
|
|
1596
1746
|
}
|
|
@@ -1711,7 +1861,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1711
1861
|
// Header building
|
|
1712
1862
|
// ---------------------------------------------------------------------------
|
|
1713
1863
|
/** Build HTTP headers. reqConfig.extraHeaders must NOT contain auth keys (OK-ACCESS-*). */
|
|
1714
|
-
buildHeaders(reqConfig, requestPath, bodyJson, timestamp) {
|
|
1864
|
+
async buildHeaders(reqConfig, requestPath, bodyJson, timestamp) {
|
|
1715
1865
|
const headers = new Headers({
|
|
1716
1866
|
"Content-Type": "application/json",
|
|
1717
1867
|
Accept: "application/json"
|
|
@@ -1720,7 +1870,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1720
1870
|
headers.set("User-Agent", this.config.userAgent);
|
|
1721
1871
|
}
|
|
1722
1872
|
if (reqConfig.auth === "private") {
|
|
1723
|
-
this.
|
|
1873
|
+
await this.applyAuth(headers, reqConfig.method, requestPath, bodyJson, timestamp);
|
|
1724
1874
|
}
|
|
1725
1875
|
const useSimulated = reqConfig.simulatedTrading !== void 0 ? reqConfig.simulatedTrading : this.config.demo;
|
|
1726
1876
|
if (useSimulated) {
|
|
@@ -1774,7 +1924,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1774
1924
|
if (reqConfig.rateLimit) {
|
|
1775
1925
|
await this.rateLimiter.consume(reqConfig.rateLimit);
|
|
1776
1926
|
}
|
|
1777
|
-
const headers = this.buildHeaders(reqConfig, requestPath, bodyJson, timestamp);
|
|
1927
|
+
const headers = await this.buildHeaders(reqConfig, requestPath, bodyJson, timestamp);
|
|
1778
1928
|
if (conn.userAgent) {
|
|
1779
1929
|
headers.set("User-Agent", conn.userAgent);
|
|
1780
1930
|
}
|
|
@@ -1926,6 +2076,23 @@ function privateRateLimit(key, rps = 10) {
|
|
|
1926
2076
|
refillPerSecond: rps
|
|
1927
2077
|
};
|
|
1928
2078
|
}
|
|
2079
|
+
var CURSOR_PROPS = {
|
|
2080
|
+
after: { type: "string", description: "Cursor: return older records" },
|
|
2081
|
+
before: { type: "string", description: "Cursor: return newer records" }
|
|
2082
|
+
};
|
|
2083
|
+
var TIME_RANGE_PROPS = {
|
|
2084
|
+
begin: { type: "string", description: "Start time (ms)" },
|
|
2085
|
+
end: { type: "string", description: "End time (ms)" }
|
|
2086
|
+
};
|
|
2087
|
+
function readPaginationParams(args, readStr, readNum) {
|
|
2088
|
+
return {
|
|
2089
|
+
after: readStr(args, "after"),
|
|
2090
|
+
before: readStr(args, "before"),
|
|
2091
|
+
begin: readStr(args, "begin"),
|
|
2092
|
+
end: readStr(args, "end"),
|
|
2093
|
+
limit: readNum(args, "limit")
|
|
2094
|
+
};
|
|
2095
|
+
}
|
|
1929
2096
|
function assertNotDemo(config, endpoint) {
|
|
1930
2097
|
if (config.demo) {
|
|
1931
2098
|
throw new ConfigError(
|
|
@@ -2197,7 +2364,7 @@ var OKX_SITES = {
|
|
|
2197
2364
|
},
|
|
2198
2365
|
us: {
|
|
2199
2366
|
label: "US",
|
|
2200
|
-
apiBaseUrl: "https://
|
|
2367
|
+
apiBaseUrl: "https://us.okx.com",
|
|
2201
2368
|
webUrl: "https://app.okx.com"
|
|
2202
2369
|
}
|
|
2203
2370
|
};
|
|
@@ -3744,7 +3911,7 @@ function safeWriteFile(targetDir, fileName, data) {
|
|
|
3744
3911
|
throw new Error(`Invalid file name: "${fileName}"`);
|
|
3745
3912
|
}
|
|
3746
3913
|
const resolvedDir = resolve(targetDir);
|
|
3747
|
-
const filePath =
|
|
3914
|
+
const filePath = join4(resolvedDir, safeName);
|
|
3748
3915
|
const resolvedPath = resolve(filePath);
|
|
3749
3916
|
if (!resolvedPath.startsWith(resolvedDir + sep)) {
|
|
3750
3917
|
throw new Error(`Path traversal detected: "${fileName}" resolves outside target directory`);
|
|
@@ -3872,7 +4039,7 @@ async function extractSkillZip(zipPath, targetDir, limits) {
|
|
|
3872
4039
|
});
|
|
3873
4040
|
}
|
|
3874
4041
|
function readMetaJson(contentDir) {
|
|
3875
|
-
const metaPath =
|
|
4042
|
+
const metaPath = join5(contentDir, "_meta.json");
|
|
3876
4043
|
if (!existsSync(metaPath)) {
|
|
3877
4044
|
throw new Error(`_meta.json not found in ${contentDir}. Invalid skill package.`);
|
|
3878
4045
|
}
|
|
@@ -3898,12 +4065,12 @@ function readMetaJson(contentDir) {
|
|
|
3898
4065
|
};
|
|
3899
4066
|
}
|
|
3900
4067
|
function validateSkillMdExists(contentDir) {
|
|
3901
|
-
const skillMdPath =
|
|
4068
|
+
const skillMdPath = join5(contentDir, "SKILL.md");
|
|
3902
4069
|
if (!existsSync(skillMdPath)) {
|
|
3903
4070
|
throw new Error(`SKILL.md not found in ${contentDir}. Invalid skill package.`);
|
|
3904
4071
|
}
|
|
3905
4072
|
}
|
|
3906
|
-
var DEFAULT_REGISTRY_PATH =
|
|
4073
|
+
var DEFAULT_REGISTRY_PATH = join6(homedir4(), ".okx", "skills", "registry.json");
|
|
3907
4074
|
function readRegistry(registryPath = DEFAULT_REGISTRY_PATH) {
|
|
3908
4075
|
if (!existsSync2(registryPath)) {
|
|
3909
4076
|
return { version: 1, skills: {} };
|
|
@@ -6341,37 +6508,45 @@ function registerEventContractTools() {
|
|
|
6341
6508
|
{
|
|
6342
6509
|
name: "event_get_orders",
|
|
6343
6510
|
module: "event",
|
|
6344
|
-
description: "Query event contract orders
|
|
6511
|
+
description: "Query event contract orders (open, 7d history, or 3-month archive). outcome pre-translated (YES/NO/UP/DOWN). Do NOT use for trade executions \u2014 use event_get_fills for fill records and settlement outcomes.",
|
|
6345
6512
|
isWrite: false,
|
|
6346
6513
|
inputSchema: {
|
|
6347
6514
|
type: "object",
|
|
6348
6515
|
properties: {
|
|
6349
|
-
|
|
6516
|
+
status: {
|
|
6350
6517
|
type: "string",
|
|
6351
|
-
|
|
6518
|
+
enum: ["open", "history", "archive"],
|
|
6519
|
+
description: "open=active, history=7d (default), archive=3mo"
|
|
6352
6520
|
},
|
|
6353
|
-
|
|
6521
|
+
instId: {
|
|
6354
6522
|
type: "string",
|
|
6355
|
-
description: "
|
|
6523
|
+
description: "Event contract instrument ID"
|
|
6356
6524
|
},
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6525
|
+
ordType: { type: "string", description: "Order type filter" },
|
|
6526
|
+
state: { type: "string", description: "canceled|filled (only for history/archive)" },
|
|
6527
|
+
...CURSOR_PROPS,
|
|
6528
|
+
...TIME_RANGE_PROPS,
|
|
6529
|
+
limit: { type: "number", description: "Max results (default 100)" }
|
|
6361
6530
|
}
|
|
6362
6531
|
},
|
|
6363
6532
|
handler: async (rawArgs, context) => {
|
|
6364
6533
|
const args = asRecord(rawArgs);
|
|
6365
|
-
const
|
|
6366
|
-
const
|
|
6367
|
-
|
|
6534
|
+
const status = readString(args, "status") ?? "history";
|
|
6535
|
+
const endpointMap = {
|
|
6536
|
+
open: "/api/v5/trade/orders-pending",
|
|
6537
|
+
archive: "/api/v5/trade/orders-history-archive"
|
|
6538
|
+
};
|
|
6539
|
+
const endpoint = endpointMap[status] ?? "/api/v5/trade/orders-history";
|
|
6540
|
+
const params = compactObject({
|
|
6541
|
+
instType: "EVENTS",
|
|
6542
|
+
instId: readString(args, "instId"),
|
|
6543
|
+
ordType: readString(args, "ordType"),
|
|
6544
|
+
state: readString(args, "state"),
|
|
6545
|
+
...readPaginationParams(args, readString, readNumber)
|
|
6546
|
+
});
|
|
6368
6547
|
const response = await context.client.privateGet(
|
|
6369
6548
|
endpoint,
|
|
6370
|
-
|
|
6371
|
-
instType: "EVENTS",
|
|
6372
|
-
instId: readString(args, "instId"),
|
|
6373
|
-
limit: readNumber(args, "limit")
|
|
6374
|
-
}),
|
|
6549
|
+
params,
|
|
6375
6550
|
privateRateLimit("event_get_orders", 20)
|
|
6376
6551
|
);
|
|
6377
6552
|
const base = normalizeResponse(response);
|
|
@@ -6385,41 +6560,51 @@ function registerEventContractTools() {
|
|
|
6385
6560
|
stateLabel: mapOrderState(String(item["state"] ?? ""))
|
|
6386
6561
|
};
|
|
6387
6562
|
}) : base["data"];
|
|
6388
|
-
return { ...base, data };
|
|
6563
|
+
return { ...base, data, requestParams: params };
|
|
6389
6564
|
}
|
|
6390
6565
|
},
|
|
6391
6566
|
{
|
|
6392
6567
|
name: "event_get_fills",
|
|
6393
6568
|
module: "event",
|
|
6394
|
-
description: "Get event contract fill history. outcome pre-translated (YES/NO/UP/DOWN). Each record includes a 'type' field: 'fill' (
|
|
6569
|
+
description: "Get event contract fill history (trade executions and settlement payouts). archive=true for up to 3mo, false (default) for last 3d. outcome pre-translated (YES/NO/UP/DOWN). Each record includes a 'type' field: 'fill' (opening trade) or 'settlement' (expiry payout with settlementResult win/loss and pnl). Do NOT use for order status \u2014 use event_get_orders instead.",
|
|
6395
6570
|
isWrite: false,
|
|
6396
6571
|
inputSchema: {
|
|
6397
6572
|
type: "object",
|
|
6398
6573
|
properties: {
|
|
6574
|
+
archive: {
|
|
6575
|
+
type: "boolean",
|
|
6576
|
+
description: "true=up to 3mo, false=3d (default)"
|
|
6577
|
+
},
|
|
6399
6578
|
instId: {
|
|
6400
6579
|
type: "string",
|
|
6401
6580
|
description: "Event contract instrument ID"
|
|
6402
6581
|
},
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
}
|
|
6582
|
+
ordId: { type: "string", description: "Order ID filter" },
|
|
6583
|
+
...CURSOR_PROPS,
|
|
6584
|
+
...TIME_RANGE_PROPS,
|
|
6585
|
+
limit: { type: "number", description: "Max results (default 100 or 20 for archive)" }
|
|
6407
6586
|
}
|
|
6408
6587
|
},
|
|
6409
6588
|
handler: async (rawArgs, context) => {
|
|
6410
6589
|
const args = asRecord(rawArgs);
|
|
6590
|
+
const archive = readBoolean(args, "archive") ?? false;
|
|
6591
|
+
const path42 = archive ? "/api/v5/trade/fills-history" : "/api/v5/trade/fills";
|
|
6592
|
+
const paging = readPaginationParams(args, readString, readNumber);
|
|
6593
|
+
const params = compactObject({
|
|
6594
|
+
instType: "EVENTS",
|
|
6595
|
+
instId: readString(args, "instId"),
|
|
6596
|
+
ordId: readString(args, "ordId"),
|
|
6597
|
+
...paging,
|
|
6598
|
+
limit: paging.limit ?? (archive ? 20 : void 0)
|
|
6599
|
+
});
|
|
6411
6600
|
const response = await context.client.privateGet(
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
instType: "EVENTS",
|
|
6415
|
-
instId: readString(args, "instId"),
|
|
6416
|
-
limit: readNumber(args, "limit")
|
|
6417
|
-
}),
|
|
6601
|
+
path42,
|
|
6602
|
+
params,
|
|
6418
6603
|
privateRateLimit("event_get_fills", 20)
|
|
6419
6604
|
);
|
|
6420
6605
|
const base = normalizeResponse(response);
|
|
6421
6606
|
const data = Array.isArray(base["data"]) ? base["data"].map(enrichFill) : base["data"];
|
|
6422
|
-
return { ...base, data };
|
|
6607
|
+
return { ...base, data, requestParams: params };
|
|
6423
6608
|
}
|
|
6424
6609
|
},
|
|
6425
6610
|
// -----------------------------------------------------------------------
|
|
@@ -6503,7 +6688,7 @@ function registerEventContractTools() {
|
|
|
6503
6688
|
{
|
|
6504
6689
|
name: "event_amend_order",
|
|
6505
6690
|
module: "event",
|
|
6506
|
-
description: "Amend a pending event contract order (change price or size). [CAUTION] Modifies a real order. Before amending, call event_get_orders(
|
|
6691
|
+
description: "Amend a pending event contract order (change price or size). [CAUTION] Modifies a real order. Before amending, call event_get_orders(status=open) to obtain the ordId and confirm the order is still pending. Only limit/post_only orders can be amended.",
|
|
6507
6692
|
isWrite: true,
|
|
6508
6693
|
inputSchema: {
|
|
6509
6694
|
type: "object",
|
|
@@ -6534,7 +6719,7 @@ function registerEventContractTools() {
|
|
|
6534
6719
|
{
|
|
6535
6720
|
name: "event_cancel_order",
|
|
6536
6721
|
module: "event",
|
|
6537
|
-
description: "Cancel a pending event contract order. [CAUTION] Cancels a real order. Before cancelling, call event_get_orders(
|
|
6722
|
+
description: "Cancel a pending event contract order. [CAUTION] Cancels a real order. Before cancelling, call event_get_orders(status=open) to obtain the ordId and confirm the order is still pending. instId must be the full event contract instrument ID (e.g. BTC-ABOVE-DAILY-260224-1600-69700), NOT a spot trading pair.",
|
|
6538
6723
|
isWrite: true,
|
|
6539
6724
|
inputSchema: {
|
|
6540
6725
|
type: "object",
|
|
@@ -6582,27 +6767,27 @@ var PATH_SIGNAL_HISTORY = "/api/v5/journal/smartmoney/signal-history";
|
|
|
6582
6767
|
var SIGNAL_POOL_FILTER_PROPS = {
|
|
6583
6768
|
sortType: {
|
|
6584
6769
|
type: "string",
|
|
6585
|
-
description: "pnl
|
|
6770
|
+
description: "Pool ranking: pnl|pnlRatio (default pnl)"
|
|
6586
6771
|
},
|
|
6587
6772
|
period: {
|
|
6588
6773
|
type: "string",
|
|
6589
|
-
description: "3|7|30|90
|
|
6774
|
+
description: "Win-rate window days: 3|7|30|90 (default 90). Not snapshot range."
|
|
6590
6775
|
},
|
|
6591
6776
|
pnl: {
|
|
6592
6777
|
type: "string",
|
|
6593
|
-
description: "PNL_ANY|PNL_TOP50|PNL_TOP20|PNL_TOP5"
|
|
6778
|
+
description: "Top N% by PnL: PNL_ANY|PNL_TOP50|PNL_TOP20|PNL_TOP5 (default PNL_ANY)"
|
|
6594
6779
|
},
|
|
6595
6780
|
winRatio: {
|
|
6596
6781
|
type: "string",
|
|
6597
|
-
description: "WR_ANY|WR_GE_50|WR_GE_80"
|
|
6782
|
+
description: "Min win-rate: WR_ANY|WR_GE_50|WR_GE_80 (default WR_ANY)"
|
|
6598
6783
|
},
|
|
6599
6784
|
maxRetreat: {
|
|
6600
6785
|
type: "string",
|
|
6601
|
-
description: "MR_ANY|MR_LE_20|MR_LE_50"
|
|
6786
|
+
description: "Max drawdown: MR_ANY|MR_LE_20|MR_LE_50 (default MR_ANY)"
|
|
6602
6787
|
},
|
|
6603
6788
|
asset: {
|
|
6604
6789
|
type: "string",
|
|
6605
|
-
description: "AUM_ANY|AUM_TOP50|AUM_TOP20|AUM_TOP5"
|
|
6790
|
+
description: "Top N% by AUM: AUM_ANY|AUM_TOP50|AUM_TOP20|AUM_TOP5 (default AUM_ANY)"
|
|
6606
6791
|
}
|
|
6607
6792
|
};
|
|
6608
6793
|
var LEADERBOARD_POOL_FILTER_PROPS = {
|
|
@@ -6654,39 +6839,39 @@ function registerSmartmoneyTools() {
|
|
|
6654
6839
|
{
|
|
6655
6840
|
name: "smartmoney_get_overview",
|
|
6656
6841
|
module: "smartmoney",
|
|
6657
|
-
description: "Multi-currency smart money overview ranked by most-watched
|
|
6842
|
+
description: "Multi-currency smart money overview, ranked by tradersWithPosition DESC (most-watched first). Requires either ts (recommended, Date.now()) or dataVersion (yyyyMMddHHmm UTC) \u2014 at least one must be set; ts wins when both are sent. For single-currency signal with entry prices and trend, use smartmoney_get_signal.",
|
|
6658
6843
|
isWrite: false,
|
|
6659
6844
|
inputSchema: {
|
|
6660
6845
|
type: "object",
|
|
6661
6846
|
properties: {
|
|
6662
|
-
|
|
6847
|
+
ts: {
|
|
6663
6848
|
type: "string",
|
|
6664
|
-
description: "
|
|
6849
|
+
description: "Recommended. Timestamp ms \u2014 use Date.now() for latest."
|
|
6665
6850
|
},
|
|
6666
|
-
|
|
6851
|
+
dataVersion: {
|
|
6667
6852
|
type: "string",
|
|
6668
|
-
description: "
|
|
6853
|
+
description: "Alternative. yyyyMMddHHmm UTC for prior snapshot. If both sent, ts wins."
|
|
6669
6854
|
},
|
|
6670
6855
|
instType: {
|
|
6671
6856
|
type: "string",
|
|
6672
|
-
description: "SPOT|MARGIN|FUTURES|SWAP|OPTION"
|
|
6857
|
+
description: "SPOT|MARGIN|FUTURES|SWAP|OPTION (default SWAP)"
|
|
6673
6858
|
},
|
|
6674
6859
|
...SIGNAL_POOL_FILTER_PROPS,
|
|
6675
6860
|
lmtNum: {
|
|
6676
6861
|
type: "string",
|
|
6677
|
-
description: "Trader pool size 1-500"
|
|
6862
|
+
description: "Trader pool size 1-500 (default 100)"
|
|
6678
6863
|
},
|
|
6679
6864
|
instCcyList: {
|
|
6680
6865
|
type: "string",
|
|
6681
|
-
description: "Comma-separated e.g. BTC,ETH,SOL"
|
|
6866
|
+
description: "Comma-separated currency codes e.g. BTC,ETH,SOL (prefix-matched against instId)"
|
|
6682
6867
|
},
|
|
6683
6868
|
instCcy: {
|
|
6684
6869
|
type: "string",
|
|
6685
|
-
description: "Single currency e.g. BTC"
|
|
6870
|
+
description: "Single currency e.g. BTC; alias for instCcyList (instCcyList wins if both set)"
|
|
6686
6871
|
},
|
|
6687
6872
|
topInstruments: {
|
|
6688
6873
|
type: "string",
|
|
6689
|
-
description: "Top N instruments 1-100"
|
|
6874
|
+
description: "Top N instruments 1-100 (default 20)"
|
|
6690
6875
|
}
|
|
6691
6876
|
}
|
|
6692
6877
|
},
|
|
@@ -6718,7 +6903,7 @@ function registerSmartmoneyTools() {
|
|
|
6718
6903
|
{
|
|
6719
6904
|
name: "smartmoney_get_signal",
|
|
6720
6905
|
module: "smartmoney",
|
|
6721
|
-
description: "Single-currency consensus signal: long/short ratio, entry prices, trend, capital flow.
|
|
6906
|
+
description: "Single-currency consensus signal: long/short ratio, entry prices, trend, capital flow. Requires either instId (e.g. BTC-USDT-SWAP, recommended) or instCcy (SPOT/SWAP only) \u2014 instId wins when both are sent. Requires either ts (recommended, Date.now()) or dataVersion (yyyyMMddHHmm UTC) \u2014 at least one must be set; ts wins when both are sent. For multi-currency overview, use smartmoney_get_overview. For timeline, use smartmoney_get_signal_history.",
|
|
6722
6907
|
isWrite: false,
|
|
6723
6908
|
inputSchema: {
|
|
6724
6909
|
type: "object",
|
|
@@ -6729,24 +6914,24 @@ function registerSmartmoneyTools() {
|
|
|
6729
6914
|
},
|
|
6730
6915
|
instCcy: {
|
|
6731
6916
|
type: "string",
|
|
6732
|
-
description: "e.g. BTC
|
|
6917
|
+
description: "e.g. BTC (SPOT/SWAP only); instId takes precedence if both set"
|
|
6733
6918
|
},
|
|
6734
|
-
|
|
6919
|
+
ts: {
|
|
6735
6920
|
type: "string",
|
|
6736
|
-
description: "
|
|
6921
|
+
description: "Recommended. Timestamp ms \u2014 use Date.now() for latest."
|
|
6737
6922
|
},
|
|
6738
|
-
|
|
6923
|
+
dataVersion: {
|
|
6739
6924
|
type: "string",
|
|
6740
|
-
description: "
|
|
6925
|
+
description: "Alternative. yyyyMMddHHmm UTC for prior snapshot. If both sent, ts wins."
|
|
6741
6926
|
},
|
|
6742
6927
|
...SIGNAL_POOL_FILTER_PROPS,
|
|
6743
6928
|
lmtNum: {
|
|
6744
6929
|
type: "string",
|
|
6745
|
-
description: "Trader pool size 1-500"
|
|
6930
|
+
description: "Trader pool size 1-500 (default 100)"
|
|
6746
6931
|
},
|
|
6747
6932
|
authorIds: {
|
|
6748
6933
|
type: "string",
|
|
6749
|
-
description: "Comma-separated user IDs e.g. 1001,1002"
|
|
6934
|
+
description: "Comma-separated user IDs e.g. 1001,1002 \u2014 restricts the trader pool to these IDs only (precise filter)"
|
|
6750
6935
|
}
|
|
6751
6936
|
}
|
|
6752
6937
|
},
|
|
@@ -6782,7 +6967,7 @@ function registerSmartmoneyTools() {
|
|
|
6782
6967
|
{
|
|
6783
6968
|
name: "smartmoney_get_signal_history",
|
|
6784
6969
|
module: "smartmoney",
|
|
6785
|
-
description: "Signal history timeline sorted by ts DESC for trend analysis. Requires instId.
|
|
6970
|
+
description: "Signal history timeline sorted by ts DESC for trend analysis. Requires instId. Requires either ts (recommended, Date.now()) or dataVersion (yyyyMMddHHmm UTC) \u2014 at least one must be set; ts wins when both are sent. For current snapshot, use smartmoney_get_signal.",
|
|
6786
6971
|
isWrite: false,
|
|
6787
6972
|
inputSchema: {
|
|
6788
6973
|
type: "object",
|
|
@@ -6791,13 +6976,13 @@ function registerSmartmoneyTools() {
|
|
|
6791
6976
|
type: "string",
|
|
6792
6977
|
description: "e.g. BTC-USDT-SWAP"
|
|
6793
6978
|
},
|
|
6794
|
-
|
|
6979
|
+
ts: {
|
|
6795
6980
|
type: "string",
|
|
6796
|
-
description: "
|
|
6981
|
+
description: "Recommended. Timestamp ms \u2014 use Date.now() for latest."
|
|
6797
6982
|
},
|
|
6798
|
-
|
|
6983
|
+
dataVersion: {
|
|
6799
6984
|
type: "string",
|
|
6800
|
-
description: "
|
|
6985
|
+
description: "Alternative. yyyyMMddHHmm UTC for prior snapshot. If both sent, ts wins."
|
|
6801
6986
|
},
|
|
6802
6987
|
granularity: {
|
|
6803
6988
|
type: "string",
|
|
@@ -10300,7 +10485,7 @@ function createToolRunner(client, config) {
|
|
|
10300
10485
|
};
|
|
10301
10486
|
}
|
|
10302
10487
|
function configFilePath() {
|
|
10303
|
-
return
|
|
10488
|
+
return join7(homedir5(), ".okx", "config.toml");
|
|
10304
10489
|
}
|
|
10305
10490
|
function readFullConfig() {
|
|
10306
10491
|
const path42 = configFilePath();
|
|
@@ -10319,11 +10504,6 @@ Or re-run: okx config init`
|
|
|
10319
10504
|
);
|
|
10320
10505
|
}
|
|
10321
10506
|
}
|
|
10322
|
-
function readTomlProfile(profileName) {
|
|
10323
|
-
const config = readFullConfig();
|
|
10324
|
-
const name = profileName ?? config.default_profile ?? "default";
|
|
10325
|
-
return config.profiles?.[name] ?? {};
|
|
10326
|
-
}
|
|
10327
10507
|
var CONFIG_HEADER = `# OKX Trade Kit Configuration
|
|
10328
10508
|
# If editing manually, wrap values containing special chars in quotes:
|
|
10329
10509
|
# passphrase = 'value' (if value contains # \\ ")
|
|
@@ -10372,18 +10552,24 @@ function parseModuleList(rawModules) {
|
|
|
10372
10552
|
}
|
|
10373
10553
|
return Array.from(deduped);
|
|
10374
10554
|
}
|
|
10375
|
-
function loadCredentials(toml) {
|
|
10555
|
+
async function loadCredentials(toml) {
|
|
10376
10556
|
const apiKey = process.env.OKX_API_KEY?.trim() ?? toml.api_key;
|
|
10377
10557
|
const secretKey = process.env.OKX_SECRET_KEY?.trim() ?? toml.secret_key;
|
|
10378
10558
|
const passphrase = process.env.OKX_PASSPHRASE?.trim() ?? toml.passphrase;
|
|
10379
|
-
const
|
|
10559
|
+
const hasApiKey = Boolean(apiKey && secretKey && passphrase);
|
|
10380
10560
|
const partialAuth = Boolean(apiKey) || Boolean(secretKey) || Boolean(passphrase);
|
|
10381
|
-
if (partialAuth && !
|
|
10561
|
+
if (partialAuth && !hasApiKey) {
|
|
10382
10562
|
throw new ConfigError(
|
|
10383
10563
|
"Partial API credentials detected.",
|
|
10384
10564
|
"Set OKX_API_KEY, OKX_SECRET_KEY and OKX_PASSPHRASE together (env vars or config.toml profile)."
|
|
10385
10565
|
);
|
|
10386
10566
|
}
|
|
10567
|
+
let hasOAuth = false;
|
|
10568
|
+
if (!hasApiKey) {
|
|
10569
|
+
const status = await execAuthStatus();
|
|
10570
|
+
hasOAuth = status?.status === "logged_in";
|
|
10571
|
+
}
|
|
10572
|
+
const hasAuth = hasOAuth || hasApiKey;
|
|
10387
10573
|
return { apiKey, secretKey, passphrase, hasAuth };
|
|
10388
10574
|
}
|
|
10389
10575
|
function resolveSite(cliSite, tomlSite) {
|
|
@@ -10417,9 +10603,11 @@ function resolveDemo(cli, toml) {
|
|
|
10417
10603
|
if (cli.demo === true) return true;
|
|
10418
10604
|
return process.env.OKX_DEMO === "1" || process.env.OKX_DEMO === "true" || (toml.demo ?? false);
|
|
10419
10605
|
}
|
|
10420
|
-
function loadConfig(cli) {
|
|
10421
|
-
const
|
|
10422
|
-
const
|
|
10606
|
+
async function loadConfig(cli) {
|
|
10607
|
+
const config = readFullConfig();
|
|
10608
|
+
const profileName = cli.profile ?? config.default_profile ?? "default";
|
|
10609
|
+
const toml = config.profiles?.[profileName] ?? {};
|
|
10610
|
+
const creds = await loadCredentials(toml);
|
|
10423
10611
|
const demo = resolveDemo(cli, toml);
|
|
10424
10612
|
const site = resolveSite(cli.site, toml.site);
|
|
10425
10613
|
const baseUrl = resolveBaseUrl(site, toml.base_url);
|
|
@@ -10439,6 +10627,7 @@ function loadConfig(cli) {
|
|
|
10439
10627
|
}
|
|
10440
10628
|
return {
|
|
10441
10629
|
...creds,
|
|
10630
|
+
profile: profileName,
|
|
10442
10631
|
baseUrl,
|
|
10443
10632
|
timeoutMs: Math.floor(rawTimeout),
|
|
10444
10633
|
modules: parseModuleList(cli.modules),
|
|
@@ -10451,7 +10640,7 @@ function loadConfig(cli) {
|
|
|
10451
10640
|
verbose: cli.verbose ?? false
|
|
10452
10641
|
};
|
|
10453
10642
|
}
|
|
10454
|
-
var CACHE_FILE =
|
|
10643
|
+
var CACHE_FILE = join8(homedir6(), ".okx", "update-check.json");
|
|
10455
10644
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
10456
10645
|
function readCache2() {
|
|
10457
10646
|
try {
|
|
@@ -10464,7 +10653,7 @@ function readCache2() {
|
|
|
10464
10653
|
}
|
|
10465
10654
|
function writeCache2(cache) {
|
|
10466
10655
|
try {
|
|
10467
|
-
mkdirSync6(
|
|
10656
|
+
mkdirSync6(join8(homedir6(), ".okx"), { recursive: true });
|
|
10468
10657
|
writeFileSync5(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
|
|
10469
10658
|
} catch {
|
|
10470
10659
|
}
|
|
@@ -10634,13 +10823,13 @@ function findMsStoreClaudePath() {
|
|
|
10634
10823
|
}
|
|
10635
10824
|
function getConfigPath(client) {
|
|
10636
10825
|
const home = os3.homedir();
|
|
10637
|
-
const
|
|
10826
|
+
const platform3 = process.platform;
|
|
10638
10827
|
switch (client) {
|
|
10639
10828
|
case "claude-desktop":
|
|
10640
|
-
if (
|
|
10829
|
+
if (platform3 === "win32") {
|
|
10641
10830
|
return findMsStoreClaudePath() ?? path3.join(appData(), "Claude", CLAUDE_CONFIG_FILE);
|
|
10642
10831
|
}
|
|
10643
|
-
if (
|
|
10832
|
+
if (platform3 === "darwin") {
|
|
10644
10833
|
return path3.join(home, "Library", "Application Support", "Claude", CLAUDE_CONFIG_FILE);
|
|
10645
10834
|
}
|
|
10646
10835
|
return path3.join(process.env.XDG_CONFIG_HOME ?? path3.join(home, ".config"), "Claude", CLAUDE_CONFIG_FILE);
|
|
@@ -10752,7 +10941,7 @@ var DOWNLOAD_TIMEOUT_MS = 3e4;
|
|
|
10752
10941
|
var PLATFORM_MAP = {
|
|
10753
10942
|
"darwin-arm64": "darwin-arm64",
|
|
10754
10943
|
"darwin-x64": "darwin-x64",
|
|
10755
|
-
"linux-arm64": "linux-
|
|
10944
|
+
"linux-arm64": "linux-x64",
|
|
10756
10945
|
"linux-x64": "linux-x64",
|
|
10757
10946
|
"win32-arm64": "win32-arm64",
|
|
10758
10947
|
"win32-x64": "win32-x64"
|
|
@@ -10884,7 +11073,7 @@ async function installPilotBinary(destPath, sources = CDN_SOURCES, onProgress) {
|
|
|
10884
11073
|
if (earlyResult) return earlyResult;
|
|
10885
11074
|
const platformDir = getPlatformDir();
|
|
10886
11075
|
const binaryName = getBinaryName();
|
|
10887
|
-
const resolvedDest = destPath ??
|
|
11076
|
+
const resolvedDest = destPath ?? join10(homedir8(), ".okx", "bin", binaryName);
|
|
10888
11077
|
const tmpPath = resolvedDest + ".tmp";
|
|
10889
11078
|
mkdirSync8(dirname6(resolvedDest), { recursive: true });
|
|
10890
11079
|
const localHash = existsSync6(resolvedDest) ? hashFile(resolvedDest) : null;
|
|
@@ -11007,107 +11196,646 @@ function downloadText(url, timeoutMs) {
|
|
|
11007
11196
|
})
|
|
11008
11197
|
);
|
|
11009
11198
|
}
|
|
11010
|
-
|
|
11011
|
-
|
|
11012
|
-
|
|
11013
|
-
import net from "net";
|
|
11014
|
-
import os5 from "os";
|
|
11015
|
-
import tls from "tls";
|
|
11016
|
-
|
|
11017
|
-
// src/commands/diagnose-utils.ts
|
|
11018
|
-
import fs4 from "fs";
|
|
11019
|
-
import { createRequire } from "module";
|
|
11020
|
-
|
|
11021
|
-
// src/formatter.ts
|
|
11022
|
-
import { EOL } from "os";
|
|
11023
|
-
var stdioOutput = {
|
|
11024
|
-
out: (message) => process.stdout.write(message),
|
|
11025
|
-
err: (message) => process.stderr.write(message)
|
|
11026
|
-
};
|
|
11027
|
-
var activeOutput = stdioOutput;
|
|
11028
|
-
function setOutput(impl) {
|
|
11029
|
-
activeOutput = impl;
|
|
11030
|
-
}
|
|
11031
|
-
var envContext = null;
|
|
11032
|
-
function setEnvContext(ctx) {
|
|
11033
|
-
envContext = ctx;
|
|
11034
|
-
}
|
|
11035
|
-
function output(message) {
|
|
11036
|
-
activeOutput.out(message);
|
|
11037
|
-
}
|
|
11038
|
-
function errorOutput(message) {
|
|
11039
|
-
activeOutput.err(message);
|
|
11040
|
-
}
|
|
11041
|
-
function outputLine(message) {
|
|
11042
|
-
activeOutput.out(message + EOL);
|
|
11043
|
-
}
|
|
11044
|
-
function errorLine(message) {
|
|
11045
|
-
activeOutput.err(message + EOL);
|
|
11046
|
-
}
|
|
11047
|
-
var jsonEnvEnabled = false;
|
|
11048
|
-
function setJsonEnvEnabled(enabled) {
|
|
11049
|
-
jsonEnvEnabled = enabled;
|
|
11050
|
-
}
|
|
11051
|
-
function printJson(data) {
|
|
11052
|
-
const payload = jsonEnvEnabled && envContext ? {
|
|
11053
|
-
env: envContext.demo ? "demo" : "live",
|
|
11054
|
-
profile: envContext.profile,
|
|
11055
|
-
data
|
|
11056
|
-
} : data;
|
|
11057
|
-
activeOutput.out(JSON.stringify(payload, null, 2) + EOL);
|
|
11199
|
+
var AUTH_CDN_PATH_PREFIX = "/upgradeapp/tools/oauth";
|
|
11200
|
+
function getAuthBinaryName() {
|
|
11201
|
+
return platform2() === "win32" ? "okx-auth.exe" : "okx-auth";
|
|
11058
11202
|
}
|
|
11059
|
-
function
|
|
11060
|
-
|
|
11061
|
-
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
if (rows.length === 0) {
|
|
11065
|
-
activeOutput.out("(no data)" + EOL);
|
|
11066
|
-
return;
|
|
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 };
|
|
11067
11208
|
}
|
|
11068
|
-
|
|
11069
|
-
|
|
11070
|
-
(k) => Math.max(k.length, ...rows.map((r) => String(r[k] ?? "").length))
|
|
11071
|
-
);
|
|
11072
|
-
const header = keys.map((k, i) => k.padEnd(widths[i])).join(" ");
|
|
11073
|
-
const divider = widths.map((w) => "-".repeat(w)).join(" ");
|
|
11074
|
-
activeOutput.out(header + EOL + divider + EOL);
|
|
11075
|
-
for (const row of rows) {
|
|
11076
|
-
activeOutput.out(keys.map((k, i) => String(row[k] ?? "").padEnd(widths[i])).join(" ") + EOL);
|
|
11209
|
+
if (opts?.skipHash) {
|
|
11210
|
+
return { binaryPath: resolvedPath, exists: true, platform: platformDir };
|
|
11077
11211
|
}
|
|
11212
|
+
const { size, sha256 } = hashFile(resolvedPath);
|
|
11213
|
+
return { binaryPath: resolvedPath, exists: true, platform: platformDir, fileSize: size, sha256 };
|
|
11078
11214
|
}
|
|
11079
|
-
function
|
|
11080
|
-
const
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
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 {
|
|
11087
11229
|
}
|
|
11088
11230
|
}
|
|
11231
|
+
return null;
|
|
11089
11232
|
}
|
|
11090
|
-
function
|
|
11091
|
-
|
|
11092
|
-
|
|
11093
|
-
|
|
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");
|
|
11094
11240
|
}
|
|
11095
|
-
|
|
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 };
|
|
11096
11245
|
}
|
|
11097
|
-
function
|
|
11098
|
-
|
|
11099
|
-
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
|
|
11105
|
-
|
|
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 {
|
|
11106
11263
|
}
|
|
11107
11264
|
}
|
|
11265
|
+
renameSync4(tmpPath, resolvedDest);
|
|
11266
|
+
if (platform2() !== "win32") {
|
|
11267
|
+
chmodSync2(resolvedDest, 493);
|
|
11268
|
+
}
|
|
11108
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
|
+
|
|
11466
|
+
// src/commands/auth.ts
|
|
11467
|
+
import { spawn as spawn2 } from "child_process";
|
|
11468
|
+
import readline from "readline";
|
|
11469
|
+
|
|
11470
|
+
// src/formatter.ts
|
|
11471
|
+
import { EOL } from "os";
|
|
11472
|
+
var stdioOutput = {
|
|
11473
|
+
out: (message) => process.stdout.write(message),
|
|
11474
|
+
err: (message) => process.stderr.write(message)
|
|
11475
|
+
};
|
|
11476
|
+
var activeOutput = stdioOutput;
|
|
11477
|
+
function setOutput(impl) {
|
|
11478
|
+
activeOutput = impl;
|
|
11479
|
+
}
|
|
11480
|
+
var envContext = null;
|
|
11481
|
+
function setEnvContext(ctx) {
|
|
11482
|
+
envContext = ctx;
|
|
11483
|
+
}
|
|
11484
|
+
function output(message) {
|
|
11485
|
+
activeOutput.out(message);
|
|
11486
|
+
}
|
|
11487
|
+
function errorOutput(message) {
|
|
11488
|
+
activeOutput.err(message);
|
|
11489
|
+
}
|
|
11490
|
+
function outputLine(message) {
|
|
11491
|
+
activeOutput.out(message + EOL);
|
|
11492
|
+
}
|
|
11493
|
+
function errorLine(message) {
|
|
11494
|
+
activeOutput.err(message + EOL);
|
|
11495
|
+
}
|
|
11496
|
+
var jsonEnvEnabled = false;
|
|
11497
|
+
function setJsonEnvEnabled(enabled) {
|
|
11498
|
+
jsonEnvEnabled = enabled;
|
|
11499
|
+
}
|
|
11500
|
+
function printJson(data) {
|
|
11501
|
+
const payload = jsonEnvEnabled && envContext ? {
|
|
11502
|
+
env: envContext.demo ? "demo" : "live",
|
|
11503
|
+
profile: envContext.profile,
|
|
11504
|
+
data
|
|
11505
|
+
} : data;
|
|
11506
|
+
activeOutput.out(JSON.stringify(payload, null, 2) + EOL);
|
|
11507
|
+
}
|
|
11508
|
+
function printTable(rows) {
|
|
11509
|
+
if (envContext) {
|
|
11510
|
+
const envLabel = envContext.demo ? "demo (simulated trading)" : "live";
|
|
11511
|
+
activeOutput.out(`Environment: ${envLabel}` + EOL + EOL);
|
|
11512
|
+
}
|
|
11513
|
+
if (rows.length === 0) {
|
|
11514
|
+
activeOutput.out("(no data)" + EOL);
|
|
11515
|
+
return;
|
|
11516
|
+
}
|
|
11517
|
+
const keys = Object.keys(rows[0]);
|
|
11518
|
+
const widths = keys.map(
|
|
11519
|
+
(k) => Math.max(k.length, ...rows.map((r) => String(r[k] ?? "").length))
|
|
11520
|
+
);
|
|
11521
|
+
const header = keys.map((k, i) => k.padEnd(widths[i])).join(" ");
|
|
11522
|
+
const divider = widths.map((w) => "-".repeat(w)).join(" ");
|
|
11523
|
+
activeOutput.out(header + EOL + divider + EOL);
|
|
11524
|
+
for (const row of rows) {
|
|
11525
|
+
activeOutput.out(keys.map((k, i) => String(row[k] ?? "").padEnd(widths[i])).join(" ") + EOL);
|
|
11526
|
+
}
|
|
11527
|
+
}
|
|
11528
|
+
function printKv(obj, indent = 0) {
|
|
11529
|
+
const pad = " ".repeat(indent);
|
|
11530
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
11531
|
+
if (v !== null && typeof v === "object" && !Array.isArray(v)) {
|
|
11532
|
+
activeOutput.out(`${pad}${k}:${EOL}`);
|
|
11533
|
+
printKv(v, indent + 2);
|
|
11534
|
+
} else {
|
|
11535
|
+
activeOutput.out(`${pad}${k.padEnd(20 - indent)} ${v}${EOL}`);
|
|
11536
|
+
}
|
|
11537
|
+
}
|
|
11538
|
+
}
|
|
11539
|
+
function extractData(result) {
|
|
11540
|
+
if (result && typeof result === "object") {
|
|
11541
|
+
const data = result["data"];
|
|
11542
|
+
if (Array.isArray(data)) return data;
|
|
11543
|
+
}
|
|
11544
|
+
return [];
|
|
11545
|
+
}
|
|
11546
|
+
function markFailedIfSCodeError(data) {
|
|
11547
|
+
if (!Array.isArray(data)) return;
|
|
11548
|
+
for (const item of data) {
|
|
11549
|
+
if (item !== null && typeof item === "object") {
|
|
11550
|
+
const sCode = item["sCode"];
|
|
11551
|
+
if (sCode !== void 0 && sCode !== "0" && sCode !== 0) {
|
|
11552
|
+
process.exitCode = 1;
|
|
11553
|
+
return;
|
|
11554
|
+
}
|
|
11555
|
+
}
|
|
11556
|
+
}
|
|
11557
|
+
}
|
|
11558
|
+
|
|
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";
|
|
11109
11835
|
|
|
11110
11836
|
// src/commands/diagnose-utils.ts
|
|
11837
|
+
import fs4 from "fs";
|
|
11838
|
+
import { createRequire } from "module";
|
|
11111
11839
|
var _require = createRequire(import.meta.url);
|
|
11112
11840
|
function readCliVersion() {
|
|
11113
11841
|
for (const rel of ["../package.json", "../../package.json"]) {
|
|
@@ -11193,7 +11921,7 @@ function sanitize2(value) {
|
|
|
11193
11921
|
import fs5 from "fs";
|
|
11194
11922
|
import path4 from "path";
|
|
11195
11923
|
import os4 from "os";
|
|
11196
|
-
import { spawnSync, spawn } from "child_process";
|
|
11924
|
+
import { spawnSync, spawn as spawn3 } from "child_process";
|
|
11197
11925
|
import { createRequire as createRequire2 } from "module";
|
|
11198
11926
|
import { fileURLToPath } from "url";
|
|
11199
11927
|
var _require2 = createRequire2(import.meta.url);
|
|
@@ -11527,7 +12255,7 @@ async function checkStdioHandshake(entryPath, report) {
|
|
|
11527
12255
|
clearTimeout(timer);
|
|
11528
12256
|
resolve3(passed);
|
|
11529
12257
|
};
|
|
11530
|
-
const child =
|
|
12258
|
+
const child = spawn3(process.execPath, [entryPath], {
|
|
11531
12259
|
stdio: ["pipe", "pipe", "pipe"],
|
|
11532
12260
|
env: { ...process.env }
|
|
11533
12261
|
});
|
|
@@ -11646,7 +12374,7 @@ async function cmdDiagnoseMcp(options = {}) {
|
|
|
11646
12374
|
|
|
11647
12375
|
// src/commands/diagnose.ts
|
|
11648
12376
|
var CLI_VERSION = readCliVersion();
|
|
11649
|
-
var GIT_HASH = true ? "
|
|
12377
|
+
var GIT_HASH = true ? "a4277b3" : "dev";
|
|
11650
12378
|
function maskKey2(key) {
|
|
11651
12379
|
if (!key) return "(not set)";
|
|
11652
12380
|
if (key.length <= 8) return "****";
|
|
@@ -12007,24 +12735,24 @@ function suggestSubcommand(action, knownActions) {
|
|
|
12007
12735
|
|
|
12008
12736
|
// src/commands/upgrade.ts
|
|
12009
12737
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
12010
|
-
import { readFileSync as
|
|
12011
|
-
import { dirname as
|
|
12012
|
-
import { homedir as
|
|
12738
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, mkdirSync as mkdirSync11 } from "fs";
|
|
12739
|
+
import { dirname as dirname8, join as join13 } from "path";
|
|
12740
|
+
import { homedir as homedir11 } from "os";
|
|
12013
12741
|
var PACKAGES = ["@okx_ai/okx-trade-mcp", "@okx_ai/okx-trade-cli"];
|
|
12014
|
-
var CACHE_FILE2 =
|
|
12742
|
+
var CACHE_FILE2 = join13(homedir11(), ".okx", "last_check");
|
|
12015
12743
|
var THROTTLE_MS = 12 * 60 * 60 * 1e3;
|
|
12016
|
-
var NPM_BIN =
|
|
12744
|
+
var NPM_BIN = join13(dirname8(process.execPath), process.platform === "win32" ? "npm.cmd" : "npm");
|
|
12017
12745
|
function readLastCheck() {
|
|
12018
12746
|
try {
|
|
12019
|
-
return parseInt(
|
|
12747
|
+
return parseInt(readFileSync9(CACHE_FILE2, "utf-8").trim(), 10) || 0;
|
|
12020
12748
|
} catch {
|
|
12021
12749
|
return 0;
|
|
12022
12750
|
}
|
|
12023
12751
|
}
|
|
12024
12752
|
function writeLastCheck() {
|
|
12025
12753
|
try {
|
|
12026
|
-
|
|
12027
|
-
|
|
12754
|
+
mkdirSync11(join13(homedir11(), ".okx"), { recursive: true });
|
|
12755
|
+
writeFileSync8(CACHE_FILE2, String(Math.floor(Date.now() / 1e3)), "utf-8");
|
|
12028
12756
|
} catch {
|
|
12029
12757
|
}
|
|
12030
12758
|
}
|
|
@@ -12938,12 +13666,12 @@ var CLI_REGISTRY = {
|
|
|
12938
13666
|
},
|
|
12939
13667
|
orders: {
|
|
12940
13668
|
toolName: "event_get_orders",
|
|
12941
|
-
usage: "okx event orders [--instId <id>] [--state
|
|
13669
|
+
usage: "okx event orders [--status <open|history|archive>] [--instId <id>] [--ordType <type>] [--state <canceled|filled>] [--after <id>] [--before <id>] [--begin <ms>] [--end <ms>] [--limit <n>] [--json]",
|
|
12942
13670
|
description: "Query event contract orders"
|
|
12943
13671
|
},
|
|
12944
13672
|
fills: {
|
|
12945
13673
|
toolName: "event_get_fills",
|
|
12946
|
-
usage: "okx event fills [--instId <id>] [--limit <n>] [--json]",
|
|
13674
|
+
usage: "okx event fills [--archive] [--instId <id>] [--ordId <id>] [--after <id>] [--before <id>] [--begin <ms>] [--end <ms>] [--limit <n>] [--json]",
|
|
12947
13675
|
description: "Get event contract fill history"
|
|
12948
13676
|
}
|
|
12949
13677
|
}
|
|
@@ -12954,18 +13682,18 @@ var CLI_REGISTRY = {
|
|
|
12954
13682
|
commands: {
|
|
12955
13683
|
overview: {
|
|
12956
13684
|
toolName: "smartmoney_get_overview",
|
|
12957
|
-
usage: "okx smartmoney overview [--
|
|
12958
|
-
description: "Multi-currency smart money overview
|
|
13685
|
+
usage: "okx smartmoney overview [--ts <ms> | --dataVersion <ver>] [--instType <SWAP|SPOT>] [--sortType <pnl|pnlRatio>] [--period <3|7|30|90>] [--pnl <tier>] [--winRatio <tier>] [--maxRetreat <tier>] [--asset <tier>] [--lmtNum <n>] [--instCcyList <ccys>] [--instCcy <ccy>] [--topInstruments <n>] [--json]",
|
|
13686
|
+
description: "Multi-currency smart money overview ranked by tradersWithPosition DESC (requires --ts or --dataVersion; --ts takes precedence)"
|
|
12959
13687
|
},
|
|
12960
13688
|
signal: {
|
|
12961
13689
|
toolName: "smartmoney_get_signal",
|
|
12962
|
-
usage: "okx smartmoney signal [--instId <id>] [--instCcy <ccy>] [--
|
|
12963
|
-
description: "Single-currency aggregated consensus signal (
|
|
13690
|
+
usage: "okx smartmoney signal [--instId <id>] [--instCcy <ccy>] [--ts <ms> | --dataVersion <ver>] [--sortType <pnl|pnlRatio>] [--period <3|7|30|90>] [--pnl <tier>] [--winRatio <tier>] [--maxRetreat <tier>] [--asset <tier>] [--lmtNum <n>] [--authorIds <ids>] [--json]",
|
|
13691
|
+
description: "Single-currency aggregated consensus signal (requires --instId or --instCcy, and --ts or --dataVersion; --instId / --ts take precedence)"
|
|
12964
13692
|
},
|
|
12965
13693
|
"signal-history": {
|
|
12966
13694
|
toolName: "smartmoney_get_signal_history",
|
|
12967
|
-
usage: "okx smartmoney signal-history --instId <id> [--
|
|
12968
|
-
description: "Signal history timeline
|
|
13695
|
+
usage: "okx smartmoney signal-history --instId <id> [--ts <ms> | --dataVersion <ver>] [--granularity <1h|1d>] [--limit <n>] [--sortType <pnl|pnlRatio>] [--period <3|7|30|90>] [--pnl <tier>] [--winRatio <tier>] [--maxRetreat <tier>] [--asset <tier>] [--json]",
|
|
13696
|
+
description: "Signal history timeline sorted by ts DESC (requires --instId and --ts/--dataVersion)"
|
|
12969
13697
|
},
|
|
12970
13698
|
traders: {
|
|
12971
13699
|
toolName: "smartmoney_get_traders",
|
|
@@ -13489,7 +14217,7 @@ async function cmdNewsSentimentRank(run, opts) {
|
|
|
13489
14217
|
}
|
|
13490
14218
|
|
|
13491
14219
|
// src/config/loader.ts
|
|
13492
|
-
function loadProfileConfig(opts) {
|
|
14220
|
+
async function loadProfileConfig(opts) {
|
|
13493
14221
|
return loadConfig({
|
|
13494
14222
|
profile: opts.profile,
|
|
13495
14223
|
modules: opts.modules,
|
|
@@ -13826,6 +14554,9 @@ var CLI_OPTIONS = {
|
|
|
13826
14554
|
dir: { type: "string" },
|
|
13827
14555
|
page: { type: "string" },
|
|
13828
14556
|
format: { type: "string" },
|
|
14557
|
+
// auth
|
|
14558
|
+
site: { type: "string" },
|
|
14559
|
+
manual: { type: "boolean", default: false },
|
|
13829
14560
|
// event contract
|
|
13830
14561
|
underlying: { type: "string" },
|
|
13831
14562
|
seriesId: { type: "string" },
|
|
@@ -14247,12 +14978,13 @@ async function cmdMarketOiHistory(run, instId, opts) {
|
|
|
14247
14978
|
});
|
|
14248
14979
|
const data = getData2(result);
|
|
14249
14980
|
if (opts.json) return printJson(data);
|
|
14250
|
-
const
|
|
14981
|
+
const entry = Array.isArray(data) ? data[0] : data;
|
|
14982
|
+
const rows = entry?.["rows"] ?? [];
|
|
14251
14983
|
if (!rows.length) {
|
|
14252
14984
|
outputLine("No OI data");
|
|
14253
14985
|
return;
|
|
14254
14986
|
}
|
|
14255
|
-
outputLine(`${
|
|
14987
|
+
outputLine(`${entry?.["instId"] ?? instId} bar=${entry?.["bar"] ?? opts.bar ?? "1H"}`);
|
|
14256
14988
|
printTable(
|
|
14257
14989
|
rows.map((r) => ({
|
|
14258
14990
|
ts: new Date(Number(r["ts"])).toLocaleString(),
|
|
@@ -17048,14 +17780,14 @@ async function cmdDcdQuoteAndBuy(run, opts) {
|
|
|
17048
17780
|
}
|
|
17049
17781
|
|
|
17050
17782
|
// src/commands/skill.ts
|
|
17051
|
-
import { tmpdir, homedir as
|
|
17052
|
-
import { join as
|
|
17053
|
-
import { mkdirSync as
|
|
17783
|
+
import { tmpdir, homedir as homedir13 } from "os";
|
|
17784
|
+
import { join as join15, dirname as dirname9 } from "path";
|
|
17785
|
+
import { mkdirSync as mkdirSync12, rmSync, existsSync as existsSync10, copyFileSync as copyFileSync2 } from "fs";
|
|
17054
17786
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
17055
17787
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
17056
17788
|
function resolveNpx() {
|
|
17057
|
-
const sibling =
|
|
17058
|
-
if (
|
|
17789
|
+
const sibling = join15(dirname9(process.execPath), "npx");
|
|
17790
|
+
if (existsSync10(sibling)) return sibling;
|
|
17059
17791
|
return "npx";
|
|
17060
17792
|
}
|
|
17061
17793
|
var THIRD_PARTY_INSTALL_NOTICE = "Note: This skill was created by a third-party developer, not by OKX. Review SKILL.md before use.";
|
|
@@ -17108,13 +17840,13 @@ async function cmdSkillCategories(run, json) {
|
|
|
17108
17840
|
outputLine("");
|
|
17109
17841
|
}
|
|
17110
17842
|
async function cmdSkillAdd(name, config, json) {
|
|
17111
|
-
const tmpBase =
|
|
17112
|
-
|
|
17843
|
+
const tmpBase = join15(tmpdir(), `okx-skill-${randomUUID2()}`);
|
|
17844
|
+
mkdirSync12(tmpBase, { recursive: true });
|
|
17113
17845
|
try {
|
|
17114
17846
|
outputLine(`Downloading ${name}...`);
|
|
17115
17847
|
const client = new OkxRestClient(config);
|
|
17116
17848
|
const zipPath = await downloadSkillZip(client, name, tmpBase);
|
|
17117
|
-
const contentDir = await extractSkillZip(zipPath,
|
|
17849
|
+
const contentDir = await extractSkillZip(zipPath, join15(tmpBase, "content"));
|
|
17118
17850
|
const meta = readMetaJson(contentDir);
|
|
17119
17851
|
validateSkillMdExists(contentDir);
|
|
17120
17852
|
outputLine("Installing to detected agents...");
|
|
@@ -17124,7 +17856,7 @@ async function cmdSkillAdd(name, config, json) {
|
|
|
17124
17856
|
timeout: 6e4
|
|
17125
17857
|
});
|
|
17126
17858
|
} catch (e) {
|
|
17127
|
-
const savedZip =
|
|
17859
|
+
const savedZip = join15(process.cwd(), `${name}.zip`);
|
|
17128
17860
|
try {
|
|
17129
17861
|
copyFileSync2(zipPath, savedZip);
|
|
17130
17862
|
} catch {
|
|
@@ -17163,7 +17895,7 @@ function cmdSkillRemove(name, json) {
|
|
|
17163
17895
|
timeout: 6e4
|
|
17164
17896
|
});
|
|
17165
17897
|
} catch {
|
|
17166
|
-
const agentsPath =
|
|
17898
|
+
const agentsPath = join15(homedir13(), ".agents", "skills", name);
|
|
17167
17899
|
try {
|
|
17168
17900
|
rmSync(agentsPath, { recursive: true, force: true });
|
|
17169
17901
|
} catch {
|
|
@@ -17237,14 +17969,14 @@ function printSkillInstallResult(meta, json) {
|
|
|
17237
17969
|
}
|
|
17238
17970
|
|
|
17239
17971
|
// src/commands/pilot.ts
|
|
17240
|
-
import
|
|
17241
|
-
function
|
|
17972
|
+
import readline2 from "readline";
|
|
17973
|
+
function resolveChecksumMatch2(local, cdnChecksum, cdnError) {
|
|
17242
17974
|
if (!local.exists) return "not-installed";
|
|
17243
17975
|
if (cdnError || !cdnChecksum) return "unavailable";
|
|
17244
17976
|
if (cdnChecksum.sha256 === local.sha256) return "match";
|
|
17245
17977
|
return "mismatch";
|
|
17246
17978
|
}
|
|
17247
|
-
function
|
|
17979
|
+
function checksumMatchLabel2(match) {
|
|
17248
17980
|
if (match === "match") return "\u2713 match";
|
|
17249
17981
|
if (match === "mismatch") return "\u2717 mismatch (update available)";
|
|
17250
17982
|
return "CDN unreachable";
|
|
@@ -17257,9 +17989,9 @@ function formatStatusText(local, checksumMatch, cdnChecksum, runtimeMode) {
|
|
|
17257
17989
|
outputLine(` Installed : ${local.exists ? "yes" : "no"}`);
|
|
17258
17990
|
outputLine(` Platform : ${local.platform ?? "(unsupported)"}`);
|
|
17259
17991
|
if (local.exists) {
|
|
17260
|
-
outputLine(` File size : ${
|
|
17992
|
+
outputLine(` File size : ${formatBytes2(local.fileSize)}`);
|
|
17261
17993
|
outputLine(` SHA-256 : ${local.sha256 ?? "(unknown)"}`);
|
|
17262
|
-
outputLine(` CDN check : ${
|
|
17994
|
+
outputLine(` CDN check : ${checksumMatchLabel2(checksumMatch)}`);
|
|
17263
17995
|
if (cdnChecksum) {
|
|
17264
17996
|
outputLine(` CDN source : ${cdnChecksum.source}`);
|
|
17265
17997
|
}
|
|
@@ -17286,7 +18018,7 @@ async function cmdPilotStatus(json, binaryPath) {
|
|
|
17286
18018
|
cdnError = err instanceof Error ? err.message : String(err);
|
|
17287
18019
|
}
|
|
17288
18020
|
}
|
|
17289
|
-
const checksumMatch =
|
|
18021
|
+
const checksumMatch = resolveChecksumMatch2(local, cdnChecksum, cdnError);
|
|
17290
18022
|
if (json) {
|
|
17291
18023
|
outputLine(
|
|
17292
18024
|
JSON.stringify({
|
|
@@ -17352,7 +18084,7 @@ async function cmdPilotRemove(force, json, binaryPath) {
|
|
|
17352
18084
|
process.exitCode = 1;
|
|
17353
18085
|
return;
|
|
17354
18086
|
}
|
|
17355
|
-
const confirmed = await
|
|
18087
|
+
const confirmed = await askConfirmation2(
|
|
17356
18088
|
` Remove Pilot at ${local.binaryPath}? [y/N] `
|
|
17357
18089
|
);
|
|
17358
18090
|
if (!confirmed) {
|
|
@@ -17371,14 +18103,14 @@ async function cmdPilotRemove(force, json, binaryPath) {
|
|
|
17371
18103
|
outputLine(" Pilot is not installed.");
|
|
17372
18104
|
}
|
|
17373
18105
|
}
|
|
17374
|
-
function
|
|
18106
|
+
function formatBytes2(bytes) {
|
|
17375
18107
|
if (bytes < 1024) return `${bytes} B`;
|
|
17376
18108
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
17377
18109
|
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
17378
18110
|
}
|
|
17379
|
-
function
|
|
18111
|
+
function askConfirmation2(prompt2) {
|
|
17380
18112
|
return new Promise((resolve3) => {
|
|
17381
|
-
const rl =
|
|
18113
|
+
const rl = readline2.createInterface({
|
|
17382
18114
|
input: process.stdin,
|
|
17383
18115
|
output: process.stdout
|
|
17384
18116
|
});
|
|
@@ -17626,8 +18358,14 @@ async function cmdEventMarkets(run, opts) {
|
|
|
17626
18358
|
}
|
|
17627
18359
|
async function cmdEventOrders(run, opts) {
|
|
17628
18360
|
const result = await run("event_get_orders", {
|
|
18361
|
+
status: opts.status,
|
|
17629
18362
|
instId: opts.instId,
|
|
18363
|
+
ordType: opts.ordType,
|
|
17630
18364
|
state: opts.state,
|
|
18365
|
+
after: opts.after,
|
|
18366
|
+
before: opts.before,
|
|
18367
|
+
begin: opts.begin,
|
|
18368
|
+
end: opts.end,
|
|
17631
18369
|
limit: opts.limit
|
|
17632
18370
|
});
|
|
17633
18371
|
const data = getData9(result);
|
|
@@ -17646,7 +18384,13 @@ async function cmdEventOrders(run, opts) {
|
|
|
17646
18384
|
}
|
|
17647
18385
|
async function cmdEventFills(run, opts) {
|
|
17648
18386
|
const result = await run("event_get_fills", {
|
|
18387
|
+
archive: opts.archive,
|
|
17649
18388
|
instId: opts.instId,
|
|
18389
|
+
ordId: opts.ordId,
|
|
18390
|
+
after: opts.after,
|
|
18391
|
+
before: opts.before,
|
|
18392
|
+
begin: opts.begin,
|
|
18393
|
+
end: opts.end,
|
|
17650
18394
|
limit: opts.limit
|
|
17651
18395
|
});
|
|
17652
18396
|
const data = getData9(result);
|
|
@@ -17835,7 +18579,7 @@ async function cmdEventCancel(run, opts) {
|
|
|
17835
18579
|
// src/index.ts
|
|
17836
18580
|
var _require3 = createRequire3(import.meta.url);
|
|
17837
18581
|
var CLI_VERSION2 = _require3("../package.json").version;
|
|
17838
|
-
var GIT_HASH2 = true ? "
|
|
18582
|
+
var GIT_HASH2 = true ? "a4277b3" : "dev";
|
|
17839
18583
|
function handlePilotCommand(action, json, force, binaryPath) {
|
|
17840
18584
|
if (action === "status") return cmdPilotStatus(json, binaryPath);
|
|
17841
18585
|
if (action === "install") return cmdPilotInstall(json, binaryPath);
|
|
@@ -18878,13 +19622,13 @@ function handleNewsCommand(run, action, rest, v, json) {
|
|
|
18878
19622
|
const period = v.period;
|
|
18879
19623
|
const points = v.points !== void 0 ? Number(v.points) : 24;
|
|
18880
19624
|
const sortBy = v["sort-by"];
|
|
18881
|
-
const
|
|
18882
|
-
const searchOpts = { coins: v.coins, importance: v.importance, platform:
|
|
18883
|
-
const listOpts = { coins: v.coins, importance: v.importance, platform:
|
|
19625
|
+
const platform3 = v.platform;
|
|
19626
|
+
const searchOpts = { coins: v.coins, importance: v.importance, platform: platform3, sentiment: v.sentiment, sortBy, begin, end, language, detailLvl, limit, after, json };
|
|
19627
|
+
const listOpts = { coins: v.coins, importance: v.importance, platform: platform3, begin, end, language, detailLvl, limit, after, json };
|
|
18884
19628
|
const dispatch = {
|
|
18885
19629
|
latest: () => cmdNewsLatest(run, listOpts),
|
|
18886
|
-
important: () => cmdNewsImportant(run, { coins: v.coins, platform:
|
|
18887
|
-
"by-coin": () => cmdNewsByCoin(run, v.coins ?? rest[0], { importance: v.importance, platform:
|
|
19630
|
+
important: () => cmdNewsImportant(run, { coins: v.coins, platform: platform3, begin, end, language, detailLvl, limit, json }),
|
|
19631
|
+
"by-coin": () => cmdNewsByCoin(run, v.coins ?? rest[0], { importance: v.importance, platform: platform3, begin, end, language, detailLvl, limit, json }),
|
|
18888
19632
|
search: () => cmdNewsSearch(run, v.keyword ?? rest[0], searchOpts),
|
|
18889
19633
|
detail: () => cmdNewsDetail(run, rest[0], { language, json }),
|
|
18890
19634
|
platforms: () => cmdNewsPlatforms(run, { json }),
|
|
@@ -18958,8 +19702,29 @@ function handleEventCommand(run, action, rest, v, json) {
|
|
|
18958
19702
|
}),
|
|
18959
19703
|
amend: () => cmdEventAmend(run, { instId: v.instId ?? rest[0], ordId: v.ordId ?? rest[1], px: v.px, sz: v.sz, json }),
|
|
18960
19704
|
cancel: () => cmdEventCancel(run, { instId: v.instId ?? rest[0], ordId: v.ordId ?? rest[1], json }),
|
|
18961
|
-
orders: () => cmdEventOrders(run, {
|
|
18962
|
-
|
|
19705
|
+
orders: () => cmdEventOrders(run, {
|
|
19706
|
+
status: v.status,
|
|
19707
|
+
instId: v.instId,
|
|
19708
|
+
ordType: v.ordType,
|
|
19709
|
+
state: v.state,
|
|
19710
|
+
after: v.after,
|
|
19711
|
+
before: v.before,
|
|
19712
|
+
begin: v.begin,
|
|
19713
|
+
end: v.end,
|
|
19714
|
+
limit,
|
|
19715
|
+
json
|
|
19716
|
+
}),
|
|
19717
|
+
fills: () => cmdEventFills(run, {
|
|
19718
|
+
archive: v.archive ?? false,
|
|
19719
|
+
instId: v.instId,
|
|
19720
|
+
ordId: v.ordId,
|
|
19721
|
+
after: v.after,
|
|
19722
|
+
before: v.before,
|
|
19723
|
+
begin: v.begin,
|
|
19724
|
+
end: v.end,
|
|
19725
|
+
limit,
|
|
19726
|
+
json
|
|
19727
|
+
})
|
|
18963
19728
|
};
|
|
18964
19729
|
const handler = handlers[action];
|
|
18965
19730
|
if (handler) return handler();
|
|
@@ -19004,7 +19769,7 @@ function wrapRunnerWithLogger(baseRunner, logger, verbose = false) {
|
|
|
19004
19769
|
async function runDiagnose(v) {
|
|
19005
19770
|
let config;
|
|
19006
19771
|
try {
|
|
19007
|
-
config = loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
|
|
19772
|
+
config = await loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
|
|
19008
19773
|
} catch {
|
|
19009
19774
|
}
|
|
19010
19775
|
return cmdDiagnose(config, v.profile ?? "default", { mcp: v.mcp, cli: v.cli, all: v.all, output: v.output });
|
|
@@ -19027,6 +19792,7 @@ function routeManagementCommand(module, action, rest, json, v) {
|
|
|
19027
19792
|
handleSetupCommand(v);
|
|
19028
19793
|
return true;
|
|
19029
19794
|
}
|
|
19795
|
+
if (module === "auth") return handleAuthCommand(action, rest, v);
|
|
19030
19796
|
if (module === "upgrade") return cmdUpgrade(CLI_VERSION2, { beta: v.beta, check: v.check, force: v.force }, json);
|
|
19031
19797
|
if (module === "pilot") {
|
|
19032
19798
|
const r = handlePilotCommand(action, json, v.force ?? false);
|
|
@@ -19059,7 +19825,7 @@ async function main() {
|
|
|
19059
19825
|
const json = v.json ?? false;
|
|
19060
19826
|
const mgmt = routeManagementCommand(module, action, rest, json, v);
|
|
19061
19827
|
if (mgmt !== void 0) return mgmt === true ? void 0 : mgmt;
|
|
19062
|
-
const config = loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
|
|
19828
|
+
const config = await loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
|
|
19063
19829
|
setEnvContext({ demo: config.demo, profile: v.profile ?? "default" });
|
|
19064
19830
|
setJsonEnvEnabled(v.env ?? false);
|
|
19065
19831
|
const client = new OkxRestClient(config);
|