@liquiditytech/rapidx-cli 1.0.26

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.
Files changed (64) hide show
  1. package/README.md +81 -0
  2. package/dist/cli/audit.js +10 -0
  3. package/dist/cli/bin.js +41 -0
  4. package/dist/cli/commands/account.js +34 -0
  5. package/dist/cli/commands/algo.js +35 -0
  6. package/dist/cli/commands/auth.js +22 -0
  7. package/dist/cli/commands/config.js +46 -0
  8. package/dist/cli/commands/doctor.js +42 -0
  9. package/dist/cli/commands/index.js +73 -0
  10. package/dist/cli/commands/market.js +26 -0
  11. package/dist/cli/commands/order.js +81 -0
  12. package/dist/cli/commands/position.js +35 -0
  13. package/dist/cli/commands/schema.js +5 -0
  14. package/dist/cli/commands/self-check.js +24 -0
  15. package/dist/cli/commands/trade-gate.js +26 -0
  16. package/dist/cli/commands/trade.js +30 -0
  17. package/dist/cli/commands/update.js +27 -0
  18. package/dist/cli/envelope.js +29 -0
  19. package/dist/cli/help.js +34 -0
  20. package/dist/cli/invocation-checker.js +39 -0
  21. package/dist/cli/mcp-entry.js +4 -0
  22. package/dist/cli/parser.js +87 -0
  23. package/dist/core/audit/redaction.js +56 -0
  24. package/dist/core/audit/writer.js +27 -0
  25. package/dist/core/client/capability-executor.js +400 -0
  26. package/dist/core/client/rapid-x-client.js +156 -0
  27. package/dist/core/client/signing.js +24 -0
  28. package/dist/core/client/symbol.js +36 -0
  29. package/dist/core/config/credential.js +42 -0
  30. package/dist/core/config/resolve.js +24 -0
  31. package/dist/core/contracts/capabilities.js +77 -0
  32. package/dist/core/contracts/compatibility.js +65 -0
  33. package/dist/core/contracts/events.js +29 -0
  34. package/dist/core/contracts/evidence.js +7 -0
  35. package/dist/core/contracts/input-schema.js +370 -0
  36. package/dist/core/contracts/types.js +1 -0
  37. package/dist/core/errors/product-error.js +74 -0
  38. package/dist/core/index.js +24 -0
  39. package/dist/core/safety/policy.js +215 -0
  40. package/dist/core/safety/raw-api.js +19 -0
  41. package/dist/core/self-check/live-read-only-probes.js +25 -0
  42. package/dist/core/self-check/live-trading-verification-probes.js +252 -0
  43. package/dist/core/self-check/run-self-check.js +91 -0
  44. package/dist/core/trading/preview.js +330 -0
  45. package/dist/core/trading/trading-verification.js +137 -0
  46. package/dist/core/update/check-update.js +295 -0
  47. package/dist/core/version.js +1 -0
  48. package/dist/mcp/audit.js +10 -0
  49. package/dist/mcp/server.js +73 -0
  50. package/dist/mcp/tool-registry.js +31 -0
  51. package/dist/mcp/tool-runner.js +144 -0
  52. package/package.json +48 -0
  53. package/packages/distribution/docs/cli-only-agent.md +12 -0
  54. package/packages/distribution/docs/cli.md +49 -0
  55. package/packages/distribution/docs/index.md +58 -0
  56. package/packages/distribution/docs/mcp.md +36 -0
  57. package/packages/distribution/docs/quickstart.md +129 -0
  58. package/packages/distribution/docs/self-check.md +7 -0
  59. package/packages/distribution/docs/skills.md +140 -0
  60. package/packages/distribution/docs/tools.md +35 -0
  61. package/packages/distribution/docs/trading-verification.md +17 -0
  62. package/packages/distribution/docs/troubleshooting/index.md +27 -0
  63. package/packages/distribution/manifests/offline-manifest.json +26 -0
  64. package/packages/distribution/registry/rapidx.mcp.json +26 -0
@@ -0,0 +1,156 @@
1
+ import { resolveCredential } from "../config/resolve.js";
2
+ import { CORE_ERRORS, ProductError } from "../errors/product-error.js";
3
+ import { flattenParams, signParams } from "./signing.js";
4
+ export class RapidXClient {
5
+ baseUrl;
6
+ credential;
7
+ fetchFn;
8
+ nowSeconds;
9
+ readOnlyRetryAttempts;
10
+ readOnlyRetryDelayMs;
11
+ constructor(options = {}) {
12
+ this.baseUrl = resolveBaseUrl(options.baseUrl);
13
+ this.credential = options.credential ?? resolveCredential({ ref: options.credentialRef ?? { source: "env" } });
14
+ this.fetchFn = options.fetchFn ?? fetch;
15
+ this.nowSeconds = options.nowSeconds ?? (() => Math.floor(Date.now() / 1000));
16
+ this.readOnlyRetryAttempts = Math.max(1, options.readOnlyRetryAttempts ?? 4);
17
+ this.readOnlyRetryDelayMs = Math.max(0, options.readOnlyRetryDelayMs ?? 2_000);
18
+ }
19
+ async get(path, params = {}) {
20
+ return this.request("GET", path, params);
21
+ }
22
+ async post(path, body, params = {}) {
23
+ return this.request("POST", path, params, body);
24
+ }
25
+ async put(path, body) {
26
+ return this.request("PUT", path, {}, body);
27
+ }
28
+ async delete(path, body, params = {}) {
29
+ return this.request("DELETE", path, params, body);
30
+ }
31
+ buildSignedHeaders(method, params, body) {
32
+ const nonce = String(this.nowSeconds());
33
+ const signSource = method === "POST" || method === "PUT" || method === "DELETE"
34
+ ? flattenParams(body ?? params)
35
+ : params;
36
+ return {
37
+ "Content-Type": "application/json",
38
+ "X-MBX-APIKEY": this.credential.accessKey,
39
+ nonce,
40
+ signature: signParams(signSource, nonce, this.credential.secretKey)
41
+ };
42
+ }
43
+ async request(method, path, params = {}, body) {
44
+ const url = new URL(path, this.baseUrl);
45
+ if ((method === "GET" || method === "DELETE") && Object.keys(params).length > 0) {
46
+ for (const [key, value] of Object.entries(params)) {
47
+ url.searchParams.set(key, value);
48
+ }
49
+ }
50
+ const maxAttempts = method === "GET" ? this.readOnlyRetryAttempts : 1;
51
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
52
+ const headers = this.buildSignedHeaders(method, params, body);
53
+ const init = {
54
+ method,
55
+ headers,
56
+ signal: AbortSignal.timeout(30_000)
57
+ };
58
+ if (body !== undefined) {
59
+ init.body = JSON.stringify(body);
60
+ }
61
+ const response = await this.fetchFn(url.toString(), init);
62
+ const text = await response.text();
63
+ if (!response.ok) {
64
+ if (method === "GET" && response.status === 429 && attempt < maxAttempts) {
65
+ await delay(this.readOnlyRetryDelayMs * (2 ** (attempt - 1)));
66
+ continue;
67
+ }
68
+ const hint = upstreamHttpErrorHint(path, response.status);
69
+ throw new ProductError({
70
+ code: upstreamHttpErrorCode(response.status),
71
+ status: "FAIL",
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 } : {}) }
74
+ });
75
+ }
76
+ if (!text) {
77
+ return {};
78
+ }
79
+ let parsed;
80
+ try {
81
+ parsed = JSON.parse(text);
82
+ }
83
+ catch {
84
+ throw new ProductError({
85
+ code: CORE_ERRORS.UPSTREAM_REJECTED,
86
+ status: "FAIL",
87
+ message: "RapidX upstream returned non-JSON response."
88
+ });
89
+ }
90
+ assertRapidXBusinessSuccess(parsed);
91
+ return parsed;
92
+ }
93
+ throw new ProductError({
94
+ code: CORE_ERRORS.UPSTREAM_RATE_LIMITED,
95
+ status: "FAIL",
96
+ message: "RapidX upstream rate limit retry attempts were exhausted."
97
+ });
98
+ }
99
+ }
100
+ function resolveBaseUrl(explicitBaseUrl) {
101
+ const value = firstNonEmpty(explicitBaseUrl, process.env.LTP_API_HOST);
102
+ if (!value) {
103
+ throw new ProductError({
104
+ code: CORE_ERRORS.MISSING_API_HOST,
105
+ status: "NOT_VERIFIED",
106
+ message: "LTP_API_HOST is required. Configure the API host provided for your environment."
107
+ });
108
+ }
109
+ return value;
110
+ }
111
+ function firstNonEmpty(...values) {
112
+ return values.find((value) => value !== undefined && value.length > 0);
113
+ }
114
+ function upstreamHttpErrorHint(path, status) {
115
+ if (path === "/api/v1/account/balance" && status >= 500) {
116
+ return "account balance mode=account requires account-level credentials; portfolio keys should use mode=portfolio.";
117
+ }
118
+ return undefined;
119
+ }
120
+ function upstreamHttpErrorCode(status) {
121
+ if (status === 429) {
122
+ return CORE_ERRORS.UPSTREAM_RATE_LIMITED;
123
+ }
124
+ if (status >= 500) {
125
+ return CORE_ERRORS.UPSTREAM_REJECTED;
126
+ }
127
+ return CORE_ERRORS.INVALID_CREDENTIAL;
128
+ }
129
+ function delay(ms) {
130
+ if (ms <= 0) {
131
+ return Promise.resolve();
132
+ }
133
+ return new Promise((resolve) => setTimeout(resolve, ms));
134
+ }
135
+ function assertRapidXBusinessSuccess(payload) {
136
+ if (!payload || typeof payload !== "object" || !Object.prototype.hasOwnProperty.call(payload, "code")) {
137
+ return;
138
+ }
139
+ const body = payload;
140
+ const code = String(body.code ?? "");
141
+ if (code === "200000") {
142
+ return;
143
+ }
144
+ const upstreamMessage = typeof body.message === "string" && body.message.length > 0
145
+ ? `: ${body.message}`
146
+ : "";
147
+ throw new ProductError({
148
+ code: CORE_ERRORS.UPSTREAM_REJECTED,
149
+ status: "FAIL",
150
+ message: `RapidX upstream business error ${code}${upstreamMessage}`,
151
+ details: {
152
+ upstreamCode: code,
153
+ upstreamMessage: typeof body.message === "string" ? body.message : undefined
154
+ }
155
+ });
156
+ }
@@ -0,0 +1,24 @@
1
+ import { createHmac } from "node:crypto";
2
+ export function flattenParams(input) {
3
+ if (!input || typeof input !== "object") {
4
+ return {};
5
+ }
6
+ const result = {};
7
+ for (const [key, value] of Object.entries(input)) {
8
+ if (value !== undefined && value !== null) {
9
+ result[key] = String(value);
10
+ }
11
+ }
12
+ return result;
13
+ }
14
+ export function canonicalizeParams(params) {
15
+ return Object.keys(params)
16
+ .sort()
17
+ .map((key) => `${key}=${params[key] ?? ""}`)
18
+ .join("&");
19
+ }
20
+ export function signParams(params, nonce, secretKey) {
21
+ const serialized = canonicalizeParams(params);
22
+ const message = `${serialized}&${nonce}`;
23
+ return createHmac("sha256", secretKey).update(message).digest("hex");
24
+ }
@@ -0,0 +1,36 @@
1
+ import { ProductError } from "../errors/product-error.js";
2
+ export function parseRapidXSymbol(symbol) {
3
+ const parts = symbol.split("_");
4
+ const [exchangeRaw, typeRaw, baseRaw, quoteRaw] = parts;
5
+ if (parts.length !== 4 || !exchangeRaw || !typeRaw || !baseRaw || !quoteRaw) {
6
+ throw new ProductError({
7
+ code: "RCORE12001",
8
+ status: "FAIL",
9
+ message: `Invalid RapidX symbol: ${symbol}`
10
+ });
11
+ }
12
+ const exchange = exchangeRaw.toUpperCase();
13
+ const type = typeRaw.toUpperCase();
14
+ if (type !== "PERP" && type !== "SPOT") {
15
+ throw new ProductError({
16
+ code: "RCORE12001",
17
+ status: "FAIL",
18
+ message: `Unsupported RapidX symbol type: ${typeRaw}`
19
+ });
20
+ }
21
+ const base = baseRaw.toUpperCase();
22
+ const quote = quoteRaw.toUpperCase();
23
+ const isPerp = type === "PERP";
24
+ const parsed = {
25
+ exchange,
26
+ base,
27
+ quote,
28
+ type,
29
+ binanceSymbol: `${base}${quote}`,
30
+ isPerp
31
+ };
32
+ if (exchange === "OKX") {
33
+ parsed.okxInstId = isPerp ? `${base}-${quote}-SWAP` : `${base}-${quote}`;
34
+ }
35
+ return parsed;
36
+ }
@@ -0,0 +1,42 @@
1
+ import { createHash } from "node:crypto";
2
+ import { CORE_ERRORS, ProductError } from "../errors/product-error.js";
3
+ export function maskSecret(value) {
4
+ if (!value) {
5
+ return "";
6
+ }
7
+ if (value.length <= 8) {
8
+ return `${value.slice(0, 2)}***${value.slice(-2)}`;
9
+ }
10
+ return `${value.slice(0, 4)}***${value.slice(-4)}`;
11
+ }
12
+ export function credentialFingerprint(value) {
13
+ return createHash("sha256").update(value).digest("hex").slice(0, 12);
14
+ }
15
+ export function makeCredentialRef(source, material = {}) {
16
+ const ref = { source };
17
+ if (material.accessKey) {
18
+ ref.maskedAccessKey = maskSecret(material.accessKey);
19
+ }
20
+ return ref;
21
+ }
22
+ export function makeResolvedCredential(accessKey, secretKey) {
23
+ if (!accessKey || !secretKey) {
24
+ throw new ProductError({
25
+ code: CORE_ERRORS.MISSING_CREDENTIAL,
26
+ status: "NOT_VERIFIED",
27
+ message: "Portfolio credential is not configured."
28
+ });
29
+ }
30
+ return {
31
+ accessKey,
32
+ secretKey,
33
+ maskedAccessKey: maskSecret(accessKey),
34
+ toJSON() {
35
+ throw new ProductError({
36
+ code: CORE_ERRORS.SECRET_REDACTION_RISK,
37
+ status: "FAIL",
38
+ message: "Resolved credentials cannot be serialized."
39
+ });
40
+ }
41
+ };
42
+ }
@@ -0,0 +1,24 @@
1
+ import { makeResolvedCredential } from "./credential.js";
2
+ import { CORE_ERRORS, ProductError } from "../errors/product-error.js";
3
+ export function resolveCredential(options) {
4
+ const env = options.env ?? process.env;
5
+ const material = options.material ?? {};
6
+ if (options.ref.source === "env") {
7
+ const accessKeyRef = options.ref.accessKeyRef ?? "LTP_ACCESS_KEY";
8
+ const secretKeyRef = options.ref.secretKeyRef ?? "LTP_SECRET_KEY";
9
+ const accessKey = firstNonEmpty(env[accessKeyRef]);
10
+ const secretKey = firstNonEmpty(env[secretKeyRef]);
11
+ return makeResolvedCredential(accessKey ?? "", secretKey ?? "");
12
+ }
13
+ if (options.ref.source === "chat-secret" || options.ref.source === "mcp-config" || options.ref.source === "local-file" || options.ref.source === "secret-manager") {
14
+ return makeResolvedCredential(material.accessKey ?? "", material.secretKey ?? "");
15
+ }
16
+ throw new ProductError({
17
+ code: CORE_ERRORS.MISSING_CREDENTIAL,
18
+ status: "NOT_VERIFIED",
19
+ message: `Unsupported credential source: ${String(options.ref.source)}`
20
+ });
21
+ }
22
+ function firstNonEmpty(...values) {
23
+ return values.find((value) => value !== undefined && value.length > 0);
24
+ }
@@ -0,0 +1,77 @@
1
+ import { SCHEMA_VERSION } from "./types.js";
2
+ export const CAPABILITIES = [
3
+ { capabilityId: "config.get", cliCommand: "rapidx config get", operationType: "READ", riskLevel: "read", inputSchema: "ConfigGetInput", outputSchema: "ConfigResult", previewRequired: false },
4
+ { capabilityId: "config.set", cliCommand: "rapidx config set", operationType: "DIAGNOSTIC", riskLevel: "write-config", inputSchema: "ConfigSetInput", outputSchema: "ConfigResult", previewRequired: false },
5
+ { capabilityId: "config.unset", cliCommand: "rapidx config unset", operationType: "DIAGNOSTIC", riskLevel: "write-config", inputSchema: "ConfigUnsetInput", outputSchema: "ConfigResult", previewRequired: false },
6
+ { capabilityId: "config.list", cliCommand: "rapidx config list", operationType: "READ", riskLevel: "read", inputSchema: "EmptyInput", outputSchema: "ConfigResult", previewRequired: false },
7
+ { capabilityId: "auth.check", cliCommand: "rapidx auth check", mcpTool: "rapidx/self-check", operationType: "DIAGNOSTIC", riskLevel: "read", inputSchema: "AuthInput", outputSchema: "AuthResult", previewRequired: false },
8
+ { capabilityId: "doctor.run", cliCommand: "rapidx doctor --json", mcpTool: "rapidx/self-check", operationType: "DIAGNOSTIC", riskLevel: "read", inputSchema: "DoctorInput", outputSchema: "DoctorReport", previewRequired: false },
9
+ { capabilityId: "update.check", cliCommand: "rapidx update check", mcpTool: "rapidx/update/check", operationType: "DIAGNOSTIC", riskLevel: "read", inputSchema: "UpdateCheckInput", outputSchema: "UpdateCheckResult", previewRequired: false },
10
+ { capabilityId: "schema.discover", cliCommand: "rapidx schema --json", mcpTool: "rapidx/tools", operationType: "READ", riskLevel: "read", inputSchema: "SchemaQuery", outputSchema: "SchemaResult", previewRequired: false },
11
+ { capabilityId: "self-check.run", cliCommand: "rapidx self-check --read-only --json", mcpTool: "rapidx/self-check", operationType: "READ", riskLevel: "read", inputSchema: "SelfCheckInput", outputSchema: "SelfCheckReport", previewRequired: false },
12
+ { capabilityId: "market.ticker", cliCommand: "rapidx market get-ticker", mcpTool: "rapidx/market/get-ticker", operationType: "READ", riskLevel: "read", inputSchema: "SymbolInput", outputSchema: "MarketTicker", previewRequired: false },
13
+ { capabilityId: "market.orderbook", cliCommand: "rapidx market get-orderbook", mcpTool: "rapidx/market/get-orderbook", operationType: "READ", riskLevel: "read", inputSchema: "OrderbookInput", outputSchema: "Orderbook", previewRequired: false },
14
+ { capabilityId: "market.klines", cliCommand: "rapidx market get-klines", mcpTool: "rapidx/market/get-klines", operationType: "READ", riskLevel: "read", inputSchema: "KlinesInput", outputSchema: "Klines", previewRequired: false },
15
+ { capabilityId: "market.funding-rate", cliCommand: "rapidx market get-funding-rate", mcpTool: "rapidx/market/get-funding-rate", operationType: "READ", riskLevel: "read", inputSchema: "SymbolInput", outputSchema: "FundingRate", previewRequired: false },
16
+ { capabilityId: "market.mark-price", cliCommand: "rapidx market get-mark-price", mcpTool: "rapidx/market/get-mark-price", operationType: "READ", riskLevel: "read", inputSchema: "SymbolInput", outputSchema: "MarkPrice", previewRequired: false },
17
+ { capabilityId: "market.symbol-info", cliCommand: "rapidx market get-symbol-info", mcpTool: "rapidx/market/get-symbol-info", operationType: "READ", riskLevel: "read", inputSchema: "SymbolInput", outputSchema: "SymbolInfo", previewRequired: false },
18
+ { capabilityId: "market.open-interest", cliCommand: "rapidx market get-open-interest", mcpTool: "rapidx/market/get-open-interest", operationType: "READ", riskLevel: "read", inputSchema: "SymbolInput", outputSchema: "OpenInterest", previewRequired: false },
19
+ { capabilityId: "account.overview", cliCommand: "rapidx account overview", mcpTool: "rapidx/account/overview", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "EmptyInput", outputSchema: "AccountOverview", previewRequired: false },
20
+ { capabilityId: "account.balance", cliCommand: "rapidx account balance", mcpTool: "rapidx/account/balance", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "AccountBalanceInput", outputSchema: "AccountBalance", previewRequired: false },
21
+ { capabilityId: "account.set-position-mode", cliCommand: "rapidx account set-position-mode", mcpTool: "rapidx/account/set-position-mode", operationType: "TRADE_WRITE", riskLevel: "critical-trade-write", inputSchema: "SetPositionModeInput", outputSchema: "SetPositionModeResult", previewRequired: true },
22
+ { capabilityId: "trade.preview", cliCommand: "rapidx trade preview", mcpTool: "rapidx/trade/preview", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "TradePreviewInput", outputSchema: "TradePreviewResult", previewRequired: false },
23
+ { capabilityId: "order.preview", cliCommand: "rapidx order preview", mcpTool: "rapidx/order/preview", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "PreviewOrderInput", outputSchema: "PreviewOrderResult", previewRequired: false },
24
+ { capabilityId: "order.place-preview", cliCommand: "rapidx order place-preview", mcpTool: "rapidx/order/place-preview", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "PreviewOrderInput", outputSchema: "PreviewOrderResult", previewRequired: false },
25
+ { capabilityId: "order.amend-preview", cliCommand: "rapidx order amend-preview", mcpTool: "rapidx/order/amend-preview", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "AmendOrderPreviewInput", outputSchema: "TradePreviewResult", previewRequired: false },
26
+ { capabilityId: "order.cancel-preview", cliCommand: "rapidx order cancel-preview", mcpTool: "rapidx/order/cancel-preview", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "CancelOrderPreviewInput", outputSchema: "TradePreviewResult", previewRequired: false },
27
+ { capabilityId: "order.place", cliCommand: "rapidx order place", mcpTool: "rapidx/order/place", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "PlaceOrderInput", outputSchema: "OrderStatusResult", previewRequired: true },
28
+ { capabilityId: "order.amend", cliCommand: "rapidx order amend", mcpTool: "rapidx/order/amend", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "AmendOrderInput", outputSchema: "OrderStatusResult", previewRequired: true },
29
+ { capabilityId: "order.cancel", cliCommand: "rapidx order cancel", mcpTool: "rapidx/order/cancel", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "CancelOrderInput", outputSchema: "OrderStatusResult", previewRequired: true },
30
+ { capabilityId: "order.get", cliCommand: "rapidx order get", mcpTool: "rapidx/order/get", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "OrderLookupInput", outputSchema: "OrderStatusResult", previewRequired: false },
31
+ { capabilityId: "order.list", cliCommand: "rapidx order list", mcpTool: "rapidx/order/list", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "OrderListInput", outputSchema: "OrderList", previewRequired: false },
32
+ { capabilityId: "order.history", cliCommand: "rapidx order history", mcpTool: "rapidx/order/history", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "OrderHistoryInput", outputSchema: "OrderHistory", previewRequired: false },
33
+ { capabilityId: "position.list", cliCommand: "rapidx position list", mcpTool: "rapidx/position/list", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "PositionListInput", outputSchema: "PositionList", previewRequired: false },
34
+ { capabilityId: "position.history", cliCommand: "rapidx position history", mcpTool: "rapidx/position/history", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "PositionHistoryInput", outputSchema: "PositionHistory", previewRequired: false },
35
+ { capabilityId: "position.close", cliCommand: "rapidx position close", mcpTool: "rapidx/position/close", operationType: "TRADE_WRITE", riskLevel: "critical-trade-write", inputSchema: "ClosePositionInput", outputSchema: "ClosePositionResult", previewRequired: true },
36
+ { capabilityId: "position.set-leverage", cliCommand: "rapidx position set-leverage", mcpTool: "rapidx/position/set-leverage", operationType: "TRADE_WRITE", riskLevel: "critical-trade-write", inputSchema: "SetLeverageInput", outputSchema: "SetLeverageResult", previewRequired: true },
37
+ { capabilityId: "algo.place", cliCommand: "rapidx algo place", mcpTool: "rapidx/algo/place", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "AlgoPlaceInput", outputSchema: "AlgoOrderStatus", previewRequired: true },
38
+ { capabilityId: "algo.amend", cliCommand: "rapidx algo amend", mcpTool: "rapidx/algo/amend", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "AlgoAmendInput", outputSchema: "AlgoOrderStatus", previewRequired: true },
39
+ { capabilityId: "algo.cancel", cliCommand: "rapidx algo cancel", mcpTool: "rapidx/algo/cancel", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "AlgoCancelInput", outputSchema: "AlgoOrderStatus", previewRequired: true },
40
+ { capabilityId: "algo.list", cliCommand: "rapidx algo list", mcpTool: "rapidx/algo/list", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "AlgoListInput", outputSchema: "AlgoList", previewRequired: false },
41
+ { capabilityId: "trading.verify", cliCommand: "rapidx self-check trade-verify", mcpTool: "rapidx/trading-verification", operationType: "TRADE_WRITE", riskLevel: "critical-trade-write", inputSchema: "TradingVerificationInput", outputSchema: "TradingVerificationReport", previewRequired: false },
42
+ { capabilityId: "trading.verify-live", cliCommand: "rapidx trade verify-live", mcpTool: "rapidx/trade/verify-live", operationType: "TRADE_WRITE", riskLevel: "critical-trade-write", inputSchema: "TradingVerificationInput", outputSchema: "TradingVerificationReport", previewRequired: false },
43
+ { capabilityId: "invocation.check", cliCommand: "rapidx invocation check", operationType: "DIAGNOSTIC", riskLevel: "read", inputSchema: "InvocationCheckInput", outputSchema: "InvocationCompliance", previewRequired: false }
44
+ ];
45
+ export function getSchemaResult() {
46
+ return {
47
+ schemaVersion: SCHEMA_VERSION,
48
+ capabilities: [...CAPABILITIES]
49
+ };
50
+ }
51
+ export function listMcpCapabilities() {
52
+ return CAPABILITIES.filter((capability) => Boolean(capability.mcpTool));
53
+ }
54
+ export function findCapabilityById(capabilityId) {
55
+ return CAPABILITIES.find((capability) => capability.capabilityId === capabilityId);
56
+ }
57
+ export function findCapabilityByCliCommand(command) {
58
+ const normalized = command.trim().replace(/\s+/g, " ");
59
+ return CAPABILITIES.find((capability) => capability.cliCommand === normalized);
60
+ }
61
+ export function findCapabilityByMcpTool(toolName) {
62
+ return CAPABILITIES.find((capability) => capability.mcpTool === toolName);
63
+ }
64
+ export function assertCanonicalRegistry() {
65
+ const ids = new Set();
66
+ const cli = new Set();
67
+ for (const capability of CAPABILITIES) {
68
+ if (ids.has(capability.capabilityId)) {
69
+ throw new Error(`Duplicate capabilityId: ${capability.capabilityId}`);
70
+ }
71
+ if (cli.has(capability.cliCommand)) {
72
+ throw new Error(`Duplicate cliCommand: ${capability.cliCommand}`);
73
+ }
74
+ ids.add(capability.capabilityId);
75
+ cli.add(capability.cliCommand);
76
+ }
77
+ }
@@ -0,0 +1,65 @@
1
+ import { SCHEMA_VERSION } from "./types.js";
2
+ import { RAPIDX_VERSION } from "../version.js";
3
+ export const RAPIDX_SKILLS_DISTRIBUTION = "github";
4
+ export const RAPIDX_SKILLS_VERSION = "1.0.1";
5
+ export const RAPIDX_SKILLS_SCHEMA_VERSION = "1.0.0";
6
+ export function buildCompatibilityReport(input = {}) {
7
+ const checks = [
8
+ {
9
+ name: "cli-version",
10
+ status: "PASS",
11
+ expected: RAPIDX_VERSION,
12
+ actual: RAPIDX_VERSION,
13
+ message: "RapidX CLI version is available."
14
+ },
15
+ {
16
+ name: "mcp-schema-version",
17
+ status: compareOptionalVersion(input.mcpSchemaVersion, SCHEMA_VERSION),
18
+ expected: SCHEMA_VERSION,
19
+ actual: input.mcpSchemaVersion ?? SCHEMA_VERSION,
20
+ message: input.mcpSchemaVersion === undefined
21
+ ? "No external MCP schema version was supplied; using bundled schema."
22
+ : "MCP schema version was checked."
23
+ },
24
+ {
25
+ name: "skills-version",
26
+ status: compareOptionalVersion(input.skillsVersion, RAPIDX_SKILLS_VERSION, "NOT_VERIFIED"),
27
+ expected: RAPIDX_SKILLS_VERSION,
28
+ actual: input.skillsVersion,
29
+ message: input.skillsVersion === undefined
30
+ ? "Skills version was not supplied; install or inspect GitHub-distributed skills to verify."
31
+ : "Skills version was checked."
32
+ },
33
+ {
34
+ name: "skills-schema-version",
35
+ status: compareOptionalVersion(input.skillsSchemaVersion, RAPIDX_SKILLS_SCHEMA_VERSION, "NOT_VERIFIED"),
36
+ expected: RAPIDX_SKILLS_SCHEMA_VERSION,
37
+ actual: input.skillsSchemaVersion,
38
+ message: input.skillsSchemaVersion === undefined
39
+ ? "Skills schema version was not supplied; compatibility cannot be fully asserted."
40
+ : "Skills schema version was checked."
41
+ }
42
+ ];
43
+ const status = checks.some((check) => check.status === "BLOCKED")
44
+ ? "BLOCKED"
45
+ : checks.some((check) => check.status === "FAIL")
46
+ ? "FAIL"
47
+ : checks.some((check) => check.status === "NOT_VERIFIED")
48
+ ? "NOT_VERIFIED"
49
+ : "PASS";
50
+ return {
51
+ cliVersion: RAPIDX_VERSION,
52
+ mcpSchemaVersion: SCHEMA_VERSION,
53
+ skillsDistribution: RAPIDX_SKILLS_DISTRIBUTION,
54
+ expectedSkillsVersion: RAPIDX_SKILLS_VERSION,
55
+ expectedSkillsSchemaVersion: RAPIDX_SKILLS_SCHEMA_VERSION,
56
+ status,
57
+ checks
58
+ };
59
+ }
60
+ function compareOptionalVersion(actual, expected, missingStatus = "PASS") {
61
+ if (actual === undefined || actual.length === 0) {
62
+ return missingStatus;
63
+ }
64
+ return actual === expected ? "PASS" : "BLOCKED";
65
+ }
@@ -0,0 +1,29 @@
1
+ export const EVENT_VERSION = "1.0";
2
+ export const EVENTS = [
3
+ { eventName: "CoreAuthChecked", channel: "rapidx.auth", producer: "core", consumer: "cli,mcp,audit", requiredPayload: ["credentialSource", "maskedAccessKey", "permissionStatus", "status", "errorCode"] },
4
+ { eventName: "ToolSchemaUpdated", channel: "rapidx.schema", producer: "core", consumer: "cli,mcp,skills,distribution", requiredPayload: ["schemaVersion", "capabilityIds", "compatibility", "riskChanges"] },
5
+ { eventName: "SelfCheckCompleted", channel: "rapidx.selfcheck", producer: "cli,mcp/core", consumer: "skills,audit", requiredPayload: ["scope", "status", "checks", "notVerifiedItems", "evidence"] },
6
+ { eventName: "TradePreviewCompleted", channel: "rapidx.trade.preview", producer: "cli/mcp/core", consumer: "audit", requiredPayload: ["capabilityId", "previewId", "submitted", "paramsHash", "expiresAt", "status"] },
7
+ { eventName: "TradeWriteSubmitted", channel: "rapidx.trade.write", producer: "cli/mcp/core", consumer: "audit", requiredPayload: ["capabilityId", "clientOrderId", "orderId", "requestId", "confirmationStatus", "status"] },
8
+ { eventName: "TradingVerificationCompleted", channel: "rapidx.trade.verify", producer: "cli/mcp", consumer: "skills,audit", requiredPayload: ["submittedRealOrder", "steps", "cleanupStatus", "status"] },
9
+ { eventName: "CoreSafetyDecisionMade", channel: "rapidx.policy", producer: "core", consumer: "cli,mcp,audit", requiredPayload: ["capabilityId", "decision", "blockedAt", "errorCode"] },
10
+ { eventName: "SafetyPolicyUpdated", channel: "rapidx.policy", producer: "cli/mcp/core", consumer: "audit", requiredPayload: ["readOnly", "tradingEnabled", "maxNotional", "rateLimit", "duplicateWindowMs"] },
11
+ { eventName: "ReleaseArtifactUpdated", channel: "rapidx.release", producer: "distribution", consumer: "cli,mcp,skills", requiredPayload: ["artifact", "version", "checksum", "compatibility", "status"] },
12
+ { eventName: "UserTradingConsentReceived", channel: "rapidx.consent", producer: "skills/agent-host", consumer: "cli,mcp", requiredPayload: ["consentId", "scope", "maxNotional", "acceptedRiskText", "timestamp"] }
13
+ ];
14
+ export function makeEvent(eventName, payload) {
15
+ const definition = EVENTS.find((event) => event.eventName === eventName);
16
+ if (!definition) {
17
+ throw new Error(`Unknown eventName: ${eventName}`);
18
+ }
19
+ return {
20
+ eventName,
21
+ eventVersion: EVENT_VERSION,
22
+ channel: definition.channel,
23
+ timestamp: new Date().toISOString(),
24
+ producer: definition.producer,
25
+ consumer: definition.consumer,
26
+ idempotencyKey: `${eventName}:${JSON.stringify(payload)}`,
27
+ payload
28
+ };
29
+ }
@@ -0,0 +1,7 @@
1
+ export function makeEvidence(toolOrCommandEvidence, source = "local_check") {
2
+ return {
3
+ source,
4
+ toolOrCommandEvidence,
5
+ timestamp: new Date().toISOString()
6
+ };
7
+ }