@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,17 @@
1
+ /**
2
+ * Shared adapter utilities for safe payload extraction and type conversion.
3
+ *
4
+ * These helpers allow adapters to traverse untyped JSON payloads (REST/WS responses)
5
+ * and extract typed values without unsafe casts.
6
+ */
7
+ export type JsonRecord = Record<string, unknown>;
8
+ export declare function isRecord(value: unknown): value is JsonRecord;
9
+ export declare function pickUnknown(payload: unknown, paths: string[]): unknown;
10
+ export declare function pickArray(payload: unknown, paths: string[]): JsonRecord[];
11
+ export declare function pickObject(payload: unknown, paths: string[]): JsonRecord | null;
12
+ export declare function pickString(payload: unknown, paths: string[]): string | null;
13
+ export declare function pickNumber(payload: unknown, paths: string[], fallback: number): number;
14
+ export declare function pickBoolean(payload: unknown, paths: string[], fallback: boolean): boolean;
15
+ export declare function toTimestampMs(value: unknown, fallback: number): number;
16
+ export declare function decimalToScaled(value: string, decimals: number): bigint;
17
+ export declare function decimalPlaces(value: string): number;
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Shared adapter utilities for safe payload extraction and type conversion.
3
+ *
4
+ * These helpers allow adapters to traverse untyped JSON payloads (REST/WS responses)
5
+ * and extract typed values without unsafe casts.
6
+ */
7
+ export function isRecord(value) {
8
+ return typeof value === "object" && value !== null;
9
+ }
10
+ export function pickUnknown(payload, paths) {
11
+ for (const path of paths) {
12
+ const segments = path.split(".");
13
+ let current = payload;
14
+ let valid = true;
15
+ for (const segment of segments) {
16
+ if (Array.isArray(current)) {
17
+ const index = Number(segment);
18
+ if (!Number.isInteger(index) || index < 0 || index >= current.length) {
19
+ valid = false;
20
+ break;
21
+ }
22
+ current = current[index];
23
+ continue;
24
+ }
25
+ if (!isRecord(current) || !(segment in current)) {
26
+ valid = false;
27
+ break;
28
+ }
29
+ current = current[segment];
30
+ }
31
+ if (valid)
32
+ return current;
33
+ }
34
+ return undefined;
35
+ }
36
+ export function pickArray(payload, paths) {
37
+ for (const path of paths) {
38
+ const value = pickUnknown(payload, [path]);
39
+ if (Array.isArray(value)) {
40
+ return value.filter(isRecord);
41
+ }
42
+ }
43
+ if (Array.isArray(payload)) {
44
+ return payload.filter(isRecord);
45
+ }
46
+ return [];
47
+ }
48
+ export function pickObject(payload, paths) {
49
+ for (const path of paths) {
50
+ const value = pickUnknown(payload, [path]);
51
+ if (isRecord(value)) {
52
+ return value;
53
+ }
54
+ }
55
+ return null;
56
+ }
57
+ export function pickString(payload, paths) {
58
+ const value = pickUnknown(payload, paths);
59
+ if (typeof value === "string")
60
+ return value;
61
+ if (typeof value === "number" && Number.isFinite(value))
62
+ return value.toString();
63
+ if (typeof value === "bigint")
64
+ return value.toString();
65
+ return null;
66
+ }
67
+ export function pickNumber(payload, paths, fallback) {
68
+ const value = pickUnknown(payload, paths);
69
+ if (typeof value === "number" && Number.isFinite(value))
70
+ return value;
71
+ if (typeof value === "string") {
72
+ const parsed = parseFloat(value);
73
+ if (Number.isFinite(parsed))
74
+ return parsed;
75
+ }
76
+ if (typeof value === "bigint")
77
+ return Number(value);
78
+ return fallback;
79
+ }
80
+ export function pickBoolean(payload, paths, fallback) {
81
+ const value = pickUnknown(payload, paths);
82
+ if (typeof value === "boolean")
83
+ return value;
84
+ if (typeof value === "string") {
85
+ if (value.toLowerCase() === "true")
86
+ return true;
87
+ if (value.toLowerCase() === "false")
88
+ return false;
89
+ }
90
+ return fallback;
91
+ }
92
+ export function toTimestampMs(value, fallback) {
93
+ if (typeof value === "number" && Number.isFinite(value)) {
94
+ return value > 1e12 ? value : value * 1000;
95
+ }
96
+ if (typeof value === "string") {
97
+ const parsed = Number(value);
98
+ if (Number.isFinite(parsed)) {
99
+ return parsed > 1e12 ? parsed : parsed * 1000;
100
+ }
101
+ }
102
+ return fallback;
103
+ }
104
+ export function decimalToScaled(value, decimals) {
105
+ const trimmed = value.trim();
106
+ if (!trimmed)
107
+ return 0n;
108
+ const negative = trimmed.startsWith("-");
109
+ const normalized = negative ? trimmed.slice(1) : trimmed;
110
+ const [wholeRaw, fractionRaw = ""] = normalized.split(".");
111
+ const whole = wholeRaw === "" ? "0" : wholeRaw;
112
+ const fraction = (fractionRaw + "0".repeat(decimals)).slice(0, decimals);
113
+ const digits = `${whole}${fraction}`.replace(/^0+/, "") || "0";
114
+ const scaled = BigInt(digits);
115
+ return negative ? -scaled : scaled;
116
+ }
117
+ export function decimalPlaces(value) {
118
+ const idx = value.indexOf(".");
119
+ if (idx === -1)
120
+ return 0;
121
+ return value.length - idx - 1;
122
+ }
@@ -0,0 +1,2 @@
1
+ export type CommandIntent = "execution" | "data" | "neutral";
2
+ export declare function classifyCommandIntentFromMetadata(path: string[]): CommandIntent;
@@ -0,0 +1,44 @@
1
+ const ROOT_INTENTS = {
2
+ order: "execution",
3
+ markets: "data",
4
+ asset: "data",
5
+ data: "data",
6
+ exchange: "data",
7
+ ui: "data",
8
+ };
9
+ const PATH_INTENTS = {
10
+ "arb/execute": "execution",
11
+ "account/add": "execution",
12
+ "agent/serve": "execution",
13
+ "arb/spread": "data",
14
+ "arb/funding": "data",
15
+ "arb/track": "data",
16
+ "arb/compare": "data",
17
+ "arb/history": "data",
18
+ "arb/positions": "data",
19
+ "arb/alert": "data",
20
+ "account/balances": "data",
21
+ "account/positions": "data",
22
+ "account/ls": "data",
23
+ "account/remove": "data",
24
+ "account/set-default": "data",
25
+ };
26
+ function normalizePath(path) {
27
+ return path.map((segment) => segment.trim().toLowerCase()).filter(Boolean);
28
+ }
29
+ export function classifyCommandIntentFromMetadata(path) {
30
+ const normalizedPath = normalizePath(path);
31
+ if (normalizedPath.length === 0) {
32
+ return "neutral";
33
+ }
34
+ const fullPath = normalizedPath.join("/");
35
+ const pathIntent = PATH_INTENTS[fullPath];
36
+ if (pathIntent) {
37
+ return pathIntent;
38
+ }
39
+ const rootIntent = ROOT_INTENTS[normalizedPath[0]];
40
+ if (rootIntent) {
41
+ return rootIntent;
42
+ }
43
+ return "neutral";
44
+ }
@@ -0,0 +1,14 @@
1
+ import { InfoClient, ExchangeClient } from "@nktkas/hyperliquid";
2
+ import type { Config } from "../lib/config.js";
3
+ import type { Address } from "viem";
4
+ import { ServerClient } from "../client/index.js";
5
+ export interface CLIContext {
6
+ config: Config;
7
+ getPublicClient(): InfoClient;
8
+ getWalletClient(): ExchangeClient;
9
+ getWalletAddress(): Address;
10
+ getServerClient(): Promise<ServerClient | null>;
11
+ hasAccount(): boolean;
12
+ requiresAccountSetup(): boolean;
13
+ }
14
+ export declare function createContext(config: Config): CLIContext;
@@ -0,0 +1,59 @@
1
+ import { HttpTransport, InfoClient, ExchangeClient, } from "@nktkas/hyperliquid";
2
+ import { privateKeyToAccount } from "viem/accounts";
3
+ import { tryConnectToServer } from "../client/index.js";
4
+ export function createContext(config) {
5
+ let publicClient = null;
6
+ let walletClient = null;
7
+ let serverClient = undefined; // undefined = not checked yet
8
+ const transport = new HttpTransport({
9
+ isTestnet: config.testnet,
10
+ });
11
+ return {
12
+ config,
13
+ getPublicClient() {
14
+ if (!publicClient) {
15
+ publicClient = new InfoClient({ transport });
16
+ }
17
+ return publicClient;
18
+ },
19
+ getWalletClient() {
20
+ if (!walletClient) {
21
+ if (!config.privateKey) {
22
+ if (config.account?.type === "readonly") {
23
+ throw new Error(`Account "${config.account.alias}" is read-only and cannot perform trading operations.\n` +
24
+ "Run 'perps account add' to set up an API wallet for trading.");
25
+ }
26
+ throw new Error("No account configured. Run 'perps account add' to set up your account.");
27
+ }
28
+ const account = privateKeyToAccount(config.privateKey);
29
+ walletClient = new ExchangeClient({ transport, wallet: account });
30
+ }
31
+ return walletClient;
32
+ },
33
+ getWalletAddress() {
34
+ if (config.walletAddress) {
35
+ return config.walletAddress;
36
+ }
37
+ if (config.privateKey) {
38
+ const account = privateKeyToAccount(config.privateKey);
39
+ return account.address;
40
+ }
41
+ throw new Error("No account configured. Run 'perps account add' to set up your account.");
42
+ },
43
+ async getServerClient() {
44
+ // Return cached result if already checked
45
+ if (serverClient !== undefined) {
46
+ return serverClient;
47
+ }
48
+ // Try to connect to server
49
+ serverClient = await tryConnectToServer();
50
+ return serverClient;
51
+ },
52
+ hasAccount() {
53
+ return !!(config.walletAddress || config.privateKey);
54
+ },
55
+ requiresAccountSetup() {
56
+ return !config.walletAddress && !config.privateKey;
57
+ },
58
+ };
59
+ }
@@ -0,0 +1,48 @@
1
+ type StatusKind = "success" | "error" | "warn" | "info";
2
+ type ThemeTone = StatusKind | "dim" | "brand" | "accent";
3
+ export declare const supportsColor: (stream?: NodeJS.WriteStream) => boolean;
4
+ export declare const highlighter: {
5
+ bold: (text: string) => string;
6
+ dim: (text: string) => string;
7
+ dimWhite: (text: string) => string;
8
+ success: (text: string) => string;
9
+ error: (text: string) => string;
10
+ warn: (text: string) => string;
11
+ info: (text: string) => string;
12
+ brand: (text: string) => string;
13
+ accent: (text: string) => string;
14
+ };
15
+ /**
16
+ * Strip ANSI escape codes from a string to get its visible length
17
+ */
18
+ export declare function stripAnsi(text: string): string;
19
+ export declare function formatStatusLine(kind: StatusKind, text: string, stream?: NodeJS.WriteStream): string;
20
+ export declare function formatTag(label: string, tone?: ThemeTone): string;
21
+ export declare function printSessionBanner(args: {
22
+ version: string;
23
+ commandPath: string[];
24
+ exchange: string;
25
+ isTestnet: boolean;
26
+ }): void;
27
+ export declare function printCommandCompletion(durationSeconds: number): void;
28
+ export interface FramedLine {
29
+ plainText: string;
30
+ renderedText: string;
31
+ }
32
+ export interface FrameBoxOptions {
33
+ indent?: number;
34
+ padding?: number;
35
+ borderTone?: ThemeTone;
36
+ }
37
+ export declare function createFramedLine(plainText: string, renderedText?: string): FramedLine;
38
+ export declare function renderFramedBox(lines: FramedLine[], options?: FrameBoxOptions): string;
39
+ export declare function printFramedBox(lines: FramedLine[], options?: FrameBoxOptions): void;
40
+ export interface SpinnerHandle {
41
+ update: (nextText: string) => void;
42
+ succeed: (message: string) => void;
43
+ fail: (message: string) => void;
44
+ info: (message: string) => void;
45
+ }
46
+ export declare function startSpinner(initialText: string): SpinnerHandle;
47
+ export declare function registerCursorCleanup(): void;
48
+ export {};
@@ -0,0 +1,243 @@
1
+ const ANSI_RESET = "\u001b[0m";
2
+ const ANSI_BOLD = "\u001b[1m";
3
+ const ANSI_DIM = "\u001b[2m";
4
+ const ANSI_RED = "\u001b[31m";
5
+ const ANSI_GREEN = "\u001b[32m";
6
+ const ANSI_YELLOW = "\u001b[33m";
7
+ const ANSI_CYAN = "\u001b[36m";
8
+ const ANSI_BRIGHT_BLUE = "\u001b[94m";
9
+ const ANSI_BRIGHT_CYAN = "\u001b[96m";
10
+ const ANSI_DIM_WHITE = "\u001b[90m";
11
+ const ANSI_CLEAR_LINE = "\u001b[2K";
12
+ // eslint-disable-next-line no-control-regex
13
+ const ANSI_REGEX = /\u001b\[[0-9;]*m/g;
14
+ export const supportsColor = (stream = process.stdout) => Boolean(stream.isTTY) && !process.env.NO_COLOR;
15
+ const supportsDecoratedOutput = (stream = process.stdout) => Boolean(stream.isTTY);
16
+ const supportsUnicodeSymbols = () => {
17
+ if (process.platform !== "win32")
18
+ return true;
19
+ return Boolean(process.env.WT_SESSION || process.env.TERM_PROGRAM || process.env.ANSICON);
20
+ };
21
+ const paint = (text, ansiCode, stream = process.stdout) => {
22
+ if (!supportsColor(stream))
23
+ return text;
24
+ return `${ansiCode}${text}${ANSI_RESET}`;
25
+ };
26
+ const unicode = supportsUnicodeSymbols();
27
+ const symbolMap = {
28
+ success: unicode ? "◆" : "[ok]",
29
+ error: unicode ? "◈" : "[x]",
30
+ warn: unicode ? "▲" : "[!]",
31
+ info: unicode ? "●" : "[i]",
32
+ };
33
+ const SPINNER_FRAMES = unicode
34
+ ? ["⠇", "⠋", "⠙", "⠸", "⠴", "⠦"]
35
+ : ["-", "\\", "|", "/"];
36
+ const PERPS_MARK_UNICODE = [
37
+ "╔═╗┌─┐┬─┐┌─┐┌─┐",
38
+ "╠═╝├┤ ├┬┘├─┘└─┐",
39
+ "╩ └─┘┴└─┴ └─┘",
40
+ ];
41
+ const PERPS_MARK_ASCII = [
42
+ " ____ _____ ____ ____ ____",
43
+ "| _ \\| ____| _ \\| _ \\/ ___|",
44
+ "| |_) | _| | |_) | |_) \\___ \\",
45
+ "| __/| |___| _ <| __/ ___) |",
46
+ "|_| |_____|_| \\_\\_| |____/",
47
+ ];
48
+ export const highlighter = {
49
+ bold: (text) => paint(text, ANSI_BOLD),
50
+ dim: (text) => paint(text, ANSI_DIM),
51
+ dimWhite: (text) => paint(text, ANSI_DIM_WHITE),
52
+ success: (text) => paint(text, ANSI_GREEN),
53
+ error: (text) => paint(text, ANSI_RED),
54
+ warn: (text) => paint(text, ANSI_YELLOW),
55
+ info: (text) => paint(text, ANSI_CYAN),
56
+ brand: (text) => paint(text, ANSI_BRIGHT_BLUE),
57
+ accent: (text) => paint(text, ANSI_BRIGHT_CYAN),
58
+ };
59
+ /**
60
+ * Strip ANSI escape codes from a string to get its visible length
61
+ */
62
+ export function stripAnsi(text) {
63
+ return text.replace(ANSI_REGEX, "");
64
+ }
65
+ const colorizeByTone = (tone, text, stream = process.stdout) => {
66
+ if (tone === "success")
67
+ return paint(text, ANSI_GREEN, stream);
68
+ if (tone === "error")
69
+ return paint(text, ANSI_RED, stream);
70
+ if (tone === "warn")
71
+ return paint(text, ANSI_YELLOW, stream);
72
+ if (tone === "info")
73
+ return paint(text, ANSI_CYAN, stream);
74
+ if (tone === "brand")
75
+ return paint(text, ANSI_BRIGHT_BLUE, stream);
76
+ if (tone === "accent")
77
+ return paint(text, ANSI_BRIGHT_CYAN, stream);
78
+ return paint(text, ANSI_DIM, stream);
79
+ };
80
+ function decorateWithSymbol(kind, text, stream = process.stdout) {
81
+ if (!supportsDecoratedOutput(stream))
82
+ return text;
83
+ return `${symbolMap[kind]} ${text}`;
84
+ }
85
+ export function formatStatusLine(kind, text, stream = process.stdout) {
86
+ const withSymbol = decorateWithSymbol(kind, text, stream);
87
+ if (!supportsColor(stream))
88
+ return withSymbol;
89
+ return colorizeByTone(kind, withSymbol, stream);
90
+ }
91
+ export function formatTag(label, tone = "info") {
92
+ const normalized = label.trim().toUpperCase();
93
+ const raw = unicode ? `⟦${normalized}⟧` : `[${normalized}]`;
94
+ return colorizeByTone(tone, raw);
95
+ }
96
+ function getPerpsAsciiMark() {
97
+ return unicode ? PERPS_MARK_UNICODE : PERPS_MARK_ASCII;
98
+ }
99
+ export function printSessionBanner(args) {
100
+ if (!process.stdout.isTTY)
101
+ return;
102
+ const commandLabel = args.commandPath.length > 0 ? args.commandPath.join(" > ") : "root";
103
+ const networkTag = args.isTestnet ? formatTag("testnet", "warn") : formatTag("mainnet", "success");
104
+ const exchangeTag = formatTag(args.exchange, "accent");
105
+ const commandTag = formatTag(commandLabel, "brand");
106
+ console.log("");
107
+ for (const line of getPerpsAsciiMark()) {
108
+ console.log(highlighter.brand(line));
109
+ }
110
+ console.log(highlighter.dim("by Raintree Technology"));
111
+ console.log("");
112
+ console.log(`${highlighter.dim("mode")} ${networkTag} ${highlighter.dim("exchange")} ${exchangeTag}`);
113
+ console.log(`${highlighter.dim("command")} ${commandTag} ${highlighter.dim("version")} ${highlighter.dim(`v${args.version}`)}`);
114
+ console.log("");
115
+ }
116
+ export function printCommandCompletion(durationSeconds) {
117
+ const message = `Completed in ${durationSeconds.toFixed(2)}s`;
118
+ if (!process.stdout.isTTY) {
119
+ console.log(`\n${message}`);
120
+ return;
121
+ }
122
+ console.log("");
123
+ console.log(formatStatusLine("success", message));
124
+ }
125
+ export function createFramedLine(plainText, renderedText = plainText) {
126
+ return {
127
+ plainText,
128
+ renderedText,
129
+ };
130
+ }
131
+ function getBoxChars() {
132
+ if (unicode) {
133
+ return {
134
+ topLeft: "┌",
135
+ topRight: "┐",
136
+ bottomLeft: "└",
137
+ bottomRight: "┘",
138
+ horizontal: "─",
139
+ vertical: "│",
140
+ };
141
+ }
142
+ return {
143
+ topLeft: "+",
144
+ topRight: "+",
145
+ bottomLeft: "+",
146
+ bottomRight: "+",
147
+ horizontal: "-",
148
+ vertical: "|",
149
+ };
150
+ }
151
+ export function renderFramedBox(lines, options) {
152
+ if (lines.length === 0)
153
+ return "";
154
+ const boxChars = getBoxChars();
155
+ const indent = " ".repeat(options?.indent ?? 2);
156
+ const padding = " ".repeat(options?.padding ?? 1);
157
+ const borderTone = options?.borderTone ?? "dim";
158
+ const maxLineLength = Math.max(...lines.map((line) => line.plainText.length));
159
+ const horizontal = boxChars.horizontal.repeat(maxLineLength + padding.length * 2);
160
+ const border = (text) => colorizeByTone(borderTone, text);
161
+ const outputLines = [];
162
+ outputLines.push(`${indent}${border(`${boxChars.topLeft}${horizontal}${boxChars.topRight}`)}`);
163
+ for (const line of lines) {
164
+ const trailingSpaces = " ".repeat(maxLineLength - line.plainText.length);
165
+ outputLines.push(`${indent}${border(boxChars.vertical)}${padding}${line.renderedText}${trailingSpaces}${padding}${border(boxChars.vertical)}`);
166
+ }
167
+ outputLines.push(`${indent}${border(`${boxChars.bottomLeft}${horizontal}${boxChars.bottomRight}`)}`);
168
+ return outputLines.join("\n");
169
+ }
170
+ export function printFramedBox(lines, options) {
171
+ const rendered = renderFramedBox(lines, options);
172
+ if (rendered) {
173
+ console.log(rendered);
174
+ }
175
+ }
176
+ export function startSpinner(initialText) {
177
+ const canAnimate = Boolean(process.stdout.isTTY);
178
+ let text = initialText;
179
+ let frameIndex = 0;
180
+ let finished = false;
181
+ let timer = null;
182
+ const renderFrame = () => {
183
+ if (!canAnimate || finished)
184
+ return;
185
+ const frame = SPINNER_FRAMES[frameIndex % SPINNER_FRAMES.length];
186
+ frameIndex += 1;
187
+ process.stdout.write(`\r${ANSI_CLEAR_LINE}${highlighter.brand(frame)} ${text}`);
188
+ };
189
+ const finalize = (kind, message) => {
190
+ if (finished)
191
+ return;
192
+ finished = true;
193
+ if (timer) {
194
+ clearInterval(timer);
195
+ timer = null;
196
+ }
197
+ if (canAnimate) {
198
+ process.stdout.write(`\r${ANSI_CLEAR_LINE}`);
199
+ }
200
+ console.log(formatStatusLine(kind, message));
201
+ };
202
+ if (canAnimate) {
203
+ renderFrame();
204
+ timer = setInterval(renderFrame, 90);
205
+ }
206
+ return {
207
+ update(nextText) {
208
+ text = nextText;
209
+ renderFrame();
210
+ },
211
+ succeed(message) {
212
+ finalize("success", message);
213
+ },
214
+ fail(message) {
215
+ finalize("error", message);
216
+ },
217
+ info(message) {
218
+ finalize("info", message);
219
+ },
220
+ };
221
+ }
222
+ /**
223
+ * Register signal handlers to restore terminal cursor on exit.
224
+ * Call once at startup when using hideCursor/watch mode.
225
+ */
226
+ let cursorCleanupRegistered = false;
227
+ export function registerCursorCleanup() {
228
+ if (cursorCleanupRegistered)
229
+ return;
230
+ cursorCleanupRegistered = true;
231
+ const restore = () => {
232
+ process.stdout.write("\x1b[?25h");
233
+ };
234
+ process.on("SIGINT", () => {
235
+ restore();
236
+ process.exit(130);
237
+ });
238
+ process.on("SIGTERM", () => {
239
+ restore();
240
+ process.exit(143);
241
+ });
242
+ process.on("exit", restore);
243
+ }
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ import type { ShortcutHint, StatusChip, Tone } from "./types.js";
3
+ export interface AppShellProps {
4
+ title: string;
5
+ subtitle?: string;
6
+ status?: StatusChip[];
7
+ lastUpdated?: Date;
8
+ shortcuts?: ShortcutHint[];
9
+ children: React.ReactNode;
10
+ }
11
+ export declare function AppShell({ title, subtitle, status, lastUpdated, shortcuts, children, }: AppShellProps): React.ReactElement;
12
+ export declare function getToneTextColor(tone: Tone | undefined): string;
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { colors } from "../theme.js";
4
+ function getToneColor(tone) {
5
+ switch (tone) {
6
+ case "success":
7
+ return colors.profit;
8
+ case "warning":
9
+ return colors.warning;
10
+ case "danger":
11
+ return colors.loss;
12
+ case "info":
13
+ return colors.info;
14
+ case "neutral":
15
+ default:
16
+ return colors.muted;
17
+ }
18
+ }
19
+ function formatClock(value) {
20
+ return value.toLocaleTimeString("en-US", {
21
+ hour12: false,
22
+ hour: "2-digit",
23
+ minute: "2-digit",
24
+ second: "2-digit",
25
+ });
26
+ }
27
+ export function AppShell({ title, subtitle, status = [], lastUpdated, shortcuts = [], children, }) {
28
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, paddingY: 0, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: colors.header, children: title }), subtitle && (_jsxs(Text, { color: colors.muted, children: [" ", subtitle] }))] }), _jsxs(Box, { marginBottom: 1, children: [status.map((chip, index) => (_jsx(Box, { marginRight: 1, children: _jsxs(Text, { color: getToneColor(chip.tone), children: ["[", chip.label, "]"] }) }, `${chip.label}-${index}`))), _jsx(Box, { flexGrow: 1 }), lastUpdated && _jsxs(Text, { color: colors.muted, children: ["updated ", formatClock(lastUpdated)] })] }), _jsx(Box, { flexDirection: "column", children: children }), shortcuts.length > 0 && (_jsx(Box, { marginTop: 1, children: shortcuts.map((shortcut, index) => (_jsx(Box, { marginRight: 2, children: _jsxs(Text, { color: colors.muted, children: [_jsx(Text, { color: colors.header, children: shortcut.key }), " ", shortcut.label] }) }, `${shortcut.key}-${index}`))) }))] }));
29
+ }
30
+ export function getToneTextColor(tone) {
31
+ return getToneColor(tone);
32
+ }
@@ -0,0 +1,6 @@
1
+ import React from "react";
2
+ import type { Metric } from "./types.js";
3
+ export interface MetricStripProps {
4
+ metrics: Metric[];
5
+ }
6
+ export declare function MetricStrip({ metrics }: MetricStripProps): React.ReactElement;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { colors } from "../theme.js";
4
+ import { getToneTextColor } from "./AppShell.js";
5
+ function getDeltaColor(delta) {
6
+ if (delta.startsWith("+"))
7
+ return colors.profit;
8
+ if (delta.startsWith("-"))
9
+ return colors.loss;
10
+ return colors.muted;
11
+ }
12
+ export function MetricStrip({ metrics }) {
13
+ return (_jsx(Box, { marginBottom: 1, flexWrap: "wrap", children: metrics.map((metric, index) => (_jsxs(Box, { marginRight: 2, children: [_jsx(Text, { color: colors.muted, children: metric.label }), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, color: getToneTextColor(metric.tone), children: metric.value }), metric.delta && (_jsxs(Text, { color: getDeltaColor(metric.delta), children: [" ", metric.delta] }))] }, `${metric.label}-${index}`))) }));
14
+ }
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ import type { Tone } from "./types.js";
3
+ export interface PanelProps {
4
+ title: string;
5
+ subtitle?: string;
6
+ tone?: Tone;
7
+ children: React.ReactNode;
8
+ }
9
+ export declare function Panel({ title, subtitle, tone, children, }: PanelProps): React.ReactElement;
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { colors } from "../theme.js";
4
+ import { getToneTextColor } from "./AppShell.js";
5
+ export function Panel({ title, subtitle, tone = "neutral", children, }) {
6
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: getToneTextColor(tone), paddingX: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: getToneTextColor(tone), children: title }), subtitle && (_jsxs(Text, { color: colors.muted, children: [" ", subtitle] }))] }), _jsx(Box, { flexDirection: "column", children: children })] }));
7
+ }
@@ -0,0 +1,2 @@
1
+ export declare function toSparkline(values: number[], width?: number, chars?: string): string;
2
+ export declare function toBar(value: number, max: number, width?: number, fillChar?: string, emptyChar?: string): string;