@liquiditytech/rapidx-cli 1.0.31 → 1.0.33
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/cli/commands/account.js +15 -12
- package/dist/cli/commands/algo.js +3 -2
- package/dist/cli/commands/index.js +6 -6
- package/dist/cli/commands/order.js +2 -2
- package/dist/cli/commands/position.js +3 -1
- package/dist/cli/commands/update.js +3 -0
- package/dist/cli/help.js +1 -1
- package/dist/core/client/capability-executor.js +109 -32
- package/dist/core/client/rapid-x-client.js +6 -32
- package/dist/core/contracts/capabilities.js +18 -10
- package/dist/core/contracts/compatibility.js +1 -1
- package/dist/core/contracts/input-schema.js +40 -14
- package/dist/core/safety/policy.js +9 -5
- package/dist/core/self-check/live-read-only-probes.js +4 -4
- package/dist/core/self-check/live-trading-verification-probes.js +3 -3
- package/dist/core/trading/preview-preflight.js +3 -3
- package/dist/core/trading/preview.js +2 -2
- package/dist/core/trading/trading-verification.js +8 -8
- package/dist/core/update/check-update.js +77 -10
- package/dist/core/version.js +1 -1
- package/dist/mcp/tool-runner.js +5 -2
- package/package.json +1 -1
- package/packages/distribution/docs/cli.md +36 -11
- package/packages/distribution/docs/mcp.md +4 -4
- package/packages/distribution/docs/quickstart.md +5 -5
- package/packages/distribution/docs/self-check.md +1 -1
- package/packages/distribution/docs/skills.md +1 -1
- package/packages/distribution/docs/tools.md +16 -14
- package/packages/distribution/docs/trading-verification.md +1 -1
- package/packages/distribution/manifests/offline-manifest.json +4 -4
- package/packages/distribution/registry/rapidx.mcp.json +1 -1
|
@@ -85,13 +85,24 @@ const targetCapabilityIdSchema = {
|
|
|
85
85
|
};
|
|
86
86
|
const orderIdSchema = {
|
|
87
87
|
type: "string",
|
|
88
|
-
description: "RapidX order id returned by order.place, order.
|
|
88
|
+
description: "RapidX order id returned by order.place, order.open-orders, or order.query.",
|
|
89
89
|
examples: ["2173374713391199"]
|
|
90
90
|
};
|
|
91
|
-
const
|
|
91
|
+
const exchangeTypeSchema = { type: "string", description: "RapidX exchange type, for example BINANCE or OKX." };
|
|
92
|
+
const businessTypeSchema = { type: "string", description: "RapidX business type, for example PERP." };
|
|
93
|
+
const pageSchema = { type: "number", description: "1-based page number." };
|
|
94
|
+
const pageSizeSchema = { type: "number", description: "Page size." };
|
|
95
|
+
const startTimeSchema = { type: "string", description: "Start timestamp accepted by the RapidX API." };
|
|
96
|
+
const endTimeSchema = { type: "string", description: "End timestamp accepted by the RapidX API." };
|
|
97
|
+
const coinSchema = { type: "string", description: "Asset coin, for example USDT." };
|
|
98
|
+
const statementTypeSchema = { type: "string", description: "RapidX statement type filter." };
|
|
99
|
+
const filterExecutedSchema = { type: "boolean", description: "Whether to filter executed order history where the endpoint supports it." };
|
|
100
|
+
const closeAllPositionsSchema = { type: "boolean", description: "When true, requests RapidX to close all positions allowed by the provided filters." };
|
|
101
|
+
const symbolListSchema = { type: "string", description: "Comma-separated RapidX symbols for close-all position requests." };
|
|
102
|
+
const closeAllPositionSideSchema = {
|
|
92
103
|
type: "string",
|
|
93
|
-
enum: ["
|
|
94
|
-
description: "
|
|
104
|
+
enum: ["LONG", "SHORT", "NONE"],
|
|
105
|
+
description: "Position side for close-all. Use NONE only when the RapidX close-all endpoint accepts it for one-way mode."
|
|
95
106
|
};
|
|
96
107
|
const positionSideSchema = {
|
|
97
108
|
type: "string",
|
|
@@ -114,8 +125,10 @@ export function inputSchemaForName(name) {
|
|
|
114
125
|
return objectSchema({ symbol: symbolSchema, depth: numberSchema }, ["symbol"]);
|
|
115
126
|
case "KlinesInput":
|
|
116
127
|
return objectSchema({ symbol: symbolSchema, interval: stringSchema, limit: numberSchema }, ["symbol"]);
|
|
117
|
-
case "
|
|
118
|
-
return objectSchema({
|
|
128
|
+
case "PortfolioAssetsInput":
|
|
129
|
+
return objectSchema({ exchangeType: exchangeTypeSchema, page: pageSchema, pageSize: pageSizeSchema });
|
|
130
|
+
case "PositionBracketInput":
|
|
131
|
+
return objectSchema({ symbol: symbolSchema }, ["symbol"]);
|
|
119
132
|
case "OrderLookupInput":
|
|
120
133
|
return {
|
|
121
134
|
...objectSchema({ orderId: orderIdSchema, clientOrderId: clientOrderIdSchema, symbol: symbolSchema }),
|
|
@@ -123,12 +136,16 @@ export function inputSchemaForName(name) {
|
|
|
123
136
|
};
|
|
124
137
|
case "OrderListInput":
|
|
125
138
|
case "OrderHistoryInput":
|
|
126
|
-
return objectSchema({ symbol: symbolSchema, pageSize:
|
|
139
|
+
return objectSchema({ symbol: symbolSchema, exchange: stringSchema, businessType: businessTypeSchema, page: pageSchema, pageSize: pageSizeSchema, startTime: startTimeSchema, endTime: endTimeSchema, filterExecuted: filterExecutedSchema });
|
|
140
|
+
case "ExecutionListInput":
|
|
141
|
+
return objectSchema({ orderId: orderIdSchema, symbol: symbolSchema, exchange: stringSchema, businessType: businessTypeSchema, limit: numberSchema, startTime: startTimeSchema, endTime: endTimeSchema });
|
|
142
|
+
case "StatementInput":
|
|
143
|
+
return objectSchema({ coin: coinSchema, symbol: symbolSchema, statementType: statementTypeSchema, exchange: stringSchema, page: pageSchema, pageSize: pageSizeSchema, startTime: startTimeSchema, endTime: endTimeSchema });
|
|
127
144
|
case "PositionListInput":
|
|
128
145
|
case "AlgoListInput":
|
|
129
|
-
return objectSchema({ symbol: symbolSchema });
|
|
146
|
+
return objectSchema({ symbol: symbolSchema, exchange: stringSchema, businessType: businessTypeSchema, page: pageSchema, pageSize: pageSizeSchema, startTime: startTimeSchema, endTime: endTimeSchema });
|
|
130
147
|
case "PositionHistoryInput":
|
|
131
|
-
return objectSchema({ symbol: symbolSchema, pageSize:
|
|
148
|
+
return objectSchema({ symbol: symbolSchema, pageSize: pageSizeSchema, startTime: startTimeSchema, endTime: endTimeSchema });
|
|
132
149
|
case "TradePreviewInput":
|
|
133
150
|
return objectSchema({
|
|
134
151
|
targetCapabilityId: targetCapabilityIdSchema,
|
|
@@ -184,7 +201,7 @@ export function inputSchemaForName(name) {
|
|
|
184
201
|
]),
|
|
185
202
|
oneOf: [{ required: ["quantity"] }, { required: ["amount"] }]
|
|
186
203
|
};
|
|
187
|
-
case "
|
|
204
|
+
case "ReplaceOrderPreviewInput":
|
|
188
205
|
return {
|
|
189
206
|
...objectSchema({ orderId: orderIdSchema, clientOrderId: clientOrderIdSchema, price: priceSchema, quantity: quantitySchema, ...automationProperties(), ...compatibilityProperties() }),
|
|
190
207
|
allOf: [
|
|
@@ -197,7 +214,7 @@ export function inputSchemaForName(name) {
|
|
|
197
214
|
...objectSchema({ orderId: orderIdSchema, clientOrderId: clientOrderIdSchema, ...automationProperties(), ...compatibilityProperties() }),
|
|
198
215
|
anyOf: [{ required: ["orderId"] }, { required: ["clientOrderId"] }]
|
|
199
216
|
};
|
|
200
|
-
case "
|
|
217
|
+
case "ReplaceOrderInput":
|
|
201
218
|
return {
|
|
202
219
|
...objectSchema({ orderId: orderIdSchema, clientOrderId: clientOrderIdSchema, price: priceSchema, quantity: quantitySchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["previewId", "continueConsentId"]),
|
|
203
220
|
allOf: [
|
|
@@ -210,10 +227,14 @@ export function inputSchemaForName(name) {
|
|
|
210
227
|
...objectSchema({ orderId: orderIdSchema, clientOrderId: clientOrderIdSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["previewId", "continueConsentId"]),
|
|
211
228
|
anyOf: [{ required: ["orderId"] }, { required: ["clientOrderId"] }]
|
|
212
229
|
};
|
|
230
|
+
case "CancelAllOrdersInput":
|
|
231
|
+
return objectSchema({ exchangeType: exchangeTypeSchema, symbol: symbolSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["previewId", "continueConsentId"]);
|
|
213
232
|
case "ClosePositionInput":
|
|
214
233
|
return objectSchema({ symbol: symbolSchema, positionSide: positionSideSchema, reduceOnly: closePositionReduceOnlySchema, maxNotional: maxNotionalSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["symbol", "reduceOnly", "maxNotional", "previewId", "continueConsentId"]);
|
|
234
|
+
case "CloseAllPositionsInput":
|
|
235
|
+
return objectSchema({ symbolList: symbolListSchema, positionSide: closeAllPositionSideSchema, closeAllPositions: closeAllPositionsSchema, exchangeType: exchangeTypeSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["previewId", "continueConsentId"]);
|
|
215
236
|
case "SetLeverageInput":
|
|
216
|
-
return objectSchema({ symbol: symbolSchema, leverage: numberSchema,
|
|
237
|
+
return objectSchema({ symbol: symbolSchema, leverage: numberSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["symbol", "leverage", "previewId", "continueConsentId"]);
|
|
217
238
|
case "SetPositionModeInput":
|
|
218
239
|
return objectSchema({ mode: { type: "string", enum: ["BOTH", "NET"] }, exchange: stringSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["mode", "exchange", "previewId", "continueConsentId"]);
|
|
219
240
|
case "AlgoPlaceInput":
|
|
@@ -242,7 +263,7 @@ export function inputSchemaForName(name) {
|
|
|
242
263
|
]),
|
|
243
264
|
anyOf: [{ required: ["quantity"] }, { required: ["amount"] }, { required: ["conditionType"] }]
|
|
244
265
|
};
|
|
245
|
-
case "
|
|
266
|
+
case "AlgoReplaceInput":
|
|
246
267
|
return objectSchema({
|
|
247
268
|
algoOrderId: stringSchema,
|
|
248
269
|
clientOrderId: clientOrderIdSchema,
|
|
@@ -257,6 +278,11 @@ export function inputSchemaForName(name) {
|
|
|
257
278
|
}, ["previewId", "continueConsentId"]);
|
|
258
279
|
case "AlgoCancelInput":
|
|
259
280
|
return objectSchema({ algoOrderId: stringSchema, clientOrderId: clientOrderIdSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["previewId", "continueConsentId"]);
|
|
281
|
+
case "AlgoLookupInput":
|
|
282
|
+
return {
|
|
283
|
+
...objectSchema({ algoOrderId: stringSchema, clientOrderId: clientOrderIdSchema, attachedOrderId: stringSchema }),
|
|
284
|
+
anyOf: [{ required: ["algoOrderId"] }, { required: ["clientOrderId"] }, { required: ["attachedOrderId"] }]
|
|
285
|
+
};
|
|
260
286
|
case "TradingVerificationInput":
|
|
261
287
|
return objectSchema({
|
|
262
288
|
symbol: symbolSchema,
|
|
@@ -279,7 +305,7 @@ export function inputSchemaForName(name) {
|
|
|
279
305
|
case "InvocationCheckInput":
|
|
280
306
|
return objectSchema({ commandLine: stringSchema, preflightError: stringSchema });
|
|
281
307
|
case "UpdateCheckInput":
|
|
282
|
-
return objectSchema({ force: booleanSchema, manifestUrl: stringSchema, maxCacheAgeSeconds: numberSchema });
|
|
308
|
+
return objectSchema({ force: booleanSchema, manifestUrl: stringSchema, maxCacheAgeSeconds: numberSchema, installedSkillsVersion: stringSchema });
|
|
283
309
|
case "SchemaQuery":
|
|
284
310
|
return objectSchema({ consumer: stringSchema, consumerVersion: stringSchema, includeExamples: booleanSchema });
|
|
285
311
|
case "SelfCheckInput":
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { buildCompatibilityReport } from "../contracts/compatibility.js";
|
|
3
3
|
import { ProductError } from "../errors/product-error.js";
|
|
4
|
-
const TRADING_DOMAINS = new Set(["
|
|
4
|
+
const TRADING_DOMAINS = new Set(["portfolio", "order", "position", "algo"]);
|
|
5
5
|
export function defaultSafetyPolicy() {
|
|
6
6
|
const policy = {
|
|
7
7
|
readOnly: process.env.RAPIDX_READ_ONLY === "true",
|
|
@@ -72,7 +72,7 @@ export function evaluateSafety(capability, input, policy, state = makeSafetyStat
|
|
|
72
72
|
return { allowed: false, code: "RCORE00001", reason: "leverage must be an integer from 1 to 125.", paramsHash };
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
if (capability.capabilityId === "
|
|
75
|
+
if (capability.capabilityId === "portfolio.set-position-mode") {
|
|
76
76
|
const mode = String(input.mode ?? "");
|
|
77
77
|
if (mode !== "BOTH" && mode !== "NET") {
|
|
78
78
|
return { allowed: false, code: "RCORE00001", reason: "mode must be BOTH or NET.", paramsHash };
|
|
@@ -124,7 +124,7 @@ function requiredTradeFields(capability, input) {
|
|
|
124
124
|
requireString(input, "algoType", missing);
|
|
125
125
|
}
|
|
126
126
|
break;
|
|
127
|
-
case "order.
|
|
127
|
+
case "order.replace":
|
|
128
128
|
requireOneOf(input, ["orderId", "clientOrderId"], "orderId or clientOrderId", missing);
|
|
129
129
|
if (!hasString(input, "price") && !hasString(input, "quantity")) {
|
|
130
130
|
missing.push("price or quantity");
|
|
@@ -146,11 +146,15 @@ function requiredTradeFields(capability, input) {
|
|
|
146
146
|
missing.push("leverage");
|
|
147
147
|
}
|
|
148
148
|
break;
|
|
149
|
-
case "
|
|
149
|
+
case "order.cancel-all":
|
|
150
|
+
break;
|
|
151
|
+
case "position.close-all":
|
|
152
|
+
break;
|
|
153
|
+
case "portfolio.set-position-mode":
|
|
150
154
|
requireString(input, "mode", missing);
|
|
151
155
|
requireString(input, "exchange", missing);
|
|
152
156
|
break;
|
|
153
|
-
case "algo.
|
|
157
|
+
case "algo.replace":
|
|
154
158
|
requireOneOf(input, ["algoOrderId", "clientOrderId"], "algoOrderId or clientOrderId", missing);
|
|
155
159
|
break;
|
|
156
160
|
case "algo.cancel":
|
|
@@ -8,10 +8,10 @@ export function buildLiveReadOnlySelfCheck(input = {}) {
|
|
|
8
8
|
const symbol = typeof input.symbol === "string" ? input.symbol : "BINANCE_PERP_BTC_USDT";
|
|
9
9
|
const probes = {
|
|
10
10
|
publicMarket: async () => executeRapidXCapability("market.ticker", { symbol }),
|
|
11
|
-
credentialAuth: async () => executeRapidXCapability("
|
|
12
|
-
accountRead: async () => executeRapidXCapability("
|
|
13
|
-
orderRead: async () => executeRapidXCapability("order.
|
|
14
|
-
positionRead: async () => executeRapidXCapability("position.
|
|
11
|
+
credentialAuth: async () => executeRapidXCapability("portfolio.overview", {}),
|
|
12
|
+
accountRead: async () => executeRapidXCapability("portfolio.assets", {}),
|
|
13
|
+
orderRead: async () => executeRapidXCapability("order.open-orders", {}),
|
|
14
|
+
positionRead: async () => executeRapidXCapability("position.query", {})
|
|
15
15
|
};
|
|
16
16
|
return { credential, probes };
|
|
17
17
|
}
|
|
@@ -77,7 +77,7 @@ async function buildMarketRules(input) {
|
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
79
|
async function queryOrder(order) {
|
|
80
|
-
const result = await executeRapidXCapability("order.
|
|
80
|
+
const result = await executeRapidXCapability("order.query", { orderId: order.orderId });
|
|
81
81
|
const data = extractDataObject(result);
|
|
82
82
|
const requestId = stringField(data, "clientOrderId") ?? order.requestId;
|
|
83
83
|
return {
|
|
@@ -89,8 +89,8 @@ async function queryOrder(order) {
|
|
|
89
89
|
async function cleanupCheck(input) {
|
|
90
90
|
const symbol = typeof input.symbol === "string" ? input.symbol : "BINANCE_PERP_BTC_USDT";
|
|
91
91
|
const [ordersResult, positionsResult] = await Promise.all([
|
|
92
|
-
executeRapidXCapability("order.
|
|
93
|
-
executeRapidXCapability("position.
|
|
92
|
+
executeRapidXCapability("order.open-orders", { symbol, pageSize: 20 }),
|
|
93
|
+
executeRapidXCapability("position.query", { symbol })
|
|
94
94
|
]);
|
|
95
95
|
const orders = extractList(extractDataObject(ordersResult));
|
|
96
96
|
const positions = extractArrayData(positionsResult);
|
|
@@ -11,8 +11,8 @@ export async function runPreviewPreflight(capabilityId, input, options = {}) {
|
|
|
11
11
|
return validateOrderPlacementPreflight(input, options);
|
|
12
12
|
case "order.cancel":
|
|
13
13
|
return validateOrderMutationPreflight(input, "cancel", options);
|
|
14
|
-
case "order.
|
|
15
|
-
return validateOrderMutationPreflight(input, "
|
|
14
|
+
case "order.replace":
|
|
15
|
+
return validateOrderMutationPreflight(input, "replace", options);
|
|
16
16
|
case "position.close":
|
|
17
17
|
return validatePositionClosePreflight(input, options);
|
|
18
18
|
default:
|
|
@@ -50,7 +50,7 @@ async function validateOrderMutationPreflight(input, action, options) {
|
|
|
50
50
|
throw new ProductError({
|
|
51
51
|
code: "RCORE22004",
|
|
52
52
|
status: "BLOCKED",
|
|
53
|
-
message: "ORDER_NOT_FOUND: order.
|
|
53
|
+
message: "ORDER_NOT_FOUND: order.query did not return an order for preview preflight."
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
const state = normalizeOrderState(order.orderState ?? order.state ?? order.status);
|
|
@@ -238,7 +238,7 @@ function makeRequestSummary(capabilityId, params) {
|
|
|
238
238
|
positionSide: params.positionSide
|
|
239
239
|
});
|
|
240
240
|
}
|
|
241
|
-
if (capabilityId === "
|
|
241
|
+
if (capabilityId === "portfolio.set-position-mode") {
|
|
242
242
|
return compactRecord({
|
|
243
243
|
action: "set_position_mode",
|
|
244
244
|
mode: params.mode,
|
|
@@ -274,7 +274,7 @@ function makeRiskNotes(capabilityId, params, automation) {
|
|
|
274
274
|
if (capabilityId === "position.close") {
|
|
275
275
|
notes.push("Do not pass side or quantity for position.close; RapidX determines BUY or SELL from the current position and closes the target symbol/positionSide.");
|
|
276
276
|
notes.push("position.close uses the RapidX close-position API and may execute as a market close with slippage.");
|
|
277
|
-
notes.push("order.
|
|
277
|
+
notes.push("order.query reduceOnly may not reflect the close-position API request; verify final exposure with position.query.");
|
|
278
278
|
}
|
|
279
279
|
return notes;
|
|
280
280
|
}
|
|
@@ -95,18 +95,18 @@ export async function runTradingVerification(rawInput, probes = {}) {
|
|
|
95
95
|
}
|
|
96
96
|
steps.push({ name: "query", status: "PASS", toolOrCommandEvidence: `${queried.orderId}:${queried.status}` });
|
|
97
97
|
let currentOrder = queried;
|
|
98
|
-
if (probes.
|
|
99
|
-
currentOrder = await probes.
|
|
100
|
-
steps.push({ name: "
|
|
98
|
+
if (probes.replaceOrder) {
|
|
99
|
+
currentOrder = await probes.replaceOrder(currentOrder);
|
|
100
|
+
steps.push({ name: "replace", status: currentOrder.status === "UNKNOWN" ? "NOT_VERIFIED" : "PASS", toolOrCommandEvidence: `${currentOrder.orderId}:${currentOrder.status}` });
|
|
101
101
|
if (currentOrder.status === "UNKNOWN") {
|
|
102
|
-
return { submittedRealOrder: true, status: "NOT_VERIFIED", cleanupStatus: "NOT_VERIFIED", steps, previewId: preview.previewId, errorCode: "RCORE23001", errorStage: "
|
|
102
|
+
return { submittedRealOrder: true, status: "NOT_VERIFIED", cleanupStatus: "NOT_VERIFIED", steps, previewId: preview.previewId, errorCode: "RCORE23001", errorStage: "replace", lastObservedOrderState: currentOrder.status };
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
else {
|
|
106
106
|
steps.push({
|
|
107
|
-
name: "
|
|
107
|
+
name: "replace",
|
|
108
108
|
status: "EXPECTED_ERROR",
|
|
109
|
-
toolOrCommandEvidence: "optional verify-live
|
|
109
|
+
toolOrCommandEvidence: "optional verify-live replace check skipped; order.replace remains available outside verify-live"
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
112
|
if (!probes.cancelOrder) {
|
|
@@ -122,7 +122,7 @@ export async function runTradingVerification(rawInput, probes = {}) {
|
|
|
122
122
|
steps.push({ name: "cancel", status: "PASS", toolOrCommandEvidence: cancelConfirmation.evidence });
|
|
123
123
|
if (!probes.cleanupCheck) {
|
|
124
124
|
steps.push({ name: "cleanup-check", status: "NOT_VERIFIED", toolOrCommandEvidence: "cleanupCheck probe missing" });
|
|
125
|
-
return { submittedRealOrder: true, status: "NOT_VERIFIED", cleanupStatus: "NOT_VERIFIED", steps, previewId: preview.previewId, errorCode: "RCORE24002", errorStage: "cleanup-check", recommendedAction: "Query order/
|
|
125
|
+
return { submittedRealOrder: true, status: "NOT_VERIFIED", cleanupStatus: "NOT_VERIFIED", steps, previewId: preview.previewId, errorCode: "RCORE24002", errorStage: "cleanup-check", recommendedAction: "Query order/open-orders and position/query before retrying verify-live." };
|
|
126
126
|
}
|
|
127
127
|
const cleanupConfirmation = await confirmCleanup(currentOrder, probes);
|
|
128
128
|
if (!cleanupConfirmation.confirmed) {
|
|
@@ -254,7 +254,7 @@ function cleanupFailureReport(steps, previewId, errorStage, lastObservedOrderSta
|
|
|
254
254
|
errorStage,
|
|
255
255
|
...(lastObservedOrderState ? { lastObservedOrderState } : {}),
|
|
256
256
|
expectedOrderStates: ["CANCELED", "EXPIRED", "REJECTED"],
|
|
257
|
-
recommendedAction: "Query order/
|
|
257
|
+
recommendedAction: "Query order/query, order/open-orders, and position/query before retrying; do not submit another verification until cleanup is confirmed."
|
|
258
258
|
};
|
|
259
259
|
}
|
|
260
260
|
function quantityForNotional(minNotional, price) {
|
|
@@ -13,11 +13,14 @@ export async function checkForUpdate(input = {}, env = process.env, cwd = proces
|
|
|
13
13
|
const cacheFile = resolveUpdateCacheFile(env, cwd);
|
|
14
14
|
const cached = loadCachedUpdateState(cacheFile);
|
|
15
15
|
if (!input.force && cached && !isCacheExpired(cached, cacheTtlSeconds)) {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const manifest = cached.manifest ?? manifestFromCachedResult(cached.result);
|
|
17
|
+
return buildUpdateCheckResult(manifest, {
|
|
18
|
+
checkedAt: cached.checkedAt,
|
|
19
|
+
cacheTtlSeconds,
|
|
20
|
+
manifestUrl,
|
|
18
21
|
manifestSource: "cache",
|
|
19
|
-
|
|
20
|
-
};
|
|
22
|
+
installedSkillsVersion: input.installedSkillsVersion
|
|
23
|
+
});
|
|
21
24
|
}
|
|
22
25
|
try {
|
|
23
26
|
const manifest = await fetchReleaseManifest(manifestUrl);
|
|
@@ -25,29 +28,35 @@ export async function checkForUpdate(input = {}, env = process.env, cwd = proces
|
|
|
25
28
|
checkedAt: new Date().toISOString(),
|
|
26
29
|
cacheTtlSeconds,
|
|
27
30
|
manifestUrl,
|
|
28
|
-
manifestSource: "remote"
|
|
31
|
+
manifestSource: "remote",
|
|
32
|
+
installedSkillsVersion: input.installedSkillsVersion
|
|
29
33
|
});
|
|
30
34
|
saveCachedUpdateState(cacheFile, {
|
|
31
35
|
checkedAt: result.checkedAt,
|
|
32
36
|
cacheTtlSeconds,
|
|
37
|
+
manifest,
|
|
33
38
|
result
|
|
34
39
|
});
|
|
35
40
|
return result;
|
|
36
41
|
}
|
|
37
42
|
catch (error) {
|
|
38
43
|
if (cached) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
const manifest = cached.manifest ?? manifestFromCachedResult(cached.result);
|
|
45
|
+
return buildUpdateCheckResult(manifest, {
|
|
46
|
+
checkedAt: cached.checkedAt,
|
|
42
47
|
cacheTtlSeconds,
|
|
48
|
+
manifestUrl,
|
|
49
|
+
manifestSource: "cache",
|
|
50
|
+
installedSkillsVersion: input.installedSkillsVersion,
|
|
43
51
|
error: error instanceof Error ? error.message : String(error)
|
|
44
|
-
};
|
|
52
|
+
});
|
|
45
53
|
}
|
|
46
54
|
return buildUnknownUpdateCheckResult({
|
|
47
55
|
checkedAt: new Date().toISOString(),
|
|
48
56
|
cacheTtlSeconds,
|
|
49
57
|
manifestUrl,
|
|
50
58
|
manifestSource: "fallback",
|
|
59
|
+
installedSkillsVersion: input.installedSkillsVersion,
|
|
51
60
|
error: error instanceof Error ? error.message : String(error)
|
|
52
61
|
});
|
|
53
62
|
}
|
|
@@ -62,6 +71,11 @@ export function buildUpdateCheckResult(manifest, metadata) {
|
|
|
62
71
|
minimumWriteVersion
|
|
63
72
|
});
|
|
64
73
|
const writeAllowed = status !== "WRITE_BLOCKED";
|
|
74
|
+
const installedSkillsVersion = normalizeInstalledSkillsVersion(metadata.installedSkillsVersion);
|
|
75
|
+
const skillsInstallStatus = computeSkillsInstallStatus(installedSkillsVersion, manifest.skillsVersion);
|
|
76
|
+
const skillsUpdateRecommended = manifest.skillsUpdateRecommended
|
|
77
|
+
|| skillsInstallStatus === "UPDATE_AVAILABLE"
|
|
78
|
+
|| (skillsInstallStatus === "NOT_VERIFIED" && compareVersions(RAPIDX_SKILLS_VERSION, manifest.skillsVersion) < 0);
|
|
65
79
|
return {
|
|
66
80
|
currentVersion: RAPIDX_VERSION,
|
|
67
81
|
latestVersion: manifest.latestCliVersion,
|
|
@@ -71,6 +85,10 @@ export function buildUpdateCheckResult(manifest, metadata) {
|
|
|
71
85
|
currentMcpSchemaVersion: SCHEMA_VERSION,
|
|
72
86
|
skillsVersion: manifest.skillsVersion,
|
|
73
87
|
currentSkillsVersion: RAPIDX_SKILLS_VERSION,
|
|
88
|
+
latestSkillsVersion: manifest.skillsVersion,
|
|
89
|
+
bundledExpectedSkillsVersion: RAPIDX_SKILLS_VERSION,
|
|
90
|
+
installedSkillsVersion,
|
|
91
|
+
skillsInstallStatus,
|
|
74
92
|
skillsSchemaVersion: manifest.skillsSchemaVersion,
|
|
75
93
|
currentSkillsSchemaVersion: RAPIDX_SKILLS_SCHEMA_VERSION,
|
|
76
94
|
updateAvailable: compareVersions(RAPIDX_VERSION, manifest.latestCliVersion) < 0,
|
|
@@ -82,9 +100,12 @@ export function buildUpdateCheckResult(manifest, metadata) {
|
|
|
82
100
|
cacheTtlSeconds: metadata.cacheTtlSeconds,
|
|
83
101
|
manifestUrl: metadata.manifestUrl,
|
|
84
102
|
manifestSource: metadata.manifestSource,
|
|
103
|
+
updateFreshness: freshnessForSource(metadata.manifestSource),
|
|
104
|
+
refreshCommand: "rapidx update check --input '{\"force\":true}' --json",
|
|
85
105
|
releaseNotesUrl: manifest.releaseNotesUrl,
|
|
86
|
-
skillsUpdateRecommended
|
|
106
|
+
skillsUpdateRecommended,
|
|
87
107
|
upgrade: manifest.upgrade,
|
|
108
|
+
...(metadata.manifestSource === "cache" ? { cacheWarning: "Result came from local cache. Use force=true to refresh the remote release manifest." } : {}),
|
|
88
109
|
...(metadata.error ? { error: metadata.error } : {})
|
|
89
110
|
};
|
|
90
111
|
}
|
|
@@ -160,6 +181,8 @@ function fallbackManifest() {
|
|
|
160
181
|
}
|
|
161
182
|
function buildUnknownUpdateCheckResult(metadata) {
|
|
162
183
|
const manifest = fallbackManifest();
|
|
184
|
+
const installedSkillsVersion = normalizeInstalledSkillsVersion(metadata.installedSkillsVersion);
|
|
185
|
+
const skillsInstallStatus = computeSkillsInstallStatus(installedSkillsVersion, manifest.skillsVersion);
|
|
163
186
|
return {
|
|
164
187
|
currentVersion: RAPIDX_VERSION,
|
|
165
188
|
latestVersion: RAPIDX_VERSION,
|
|
@@ -169,6 +192,10 @@ function buildUnknownUpdateCheckResult(metadata) {
|
|
|
169
192
|
currentMcpSchemaVersion: SCHEMA_VERSION,
|
|
170
193
|
skillsVersion: manifest.skillsVersion,
|
|
171
194
|
currentSkillsVersion: RAPIDX_SKILLS_VERSION,
|
|
195
|
+
latestSkillsVersion: manifest.skillsVersion,
|
|
196
|
+
bundledExpectedSkillsVersion: RAPIDX_SKILLS_VERSION,
|
|
197
|
+
installedSkillsVersion,
|
|
198
|
+
skillsInstallStatus,
|
|
172
199
|
skillsSchemaVersion: manifest.skillsSchemaVersion,
|
|
173
200
|
currentSkillsSchemaVersion: RAPIDX_SKILLS_SCHEMA_VERSION,
|
|
174
201
|
updateAvailable: false,
|
|
@@ -180,6 +207,8 @@ function buildUnknownUpdateCheckResult(metadata) {
|
|
|
180
207
|
cacheTtlSeconds: metadata.cacheTtlSeconds,
|
|
181
208
|
manifestUrl: metadata.manifestUrl,
|
|
182
209
|
manifestSource: metadata.manifestSource,
|
|
210
|
+
updateFreshness: freshnessForSource(metadata.manifestSource),
|
|
211
|
+
refreshCommand: "rapidx update check --input '{\"force\":true}' --json",
|
|
183
212
|
releaseNotesUrl: "",
|
|
184
213
|
skillsUpdateRecommended: false,
|
|
185
214
|
upgrade: {},
|
|
@@ -198,6 +227,41 @@ function computeUpdateStatus(input) {
|
|
|
198
227
|
}
|
|
199
228
|
return "CURRENT";
|
|
200
229
|
}
|
|
230
|
+
function computeSkillsInstallStatus(installedSkillsVersion, latestSkillsVersion) {
|
|
231
|
+
if (installedSkillsVersion === "NOT_VERIFIED") {
|
|
232
|
+
return "NOT_VERIFIED";
|
|
233
|
+
}
|
|
234
|
+
return compareVersions(installedSkillsVersion, latestSkillsVersion) < 0 ? "UPDATE_AVAILABLE" : "CURRENT";
|
|
235
|
+
}
|
|
236
|
+
function normalizeInstalledSkillsVersion(value) {
|
|
237
|
+
return typeof value === "string" && isSemver(value) ? value : "NOT_VERIFIED";
|
|
238
|
+
}
|
|
239
|
+
function freshnessForSource(source) {
|
|
240
|
+
if (source === "remote") {
|
|
241
|
+
return "REMOTE";
|
|
242
|
+
}
|
|
243
|
+
if (source === "cache") {
|
|
244
|
+
return "CACHE";
|
|
245
|
+
}
|
|
246
|
+
return "FALLBACK";
|
|
247
|
+
}
|
|
248
|
+
function manifestFromCachedResult(result) {
|
|
249
|
+
return {
|
|
250
|
+
product: "rapidx",
|
|
251
|
+
channel: "stable",
|
|
252
|
+
latestCliVersion: result.latestVersion,
|
|
253
|
+
minimumSupportedVersion: result.minimumSupportedVersion,
|
|
254
|
+
minimumWriteVersion: result.minimumWriteVersion,
|
|
255
|
+
latestMcpSchemaVersion: result.latestMcpSchemaVersion,
|
|
256
|
+
skillsVersion: result.skillsVersion,
|
|
257
|
+
skillsSchemaVersion: result.skillsSchemaVersion,
|
|
258
|
+
skillsUpdateRecommended: result.skillsUpdateRecommended,
|
|
259
|
+
severity: result.severity,
|
|
260
|
+
breaking: result.breaking,
|
|
261
|
+
releaseNotesUrl: result.releaseNotesUrl,
|
|
262
|
+
upgrade: result.upgrade
|
|
263
|
+
};
|
|
264
|
+
}
|
|
201
265
|
function compareVersions(left, right) {
|
|
202
266
|
const a = parseVersion(left);
|
|
203
267
|
const b = parseVersion(right);
|
|
@@ -220,6 +284,9 @@ function parseVersion(version) {
|
|
|
220
284
|
}
|
|
221
285
|
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
222
286
|
}
|
|
287
|
+
function isSemver(version) {
|
|
288
|
+
return /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.test(version);
|
|
289
|
+
}
|
|
223
290
|
function assertSemver(version, field) {
|
|
224
291
|
try {
|
|
225
292
|
parseVersion(version);
|
package/dist/core/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const RAPIDX_VERSION = "1.0.
|
|
1
|
+
export const RAPIDX_VERSION = "1.0.33";
|
package/dist/mcp/tool-runner.js
CHANGED
|
@@ -40,6 +40,9 @@ export async function runMcpTool(toolName, input = {}) {
|
|
|
40
40
|
if (typeof input.maxCacheAgeSeconds === "number") {
|
|
41
41
|
updateInput.maxCacheAgeSeconds = input.maxCacheAgeSeconds;
|
|
42
42
|
}
|
|
43
|
+
if (typeof input.installedSkillsVersion === "string") {
|
|
44
|
+
updateInput.installedSkillsVersion = input.installedSkillsVersion;
|
|
45
|
+
}
|
|
43
46
|
const update = await checkForUpdate(updateInput);
|
|
44
47
|
const status = envelopeStatusForUpdate(update.status);
|
|
45
48
|
const auditId = writeMcpAudit("update-check", status, { toolName, updateStatus: update.status });
|
|
@@ -136,8 +139,8 @@ export async function runMcpTool(toolName, input = {}) {
|
|
|
136
139
|
}
|
|
137
140
|
}
|
|
138
141
|
function concretePreviewTargetForTool(toolName) {
|
|
139
|
-
if (toolName === "rapidx/order/
|
|
140
|
-
return "order.
|
|
142
|
+
if (toolName === "rapidx/order/replace-preview") {
|
|
143
|
+
return "order.replace";
|
|
141
144
|
}
|
|
142
145
|
if (toolName === "rapidx/order/cancel-preview") {
|
|
143
146
|
return "order.cancel";
|
package/package.json
CHANGED
|
@@ -17,9 +17,9 @@ Supported conventions:
|
|
|
17
17
|
- Use stdin JSON when the host supports it.
|
|
18
18
|
- Do not create bridge scripts.
|
|
19
19
|
- Use `rapidx order place-preview` for `order.place`.
|
|
20
|
-
- Use `rapidx order
|
|
20
|
+
- Use `rapidx order replace-preview` for `order.replace`.
|
|
21
21
|
- Use `rapidx order cancel-preview` for `order.cancel`.
|
|
22
|
-
- Use `rapidx trade preview` with `targetCapabilityId` for non-order trade writes, including position,
|
|
22
|
+
- Use `rapidx trade preview` with `targetCapabilityId` for non-order trade writes, including position, portfolio, and algo writes.
|
|
23
23
|
- `rapidx trade preview` input is flat JSON; do not wrap target parameters under `params`.
|
|
24
24
|
- CLI preview ids are stored in the local CLI preview store. Do not submit MCP-created preview ids through CLI.
|
|
25
25
|
- Treat `maxNotional` as a safety upper bound, not as the target order amount. Check symbol `minNotional` before increasing a requested amount.
|
|
@@ -32,28 +32,53 @@ rapidx schema --json
|
|
|
32
32
|
rapidx update check --json
|
|
33
33
|
rapidx self-check --read-only --json
|
|
34
34
|
rapidx self-check --read-only --check-updates --json
|
|
35
|
-
rapidx
|
|
36
|
-
rapidx
|
|
35
|
+
rapidx portfolio overview --json
|
|
36
|
+
rapidx portfolio assets --input '{"exchangeType":"BINANCE"}' --json
|
|
37
37
|
rapidx order place-preview --input @/absolute/path/order-preview.json --json
|
|
38
|
-
rapidx order
|
|
38
|
+
rapidx order replace-preview --input @/absolute/path/order-replace-preview.json --json
|
|
39
39
|
rapidx order cancel-preview --input @/absolute/path/order-cancel-preview.json --json
|
|
40
40
|
rapidx trade preview --input @/absolute/path/trade-preview.json --json
|
|
41
41
|
rapidx position history --input @/absolute/path/position-history.json --json
|
|
42
|
-
rapidx
|
|
42
|
+
rapidx portfolio set-position-mode --input @/absolute/path/set-position-mode.json --json
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
`rapidx update check --json` reads the RapidX release manifest and caches the result locally. Use it during setup, review, or session startup. Trade submit paths should not perform a fresh network update check.
|
|
46
46
|
|
|
47
|
+
When checking an existing installation, read the installed RapidX skill `version` from the loaded `SKILL.md` frontmatter and pass it to update check:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
rapidx update check --input '{"installedSkillsVersion":"1.0.8"}' --json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For upgrade reviews, force a remote manifest refresh:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
rapidx update check --input '{"installedSkillsVersion":"1.0.8","force":true}' --json
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Update output fields:
|
|
60
|
+
|
|
61
|
+
- `latestVersion`: latest CLI version from the release manifest.
|
|
62
|
+
- `currentVersion`: running CLI version.
|
|
63
|
+
- `latestSkillsVersion` / `skillsVersion`: latest RapidX skills version from the release manifest.
|
|
64
|
+
- `bundledExpectedSkillsVersion` / `currentSkillsVersion`: skills version expected by this CLI build, not proof of locally installed skills.
|
|
65
|
+
- `installedSkillsVersion`: local skill version supplied by the caller, or `NOT_VERIFIED`.
|
|
66
|
+
- `skillsInstallStatus`: `CURRENT`, `UPDATE_AVAILABLE`, or `NOT_VERIFIED`.
|
|
67
|
+
- `manifestSource`: `remote`, `cache`, or `fallback`.
|
|
68
|
+
- `updateFreshness`: `REMOTE`, `CACHE`, or `FALLBACK`.
|
|
69
|
+
- `cacheWarning`: present when the result came from local cache.
|
|
70
|
+
- `refreshCommand`: command for forcing a remote manifest refresh.
|
|
71
|
+
|
|
47
72
|
`rapidx schema --json` returns `capabilities` plus `inputSchemas`. Agents should read the concrete input schema before constructing write inputs.
|
|
48
73
|
|
|
49
|
-
`rapidx
|
|
74
|
+
`rapidx portfolio assets` reads `/api/v1/trading/portfolio/assets`. It is the canonical CLI command for portfolio asset balances.
|
|
50
75
|
|
|
51
|
-
`rapidx
|
|
76
|
+
`rapidx portfolio set-position-mode` is a trade write. Use it only when the user explicitly asks to change account position mode. It requires a matching preview token and a `continueConsentId` before execution.
|
|
52
77
|
|
|
53
|
-
`rapidx order cancel` is asynchronous. A successful response can mean cancel accepted but not terminal. Poll `rapidx order
|
|
78
|
+
`rapidx order cancel` is asynchronous. A successful response can mean cancel accepted but not terminal. Poll `rapidx order query --json` when `terminalStateConfirmed=false`.
|
|
54
79
|
|
|
55
|
-
When using `orderId`, pass the RapidX 16-digit numeric order id. Invalid `orderId` format is rejected locally as `INVALID_INPUT`. `clientOrderId` can be used instead and does not need to satisfy the `orderId` format. Preview commands for
|
|
80
|
+
When using `orderId`, pass the RapidX 16-digit numeric order id. Invalid `orderId` format is rejected locally as `INVALID_INPUT`. `clientOrderId` can be used instead and does not need to satisfy the `orderId` format. Preview commands for replace/cancel perform a RapidX readback after local format validation; valid-but-missing orders return `NOT_FOUND` or a blocked non-open state.
|
|
56
81
|
|
|
57
82
|
Automation mode still uses preview. Pass `automationMode=true` and the user's exact `automationConsentText` to preview only when the user has enabled automation in chat for the current scope.
|
|
58
83
|
|
|
59
|
-
`rapidx position close` is a close-position action. Do not pass `side` or `quantity`; RapidX determines BUY or SELL from the current position and closes the target symbol/positionSide. Use a reduce-only order flow for partial closes. Verify the final exposure with `rapidx position
|
|
84
|
+
`rapidx position close` is a close-position action. Do not pass `side` or `quantity`; RapidX determines BUY or SELL from the current position and closes the target symbol/positionSide. Use a reduce-only order flow for partial closes. Verify the final exposure with `rapidx position query --json`, and do not rely only on `order query` to interpret the close intent.
|
|
@@ -28,14 +28,14 @@ Key trading tools:
|
|
|
28
28
|
- `rapidx/update/check` reads the RapidX release manifest and returns current/latest CLI version, minimum write version, skills update advice, and upgrade commands.
|
|
29
29
|
- `rapidx/self-check` can include update state when called with `{"checkUpdates": true}`.
|
|
30
30
|
- `rapidx/order/preview` creates preview tokens for `order.place`.
|
|
31
|
-
- `rapidx/order/place-preview`, `rapidx/order/
|
|
32
|
-
- `rapidx/trade/preview` creates preview tokens for non-place trade writes by `targetCapabilityId`, including position,
|
|
31
|
+
- `rapidx/order/place-preview`, `rapidx/order/replace-preview`, and `rapidx/order/cancel-preview` are concrete order preview aliases. Preview responses include `confirmation.submitToken`; pass it as `continueConsentId` when submitting the matching write tool.
|
|
32
|
+
- `rapidx/trade/preview` creates preview tokens for non-place trade writes by `targetCapabilityId`, including position, portfolio, and algo writes.
|
|
33
33
|
- Preview ids are local to the running MCP server. Do not submit a CLI-created preview id through MCP, and do not submit an MCP-created preview id through CLI.
|
|
34
|
-
- `rapidx/order/cancel` returns cancel acceptance plus terminal-state guidance. Poll `rapidx/order/
|
|
34
|
+
- `rapidx/order/cancel` returns cancel acceptance plus terminal-state guidance. Poll `rapidx/order/query` when `terminalStateConfirmed=false`.
|
|
35
35
|
- Automation mode still uses preview. Set `automationMode=true` and pass the user's exact `automationConsentText` only when the user has enabled automation in chat for the current scope.
|
|
36
36
|
- `rapidx/position/history` reads historical positions.
|
|
37
37
|
- Hedge-mode order placement and verification use `positionSide="LONG"` or `positionSide="SHORT"` in the order or verify-live input. Do not use account mode switching as a substitute for order-level `positionSide`.
|
|
38
|
-
- `rapidx/
|
|
38
|
+
- `rapidx/portfolio/set-position-mode` changes account position mode and requires preview plus explicit continuation consent. Use it only when the user explicitly asks to change account position mode.
|
|
39
39
|
- `rapidx/trade/verify-live` runs the optional small real-trade verification flow with `explicitUserConsent` and parameter-bound `acceptedRiskText`; it creates its own internal preview and does not accept an external `previewId`. If `positionSide` is provided, `acceptedRiskText` must include that position side. `rapidx/trading-verification` remains supported as a compatibility alias.
|
|
40
40
|
|
|
41
41
|
Agents must discover the full tool list through `rapidx/tools` and must not invent tool names.
|