@okx_ai/okx-trade-cli 1.3.0-beta.4 → 1.3.0
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 +248 -433
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/postinstall.js +2 -112
package/dist/index.js
CHANGED
|
@@ -4,37 +4,25 @@
|
|
|
4
4
|
import { createRequire as createRequire3 } from "module";
|
|
5
5
|
|
|
6
6
|
// ../core/dist/index.js
|
|
7
|
-
import {
|
|
8
|
-
import { execFile } from "child_process";
|
|
9
|
-
import { homedir } from "os";
|
|
10
|
-
import { join } from "path";
|
|
11
|
-
import {
|
|
12
|
-
readFileSync,
|
|
13
|
-
writeFileSync,
|
|
14
|
-
mkdirSync,
|
|
15
|
-
unlinkSync,
|
|
16
|
-
renameSync
|
|
17
|
-
} from "fs";
|
|
18
|
-
import { homedir as homedir2 } from "os";
|
|
19
|
-
import { join as join2, dirname } from "path";
|
|
7
|
+
import { ProxyAgent } from "undici";
|
|
20
8
|
import { createHmac } from "crypto";
|
|
21
9
|
import fs from "fs";
|
|
22
10
|
import path from "path";
|
|
23
11
|
import os from "os";
|
|
24
|
-
import { writeFileSync
|
|
25
|
-
import { join
|
|
12
|
+
import { writeFileSync, renameSync, unlinkSync, mkdirSync } from "fs";
|
|
13
|
+
import { join, resolve, basename, sep } from "path";
|
|
26
14
|
import { randomUUID } from "crypto";
|
|
27
15
|
import yauzl from "yauzl";
|
|
28
|
-
import { createWriteStream, mkdirSync as
|
|
29
|
-
import { resolve as resolve2, dirname
|
|
30
|
-
import { readFileSync
|
|
31
|
-
import { join as
|
|
32
|
-
import { readFileSync as
|
|
33
|
-
import { join as
|
|
34
|
-
import { homedir
|
|
35
|
-
import { readFileSync as
|
|
36
|
-
import { join as
|
|
37
|
-
import { homedir as
|
|
16
|
+
import { createWriteStream, mkdirSync as mkdirSync2 } from "fs";
|
|
17
|
+
import { resolve as resolve2, dirname } from "path";
|
|
18
|
+
import { readFileSync, existsSync } from "fs";
|
|
19
|
+
import { join as join2 } from "path";
|
|
20
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, existsSync as existsSync2 } from "fs";
|
|
21
|
+
import { join as join3, dirname as dirname2 } from "path";
|
|
22
|
+
import { homedir } from "os";
|
|
23
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync3 } from "fs";
|
|
24
|
+
import { join as join4, dirname as dirname3 } from "path";
|
|
25
|
+
import { homedir as homedir2 } from "os";
|
|
38
26
|
|
|
39
27
|
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/error.js
|
|
40
28
|
function getLineColFromPtr(string, ptr) {
|
|
@@ -863,9 +851,9 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
|
863
851
|
}
|
|
864
852
|
|
|
865
853
|
// ../core/dist/index.js
|
|
866
|
-
import { readFileSync as
|
|
867
|
-
import { join as
|
|
868
|
-
import { homedir as
|
|
854
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync4 } from "fs";
|
|
855
|
+
import { join as join5 } from "path";
|
|
856
|
+
import { homedir as homedir3 } from "os";
|
|
869
857
|
import fs2 from "fs";
|
|
870
858
|
import path2 from "path";
|
|
871
859
|
import os2 from "os";
|
|
@@ -873,123 +861,6 @@ import * as fs3 from "fs";
|
|
|
873
861
|
import * as path3 from "path";
|
|
874
862
|
import * as os3 from "os";
|
|
875
863
|
import { execFileSync } from "child_process";
|
|
876
|
-
var EXEC_TIMEOUT_MS = 3e4;
|
|
877
|
-
var DOH_BIN_DIR = join(homedir(), ".okx", "bin");
|
|
878
|
-
function getDohBinaryPath() {
|
|
879
|
-
if (process.env.OKX_DOH_BINARY_PATH) {
|
|
880
|
-
return process.env.OKX_DOH_BINARY_PATH;
|
|
881
|
-
}
|
|
882
|
-
const ext = process.platform === "win32" ? ".exe" : "";
|
|
883
|
-
return join(DOH_BIN_DIR, `okx-doh-resolver${ext}`);
|
|
884
|
-
}
|
|
885
|
-
function execDohBinary(domain, exclude = [], userAgent) {
|
|
886
|
-
const binPath = getDohBinaryPath();
|
|
887
|
-
const args = ["--domain", domain];
|
|
888
|
-
if (exclude.length > 0) {
|
|
889
|
-
args.push("--exclude", exclude.join(","));
|
|
890
|
-
}
|
|
891
|
-
if (userAgent) {
|
|
892
|
-
args.push("--user-agent", userAgent);
|
|
893
|
-
}
|
|
894
|
-
return new Promise((resolve3) => {
|
|
895
|
-
execFile(
|
|
896
|
-
binPath,
|
|
897
|
-
args,
|
|
898
|
-
{ timeout: EXEC_TIMEOUT_MS, encoding: "utf-8" },
|
|
899
|
-
(error, stdout) => {
|
|
900
|
-
if (error) {
|
|
901
|
-
resolve3(null);
|
|
902
|
-
return;
|
|
903
|
-
}
|
|
904
|
-
try {
|
|
905
|
-
const result = JSON.parse(stdout);
|
|
906
|
-
if (result.code === 0 && result.data) {
|
|
907
|
-
resolve3(result.data);
|
|
908
|
-
} else {
|
|
909
|
-
resolve3(null);
|
|
910
|
-
}
|
|
911
|
-
} catch {
|
|
912
|
-
resolve3(null);
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
);
|
|
916
|
-
});
|
|
917
|
-
}
|
|
918
|
-
var DOH_CACHE_PATH = join2(homedir2(), ".okx", "doh-node-cache.json");
|
|
919
|
-
function readCache(hostname, cachePath = DOH_CACHE_PATH) {
|
|
920
|
-
try {
|
|
921
|
-
const raw = readFileSync(cachePath, "utf-8");
|
|
922
|
-
const file = JSON.parse(raw);
|
|
923
|
-
return file[hostname] ?? null;
|
|
924
|
-
} catch {
|
|
925
|
-
return null;
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
function writeCache(hostname, entry, cachePath = DOH_CACHE_PATH) {
|
|
929
|
-
try {
|
|
930
|
-
const dir = dirname(cachePath);
|
|
931
|
-
mkdirSync(dir, { recursive: true });
|
|
932
|
-
let file = {};
|
|
933
|
-
try {
|
|
934
|
-
file = JSON.parse(readFileSync(cachePath, "utf-8"));
|
|
935
|
-
} catch {
|
|
936
|
-
}
|
|
937
|
-
file[hostname] = entry;
|
|
938
|
-
const tmpPath = `${cachePath}.tmp`;
|
|
939
|
-
writeFileSync(tmpPath, JSON.stringify(file));
|
|
940
|
-
renameSync(tmpPath, cachePath);
|
|
941
|
-
} catch {
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
var FAILED_NODE_TTL_MS = 60 * 60 * 1e3;
|
|
945
|
-
function classifyAndCache(node, hostname, failedNodes, cachePath) {
|
|
946
|
-
if (!node) {
|
|
947
|
-
return { mode: null, node: null };
|
|
948
|
-
}
|
|
949
|
-
if (node.ip === hostname || node.host === hostname) {
|
|
950
|
-
writeCache(hostname, {
|
|
951
|
-
mode: "direct",
|
|
952
|
-
node: null,
|
|
953
|
-
failedNodes,
|
|
954
|
-
updatedAt: Date.now()
|
|
955
|
-
}, cachePath);
|
|
956
|
-
return { mode: "direct", node: null };
|
|
957
|
-
}
|
|
958
|
-
writeCache(hostname, {
|
|
959
|
-
mode: "proxy",
|
|
960
|
-
node,
|
|
961
|
-
failedNodes,
|
|
962
|
-
updatedAt: Date.now()
|
|
963
|
-
}, cachePath);
|
|
964
|
-
return { mode: "proxy", node };
|
|
965
|
-
}
|
|
966
|
-
function getActiveFailedNodes(nodes) {
|
|
967
|
-
if (!nodes || nodes.length === 0) return [];
|
|
968
|
-
const now = Date.now();
|
|
969
|
-
return nodes.filter((n) => now - n.failedAt < FAILED_NODE_TTL_MS);
|
|
970
|
-
}
|
|
971
|
-
function resolveDoh(hostname, cachePath) {
|
|
972
|
-
const entry = readCache(hostname, cachePath);
|
|
973
|
-
if (entry) {
|
|
974
|
-
if (entry.mode === "direct") {
|
|
975
|
-
return { mode: "direct", node: null };
|
|
976
|
-
}
|
|
977
|
-
if (entry.mode === "proxy" && entry.node) {
|
|
978
|
-
return { mode: "proxy", node: entry.node };
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
return { mode: null, node: null };
|
|
982
|
-
}
|
|
983
|
-
async function reResolveDoh(hostname, failedIp, userAgent, cachePath) {
|
|
984
|
-
const entry = readCache(hostname, cachePath);
|
|
985
|
-
const active = getActiveFailedNodes(entry?.failedNodes);
|
|
986
|
-
const now = Date.now();
|
|
987
|
-
const alreadyFailed = failedIp && active.some((n) => n.ip === failedIp);
|
|
988
|
-
const failedNodes = failedIp && !alreadyFailed ? [...active, { ip: failedIp, failedAt: now }] : active;
|
|
989
|
-
const excludeIps = failedNodes.map((n) => n.ip);
|
|
990
|
-
const node = await execDohBinary(hostname, excludeIps, userAgent);
|
|
991
|
-
return classifyAndCache(node, hostname, failedNodes, cachePath);
|
|
992
|
-
}
|
|
993
864
|
function getNow() {
|
|
994
865
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
995
866
|
}
|
|
@@ -1208,14 +1079,6 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1208
1079
|
config;
|
|
1209
1080
|
rateLimiter;
|
|
1210
1081
|
dispatcher;
|
|
1211
|
-
// DoH proxy state (lazy-resolved on first request)
|
|
1212
|
-
dohResolved = false;
|
|
1213
|
-
dohRetried = false;
|
|
1214
|
-
directUnverified = false;
|
|
1215
|
-
// The first direct connection has not yet been verified
|
|
1216
|
-
dohNode = null;
|
|
1217
|
-
dohAgent = null;
|
|
1218
|
-
dohBaseUrl = null;
|
|
1219
1082
|
constructor(config) {
|
|
1220
1083
|
this.config = config;
|
|
1221
1084
|
this.rateLimiter = new RateLimiter(3e4, config.verbose);
|
|
@@ -1223,98 +1086,6 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1223
1086
|
this.dispatcher = new ProxyAgent(config.proxyUrl);
|
|
1224
1087
|
}
|
|
1225
1088
|
}
|
|
1226
|
-
/**
|
|
1227
|
-
* Lazily resolve the DoH proxy node on the first request.
|
|
1228
|
-
* Uses cache-first strategy via the resolver.
|
|
1229
|
-
*/
|
|
1230
|
-
ensureDoh() {
|
|
1231
|
-
if (this.dohResolved || this.dispatcher) return;
|
|
1232
|
-
this.dohResolved = true;
|
|
1233
|
-
try {
|
|
1234
|
-
const { hostname, protocol } = new URL(this.config.baseUrl);
|
|
1235
|
-
const result = resolveDoh(hostname);
|
|
1236
|
-
if (!result.mode) {
|
|
1237
|
-
this.directUnverified = true;
|
|
1238
|
-
if (this.config.verbose) {
|
|
1239
|
-
vlog("DoH: no cache, trying direct connection first");
|
|
1240
|
-
}
|
|
1241
|
-
return;
|
|
1242
|
-
}
|
|
1243
|
-
if (result.mode === "direct") {
|
|
1244
|
-
if (this.config.verbose) {
|
|
1245
|
-
vlog("DoH: mode=direct (overseas or cached), using direct connection");
|
|
1246
|
-
}
|
|
1247
|
-
return;
|
|
1248
|
-
}
|
|
1249
|
-
if (result.node) {
|
|
1250
|
-
this.applyDohNode(result.node, protocol);
|
|
1251
|
-
}
|
|
1252
|
-
} catch (err) {
|
|
1253
|
-
if (this.config.verbose) {
|
|
1254
|
-
const cause = err instanceof Error ? err.message : String(err);
|
|
1255
|
-
vlog(`DoH resolution failed, falling back to direct: ${cause}`);
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
/** Apply a DoH node: set up the custom Agent + base URL. */
|
|
1260
|
-
applyDohNode(node, protocol) {
|
|
1261
|
-
this.dohNode = node;
|
|
1262
|
-
this.dohBaseUrl = `${protocol}//${node.host}`;
|
|
1263
|
-
this.dohAgent = new Agent({
|
|
1264
|
-
connect: {
|
|
1265
|
-
lookup: (_hostname, options, callback) => {
|
|
1266
|
-
if (options?.all) {
|
|
1267
|
-
callback(null, [{ address: node.ip, family: 4 }]);
|
|
1268
|
-
} else {
|
|
1269
|
-
callback(null, node.ip, 4);
|
|
1270
|
-
}
|
|
1271
|
-
}
|
|
1272
|
-
}
|
|
1273
|
-
});
|
|
1274
|
-
if (this.config.verbose) {
|
|
1275
|
-
vlog(`DoH proxy active: \u2192 ${node.host} (${node.ip}), ttl=${node.ttl}s`);
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
/**
|
|
1279
|
-
* Handle network failure: re-resolve with --exclude and retry once.
|
|
1280
|
-
* Returns true if retry should proceed, false if already retried.
|
|
1281
|
-
*/
|
|
1282
|
-
async handleDohNetworkFailure() {
|
|
1283
|
-
if (this.dohRetried) return false;
|
|
1284
|
-
this.dohRetried = true;
|
|
1285
|
-
const failedIp = this.dohNode?.ip ?? "";
|
|
1286
|
-
const { hostname, protocol } = new URL(this.config.baseUrl);
|
|
1287
|
-
this.dohNode = null;
|
|
1288
|
-
this.dohAgent = null;
|
|
1289
|
-
this.dohBaseUrl = null;
|
|
1290
|
-
if (!failedIp) this.directUnverified = false;
|
|
1291
|
-
if (this.config.verbose) {
|
|
1292
|
-
vlog(failedIp ? `DoH: proxy node ${failedIp} failed, re-resolving with --exclude` : "DoH: direct connection failed, calling binary for DoH resolution");
|
|
1293
|
-
}
|
|
1294
|
-
try {
|
|
1295
|
-
const result = await reResolveDoh(hostname, failedIp, this.dohUserAgent);
|
|
1296
|
-
if (result.mode === "proxy" && result.node) {
|
|
1297
|
-
this.applyDohNode(result.node, protocol);
|
|
1298
|
-
this.dohRetried = false;
|
|
1299
|
-
return true;
|
|
1300
|
-
}
|
|
1301
|
-
} catch {
|
|
1302
|
-
}
|
|
1303
|
-
if (this.config.verbose) {
|
|
1304
|
-
vlog("DoH: re-resolution failed or switched to direct, retrying with direct connection");
|
|
1305
|
-
}
|
|
1306
|
-
return true;
|
|
1307
|
-
}
|
|
1308
|
-
get activeBaseUrl() {
|
|
1309
|
-
return this.dohNode ? this.dohBaseUrl : this.config.baseUrl;
|
|
1310
|
-
}
|
|
1311
|
-
get activeDispatcher() {
|
|
1312
|
-
return this.dispatcher ?? this.dohAgent ?? void 0;
|
|
1313
|
-
}
|
|
1314
|
-
/** User-Agent for DoH proxy requests: OKX/@okx_ai/{packageName}/{version} */
|
|
1315
|
-
get dohUserAgent() {
|
|
1316
|
-
return `OKX/@okx_ai/${this.config.userAgent ?? "unknown"}`;
|
|
1317
|
-
}
|
|
1318
1089
|
logRequest(method, url, auth) {
|
|
1319
1090
|
if (!this.config.verbose) return;
|
|
1320
1091
|
vlog(`\u2192 ${method} ${url}`);
|
|
@@ -1329,13 +1100,14 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1329
1100
|
vlog(`\u2190 ${status} | code=${code ?? "0"} | ${rawLen}B | ${elapsed}ms | trace=${traceId ?? "-"}`);
|
|
1330
1101
|
}
|
|
1331
1102
|
}
|
|
1332
|
-
async publicGet(path42, query, rateLimit) {
|
|
1103
|
+
async publicGet(path42, query, rateLimit, simulatedTrading) {
|
|
1333
1104
|
return this.request({
|
|
1334
1105
|
method: "GET",
|
|
1335
1106
|
path: path42,
|
|
1336
1107
|
auth: "public",
|
|
1337
1108
|
query,
|
|
1338
|
-
rateLimit
|
|
1109
|
+
rateLimit,
|
|
1110
|
+
simulatedTrading
|
|
1339
1111
|
});
|
|
1340
1112
|
}
|
|
1341
1113
|
async privateGet(path42, query, rateLimit) {
|
|
@@ -1484,17 +1256,13 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1484
1256
|
* Security: validates Content-Type and enforces maxBytes limit.
|
|
1485
1257
|
*/
|
|
1486
1258
|
async privatePostBinary(path42, body, opts) {
|
|
1487
|
-
this.ensureDoh();
|
|
1488
1259
|
const maxBytes = opts?.maxBytes ?? _OkxRestClient.DEFAULT_MAX_BYTES;
|
|
1489
1260
|
const expectedCT = opts?.expectedContentType ?? "application/octet-stream";
|
|
1490
1261
|
const bodyJson = body ? JSON.stringify(body) : "";
|
|
1491
1262
|
const endpoint = `POST ${path42}`;
|
|
1492
|
-
this.logRequest("POST", `${this.
|
|
1263
|
+
this.logRequest("POST", `${this.config.baseUrl}${path42}`, "private");
|
|
1493
1264
|
const reqConfig = { method: "POST", path: path42, auth: "private" };
|
|
1494
1265
|
const headers = this.buildHeaders(reqConfig, path42, bodyJson, getNow());
|
|
1495
|
-
if (this.dohNode) {
|
|
1496
|
-
headers.set("User-Agent", this.dohUserAgent);
|
|
1497
|
-
}
|
|
1498
1266
|
const t0 = Date.now();
|
|
1499
1267
|
const response = await this.fetchBinary(path42, endpoint, headers, bodyJson, t0);
|
|
1500
1268
|
const elapsed = Date.now() - t0;
|
|
@@ -1528,10 +1296,10 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1528
1296
|
method: "POST",
|
|
1529
1297
|
headers,
|
|
1530
1298
|
body: bodyJson || void 0,
|
|
1531
|
-
signal: AbortSignal.timeout(this.config.timeoutMs)
|
|
1532
|
-
dispatcher: this.activeDispatcher
|
|
1299
|
+
signal: AbortSignal.timeout(this.config.timeoutMs)
|
|
1533
1300
|
};
|
|
1534
|
-
|
|
1301
|
+
if (this.dispatcher) fetchOptions.dispatcher = this.dispatcher;
|
|
1302
|
+
return await fetch(`${this.config.baseUrl}${path42}`, fetchOptions);
|
|
1535
1303
|
} catch (error) {
|
|
1536
1304
|
if (this.config.verbose) {
|
|
1537
1305
|
vlog(`\u2717 NetworkError after ${Date.now() - t0}ms: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -1553,7 +1321,8 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1553
1321
|
if (reqConfig.auth === "private") {
|
|
1554
1322
|
this.setAuthHeaders(headers, reqConfig.method, requestPath, bodyJson, timestamp);
|
|
1555
1323
|
}
|
|
1556
|
-
|
|
1324
|
+
const useSimulated = reqConfig.simulatedTrading !== void 0 ? reqConfig.simulatedTrading : this.config.demo;
|
|
1325
|
+
if (useSimulated) {
|
|
1557
1326
|
headers.set("x-simulated-trading", "1");
|
|
1558
1327
|
}
|
|
1559
1328
|
return headers;
|
|
@@ -1561,55 +1330,10 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1561
1330
|
// ---------------------------------------------------------------------------
|
|
1562
1331
|
// JSON request
|
|
1563
1332
|
// ---------------------------------------------------------------------------
|
|
1564
|
-
/**
|
|
1565
|
-
* Handle network error during a JSON request: refresh DoH and maybe retry.
|
|
1566
|
-
* Always either returns a retry result or throws NetworkError.
|
|
1567
|
-
*/
|
|
1568
|
-
async handleRequestNetworkError(error, reqConfig, requestPath, t0) {
|
|
1569
|
-
if (!this.dohRetried) {
|
|
1570
|
-
if (this.config.verbose) {
|
|
1571
|
-
const cause = error instanceof Error ? error.message : String(error);
|
|
1572
|
-
vlog(`Network failure, refreshing DoH: ${cause}`);
|
|
1573
|
-
}
|
|
1574
|
-
const shouldRetry = await this.handleDohNetworkFailure();
|
|
1575
|
-
if (shouldRetry && reqConfig.method === "GET") {
|
|
1576
|
-
return this.request(reqConfig);
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
1579
|
-
if (this.config.verbose) {
|
|
1580
|
-
const elapsed = Date.now() - t0;
|
|
1581
|
-
const cause = error instanceof Error ? error.message : String(error);
|
|
1582
|
-
vlog(`\u2717 NetworkError after ${elapsed}ms: ${cause}`);
|
|
1583
|
-
}
|
|
1584
|
-
throw new NetworkError(
|
|
1585
|
-
`Failed to call OKX endpoint ${reqConfig.method} ${requestPath}.`,
|
|
1586
|
-
`${reqConfig.method} ${requestPath}`,
|
|
1587
|
-
error
|
|
1588
|
-
);
|
|
1589
|
-
}
|
|
1590
|
-
/**
|
|
1591
|
-
* After a successful HTTP response on direct connection, cache mode=direct.
|
|
1592
|
-
* (Even if the business response is an error, the network path is valid.)
|
|
1593
|
-
*/
|
|
1594
|
-
cacheDirectConnectionIfNeeded() {
|
|
1595
|
-
if (!this.directUnverified || this.dohNode) return;
|
|
1596
|
-
this.directUnverified = false;
|
|
1597
|
-
const { hostname } = new URL(this.config.baseUrl);
|
|
1598
|
-
writeCache(hostname, {
|
|
1599
|
-
mode: "direct",
|
|
1600
|
-
node: null,
|
|
1601
|
-
failedNodes: [],
|
|
1602
|
-
updatedAt: Date.now()
|
|
1603
|
-
});
|
|
1604
|
-
if (this.config.verbose) {
|
|
1605
|
-
vlog("DoH: direct connection succeeded, cached mode=direct");
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
1333
|
async request(reqConfig) {
|
|
1609
|
-
this.ensureDoh();
|
|
1610
1334
|
const queryString = buildQueryString(reqConfig.query);
|
|
1611
1335
|
const requestPath = queryString.length > 0 ? `${reqConfig.path}?${queryString}` : reqConfig.path;
|
|
1612
|
-
const url = `${this.
|
|
1336
|
+
const url = `${this.config.baseUrl}${requestPath}`;
|
|
1613
1337
|
const bodyJson = reqConfig.body ? JSON.stringify(reqConfig.body) : "";
|
|
1614
1338
|
const timestamp = getNow();
|
|
1615
1339
|
this.logRequest(reqConfig.method, url, reqConfig.auth);
|
|
@@ -1617,9 +1341,6 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1617
1341
|
await this.rateLimiter.consume(reqConfig.rateLimit);
|
|
1618
1342
|
}
|
|
1619
1343
|
const headers = this.buildHeaders(reqConfig, requestPath, bodyJson, timestamp);
|
|
1620
|
-
if (this.dohNode) {
|
|
1621
|
-
headers.set("User-Agent", this.dohUserAgent);
|
|
1622
|
-
}
|
|
1623
1344
|
const t0 = Date.now();
|
|
1624
1345
|
let response;
|
|
1625
1346
|
try {
|
|
@@ -1627,17 +1348,27 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1627
1348
|
method: reqConfig.method,
|
|
1628
1349
|
headers,
|
|
1629
1350
|
body: reqConfig.method === "POST" ? bodyJson : void 0,
|
|
1630
|
-
signal: AbortSignal.timeout(this.config.timeoutMs)
|
|
1631
|
-
dispatcher: this.activeDispatcher
|
|
1351
|
+
signal: AbortSignal.timeout(this.config.timeoutMs)
|
|
1632
1352
|
};
|
|
1353
|
+
if (this.dispatcher) {
|
|
1354
|
+
fetchOptions.dispatcher = this.dispatcher;
|
|
1355
|
+
}
|
|
1633
1356
|
response = await fetch(url, fetchOptions);
|
|
1634
1357
|
} catch (error) {
|
|
1635
|
-
|
|
1358
|
+
if (this.config.verbose) {
|
|
1359
|
+
const elapsed2 = Date.now() - t0;
|
|
1360
|
+
const cause = error instanceof Error ? error.message : String(error);
|
|
1361
|
+
vlog(`\u2717 NetworkError after ${elapsed2}ms: ${cause}`);
|
|
1362
|
+
}
|
|
1363
|
+
throw new NetworkError(
|
|
1364
|
+
`Failed to call OKX endpoint ${reqConfig.method} ${requestPath}.`,
|
|
1365
|
+
`${reqConfig.method} ${requestPath}`,
|
|
1366
|
+
error
|
|
1367
|
+
);
|
|
1636
1368
|
}
|
|
1637
1369
|
const rawText = await response.text();
|
|
1638
1370
|
const elapsed = Date.now() - t0;
|
|
1639
1371
|
const traceId = extractTraceId(response.headers);
|
|
1640
|
-
this.cacheDirectConnectionIfNeeded();
|
|
1641
1372
|
return this.processResponse(rawText, response, elapsed, traceId, reqConfig, requestPath);
|
|
1642
1373
|
}
|
|
1643
1374
|
};
|
|
@@ -3516,19 +3247,19 @@ function safeWriteFile(targetDir, fileName, data) {
|
|
|
3516
3247
|
throw new Error(`Invalid file name: "${fileName}"`);
|
|
3517
3248
|
}
|
|
3518
3249
|
const resolvedDir = resolve(targetDir);
|
|
3519
|
-
const filePath =
|
|
3250
|
+
const filePath = join(resolvedDir, safeName);
|
|
3520
3251
|
const resolvedPath = resolve(filePath);
|
|
3521
3252
|
if (!resolvedPath.startsWith(resolvedDir + sep)) {
|
|
3522
3253
|
throw new Error(`Path traversal detected: "${fileName}" resolves outside target directory`);
|
|
3523
3254
|
}
|
|
3524
|
-
|
|
3255
|
+
mkdirSync(resolvedDir, { recursive: true });
|
|
3525
3256
|
const tmpPath = `${resolvedPath}.${randomUUID()}.tmp`;
|
|
3526
3257
|
try {
|
|
3527
|
-
|
|
3528
|
-
|
|
3258
|
+
writeFileSync(tmpPath, data);
|
|
3259
|
+
renameSync(tmpPath, resolvedPath);
|
|
3529
3260
|
} catch (err) {
|
|
3530
3261
|
try {
|
|
3531
|
-
|
|
3262
|
+
unlinkSync(tmpPath);
|
|
3532
3263
|
} catch {
|
|
3533
3264
|
}
|
|
3534
3265
|
throw err;
|
|
@@ -3544,13 +3275,14 @@ function validateZipEntryPath(targetDir, entryName) {
|
|
|
3544
3275
|
return resolvedEntry;
|
|
3545
3276
|
}
|
|
3546
3277
|
var MAX_DOWNLOAD_BYTES = 50 * 1024 * 1024;
|
|
3547
|
-
async function downloadSkillZip(client, name, targetDir) {
|
|
3278
|
+
async function downloadSkillZip(client, name, targetDir, format = "zip") {
|
|
3548
3279
|
const result = await client.privatePostBinary(
|
|
3549
3280
|
"/api/v5/skill/download",
|
|
3550
3281
|
{ name },
|
|
3551
3282
|
{ maxBytes: MAX_DOWNLOAD_BYTES }
|
|
3552
3283
|
);
|
|
3553
|
-
const
|
|
3284
|
+
const ext = format === "skill" ? "skill" : "zip";
|
|
3285
|
+
const fileName = `${name}.${ext}`;
|
|
3554
3286
|
const filePath = safeWriteFile(targetDir, fileName, result.data);
|
|
3555
3287
|
return filePath;
|
|
3556
3288
|
}
|
|
@@ -3593,7 +3325,7 @@ async function extractSkillZip(zipPath, targetDir, limits) {
|
|
|
3593
3325
|
const maxFiles = limits?.maxFiles ?? DEFAULT_MAX_FILES;
|
|
3594
3326
|
const maxCompressionRatio = limits?.maxCompressionRatio ?? DEFAULT_MAX_COMPRESSION_RATIO;
|
|
3595
3327
|
const resolvedTarget = resolve2(targetDir);
|
|
3596
|
-
|
|
3328
|
+
mkdirSync2(resolvedTarget, { recursive: true });
|
|
3597
3329
|
return new Promise((resolvePromise, reject) => {
|
|
3598
3330
|
yauzl.open(zipPath, { lazyEntries: true }, (err, zipfile) => {
|
|
3599
3331
|
if (err) return reject(err);
|
|
@@ -3616,7 +3348,7 @@ async function extractSkillZip(zipPath, targetDir, limits) {
|
|
|
3616
3348
|
zipfile.close();
|
|
3617
3349
|
return reject(streamErr);
|
|
3618
3350
|
}
|
|
3619
|
-
|
|
3351
|
+
mkdirSync2(dirname(resolvedPath), { recursive: true });
|
|
3620
3352
|
const writeStream = createWriteStream(resolvedPath);
|
|
3621
3353
|
readStream.pipe(writeStream);
|
|
3622
3354
|
writeStream.on("close", () => zipfile.readEntry());
|
|
@@ -3632,11 +3364,11 @@ async function extractSkillZip(zipPath, targetDir, limits) {
|
|
|
3632
3364
|
});
|
|
3633
3365
|
}
|
|
3634
3366
|
function readMetaJson(contentDir) {
|
|
3635
|
-
const metaPath =
|
|
3367
|
+
const metaPath = join2(contentDir, "_meta.json");
|
|
3636
3368
|
if (!existsSync(metaPath)) {
|
|
3637
3369
|
throw new Error(`_meta.json not found in ${contentDir}. Invalid skill package.`);
|
|
3638
3370
|
}
|
|
3639
|
-
const raw =
|
|
3371
|
+
const raw = readFileSync(metaPath, "utf-8");
|
|
3640
3372
|
let parsed;
|
|
3641
3373
|
try {
|
|
3642
3374
|
parsed = JSON.parse(raw);
|
|
@@ -3658,26 +3390,26 @@ function readMetaJson(contentDir) {
|
|
|
3658
3390
|
};
|
|
3659
3391
|
}
|
|
3660
3392
|
function validateSkillMdExists(contentDir) {
|
|
3661
|
-
const skillMdPath =
|
|
3393
|
+
const skillMdPath = join2(contentDir, "SKILL.md");
|
|
3662
3394
|
if (!existsSync(skillMdPath)) {
|
|
3663
3395
|
throw new Error(`SKILL.md not found in ${contentDir}. Invalid skill package.`);
|
|
3664
3396
|
}
|
|
3665
3397
|
}
|
|
3666
|
-
var DEFAULT_REGISTRY_PATH =
|
|
3398
|
+
var DEFAULT_REGISTRY_PATH = join3(homedir(), ".okx", "skills", "registry.json");
|
|
3667
3399
|
function readRegistry(registryPath = DEFAULT_REGISTRY_PATH) {
|
|
3668
3400
|
if (!existsSync2(registryPath)) {
|
|
3669
3401
|
return { version: 1, skills: {} };
|
|
3670
3402
|
}
|
|
3671
3403
|
try {
|
|
3672
|
-
const raw =
|
|
3404
|
+
const raw = readFileSync2(registryPath, "utf-8");
|
|
3673
3405
|
return JSON.parse(raw);
|
|
3674
3406
|
} catch {
|
|
3675
3407
|
return { version: 1, skills: {} };
|
|
3676
3408
|
}
|
|
3677
3409
|
}
|
|
3678
3410
|
function writeRegistry(registry, registryPath = DEFAULT_REGISTRY_PATH) {
|
|
3679
|
-
|
|
3680
|
-
|
|
3411
|
+
mkdirSync3(dirname2(registryPath), { recursive: true });
|
|
3412
|
+
writeFileSync2(registryPath, JSON.stringify(registry, null, 2) + "\n", "utf-8");
|
|
3681
3413
|
}
|
|
3682
3414
|
function upsertSkillRecord(meta, registryPath = DEFAULT_REGISTRY_PATH) {
|
|
3683
3415
|
const registry = readRegistry(registryPath);
|
|
@@ -3750,7 +3482,7 @@ function registerSkillsTools() {
|
|
|
3750
3482
|
{
|
|
3751
3483
|
name: "skills_download",
|
|
3752
3484
|
module: "skills",
|
|
3753
|
-
description: "Download a skill
|
|
3485
|
+
description: "Download a skill package from OKX Skills Marketplace to a local directory. Always call skills_search first to confirm the skill name exists. Downloads the latest approved version. NOTE: Downloads third-party developer content \u2014 does NOT install to agents. For full installation use CLI: okx skill add <name>. Use when the user wants to inspect or manually install a skill package.",
|
|
3754
3486
|
inputSchema: {
|
|
3755
3487
|
type: "object",
|
|
3756
3488
|
properties: {
|
|
@@ -3760,7 +3492,12 @@ function registerSkillsTools() {
|
|
|
3760
3492
|
},
|
|
3761
3493
|
targetDir: {
|
|
3762
3494
|
type: "string",
|
|
3763
|
-
description: "Directory path where the
|
|
3495
|
+
description: "Directory path where the file will be saved"
|
|
3496
|
+
},
|
|
3497
|
+
format: {
|
|
3498
|
+
type: "string",
|
|
3499
|
+
description: "Output file format: 'zip' or 'skill' (default: 'skill')",
|
|
3500
|
+
enum: ["zip", "skill"]
|
|
3764
3501
|
}
|
|
3765
3502
|
},
|
|
3766
3503
|
required: ["name", "targetDir"],
|
|
@@ -3793,7 +3530,8 @@ async function handleSearch(args, ctx) {
|
|
|
3793
3530
|
async function handleDownload(args, ctx) {
|
|
3794
3531
|
const name = String(args.name);
|
|
3795
3532
|
const targetDir = String(args.targetDir);
|
|
3796
|
-
const
|
|
3533
|
+
const format = args.format === "zip" ? "zip" : "skill";
|
|
3534
|
+
const filePath = await downloadSkillZip(ctx.client, name, targetDir, format);
|
|
3797
3535
|
return {
|
|
3798
3536
|
endpoint: "POST /api/v5/skill/download",
|
|
3799
3537
|
requestTime: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -5940,6 +5678,12 @@ function registerFuturesTools() {
|
|
|
5940
5678
|
];
|
|
5941
5679
|
}
|
|
5942
5680
|
var TWO_DAYS_MS = 2 * 24 * 60 * 60 * 1e3;
|
|
5681
|
+
var DEMO_PROPERTY = {
|
|
5682
|
+
demo: {
|
|
5683
|
+
type: "boolean",
|
|
5684
|
+
description: "Query simulated trading (demo) market data. Default: false (live market data)."
|
|
5685
|
+
}
|
|
5686
|
+
};
|
|
5943
5687
|
function registerMarketTools() {
|
|
5944
5688
|
return [
|
|
5945
5689
|
{
|
|
@@ -5953,7 +5697,8 @@ function registerMarketTools() {
|
|
|
5953
5697
|
instId: {
|
|
5954
5698
|
type: "string",
|
|
5955
5699
|
description: "e.g. BTC-USDT, BTC-USDT-SWAP"
|
|
5956
|
-
}
|
|
5700
|
+
},
|
|
5701
|
+
...DEMO_PROPERTY
|
|
5957
5702
|
},
|
|
5958
5703
|
required: ["instId"]
|
|
5959
5704
|
},
|
|
@@ -5962,7 +5707,8 @@ function registerMarketTools() {
|
|
|
5962
5707
|
const response = await context.client.publicGet(
|
|
5963
5708
|
"/api/v5/market/ticker",
|
|
5964
5709
|
{ instId: requireString(args, "instId") },
|
|
5965
|
-
publicRateLimit("market_get_ticker", 20)
|
|
5710
|
+
publicRateLimit("market_get_ticker", 20),
|
|
5711
|
+
readBoolean(args, "demo") ?? false
|
|
5966
5712
|
);
|
|
5967
5713
|
return normalizeResponse(response);
|
|
5968
5714
|
}
|
|
@@ -5986,7 +5732,8 @@ function registerMarketTools() {
|
|
|
5986
5732
|
instFamily: {
|
|
5987
5733
|
type: "string",
|
|
5988
5734
|
description: "e.g. BTC-USD"
|
|
5989
|
-
}
|
|
5735
|
+
},
|
|
5736
|
+
...DEMO_PROPERTY
|
|
5990
5737
|
},
|
|
5991
5738
|
required: ["instType"]
|
|
5992
5739
|
},
|
|
@@ -5999,7 +5746,8 @@ function registerMarketTools() {
|
|
|
5999
5746
|
uly: readString(args, "uly"),
|
|
6000
5747
|
instFamily: readString(args, "instFamily")
|
|
6001
5748
|
}),
|
|
6002
|
-
publicRateLimit("market_get_tickers", 20)
|
|
5749
|
+
publicRateLimit("market_get_tickers", 20),
|
|
5750
|
+
readBoolean(args, "demo") ?? false
|
|
6003
5751
|
);
|
|
6004
5752
|
return normalizeResponse(response);
|
|
6005
5753
|
}
|
|
@@ -6019,7 +5767,8 @@ function registerMarketTools() {
|
|
|
6019
5767
|
sz: {
|
|
6020
5768
|
type: "number",
|
|
6021
5769
|
description: "Depth per side, default 1, max 400"
|
|
6022
|
-
}
|
|
5770
|
+
},
|
|
5771
|
+
...DEMO_PROPERTY
|
|
6023
5772
|
},
|
|
6024
5773
|
required: ["instId"]
|
|
6025
5774
|
},
|
|
@@ -6031,7 +5780,8 @@ function registerMarketTools() {
|
|
|
6031
5780
|
instId: requireString(args, "instId"),
|
|
6032
5781
|
sz: readNumber(args, "sz")
|
|
6033
5782
|
}),
|
|
6034
|
-
publicRateLimit("market_get_orderbook", 20)
|
|
5783
|
+
publicRateLimit("market_get_orderbook", 20),
|
|
5784
|
+
readBoolean(args, "demo") ?? false
|
|
6035
5785
|
);
|
|
6036
5786
|
return normalizeResponse(response);
|
|
6037
5787
|
}
|
|
@@ -6064,7 +5814,8 @@ function registerMarketTools() {
|
|
|
6064
5814
|
limit: {
|
|
6065
5815
|
type: "number",
|
|
6066
5816
|
description: "Max results (default 100)"
|
|
6067
|
-
}
|
|
5817
|
+
},
|
|
5818
|
+
...DEMO_PROPERTY
|
|
6068
5819
|
},
|
|
6069
5820
|
required: ["instId"]
|
|
6070
5821
|
},
|
|
@@ -6072,6 +5823,7 @@ function registerMarketTools() {
|
|
|
6072
5823
|
const args = asRecord(rawArgs);
|
|
6073
5824
|
const afterTs = readString(args, "after");
|
|
6074
5825
|
const beforeTs = readString(args, "before");
|
|
5826
|
+
const demo = readBoolean(args, "demo") ?? false;
|
|
6075
5827
|
const query = compactObject({
|
|
6076
5828
|
instId: requireString(args, "instId"),
|
|
6077
5829
|
bar: readString(args, "bar"),
|
|
@@ -6083,9 +5835,9 @@ function registerMarketTools() {
|
|
|
6083
5835
|
const hasTimestamp = afterTs !== void 0 || beforeTs !== void 0;
|
|
6084
5836
|
const useHistory = afterTs !== void 0 && Number(afterTs) < Date.now() - TWO_DAYS_MS;
|
|
6085
5837
|
const path42 = useHistory ? "/api/v5/market/history-candles" : "/api/v5/market/candles";
|
|
6086
|
-
const response = await context.client.publicGet(path42, query, rateLimit);
|
|
5838
|
+
const response = await context.client.publicGet(path42, query, rateLimit, demo);
|
|
6087
5839
|
if (!useHistory && hasTimestamp && Array.isArray(response.data) && response.data.length === 0) {
|
|
6088
|
-
return normalizeResponse(await context.client.publicGet("/api/v5/market/history-candles", query, rateLimit));
|
|
5840
|
+
return normalizeResponse(await context.client.publicGet("/api/v5/market/history-candles", query, rateLimit, demo));
|
|
6089
5841
|
}
|
|
6090
5842
|
return normalizeResponse(response);
|
|
6091
5843
|
}
|
|
@@ -6113,7 +5865,8 @@ function registerMarketTools() {
|
|
|
6113
5865
|
instFamily: {
|
|
6114
5866
|
type: "string",
|
|
6115
5867
|
description: "e.g. BTC-USD"
|
|
6116
|
-
}
|
|
5868
|
+
},
|
|
5869
|
+
...DEMO_PROPERTY
|
|
6117
5870
|
},
|
|
6118
5871
|
required: ["instType"]
|
|
6119
5872
|
},
|
|
@@ -6127,7 +5880,8 @@ function registerMarketTools() {
|
|
|
6127
5880
|
uly: readString(args, "uly"),
|
|
6128
5881
|
instFamily: readString(args, "instFamily")
|
|
6129
5882
|
}),
|
|
6130
|
-
publicRateLimit("market_get_instruments", 20)
|
|
5883
|
+
publicRateLimit("market_get_instruments", 20),
|
|
5884
|
+
readBoolean(args, "demo") ?? false
|
|
6131
5885
|
);
|
|
6132
5886
|
return normalizeResponse(response);
|
|
6133
5887
|
}
|
|
@@ -6159,13 +5913,15 @@ function registerMarketTools() {
|
|
|
6159
5913
|
limit: {
|
|
6160
5914
|
type: "number",
|
|
6161
5915
|
description: "History records (default 20, max 100)"
|
|
6162
|
-
}
|
|
5916
|
+
},
|
|
5917
|
+
...DEMO_PROPERTY
|
|
6163
5918
|
},
|
|
6164
5919
|
required: ["instId"]
|
|
6165
5920
|
},
|
|
6166
5921
|
handler: async (rawArgs, context) => {
|
|
6167
5922
|
const args = asRecord(rawArgs);
|
|
6168
5923
|
const isHistory = readBoolean(args, "history") ?? false;
|
|
5924
|
+
const demo = readBoolean(args, "demo") ?? false;
|
|
6169
5925
|
if (isHistory) {
|
|
6170
5926
|
const response2 = await context.client.publicGet(
|
|
6171
5927
|
"/api/v5/public/funding-rate-history",
|
|
@@ -6175,14 +5931,16 @@ function registerMarketTools() {
|
|
|
6175
5931
|
before: readString(args, "before"),
|
|
6176
5932
|
limit: readNumber(args, "limit") ?? 20
|
|
6177
5933
|
}),
|
|
6178
|
-
publicRateLimit("market_get_funding_rate", 20)
|
|
5934
|
+
publicRateLimit("market_get_funding_rate", 20),
|
|
5935
|
+
demo
|
|
6179
5936
|
);
|
|
6180
5937
|
return normalizeResponse(response2);
|
|
6181
5938
|
}
|
|
6182
5939
|
const response = await context.client.publicGet(
|
|
6183
5940
|
"/api/v5/public/funding-rate",
|
|
6184
5941
|
{ instId: requireString(args, "instId") },
|
|
6185
|
-
publicRateLimit("market_get_funding_rate", 20)
|
|
5942
|
+
publicRateLimit("market_get_funding_rate", 20),
|
|
5943
|
+
demo
|
|
6186
5944
|
);
|
|
6187
5945
|
return normalizeResponse(response);
|
|
6188
5946
|
}
|
|
@@ -6209,7 +5967,8 @@ function registerMarketTools() {
|
|
|
6209
5967
|
},
|
|
6210
5968
|
instFamily: {
|
|
6211
5969
|
type: "string"
|
|
6212
|
-
}
|
|
5970
|
+
},
|
|
5971
|
+
...DEMO_PROPERTY
|
|
6213
5972
|
},
|
|
6214
5973
|
required: ["instType"]
|
|
6215
5974
|
},
|
|
@@ -6223,7 +5982,8 @@ function registerMarketTools() {
|
|
|
6223
5982
|
uly: readString(args, "uly"),
|
|
6224
5983
|
instFamily: readString(args, "instFamily")
|
|
6225
5984
|
}),
|
|
6226
|
-
publicRateLimit("market_get_mark_price", 10)
|
|
5985
|
+
publicRateLimit("market_get_mark_price", 10),
|
|
5986
|
+
readBoolean(args, "demo") ?? false
|
|
6227
5987
|
);
|
|
6228
5988
|
return normalizeResponse(response);
|
|
6229
5989
|
}
|
|
@@ -6243,7 +6003,8 @@ function registerMarketTools() {
|
|
|
6243
6003
|
limit: {
|
|
6244
6004
|
type: "number",
|
|
6245
6005
|
description: "Default 20, max 500"
|
|
6246
|
-
}
|
|
6006
|
+
},
|
|
6007
|
+
...DEMO_PROPERTY
|
|
6247
6008
|
},
|
|
6248
6009
|
required: ["instId"]
|
|
6249
6010
|
},
|
|
@@ -6255,7 +6016,8 @@ function registerMarketTools() {
|
|
|
6255
6016
|
instId: requireString(args, "instId"),
|
|
6256
6017
|
limit: readNumber(args, "limit") ?? 20
|
|
6257
6018
|
}),
|
|
6258
|
-
publicRateLimit("market_get_trades", 20)
|
|
6019
|
+
publicRateLimit("market_get_trades", 20),
|
|
6020
|
+
readBoolean(args, "demo") ?? false
|
|
6259
6021
|
);
|
|
6260
6022
|
return normalizeResponse(response);
|
|
6261
6023
|
}
|
|
@@ -6275,7 +6037,8 @@ function registerMarketTools() {
|
|
|
6275
6037
|
quoteCcy: {
|
|
6276
6038
|
type: "string",
|
|
6277
6039
|
description: "e.g. USD or USDT"
|
|
6278
|
-
}
|
|
6040
|
+
},
|
|
6041
|
+
...DEMO_PROPERTY
|
|
6279
6042
|
}
|
|
6280
6043
|
},
|
|
6281
6044
|
handler: async (rawArgs, context) => {
|
|
@@ -6286,7 +6049,8 @@ function registerMarketTools() {
|
|
|
6286
6049
|
instId: readString(args, "instId"),
|
|
6287
6050
|
quoteCcy: readString(args, "quoteCcy")
|
|
6288
6051
|
}),
|
|
6289
|
-
publicRateLimit("market_get_index_ticker", 20)
|
|
6052
|
+
publicRateLimit("market_get_index_ticker", 20),
|
|
6053
|
+
readBoolean(args, "demo") ?? false
|
|
6290
6054
|
);
|
|
6291
6055
|
return normalizeResponse(response);
|
|
6292
6056
|
}
|
|
@@ -6323,7 +6087,8 @@ function registerMarketTools() {
|
|
|
6323
6087
|
history: {
|
|
6324
6088
|
type: "boolean",
|
|
6325
6089
|
description: "true=older historical data"
|
|
6326
|
-
}
|
|
6090
|
+
},
|
|
6091
|
+
...DEMO_PROPERTY
|
|
6327
6092
|
},
|
|
6328
6093
|
required: ["instId"]
|
|
6329
6094
|
},
|
|
@@ -6340,7 +6105,8 @@ function registerMarketTools() {
|
|
|
6340
6105
|
before: readString(args, "before"),
|
|
6341
6106
|
limit: readNumber(args, "limit")
|
|
6342
6107
|
}),
|
|
6343
|
-
publicRateLimit("market_get_index_candles", 20)
|
|
6108
|
+
publicRateLimit("market_get_index_candles", 20),
|
|
6109
|
+
readBoolean(args, "demo") ?? false
|
|
6344
6110
|
);
|
|
6345
6111
|
return normalizeResponse(response);
|
|
6346
6112
|
}
|
|
@@ -6356,7 +6122,8 @@ function registerMarketTools() {
|
|
|
6356
6122
|
instId: {
|
|
6357
6123
|
type: "string",
|
|
6358
6124
|
description: "SWAP or FUTURES ID, e.g. BTC-USDT-SWAP"
|
|
6359
|
-
}
|
|
6125
|
+
},
|
|
6126
|
+
...DEMO_PROPERTY
|
|
6360
6127
|
},
|
|
6361
6128
|
required: ["instId"]
|
|
6362
6129
|
},
|
|
@@ -6365,7 +6132,8 @@ function registerMarketTools() {
|
|
|
6365
6132
|
const response = await context.client.publicGet(
|
|
6366
6133
|
"/api/v5/public/price-limit",
|
|
6367
6134
|
{ instId: requireString(args, "instId") },
|
|
6368
|
-
publicRateLimit("market_get_price_limit", 20)
|
|
6135
|
+
publicRateLimit("market_get_price_limit", 20),
|
|
6136
|
+
readBoolean(args, "demo") ?? false
|
|
6369
6137
|
);
|
|
6370
6138
|
return normalizeResponse(response);
|
|
6371
6139
|
}
|
|
@@ -6392,7 +6160,8 @@ function registerMarketTools() {
|
|
|
6392
6160
|
},
|
|
6393
6161
|
instFamily: {
|
|
6394
6162
|
type: "string"
|
|
6395
|
-
}
|
|
6163
|
+
},
|
|
6164
|
+
...DEMO_PROPERTY
|
|
6396
6165
|
},
|
|
6397
6166
|
required: ["instType"]
|
|
6398
6167
|
},
|
|
@@ -6406,7 +6175,8 @@ function registerMarketTools() {
|
|
|
6406
6175
|
uly: readString(args, "uly"),
|
|
6407
6176
|
instFamily: readString(args, "instFamily")
|
|
6408
6177
|
}),
|
|
6409
|
-
publicRateLimit("market_get_open_interest", 20)
|
|
6178
|
+
publicRateLimit("market_get_open_interest", 20),
|
|
6179
|
+
readBoolean(args, "demo") ?? false
|
|
6410
6180
|
);
|
|
6411
6181
|
return normalizeResponse(response);
|
|
6412
6182
|
}
|
|
@@ -6427,7 +6197,8 @@ function registerMarketTools() {
|
|
|
6427
6197
|
instId: {
|
|
6428
6198
|
type: "string",
|
|
6429
6199
|
description: "Optional: filter by specific instrument ID, e.g. AAPL-USDT-SWAP"
|
|
6430
|
-
}
|
|
6200
|
+
},
|
|
6201
|
+
...DEMO_PROPERTY
|
|
6431
6202
|
},
|
|
6432
6203
|
required: []
|
|
6433
6204
|
},
|
|
@@ -6438,7 +6209,8 @@ function registerMarketTools() {
|
|
|
6438
6209
|
const response = await context.client.publicGet(
|
|
6439
6210
|
"/api/v5/public/instruments",
|
|
6440
6211
|
compactObject({ instType, instId }),
|
|
6441
|
-
publicRateLimit("market_get_stock_tokens", 20)
|
|
6212
|
+
publicRateLimit("market_get_stock_tokens", 20),
|
|
6213
|
+
readBoolean(args, "demo") ?? false
|
|
6442
6214
|
);
|
|
6443
6215
|
const data = response.data;
|
|
6444
6216
|
const filtered = Array.isArray(data) ? data.filter((item) => item.instCategory === "3") : data;
|
|
@@ -6448,7 +6220,7 @@ function registerMarketTools() {
|
|
|
6448
6220
|
{
|
|
6449
6221
|
name: "market_get_instruments_by_category",
|
|
6450
6222
|
module: "market",
|
|
6451
|
-
description: "Discover tradeable instruments by asset category. Stock tokens (instCategory=3, e.g. AAPL-USDT-SWAP, TSLA-USDT-SWAP), Metals (4, e.g. XAUUSDT-USDT-SWAP for gold), Commodities (5, e.g. OIL-USDT-SWAP for crude oil), Forex (6, e.g. EURUSDT-USDT-SWAP for EUR/USD), Bonds (7, e.g. US30Y-USDT-SWAP). Use this to find instIds before querying prices or placing orders. Filters client-side by instCategory.",
|
|
6223
|
+
description: "Discover tradeable instruments by asset category. Stock tokens (instCategory=3, e.g. AAPL-USDT-SWAP, TSLA-USDT-SWAP), Metals (4, e.g. XAUUSDT-USDT-SWAP for gold), Commodities (5, e.g. OIL-USDT-SWAP for crude oil), Forex (6, e.g. EURUSDT-USDT-SWAP for EUR/USD), Bonds (7, e.g. US30Y-USDT-SWAP for crude oil). Use this to find instIds before querying prices or placing orders. Filters client-side by instCategory.",
|
|
6452
6224
|
isWrite: false,
|
|
6453
6225
|
inputSchema: {
|
|
6454
6226
|
type: "object",
|
|
@@ -6466,7 +6238,8 @@ function registerMarketTools() {
|
|
|
6466
6238
|
instId: {
|
|
6467
6239
|
type: "string",
|
|
6468
6240
|
description: "Optional: filter by specific instrument ID"
|
|
6469
|
-
}
|
|
6241
|
+
},
|
|
6242
|
+
...DEMO_PROPERTY
|
|
6470
6243
|
},
|
|
6471
6244
|
required: ["instCategory"]
|
|
6472
6245
|
},
|
|
@@ -6478,7 +6251,8 @@ function registerMarketTools() {
|
|
|
6478
6251
|
const response = await context.client.publicGet(
|
|
6479
6252
|
"/api/v5/public/instruments",
|
|
6480
6253
|
compactObject({ instType, instId }),
|
|
6481
|
-
publicRateLimit("market_get_instruments_by_category", 20)
|
|
6254
|
+
publicRateLimit("market_get_instruments_by_category", 20),
|
|
6255
|
+
readBoolean(args, "demo") ?? false
|
|
6482
6256
|
);
|
|
6483
6257
|
const data = response.data;
|
|
6484
6258
|
const filtered = Array.isArray(data) ? data.filter((item) => item.instCategory === instCategory) : data;
|
|
@@ -8000,12 +7774,12 @@ function createToolRunner(client, config) {
|
|
|
8000
7774
|
};
|
|
8001
7775
|
}
|
|
8002
7776
|
function configFilePath() {
|
|
8003
|
-
return
|
|
7777
|
+
return join4(homedir2(), ".okx", "config.toml");
|
|
8004
7778
|
}
|
|
8005
7779
|
function readFullConfig() {
|
|
8006
7780
|
const path42 = configFilePath();
|
|
8007
7781
|
if (!existsSync3(path42)) return { profiles: {} };
|
|
8008
|
-
const raw =
|
|
7782
|
+
const raw = readFileSync3(path42, "utf-8");
|
|
8009
7783
|
try {
|
|
8010
7784
|
return parse(raw);
|
|
8011
7785
|
} catch (err) {
|
|
@@ -8033,11 +7807,11 @@ var CONFIG_HEADER = `# OKX Trade Kit Configuration
|
|
|
8033
7807
|
`;
|
|
8034
7808
|
function writeFullConfig(config) {
|
|
8035
7809
|
const path42 = configFilePath();
|
|
8036
|
-
const dir =
|
|
7810
|
+
const dir = dirname3(path42);
|
|
8037
7811
|
if (!existsSync3(dir)) {
|
|
8038
|
-
|
|
7812
|
+
mkdirSync4(dir, { recursive: true });
|
|
8039
7813
|
}
|
|
8040
|
-
|
|
7814
|
+
writeFileSync3(path42, CONFIG_HEADER + stringify(config), "utf-8");
|
|
8041
7815
|
}
|
|
8042
7816
|
function expandShorthand(moduleId) {
|
|
8043
7817
|
if (moduleId === "all") return [...MODULES];
|
|
@@ -8151,21 +7925,21 @@ function loadConfig(cli) {
|
|
|
8151
7925
|
verbose: cli.verbose ?? false
|
|
8152
7926
|
};
|
|
8153
7927
|
}
|
|
8154
|
-
var CACHE_FILE =
|
|
7928
|
+
var CACHE_FILE = join5(homedir3(), ".okx", "update-check.json");
|
|
8155
7929
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
8156
|
-
function
|
|
7930
|
+
function readCache() {
|
|
8157
7931
|
try {
|
|
8158
7932
|
if (existsSync4(CACHE_FILE)) {
|
|
8159
|
-
return JSON.parse(
|
|
7933
|
+
return JSON.parse(readFileSync4(CACHE_FILE, "utf-8"));
|
|
8160
7934
|
}
|
|
8161
7935
|
} catch {
|
|
8162
7936
|
}
|
|
8163
7937
|
return {};
|
|
8164
7938
|
}
|
|
8165
|
-
function
|
|
7939
|
+
function writeCache(cache) {
|
|
8166
7940
|
try {
|
|
8167
|
-
|
|
8168
|
-
|
|
7941
|
+
mkdirSync5(join5(homedir3(), ".okx"), { recursive: true });
|
|
7942
|
+
writeFileSync4(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
|
|
8169
7943
|
} catch {
|
|
8170
7944
|
}
|
|
8171
7945
|
}
|
|
@@ -8212,14 +7986,14 @@ async function fetchLatestVersion(packageName) {
|
|
|
8212
7986
|
function refreshCacheInBackground(packageName) {
|
|
8213
7987
|
fetchLatestVersion(packageName).then((latest) => {
|
|
8214
7988
|
if (!latest) return;
|
|
8215
|
-
const cache =
|
|
7989
|
+
const cache = readCache();
|
|
8216
7990
|
cache[packageName] = { latestVersion: latest, checkedAt: Date.now() };
|
|
8217
|
-
|
|
7991
|
+
writeCache(cache);
|
|
8218
7992
|
}).catch(() => {
|
|
8219
7993
|
});
|
|
8220
7994
|
}
|
|
8221
7995
|
function checkForUpdates(packageName, currentVersion) {
|
|
8222
|
-
const cache =
|
|
7996
|
+
const cache = readCache();
|
|
8223
7997
|
const entry = cache[packageName];
|
|
8224
7998
|
if (entry && isNewerVersion(currentVersion, entry.latestVersion)) {
|
|
8225
7999
|
process.stderr.write(
|
|
@@ -9074,7 +8848,7 @@ async function cmdDiagnoseMcp(options = {}) {
|
|
|
9074
8848
|
|
|
9075
8849
|
// src/commands/diagnose.ts
|
|
9076
8850
|
var CLI_VERSION = readCliVersion();
|
|
9077
|
-
var GIT_HASH = true ? "
|
|
8851
|
+
var GIT_HASH = true ? "6d4d559" : "dev";
|
|
9078
8852
|
function maskKey2(key) {
|
|
9079
8853
|
if (!key) return "(not set)";
|
|
9080
8854
|
if (key.length <= 8) return "****";
|
|
@@ -9371,24 +9145,24 @@ async function runCliChecks(config, profile, outputPath) {
|
|
|
9371
9145
|
|
|
9372
9146
|
// src/commands/upgrade.ts
|
|
9373
9147
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
9374
|
-
import { readFileSync as
|
|
9375
|
-
import { dirname as
|
|
9376
|
-
import { homedir as
|
|
9148
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7 } from "fs";
|
|
9149
|
+
import { dirname as dirname5, join as join7 } from "path";
|
|
9150
|
+
import { homedir as homedir5 } from "os";
|
|
9377
9151
|
var PACKAGES = ["@okx_ai/okx-trade-mcp", "@okx_ai/okx-trade-cli"];
|
|
9378
|
-
var CACHE_FILE2 =
|
|
9152
|
+
var CACHE_FILE2 = join7(homedir5(), ".okx", "last_check");
|
|
9379
9153
|
var THROTTLE_MS = 12 * 60 * 60 * 1e3;
|
|
9380
|
-
var NPM_BIN =
|
|
9154
|
+
var NPM_BIN = join7(dirname5(process.execPath), process.platform === "win32" ? "npm.cmd" : "npm");
|
|
9381
9155
|
function readLastCheck() {
|
|
9382
9156
|
try {
|
|
9383
|
-
return parseInt(
|
|
9157
|
+
return parseInt(readFileSync6(CACHE_FILE2, "utf-8").trim(), 10) || 0;
|
|
9384
9158
|
} catch {
|
|
9385
9159
|
return 0;
|
|
9386
9160
|
}
|
|
9387
9161
|
}
|
|
9388
9162
|
function writeLastCheck() {
|
|
9389
9163
|
try {
|
|
9390
|
-
|
|
9391
|
-
|
|
9164
|
+
mkdirSync7(join7(homedir5(), ".okx"), { recursive: true });
|
|
9165
|
+
writeFileSync6(CACHE_FILE2, String(Math.floor(Date.now() / 1e3)), "utf-8");
|
|
9392
9166
|
} catch {
|
|
9393
9167
|
}
|
|
9394
9168
|
}
|
|
@@ -10092,6 +9866,39 @@ var HELP_TREE = {
|
|
|
10092
9866
|
description: "Run network / MCP server diagnostics",
|
|
10093
9867
|
usage: "okx diagnose [--cli | --mcp | --all] [--profile <name>] [--demo | --live] [--output <file>]"
|
|
10094
9868
|
},
|
|
9869
|
+
skill: {
|
|
9870
|
+
description: "OKX Skills Marketplace \u2014 search, install, and manage agent skills",
|
|
9871
|
+
commands: {
|
|
9872
|
+
search: {
|
|
9873
|
+
usage: "okx skill search [--keyword <kw>] [--categories <id>] [--page <n>] [--limit <n>]",
|
|
9874
|
+
description: "Search for skills in the marketplace"
|
|
9875
|
+
},
|
|
9876
|
+
categories: {
|
|
9877
|
+
usage: "okx skill categories",
|
|
9878
|
+
description: "List available skill categories"
|
|
9879
|
+
},
|
|
9880
|
+
add: {
|
|
9881
|
+
usage: "okx skill add <name>",
|
|
9882
|
+
description: "Download and install a skill to detected agents"
|
|
9883
|
+
},
|
|
9884
|
+
download: {
|
|
9885
|
+
usage: "okx skill download <name> [--dir <path>] [--format zip|skill]",
|
|
9886
|
+
description: "Download a skill package without installing"
|
|
9887
|
+
},
|
|
9888
|
+
remove: {
|
|
9889
|
+
usage: "okx skill remove <name>",
|
|
9890
|
+
description: "Remove an installed skill"
|
|
9891
|
+
},
|
|
9892
|
+
check: {
|
|
9893
|
+
usage: "okx skill check <name>",
|
|
9894
|
+
description: "Check if an installed skill has a newer version"
|
|
9895
|
+
},
|
|
9896
|
+
list: {
|
|
9897
|
+
usage: "okx skill list",
|
|
9898
|
+
description: "List all locally installed skills"
|
|
9899
|
+
}
|
|
9900
|
+
}
|
|
9901
|
+
},
|
|
10095
9902
|
upgrade: {
|
|
10096
9903
|
description: "Upgrade okx CLI and MCP server to the latest stable version",
|
|
10097
9904
|
usage: "okx upgrade [--check] [--beta] [--force] [--json]"
|
|
@@ -10387,6 +10194,7 @@ var CLI_OPTIONS = {
|
|
|
10387
10194
|
categories: { type: "string" },
|
|
10388
10195
|
dir: { type: "string" },
|
|
10389
10196
|
page: { type: "string" },
|
|
10197
|
+
format: { type: "string" },
|
|
10390
10198
|
// diagnostics — cli/mcp/all/output are diagnose-specific; verbose is shared
|
|
10391
10199
|
verbose: { type: "boolean", default: false },
|
|
10392
10200
|
mcp: { type: "boolean", default: false },
|
|
@@ -10426,7 +10234,7 @@ function getData(result) {
|
|
|
10426
10234
|
return result.data;
|
|
10427
10235
|
}
|
|
10428
10236
|
async function cmdMarketInstruments(run, opts) {
|
|
10429
|
-
const result = await run("market_get_instruments", { instType: opts.instType, instId: opts.instId });
|
|
10237
|
+
const result = await run("market_get_instruments", { instType: opts.instType, instId: opts.instId, demo: opts.demo ?? false });
|
|
10430
10238
|
const items = getData(result);
|
|
10431
10239
|
if (opts.json) return printJson(items);
|
|
10432
10240
|
printTable(
|
|
@@ -10441,7 +10249,7 @@ async function cmdMarketInstruments(run, opts) {
|
|
|
10441
10249
|
);
|
|
10442
10250
|
}
|
|
10443
10251
|
async function cmdMarketFundingRate(run, instId, opts) {
|
|
10444
|
-
const result = await run("market_get_funding_rate", { instId, history: opts.history, limit: opts.limit });
|
|
10252
|
+
const result = await run("market_get_funding_rate", { instId, history: opts.history, limit: opts.limit, demo: opts.demo ?? false });
|
|
10445
10253
|
const items = getData(result);
|
|
10446
10254
|
if (opts.json) return printJson(items);
|
|
10447
10255
|
if (opts.history) {
|
|
@@ -10469,7 +10277,7 @@ async function cmdMarketFundingRate(run, instId, opts) {
|
|
|
10469
10277
|
}
|
|
10470
10278
|
}
|
|
10471
10279
|
async function cmdMarketMarkPrice(run, opts) {
|
|
10472
|
-
const result = await run("market_get_mark_price", { instType: opts.instType, instId: opts.instId });
|
|
10280
|
+
const result = await run("market_get_mark_price", { instType: opts.instType, instId: opts.instId, demo: opts.demo ?? false });
|
|
10473
10281
|
const items = getData(result);
|
|
10474
10282
|
if (opts.json) return printJson(items);
|
|
10475
10283
|
printTable(
|
|
@@ -10482,7 +10290,7 @@ async function cmdMarketMarkPrice(run, opts) {
|
|
|
10482
10290
|
);
|
|
10483
10291
|
}
|
|
10484
10292
|
async function cmdMarketTrades(run, instId, opts) {
|
|
10485
|
-
const result = await run("market_get_trades", { instId, limit: opts.limit });
|
|
10293
|
+
const result = await run("market_get_trades", { instId, limit: opts.limit, demo: opts.demo ?? false });
|
|
10486
10294
|
const items = getData(result);
|
|
10487
10295
|
if (opts.json) return printJson(items);
|
|
10488
10296
|
printTable(
|
|
@@ -10496,7 +10304,7 @@ async function cmdMarketTrades(run, instId, opts) {
|
|
|
10496
10304
|
);
|
|
10497
10305
|
}
|
|
10498
10306
|
async function cmdMarketIndexTicker(run, opts) {
|
|
10499
|
-
const result = await run("market_get_index_ticker", { instId: opts.instId, quoteCcy: opts.quoteCcy });
|
|
10307
|
+
const result = await run("market_get_index_ticker", { instId: opts.instId, quoteCcy: opts.quoteCcy, demo: opts.demo ?? false });
|
|
10500
10308
|
const items = getData(result);
|
|
10501
10309
|
if (opts.json) return printJson(items);
|
|
10502
10310
|
printTable(
|
|
@@ -10510,7 +10318,7 @@ async function cmdMarketIndexTicker(run, opts) {
|
|
|
10510
10318
|
);
|
|
10511
10319
|
}
|
|
10512
10320
|
async function cmdMarketIndexCandles(run, instId, opts) {
|
|
10513
|
-
const result = await run("market_get_index_candles", { instId, bar: opts.bar, limit: opts.limit, history: opts.history });
|
|
10321
|
+
const result = await run("market_get_index_candles", { instId, bar: opts.bar, limit: opts.limit, history: opts.history, demo: opts.demo ?? false });
|
|
10514
10322
|
const candles = getData(result);
|
|
10515
10323
|
if (opts.json) return printJson(candles);
|
|
10516
10324
|
printTable(
|
|
@@ -10523,8 +10331,8 @@ async function cmdMarketIndexCandles(run, instId, opts) {
|
|
|
10523
10331
|
}))
|
|
10524
10332
|
);
|
|
10525
10333
|
}
|
|
10526
|
-
async function cmdMarketPriceLimit(run, instId, json) {
|
|
10527
|
-
const result = await run("market_get_price_limit", { instId });
|
|
10334
|
+
async function cmdMarketPriceLimit(run, instId, json, demo) {
|
|
10335
|
+
const result = await run("market_get_price_limit", { instId, demo: demo ?? false });
|
|
10528
10336
|
const items = getData(result);
|
|
10529
10337
|
if (json) return printJson(items);
|
|
10530
10338
|
const r = items?.[0];
|
|
@@ -10540,7 +10348,7 @@ async function cmdMarketPriceLimit(run, instId, json) {
|
|
|
10540
10348
|
});
|
|
10541
10349
|
}
|
|
10542
10350
|
async function cmdMarketOpenInterest(run, opts) {
|
|
10543
|
-
const result = await run("market_get_open_interest", { instType: opts.instType, instId: opts.instId });
|
|
10351
|
+
const result = await run("market_get_open_interest", { instType: opts.instType, instId: opts.instId, demo: opts.demo ?? false });
|
|
10544
10352
|
const items = getData(result);
|
|
10545
10353
|
if (opts.json) return printJson(items);
|
|
10546
10354
|
printTable(
|
|
@@ -10552,8 +10360,8 @@ async function cmdMarketOpenInterest(run, opts) {
|
|
|
10552
10360
|
}))
|
|
10553
10361
|
);
|
|
10554
10362
|
}
|
|
10555
|
-
async function cmdMarketTicker(run, instId, json) {
|
|
10556
|
-
const result = await run("market_get_ticker", { instId });
|
|
10363
|
+
async function cmdMarketTicker(run, instId, json, demo) {
|
|
10364
|
+
const result = await run("market_get_ticker", { instId, demo: demo ?? false });
|
|
10557
10365
|
const items = getData(result);
|
|
10558
10366
|
if (json) return printJson(items);
|
|
10559
10367
|
if (!items?.length) {
|
|
@@ -10576,8 +10384,8 @@ async function cmdMarketTicker(run, instId, json) {
|
|
|
10576
10384
|
time: new Date(Number(t["ts"])).toLocaleString()
|
|
10577
10385
|
});
|
|
10578
10386
|
}
|
|
10579
|
-
async function cmdMarketTickers(run, instType, json) {
|
|
10580
|
-
const result = await run("market_get_tickers", { instType });
|
|
10387
|
+
async function cmdMarketTickers(run, instType, json, demo) {
|
|
10388
|
+
const result = await run("market_get_tickers", { instType, demo: demo ?? false });
|
|
10581
10389
|
const items = getData(result);
|
|
10582
10390
|
if (json) return printJson(items);
|
|
10583
10391
|
printTable(
|
|
@@ -10590,8 +10398,8 @@ async function cmdMarketTickers(run, instType, json) {
|
|
|
10590
10398
|
}))
|
|
10591
10399
|
);
|
|
10592
10400
|
}
|
|
10593
|
-
async function cmdMarketOrderbook(run, instId, sz, json) {
|
|
10594
|
-
const result = await run("market_get_orderbook", { instId, sz });
|
|
10401
|
+
async function cmdMarketOrderbook(run, instId, sz, json, demo) {
|
|
10402
|
+
const result = await run("market_get_orderbook", { instId, sz, demo: demo ?? false });
|
|
10595
10403
|
const data = getData(result);
|
|
10596
10404
|
if (json) return printJson(data);
|
|
10597
10405
|
const book = data[0];
|
|
@@ -10608,7 +10416,7 @@ async function cmdMarketOrderbook(run, instId, sz, json) {
|
|
|
10608
10416
|
for (const [p, s] of bids) outputLine(` ${p.padStart(16)} ${s}`);
|
|
10609
10417
|
}
|
|
10610
10418
|
async function cmdMarketCandles(run, instId, opts) {
|
|
10611
|
-
const result = await run("market_get_candles", { instId, bar: opts.bar, limit: opts.limit, after: opts.after, before: opts.before });
|
|
10419
|
+
const result = await run("market_get_candles", { instId, bar: opts.bar, limit: opts.limit, after: opts.after, before: opts.before, demo: opts.demo ?? false });
|
|
10612
10420
|
const candles = getData(result);
|
|
10613
10421
|
if (opts.json) return printJson(candles);
|
|
10614
10422
|
printTable(
|
|
@@ -10678,7 +10486,8 @@ async function cmdMarketInstrumentsByCategory(run, opts) {
|
|
|
10678
10486
|
const result = await run("market_get_instruments_by_category", {
|
|
10679
10487
|
instCategory: opts.instCategory,
|
|
10680
10488
|
instType: opts.instType,
|
|
10681
|
-
instId: opts.instId
|
|
10489
|
+
instId: opts.instId,
|
|
10490
|
+
demo: opts.demo ?? false
|
|
10682
10491
|
});
|
|
10683
10492
|
const items = getData(result);
|
|
10684
10493
|
if (opts.json) return printJson(items);
|
|
@@ -10706,7 +10515,7 @@ async function cmdMarketInstrumentsByCategory(run, opts) {
|
|
|
10706
10515
|
);
|
|
10707
10516
|
}
|
|
10708
10517
|
async function cmdMarketStockTokens(run, opts) {
|
|
10709
|
-
const result = await run("market_get_stock_tokens", { instType: opts.instType, instId: opts.instId });
|
|
10518
|
+
const result = await run("market_get_stock_tokens", { instType: opts.instType, instId: opts.instId, demo: opts.demo ?? false });
|
|
10710
10519
|
const items = getData(result);
|
|
10711
10520
|
if (opts.json) return printJson(items);
|
|
10712
10521
|
printTable(
|
|
@@ -13216,13 +13025,13 @@ async function cmdDcdQuoteAndBuy(run, opts) {
|
|
|
13216
13025
|
}
|
|
13217
13026
|
|
|
13218
13027
|
// src/commands/skill.ts
|
|
13219
|
-
import { tmpdir, homedir as
|
|
13220
|
-
import { join as
|
|
13221
|
-
import { mkdirSync as
|
|
13028
|
+
import { tmpdir, homedir as homedir7 } from "os";
|
|
13029
|
+
import { join as join9, dirname as dirname6 } from "path";
|
|
13030
|
+
import { mkdirSync as mkdirSync8, rmSync, existsSync as existsSync7, copyFileSync as copyFileSync2 } from "fs";
|
|
13222
13031
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
13223
13032
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
13224
13033
|
function resolveNpx() {
|
|
13225
|
-
const sibling =
|
|
13034
|
+
const sibling = join9(dirname6(process.execPath), "npx");
|
|
13226
13035
|
if (existsSync7(sibling)) return sibling;
|
|
13227
13036
|
return "npx";
|
|
13228
13037
|
}
|
|
@@ -13276,13 +13085,13 @@ async function cmdSkillCategories(run, json) {
|
|
|
13276
13085
|
outputLine("");
|
|
13277
13086
|
}
|
|
13278
13087
|
async function cmdSkillAdd(name, config, json) {
|
|
13279
|
-
const tmpBase =
|
|
13280
|
-
|
|
13088
|
+
const tmpBase = join9(tmpdir(), `okx-skill-${randomUUID2()}`);
|
|
13089
|
+
mkdirSync8(tmpBase, { recursive: true });
|
|
13281
13090
|
try {
|
|
13282
13091
|
outputLine(`Downloading ${name}...`);
|
|
13283
13092
|
const client = new OkxRestClient(config);
|
|
13284
13093
|
const zipPath = await downloadSkillZip(client, name, tmpBase);
|
|
13285
|
-
const contentDir = await extractSkillZip(zipPath,
|
|
13094
|
+
const contentDir = await extractSkillZip(zipPath, join9(tmpBase, "content"));
|
|
13286
13095
|
const meta = readMetaJson(contentDir);
|
|
13287
13096
|
validateSkillMdExists(contentDir);
|
|
13288
13097
|
outputLine("Installing to detected agents...");
|
|
@@ -13292,7 +13101,7 @@ async function cmdSkillAdd(name, config, json) {
|
|
|
13292
13101
|
timeout: 6e4
|
|
13293
13102
|
});
|
|
13294
13103
|
} catch (e) {
|
|
13295
|
-
const savedZip =
|
|
13104
|
+
const savedZip = join9(process.cwd(), `${name}.zip`);
|
|
13296
13105
|
try {
|
|
13297
13106
|
copyFileSync2(zipPath, savedZip);
|
|
13298
13107
|
} catch {
|
|
@@ -13307,14 +13116,14 @@ async function cmdSkillAdd(name, config, json) {
|
|
|
13307
13116
|
rmSync(tmpBase, { recursive: true, force: true });
|
|
13308
13117
|
}
|
|
13309
13118
|
}
|
|
13310
|
-
async function cmdSkillDownload(name, targetDir, config, json) {
|
|
13119
|
+
async function cmdSkillDownload(name, targetDir, config, json, format = "zip") {
|
|
13311
13120
|
outputLine(`Downloading ${name}...`);
|
|
13312
13121
|
const client = new OkxRestClient(config);
|
|
13313
|
-
const filePath = await downloadSkillZip(client, name, targetDir);
|
|
13122
|
+
const filePath = await downloadSkillZip(client, name, targetDir, format);
|
|
13314
13123
|
if (json) {
|
|
13315
13124
|
outputLine(JSON.stringify({ name, filePath }, null, 2));
|
|
13316
13125
|
} else {
|
|
13317
|
-
outputLine(`\u2713 Downloaded ${name}
|
|
13126
|
+
outputLine(`\u2713 Downloaded ${name}.${format}`);
|
|
13318
13127
|
outputLine(` Path: ${filePath}`);
|
|
13319
13128
|
}
|
|
13320
13129
|
}
|
|
@@ -13331,7 +13140,7 @@ function cmdSkillRemove(name, json) {
|
|
|
13331
13140
|
timeout: 6e4
|
|
13332
13141
|
});
|
|
13333
13142
|
} catch {
|
|
13334
|
-
const agentsPath =
|
|
13143
|
+
const agentsPath = join9(homedir7(), ".agents", "skills", name);
|
|
13335
13144
|
try {
|
|
13336
13145
|
rmSync(agentsPath, { recursive: true, force: true });
|
|
13337
13146
|
} catch {
|
|
@@ -13407,7 +13216,7 @@ function printSkillInstallResult(meta, json) {
|
|
|
13407
13216
|
// src/index.ts
|
|
13408
13217
|
var _require3 = createRequire3(import.meta.url);
|
|
13409
13218
|
var CLI_VERSION2 = _require3("../package.json").version;
|
|
13410
|
-
var GIT_HASH2 = true ? "
|
|
13219
|
+
var GIT_HASH2 = true ? "6d4d559" : "dev";
|
|
13411
13220
|
function handleConfigCommand(action, rest, json, lang, force) {
|
|
13412
13221
|
if (action === "init") return cmdConfigInit(lang === "zh" ? "zh" : "en");
|
|
13413
13222
|
if (action === "show") return cmdConfigShow(json);
|
|
@@ -13437,25 +13246,26 @@ function handleSetupCommand(v) {
|
|
|
13437
13246
|
});
|
|
13438
13247
|
}
|
|
13439
13248
|
function handleMarketPublicCommand(run, action, rest, v, json) {
|
|
13440
|
-
if (action === "ticker") return cmdMarketTicker(run, rest[0], json);
|
|
13441
|
-
if (action === "tickers") return cmdMarketTickers(run, rest[0], json);
|
|
13249
|
+
if (action === "ticker") return cmdMarketTicker(run, rest[0], json, v.demo);
|
|
13250
|
+
if (action === "tickers") return cmdMarketTickers(run, rest[0], json, v.demo);
|
|
13442
13251
|
if (action === "instruments")
|
|
13443
|
-
return cmdMarketInstruments(run, { instType: v.instType, instId: v.instId, json });
|
|
13252
|
+
return cmdMarketInstruments(run, { instType: v.instType, instId: v.instId, json, demo: v.demo });
|
|
13444
13253
|
if (action === "mark-price")
|
|
13445
|
-
return cmdMarketMarkPrice(run, { instType: v.instType, instId: v.instId, json });
|
|
13254
|
+
return cmdMarketMarkPrice(run, { instType: v.instType, instId: v.instId, json, demo: v.demo });
|
|
13446
13255
|
if (action === "index-ticker")
|
|
13447
|
-
return cmdMarketIndexTicker(run, { instId: v.instId, quoteCcy: v.quoteCcy, json });
|
|
13448
|
-
if (action === "price-limit") return cmdMarketPriceLimit(run, rest[0], json);
|
|
13256
|
+
return cmdMarketIndexTicker(run, { instId: v.instId, quoteCcy: v.quoteCcy, json, demo: v.demo });
|
|
13257
|
+
if (action === "price-limit") return cmdMarketPriceLimit(run, rest[0], json, v.demo);
|
|
13449
13258
|
if (action === "open-interest")
|
|
13450
|
-
return cmdMarketOpenInterest(run, { instType: v.instType, instId: v.instId, json });
|
|
13259
|
+
return cmdMarketOpenInterest(run, { instType: v.instType, instId: v.instId, json, demo: v.demo });
|
|
13451
13260
|
if (action === "stock-tokens")
|
|
13452
|
-
return cmdMarketStockTokens(run, { instType: v.instType, instId: v.instId, json });
|
|
13261
|
+
return cmdMarketStockTokens(run, { instType: v.instType, instId: v.instId, json, demo: v.demo });
|
|
13453
13262
|
if (action === "instruments-by-category")
|
|
13454
13263
|
return cmdMarketInstrumentsByCategory(run, {
|
|
13455
13264
|
instCategory: v.instCategory,
|
|
13456
13265
|
instType: v.instType,
|
|
13457
13266
|
instId: v.instId,
|
|
13458
|
-
json
|
|
13267
|
+
json,
|
|
13268
|
+
demo: v.demo
|
|
13459
13269
|
});
|
|
13460
13270
|
if (action === "indicator") return handleIndicatorAction(run, rest, v, json);
|
|
13461
13271
|
}
|
|
@@ -13475,15 +13285,15 @@ function handleIndicatorAction(run, rest, v, json) {
|
|
|
13475
13285
|
function handleMarketDataCommand(run, action, rest, v, json) {
|
|
13476
13286
|
const limit = v.limit !== void 0 ? Number(v.limit) : void 0;
|
|
13477
13287
|
if (action === "orderbook")
|
|
13478
|
-
return cmdMarketOrderbook(run, rest[0], v.sz !== void 0 ? Number(v.sz) : void 0, json);
|
|
13288
|
+
return cmdMarketOrderbook(run, rest[0], v.sz !== void 0 ? Number(v.sz) : void 0, json, v.demo);
|
|
13479
13289
|
if (action === "candles")
|
|
13480
|
-
return cmdMarketCandles(run, rest[0], { bar: v.bar, limit, after: v.after, before: v.before, json });
|
|
13290
|
+
return cmdMarketCandles(run, rest[0], { bar: v.bar, limit, after: v.after, before: v.before, json, demo: v.demo });
|
|
13481
13291
|
if (action === "funding-rate")
|
|
13482
|
-
return cmdMarketFundingRate(run, rest[0], { history: v.history ?? false, limit, json });
|
|
13292
|
+
return cmdMarketFundingRate(run, rest[0], { history: v.history ?? false, limit, json, demo: v.demo });
|
|
13483
13293
|
if (action === "trades")
|
|
13484
|
-
return cmdMarketTrades(run, rest[0], { limit, json });
|
|
13294
|
+
return cmdMarketTrades(run, rest[0], { limit, json, demo: v.demo });
|
|
13485
13295
|
if (action === "index-candles")
|
|
13486
|
-
return cmdMarketIndexCandles(run, rest[0], { bar: v.bar, limit, history: v.history ?? false, json });
|
|
13296
|
+
return cmdMarketIndexCandles(run, rest[0], { bar: v.bar, limit, history: v.history ?? false, json, demo: v.demo });
|
|
13487
13297
|
}
|
|
13488
13298
|
function handleMarketCommand(run, action, rest, v, json) {
|
|
13489
13299
|
return handleMarketPublicCommand(run, action, rest, v, json) ?? handleMarketDataCommand(run, action, rest, v, json);
|
|
@@ -14192,8 +14002,9 @@ function handleSkillAdd(rest, config, json) {
|
|
|
14192
14002
|
if (n) return cmdSkillAdd(n, config, json);
|
|
14193
14003
|
}
|
|
14194
14004
|
function handleSkillDownload(rest, v, config, json) {
|
|
14195
|
-
const n = requireSkillName(rest, "Usage: okx skill download <name> [--dir <path>]");
|
|
14196
|
-
|
|
14005
|
+
const n = requireSkillName(rest, "Usage: okx skill download <name> [--dir <path>] [--format zip|skill]");
|
|
14006
|
+
const format = v.format === "skill" ? "skill" : "zip";
|
|
14007
|
+
if (n) return cmdSkillDownload(n, v.dir ?? process.cwd(), config, json, format);
|
|
14197
14008
|
}
|
|
14198
14009
|
function handleSkillRemove(rest, json) {
|
|
14199
14010
|
const n = requireSkillName(rest, "Usage: okx skill remove <name>");
|
|
@@ -14228,7 +14039,7 @@ function printHelpForLevel(positionals) {
|
|
|
14228
14039
|
else if (!subgroup) printHelp(module);
|
|
14229
14040
|
else printHelp(module, subgroup);
|
|
14230
14041
|
}
|
|
14231
|
-
function wrapRunnerWithLogger(baseRunner, logger) {
|
|
14042
|
+
function wrapRunnerWithLogger(baseRunner, logger, verbose = false) {
|
|
14232
14043
|
const writeToolNames = new Set(allToolSpecs().filter((t) => t.isWrite).map((t) => t.name));
|
|
14233
14044
|
return async (toolName, args) => {
|
|
14234
14045
|
const startTime = Date.now();
|
|
@@ -14237,7 +14048,11 @@ function wrapRunnerWithLogger(baseRunner, logger) {
|
|
|
14237
14048
|
if (writeToolNames.has(toolName)) {
|
|
14238
14049
|
markFailedIfSCodeError(result.data);
|
|
14239
14050
|
}
|
|
14240
|
-
|
|
14051
|
+
const elapsed = Date.now() - startTime;
|
|
14052
|
+
logger.log("info", toolName, args, { status: "ok" }, elapsed);
|
|
14053
|
+
if (verbose) {
|
|
14054
|
+
logger.log("debug", toolName, args, result, elapsed);
|
|
14055
|
+
}
|
|
14241
14056
|
return result;
|
|
14242
14057
|
} catch (error) {
|
|
14243
14058
|
logger.log("error", toolName, args, error, Date.now() - startTime);
|
|
@@ -14280,8 +14095,8 @@ async function main() {
|
|
|
14280
14095
|
setJsonEnvEnabled(v.env ?? false);
|
|
14281
14096
|
const client = new OkxRestClient(config);
|
|
14282
14097
|
const baseRunner = createToolRunner(client, config);
|
|
14283
|
-
const logger = new TradeLogger("info");
|
|
14284
|
-
const run = wrapRunnerWithLogger(baseRunner, logger);
|
|
14098
|
+
const logger = new TradeLogger(v.verbose ? "debug" : "info");
|
|
14099
|
+
const run = wrapRunnerWithLogger(baseRunner, logger, v.verbose ?? false);
|
|
14285
14100
|
const moduleHandlers = {
|
|
14286
14101
|
market: () => handleMarketCommand(run, action, rest, v, json),
|
|
14287
14102
|
account: () => handleAccountCommand(run, action, rest, v, json),
|