@okx_ai/okx-trade-cli 1.3.0-beta.1 → 1.3.0-beta.2
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 +568 -138
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -854,6 +854,9 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
|
854
854
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync4 } from "fs";
|
|
855
855
|
import { join as join5 } from "path";
|
|
856
856
|
import { homedir as homedir3 } from "os";
|
|
857
|
+
import fs2 from "fs";
|
|
858
|
+
import path2 from "path";
|
|
859
|
+
import os2 from "os";
|
|
857
860
|
import * as fs3 from "fs";
|
|
858
861
|
import * as path3 from "path";
|
|
859
862
|
import * as os3 from "os";
|
|
@@ -2322,58 +2325,111 @@ function registerAccountTools() {
|
|
|
2322
2325
|
}
|
|
2323
2326
|
];
|
|
2324
2327
|
}
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
return { sz, tgtCcy, conversionNote: void 0 };
|
|
2328
|
-
}
|
|
2329
|
-
const [instrumentsRes, tickerRes] = await Promise.all([
|
|
2330
|
-
client.publicGet("/api/v5/public/instruments", {
|
|
2331
|
-
instType,
|
|
2332
|
-
instId
|
|
2333
|
-
}),
|
|
2334
|
-
client.publicGet("/api/v5/market/ticker", { instId })
|
|
2335
|
-
]);
|
|
2336
|
-
const instruments = Array.isArray(instrumentsRes.data) ? instrumentsRes.data : [];
|
|
2328
|
+
function extractInstrumentParams(instId, data) {
|
|
2329
|
+
const instruments = Array.isArray(data) ? data : [];
|
|
2337
2330
|
if (instruments.length === 0) {
|
|
2338
|
-
throw new Error(
|
|
2339
|
-
`Failed to fetch instrument info for ${instId}: empty instrument list. Cannot determine ctVal for quote_ccy conversion.`
|
|
2340
|
-
);
|
|
2331
|
+
throw new Error(`Failed to fetch instrument info for ${instId}: empty instrument list. Cannot determine ctVal for conversion.`);
|
|
2341
2332
|
}
|
|
2342
|
-
const
|
|
2333
|
+
const inst = instruments[0];
|
|
2334
|
+
const ctValStr = String(inst.ctVal ?? "");
|
|
2343
2335
|
const ctVal = parseFloat(ctValStr);
|
|
2344
2336
|
if (!isFinite(ctVal) || ctVal <= 0) {
|
|
2345
|
-
throw new Error(
|
|
2346
|
-
|
|
2347
|
-
|
|
2337
|
+
throw new Error(`Invalid ctVal "${ctValStr}" for ${instId}. ctVal must be a positive number for conversion.`);
|
|
2338
|
+
}
|
|
2339
|
+
const minSzStr = String(inst.minSz ?? "1");
|
|
2340
|
+
const minSz = parseFloat(minSzStr);
|
|
2341
|
+
if (!isFinite(minSz) || minSz <= 0) {
|
|
2342
|
+
throw new Error(`Invalid minSz "${minSzStr}" for ${instId}. minSz must be a positive number for conversion.`);
|
|
2343
|
+
}
|
|
2344
|
+
const lotSzStr = String(inst.lotSz ?? "1");
|
|
2345
|
+
const lotSz = parseFloat(lotSzStr);
|
|
2346
|
+
if (!isFinite(lotSz) || lotSz <= 0) {
|
|
2347
|
+
throw new Error(`Invalid lotSz "${lotSzStr}" for ${instId}. lotSz must be a positive number for conversion.`);
|
|
2348
2348
|
}
|
|
2349
|
-
|
|
2349
|
+
return { ctVal, ctValStr, minSz, minSzStr, lotSz, lotSzStr };
|
|
2350
|
+
}
|
|
2351
|
+
function extractLastPx(instId, data) {
|
|
2352
|
+
const tickers = Array.isArray(data) ? data : [];
|
|
2350
2353
|
if (tickers.length === 0) {
|
|
2351
|
-
throw new Error(
|
|
2352
|
-
`Failed to fetch ticker price for ${instId}: empty ticker response. Cannot determine last price for quote_ccy conversion.`
|
|
2353
|
-
);
|
|
2354
|
+
throw new Error(`Failed to fetch ticker price for ${instId}: empty ticker response. Cannot determine last price for conversion.`);
|
|
2354
2355
|
}
|
|
2355
2356
|
const lastStr = String(tickers[0].last ?? "");
|
|
2356
2357
|
const lastPx = parseFloat(lastStr);
|
|
2357
2358
|
if (!isFinite(lastPx) || lastPx <= 0) {
|
|
2359
|
+
throw new Error(`Invalid last price "${lastStr}" for ${instId}. Last price must be a positive number for conversion.`);
|
|
2360
|
+
}
|
|
2361
|
+
return { lastPx, lastStr };
|
|
2362
|
+
}
|
|
2363
|
+
function extractLeverage(instId, mgnMode, data) {
|
|
2364
|
+
const leverageData = Array.isArray(data) ? data : [];
|
|
2365
|
+
if (leverageData.length === 0) {
|
|
2358
2366
|
throw new Error(
|
|
2359
|
-
`
|
|
2367
|
+
`Failed to fetch leverage info for ${instId} (mgnMode=${mgnMode}): empty response. Cannot determine leverage for margin conversion. Please set leverage first using set_leverage.`
|
|
2360
2368
|
);
|
|
2361
2369
|
}
|
|
2362
|
-
const
|
|
2370
|
+
const leverStr = String(leverageData[0].lever ?? "1");
|
|
2371
|
+
const lever = parseFloat(leverStr);
|
|
2372
|
+
if (!isFinite(lever) || lever <= 0) {
|
|
2373
|
+
throw new Error(`Invalid leverage "${leverStr}" for ${instId}. Leverage must be a positive number for margin conversion.`);
|
|
2374
|
+
}
|
|
2375
|
+
return { lever, leverStr };
|
|
2376
|
+
}
|
|
2377
|
+
function computeContracts(p) {
|
|
2378
|
+
const { instId, sz, isMarginMode, inst, lastPx, lastStr, lever, leverStr } = p;
|
|
2379
|
+
const { ctVal, ctValStr, minSz, minSzStr, lotSz, lotSzStr } = inst;
|
|
2380
|
+
const userAmount = parseFloat(sz);
|
|
2363
2381
|
const contractValue = ctVal * lastPx;
|
|
2364
|
-
const
|
|
2365
|
-
|
|
2366
|
-
|
|
2382
|
+
const effectiveNotional = isMarginMode ? userAmount * lever : userAmount;
|
|
2383
|
+
const lotSzDecimals = lotSzStr.includes(".") ? lotSzStr.split(".")[1].length : 0;
|
|
2384
|
+
const precision = 10 ** (lotSzDecimals + 4);
|
|
2385
|
+
const rawContracts = Math.round(effectiveNotional / contractValue * precision) / precision;
|
|
2386
|
+
const rawLots = Math.round(rawContracts / lotSz * precision) / precision;
|
|
2387
|
+
const contractsRounded = parseFloat((Math.floor(rawLots) * lotSz).toFixed(lotSzDecimals));
|
|
2388
|
+
if (contractsRounded < minSz) {
|
|
2389
|
+
const minAmount = isMarginMode ? (minSz * contractValue / lever).toFixed(2) : (minSz * contractValue).toFixed(2);
|
|
2390
|
+
const unit = isMarginMode ? "USDT margin" : "USDT";
|
|
2367
2391
|
throw new Error(
|
|
2368
|
-
`sz=${sz}
|
|
2392
|
+
`sz=${sz} ${unit} is too small for ${instId}. Minimum order size is ${minSzStr} contracts (\u2248 ${minAmount} ${unit}). (ctVal=${ctValStr}, lastPx=${lastStr}, minSz=${minSzStr}, lotSz=${lotSzStr}` + (isMarginMode ? `, lever=${leverStr}` : "") + `).
|
|
2393
|
+
`
|
|
2369
2394
|
);
|
|
2370
2395
|
}
|
|
2371
|
-
const
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2396
|
+
const contractsStr = contractsRounded.toFixed(lotSzDecimals);
|
|
2397
|
+
const conversionNote = isMarginMode ? `Converting ${sz} USDT margin (${leverStr}x leverage) \u2192 ${contractsStr} contracts (notional value \u2248 ${(contractsRounded * contractValue).toFixed(2)} USDT, ctVal=${ctValStr}, lastPx=${lastStr}, lever=${leverStr}, minSz=${minSzStr}, lotSz=${lotSzStr})` : `Converting ${sz} USDT \u2192 ${contractsStr} contracts (ctVal=${ctValStr}, lastPx=${lastStr}, minSz=${minSzStr}, lotSz=${lotSzStr})`;
|
|
2398
|
+
return { contractsStr, conversionNote };
|
|
2399
|
+
}
|
|
2400
|
+
async function resolveQuoteCcySz(instId, sz, tgtCcy, instType, client, tdMode) {
|
|
2401
|
+
if (tgtCcy !== "quote_ccy" && tgtCcy !== "margin") {
|
|
2402
|
+
return { sz, tgtCcy, conversionNote: void 0 };
|
|
2403
|
+
}
|
|
2404
|
+
const isMarginMode = tgtCcy === "margin";
|
|
2405
|
+
if (isMarginMode && !tdMode) {
|
|
2406
|
+
throw new Error(
|
|
2407
|
+
"tdMode (cross or isolated) is required when tgtCcy=margin. Cannot determine leverage without knowing the margin mode."
|
|
2408
|
+
);
|
|
2409
|
+
}
|
|
2410
|
+
const mgnMode = tdMode === "cross" ? "cross" : "isolated";
|
|
2411
|
+
const fetchPromises = [
|
|
2412
|
+
client.publicGet("/api/v5/public/instruments", { instType, instId }),
|
|
2413
|
+
client.publicGet("/api/v5/market/ticker", { instId })
|
|
2414
|
+
];
|
|
2415
|
+
if (isMarginMode) {
|
|
2416
|
+
fetchPromises.push(client.privateGet("/api/v5/account/leverage-info", { instId, mgnMode }));
|
|
2417
|
+
}
|
|
2418
|
+
const results = await Promise.all(fetchPromises);
|
|
2419
|
+
const inst = extractInstrumentParams(instId, results[0].data);
|
|
2420
|
+
const { lastPx, lastStr } = extractLastPx(instId, results[1].data);
|
|
2421
|
+
const { lever, leverStr } = isMarginMode ? extractLeverage(instId, mgnMode, results[2].data) : { lever: 1, leverStr: "1" };
|
|
2422
|
+
const { contractsStr, conversionNote } = computeContracts({
|
|
2423
|
+
instId,
|
|
2424
|
+
sz,
|
|
2425
|
+
isMarginMode,
|
|
2426
|
+
inst,
|
|
2427
|
+
lastPx,
|
|
2428
|
+
lastStr,
|
|
2429
|
+
lever,
|
|
2430
|
+
leverStr
|
|
2431
|
+
});
|
|
2432
|
+
return { sz: contractsStr, tgtCcy: void 0, conversionNote };
|
|
2377
2433
|
}
|
|
2378
2434
|
function registerAlgoTradeTools() {
|
|
2379
2435
|
return [
|
|
@@ -2453,8 +2509,8 @@ function registerAlgoTradeTools() {
|
|
|
2453
2509
|
},
|
|
2454
2510
|
tgtCcy: {
|
|
2455
2511
|
type: "string",
|
|
2456
|
-
enum: ["base_ccy", "quote_ccy"],
|
|
2457
|
-
description: "Size unit. base_ccy(default): sz in contracts
|
|
2512
|
+
enum: ["base_ccy", "quote_ccy", "margin"],
|
|
2513
|
+
description: "Size unit. base_ccy(default): sz in contracts; quote_ccy: sz in USDT notional value; margin: sz in USDT margin cost (actual position = sz * leverage)"
|
|
2458
2514
|
},
|
|
2459
2515
|
reduceOnly: {
|
|
2460
2516
|
type: "boolean",
|
|
@@ -2475,7 +2531,8 @@ function registerAlgoTradeTools() {
|
|
|
2475
2531
|
requireString(args, "sz"),
|
|
2476
2532
|
readString(args, "tgtCcy"),
|
|
2477
2533
|
"SWAP",
|
|
2478
|
-
context.client
|
|
2534
|
+
context.client,
|
|
2535
|
+
readString(args, "tdMode")
|
|
2479
2536
|
);
|
|
2480
2537
|
const response = await context.client.privatePost(
|
|
2481
2538
|
"/api/v5/trade/order-algo",
|
|
@@ -2797,8 +2854,8 @@ function registerFuturesAlgoTools() {
|
|
|
2797
2854
|
},
|
|
2798
2855
|
tgtCcy: {
|
|
2799
2856
|
type: "string",
|
|
2800
|
-
enum: ["base_ccy", "quote_ccy"],
|
|
2801
|
-
description: "Size unit. base_ccy(default): sz in contracts
|
|
2857
|
+
enum: ["base_ccy", "quote_ccy", "margin"],
|
|
2858
|
+
description: "Size unit. base_ccy(default): sz in contracts; quote_ccy: sz in USDT notional value; margin: sz in USDT margin cost (actual position = sz * leverage)"
|
|
2802
2859
|
},
|
|
2803
2860
|
reduceOnly: {
|
|
2804
2861
|
type: "boolean",
|
|
@@ -2819,7 +2876,8 @@ function registerFuturesAlgoTools() {
|
|
|
2819
2876
|
requireString(args, "sz"),
|
|
2820
2877
|
readString(args, "tgtCcy"),
|
|
2821
2878
|
"FUTURES",
|
|
2822
|
-
context.client
|
|
2879
|
+
context.client,
|
|
2880
|
+
readString(args, "tdMode")
|
|
2823
2881
|
);
|
|
2824
2882
|
const response = await context.client.privatePost(
|
|
2825
2883
|
"/api/v5/trade/order-algo",
|
|
@@ -4021,7 +4079,7 @@ function registerEarnTools() {
|
|
|
4021
4079
|
{
|
|
4022
4080
|
name: "earn_get_savings_balance",
|
|
4023
4081
|
module: "earn.savings",
|
|
4024
|
-
description: "Get Simple Earn (savings/flexible earn) balance. Returns current holdings
|
|
4082
|
+
description: "Get Simple Earn (savings/flexible earn) balance. Returns current holdings for all currencies or a specific one. To show market rates alongside balance (\u5E02\u573A\u5747\u5229\u7387), call earn_get_lending_rate_history. earn_get_lending_rate_history also returns fixed-term (\u5B9A\u671F) product offers, so one call gives a complete view of both flexible and fixed options. Do NOT use for fixed-term (\u5B9A\u671F) order queries \u2014 use earn_get_fixed_order_list instead.",
|
|
4025
4083
|
isWrite: false,
|
|
4026
4084
|
inputSchema: {
|
|
4027
4085
|
type: "object",
|
|
@@ -4042,6 +4100,43 @@ function registerEarnTools() {
|
|
|
4042
4100
|
return normalizeResponse(response);
|
|
4043
4101
|
}
|
|
4044
4102
|
},
|
|
4103
|
+
{
|
|
4104
|
+
name: "earn_get_fixed_order_list",
|
|
4105
|
+
module: "earn.savings",
|
|
4106
|
+
description: "Get Simple Earn Fixed (\u5B9A\u671F\u8D5A\u5E01) lending order list. Returns orders sorted by creation time descending. Use this to check status of fixed-term lending orders (pending/earning/expired/settled/cancelled). Do NOT use for flexible earn balance \u2014 use earn_get_savings_balance instead. If the result is empty, do NOT display any fixed-term section in the output.",
|
|
4107
|
+
isWrite: false,
|
|
4108
|
+
inputSchema: {
|
|
4109
|
+
type: "object",
|
|
4110
|
+
properties: {
|
|
4111
|
+
ccy: {
|
|
4112
|
+
type: "string",
|
|
4113
|
+
description: "Currency, e.g. USDT. Omit for all."
|
|
4114
|
+
},
|
|
4115
|
+
state: {
|
|
4116
|
+
type: "string",
|
|
4117
|
+
description: "Order state: pending (\u5339\u914D\u4E2D), earning (\u8D5A\u5E01\u4E2D), expired (\u903E\u671F), settled (\u5DF2\u7ED3\u7B97), cancelled (\u5DF2\u64A4\u9500). Omit for all."
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4120
|
+
},
|
|
4121
|
+
handler: async (rawArgs, context) => {
|
|
4122
|
+
const args = asRecord(rawArgs);
|
|
4123
|
+
const response = await context.client.privateGet(
|
|
4124
|
+
"/api/v5/finance/simple-earn-fixed/order-list",
|
|
4125
|
+
compactObject({
|
|
4126
|
+
ccy: readString(args, "ccy"),
|
|
4127
|
+
state: readString(args, "state")
|
|
4128
|
+
}),
|
|
4129
|
+
privateRateLimit("earn_get_fixed_order_list", 3)
|
|
4130
|
+
);
|
|
4131
|
+
const result = normalizeResponse(response);
|
|
4132
|
+
if (Array.isArray(result["data"])) {
|
|
4133
|
+
result["data"] = result["data"].map(
|
|
4134
|
+
({ finalSettlementDate: _, ...rest }) => rest
|
|
4135
|
+
);
|
|
4136
|
+
}
|
|
4137
|
+
return result;
|
|
4138
|
+
}
|
|
4139
|
+
},
|
|
4045
4140
|
{
|
|
4046
4141
|
name: "earn_savings_purchase",
|
|
4047
4142
|
module: "earn.savings",
|
|
@@ -4186,10 +4281,112 @@ function registerEarnTools() {
|
|
|
4186
4281
|
return normalizeResponse(response);
|
|
4187
4282
|
}
|
|
4188
4283
|
},
|
|
4284
|
+
{
|
|
4285
|
+
name: "earn_fixed_purchase",
|
|
4286
|
+
module: "earn.savings",
|
|
4287
|
+
description: "Purchase Simple Earn Fixed (\u5B9A\u671F) product, two-step flow. First call (confirm omitted or false): returns purchase preview with product details and risk warning. Preview offer fields: lendQuota = remaining quota (\u5269\u4F59\u989D\u5EA6), soldOut = whether product is sold out (lendQuota is 0). YOU MUST display the 'warning' field from the preview response to the user VERBATIM before asking for confirmation \u2014 do NOT omit or summarize it. Second call (confirm=true): executes the purchase. Only proceed after the user explicitly confirms. IMPORTANT: Orders in 'pending' (\u5339\u914D\u4E2D) state can still be cancelled via earn_fixed_redeem; once the status changes to 'earning' (\u8D5A\u5E01\u4E2D), funds are LOCKED until maturity \u2014 no early redemption allowed.",
|
|
4288
|
+
isWrite: true,
|
|
4289
|
+
inputSchema: {
|
|
4290
|
+
type: "object",
|
|
4291
|
+
properties: {
|
|
4292
|
+
ccy: {
|
|
4293
|
+
type: "string",
|
|
4294
|
+
description: "Currency, e.g. USDT"
|
|
4295
|
+
},
|
|
4296
|
+
amt: {
|
|
4297
|
+
type: "string",
|
|
4298
|
+
description: "Purchase amount"
|
|
4299
|
+
},
|
|
4300
|
+
term: {
|
|
4301
|
+
type: "string",
|
|
4302
|
+
description: "Term, e.g. 90D"
|
|
4303
|
+
},
|
|
4304
|
+
confirm: {
|
|
4305
|
+
type: "boolean",
|
|
4306
|
+
description: "Omit or false on the first call to preview the purchase details; set to true on the second call to execute after user confirms."
|
|
4307
|
+
}
|
|
4308
|
+
},
|
|
4309
|
+
required: ["ccy", "amt", "term"]
|
|
4310
|
+
},
|
|
4311
|
+
handler: async (rawArgs, context) => {
|
|
4312
|
+
const args = asRecord(rawArgs);
|
|
4313
|
+
const ccy = requireString(args, "ccy");
|
|
4314
|
+
const amt = requireString(args, "amt");
|
|
4315
|
+
const term = requireString(args, "term");
|
|
4316
|
+
const confirm = readBoolean(args, "confirm") ?? false;
|
|
4317
|
+
if (!confirm) {
|
|
4318
|
+
const [rateResponse, fixedResponse] = await Promise.all([
|
|
4319
|
+
context.client.publicGet(
|
|
4320
|
+
"/api/v5/finance/savings/lending-rate-history",
|
|
4321
|
+
compactObject({ ccy, limit: 1 }),
|
|
4322
|
+
publicRateLimit("earn_get_lending_rate_history", 6)
|
|
4323
|
+
),
|
|
4324
|
+
context.client.privateGet(
|
|
4325
|
+
"/api/v5/finance/simple-earn-fixed/offers",
|
|
4326
|
+
compactObject({ ccy }),
|
|
4327
|
+
privateRateLimit("earn_fixed_purchase_preview_offers", 2)
|
|
4328
|
+
).catch(() => null)
|
|
4329
|
+
]);
|
|
4330
|
+
const rateResult = normalizeResponse(rateResponse);
|
|
4331
|
+
const fixedResult = fixedResponse ? normalizeResponse(fixedResponse) : { data: [] };
|
|
4332
|
+
const rateArr = Array.isArray(rateResult["data"]) ? rateResult["data"] : [];
|
|
4333
|
+
const allOffers = Array.isArray(fixedResult["data"]) ? fixedResult["data"] : [];
|
|
4334
|
+
const matchedOffer = allOffers.find(
|
|
4335
|
+
(o) => o["term"] === term && o["ccy"] === ccy
|
|
4336
|
+
);
|
|
4337
|
+
const { borrowingOrderQuota: _, ...offerWithoutTotal } = matchedOffer ?? {};
|
|
4338
|
+
const offerWithSoldOut = matchedOffer ? { ...offerWithoutTotal, soldOut: offerWithoutTotal["lendQuota"] === "0" } : null;
|
|
4339
|
+
return {
|
|
4340
|
+
preview: true,
|
|
4341
|
+
ccy,
|
|
4342
|
+
amt,
|
|
4343
|
+
term,
|
|
4344
|
+
offer: offerWithSoldOut,
|
|
4345
|
+
currentFlexibleRate: rateArr[0]?.["lendingRate"] ?? null,
|
|
4346
|
+
warning: "\u26A0\uFE0F Orders still in 'pending' state can be cancelled before matching completes. Once the status changes to 'earning', funds are LOCKED until maturity \u2014 early redemption is NOT allowed. Please call again with confirm=true to proceed."
|
|
4347
|
+
};
|
|
4348
|
+
}
|
|
4349
|
+
assertNotDemo(context.config, "earn_fixed_purchase");
|
|
4350
|
+
const response = await context.client.privatePost(
|
|
4351
|
+
"/api/v5/finance/simple-earn-fixed/purchase",
|
|
4352
|
+
{ ccy, amt, term },
|
|
4353
|
+
privateRateLimit("earn_fixed_purchase", 2)
|
|
4354
|
+
);
|
|
4355
|
+
return normalizeResponse(response);
|
|
4356
|
+
}
|
|
4357
|
+
},
|
|
4358
|
+
{
|
|
4359
|
+
name: "earn_fixed_redeem",
|
|
4360
|
+
module: "earn.savings",
|
|
4361
|
+
description: "Redeem Simple Earn Fixed (\u5B9A\u671F\u8D5A\u5E01) order. [CAUTION] Redeems a fixed-term lending order. Always redeems the full order amount. Only orders in 'pending' (\u5339\u914D\u4E2D) state can be redeemed \u2014 orders in 'earning' state are locked until maturity and cannot be redeemed early. Do NOT use for flexible earn redemption \u2014 use earn_savings_redeem instead.",
|
|
4362
|
+
isWrite: true,
|
|
4363
|
+
inputSchema: {
|
|
4364
|
+
type: "object",
|
|
4365
|
+
properties: {
|
|
4366
|
+
reqId: {
|
|
4367
|
+
type: "string",
|
|
4368
|
+
description: "Request ID of the fixed-term order to redeem"
|
|
4369
|
+
}
|
|
4370
|
+
},
|
|
4371
|
+
required: ["reqId"]
|
|
4372
|
+
},
|
|
4373
|
+
handler: async (rawArgs, context) => {
|
|
4374
|
+
assertNotDemo(context.config, "earn_fixed_redeem");
|
|
4375
|
+
const args = asRecord(rawArgs);
|
|
4376
|
+
const response = await context.client.privatePost(
|
|
4377
|
+
"/api/v5/finance/simple-earn-fixed/redeem",
|
|
4378
|
+
{
|
|
4379
|
+
reqId: requireString(args, "reqId")
|
|
4380
|
+
},
|
|
4381
|
+
privateRateLimit("earn_fixed_redeem", 2)
|
|
4382
|
+
);
|
|
4383
|
+
return normalizeResponse(response);
|
|
4384
|
+
}
|
|
4385
|
+
},
|
|
4189
4386
|
{
|
|
4190
4387
|
name: "earn_get_lending_rate_history",
|
|
4191
4388
|
module: "earn.savings",
|
|
4192
|
-
description: "Query Simple Earn lending rates
|
|
4389
|
+
description: "Query Simple Earn lending rates and fixed-term offers. Use this tool when the user asks about Simple Earn products, current or historical lending rates, or when displaying savings balance with market rate context (\u5E02\u573A\u5747\u5229\u7387). Returns lending rate history (lendingRate field, newest-first) AND available fixed-term (\u5B9A\u671F) offers with APR, term, min amount, and quota \u2014 one call gives a complete view of both flexible and fixed options. In fixedOffers: lendQuota = remaining quota (\u5269\u4F59\u989D\u5EA6), soldOut = whether product is sold out (lendQuota is 0). To get current flexible APY: use limit=1 and read lendingRate.",
|
|
4193
4390
|
isWrite: false,
|
|
4194
4391
|
inputSchema: {
|
|
4195
4392
|
type: "object",
|
|
@@ -4208,23 +4405,45 @@ function registerEarnTools() {
|
|
|
4208
4405
|
},
|
|
4209
4406
|
limit: {
|
|
4210
4407
|
type: "number",
|
|
4211
|
-
description: "Max results (default
|
|
4408
|
+
description: "Max results (default 7)"
|
|
4212
4409
|
}
|
|
4213
4410
|
}
|
|
4214
4411
|
},
|
|
4215
4412
|
handler: async (rawArgs, context) => {
|
|
4216
4413
|
const args = asRecord(rawArgs);
|
|
4217
|
-
const
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4414
|
+
const ccy = readString(args, "ccy");
|
|
4415
|
+
const [rateResponse, fixedResponse] = await Promise.all([
|
|
4416
|
+
context.client.publicGet(
|
|
4417
|
+
"/api/v5/finance/savings/lending-rate-history",
|
|
4418
|
+
compactObject({
|
|
4419
|
+
ccy,
|
|
4420
|
+
after: readString(args, "after"),
|
|
4421
|
+
before: readString(args, "before"),
|
|
4422
|
+
limit: readNumber(args, "limit") ?? 7
|
|
4423
|
+
}),
|
|
4424
|
+
publicRateLimit("earn_get_lending_rate_history", 6)
|
|
4425
|
+
),
|
|
4426
|
+
context.client.privateGet(
|
|
4427
|
+
"/api/v5/finance/simple-earn-fixed/offers",
|
|
4428
|
+
compactObject({ ccy }),
|
|
4429
|
+
privateRateLimit("earn_get_lending_rate_history_fixed", 2)
|
|
4430
|
+
).catch(() => null)
|
|
4431
|
+
]);
|
|
4432
|
+
const rateResult = normalizeResponse(rateResponse);
|
|
4433
|
+
const rateData = Array.isArray(rateResult["data"]) ? rateResult["data"].map(
|
|
4434
|
+
({ rate: _, ...rest }) => rest
|
|
4435
|
+
) : [];
|
|
4436
|
+
const fixedResult = fixedResponse ? normalizeResponse(fixedResponse) : { data: [] };
|
|
4437
|
+
const allOffers = fixedResult["data"] ?? [];
|
|
4438
|
+
const fixedOffers = allOffers.map(({ borrowingOrderQuota: _, ...rest }) => ({
|
|
4439
|
+
...rest,
|
|
4440
|
+
soldOut: rest["lendQuota"] === "0"
|
|
4441
|
+
}));
|
|
4442
|
+
return {
|
|
4443
|
+
...rateResult,
|
|
4444
|
+
data: rateData,
|
|
4445
|
+
fixedOffers
|
|
4446
|
+
};
|
|
4228
4447
|
}
|
|
4229
4448
|
}
|
|
4230
4449
|
];
|
|
@@ -4861,7 +5080,7 @@ function registerAutoEarnTools() {
|
|
|
4861
5080
|
}
|
|
4862
5081
|
var EARN_DEMO_MESSAGE = "Earn features (savings, DCD, on-chain staking, auto-earn) are not available in simulated trading mode.";
|
|
4863
5082
|
var EARN_DEMO_SUGGESTION = "Switch to a live account to use Earn features.";
|
|
4864
|
-
var DEMO_GUARD_SKIP = /* @__PURE__ */ new Set(["dcd_redeem"]);
|
|
5083
|
+
var DEMO_GUARD_SKIP = /* @__PURE__ */ new Set(["dcd_redeem", "earn_fixed_purchase"]);
|
|
4865
5084
|
function withDemoGuard(tool) {
|
|
4866
5085
|
if (!tool.isWrite || DEMO_GUARD_SKIP.has(tool.name)) return tool;
|
|
4867
5086
|
const originalHandler = tool.handler;
|
|
@@ -4922,12 +5141,12 @@ function buildContractTradeTools(cfg) {
|
|
|
4922
5141
|
},
|
|
4923
5142
|
sz: {
|
|
4924
5143
|
type: "string",
|
|
4925
|
-
description: "Number of contracts. Each contract = ctVal units (e.g. 0.1 ETH for ETH-USDT-SWAP). Query market_get_instruments for exact ctVal. Set tgtCcy=quote_ccy to specify sz in USDT
|
|
5144
|
+
description: "Number of contracts. Each contract = ctVal units (e.g. 0.1 ETH for ETH-USDT-SWAP). Query market_get_instruments for exact ctVal. Set tgtCcy=quote_ccy to specify sz in USDT notional value; set tgtCcy=margin to specify sz as margin cost (notional = sz * leverage)."
|
|
4926
5145
|
},
|
|
4927
5146
|
tgtCcy: {
|
|
4928
5147
|
type: "string",
|
|
4929
|
-
enum: ["base_ccy", "quote_ccy"],
|
|
4930
|
-
description: "Size unit. base_ccy(default): sz in contracts
|
|
5148
|
+
enum: ["base_ccy", "quote_ccy", "margin"],
|
|
5149
|
+
description: "Size unit. base_ccy(default): sz in contracts; quote_ccy: sz in USDT notional value; margin: sz in USDT margin cost (actual position = sz * leverage)"
|
|
4931
5150
|
},
|
|
4932
5151
|
px: { type: "string", description: "Required for limit/post_only/fok/ioc" },
|
|
4933
5152
|
reduceOnly: {
|
|
@@ -4951,7 +5170,8 @@ function buildContractTradeTools(cfg) {
|
|
|
4951
5170
|
requireString(args, "sz"),
|
|
4952
5171
|
readString(args, "tgtCcy"),
|
|
4953
5172
|
defaultType,
|
|
4954
|
-
context.client
|
|
5173
|
+
context.client,
|
|
5174
|
+
readString(args, "tdMode")
|
|
4955
5175
|
);
|
|
4956
5176
|
const response = await context.client.privatePost(
|
|
4957
5177
|
"/api/v5/trade/order",
|
|
@@ -6049,8 +6269,8 @@ function registerOptionAlgoTools() {
|
|
|
6049
6269
|
},
|
|
6050
6270
|
tgtCcy: {
|
|
6051
6271
|
type: "string",
|
|
6052
|
-
enum: ["base_ccy", "quote_ccy"],
|
|
6053
|
-
description: "Size unit. base_ccy(default): sz in contracts
|
|
6272
|
+
enum: ["base_ccy", "quote_ccy", "margin"],
|
|
6273
|
+
description: "Size unit. base_ccy(default): sz in contracts; quote_ccy: sz in USDT notional value; margin: sz in USDT margin cost (actual position = sz * leverage)"
|
|
6054
6274
|
},
|
|
6055
6275
|
reduceOnly: {
|
|
6056
6276
|
type: "boolean",
|
|
@@ -6071,7 +6291,8 @@ function registerOptionAlgoTools() {
|
|
|
6071
6291
|
requireString(args, "sz"),
|
|
6072
6292
|
readString(args, "tgtCcy"),
|
|
6073
6293
|
"OPTION",
|
|
6074
|
-
context.client
|
|
6294
|
+
context.client,
|
|
6295
|
+
readString(args, "tdMode")
|
|
6075
6296
|
);
|
|
6076
6297
|
const response = await context.client.privatePost(
|
|
6077
6298
|
"/api/v5/trade/order-algo",
|
|
@@ -6288,12 +6509,12 @@ function registerOptionTools() {
|
|
|
6288
6509
|
},
|
|
6289
6510
|
sz: {
|
|
6290
6511
|
type: "string",
|
|
6291
|
-
description: "Contracts count by default. Set tgtCcy=quote_ccy to
|
|
6512
|
+
description: "Contracts count by default. Set tgtCcy=quote_ccy to specify USDT notional value; set tgtCcy=margin to specify USDT margin cost (notional = sz * leverage)."
|
|
6292
6513
|
},
|
|
6293
6514
|
tgtCcy: {
|
|
6294
6515
|
type: "string",
|
|
6295
|
-
enum: ["base_ccy", "quote_ccy"],
|
|
6296
|
-
description: "Size unit. base_ccy(default): sz in contracts
|
|
6516
|
+
enum: ["base_ccy", "quote_ccy", "margin"],
|
|
6517
|
+
description: "Size unit. base_ccy(default): sz in contracts; quote_ccy: sz in USDT notional value; margin: sz in USDT margin cost (actual position = sz * leverage)"
|
|
6297
6518
|
},
|
|
6298
6519
|
px: {
|
|
6299
6520
|
type: "string",
|
|
@@ -6335,7 +6556,8 @@ function registerOptionTools() {
|
|
|
6335
6556
|
requireString(args, "sz"),
|
|
6336
6557
|
readString(args, "tgtCcy"),
|
|
6337
6558
|
"OPTION",
|
|
6338
|
-
context.client
|
|
6559
|
+
context.client,
|
|
6560
|
+
readString(args, "tdMode")
|
|
6339
6561
|
);
|
|
6340
6562
|
const response = await context.client.privatePost(
|
|
6341
6563
|
"/api/v5/trade/order",
|
|
@@ -7735,6 +7957,69 @@ Run: npm install -g ${packageName}
|
|
|
7735
7957
|
refreshCacheInBackground(packageName);
|
|
7736
7958
|
}
|
|
7737
7959
|
}
|
|
7960
|
+
var LOG_LEVEL_PRIORITY = {
|
|
7961
|
+
error: 0,
|
|
7962
|
+
warn: 1,
|
|
7963
|
+
info: 2,
|
|
7964
|
+
debug: 3
|
|
7965
|
+
};
|
|
7966
|
+
var SENSITIVE_KEY_PATTERN = /apiKey|secretKey|passphrase|password|secret/i;
|
|
7967
|
+
function sanitize(value) {
|
|
7968
|
+
if (value === null || value === void 0) {
|
|
7969
|
+
return value;
|
|
7970
|
+
}
|
|
7971
|
+
if (Array.isArray(value)) {
|
|
7972
|
+
return value.map(sanitize);
|
|
7973
|
+
}
|
|
7974
|
+
if (typeof value === "object") {
|
|
7975
|
+
const result = {};
|
|
7976
|
+
for (const [k, v] of Object.entries(value)) {
|
|
7977
|
+
if (SENSITIVE_KEY_PATTERN.test(k)) {
|
|
7978
|
+
result[k] = "[REDACTED]";
|
|
7979
|
+
} else {
|
|
7980
|
+
result[k] = sanitize(v);
|
|
7981
|
+
}
|
|
7982
|
+
}
|
|
7983
|
+
return result;
|
|
7984
|
+
}
|
|
7985
|
+
return value;
|
|
7986
|
+
}
|
|
7987
|
+
var TradeLogger = class {
|
|
7988
|
+
logLevel;
|
|
7989
|
+
logDir;
|
|
7990
|
+
constructor(logLevel = "info", logDir) {
|
|
7991
|
+
this.logLevel = logLevel;
|
|
7992
|
+
this.logDir = logDir ?? path2.join(os2.homedir(), ".okx", "logs");
|
|
7993
|
+
}
|
|
7994
|
+
getLogPath(date) {
|
|
7995
|
+
const d = date ?? /* @__PURE__ */ new Date();
|
|
7996
|
+
const yyyy = d.getUTCFullYear();
|
|
7997
|
+
const mm = String(d.getUTCMonth() + 1).padStart(2, "0");
|
|
7998
|
+
const dd = String(d.getUTCDate()).padStart(2, "0");
|
|
7999
|
+
return path2.join(this.logDir, `trade-${yyyy}-${mm}-${dd}.log`);
|
|
8000
|
+
}
|
|
8001
|
+
log(level, tool, params, result, durationMs) {
|
|
8002
|
+
if (LOG_LEVEL_PRIORITY[level] > LOG_LEVEL_PRIORITY[this.logLevel]) {
|
|
8003
|
+
return;
|
|
8004
|
+
}
|
|
8005
|
+
const entry = {
|
|
8006
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8007
|
+
level: level.toUpperCase(),
|
|
8008
|
+
tool,
|
|
8009
|
+
durationMs,
|
|
8010
|
+
params: sanitize(params),
|
|
8011
|
+
result: sanitize(result)
|
|
8012
|
+
};
|
|
8013
|
+
try {
|
|
8014
|
+
fs2.mkdirSync(this.logDir, { recursive: true });
|
|
8015
|
+
fs2.appendFileSync(this.getLogPath(), JSON.stringify(entry) + "\n", "utf8");
|
|
8016
|
+
} catch {
|
|
8017
|
+
}
|
|
8018
|
+
}
|
|
8019
|
+
static sanitize(params) {
|
|
8020
|
+
return sanitize(params);
|
|
8021
|
+
}
|
|
8022
|
+
};
|
|
7738
8023
|
var CLIENT_NAMES = {
|
|
7739
8024
|
"claude-desktop": "Claude Desktop",
|
|
7740
8025
|
cursor: "Cursor",
|
|
@@ -7884,11 +8169,11 @@ function runSetup(options) {
|
|
|
7884
8169
|
// src/commands/diagnose.ts
|
|
7885
8170
|
import dns from "dns/promises";
|
|
7886
8171
|
import net from "net";
|
|
7887
|
-
import
|
|
8172
|
+
import os5 from "os";
|
|
7888
8173
|
import tls from "tls";
|
|
7889
8174
|
|
|
7890
8175
|
// src/commands/diagnose-utils.ts
|
|
7891
|
-
import
|
|
8176
|
+
import fs4 from "fs";
|
|
7892
8177
|
import { createRequire } from "module";
|
|
7893
8178
|
|
|
7894
8179
|
// src/formatter.ts
|
|
@@ -7917,8 +8202,12 @@ function outputLine(message) {
|
|
|
7917
8202
|
function errorLine(message) {
|
|
7918
8203
|
activeOutput.err(message + EOL);
|
|
7919
8204
|
}
|
|
8205
|
+
var jsonEnvEnabled = false;
|
|
8206
|
+
function setJsonEnvEnabled(enabled) {
|
|
8207
|
+
jsonEnvEnabled = enabled;
|
|
8208
|
+
}
|
|
7920
8209
|
function printJson(data) {
|
|
7921
|
-
const payload = envContext ? {
|
|
8210
|
+
const payload = jsonEnvEnabled && envContext ? {
|
|
7922
8211
|
env: envContext.demo ? "demo" : "live",
|
|
7923
8212
|
profile: envContext.profile,
|
|
7924
8213
|
data
|
|
@@ -8006,7 +8295,7 @@ var Report = class {
|
|
|
8006
8295
|
lines.push(`${key.padEnd(14)} ${value}`);
|
|
8007
8296
|
}
|
|
8008
8297
|
lines.push(sep2, "");
|
|
8009
|
-
|
|
8298
|
+
fs4.writeFileSync(filePath, lines.join("\n"), "utf8");
|
|
8010
8299
|
return true;
|
|
8011
8300
|
} catch (_e) {
|
|
8012
8301
|
return false;
|
|
@@ -8041,7 +8330,7 @@ function writeReportIfRequested(report, outputPath) {
|
|
|
8041
8330
|
errorLine(` Warning: failed to write report to: ${outputPath}`);
|
|
8042
8331
|
}
|
|
8043
8332
|
}
|
|
8044
|
-
function
|
|
8333
|
+
function sanitize2(value) {
|
|
8045
8334
|
value = value.replace(
|
|
8046
8335
|
/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi,
|
|
8047
8336
|
"****-uuid-****"
|
|
@@ -8052,14 +8341,14 @@ function sanitize(value) {
|
|
|
8052
8341
|
}
|
|
8053
8342
|
|
|
8054
8343
|
// src/commands/diagnose-mcp.ts
|
|
8055
|
-
import
|
|
8056
|
-
import
|
|
8057
|
-
import
|
|
8344
|
+
import fs5 from "fs";
|
|
8345
|
+
import path4 from "path";
|
|
8346
|
+
import os4 from "os";
|
|
8058
8347
|
import { spawnSync, spawn } from "child_process";
|
|
8059
8348
|
import { createRequire as createRequire2 } from "module";
|
|
8060
8349
|
import { fileURLToPath } from "url";
|
|
8061
8350
|
var _require2 = createRequire2(import.meta.url);
|
|
8062
|
-
var __dirname =
|
|
8351
|
+
var __dirname = path4.dirname(fileURLToPath(import.meta.url));
|
|
8063
8352
|
function readMcpVersion() {
|
|
8064
8353
|
const candidates = [
|
|
8065
8354
|
// Installed as global or local dependency
|
|
@@ -8112,13 +8401,13 @@ function checkMcpEntryPoint(report) {
|
|
|
8112
8401
|
if (!entryPath) {
|
|
8113
8402
|
const candidates = [
|
|
8114
8403
|
// Installed locally
|
|
8115
|
-
|
|
8404
|
+
path4.join(process.cwd(), "node_modules", ".bin", "okx-trade-mcp"),
|
|
8116
8405
|
// Monorepo workspace (e.g. running from source)
|
|
8117
|
-
|
|
8406
|
+
path4.join(__dirname, "..", "..", "..", "..", "mcp", "dist", "index.js")
|
|
8118
8407
|
];
|
|
8119
8408
|
for (const candidate of candidates) {
|
|
8120
8409
|
try {
|
|
8121
|
-
|
|
8410
|
+
fs5.accessSync(candidate, fs5.constants.X_OK | fs5.constants.R_OK);
|
|
8122
8411
|
entryPath = candidate;
|
|
8123
8412
|
break;
|
|
8124
8413
|
} catch (_e) {
|
|
@@ -8143,9 +8432,9 @@ var CLIENT_LIMITS = {
|
|
|
8143
8432
|
cursor: { perServer: 40, total: 80 }
|
|
8144
8433
|
};
|
|
8145
8434
|
function checkJsonMcpConfig(configPath) {
|
|
8146
|
-
if (!
|
|
8435
|
+
if (!fs5.existsSync(configPath)) return "missing";
|
|
8147
8436
|
try {
|
|
8148
|
-
const raw =
|
|
8437
|
+
const raw = fs5.readFileSync(configPath, "utf8");
|
|
8149
8438
|
const parsed = JSON.parse(raw);
|
|
8150
8439
|
const mcpServers = parsed["mcpServers"];
|
|
8151
8440
|
if (!mcpServers) return "not-configured";
|
|
@@ -8163,15 +8452,15 @@ function checkJsonMcpConfig(configPath) {
|
|
|
8163
8452
|
}
|
|
8164
8453
|
}
|
|
8165
8454
|
function checkClaudeCodeConfig() {
|
|
8166
|
-
const home =
|
|
8455
|
+
const home = os4.homedir();
|
|
8167
8456
|
const candidates = [
|
|
8168
|
-
|
|
8169
|
-
|
|
8457
|
+
path4.join(home, ".claude", "settings.json"),
|
|
8458
|
+
path4.join(home, ".claude.json")
|
|
8170
8459
|
];
|
|
8171
8460
|
let anyFound = false;
|
|
8172
8461
|
let anyParseError = false;
|
|
8173
8462
|
for (const cfgPath of candidates) {
|
|
8174
|
-
if (!
|
|
8463
|
+
if (!fs5.existsSync(cfgPath)) continue;
|
|
8175
8464
|
anyFound = true;
|
|
8176
8465
|
const result = checkJsonMcpConfig(cfgPath);
|
|
8177
8466
|
if (result === "found") return "found";
|
|
@@ -8188,8 +8477,8 @@ function handleJsonClient(clientId, report, configuredClients) {
|
|
|
8188
8477
|
const status = checkJsonMcpConfig(configPath);
|
|
8189
8478
|
if (status === "missing") return false;
|
|
8190
8479
|
if (status === "found") {
|
|
8191
|
-
ok(name, `configured (${
|
|
8192
|
-
report.add(`client_${clientId}`, `OK ${
|
|
8480
|
+
ok(name, `configured (${sanitize2(configPath)})`);
|
|
8481
|
+
report.add(`client_${clientId}`, `OK ${sanitize2(configPath)}`);
|
|
8193
8482
|
configuredClients.push(clientId);
|
|
8194
8483
|
return false;
|
|
8195
8484
|
}
|
|
@@ -8197,8 +8486,8 @@ function handleJsonClient(clientId, report, configuredClients) {
|
|
|
8197
8486
|
fail(name, "okx-trade-mcp not found in mcpServers", [`Run: okx setup --client ${clientId}`]);
|
|
8198
8487
|
report.add(`client_${clientId}`, "NOT_CONFIGURED");
|
|
8199
8488
|
} else {
|
|
8200
|
-
fail(name, `JSON parse error in ${
|
|
8201
|
-
`Check ${
|
|
8489
|
+
fail(name, `JSON parse error in ${sanitize2(configPath)}`, [
|
|
8490
|
+
`Check ${sanitize2(configPath)} for JSON syntax errors`,
|
|
8202
8491
|
`Then run: okx setup --client ${clientId}`
|
|
8203
8492
|
]);
|
|
8204
8493
|
report.add(`client_${clientId}`, "PARSE_ERROR");
|
|
@@ -8291,37 +8580,37 @@ function checkToolCount(report, configuredClients, getSpecs = allToolSpecs) {
|
|
|
8291
8580
|
}
|
|
8292
8581
|
}
|
|
8293
8582
|
function readLogTail(logPath) {
|
|
8294
|
-
const stat =
|
|
8583
|
+
const stat = fs5.statSync(logPath);
|
|
8295
8584
|
const readSize = Math.min(8192, stat.size);
|
|
8296
8585
|
const buffer = Buffer.alloc(readSize);
|
|
8297
|
-
const fd =
|
|
8586
|
+
const fd = fs5.openSync(logPath, "r");
|
|
8298
8587
|
try {
|
|
8299
|
-
|
|
8588
|
+
fs5.readSync(fd, buffer, 0, readSize, Math.max(0, stat.size - readSize));
|
|
8300
8589
|
} finally {
|
|
8301
|
-
|
|
8590
|
+
fs5.closeSync(fd);
|
|
8302
8591
|
}
|
|
8303
8592
|
return buffer.toString("utf8").split("\n").filter((l) => l.trim()).slice(-5);
|
|
8304
8593
|
}
|
|
8305
8594
|
function getMcpLogCandidates() {
|
|
8306
8595
|
if (process.platform === "darwin") {
|
|
8307
|
-
const logsDir =
|
|
8596
|
+
const logsDir = path4.join(os4.homedir(), "Library", "Logs", "Claude");
|
|
8308
8597
|
const candidates = [
|
|
8309
|
-
|
|
8310
|
-
|
|
8598
|
+
path4.join(logsDir, "mcp.log"),
|
|
8599
|
+
path4.join(logsDir, "mcp-server-okx-trade-mcp.log")
|
|
8311
8600
|
];
|
|
8312
8601
|
try {
|
|
8313
|
-
const extra =
|
|
8602
|
+
const extra = fs5.readdirSync(logsDir).filter((f) => f.startsWith("mcp") && f.endsWith(".log")).map((f) => path4.join(logsDir, f));
|
|
8314
8603
|
candidates.push(...extra);
|
|
8315
8604
|
} catch (_e) {
|
|
8316
8605
|
}
|
|
8317
8606
|
return candidates;
|
|
8318
8607
|
}
|
|
8319
8608
|
if (process.platform === "win32") {
|
|
8320
|
-
const appData2 = process.env.APPDATA ??
|
|
8321
|
-
return [
|
|
8609
|
+
const appData2 = process.env.APPDATA ?? path4.join(os4.homedir(), "AppData", "Roaming");
|
|
8610
|
+
return [path4.join(appData2, "Claude", "logs", "mcp.log")];
|
|
8322
8611
|
}
|
|
8323
|
-
const configHome = process.env.XDG_CONFIG_HOME ??
|
|
8324
|
-
return [
|
|
8612
|
+
const configHome = process.env.XDG_CONFIG_HOME ?? path4.join(os4.homedir(), ".config");
|
|
8613
|
+
return [path4.join(configHome, "Claude", "logs", "mcp.log")];
|
|
8325
8614
|
}
|
|
8326
8615
|
function checkMcpLogs(report) {
|
|
8327
8616
|
section("MCP Server Logs (recent)");
|
|
@@ -8335,7 +8624,7 @@ function checkMcpLogs(report) {
|
|
|
8335
8624
|
report.add("mcp_log", logPath);
|
|
8336
8625
|
if (lines.length > 0) {
|
|
8337
8626
|
ok("last lines", `(${lines.length} shown)`);
|
|
8338
|
-
for (const line of lines) outputLine(` ${
|
|
8627
|
+
for (const line of lines) outputLine(` ${sanitize2(line)}`);
|
|
8339
8628
|
} else {
|
|
8340
8629
|
ok("last lines", "(empty log)");
|
|
8341
8630
|
}
|
|
@@ -8461,11 +8750,11 @@ function checkModuleLoading(entryPath, report) {
|
|
|
8461
8750
|
return true;
|
|
8462
8751
|
} else {
|
|
8463
8752
|
const errMsg = result.stderr?.trim() || result.error?.message || "non-zero exit";
|
|
8464
|
-
fail("module load", `failed: ${
|
|
8753
|
+
fail("module load", `failed: ${sanitize2(errMsg)}`, [
|
|
8465
8754
|
"MCP server may have import errors or missing dependencies",
|
|
8466
8755
|
`Try: node ${entryPath} --version`
|
|
8467
8756
|
]);
|
|
8468
|
-
report.add("module_load", `FAIL ${
|
|
8757
|
+
report.add("module_load", `FAIL ${sanitize2(errMsg)}`);
|
|
8469
8758
|
return false;
|
|
8470
8759
|
}
|
|
8471
8760
|
}
|
|
@@ -8476,7 +8765,7 @@ async function cmdDiagnoseMcp(options = {}) {
|
|
|
8476
8765
|
const report = new Report();
|
|
8477
8766
|
report.add("ts", (/* @__PURE__ */ new Date()).toISOString());
|
|
8478
8767
|
report.add("mode", "mcp");
|
|
8479
|
-
report.add("os", `${process.platform} ${process.arch} ${
|
|
8768
|
+
report.add("os", `${process.platform} ${process.arch} ${os4.release()}`);
|
|
8480
8769
|
checkMcpPackageVersion(report);
|
|
8481
8770
|
const nodePassed = checkNodeCompat(report);
|
|
8482
8771
|
const { entryPath, passed: entryPassed } = checkMcpEntryPoint(report);
|
|
@@ -8508,7 +8797,7 @@ async function cmdDiagnoseMcp(options = {}) {
|
|
|
8508
8797
|
|
|
8509
8798
|
// src/commands/diagnose.ts
|
|
8510
8799
|
var CLI_VERSION = readCliVersion();
|
|
8511
|
-
var GIT_HASH = true ? "
|
|
8800
|
+
var GIT_HASH = true ? "0a5911f" : "dev";
|
|
8512
8801
|
function maskKey2(key) {
|
|
8513
8802
|
if (!key) return "(not set)";
|
|
8514
8803
|
if (key.length <= 8) return "****";
|
|
@@ -8588,14 +8877,14 @@ function checkEnvironment(report) {
|
|
|
8588
8877
|
}
|
|
8589
8878
|
ok("CLI", `v${CLI_VERSION} (${GIT_HASH})`);
|
|
8590
8879
|
ok("OS", `${process.platform} ${process.arch}`);
|
|
8591
|
-
ok("OS release",
|
|
8880
|
+
ok("OS release", os5.release());
|
|
8592
8881
|
ok("Shell", process.env.SHELL ?? "(unknown)");
|
|
8593
8882
|
ok("Locale", `${process.env.LANG ?? process.env.LC_ALL ?? "(unknown)"}`);
|
|
8594
8883
|
ok("Timezone", Intl.DateTimeFormat().resolvedOptions().timeZone);
|
|
8595
8884
|
report.add("cli", `${CLI_VERSION} (${GIT_HASH})`);
|
|
8596
8885
|
report.add("node", `${nodeVersion} ${process.platform} ${process.arch}`);
|
|
8597
|
-
const machine = typeof
|
|
8598
|
-
report.add("os", `${
|
|
8886
|
+
const machine = typeof os5.machine === "function" ? os5.machine() : process.arch;
|
|
8887
|
+
report.add("os", `${os5.type()} ${os5.release()} ${machine}`);
|
|
8599
8888
|
report.add("shell", process.env.SHELL ?? "-");
|
|
8600
8889
|
report.add("locale", process.env.LANG ?? process.env.LC_ALL ?? "-");
|
|
8601
8890
|
report.add("tz", Intl.DateTimeFormat().resolvedOptions().timeZone);
|
|
@@ -8752,10 +9041,10 @@ async function cmdDiagnose(config, profile, options = {}) {
|
|
|
8752
9041
|
}
|
|
8753
9042
|
function checkConfigFile(report) {
|
|
8754
9043
|
section("Config File");
|
|
8755
|
-
const
|
|
9044
|
+
const path6 = configFilePath();
|
|
8756
9045
|
try {
|
|
8757
9046
|
readFullConfig();
|
|
8758
|
-
ok("Config parse", `${
|
|
9047
|
+
ok("Config parse", `${path6} OK`);
|
|
8759
9048
|
report.add("config_parse", "OK");
|
|
8760
9049
|
return true;
|
|
8761
9050
|
} catch (e) {
|
|
@@ -8925,7 +9214,7 @@ function loadProfileConfig(opts) {
|
|
|
8925
9214
|
import { EOL as EOL2 } from "os";
|
|
8926
9215
|
|
|
8927
9216
|
// src/commands/client-setup.ts
|
|
8928
|
-
import * as
|
|
9217
|
+
import * as fs6 from "fs";
|
|
8929
9218
|
var DETECTABLE_CLIENTS = ["claude-desktop", "cursor", "windsurf"];
|
|
8930
9219
|
function cmdSetupClient(options) {
|
|
8931
9220
|
runSetup(options);
|
|
@@ -8934,14 +9223,14 @@ function cmdSetupClients() {
|
|
|
8934
9223
|
const detected = [];
|
|
8935
9224
|
for (const id of DETECTABLE_CLIENTS) {
|
|
8936
9225
|
const p = getConfigPath(id);
|
|
8937
|
-
if (p &&
|
|
9226
|
+
if (p && fs6.existsSync(p)) {
|
|
8938
9227
|
detected.push({ id, path: p });
|
|
8939
9228
|
}
|
|
8940
9229
|
}
|
|
8941
9230
|
if (detected.length > 0) {
|
|
8942
9231
|
outputLine("Detected clients:");
|
|
8943
|
-
for (const { id, path:
|
|
8944
|
-
outputLine(` ${id.padEnd(16)} ${
|
|
9232
|
+
for (const { id, path: path6 } of detected) {
|
|
9233
|
+
outputLine(` ${id.padEnd(16)} ${path6}`);
|
|
8945
9234
|
}
|
|
8946
9235
|
outputLine("");
|
|
8947
9236
|
}
|
|
@@ -9325,7 +9614,7 @@ var HELP_TREE = {
|
|
|
9325
9614
|
description: "Earn products \u2014 Simple Earn, On-chain Earn, and DCD (Dual Currency Deposit)",
|
|
9326
9615
|
subgroups: {
|
|
9327
9616
|
savings: {
|
|
9328
|
-
description: "Simple Earn \u2014 flexible savings and lending",
|
|
9617
|
+
description: "Simple Earn \u2014 flexible savings, fixed-term, and lending",
|
|
9329
9618
|
commands: {
|
|
9330
9619
|
balance: {
|
|
9331
9620
|
usage: "okx earn savings balance [<ccy>]",
|
|
@@ -9349,7 +9638,19 @@ var HELP_TREE = {
|
|
|
9349
9638
|
},
|
|
9350
9639
|
"rate-history": {
|
|
9351
9640
|
usage: "okx earn savings rate-history [--ccy <ccy>] [--limit <n>]",
|
|
9352
|
-
description: "Query Simple Earn lending rates (
|
|
9641
|
+
description: "Query Simple Earn lending rates and fixed-term offers (requires auth)"
|
|
9642
|
+
},
|
|
9643
|
+
"fixed-orders": {
|
|
9644
|
+
usage: "okx earn savings fixed-orders [--ccy <ccy>] [--state <pending|earning|expired|settled|cancelled>]",
|
|
9645
|
+
description: "List fixed-term earn orders"
|
|
9646
|
+
},
|
|
9647
|
+
"fixed-purchase": {
|
|
9648
|
+
usage: "okx earn savings fixed-purchase --ccy <ccy> --amt <n> --term <term> [--confirm]",
|
|
9649
|
+
description: "Purchase Simple Earn Fixed (\u5B9A\u671F). Preview by default; add --confirm to execute. Funds locked until maturity"
|
|
9650
|
+
},
|
|
9651
|
+
"fixed-redeem": {
|
|
9652
|
+
usage: "okx earn savings fixed-redeem <reqId>",
|
|
9653
|
+
description: "Redeem a fixed-term earn order (full amount)"
|
|
9353
9654
|
}
|
|
9354
9655
|
}
|
|
9355
9656
|
},
|
|
@@ -9529,6 +9830,7 @@ function printGlobalHelp() {
|
|
|
9529
9830
|
" --demo Use simulated trading (demo) mode",
|
|
9530
9831
|
" --live Force live trading mode (overrides profile demo=true; mutually exclusive with --demo)",
|
|
9531
9832
|
" --json Output raw JSON",
|
|
9833
|
+
" --env With --json, wrap output as {env, profile, data}",
|
|
9532
9834
|
" --verbose Show detailed network request/response info (stderr)",
|
|
9533
9835
|
" --version, -v Show version",
|
|
9534
9836
|
" --help Show this help",
|
|
@@ -9643,8 +9945,8 @@ function printCommandList(lines, commands) {
|
|
|
9643
9945
|
lines.push("");
|
|
9644
9946
|
}
|
|
9645
9947
|
}
|
|
9646
|
-
function printHelp(...
|
|
9647
|
-
const [moduleName, subgroupName] =
|
|
9948
|
+
function printHelp(...path6) {
|
|
9949
|
+
const [moduleName, subgroupName] = path6;
|
|
9648
9950
|
if (!moduleName) {
|
|
9649
9951
|
printGlobalHelp();
|
|
9650
9952
|
} else if (!subgroupName) {
|
|
@@ -9660,6 +9962,7 @@ var CLI_OPTIONS = {
|
|
|
9660
9962
|
profile: { type: "string" },
|
|
9661
9963
|
demo: { type: "boolean", default: false },
|
|
9662
9964
|
json: { type: "boolean", default: false },
|
|
9965
|
+
env: { type: "boolean", default: false },
|
|
9663
9966
|
help: { type: "boolean", default: false },
|
|
9664
9967
|
version: { type: "boolean", short: "v", default: false },
|
|
9665
9968
|
// setup command
|
|
@@ -9765,6 +10068,8 @@ var CLI_OPTIONS = {
|
|
|
9765
10068
|
orders: { type: "string" },
|
|
9766
10069
|
// earn
|
|
9767
10070
|
rate: { type: "string" },
|
|
10071
|
+
reqId: { type: "string" },
|
|
10072
|
+
confirm: { type: "boolean", default: false },
|
|
9768
10073
|
// audit
|
|
9769
10074
|
since: { type: "string" },
|
|
9770
10075
|
tool: { type: "string" },
|
|
@@ -10141,9 +10446,9 @@ async function cmdMarketStockTokens(run, opts) {
|
|
|
10141
10446
|
}
|
|
10142
10447
|
|
|
10143
10448
|
// src/commands/account.ts
|
|
10144
|
-
import * as
|
|
10145
|
-
import * as
|
|
10146
|
-
import * as
|
|
10449
|
+
import * as fs7 from "fs";
|
|
10450
|
+
import * as path5 from "path";
|
|
10451
|
+
import * as os6 from "os";
|
|
10147
10452
|
function getData2(result) {
|
|
10148
10453
|
return result.data;
|
|
10149
10454
|
}
|
|
@@ -10354,10 +10659,10 @@ function readAuditLogs(logDir, days = 7) {
|
|
|
10354
10659
|
const yyyy = d.getUTCFullYear();
|
|
10355
10660
|
const mm = String(d.getUTCMonth() + 1).padStart(2, "0");
|
|
10356
10661
|
const dd = String(d.getUTCDate()).padStart(2, "0");
|
|
10357
|
-
const filePath =
|
|
10662
|
+
const filePath = path5.join(logDir, `trade-${yyyy}-${mm}-${dd}.log`);
|
|
10358
10663
|
let content;
|
|
10359
10664
|
try {
|
|
10360
|
-
content =
|
|
10665
|
+
content = fs7.readFileSync(filePath, "utf8");
|
|
10361
10666
|
} catch {
|
|
10362
10667
|
continue;
|
|
10363
10668
|
}
|
|
@@ -10373,7 +10678,7 @@ function readAuditLogs(logDir, days = 7) {
|
|
|
10373
10678
|
return entries;
|
|
10374
10679
|
}
|
|
10375
10680
|
function cmdAccountAudit(opts) {
|
|
10376
|
-
const logDir =
|
|
10681
|
+
const logDir = path5.join(os6.homedir(), ".okx", "logs");
|
|
10377
10682
|
const limit = Math.min(Number(opts.limit) || 20, 100);
|
|
10378
10683
|
let entries = readAuditLogs(logDir);
|
|
10379
10684
|
if (opts.tool) entries = entries.filter((e) => e.tool === opts.tool);
|
|
@@ -11829,6 +12134,22 @@ async function cmdEarnSavingsBalance(run, ccy, json) {
|
|
|
11829
12134
|
pendingAmt: r["pendingAmt"]
|
|
11830
12135
|
}));
|
|
11831
12136
|
}
|
|
12137
|
+
async function cmdEarnFixedOrderList(run, opts) {
|
|
12138
|
+
const data = extractData(await run("earn_get_fixed_order_list", {
|
|
12139
|
+
ccy: opts.ccy,
|
|
12140
|
+
state: opts.state
|
|
12141
|
+
}));
|
|
12142
|
+
printDataList(data, opts.json, "No fixed earn orders", (r) => ({
|
|
12143
|
+
reqId: r["reqId"],
|
|
12144
|
+
ccy: r["ccy"],
|
|
12145
|
+
amt: r["amt"],
|
|
12146
|
+
rate: r["rate"],
|
|
12147
|
+
term: r["term"],
|
|
12148
|
+
state: r["state"],
|
|
12149
|
+
accruedInterest: r["accruedInterest"],
|
|
12150
|
+
cTime: new Date(Number(r["cTime"])).toLocaleString()
|
|
12151
|
+
}));
|
|
12152
|
+
}
|
|
11832
12153
|
async function cmdEarnSavingsPurchase(run, opts) {
|
|
11833
12154
|
const data = extractData(await run("earn_savings_purchase", { ccy: opts.ccy, amt: opts.amt, rate: opts.rate }));
|
|
11834
12155
|
if (opts.json) {
|
|
@@ -11874,14 +12195,107 @@ async function cmdEarnLendingHistory(run, opts) {
|
|
|
11874
12195
|
ts: new Date(Number(r["ts"])).toLocaleString()
|
|
11875
12196
|
}));
|
|
11876
12197
|
}
|
|
12198
|
+
function printFixedPurchasePreview(rec) {
|
|
12199
|
+
const offer = rec["offer"];
|
|
12200
|
+
outputLine("");
|
|
12201
|
+
outputLine("\u{1F4CB} Fixed Earn Purchase Preview");
|
|
12202
|
+
outputLine(` Currency: ${rec["ccy"]}`);
|
|
12203
|
+
outputLine(` Amount: ${rec["amt"]}`);
|
|
12204
|
+
outputLine(` Term: ${rec["term"]}`);
|
|
12205
|
+
if (rec["currentFlexibleRate"]) {
|
|
12206
|
+
outputLine(` Current flexible rate: ${rec["currentFlexibleRate"]}`);
|
|
12207
|
+
}
|
|
12208
|
+
if (offer) {
|
|
12209
|
+
printKv({
|
|
12210
|
+
rate: offer["rate"],
|
|
12211
|
+
minLend: offer["minLend"],
|
|
12212
|
+
remainingQuota: offer["lendQuota"],
|
|
12213
|
+
soldOut: offer["soldOut"] ? "Yes" : "No"
|
|
12214
|
+
});
|
|
12215
|
+
} else {
|
|
12216
|
+
outputLine(" \u26A0\uFE0F No matching offer found for this term.");
|
|
12217
|
+
}
|
|
12218
|
+
outputLine("");
|
|
12219
|
+
outputLine(rec["warning"] ?? "");
|
|
12220
|
+
outputLine("");
|
|
12221
|
+
outputLine("Re-run with --confirm to execute.");
|
|
12222
|
+
}
|
|
12223
|
+
async function cmdEarnFixedPurchase(run, opts) {
|
|
12224
|
+
const result = await run("earn_fixed_purchase", {
|
|
12225
|
+
ccy: opts.ccy,
|
|
12226
|
+
amt: opts.amt,
|
|
12227
|
+
term: opts.term,
|
|
12228
|
+
confirm: opts.confirm
|
|
12229
|
+
});
|
|
12230
|
+
if (!result || typeof result !== "object") {
|
|
12231
|
+
outputLine("No response data");
|
|
12232
|
+
return;
|
|
12233
|
+
}
|
|
12234
|
+
const rec = result;
|
|
12235
|
+
if (rec["preview"]) {
|
|
12236
|
+
if (opts.json) {
|
|
12237
|
+
printJson(rec);
|
|
12238
|
+
return;
|
|
12239
|
+
}
|
|
12240
|
+
printFixedPurchasePreview(rec);
|
|
12241
|
+
return;
|
|
12242
|
+
}
|
|
12243
|
+
const data = extractData(result);
|
|
12244
|
+
if (opts.json) {
|
|
12245
|
+
printJson(data);
|
|
12246
|
+
return;
|
|
12247
|
+
}
|
|
12248
|
+
const r = data[0];
|
|
12249
|
+
if (!r) {
|
|
12250
|
+
outputLine("No response data");
|
|
12251
|
+
return;
|
|
12252
|
+
}
|
|
12253
|
+
printKv({ reqId: r["reqId"], ccy: r["ccy"], amt: r["amt"], term: r["term"] });
|
|
12254
|
+
}
|
|
12255
|
+
async function cmdEarnFixedRedeem(run, opts) {
|
|
12256
|
+
const data = extractData(await run("earn_fixed_redeem", { reqId: opts.reqId }));
|
|
12257
|
+
if (opts.json) {
|
|
12258
|
+
printJson(data);
|
|
12259
|
+
return;
|
|
12260
|
+
}
|
|
12261
|
+
if (!data.length) {
|
|
12262
|
+
outputLine("No response data");
|
|
12263
|
+
return;
|
|
12264
|
+
}
|
|
12265
|
+
printTable(data.map((r) => ({ reqId: r["reqId"] })));
|
|
12266
|
+
}
|
|
11877
12267
|
async function cmdEarnLendingRateHistory(run, opts) {
|
|
11878
|
-
const
|
|
11879
|
-
|
|
12268
|
+
const result = await run("earn_get_lending_rate_history", { ccy: opts.ccy, limit: opts.limit });
|
|
12269
|
+
const data = extractData(result);
|
|
12270
|
+
const fixedOffers = extractFixedOffers(result);
|
|
12271
|
+
if (opts.json) {
|
|
12272
|
+
printJson({ data, fixedOffers });
|
|
12273
|
+
return;
|
|
12274
|
+
}
|
|
12275
|
+
printDataList(data, false, "No rate history data", (r) => ({
|
|
11880
12276
|
ccy: r["ccy"],
|
|
11881
12277
|
lendingRate: r["lendingRate"],
|
|
11882
|
-
rate: r["rate"],
|
|
11883
12278
|
ts: new Date(Number(r["ts"])).toLocaleString()
|
|
11884
12279
|
}));
|
|
12280
|
+
if (fixedOffers.length > 0) {
|
|
12281
|
+
outputLine("");
|
|
12282
|
+
outputLine("Fixed-term offers:");
|
|
12283
|
+
printTable(fixedOffers.map((r) => ({
|
|
12284
|
+
ccy: r["ccy"],
|
|
12285
|
+
term: r["term"],
|
|
12286
|
+
rate: r["rate"],
|
|
12287
|
+
minLend: r["minLend"],
|
|
12288
|
+
remainingQuota: r["lendQuota"],
|
|
12289
|
+
soldOut: r["soldOut"] ? "Yes" : "No"
|
|
12290
|
+
})));
|
|
12291
|
+
}
|
|
12292
|
+
}
|
|
12293
|
+
function extractFixedOffers(result) {
|
|
12294
|
+
if (result && typeof result === "object") {
|
|
12295
|
+
const offers = result["fixedOffers"];
|
|
12296
|
+
if (Array.isArray(offers)) return offers;
|
|
12297
|
+
}
|
|
12298
|
+
return [];
|
|
11885
12299
|
}
|
|
11886
12300
|
|
|
11887
12301
|
// src/commands/auto-earn.ts
|
|
@@ -12716,7 +13130,7 @@ function printSkillInstallResult(meta, json) {
|
|
|
12716
13130
|
// src/index.ts
|
|
12717
13131
|
var _require3 = createRequire3(import.meta.url);
|
|
12718
13132
|
var CLI_VERSION2 = _require3("../package.json").version;
|
|
12719
|
-
var GIT_HASH2 = true ? "
|
|
13133
|
+
var GIT_HASH2 = true ? "0a5911f" : "dev";
|
|
12720
13134
|
function handleConfigCommand(action, rest, json, lang, force) {
|
|
12721
13135
|
if (action === "init") return cmdConfigInit(lang === "zh" ? "zh" : "en");
|
|
12722
13136
|
if (action === "show") return cmdConfigShow(json);
|
|
@@ -13416,6 +13830,9 @@ function handleEarnSavingsCommand(run, action, rest, v, json) {
|
|
|
13416
13830
|
if (action === "set-rate") return cmdEarnSetLendingRate(run, { ccy: v.ccy, rate: v.rate, json });
|
|
13417
13831
|
if (action === "lending-history") return cmdEarnLendingHistory(run, { ccy: v.ccy, limit, json });
|
|
13418
13832
|
if (action === "rate-history") return cmdEarnLendingRateHistory(run, { ccy: v.ccy, limit, json });
|
|
13833
|
+
if (action === "fixed-orders") return cmdEarnFixedOrderList(run, { ccy: v.ccy, state: v.state, json });
|
|
13834
|
+
if (action === "fixed-purchase") return cmdEarnFixedPurchase(run, { ccy: v.ccy, amt: v.amt, term: v.term, confirm: v.confirm ?? false, json });
|
|
13835
|
+
if (action === "fixed-redeem") return cmdEarnFixedRedeem(run, { reqId: v.reqId, json });
|
|
13419
13836
|
errorLine(`Unknown earn savings command: ${action}`);
|
|
13420
13837
|
process.exitCode = 1;
|
|
13421
13838
|
}
|
|
@@ -13534,6 +13951,23 @@ function printHelpForLevel(positionals) {
|
|
|
13534
13951
|
else if (!subgroup) printHelp(module);
|
|
13535
13952
|
else printHelp(module, subgroup);
|
|
13536
13953
|
}
|
|
13954
|
+
function wrapRunnerWithLogger(baseRunner, logger) {
|
|
13955
|
+
const writeToolNames = new Set(allToolSpecs().filter((t) => t.isWrite).map((t) => t.name));
|
|
13956
|
+
return async (toolName, args) => {
|
|
13957
|
+
const startTime = Date.now();
|
|
13958
|
+
try {
|
|
13959
|
+
const result = await baseRunner(toolName, args);
|
|
13960
|
+
if (writeToolNames.has(toolName)) {
|
|
13961
|
+
markFailedIfSCodeError(result.data);
|
|
13962
|
+
}
|
|
13963
|
+
logger.log("info", toolName, args, result, Date.now() - startTime);
|
|
13964
|
+
return result;
|
|
13965
|
+
} catch (error) {
|
|
13966
|
+
logger.log("error", toolName, args, error, Date.now() - startTime);
|
|
13967
|
+
throw error;
|
|
13968
|
+
}
|
|
13969
|
+
};
|
|
13970
|
+
}
|
|
13537
13971
|
async function runDiagnose(v) {
|
|
13538
13972
|
let config;
|
|
13539
13973
|
try {
|
|
@@ -13566,16 +14000,11 @@ async function main() {
|
|
|
13566
14000
|
if (module === "diagnose") return runDiagnose(v);
|
|
13567
14001
|
const config = loadProfileConfig({ profile: v.profile, demo: v.demo, live: v.live, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
|
|
13568
14002
|
setEnvContext({ demo: config.demo, profile: v.profile ?? "default" });
|
|
14003
|
+
setJsonEnvEnabled(v.env ?? false);
|
|
13569
14004
|
const client = new OkxRestClient(config);
|
|
13570
14005
|
const baseRunner = createToolRunner(client, config);
|
|
13571
|
-
const
|
|
13572
|
-
const run =
|
|
13573
|
-
const result = await baseRunner(toolName, args);
|
|
13574
|
-
if (writeToolNames.has(toolName)) {
|
|
13575
|
-
markFailedIfSCodeError(result.data);
|
|
13576
|
-
}
|
|
13577
|
-
return result;
|
|
13578
|
-
};
|
|
14006
|
+
const logger = new TradeLogger("info");
|
|
14007
|
+
const run = wrapRunnerWithLogger(baseRunner, logger);
|
|
13579
14008
|
const moduleHandlers = {
|
|
13580
14009
|
market: () => handleMarketCommand(run, action, rest, v, json),
|
|
13581
14010
|
account: () => handleAccountCommand(run, action, rest, v, json),
|
|
@@ -13620,7 +14049,8 @@ export {
|
|
|
13620
14049
|
handleSpotCommand,
|
|
13621
14050
|
handleSwapAlgoCommand,
|
|
13622
14051
|
handleSwapCommand,
|
|
13623
|
-
printHelp
|
|
14052
|
+
printHelp,
|
|
14053
|
+
wrapRunnerWithLogger
|
|
13624
14054
|
};
|
|
13625
14055
|
/*! Bundled license information:
|
|
13626
14056
|
|