@raintree-technology/perps 0.1.0

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 (316) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +175 -0
  4. package/dist/adapters/aevo.d.ts +64 -0
  5. package/dist/adapters/aevo.js +899 -0
  6. package/dist/adapters/certification.d.ts +33 -0
  7. package/dist/adapters/certification.js +99 -0
  8. package/dist/adapters/decibel/order-manager.d.ts +45 -0
  9. package/dist/adapters/decibel/order-manager.js +140 -0
  10. package/dist/adapters/decibel/rest-client.d.ts +176 -0
  11. package/dist/adapters/decibel/rest-client.js +155 -0
  12. package/dist/adapters/decibel/ws-feed.d.ts +28 -0
  13. package/dist/adapters/decibel/ws-feed.js +166 -0
  14. package/dist/adapters/decibel.d.ts +108 -0
  15. package/dist/adapters/decibel.js +1377 -0
  16. package/dist/adapters/hyperliquid.d.ts +63 -0
  17. package/dist/adapters/hyperliquid.js +797 -0
  18. package/dist/adapters/index.d.ts +11 -0
  19. package/dist/adapters/index.js +12 -0
  20. package/dist/adapters/interface.d.ts +310 -0
  21. package/dist/adapters/interface.js +15 -0
  22. package/dist/adapters/orderly.d.ts +70 -0
  23. package/dist/adapters/orderly.js +936 -0
  24. package/dist/adapters/paradex.d.ts +69 -0
  25. package/dist/adapters/paradex.js +862 -0
  26. package/dist/adapters/utils.d.ts +17 -0
  27. package/dist/adapters/utils.js +122 -0
  28. package/dist/cli/command-metadata.d.ts +2 -0
  29. package/dist/cli/command-metadata.js +44 -0
  30. package/dist/cli/context.d.ts +14 -0
  31. package/dist/cli/context.js +59 -0
  32. package/dist/cli/experience.d.ts +48 -0
  33. package/dist/cli/experience.js +243 -0
  34. package/dist/cli/ink/app/AppShell.d.ts +12 -0
  35. package/dist/cli/ink/app/AppShell.js +32 -0
  36. package/dist/cli/ink/app/MetricStrip.d.ts +6 -0
  37. package/dist/cli/ink/app/MetricStrip.js +14 -0
  38. package/dist/cli/ink/app/Panel.d.ts +9 -0
  39. package/dist/cli/ink/app/Panel.js +7 -0
  40. package/dist/cli/ink/app/ascii.d.ts +2 -0
  41. package/dist/cli/ink/app/ascii.js +46 -0
  42. package/dist/cli/ink/app/index.d.ts +5 -0
  43. package/dist/cli/ink/app/index.js +4 -0
  44. package/dist/cli/ink/app/types.d.ts +15 -0
  45. package/dist/cli/ink/app/types.js +1 -0
  46. package/dist/cli/ink/components/PnL.d.ts +12 -0
  47. package/dist/cli/ink/components/PnL.js +23 -0
  48. package/dist/cli/ink/components/Spinner.d.ts +13 -0
  49. package/dist/cli/ink/components/Spinner.js +13 -0
  50. package/dist/cli/ink/components/Table.d.ts +14 -0
  51. package/dist/cli/ink/components/Table.js +42 -0
  52. package/dist/cli/ink/components/WatchHeader.d.ts +10 -0
  53. package/dist/cli/ink/components/WatchHeader.js +18 -0
  54. package/dist/cli/ink/components/index.d.ts +4 -0
  55. package/dist/cli/ink/components/index.js +4 -0
  56. package/dist/cli/ink/index.d.ts +4 -0
  57. package/dist/cli/ink/index.js +4 -0
  58. package/dist/cli/ink/render.d.ts +12 -0
  59. package/dist/cli/ink/render.js +21 -0
  60. package/dist/cli/ink/theme.d.ts +29 -0
  61. package/dist/cli/ink/theme.js +40 -0
  62. package/dist/cli/network-defaults.d.ts +10 -0
  63. package/dist/cli/network-defaults.js +35 -0
  64. package/dist/cli/output.d.ts +11 -0
  65. package/dist/cli/output.js +115 -0
  66. package/dist/cli/program.d.ts +18 -0
  67. package/dist/cli/program.js +164 -0
  68. package/dist/cli/watch.d.ts +19 -0
  69. package/dist/cli/watch.js +35 -0
  70. package/dist/client/index.d.ts +55 -0
  71. package/dist/client/index.js +157 -0
  72. package/dist/commands/account/add.d.ts +2 -0
  73. package/dist/commands/account/add.js +510 -0
  74. package/dist/commands/account/balances-simple.d.ts +5 -0
  75. package/dist/commands/account/balances-simple.js +63 -0
  76. package/dist/commands/account/index.d.ts +2 -0
  77. package/dist/commands/account/index.js +17 -0
  78. package/dist/commands/account/ls.d.ts +2 -0
  79. package/dist/commands/account/ls.js +95 -0
  80. package/dist/commands/account/positions-simple.d.ts +5 -0
  81. package/dist/commands/account/positions-simple.js +77 -0
  82. package/dist/commands/account/remove.d.ts +2 -0
  83. package/dist/commands/account/remove.js +47 -0
  84. package/dist/commands/account/set-default.d.ts +2 -0
  85. package/dist/commands/account/set-default.js +47 -0
  86. package/dist/commands/agent/index.d.ts +2 -0
  87. package/dist/commands/agent/index.js +126 -0
  88. package/dist/commands/arb/alert.d.ts +6 -0
  89. package/dist/commands/arb/alert.js +88 -0
  90. package/dist/commands/arb/basis-execute.d.ts +6 -0
  91. package/dist/commands/arb/basis-execute.js +332 -0
  92. package/dist/commands/arb/basis.d.ts +6 -0
  93. package/dist/commands/arb/basis.js +181 -0
  94. package/dist/commands/arb/compare.d.ts +6 -0
  95. package/dist/commands/arb/compare.js +216 -0
  96. package/dist/commands/arb/execute.d.ts +6 -0
  97. package/dist/commands/arb/execute.js +467 -0
  98. package/dist/commands/arb/funding.d.ts +6 -0
  99. package/dist/commands/arb/funding.js +201 -0
  100. package/dist/commands/arb/history.d.ts +6 -0
  101. package/dist/commands/arb/history.js +153 -0
  102. package/dist/commands/arb/index.d.ts +6 -0
  103. package/dist/commands/arb/index.js +29 -0
  104. package/dist/commands/arb/positions.d.ts +6 -0
  105. package/dist/commands/arb/positions.js +158 -0
  106. package/dist/commands/arb/spread.d.ts +6 -0
  107. package/dist/commands/arb/spread.js +253 -0
  108. package/dist/commands/arb/track.d.ts +6 -0
  109. package/dist/commands/arb/track.js +259 -0
  110. package/dist/commands/asset/book-simple.d.ts +5 -0
  111. package/dist/commands/asset/book-simple.js +77 -0
  112. package/dist/commands/asset/index.d.ts +2 -0
  113. package/dist/commands/asset/index.js +5 -0
  114. package/dist/commands/completion.d.ts +2 -0
  115. package/dist/commands/completion.js +161 -0
  116. package/dist/commands/config/index.d.ts +5 -0
  117. package/dist/commands/config/index.js +109 -0
  118. package/dist/commands/data/index.d.ts +31 -0
  119. package/dist/commands/data/index.js +1466 -0
  120. package/dist/commands/doctor.d.ts +2 -0
  121. package/dist/commands/doctor.js +201 -0
  122. package/dist/commands/exchange/index.d.ts +2 -0
  123. package/dist/commands/exchange/index.js +107 -0
  124. package/dist/commands/index.d.ts +2 -0
  125. package/dist/commands/index.js +48 -0
  126. package/dist/commands/markets/index.d.ts +2 -0
  127. package/dist/commands/markets/index.js +5 -0
  128. package/dist/commands/markets/ls-simple.d.ts +7 -0
  129. package/dist/commands/markets/ls-simple.js +277 -0
  130. package/dist/commands/operator/index.d.ts +2 -0
  131. package/dist/commands/operator/index.js +146 -0
  132. package/dist/commands/order/cancel-simple.d.ts +5 -0
  133. package/dist/commands/order/cancel-simple.js +104 -0
  134. package/dist/commands/order/index.d.ts +2 -0
  135. package/dist/commands/order/index.js +13 -0
  136. package/dist/commands/order/limit-simple.d.ts +5 -0
  137. package/dist/commands/order/limit-simple.js +195 -0
  138. package/dist/commands/order/market-simple.d.ts +5 -0
  139. package/dist/commands/order/market-simple.js +190 -0
  140. package/dist/commands/order/shared.d.ts +17 -0
  141. package/dist/commands/order/shared.js +51 -0
  142. package/dist/commands/order/trigger-simple.d.ts +5 -0
  143. package/dist/commands/order/trigger-simple.js +246 -0
  144. package/dist/commands/referral/index.d.ts +2 -0
  145. package/dist/commands/referral/index.js +7 -0
  146. package/dist/commands/referral/set.d.ts +2 -0
  147. package/dist/commands/referral/set.js +26 -0
  148. package/dist/commands/referral/status.d.ts +2 -0
  149. package/dist/commands/referral/status.js +31 -0
  150. package/dist/commands/replay/index.d.ts +2 -0
  151. package/dist/commands/replay/index.js +152 -0
  152. package/dist/commands/risk/analytics.d.ts +2 -0
  153. package/dist/commands/risk/analytics.js +64 -0
  154. package/dist/commands/risk/audit.d.ts +2 -0
  155. package/dist/commands/risk/audit.js +52 -0
  156. package/dist/commands/risk/index.d.ts +2 -0
  157. package/dist/commands/risk/index.js +9 -0
  158. package/dist/commands/risk/rules.d.ts +2 -0
  159. package/dist/commands/risk/rules.js +102 -0
  160. package/dist/commands/server.d.ts +2 -0
  161. package/dist/commands/server.js +208 -0
  162. package/dist/commands/setup/index.d.ts +2 -0
  163. package/dist/commands/setup/index.js +478 -0
  164. package/dist/commands/signal/index.d.ts +2 -0
  165. package/dist/commands/signal/index.js +129 -0
  166. package/dist/commands/state/index.d.ts +2 -0
  167. package/dist/commands/state/index.js +5 -0
  168. package/dist/commands/state/show.d.ts +2 -0
  169. package/dist/commands/state/show.js +105 -0
  170. package/dist/commands/strategy/index.d.ts +4 -0
  171. package/dist/commands/strategy/index.js +73 -0
  172. package/dist/commands/traces/index.d.ts +2 -0
  173. package/dist/commands/traces/index.js +76 -0
  174. package/dist/commands/ui/demo.d.ts +9 -0
  175. package/dist/commands/ui/demo.js +195 -0
  176. package/dist/commands/ui/index.d.ts +2 -0
  177. package/dist/commands/ui/index.js +7 -0
  178. package/dist/commands/ui/terminal.d.ts +2 -0
  179. package/dist/commands/ui/terminal.js +255 -0
  180. package/dist/commands/upgrade.d.ts +2 -0
  181. package/dist/commands/upgrade.js +98 -0
  182. package/dist/index.d.ts +2 -0
  183. package/dist/index.js +4 -0
  184. package/dist/lib/agent/audit.d.ts +12 -0
  185. package/dist/lib/agent/audit.js +13 -0
  186. package/dist/lib/agent/gateway.d.ts +13 -0
  187. package/dist/lib/agent/gateway.js +598 -0
  188. package/dist/lib/agent/metrics.d.ts +33 -0
  189. package/dist/lib/agent/metrics.js +175 -0
  190. package/dist/lib/agent/signature.d.ts +8 -0
  191. package/dist/lib/agent/signature.js +28 -0
  192. package/dist/lib/agent/tools.d.ts +28 -0
  193. package/dist/lib/agent/tools.js +453 -0
  194. package/dist/lib/agent/x402.d.ts +23 -0
  195. package/dist/lib/agent/x402.js +62 -0
  196. package/dist/lib/api-wallet.d.ts +69 -0
  197. package/dist/lib/api-wallet.js +101 -0
  198. package/dist/lib/balance-watcher.d.ts +25 -0
  199. package/dist/lib/balance-watcher.js +83 -0
  200. package/dist/lib/book-watcher.d.ts +25 -0
  201. package/dist/lib/book-watcher.js +48 -0
  202. package/dist/lib/config.d.ts +88 -0
  203. package/dist/lib/config.js +427 -0
  204. package/dist/lib/constants.d.ts +50 -0
  205. package/dist/lib/constants.js +84 -0
  206. package/dist/lib/contracts.d.ts +7 -0
  207. package/dist/lib/contracts.js +8 -0
  208. package/dist/lib/credential-vault.d.ts +22 -0
  209. package/dist/lib/credential-vault.js +109 -0
  210. package/dist/lib/db/accounts.d.ts +83 -0
  211. package/dist/lib/db/accounts.js +203 -0
  212. package/dist/lib/db/funding-history.d.ts +69 -0
  213. package/dist/lib/db/funding-history.js +183 -0
  214. package/dist/lib/db/index.d.ts +11 -0
  215. package/dist/lib/db/index.js +272 -0
  216. package/dist/lib/events/bus.d.ts +10 -0
  217. package/dist/lib/events/bus.js +17 -0
  218. package/dist/lib/events/types.d.ts +51 -0
  219. package/dist/lib/events/types.js +1 -0
  220. package/dist/lib/exchange.d.ts +30 -0
  221. package/dist/lib/exchange.js +84 -0
  222. package/dist/lib/execution/journal.d.ts +25 -0
  223. package/dist/lib/execution/journal.js +158 -0
  224. package/dist/lib/execution/safety.d.ts +34 -0
  225. package/dist/lib/execution/safety.js +197 -0
  226. package/dist/lib/exit-codes.d.ts +18 -0
  227. package/dist/lib/exit-codes.js +60 -0
  228. package/dist/lib/fetch.d.ts +18 -0
  229. package/dist/lib/fetch.js +66 -0
  230. package/dist/lib/fs-security.d.ts +10 -0
  231. package/dist/lib/fs-security.js +26 -0
  232. package/dist/lib/funding-tracker.d.ts +40 -0
  233. package/dist/lib/funding-tracker.js +118 -0
  234. package/dist/lib/logger.d.ts +27 -0
  235. package/dist/lib/logger.js +82 -0
  236. package/dist/lib/network-model.d.ts +13 -0
  237. package/dist/lib/network-model.js +30 -0
  238. package/dist/lib/onboarding.d.ts +133 -0
  239. package/dist/lib/onboarding.js +1459 -0
  240. package/dist/lib/operator-state.d.ts +25 -0
  241. package/dist/lib/operator-state.js +82 -0
  242. package/dist/lib/orders-watcher.d.ts +24 -0
  243. package/dist/lib/orders-watcher.js +74 -0
  244. package/dist/lib/paths.d.ts +20 -0
  245. package/dist/lib/paths.js +23 -0
  246. package/dist/lib/portfolio-watcher.d.ts +33 -0
  247. package/dist/lib/portfolio-watcher.js +95 -0
  248. package/dist/lib/position-watcher.d.ts +16 -0
  249. package/dist/lib/position-watcher.js +44 -0
  250. package/dist/lib/price-watcher.d.ts +15 -0
  251. package/dist/lib/price-watcher.js +84 -0
  252. package/dist/lib/prompts.d.ts +32 -0
  253. package/dist/lib/prompts.js +105 -0
  254. package/dist/lib/rate-limit.d.ts +32 -0
  255. package/dist/lib/rate-limit.js +88 -0
  256. package/dist/lib/risk/analytics.d.ts +39 -0
  257. package/dist/lib/risk/analytics.js +98 -0
  258. package/dist/lib/risk/drawdown.d.ts +18 -0
  259. package/dist/lib/risk/drawdown.js +49 -0
  260. package/dist/lib/risk/evaluation-log.d.ts +29 -0
  261. package/dist/lib/risk/evaluation-log.js +61 -0
  262. package/dist/lib/risk/index.d.ts +4 -0
  263. package/dist/lib/risk/index.js +4 -0
  264. package/dist/lib/risk/limits.d.ts +23 -0
  265. package/dist/lib/risk/limits.js +27 -0
  266. package/dist/lib/risk/manager.d.ts +32 -0
  267. package/dist/lib/risk/manager.js +85 -0
  268. package/dist/lib/risk/policy-middleware.d.ts +33 -0
  269. package/dist/lib/risk/policy-middleware.js +267 -0
  270. package/dist/lib/risk/position-sizer.d.ts +9 -0
  271. package/dist/lib/risk/position-sizer.js +14 -0
  272. package/dist/lib/risk/rules-store.d.ts +16 -0
  273. package/dist/lib/risk/rules-store.js +47 -0
  274. package/dist/lib/schema.d.ts +254 -0
  275. package/dist/lib/schema.js +199 -0
  276. package/dist/lib/secrets.d.ts +3 -0
  277. package/dist/lib/secrets.js +62 -0
  278. package/dist/lib/settings.d.ts +24 -0
  279. package/dist/lib/settings.js +86 -0
  280. package/dist/lib/signals.d.ts +73 -0
  281. package/dist/lib/signals.js +136 -0
  282. package/dist/lib/stable-stringify.d.ts +6 -0
  283. package/dist/lib/stable-stringify.js +17 -0
  284. package/dist/lib/state-context.d.ts +44 -0
  285. package/dist/lib/state-context.js +133 -0
  286. package/dist/lib/strategy/basis-trade.d.ts +2 -0
  287. package/dist/lib/strategy/basis-trade.js +24 -0
  288. package/dist/lib/strategy/funding-arb.d.ts +2 -0
  289. package/dist/lib/strategy/funding-arb.js +23 -0
  290. package/dist/lib/strategy/interface.d.ts +23 -0
  291. package/dist/lib/strategy/interface.js +1 -0
  292. package/dist/lib/strategy/registry.d.ts +4 -0
  293. package/dist/lib/strategy/registry.js +10 -0
  294. package/dist/lib/telemetry.d.ts +25 -0
  295. package/dist/lib/telemetry.js +101 -0
  296. package/dist/lib/trace-queries.d.ts +20 -0
  297. package/dist/lib/trace-queries.js +133 -0
  298. package/dist/lib/trace.d.ts +1 -0
  299. package/dist/lib/trace.js +4 -0
  300. package/dist/lib/trade-reputation.d.ts +6 -0
  301. package/dist/lib/trade-reputation.js +99 -0
  302. package/dist/lib/ui-tokens.d.ts +21 -0
  303. package/dist/lib/ui-tokens.js +26 -0
  304. package/dist/lib/validate.d.ts +39 -0
  305. package/dist/lib/validate.js +108 -0
  306. package/dist/lib/validation.d.ts +9 -0
  307. package/dist/lib/validation.js +64 -0
  308. package/dist/server/cache.d.ts +38 -0
  309. package/dist/server/cache.js +56 -0
  310. package/dist/server/index.d.ts +2 -0
  311. package/dist/server/index.js +89 -0
  312. package/dist/server/ipc.d.ts +18 -0
  313. package/dist/server/ipc.js +159 -0
  314. package/dist/server/subscriptions.d.ts +18 -0
  315. package/dist/server/subscriptions.js +114 -0
  316. package/package.json +124 -0
@@ -0,0 +1,52 @@
1
+ import { getOutputOptions } from "../../cli/program.js";
2
+ import { output } from "../../cli/output.js";
3
+ import { withJsonContract } from "../../lib/contracts.js";
4
+ import { queryRiskEvaluations } from "../../lib/risk/evaluation-log.js";
5
+ export function registerRiskAuditCommand(parent) {
6
+ parent
7
+ .command("audit")
8
+ .description("Query risk evaluation log")
9
+ .option("--market <m>", "Filter by market")
10
+ .option("--exchange <e>", "Filter by exchange")
11
+ .option("--denied-only", "Show only denied evaluations")
12
+ .option("--trace <traceId>", "Filter by trace ID")
13
+ .option("--limit <n>", "Maximum results to return", Number.parseInt)
14
+ .action(function () {
15
+ const outputOpts = getOutputOptions(this);
16
+ const opts = this.opts();
17
+ const evaluations = queryRiskEvaluations({
18
+ market: opts.market,
19
+ exchange: opts.exchange,
20
+ allowed: opts.deniedOnly ? false : undefined,
21
+ traceId: opts.trace,
22
+ limit: opts.limit,
23
+ });
24
+ if (outputOpts.json) {
25
+ output(withJsonContract("risk.audit.list", { evaluations }), outputOpts);
26
+ return;
27
+ }
28
+ if (evaluations.length === 0) {
29
+ console.log("\nNo risk evaluations found.\n");
30
+ return;
31
+ }
32
+ console.log("");
33
+ for (const ev of evaluations) {
34
+ const ts = new Date(ev.createdAt).toISOString();
35
+ const status = ev.allowed ? "ALLOWED" : "DENIED";
36
+ console.log(` [${ts}] ${status}`);
37
+ console.log(` Exchange: ${ev.exchange}`);
38
+ if (ev.market)
39
+ console.log(` Market: ${ev.market}`);
40
+ if (ev.side)
41
+ console.log(` Side: ${ev.side}`);
42
+ console.log(` Requested: $${ev.requestedSizeUsd.toFixed(2)}`);
43
+ if (ev.rulesFired.length > 0) {
44
+ console.log(` Rules fired: ${ev.rulesFired.join(", ")}`);
45
+ }
46
+ if (ev.reason) {
47
+ console.log(` Reason: ${ev.reason}`);
48
+ }
49
+ console.log("");
50
+ }
51
+ });
52
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerRiskCommands(program: Command): void;
@@ -0,0 +1,9 @@
1
+ import { registerRiskRulesCommands } from "./rules.js";
2
+ import { registerRiskAuditCommand } from "./audit.js";
3
+ import { registerRiskAnalyticsCommands } from "./analytics.js";
4
+ export function registerRiskCommands(program) {
5
+ const risk = program.command("risk").description("Risk rules, limits, and audit");
6
+ registerRiskRulesCommands(risk);
7
+ registerRiskAuditCommand(risk);
8
+ registerRiskAnalyticsCommands(risk);
9
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerRiskRulesCommands(parent: Command): void;
@@ -0,0 +1,102 @@
1
+ import { getOutputOptions } from "../../cli/program.js";
2
+ import { output, outputError, outputSuccess } from "../../cli/output.js";
3
+ import { withJsonContract } from "../../lib/contracts.js";
4
+ import { addRiskRule, listRiskRules, removeRiskRule, } from "../../lib/risk/rules-store.js";
5
+ const VALID_TYPES = [
6
+ "max_position_size",
7
+ "max_total_exposure",
8
+ "max_leverage",
9
+ "max_drawdown",
10
+ "min_confidence",
11
+ "cooldown_after_loss",
12
+ "rate_limit",
13
+ ];
14
+ const VALID_SCOPES = ["global", "exchange", "market", "strategy"];
15
+ export function registerRiskRulesCommands(parent) {
16
+ const rules = parent.command("rules").description("Manage risk rules");
17
+ rules
18
+ .command("ls")
19
+ .description("List all risk rules")
20
+ .action(function () {
21
+ const outputOpts = getOutputOptions(this);
22
+ const allRules = listRiskRules();
23
+ if (outputOpts.json) {
24
+ output(withJsonContract("risk.rules.list", { rules: allRules }), outputOpts);
25
+ return;
26
+ }
27
+ if (allRules.length === 0) {
28
+ console.log("\nNo risk rules configured.\n");
29
+ return;
30
+ }
31
+ const rows = allRules.map((r) => ({
32
+ ID: r.id,
33
+ Name: r.name,
34
+ Type: r.type,
35
+ Scope: r.scope,
36
+ "Scope Value": r.scopeValue ?? "",
37
+ Value: r.value,
38
+ Enabled: r.enabled ? "yes" : "no",
39
+ }));
40
+ output(rows, outputOpts);
41
+ });
42
+ rules
43
+ .command("add")
44
+ .description("Add a risk rule")
45
+ .requiredOption("--name <name>", "Rule name")
46
+ .requiredOption("--type <type>", "Rule type")
47
+ .requiredOption("--scope <scope>", "Rule scope (global, exchange, market, strategy)")
48
+ .option("--scope-value <value>", "Scope value (e.g. exchange name, market symbol)")
49
+ .requiredOption("--value <number>", "Rule threshold value", Number.parseFloat)
50
+ .option("--disabled", "Create the rule in disabled state")
51
+ .action(function () {
52
+ const outputOpts = getOutputOptions(this);
53
+ const opts = this.opts();
54
+ if (!VALID_TYPES.includes(opts.type)) {
55
+ outputError(`Invalid type "${opts.type}". Must be one of: ${VALID_TYPES.join(", ")}`);
56
+ process.exitCode = 1;
57
+ return;
58
+ }
59
+ if (!VALID_SCOPES.includes(opts.scope)) {
60
+ outputError(`Invalid scope "${opts.scope}". Must be one of: ${VALID_SCOPES.join(", ")}`);
61
+ process.exitCode = 1;
62
+ return;
63
+ }
64
+ const id = addRiskRule({
65
+ name: opts.name,
66
+ type: opts.type,
67
+ scope: opts.scope,
68
+ scopeValue: opts.scopeValue ?? null,
69
+ value: opts.value,
70
+ enabled: !opts.disabled,
71
+ });
72
+ if (outputOpts.json) {
73
+ output({ success: true, id }, outputOpts);
74
+ return;
75
+ }
76
+ outputSuccess(`Rule added with ID ${id}`);
77
+ });
78
+ rules
79
+ .command("remove <id>")
80
+ .description("Remove a risk rule by ID")
81
+ .action(function (id) {
82
+ const outputOpts = getOutputOptions(this);
83
+ const numericId = Number.parseInt(id, 10);
84
+ if (Number.isNaN(numericId)) {
85
+ outputError("Invalid rule ID");
86
+ process.exitCode = 1;
87
+ return;
88
+ }
89
+ const removed = removeRiskRule(numericId);
90
+ if (outputOpts.json) {
91
+ output({ success: removed, id: numericId }, outputOpts);
92
+ return;
93
+ }
94
+ if (removed) {
95
+ outputSuccess(`Rule ${numericId} removed`);
96
+ }
97
+ else {
98
+ outputError(`Rule ${numericId} not found`);
99
+ process.exitCode = 1;
100
+ }
101
+ });
102
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerServerCommands(program: Command): void;
@@ -0,0 +1,208 @@
1
+ import { spawn } from "node:child_process";
2
+ import { readFileSync, existsSync } from "node:fs";
3
+ import { fileURLToPath } from "node:url";
4
+ import { dirname, join } from "node:path";
5
+ import { getOutputOptions } from "../cli/program.js";
6
+ import { output, outputError, outputSuccess } from "../cli/output.js";
7
+ import { SERVER_PID_PATH, SERVER_LOG_PATH } from "../lib/paths.js";
8
+ import { ServerClient, isServerRunning } from "../client/index.js";
9
+ export function registerServerCommands(program) {
10
+ const server = program.command("server").description("Manage the background WebSocket server");
11
+ server
12
+ .command("start")
13
+ .description("Start the background WebSocket server")
14
+ .action(async function () {
15
+ const opts = this.optsWithGlobals();
16
+ const isTestnet = opts.testnet ?? false;
17
+ // Check if server is already running
18
+ if (existsSync(SERVER_PID_PATH)) {
19
+ const pid = parseInt(readFileSync(SERVER_PID_PATH, "utf-8").trim(), 10);
20
+ try {
21
+ // Check if process is still alive (signal 0 just checks)
22
+ process.kill(pid, 0);
23
+ outputError(`Server is already running (pid: ${pid})`);
24
+ process.exit(1);
25
+ }
26
+ catch {
27
+ // Process not running, PID file is stale
28
+ }
29
+ }
30
+ // Resolve server entry point for both built (dist) and dev (src) modes.
31
+ const __filename = fileURLToPath(import.meta.url);
32
+ const __dirname = dirname(__filename);
33
+ const jsServerPath = join(__dirname, "..", "server", "index.js");
34
+ const tsServerPath = join(__dirname, "..", "server", "index.ts");
35
+ let spawnCommand = process.execPath;
36
+ let spawnArgs = [];
37
+ if (existsSync(jsServerPath)) {
38
+ spawnArgs = [jsServerPath];
39
+ }
40
+ else if (existsSync(tsServerPath)) {
41
+ // Use local tsx bin for source-mode runs (`pnpm dev`).
42
+ const tsxBin = join(process.cwd(), "node_modules", ".bin", process.platform === "win32" ? "tsx.cmd" : "tsx");
43
+ if (existsSync(tsxBin)) {
44
+ spawnCommand = tsxBin;
45
+ spawnArgs = [tsServerPath];
46
+ }
47
+ else {
48
+ // Fallback for environments where tsx is available as a node import.
49
+ spawnArgs = ["--import", "tsx", tsServerPath];
50
+ }
51
+ }
52
+ else {
53
+ outputError(`Server entry point not found: ${jsServerPath} or ${tsServerPath}`);
54
+ process.exit(1);
55
+ }
56
+ // Spawn server as detached background process
57
+ if (isTestnet) {
58
+ spawnArgs.push("--testnet");
59
+ }
60
+ const child = spawn(spawnCommand, spawnArgs, {
61
+ detached: true,
62
+ stdio: "ignore",
63
+ });
64
+ child.unref();
65
+ // Wait for server to start (poll for socket file, max 10 seconds)
66
+ const maxWait = 10_000;
67
+ const pollInterval = 200;
68
+ let waited = 0;
69
+ while (waited < maxWait) {
70
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
71
+ waited += pollInterval;
72
+ if (isServerRunning()) {
73
+ // Try connecting to verify it's ready
74
+ try {
75
+ const client = new ServerClient();
76
+ await client.connect();
77
+ await client.getStatus();
78
+ client.close();
79
+ const network = isTestnet ? "testnet" : "mainnet";
80
+ outputSuccess(`Server started (${network})`);
81
+ return;
82
+ }
83
+ catch {
84
+ // Socket exists but server not ready yet, keep waiting
85
+ }
86
+ }
87
+ }
88
+ outputError(`Failed to start server. Check logs at: ${SERVER_LOG_PATH}`);
89
+ process.exit(1);
90
+ });
91
+ server
92
+ .command("stop")
93
+ .description("Stop the background WebSocket server")
94
+ .action(async function () {
95
+ if (!isServerRunning()) {
96
+ outputError("Server is not running, run 'perps server start' to start it");
97
+ process.exit(1);
98
+ }
99
+ try {
100
+ const client = new ServerClient();
101
+ await client.connect();
102
+ await client.shutdown();
103
+ client.close();
104
+ // Wait for server to stop
105
+ await new Promise((resolve) => setTimeout(resolve, 500));
106
+ if (isServerRunning()) {
107
+ // Force kill if still running
108
+ if (existsSync(SERVER_PID_PATH)) {
109
+ const pid = parseInt(readFileSync(SERVER_PID_PATH, "utf-8").trim(), 10);
110
+ try {
111
+ process.kill(pid, "SIGKILL");
112
+ }
113
+ catch {
114
+ // Already dead
115
+ }
116
+ }
117
+ }
118
+ outputSuccess("Server stopped");
119
+ }
120
+ catch (err) {
121
+ // Try force kill via PID
122
+ if (existsSync(SERVER_PID_PATH)) {
123
+ const pid = parseInt(readFileSync(SERVER_PID_PATH, "utf-8").trim(), 10);
124
+ try {
125
+ process.kill(pid, "SIGTERM");
126
+ outputSuccess("Server stopped");
127
+ return;
128
+ }
129
+ catch {
130
+ // Already dead
131
+ }
132
+ }
133
+ outputError(err instanceof Error ? err.message : String(err));
134
+ process.exit(1);
135
+ }
136
+ });
137
+ server
138
+ .command("status")
139
+ .description("Show background server status")
140
+ .action(async function () {
141
+ const outputOpts = getOutputOptions(this);
142
+ if (!isServerRunning()) {
143
+ if (outputOpts.json) {
144
+ output({ running: false }, outputOpts);
145
+ }
146
+ else {
147
+ console.log(`Server is not running, run 'perps server start' to start it`);
148
+ }
149
+ return;
150
+ }
151
+ try {
152
+ const client = new ServerClient();
153
+ await client.connect();
154
+ const status = await client.getStatus();
155
+ client.close();
156
+ if (outputOpts.json) {
157
+ output(status, outputOpts);
158
+ }
159
+ else {
160
+ console.log(`Status: running`);
161
+ console.log(`Network: ${status.testnet ? "testnet" : "mainnet"}`);
162
+ console.log(`WebSocket: ${status.connected ? "connected" : "disconnected"}`);
163
+ console.log(`Uptime: ${formatUptime(status.uptime)}`);
164
+ console.log(``);
165
+ console.log(`Cache:`);
166
+ console.log(` Mid Prices: ${status.cache.hasMids ? `cached (${formatAge(status.cache.midsAge)} ago)` : "not loaded"}`);
167
+ console.log(` Perp Meta: ${status.cache.hasPerpMetas ? `cached (${formatAge(status.cache.perpMetasAge)} ago)` : "not loaded"}`);
168
+ console.log(` Perp Asset Ctxs: ${status.cache.hasAssetCtxs ? `cached (${formatAge(status.cache.assetCtxsAge)} ago)` : "not loaded"}`);
169
+ console.log(` Spot Meta: ${status.cache.hasSpotMeta ? `cached (${formatAge(status.cache.spotMetaAge)} ago)` : "not loaded"}`);
170
+ console.log(` Spot Ctxs: ${status.cache.hasSpotAssetCtxs ? `cached (${formatAge(status.cache.spotAssetCtxsAge)} ago)` : "not loaded"}`);
171
+ }
172
+ }
173
+ catch (err) {
174
+ // Server might be in bad state
175
+ if (outputOpts.json) {
176
+ output({ running: true, error: String(err) }, outputOpts);
177
+ }
178
+ else {
179
+ console.log(`Server appears running but not responding`);
180
+ console.log(`Try: perps server stop && perps server start`);
181
+ }
182
+ }
183
+ });
184
+ }
185
+ function formatUptime(ms) {
186
+ const seconds = Math.floor(ms / 1000);
187
+ const minutes = Math.floor(seconds / 60);
188
+ const hours = Math.floor(minutes / 60);
189
+ const days = Math.floor(hours / 24);
190
+ if (days > 0)
191
+ return `${days}d ${hours % 24}h`;
192
+ if (hours > 0)
193
+ return `${hours}h ${minutes % 60}m`;
194
+ if (minutes > 0)
195
+ return `${minutes}m ${seconds % 60}s`;
196
+ return `${seconds}s`;
197
+ }
198
+ function formatAge(ms) {
199
+ if (ms === undefined)
200
+ return "unknown";
201
+ if (ms < 1000)
202
+ return `${ms}ms`;
203
+ const seconds = Math.floor(ms / 1000);
204
+ if (seconds < 60)
205
+ return `${seconds}s`;
206
+ const minutes = Math.floor(seconds / 60);
207
+ return `${minutes}m ${seconds % 60}s`;
208
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerSetupCommands(program: Command): void;