@okx_ai/okx-trade-cli 1.2.9-beta.1 → 1.2.9-beta.3
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 +188 -216
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/scripts/postinstall.js +1 -8
- package/LICENSE +0 -21
- package/scripts/postinstall-download.js +0 -152
package/dist/index.js
CHANGED
|
@@ -4,30 +4,25 @@
|
|
|
4
4
|
import { createRequire as createRequire3 } from "module";
|
|
5
5
|
|
|
6
6
|
// ../core/dist/index.js
|
|
7
|
-
import {
|
|
8
|
-
import { unlink } from "fs/promises";
|
|
9
|
-
import { execFile } from "child_process";
|
|
10
|
-
import { access, constants } from "fs/promises";
|
|
11
|
-
import { homedir } from "os";
|
|
12
|
-
import { join } from "path";
|
|
7
|
+
import { ProxyAgent } from "undici";
|
|
13
8
|
import { createHmac } from "crypto";
|
|
14
9
|
import fs from "fs";
|
|
15
10
|
import path from "path";
|
|
16
11
|
import os from "os";
|
|
17
12
|
import { writeFileSync, renameSync, unlinkSync, mkdirSync } from "fs";
|
|
18
|
-
import { join
|
|
13
|
+
import { join, resolve, basename, sep } from "path";
|
|
19
14
|
import { randomUUID } from "crypto";
|
|
20
15
|
import yauzl from "yauzl";
|
|
21
16
|
import { createWriteStream, mkdirSync as mkdirSync2 } from "fs";
|
|
22
17
|
import { resolve as resolve2, dirname } from "path";
|
|
23
18
|
import { readFileSync, existsSync } from "fs";
|
|
24
|
-
import { join as
|
|
19
|
+
import { join as join2 } from "path";
|
|
25
20
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, existsSync as existsSync2 } from "fs";
|
|
26
|
-
import { join as
|
|
27
|
-
import { homedir
|
|
21
|
+
import { join as join3, dirname as dirname2 } from "path";
|
|
22
|
+
import { homedir } from "os";
|
|
28
23
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync3 } from "fs";
|
|
29
|
-
import { join as
|
|
30
|
-
import { homedir as
|
|
24
|
+
import { join as join4, dirname as dirname3 } from "path";
|
|
25
|
+
import { homedir as homedir2 } from "os";
|
|
31
26
|
|
|
32
27
|
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/error.js
|
|
33
28
|
function getLineColFromPtr(string, ptr) {
|
|
@@ -857,66 +852,12 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
|
857
852
|
|
|
858
853
|
// ../core/dist/index.js
|
|
859
854
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync4 } from "fs";
|
|
860
|
-
import { join as
|
|
861
|
-
import { homedir as
|
|
855
|
+
import { join as join5 } from "path";
|
|
856
|
+
import { homedir as homedir3 } from "os";
|
|
862
857
|
import * as fs3 from "fs";
|
|
863
858
|
import * as path3 from "path";
|
|
864
859
|
import * as os3 from "os";
|
|
865
860
|
import { execFileSync } from "child_process";
|
|
866
|
-
var EXEC_TIMEOUT_MS = 15e3;
|
|
867
|
-
var DOH_BIN_DIR = join(homedir(), ".okx", "bin");
|
|
868
|
-
var DOH_CACHE_FILE = join(homedir(), ".okx", ".doh-cache.json");
|
|
869
|
-
function getDohBinaryPath() {
|
|
870
|
-
if (process.env.OKX_DOH_BINARY_PATH) {
|
|
871
|
-
return process.env.OKX_DOH_BINARY_PATH;
|
|
872
|
-
}
|
|
873
|
-
const ext = process.platform === "win32" ? ".exe" : "";
|
|
874
|
-
return join(DOH_BIN_DIR, `okx-doh-resolver${ext}`);
|
|
875
|
-
}
|
|
876
|
-
function getDohCachePath() {
|
|
877
|
-
return DOH_CACHE_FILE;
|
|
878
|
-
}
|
|
879
|
-
async function dohBinaryExists() {
|
|
880
|
-
try {
|
|
881
|
-
const flag = process.platform === "win32" ? constants.F_OK : constants.X_OK;
|
|
882
|
-
await access(getDohBinaryPath(), flag);
|
|
883
|
-
return true;
|
|
884
|
-
} catch {
|
|
885
|
-
return false;
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
function execDohBinary(domain) {
|
|
889
|
-
const binPath = getDohBinaryPath();
|
|
890
|
-
return new Promise((resolve3) => {
|
|
891
|
-
execFile(
|
|
892
|
-
binPath,
|
|
893
|
-
["--domain", domain],
|
|
894
|
-
{ timeout: EXEC_TIMEOUT_MS, encoding: "utf-8" },
|
|
895
|
-
(error, stdout) => {
|
|
896
|
-
if (error) {
|
|
897
|
-
resolve3(null);
|
|
898
|
-
return;
|
|
899
|
-
}
|
|
900
|
-
try {
|
|
901
|
-
const result = JSON.parse(stdout);
|
|
902
|
-
if (result.code === 0 && result.data) {
|
|
903
|
-
resolve3(result.data);
|
|
904
|
-
} else {
|
|
905
|
-
resolve3(null);
|
|
906
|
-
}
|
|
907
|
-
} catch {
|
|
908
|
-
resolve3(null);
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
);
|
|
912
|
-
});
|
|
913
|
-
}
|
|
914
|
-
async function resolveDoh(domain) {
|
|
915
|
-
if (!await dohBinaryExists()) {
|
|
916
|
-
return null;
|
|
917
|
-
}
|
|
918
|
-
return execDohBinary(domain);
|
|
919
|
-
}
|
|
920
861
|
function getNow() {
|
|
921
862
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
922
863
|
}
|
|
@@ -1135,80 +1076,12 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1135
1076
|
config;
|
|
1136
1077
|
rateLimiter;
|
|
1137
1078
|
dispatcher;
|
|
1138
|
-
|
|
1139
|
-
dohResolverFn;
|
|
1140
|
-
dohResolved = false;
|
|
1141
|
-
dohNode = null;
|
|
1142
|
-
dohAgent = null;
|
|
1143
|
-
dohBaseUrl = null;
|
|
1144
|
-
/**
|
|
1145
|
-
* @param config - OKX API client configuration
|
|
1146
|
-
* @param options - Optional overrides (e.g. custom DoH resolver for testing).
|
|
1147
|
-
* Pass `{ resolveDoh: null }` to disable DoH entirely.
|
|
1148
|
-
*/
|
|
1149
|
-
constructor(config, options) {
|
|
1079
|
+
constructor(config) {
|
|
1150
1080
|
this.config = config;
|
|
1151
1081
|
this.rateLimiter = new RateLimiter(3e4, config.verbose);
|
|
1152
1082
|
if (config.proxyUrl) {
|
|
1153
1083
|
this.dispatcher = new ProxyAgent(config.proxyUrl);
|
|
1154
1084
|
}
|
|
1155
|
-
this.dohResolverFn = options?.resolveDoh !== void 0 ? options.resolveDoh : resolveDoh;
|
|
1156
|
-
}
|
|
1157
|
-
/**
|
|
1158
|
-
* Lazily resolve the DoH proxy node on the first request.
|
|
1159
|
-
* Skipped entirely when the user has configured proxy_url or DoH is disabled.
|
|
1160
|
-
* On failure, silently falls back to direct connection.
|
|
1161
|
-
*/
|
|
1162
|
-
async ensureDoh() {
|
|
1163
|
-
if (this.dohResolved || this.dispatcher || !this.dohResolverFn) return;
|
|
1164
|
-
this.dohResolved = true;
|
|
1165
|
-
try {
|
|
1166
|
-
const { hostname, protocol } = new URL(this.config.baseUrl);
|
|
1167
|
-
const node = await this.dohResolverFn(hostname);
|
|
1168
|
-
if (!node) return;
|
|
1169
|
-
if (node.ip === hostname) {
|
|
1170
|
-
if (this.config.verbose) {
|
|
1171
|
-
vlog(`DoH: resolved ip matches hostname (${hostname}), using direct connection`);
|
|
1172
|
-
}
|
|
1173
|
-
return;
|
|
1174
|
-
}
|
|
1175
|
-
this.dohNode = node;
|
|
1176
|
-
this.dohBaseUrl = `${protocol}//${node.host}`;
|
|
1177
|
-
this.dohAgent = new Agent({
|
|
1178
|
-
connect: {
|
|
1179
|
-
lookup: (_hostname, options, callback) => {
|
|
1180
|
-
if (options?.all) {
|
|
1181
|
-
callback(null, [{ address: node.ip, family: 4 }]);
|
|
1182
|
-
} else {
|
|
1183
|
-
callback(null, node.ip, 4);
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
});
|
|
1188
|
-
if (this.config.verbose) {
|
|
1189
|
-
vlog(`DoH proxy active: ${hostname} \u2192 ${node.host} (${node.ip}), ttl=${node.ttl}s`);
|
|
1190
|
-
}
|
|
1191
|
-
} catch (err) {
|
|
1192
|
-
if (this.config.verbose) {
|
|
1193
|
-
const cause = err instanceof Error ? err.message : String(err);
|
|
1194
|
-
vlog(`DoH resolution failed, falling back to direct: ${cause}`);
|
|
1195
|
-
}
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
/**
|
|
1199
|
-
* Invalidate DoH state and delete the binary's cache file so the next
|
|
1200
|
-
* resolution performs a fresh lookup. Called on network-level failures
|
|
1201
|
-
* when a DoH proxy node was in use.
|
|
1202
|
-
*/
|
|
1203
|
-
async invalidateDoh() {
|
|
1204
|
-
this.dohNode = null;
|
|
1205
|
-
this.dohAgent = null;
|
|
1206
|
-
this.dohBaseUrl = null;
|
|
1207
|
-
this.dohResolved = false;
|
|
1208
|
-
try {
|
|
1209
|
-
await unlink(getDohCachePath());
|
|
1210
|
-
} catch {
|
|
1211
|
-
}
|
|
1212
1085
|
}
|
|
1213
1086
|
logRequest(method, url, auth) {
|
|
1214
1087
|
if (!this.config.verbose) return;
|
|
@@ -1379,18 +1252,13 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1379
1252
|
* Security: validates Content-Type and enforces maxBytes limit.
|
|
1380
1253
|
*/
|
|
1381
1254
|
async privatePostBinary(path42, body, opts) {
|
|
1382
|
-
await this.ensureDoh();
|
|
1383
1255
|
const maxBytes = opts?.maxBytes ?? _OkxRestClient.DEFAULT_MAX_BYTES;
|
|
1384
1256
|
const expectedCT = opts?.expectedContentType ?? "application/octet-stream";
|
|
1385
1257
|
const bodyJson = body ? JSON.stringify(body) : "";
|
|
1386
1258
|
const endpoint = `POST ${path42}`;
|
|
1387
|
-
|
|
1388
|
-
this.logRequest("POST", `${baseUrl}${path42}`, "private");
|
|
1259
|
+
this.logRequest("POST", `${this.config.baseUrl}${path42}`, "private");
|
|
1389
1260
|
const reqConfig = { method: "POST", path: path42, auth: "private" };
|
|
1390
1261
|
const headers = this.buildHeaders(reqConfig, path42, bodyJson, getNow());
|
|
1391
|
-
if (this.dohNode) {
|
|
1392
|
-
headers.set("User-Agent", "OKX/2.7.2");
|
|
1393
|
-
}
|
|
1394
1262
|
const t0 = Date.now();
|
|
1395
1263
|
const response = await this.fetchBinary(path42, endpoint, headers, bodyJson, t0);
|
|
1396
1264
|
const elapsed = Date.now() - t0;
|
|
@@ -1420,19 +1288,14 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1420
1288
|
/** Execute fetch for binary endpoint, wrapping network errors. */
|
|
1421
1289
|
async fetchBinary(path42, endpoint, headers, bodyJson, t0) {
|
|
1422
1290
|
try {
|
|
1423
|
-
const baseUrl = this.dohNode ? this.dohBaseUrl : this.config.baseUrl;
|
|
1424
1291
|
const fetchOptions = {
|
|
1425
1292
|
method: "POST",
|
|
1426
1293
|
headers,
|
|
1427
1294
|
body: bodyJson || void 0,
|
|
1428
1295
|
signal: AbortSignal.timeout(this.config.timeoutMs)
|
|
1429
1296
|
};
|
|
1430
|
-
if (this.dispatcher)
|
|
1431
|
-
|
|
1432
|
-
} else if (this.dohAgent) {
|
|
1433
|
-
fetchOptions.dispatcher = this.dohAgent;
|
|
1434
|
-
}
|
|
1435
|
-
return await fetch(`${baseUrl}${path42}`, fetchOptions);
|
|
1297
|
+
if (this.dispatcher) fetchOptions.dispatcher = this.dispatcher;
|
|
1298
|
+
return await fetch(`${this.config.baseUrl}${path42}`, fetchOptions);
|
|
1436
1299
|
} catch (error) {
|
|
1437
1300
|
if (this.config.verbose) {
|
|
1438
1301
|
vlog(`\u2717 NetworkError after ${Date.now() - t0}ms: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -1463,11 +1326,9 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1463
1326
|
// JSON request
|
|
1464
1327
|
// ---------------------------------------------------------------------------
|
|
1465
1328
|
async request(reqConfig) {
|
|
1466
|
-
await this.ensureDoh();
|
|
1467
1329
|
const queryString = buildQueryString(reqConfig.query);
|
|
1468
1330
|
const requestPath = queryString.length > 0 ? `${reqConfig.path}?${queryString}` : reqConfig.path;
|
|
1469
|
-
const
|
|
1470
|
-
const url = `${baseUrl}${requestPath}`;
|
|
1331
|
+
const url = `${this.config.baseUrl}${requestPath}`;
|
|
1471
1332
|
const bodyJson = reqConfig.body ? JSON.stringify(reqConfig.body) : "";
|
|
1472
1333
|
const timestamp = getNow();
|
|
1473
1334
|
this.logRequest(reqConfig.method, url, reqConfig.auth);
|
|
@@ -1475,9 +1336,6 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1475
1336
|
await this.rateLimiter.consume(reqConfig.rateLimit);
|
|
1476
1337
|
}
|
|
1477
1338
|
const headers = this.buildHeaders(reqConfig, requestPath, bodyJson, timestamp);
|
|
1478
|
-
if (this.dohNode) {
|
|
1479
|
-
headers.set("User-Agent", "OKX/2.7.2");
|
|
1480
|
-
}
|
|
1481
1339
|
const t0 = Date.now();
|
|
1482
1340
|
let response;
|
|
1483
1341
|
try {
|
|
@@ -1489,18 +1347,9 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1489
1347
|
};
|
|
1490
1348
|
if (this.dispatcher) {
|
|
1491
1349
|
fetchOptions.dispatcher = this.dispatcher;
|
|
1492
|
-
} else if (this.dohAgent) {
|
|
1493
|
-
fetchOptions.dispatcher = this.dohAgent;
|
|
1494
1350
|
}
|
|
1495
1351
|
response = await fetch(url, fetchOptions);
|
|
1496
1352
|
} catch (error) {
|
|
1497
|
-
if (this.dohNode) {
|
|
1498
|
-
if (this.config.verbose) {
|
|
1499
|
-
vlog(`DoH request failed, invalidating cache and retrying: ${error instanceof Error ? error.message : String(error)}`);
|
|
1500
|
-
}
|
|
1501
|
-
await this.invalidateDoh();
|
|
1502
|
-
return this.request(reqConfig);
|
|
1503
|
-
}
|
|
1504
1353
|
if (this.config.verbose) {
|
|
1505
1354
|
const elapsed2 = Date.now() - t0;
|
|
1506
1355
|
const cause = error instanceof Error ? error.message : String(error);
|
|
@@ -2342,6 +2191,59 @@ function registerAccountTools() {
|
|
|
2342
2191
|
}
|
|
2343
2192
|
];
|
|
2344
2193
|
}
|
|
2194
|
+
async function resolveQuoteCcySz(instId, sz, tgtCcy, instType, client) {
|
|
2195
|
+
if (tgtCcy !== "quote_ccy") {
|
|
2196
|
+
return { sz, tgtCcy, conversionNote: void 0 };
|
|
2197
|
+
}
|
|
2198
|
+
const [instrumentsRes, tickerRes] = await Promise.all([
|
|
2199
|
+
client.publicGet("/api/v5/public/instruments", {
|
|
2200
|
+
instType,
|
|
2201
|
+
instId
|
|
2202
|
+
}),
|
|
2203
|
+
client.publicGet("/api/v5/market/ticker", { instId })
|
|
2204
|
+
]);
|
|
2205
|
+
const instruments = Array.isArray(instrumentsRes.data) ? instrumentsRes.data : [];
|
|
2206
|
+
if (instruments.length === 0) {
|
|
2207
|
+
throw new Error(
|
|
2208
|
+
`Failed to fetch instrument info for ${instId}: empty instrument list. Cannot determine ctVal for quote_ccy conversion.`
|
|
2209
|
+
);
|
|
2210
|
+
}
|
|
2211
|
+
const ctValStr = String(instruments[0].ctVal ?? "");
|
|
2212
|
+
const ctVal = parseFloat(ctValStr);
|
|
2213
|
+
if (!isFinite(ctVal) || ctVal <= 0) {
|
|
2214
|
+
throw new Error(
|
|
2215
|
+
`Invalid ctVal "${ctValStr}" for ${instId}. ctVal must be a positive number for quote_ccy conversion.`
|
|
2216
|
+
);
|
|
2217
|
+
}
|
|
2218
|
+
const tickers = Array.isArray(tickerRes.data) ? tickerRes.data : [];
|
|
2219
|
+
if (tickers.length === 0) {
|
|
2220
|
+
throw new Error(
|
|
2221
|
+
`Failed to fetch ticker price for ${instId}: empty ticker response. Cannot determine last price for quote_ccy conversion.`
|
|
2222
|
+
);
|
|
2223
|
+
}
|
|
2224
|
+
const lastStr = String(tickers[0].last ?? "");
|
|
2225
|
+
const lastPx = parseFloat(lastStr);
|
|
2226
|
+
if (!isFinite(lastPx) || lastPx <= 0) {
|
|
2227
|
+
throw new Error(
|
|
2228
|
+
`Invalid last price "${lastStr}" for ${instId}. Last price must be a positive number for quote_ccy conversion.`
|
|
2229
|
+
);
|
|
2230
|
+
}
|
|
2231
|
+
const usdtAmount = parseFloat(sz);
|
|
2232
|
+
const contractValue = ctVal * lastPx;
|
|
2233
|
+
const contracts = Math.floor(usdtAmount / contractValue);
|
|
2234
|
+
if (contracts <= 0) {
|
|
2235
|
+
const minUsdt = contractValue.toFixed(2);
|
|
2236
|
+
throw new Error(
|
|
2237
|
+
`sz=${sz} USDT is too small to buy even 1 contract of ${instId}. Minimum amount required is at least ${minUsdt} USDT (ctVal=${ctValStr}, lastPx=${lastStr}, 1 contract = ${minUsdt} USDT).`
|
|
2238
|
+
);
|
|
2239
|
+
}
|
|
2240
|
+
const conversionNote = `Converting ${sz} USDT \u2192 ${contracts} contracts (ctVal=${ctValStr}, lastPx=${lastStr}, formula: floor(${sz} / (${ctValStr} \xD7 ${lastStr})) = ${contracts})`;
|
|
2241
|
+
return {
|
|
2242
|
+
sz: String(contracts),
|
|
2243
|
+
tgtCcy: void 0,
|
|
2244
|
+
conversionNote
|
|
2245
|
+
};
|
|
2246
|
+
}
|
|
2345
2247
|
function registerAlgoTradeTools() {
|
|
2346
2248
|
return [
|
|
2347
2249
|
{
|
|
@@ -2437,6 +2339,13 @@ function registerAlgoTradeTools() {
|
|
|
2437
2339
|
handler: async (rawArgs, context) => {
|
|
2438
2340
|
const args = asRecord(rawArgs);
|
|
2439
2341
|
const reduceOnly = args.reduceOnly;
|
|
2342
|
+
const resolved = await resolveQuoteCcySz(
|
|
2343
|
+
requireString(args, "instId"),
|
|
2344
|
+
requireString(args, "sz"),
|
|
2345
|
+
readString(args, "tgtCcy"),
|
|
2346
|
+
"SWAP",
|
|
2347
|
+
context.client
|
|
2348
|
+
);
|
|
2440
2349
|
const response = await context.client.privatePost(
|
|
2441
2350
|
"/api/v5/trade/order-algo",
|
|
2442
2351
|
compactObject({
|
|
@@ -2445,8 +2354,8 @@ function registerAlgoTradeTools() {
|
|
|
2445
2354
|
side: requireString(args, "side"),
|
|
2446
2355
|
posSide: readString(args, "posSide"),
|
|
2447
2356
|
ordType: requireString(args, "ordType"),
|
|
2448
|
-
sz:
|
|
2449
|
-
tgtCcy:
|
|
2357
|
+
sz: resolved.sz,
|
|
2358
|
+
tgtCcy: resolved.tgtCcy,
|
|
2450
2359
|
tpTriggerPx: readString(args, "tpTriggerPx"),
|
|
2451
2360
|
tpOrdPx: readString(args, "tpOrdPx"),
|
|
2452
2361
|
tpTriggerPxType: readString(args, "tpTriggerPxType"),
|
|
@@ -2462,7 +2371,11 @@ function registerAlgoTradeTools() {
|
|
|
2462
2371
|
}),
|
|
2463
2372
|
privateRateLimit("swap_place_algo_order", 20)
|
|
2464
2373
|
);
|
|
2465
|
-
|
|
2374
|
+
const result = normalizeResponse(response);
|
|
2375
|
+
if (resolved.conversionNote) {
|
|
2376
|
+
result._conversion = resolved.conversionNote;
|
|
2377
|
+
}
|
|
2378
|
+
return result;
|
|
2466
2379
|
}
|
|
2467
2380
|
},
|
|
2468
2381
|
{
|
|
@@ -2770,6 +2683,13 @@ function registerFuturesAlgoTools() {
|
|
|
2770
2683
|
handler: async (rawArgs, context) => {
|
|
2771
2684
|
const args = asRecord(rawArgs);
|
|
2772
2685
|
const reduceOnly = args.reduceOnly;
|
|
2686
|
+
const resolved = await resolveQuoteCcySz(
|
|
2687
|
+
requireString(args, "instId"),
|
|
2688
|
+
requireString(args, "sz"),
|
|
2689
|
+
readString(args, "tgtCcy"),
|
|
2690
|
+
"FUTURES",
|
|
2691
|
+
context.client
|
|
2692
|
+
);
|
|
2773
2693
|
const response = await context.client.privatePost(
|
|
2774
2694
|
"/api/v5/trade/order-algo",
|
|
2775
2695
|
compactObject({
|
|
@@ -2778,8 +2698,8 @@ function registerFuturesAlgoTools() {
|
|
|
2778
2698
|
side: requireString(args, "side"),
|
|
2779
2699
|
posSide: readString(args, "posSide"),
|
|
2780
2700
|
ordType: requireString(args, "ordType"),
|
|
2781
|
-
sz:
|
|
2782
|
-
tgtCcy:
|
|
2701
|
+
sz: resolved.sz,
|
|
2702
|
+
tgtCcy: resolved.tgtCcy,
|
|
2783
2703
|
tpTriggerPx: readString(args, "tpTriggerPx"),
|
|
2784
2704
|
tpOrdPx: readString(args, "tpOrdPx"),
|
|
2785
2705
|
tpTriggerPxType: readString(args, "tpTriggerPxType"),
|
|
@@ -2795,7 +2715,11 @@ function registerFuturesAlgoTools() {
|
|
|
2795
2715
|
}),
|
|
2796
2716
|
privateRateLimit("futures_place_algo_order", 20)
|
|
2797
2717
|
);
|
|
2798
|
-
|
|
2718
|
+
const result = normalizeResponse(response);
|
|
2719
|
+
if (resolved.conversionNote) {
|
|
2720
|
+
result._conversion = resolved.conversionNote;
|
|
2721
|
+
}
|
|
2722
|
+
return result;
|
|
2799
2723
|
}
|
|
2800
2724
|
},
|
|
2801
2725
|
{
|
|
@@ -3126,7 +3050,7 @@ function safeWriteFile(targetDir, fileName, data) {
|
|
|
3126
3050
|
throw new Error(`Invalid file name: "${fileName}"`);
|
|
3127
3051
|
}
|
|
3128
3052
|
const resolvedDir = resolve(targetDir);
|
|
3129
|
-
const filePath =
|
|
3053
|
+
const filePath = join(resolvedDir, safeName);
|
|
3130
3054
|
const resolvedPath = resolve(filePath);
|
|
3131
3055
|
if (!resolvedPath.startsWith(resolvedDir + sep)) {
|
|
3132
3056
|
throw new Error(`Path traversal detected: "${fileName}" resolves outside target directory`);
|
|
@@ -3242,7 +3166,7 @@ async function extractSkillZip(zipPath, targetDir, limits) {
|
|
|
3242
3166
|
});
|
|
3243
3167
|
}
|
|
3244
3168
|
function readMetaJson(contentDir) {
|
|
3245
|
-
const metaPath =
|
|
3169
|
+
const metaPath = join2(contentDir, "_meta.json");
|
|
3246
3170
|
if (!existsSync(metaPath)) {
|
|
3247
3171
|
throw new Error(`_meta.json not found in ${contentDir}. Invalid skill package.`);
|
|
3248
3172
|
}
|
|
@@ -3268,12 +3192,12 @@ function readMetaJson(contentDir) {
|
|
|
3268
3192
|
};
|
|
3269
3193
|
}
|
|
3270
3194
|
function validateSkillMdExists(contentDir) {
|
|
3271
|
-
const skillMdPath =
|
|
3195
|
+
const skillMdPath = join2(contentDir, "SKILL.md");
|
|
3272
3196
|
if (!existsSync(skillMdPath)) {
|
|
3273
3197
|
throw new Error(`SKILL.md not found in ${contentDir}. Invalid skill package.`);
|
|
3274
3198
|
}
|
|
3275
3199
|
}
|
|
3276
|
-
var DEFAULT_REGISTRY_PATH =
|
|
3200
|
+
var DEFAULT_REGISTRY_PATH = join3(homedir(), ".okx", "skills", "registry.json");
|
|
3277
3201
|
function readRegistry(registryPath = DEFAULT_REGISTRY_PATH) {
|
|
3278
3202
|
if (!existsSync2(registryPath)) {
|
|
3279
3203
|
return { version: 1, skills: {} };
|
|
@@ -3360,7 +3284,7 @@ function registerSkillsTools() {
|
|
|
3360
3284
|
{
|
|
3361
3285
|
name: "skills_download",
|
|
3362
3286
|
module: "skills",
|
|
3363
|
-
description: "Download a skill zip file 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:
|
|
3287
|
+
description: "Download a skill zip file 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 as a zip \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.",
|
|
3364
3288
|
inputSchema: {
|
|
3365
3289
|
type: "object",
|
|
3366
3290
|
properties: {
|
|
@@ -4508,7 +4432,7 @@ function registerDcdTools() {
|
|
|
4508
4432
|
{
|
|
4509
4433
|
name: "dcd_get_products",
|
|
4510
4434
|
module: "earn.dcd",
|
|
4511
|
-
description: "Get DCD products with yield and quota info.",
|
|
4435
|
+
description: "Get DCD products with yield and quota info. Yields in response are decimal fractions, not percentages.",
|
|
4512
4436
|
isWrite: false,
|
|
4513
4437
|
inputSchema: {
|
|
4514
4438
|
type: "object",
|
|
@@ -4562,7 +4486,7 @@ function registerDcdTools() {
|
|
|
4562
4486
|
{
|
|
4563
4487
|
name: "dcd_get_orders",
|
|
4564
4488
|
module: "earn.dcd",
|
|
4565
|
-
description: "Get DCD order history.",
|
|
4489
|
+
description: "Get DCD order history. Yields in response are decimal fractions, not percentages.",
|
|
4566
4490
|
isWrite: false,
|
|
4567
4491
|
inputSchema: {
|
|
4568
4492
|
type: "object",
|
|
@@ -4606,7 +4530,7 @@ function registerDcdTools() {
|
|
|
4606
4530
|
{
|
|
4607
4531
|
name: "dcd_subscribe",
|
|
4608
4532
|
module: "earn.dcd",
|
|
4609
|
-
description: "Subscribe to a DCD product: get quote and execute atomically. Confirm product, amount, and currency with user before calling. Optional minAnnualizedYield
|
|
4533
|
+
description: "Subscribe to a DCD product: get quote and execute atomically. Confirm product, amount, and currency with user before calling. Optional minAnnualizedYield rejects the order if quote yield falls below threshold. Returns order result with quote snapshot (minAnnualizedYield is in percent; response yields are decimal fractions).",
|
|
4610
4534
|
isWrite: true,
|
|
4611
4535
|
inputSchema: {
|
|
4612
4536
|
type: "object",
|
|
@@ -4645,13 +4569,23 @@ function registerDcdTools() {
|
|
|
4645
4569
|
});
|
|
4646
4570
|
}
|
|
4647
4571
|
if (minAnnualizedYield !== void 0) {
|
|
4648
|
-
const
|
|
4649
|
-
if (
|
|
4572
|
+
const rawYield = parseFloat(quote["annualizedYield"]);
|
|
4573
|
+
if (isNaN(rawYield)) {
|
|
4650
4574
|
throw new OkxApiError(
|
|
4651
|
-
|
|
4575
|
+
"Quote returned non-numeric annualizedYield, cannot verify minimum yield threshold.",
|
|
4576
|
+
{
|
|
4577
|
+
code: "INVALID_YIELD_VALUE",
|
|
4578
|
+
suggestion: "Order not placed. The quote did not include a valid annualizedYield. Retry or pick a different product."
|
|
4579
|
+
}
|
|
4580
|
+
);
|
|
4581
|
+
}
|
|
4582
|
+
const actualYieldPct = rawYield * 100;
|
|
4583
|
+
if (actualYieldPct < minAnnualizedYield) {
|
|
4584
|
+
throw new OkxApiError(
|
|
4585
|
+
`Quote yield ${actualYieldPct.toFixed(2)}% is below the minimum threshold of ${minAnnualizedYield}%.`,
|
|
4652
4586
|
{
|
|
4653
4587
|
code: "YIELD_BELOW_MIN",
|
|
4654
|
-
suggestion: `Order not placed. Actual: ${
|
|
4588
|
+
suggestion: `Order not placed. Actual: ${actualYieldPct.toFixed(2)}%, required: >= ${minAnnualizedYield}%. Try a different product or lower your minimum yield.`
|
|
4655
4589
|
}
|
|
4656
4590
|
);
|
|
4657
4591
|
}
|
|
@@ -4881,6 +4815,13 @@ function buildContractTradeTools(cfg) {
|
|
|
4881
4815
|
const args = asRecord(rawArgs);
|
|
4882
4816
|
const reduceOnly = args.reduceOnly;
|
|
4883
4817
|
const attachAlgoOrds = buildAttachAlgoOrds(args);
|
|
4818
|
+
const resolved = await resolveQuoteCcySz(
|
|
4819
|
+
requireString(args, "instId"),
|
|
4820
|
+
requireString(args, "sz"),
|
|
4821
|
+
readString(args, "tgtCcy"),
|
|
4822
|
+
defaultType,
|
|
4823
|
+
context.client
|
|
4824
|
+
);
|
|
4884
4825
|
const response = await context.client.privatePost(
|
|
4885
4826
|
"/api/v5/trade/order",
|
|
4886
4827
|
compactObject({
|
|
@@ -4889,8 +4830,8 @@ function buildContractTradeTools(cfg) {
|
|
|
4889
4830
|
side: requireString(args, "side"),
|
|
4890
4831
|
posSide: readString(args, "posSide"),
|
|
4891
4832
|
ordType: requireString(args, "ordType"),
|
|
4892
|
-
sz:
|
|
4893
|
-
tgtCcy:
|
|
4833
|
+
sz: resolved.sz,
|
|
4834
|
+
tgtCcy: resolved.tgtCcy,
|
|
4894
4835
|
px: readString(args, "px"),
|
|
4895
4836
|
reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
|
|
4896
4837
|
clOrdId: readString(args, "clOrdId"),
|
|
@@ -4899,7 +4840,11 @@ function buildContractTradeTools(cfg) {
|
|
|
4899
4840
|
}),
|
|
4900
4841
|
privateRateLimit(n("place_order"), 60)
|
|
4901
4842
|
);
|
|
4902
|
-
|
|
4843
|
+
const result = normalizeResponse(response);
|
|
4844
|
+
if (resolved.conversionNote) {
|
|
4845
|
+
result._conversion = resolved.conversionNote;
|
|
4846
|
+
}
|
|
4847
|
+
return result;
|
|
4903
4848
|
}
|
|
4904
4849
|
},
|
|
4905
4850
|
// ── cancel_order ─────────────────────────────────────────────────────────
|
|
@@ -5974,7 +5919,7 @@ function registerOptionAlgoTools() {
|
|
|
5974
5919
|
tgtCcy: {
|
|
5975
5920
|
type: "string",
|
|
5976
5921
|
enum: ["base_ccy", "quote_ccy"],
|
|
5977
|
-
description: "Size unit. base_ccy(default): sz in contracts, quote_ccy: sz in USDT (
|
|
5922
|
+
description: "Size unit. base_ccy(default): sz in contracts, quote_ccy: sz in USDT (auto-converted to contracts)"
|
|
5978
5923
|
},
|
|
5979
5924
|
reduceOnly: {
|
|
5980
5925
|
type: "boolean",
|
|
@@ -5990,6 +5935,13 @@ function registerOptionAlgoTools() {
|
|
|
5990
5935
|
handler: async (rawArgs, context) => {
|
|
5991
5936
|
const args = asRecord(rawArgs);
|
|
5992
5937
|
const reduceOnly = readBoolean(args, "reduceOnly");
|
|
5938
|
+
const resolved = await resolveQuoteCcySz(
|
|
5939
|
+
requireString(args, "instId"),
|
|
5940
|
+
requireString(args, "sz"),
|
|
5941
|
+
readString(args, "tgtCcy"),
|
|
5942
|
+
"OPTION",
|
|
5943
|
+
context.client
|
|
5944
|
+
);
|
|
5993
5945
|
const response = await context.client.privatePost(
|
|
5994
5946
|
"/api/v5/trade/order-algo",
|
|
5995
5947
|
compactObject({
|
|
@@ -5997,8 +5949,8 @@ function registerOptionAlgoTools() {
|
|
|
5997
5949
|
tdMode: requireString(args, "tdMode"),
|
|
5998
5950
|
side: requireString(args, "side"),
|
|
5999
5951
|
ordType: requireString(args, "ordType"),
|
|
6000
|
-
sz:
|
|
6001
|
-
tgtCcy:
|
|
5952
|
+
sz: resolved.sz,
|
|
5953
|
+
tgtCcy: resolved.tgtCcy,
|
|
6002
5954
|
tpTriggerPx: readString(args, "tpTriggerPx"),
|
|
6003
5955
|
tpOrdPx: readString(args, "tpOrdPx"),
|
|
6004
5956
|
tpTriggerPxType: readString(args, "tpTriggerPxType"),
|
|
@@ -6205,7 +6157,12 @@ function registerOptionTools() {
|
|
|
6205
6157
|
},
|
|
6206
6158
|
sz: {
|
|
6207
6159
|
type: "string",
|
|
6208
|
-
description: "Contracts count
|
|
6160
|
+
description: "Contracts count by default. Set tgtCcy=quote_ccy to use USDT amount instead."
|
|
6161
|
+
},
|
|
6162
|
+
tgtCcy: {
|
|
6163
|
+
type: "string",
|
|
6164
|
+
enum: ["base_ccy", "quote_ccy"],
|
|
6165
|
+
description: "Size unit. base_ccy(default): sz in contracts, quote_ccy: sz in USDT (auto-converted to contracts)"
|
|
6209
6166
|
},
|
|
6210
6167
|
px: {
|
|
6211
6168
|
type: "string",
|
|
@@ -6242,6 +6199,13 @@ function registerOptionTools() {
|
|
|
6242
6199
|
const args = asRecord(rawArgs);
|
|
6243
6200
|
const reduceOnly = args.reduceOnly;
|
|
6244
6201
|
const attachAlgoOrds = buildAttachAlgoOrds(args);
|
|
6202
|
+
const resolved = await resolveQuoteCcySz(
|
|
6203
|
+
requireString(args, "instId"),
|
|
6204
|
+
requireString(args, "sz"),
|
|
6205
|
+
readString(args, "tgtCcy"),
|
|
6206
|
+
"OPTION",
|
|
6207
|
+
context.client
|
|
6208
|
+
);
|
|
6245
6209
|
const response = await context.client.privatePost(
|
|
6246
6210
|
"/api/v5/trade/order",
|
|
6247
6211
|
compactObject({
|
|
@@ -6249,7 +6213,8 @@ function registerOptionTools() {
|
|
|
6249
6213
|
tdMode: requireString(args, "tdMode"),
|
|
6250
6214
|
side: requireString(args, "side"),
|
|
6251
6215
|
ordType: requireString(args, "ordType"),
|
|
6252
|
-
sz:
|
|
6216
|
+
sz: resolved.sz,
|
|
6217
|
+
tgtCcy: resolved.tgtCcy,
|
|
6253
6218
|
px: readString(args, "px"),
|
|
6254
6219
|
reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
|
|
6255
6220
|
clOrdId: readString(args, "clOrdId"),
|
|
@@ -7405,7 +7370,7 @@ function createToolRunner(client, config) {
|
|
|
7405
7370
|
};
|
|
7406
7371
|
}
|
|
7407
7372
|
function configFilePath() {
|
|
7408
|
-
return
|
|
7373
|
+
return join4(homedir2(), ".okx", "config.toml");
|
|
7409
7374
|
}
|
|
7410
7375
|
function readFullConfig() {
|
|
7411
7376
|
const path42 = configFilePath();
|
|
@@ -7556,7 +7521,7 @@ function loadConfig(cli) {
|
|
|
7556
7521
|
verbose: cli.verbose ?? false
|
|
7557
7522
|
};
|
|
7558
7523
|
}
|
|
7559
|
-
var CACHE_FILE =
|
|
7524
|
+
var CACHE_FILE = join5(homedir3(), ".okx", "update-check.json");
|
|
7560
7525
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
7561
7526
|
function readCache() {
|
|
7562
7527
|
try {
|
|
@@ -7569,7 +7534,7 @@ function readCache() {
|
|
|
7569
7534
|
}
|
|
7570
7535
|
function writeCache(cache) {
|
|
7571
7536
|
try {
|
|
7572
|
-
mkdirSync5(
|
|
7537
|
+
mkdirSync5(join5(homedir3(), ".okx"), { recursive: true });
|
|
7573
7538
|
writeFileSync4(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
|
|
7574
7539
|
} catch {
|
|
7575
7540
|
}
|
|
@@ -8399,7 +8364,7 @@ async function cmdDiagnoseMcp(options = {}) {
|
|
|
8399
8364
|
|
|
8400
8365
|
// src/commands/diagnose.ts
|
|
8401
8366
|
var CLI_VERSION = readCliVersion();
|
|
8402
|
-
var GIT_HASH = true ? "
|
|
8367
|
+
var GIT_HASH = true ? "d684c01" : "dev";
|
|
8403
8368
|
function maskKey2(key) {
|
|
8404
8369
|
if (!key) return "(not set)";
|
|
8405
8370
|
if (key.length <= 8) return "****";
|
|
@@ -8697,12 +8662,12 @@ async function runCliChecks(config, profile, outputPath) {
|
|
|
8697
8662
|
// src/commands/upgrade.ts
|
|
8698
8663
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
8699
8664
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7 } from "fs";
|
|
8700
|
-
import { dirname as dirname5, join as
|
|
8701
|
-
import { homedir as
|
|
8665
|
+
import { dirname as dirname5, join as join7 } from "path";
|
|
8666
|
+
import { homedir as homedir5 } from "os";
|
|
8702
8667
|
var PACKAGES = ["@okx_ai/okx-trade-mcp", "@okx_ai/okx-trade-cli"];
|
|
8703
|
-
var CACHE_FILE2 =
|
|
8668
|
+
var CACHE_FILE2 = join7(homedir5(), ".okx", "last_check");
|
|
8704
8669
|
var THROTTLE_MS = 12 * 60 * 60 * 1e3;
|
|
8705
|
-
var NPM_BIN =
|
|
8670
|
+
var NPM_BIN = join7(dirname5(process.execPath), process.platform === "win32" ? "npm.cmd" : "npm");
|
|
8706
8671
|
function readLastCheck() {
|
|
8707
8672
|
try {
|
|
8708
8673
|
return parseInt(readFileSync6(CACHE_FILE2, "utf-8").trim(), 10) || 0;
|
|
@@ -8712,7 +8677,7 @@ function readLastCheck() {
|
|
|
8712
8677
|
}
|
|
8713
8678
|
function writeLastCheck() {
|
|
8714
8679
|
try {
|
|
8715
|
-
mkdirSync7(
|
|
8680
|
+
mkdirSync7(join7(homedir5(), ".okx"), { recursive: true });
|
|
8716
8681
|
writeFileSync6(CACHE_FILE2, String(Math.floor(Date.now() / 1e3)), "utf-8");
|
|
8717
8682
|
} catch {
|
|
8718
8683
|
}
|
|
@@ -11248,6 +11213,7 @@ async function cmdOptionPlace(run, opts) {
|
|
|
11248
11213
|
side: opts.side,
|
|
11249
11214
|
ordType: opts.ordType,
|
|
11250
11215
|
sz: opts.sz,
|
|
11216
|
+
tgtCcy: opts.tgtCcy,
|
|
11251
11217
|
px: opts.px,
|
|
11252
11218
|
reduceOnly: opts.reduceOnly,
|
|
11253
11219
|
clOrdId: opts.clOrdId,
|
|
@@ -12294,7 +12260,7 @@ async function cmdDcdRedeemExecute(run, opts) {
|
|
|
12294
12260
|
ordId: r["ordId"],
|
|
12295
12261
|
state: r["state"],
|
|
12296
12262
|
redeemSz: q["redeemSz"] ? `${parseFloat(q["redeemSz"]).toFixed(8)} ${q["redeemCcy"]}` : "\u2014",
|
|
12297
|
-
termRate: q["termRate"] ? `${q["termRate"]}%` : "\u2014"
|
|
12263
|
+
termRate: q["termRate"] ? `${(parseFloat(q["termRate"]) * 100).toFixed(2)}%` : "\u2014"
|
|
12298
12264
|
});
|
|
12299
12265
|
}
|
|
12300
12266
|
async function cmdDcdOrderState(run, opts) {
|
|
@@ -12347,7 +12313,7 @@ async function cmdDcdOrders(run, opts) {
|
|
|
12347
12313
|
quoteCcy: r["quoteCcy"],
|
|
12348
12314
|
strike: r["strike"],
|
|
12349
12315
|
notionalSz: r["notionalSz"],
|
|
12350
|
-
annualizedYield: r["annualizedYield"],
|
|
12316
|
+
annualizedYield: r["annualizedYield"] ? `${(parseFloat(r["annualizedYield"]) * 100).toFixed(2)}%` : "\u2014",
|
|
12351
12317
|
yieldSz: r["yieldSz"],
|
|
12352
12318
|
settleTime: r["settleTime"] ? new Date(Number(r["settleTime"])).toLocaleDateString() : "",
|
|
12353
12319
|
// scheduled settlement time
|
|
@@ -12387,7 +12353,7 @@ async function cmdDcdQuoteAndBuy(run, opts) {
|
|
|
12387
12353
|
outputLine("Quote:");
|
|
12388
12354
|
printKv({
|
|
12389
12355
|
quoteId: q["quoteId"],
|
|
12390
|
-
annualizedYield: q["annualizedYield"] ? `${q["annualizedYield"]}%` : "\u2014",
|
|
12356
|
+
annualizedYield: q["annualizedYield"] ? `${(parseFloat(q["annualizedYield"]) * 100).toFixed(2)}%` : "\u2014",
|
|
12391
12357
|
absYield: q["absYield"],
|
|
12392
12358
|
notionalSz: q["notionalSz"],
|
|
12393
12359
|
notionalCcy: q["notionalCcy"]
|
|
@@ -12411,16 +12377,17 @@ async function cmdDcdQuoteAndBuy(run, opts) {
|
|
|
12411
12377
|
}
|
|
12412
12378
|
|
|
12413
12379
|
// src/commands/skill.ts
|
|
12414
|
-
import { tmpdir, homedir as
|
|
12415
|
-
import { join as
|
|
12380
|
+
import { tmpdir, homedir as homedir7 } from "os";
|
|
12381
|
+
import { join as join9, dirname as dirname6 } from "path";
|
|
12416
12382
|
import { mkdirSync as mkdirSync8, rmSync, existsSync as existsSync7, copyFileSync as copyFileSync2 } from "fs";
|
|
12417
12383
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
12418
12384
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
12419
12385
|
function resolveNpx() {
|
|
12420
|
-
const sibling =
|
|
12386
|
+
const sibling = join9(dirname6(process.execPath), "npx");
|
|
12421
12387
|
if (existsSync7(sibling)) return sibling;
|
|
12422
12388
|
return "npx";
|
|
12423
12389
|
}
|
|
12390
|
+
var THIRD_PARTY_INSTALL_NOTICE = "Note: This skill was created by a third-party developer, not by OKX. Review SKILL.md before use.";
|
|
12424
12391
|
async function cmdSkillSearch(run, opts) {
|
|
12425
12392
|
const args = {};
|
|
12426
12393
|
if (opts.keyword) args.keyword = opts.keyword;
|
|
@@ -12470,13 +12437,13 @@ async function cmdSkillCategories(run, json) {
|
|
|
12470
12437
|
outputLine("");
|
|
12471
12438
|
}
|
|
12472
12439
|
async function cmdSkillAdd(name, config, json) {
|
|
12473
|
-
const tmpBase =
|
|
12440
|
+
const tmpBase = join9(tmpdir(), `okx-skill-${randomUUID2()}`);
|
|
12474
12441
|
mkdirSync8(tmpBase, { recursive: true });
|
|
12475
12442
|
try {
|
|
12476
12443
|
outputLine(`Downloading ${name}...`);
|
|
12477
12444
|
const client = new OkxRestClient(config);
|
|
12478
12445
|
const zipPath = await downloadSkillZip(client, name, tmpBase);
|
|
12479
|
-
const contentDir = await extractSkillZip(zipPath,
|
|
12446
|
+
const contentDir = await extractSkillZip(zipPath, join9(tmpBase, "content"));
|
|
12480
12447
|
const meta = readMetaJson(contentDir);
|
|
12481
12448
|
validateSkillMdExists(contentDir);
|
|
12482
12449
|
outputLine("Installing to detected agents...");
|
|
@@ -12486,7 +12453,7 @@ async function cmdSkillAdd(name, config, json) {
|
|
|
12486
12453
|
timeout: 6e4
|
|
12487
12454
|
});
|
|
12488
12455
|
} catch (e) {
|
|
12489
|
-
const savedZip =
|
|
12456
|
+
const savedZip = join9(process.cwd(), `${name}.zip`);
|
|
12490
12457
|
try {
|
|
12491
12458
|
copyFileSync2(zipPath, savedZip);
|
|
12492
12459
|
} catch {
|
|
@@ -12496,11 +12463,7 @@ async function cmdSkillAdd(name, config, json) {
|
|
|
12496
12463
|
throw e;
|
|
12497
12464
|
}
|
|
12498
12465
|
upsertSkillRecord(meta);
|
|
12499
|
-
|
|
12500
|
-
outputLine(JSON.stringify({ name: meta.name, version: meta.version, status: "installed" }, null, 2));
|
|
12501
|
-
} else {
|
|
12502
|
-
outputLine(`\u2713 Skill "${meta.name}" v${meta.version} installed`);
|
|
12503
|
-
}
|
|
12466
|
+
printSkillInstallResult(meta, json);
|
|
12504
12467
|
} finally {
|
|
12505
12468
|
rmSync(tmpBase, { recursive: true, force: true });
|
|
12506
12469
|
}
|
|
@@ -12529,7 +12492,7 @@ function cmdSkillRemove(name, json) {
|
|
|
12529
12492
|
timeout: 6e4
|
|
12530
12493
|
});
|
|
12531
12494
|
} catch {
|
|
12532
|
-
const agentsPath =
|
|
12495
|
+
const agentsPath = join9(homedir7(), ".agents", "skills", name);
|
|
12533
12496
|
try {
|
|
12534
12497
|
rmSync(agentsPath, { recursive: true, force: true });
|
|
12535
12498
|
} catch {
|
|
@@ -12593,11 +12556,19 @@ function cmdSkillList(json) {
|
|
|
12593
12556
|
outputLine("");
|
|
12594
12557
|
outputLine(`${skills.length} skills installed.`);
|
|
12595
12558
|
}
|
|
12559
|
+
function printSkillInstallResult(meta, json) {
|
|
12560
|
+
if (json) {
|
|
12561
|
+
outputLine(JSON.stringify({ name: meta.name, version: meta.version, status: "installed" }, null, 2));
|
|
12562
|
+
} else {
|
|
12563
|
+
outputLine(`\u2713 Skill "${meta.name}" v${meta.version} installed`);
|
|
12564
|
+
outputLine(` ${THIRD_PARTY_INSTALL_NOTICE}`);
|
|
12565
|
+
}
|
|
12566
|
+
}
|
|
12596
12567
|
|
|
12597
12568
|
// src/index.ts
|
|
12598
12569
|
var _require3 = createRequire3(import.meta.url);
|
|
12599
12570
|
var CLI_VERSION2 = _require3("../package.json").version;
|
|
12600
|
-
var GIT_HASH2 = true ? "
|
|
12571
|
+
var GIT_HASH2 = true ? "d684c01" : "dev";
|
|
12601
12572
|
function handleConfigCommand(action, rest, json, lang, force) {
|
|
12602
12573
|
if (action === "init") return cmdConfigInit(lang === "zh" ? "zh" : "en");
|
|
12603
12574
|
if (action === "show") return cmdConfigShow(json);
|
|
@@ -13004,6 +12975,7 @@ function handleOptionCommand(run, action, rest, v, json) {
|
|
|
13004
12975
|
side: v.side,
|
|
13005
12976
|
ordType: v.ordType,
|
|
13006
12977
|
sz: v.sz,
|
|
12978
|
+
tgtCcy: v.tgtCcy,
|
|
13007
12979
|
px: v.px,
|
|
13008
12980
|
reduceOnly: v.reduceOnly,
|
|
13009
12981
|
clOrdId: v.clOrdId,
|