@liquiditytech/rapidx-cli 1.0.29 → 1.0.31

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.
@@ -1,4 +1,4 @@
1
- import { executeRapidXCapability, findCapabilityById, normalizeUnknownError } from "../../core/index.js";
1
+ import { executeRapidXCapability, findCapabilityById, normalizeUnknownError, publicErrorDetails } from "../../core/index.js";
2
2
  import { writeCliAudit } from "../audit.js";
3
3
  import { fail, ok } from "../envelope.js";
4
4
  import { enforceCliPreviewGate } from "./trade-gate.js";
@@ -29,6 +29,6 @@ export async function runAccountCommand(action, input) {
29
29
  }
30
30
  catch (error) {
31
31
  const productError = normalizeUnknownError(error, "RCLI01001");
32
- return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx account ${action}`);
32
+ return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx account ${action}`, publicErrorDetails(productError));
33
33
  }
34
34
  }
@@ -1,4 +1,4 @@
1
- import { executeRapidXCapability, findCapabilityById, normalizeUnknownError } from "../../core/index.js";
1
+ import { executeRapidXCapability, findCapabilityById, normalizeUnknownError, publicErrorDetails } from "../../core/index.js";
2
2
  import { writeCliAudit } from "../audit.js";
3
3
  import { fail, ok } from "../envelope.js";
4
4
  import { enforceCliPreviewGate } from "./trade-gate.js";
@@ -30,6 +30,6 @@ export async function runAlgoCommand(action, input) {
30
30
  }
31
31
  catch (error) {
32
32
  const productError = normalizeUnknownError(error, "RCLI12001");
33
- return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx algo ${action}`);
33
+ return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx algo ${action}`, publicErrorDetails(productError));
34
34
  }
35
35
  }
@@ -1,4 +1,4 @@
1
- import { executeRapidXCapability, normalizeUnknownError } from "../../core/index.js";
1
+ import { executeRapidXCapability, normalizeUnknownError, publicErrorDetails } from "../../core/index.js";
2
2
  import { ok } from "../envelope.js";
3
3
  import { fail } from "../envelope.js";
4
4
  const MARKET_CAPABILITY_BY_ACTION = {
@@ -21,6 +21,6 @@ export async function runMarketCommand(action, input) {
21
21
  }
22
22
  catch (error) {
23
23
  const productError = normalizeUnknownError(error, "RCLI12001");
24
- return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx market ${action}`);
24
+ return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx market ${action}`, publicErrorDetails(productError));
25
25
  }
26
26
  }
@@ -1,4 +1,4 @@
1
- import { consumePreview, createTargetedTradePreview, createTradePreview, defaultSafetyPolicy, executeRapidXCapability, findCapabilityById, loadPreviewStoreFromFile, makeSafetyState, normalizeUnknownError, resolvePreviewStoreFile, runPreviewPreflight, savePreviewStoreToFile, verifyPreview } from "../../core/index.js";
1
+ import { consumePreview, createTargetedTradePreview, createTradePreview, defaultSafetyPolicy, executeRapidXCapability, findCapabilityById, loadPreviewStoreFromFile, makeSafetyState, normalizeUnknownError, publicErrorDetails, resolvePreviewStoreFile, runPreviewPreflight, savePreviewStoreToFile, verifyPreview } from "../../core/index.js";
2
2
  import { fail, ok } from "../envelope.js";
3
3
  import { writeCliAudit } from "../audit.js";
4
4
  const safetyState = makeSafetyState();
@@ -18,7 +18,7 @@ export async function runOrderCommand(action, input) {
18
18
  }
19
19
  catch (error) {
20
20
  const productError = normalizeUnknownError(error, "RCLI20002");
21
- return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx order ${action}`);
21
+ return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx order ${action}`, publicErrorDetails(productError));
22
22
  }
23
23
  }
24
24
  const previewTarget = previewTargetForAction(action);
@@ -35,7 +35,7 @@ export async function runOrderCommand(action, input) {
35
35
  }
36
36
  catch (error) {
37
37
  const productError = normalizeUnknownError(error, "RCLI20002");
38
- return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx order ${action}`);
38
+ return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx order ${action}`, publicErrorDetails(productError));
39
39
  }
40
40
  }
41
41
  const capability = findCapabilityById(`order.${action}`);
@@ -69,7 +69,7 @@ export async function runOrderCommand(action, input) {
69
69
  }
70
70
  catch (error) {
71
71
  const productError = normalizeUnknownError(error, "RCLI12001");
72
- return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx order ${action}`);
72
+ return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx order ${action}`, publicErrorDetails(productError));
73
73
  }
74
74
  }
75
75
  function previewTargetForAction(action) {
@@ -1,4 +1,4 @@
1
- import { executeRapidXCapability, findCapabilityById, normalizeUnknownError } from "../../core/index.js";
1
+ import { executeRapidXCapability, findCapabilityById, normalizeUnknownError, publicErrorDetails } from "../../core/index.js";
2
2
  import { writeCliAudit } from "../audit.js";
3
3
  import { fail, ok } from "../envelope.js";
4
4
  import { enforceCliPreviewGate } from "./trade-gate.js";
@@ -30,6 +30,6 @@ export async function runPositionCommand(action, input) {
30
30
  }
31
31
  catch (error) {
32
32
  const productError = normalizeUnknownError(error, "RCLI12001");
33
- return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx position ${action}`);
33
+ return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx position ${action}`, publicErrorDetails(productError));
34
34
  }
35
35
  }
@@ -1,4 +1,4 @@
1
- import { createTargetedTradePreview, defaultSafetyPolicy, findCapabilityById, loadPreviewStoreFromFile, makeSafetyState, normalizeUnknownError, resolvePreviewStoreFile, runPreviewPreflight, savePreviewStoreToFile } from "../../core/index.js";
1
+ import { createTargetedTradePreview, defaultSafetyPolicy, findCapabilityById, loadPreviewStoreFromFile, makeSafetyState, normalizeUnknownError, publicErrorDetails, resolvePreviewStoreFile, runPreviewPreflight, savePreviewStoreToFile } from "../../core/index.js";
2
2
  import { fail, ok } from "../envelope.js";
3
3
  const safetyState = makeSafetyState();
4
4
  export async function runTradeCommand(action, input) {
@@ -23,7 +23,7 @@ export async function runTradeCommand(action, input) {
23
23
  }
24
24
  catch (error) {
25
25
  const productError = normalizeUnknownError(error, "RCLI20002");
26
- return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, "rapidx trade preview");
26
+ return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, "rapidx trade preview", publicErrorDetails(productError));
27
27
  }
28
28
  }
29
29
  function isPreviewCapability(capabilityId) {
@@ -8,12 +8,13 @@ export function ok(data, evidenceText, status = "PASS", source = "local_check",
8
8
  evidence: [makeEvidence(evidenceText, source)]
9
9
  };
10
10
  }
11
- export function fail(code, message, status = "FAIL", evidenceText = "rapidx cli") {
11
+ export function fail(code, message, status = "FAIL", evidenceText = "rapidx cli", details) {
12
12
  return {
13
13
  ok: false,
14
14
  status,
15
15
  code,
16
16
  message,
17
+ ...(details ? { details } : {}),
17
18
  evidence: [makeEvidence(evidenceText)]
18
19
  };
19
20
  }
@@ -1,6 +1,7 @@
1
1
  import { ProductError } from "../errors/product-error.js";
2
2
  import { parseRapidXSymbol } from "./symbol.js";
3
3
  import { RapidXClient } from "./rapid-x-client.js";
4
+ import { assertOrderLookupReference, assertValidOrderId } from "./order-id.js";
4
5
  import { findCapabilityById } from "../contracts/capabilities.js";
5
6
  import { assertInputMatchesSchema } from "../contracts/input-schema.js";
6
7
  export async function executeRapidXCapability(capabilityId, input = {}, options = {}) {
@@ -34,7 +35,7 @@ export async function executeRapidXCapability(capabilityId, input = {}, options
34
35
  case "order.cancel":
35
36
  return executeOrderCancelCapability(client, input);
36
37
  case "order.get":
37
- return client.get("/api/v1/trading/order", optionalParams(input, ["orderId", "clientOrderId", "symbol"]));
38
+ return client.get("/api/v1/trading/order", orderReadParams(input));
38
39
  case "order.list":
39
40
  return client.get("/api/v1/trading/orders", { pageSize: stringValue(input.pageSize, "1000"), ...optionalParams(input, ["symbol"]) });
40
41
  case "order.history":
@@ -271,6 +272,7 @@ function orderPlaceBody(input) {
271
272
  };
272
273
  }
273
274
  function orderAmendBody(input) {
275
+ assertValidOrderId(input.orderId);
274
276
  const body = optionalParams(input, ["orderId", "clientOrderId"]);
275
277
  if (input.quantity !== undefined) {
276
278
  body.replaceQty = String(input.quantity);
@@ -281,8 +283,13 @@ function orderAmendBody(input) {
281
283
  return body;
282
284
  }
283
285
  function orderCancelBody(input) {
286
+ assertValidOrderId(input.orderId);
284
287
  return optionalParams(input, ["orderId", "clientOrderId"]);
285
288
  }
289
+ function orderReadParams(input) {
290
+ assertOrderLookupReference(input);
291
+ return optionalParams(input, ["orderId", "clientOrderId", "symbol"]);
292
+ }
286
293
  function positionCloseBody(input) {
287
294
  const body = {
288
295
  sym: String(input.symbol)
@@ -0,0 +1,24 @@
1
+ import { CORE_ERRORS, ProductError } from "../errors/product-error.js";
2
+ export function assertValidOrderId(orderId) {
3
+ if (orderId === undefined || orderId === null || orderId === "") {
4
+ return;
5
+ }
6
+ if (!/^\d{16}$/.test(String(orderId))) {
7
+ throw new ProductError({
8
+ code: CORE_ERRORS.INVALID_ORDER_ID,
9
+ status: "INVALID_INPUT",
10
+ message: "orderId must be 16 digits."
11
+ });
12
+ }
13
+ }
14
+ export function assertOrderLookupReference(input) {
15
+ assertValidOrderId(input.orderId);
16
+ if ((input.orderId === undefined || input.orderId === null || input.orderId === "")
17
+ && (input.clientOrderId === undefined || input.clientOrderId === null || input.clientOrderId === "")) {
18
+ throw new ProductError({
19
+ code: "RCORE00001",
20
+ status: "INVALID_INPUT",
21
+ message: "orderId or clientOrderId is required."
22
+ });
23
+ }
24
+ }
@@ -70,7 +70,7 @@ export class RapidXClient {
70
70
  code: upstreamHttpErrorCode(path, response.status, text),
71
71
  status: upstreamHttpErrorStatus(path, response.status, text),
72
72
  message: hint ? `RapidX upstream error ${response.status}. ${hint}` : `RapidX upstream error ${response.status}`,
73
- details: { status: response.status, body: text.slice(0, 500), attempts: attempt, ...(hint ? { hint } : {}) }
73
+ details: { upstreamStatus: response.status, status: response.status, body: text.slice(0, 500), attempts: attempt, ...(hint ? { hint } : {}) }
74
74
  });
75
75
  }
76
76
  if (!text) {
@@ -145,6 +145,9 @@ function isAccountBalanceScopeError(path, status, body) {
145
145
  if (path !== "/api/v1/account/balance" || status < 400) {
146
146
  return false;
147
147
  }
148
+ if (status >= 500) {
149
+ return true;
150
+ }
148
151
  const lowerBody = body.toLowerCase();
149
152
  return lowerBody.includes("account-level")
150
153
  || lowerBody.includes("permission scope")
@@ -1,7 +1,7 @@
1
1
  import { SCHEMA_VERSION } from "./types.js";
2
2
  import { RAPIDX_VERSION } from "../version.js";
3
3
  export const RAPIDX_SKILLS_DISTRIBUTION = "github";
4
- export const RAPIDX_SKILLS_VERSION = "1.0.3";
4
+ export const RAPIDX_SKILLS_VERSION = "1.0.5";
5
5
  export const RAPIDX_SKILLS_SCHEMA_VERSION = "1.0.0";
6
6
  export function buildCompatibilityReport(input = {}) {
7
7
  const checks = [
@@ -86,7 +86,7 @@ const targetCapabilityIdSchema = {
86
86
  const orderIdSchema = {
87
87
  type: "string",
88
88
  description: "RapidX order id returned by order.place, order.list, or order.get.",
89
- examples: ["1234567890"]
89
+ examples: ["2173374713391199"]
90
90
  };
91
91
  const accountBalanceModeSchema = {
92
92
  type: "string",
@@ -117,7 +117,10 @@ export function inputSchemaForName(name) {
117
117
  case "AccountBalanceInput":
118
118
  return objectSchema({ mode: accountBalanceModeSchema, currency: stringSchema });
119
119
  case "OrderLookupInput":
120
- return objectSchema({ orderId: orderIdSchema, clientOrderId: clientOrderIdSchema, symbol: symbolSchema });
120
+ return {
121
+ ...objectSchema({ orderId: orderIdSchema, clientOrderId: clientOrderIdSchema, symbol: symbolSchema }),
122
+ anyOf: [{ required: ["orderId"] }, { required: ["clientOrderId"] }]
123
+ };
121
124
  case "OrderListInput":
122
125
  case "OrderHistoryInput":
123
126
  return objectSchema({ symbol: symbolSchema, pageSize: numberSchema, startTime: stringSchema, endTime: stringSchema });
@@ -12,11 +12,13 @@ export class ProductError extends Error {
12
12
  }
13
13
  }
14
14
  toEnvelope(evidence = []) {
15
+ const details = publicErrorDetails(this);
15
16
  return {
16
17
  ok: false,
17
18
  status: this.status,
18
19
  code: this.code,
19
20
  message: this.message,
21
+ ...(details ? { details } : {}),
20
22
  evidence
21
23
  };
22
24
  }
@@ -26,6 +28,7 @@ export const CORE_ERRORS = {
26
28
  INVALID_CREDENTIAL: "RCORE01002",
27
29
  MISSING_API_HOST: "RCORE01003",
28
30
  SECRET_REDACTION_RISK: "RCORE90002",
31
+ INVALID_ORDER_ID: "RCORE00002",
29
32
  UPSTREAM_REJECTED: "RCORE22001",
30
33
  PERMISSION_SCOPE_ERROR: "RCORE01004",
31
34
  NOT_FOUND: "RCORE22004",
@@ -51,6 +54,18 @@ export function normalizeUnknownError(error, fallbackCode = "RCORE00001") {
51
54
  message
52
55
  });
53
56
  }
57
+ export function publicErrorDetails(error) {
58
+ if (!error.details) {
59
+ return undefined;
60
+ }
61
+ const details = {};
62
+ for (const key of ["upstreamStatus", "upstreamCode", "upstreamMessage", "hint", "attempts"]) {
63
+ if (error.details[key] !== undefined) {
64
+ details[key] = error.details[key];
65
+ }
66
+ }
67
+ return Object.keys(details).length > 0 ? details : undefined;
68
+ }
54
69
  function isUpstreamNetworkError(error) {
55
70
  if (!(error instanceof Error)) {
56
71
  return false;
@@ -12,6 +12,7 @@ export * from "./errors/product-error.js";
12
12
  export * from "./client/signing.js";
13
13
  export * from "./client/rapid-x-client.js";
14
14
  export * from "./client/capability-executor.js";
15
+ export * from "./client/order-id.js";
15
16
  export * from "./client/symbol.js";
16
17
  export * from "./safety/policy.js";
17
18
  export * from "./safety/raw-api.js";
@@ -1,4 +1,5 @@
1
1
  import { RapidXClient } from "../client/rapid-x-client.js";
2
+ import { assertOrderLookupReference } from "../client/order-id.js";
2
3
  import { parseRapidXSymbol } from "../client/symbol.js";
3
4
  import { ProductError } from "../errors/product-error.js";
4
5
  export async function runPreviewPreflight(capabilityId, input, options = {}) {
@@ -236,18 +237,12 @@ function estimateNotional(input) {
236
237
  return price * quantity;
237
238
  }
238
239
  function orderLookupParams(input) {
240
+ assertOrderLookupReference(input);
239
241
  const params = compactObject({
240
242
  orderId: input.orderId,
241
243
  clientOrderId: input.clientOrderId,
242
244
  symbol: input.symbol
243
245
  });
244
- if (!params.orderId && !params.clientOrderId) {
245
- throw new ProductError({
246
- code: "RCORE00001",
247
- status: "FAIL",
248
- message: "orderId or clientOrderId is required."
249
- });
250
- }
251
246
  return params;
252
247
  }
253
248
  function extractOrderReadback(response) {
@@ -1 +1 @@
1
- export const RAPIDX_VERSION = "1.0.29";
1
+ export const RAPIDX_VERSION = "1.0.31";
@@ -1,4 +1,4 @@
1
- import { consumePreview, createTargetedTradePreview, createTradePreview, defaultSafetyPolicy, executeRapidXCapability, findCapabilityById, getSchemaResult, makeEvidence, makePreviewStore, makeSafetyState, normalizeUnknownError, runSelfCheck, runPreviewPreflight, runTradingVerification, verifyPreview, buildLiveReadOnlySelfCheck, buildLiveTradingVerificationProbes, checkForUpdate, } from "../core/index.js";
1
+ import { consumePreview, createTargetedTradePreview, createTradePreview, defaultSafetyPolicy, executeRapidXCapability, findCapabilityById, getSchemaResult, makeEvidence, makePreviewStore, makeSafetyState, normalizeUnknownError, publicErrorDetails, runSelfCheck, runPreviewPreflight, runTradingVerification, verifyPreview, buildLiveReadOnlySelfCheck, buildLiveTradingVerificationProbes, checkForUpdate, } from "../core/index.js";
2
2
  import { capabilityForTool, getMcpToolDefinitions } from "./tool-registry.js";
3
3
  import { writeMcpAudit } from "./audit.js";
4
4
  const previewStore = makePreviewStore();
@@ -124,11 +124,13 @@ export async function runMcpTool(toolName, input = {}) {
124
124
  }
125
125
  catch (error) {
126
126
  const productError = normalizeUnknownError(error, "RMCP12003");
127
+ const details = publicErrorDetails(productError);
127
128
  return {
128
129
  ok: false,
129
130
  status: productError.status,
130
131
  code: productError.code.replace(/^RCORE/, "RMCP"),
131
132
  message: productError.message,
133
+ ...(details ? { details } : {}),
132
134
  evidence: [makeEvidence(toolName)]
133
135
  };
134
136
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liquiditytech/rapidx-cli",
3
- "version": "1.0.29",
3
+ "version": "1.0.31",
4
4
  "description": "RapidX CLI, MCP server mode, registry, and release assets.",
5
5
  "type": "module",
6
6
  "private": false,
@@ -52,6 +52,8 @@ rapidx account set-position-mode --input @/absolute/path/set-position-mode.json
52
52
 
53
53
  `rapidx order cancel` is asynchronous. A successful response can mean cancel accepted but not terminal. Poll `rapidx order get --json` when `terminalStateConfirmed=false`.
54
54
 
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 amend/cancel perform a RapidX readback after local format validation; valid-but-missing orders return `NOT_FOUND` or a blocked non-open state.
56
+
55
57
  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.
56
58
 
57
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 list --json`, and do not rely only on `order get` to interpret the close intent.
@@ -53,6 +53,8 @@ Preview ids are runtime-local. A preview created by MCP must be submitted throug
53
53
 
54
54
  `order.cancel` is asynchronous. A successful cancel response means the cancel request was accepted; it may not prove a terminal order state yet. The response includes `cancelAccepted`, `terminalStateConfirmed`, `lastObservedOrderState`, and `recommendedAction`. Poll `order.get` until `CANCELED`, `REJECTED`, `EXPIRED`, or timeout when `terminalStateConfirmed=false`.
55
55
 
56
+ Order identifiers use two validation layers. If `orderId` is provided, RapidX validates it locally as a 16-digit numeric id and returns `INVALID_INPUT` before any upstream call when the format is wrong. If `clientOrderId` is provided instead, do not apply `orderId` validation. For `order.get`, `order.amend-preview`, and `order.cancel-preview`, a syntactically valid `orderId` or `clientOrderId` is checked through RapidX readback; missing or non-open orders return `NOT_FOUND` or `BLOCKED` depending on the observed state.
57
+
56
58
  For automation, keep preview-first execution. Set `automationMode=true` and pass the user's exact `automationConsentText` only when the user has explicitly enabled RapidX automation mode in chat. The preview response still returns `confirmation.submitToken`; automation mode only means the agent may use that submit token without asking for another per-order chat confirmation within the authorized scope.
57
59
 
58
60
  For TPSL or conditional algo orders, use `rapidx/trade/preview` with `targetCapabilityId="algo.place"`, then submit `rapidx/algo/place`. `conditionType="ENTIRE_CLOSE_POSITION"` may use `orderType="MARKET"` without `quantity` or `amount`; provide at least one take-profit or stop-loss trigger and verify with `rapidx/algo/list`.
@@ -1,11 +1,11 @@
1
1
  {
2
- "version": "1.0.29",
2
+ "version": "1.0.31",
3
3
  "artifacts": [
4
4
  {
5
5
  "name": "rapidx-mcp-registry",
6
6
  "path": "packages/distribution/registry/rapidx.mcp.json",
7
7
  "channel": "offline",
8
- "checksum": "sha256:8a462f111ce2e1496b670978113277deeb49fc8ebcc9bfb2f9af3a91e5c8f9eb",
8
+ "checksum": "sha256:d3ee1491bd542f204e765f04ae98daa5970e0e32b8edd06ff5fab47189b20b6f",
9
9
  "status": "ready"
10
10
  },
11
11
  {
@@ -19,7 +19,7 @@
19
19
  "name": "rapidx-tools-doc",
20
20
  "path": "packages/distribution/docs/tools.md",
21
21
  "channel": "offline",
22
- "checksum": "sha256:e6ba0a1cbafa47fef2d6a2de6baffeb0a786d1d38886961c1347b9ffbd870e54",
22
+ "checksum": "sha256:fc80e63eabc8407c74b01ed707187505c90497af53a25f201c07e13ef948bf18",
23
23
  "status": "ready"
24
24
  }
25
25
  ]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rapidx",
3
3
  "packageName": "@liquiditytech/rapidx-cli",
4
- "version": "1.0.29",
4
+ "version": "1.0.31",
5
5
  "command": "rapidx",
6
6
  "args": ["mcp", "serve"],
7
7
  "launchCommand": "rapidx",