httpcat-cli 0.3.0 → 0.3.1

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 (322) hide show
  1. package/.github/workflows/ci.yml +3 -0
  2. package/.github/workflows/rc-publish.yml +6 -0
  3. package/.github/workflows/release.yml +102 -0
  4. package/.github/workflows/sync-version.yml +31 -2
  5. package/README.md +1408 -109
  6. package/additions.txt +3 -0
  7. package/bun.lock +260 -25
  8. package/dist/agent/autonomous-trader.d.ts.map +1 -0
  9. package/dist/agent/autonomous-trader.js +362 -0
  10. package/dist/agent/autonomous-trader.js.map +1 -0
  11. package/dist/agent/ax-agent.d.ts.map +1 -1
  12. package/dist/agent/ax-agent.js +356 -18
  13. package/dist/agent/ax-agent.js.map +1 -1
  14. package/dist/agent/event-client.d.ts.map +1 -0
  15. package/dist/agent/event-client.js +82 -0
  16. package/dist/agent/event-client.js.map +1 -0
  17. package/dist/agent/log-stream.d.ts.map +1 -0
  18. package/dist/agent/log-stream.js +95 -0
  19. package/dist/agent/log-stream.js.map +1 -0
  20. package/dist/agent/memory/conversation-session.d.ts.map +1 -0
  21. package/dist/agent/memory/conversation-session.js +232 -0
  22. package/dist/agent/memory/conversation-session.js.map +1 -0
  23. package/dist/agent/memory/conversation-store.d.ts.map +1 -0
  24. package/dist/agent/memory/conversation-store.js +214 -0
  25. package/dist/agent/memory/conversation-store.js.map +1 -0
  26. package/dist/agent/memory/database-schema.d.ts.map +1 -0
  27. package/dist/agent/memory/database-schema.js +355 -0
  28. package/dist/agent/memory/database-schema.js.map +1 -0
  29. package/dist/agent/memory/decision-tracker.d.ts.map +1 -0
  30. package/dist/agent/memory/decision-tracker.js +274 -0
  31. package/dist/agent/memory/decision-tracker.js.map +1 -0
  32. package/dist/agent/memory/memory-manager.d.ts.map +1 -0
  33. package/dist/agent/memory/memory-manager.js +187 -0
  34. package/dist/agent/memory/memory-manager.js.map +1 -0
  35. package/dist/agent/memory/types.d.ts.map +1 -0
  36. package/dist/agent/memory/types.js +5 -0
  37. package/dist/agent/memory/types.js.map +1 -0
  38. package/dist/agent/message-formatter.d.ts.map +1 -0
  39. package/dist/agent/message-formatter.js +76 -0
  40. package/dist/agent/message-formatter.js.map +1 -0
  41. package/dist/agent/position-db.d.ts.map +1 -0
  42. package/dist/agent/position-db.js +154 -0
  43. package/dist/agent/position-db.js.map +1 -0
  44. package/dist/agent/simple-chat-ui-static.d.ts.map +1 -0
  45. package/dist/agent/simple-chat-ui-static.js +129 -0
  46. package/dist/agent/simple-chat-ui-static.js.map +1 -0
  47. package/dist/agent/simple-chat-ui.d.ts.map +1 -0
  48. package/dist/agent/simple-chat-ui.js +90 -0
  49. package/dist/agent/simple-chat-ui.js.map +1 -0
  50. package/dist/agent/tools.d.ts.map +1 -1
  51. package/dist/agent/tools.js +297 -4
  52. package/dist/agent/tools.js.map +1 -1
  53. package/dist/agent/ui.d.ts.map +1 -0
  54. package/dist/agent/ui.js +84 -0
  55. package/dist/agent/ui.js.map +1 -0
  56. package/dist/agent/unified-runtime.d.ts.map +1 -0
  57. package/dist/agent/unified-runtime.js +397 -0
  58. package/dist/agent/unified-runtime.js.map +1 -0
  59. package/dist/client.d.ts.map +1 -1
  60. package/dist/client.js +272 -21
  61. package/dist/client.js.map +1 -1
  62. package/dist/commands/account.d.ts.map +1 -1
  63. package/dist/commands/account.js +187 -33
  64. package/dist/commands/account.js.map +1 -1
  65. package/dist/commands/agent.d.ts.map +1 -0
  66. package/dist/commands/agent.js +125 -0
  67. package/dist/commands/agent.js.map +1 -0
  68. package/dist/commands/approve.d.ts.map +1 -0
  69. package/dist/commands/approve.js +505 -0
  70. package/dist/commands/approve.js.map +1 -0
  71. package/dist/commands/automation.d.ts.map +1 -0
  72. package/dist/commands/automation.js +346 -0
  73. package/dist/commands/automation.js.map +1 -0
  74. package/dist/commands/balances.d.ts.map +1 -1
  75. package/dist/commands/balances.js +226 -73
  76. package/dist/commands/balances.js.map +1 -1
  77. package/dist/commands/buy.d.ts.map +1 -1
  78. package/dist/commands/buy.js +149 -146
  79. package/dist/commands/buy.js.map +1 -1
  80. package/dist/commands/call.d.ts.map +1 -0
  81. package/dist/commands/call.js +51 -0
  82. package/dist/commands/call.js.map +1 -0
  83. package/dist/commands/cex.d.ts.map +1 -0
  84. package/dist/commands/cex.js +958 -0
  85. package/dist/commands/cex.js.map +1 -0
  86. package/dist/commands/chat.d.ts.map +1 -1
  87. package/dist/commands/chat.js +169 -411
  88. package/dist/commands/chat.js.map +1 -1
  89. package/dist/commands/claim.d.ts.map +1 -1
  90. package/dist/commands/claim.js +313 -29
  91. package/dist/commands/claim.js.map +1 -1
  92. package/dist/commands/create.d.ts.map +1 -1
  93. package/dist/commands/create.js +151 -43
  94. package/dist/commands/create.js.map +1 -1
  95. package/dist/commands/gasless-swap.d.ts.map +1 -0
  96. package/dist/commands/gasless-swap.js +232 -0
  97. package/dist/commands/gasless-swap.js.map +1 -0
  98. package/dist/commands/health.d.ts.map +1 -1
  99. package/dist/commands/health.js +63 -7
  100. package/dist/commands/health.js.map +1 -1
  101. package/dist/commands/info.d.ts.map +1 -1
  102. package/dist/commands/info.js +131 -47
  103. package/dist/commands/info.js.map +1 -1
  104. package/dist/commands/launchpad.d.ts.map +1 -0
  105. package/dist/commands/launchpad.js +708 -0
  106. package/dist/commands/launchpad.js.map +1 -0
  107. package/dist/commands/list.d.ts.map +1 -1
  108. package/dist/commands/list.js +57 -23
  109. package/dist/commands/list.js.map +1 -1
  110. package/dist/commands/market.d.ts.map +1 -0
  111. package/dist/commands/market.js +960 -0
  112. package/dist/commands/market.js.map +1 -0
  113. package/dist/commands/mcp-install.d.ts.map +1 -0
  114. package/dist/commands/mcp-install.js +387 -0
  115. package/dist/commands/mcp-install.js.map +1 -0
  116. package/dist/commands/opps.d.ts.map +1 -0
  117. package/dist/commands/opps.js +409 -0
  118. package/dist/commands/opps.js.map +1 -0
  119. package/dist/commands/perps.d.ts.map +1 -0
  120. package/dist/commands/perps.js +248 -0
  121. package/dist/commands/perps.js.map +1 -0
  122. package/dist/commands/portfolio.d.ts.map +1 -0
  123. package/dist/commands/portfolio.js +679 -0
  124. package/dist/commands/portfolio.js.map +1 -0
  125. package/dist/commands/positions.d.ts.map +1 -1
  126. package/dist/commands/positions.js +76 -47
  127. package/dist/commands/positions.js.map +1 -1
  128. package/dist/commands/predict.d.ts.map +1 -0
  129. package/dist/commands/predict.js +280 -0
  130. package/dist/commands/predict.js.map +1 -0
  131. package/dist/commands/predictions.d.ts.map +1 -0
  132. package/dist/commands/predictions.js +486 -0
  133. package/dist/commands/predictions.js.map +1 -0
  134. package/dist/commands/risk.d.ts.map +1 -0
  135. package/dist/commands/risk.js +225 -0
  136. package/dist/commands/risk.js.map +1 -0
  137. package/dist/commands/security.d.ts.map +1 -0
  138. package/dist/commands/security.js +244 -0
  139. package/dist/commands/security.js.map +1 -0
  140. package/dist/commands/sell.d.ts.map +1 -1
  141. package/dist/commands/sell.js +67 -34
  142. package/dist/commands/sell.js.map +1 -1
  143. package/dist/commands/send.d.ts.map +1 -0
  144. package/dist/commands/send.js +733 -0
  145. package/dist/commands/send.js.map +1 -0
  146. package/dist/commands/sign.d.ts.map +1 -0
  147. package/dist/commands/sign.js +1048 -0
  148. package/dist/commands/sign.js.map +1 -0
  149. package/dist/commands/swap.d.ts.map +1 -0
  150. package/dist/commands/swap.js +744 -0
  151. package/dist/commands/swap.js.map +1 -0
  152. package/dist/commands/system.d.ts.map +1 -0
  153. package/dist/commands/system.js +417 -0
  154. package/dist/commands/system.js.map +1 -0
  155. package/dist/commands/tools/index.d.ts.map +1 -0
  156. package/dist/commands/tools/index.js +2040 -0
  157. package/dist/commands/tools/index.js.map +1 -0
  158. package/dist/commands/trade.d.ts.map +1 -0
  159. package/dist/commands/trade.js +237 -0
  160. package/dist/commands/trade.js.map +1 -0
  161. package/dist/commands/transactions.d.ts.map +1 -1
  162. package/dist/commands/transactions.js +29 -17
  163. package/dist/commands/transactions.js.map +1 -1
  164. package/dist/commands/update.d.ts.map +1 -0
  165. package/dist/commands/update.js +429 -0
  166. package/dist/commands/update.js.map +1 -0
  167. package/dist/config.d.ts.map +1 -1
  168. package/dist/config.js +351 -40
  169. package/dist/config.js.map +1 -1
  170. package/dist/index.js +4524 -924
  171. package/dist/index.js.map +1 -1
  172. package/dist/interactive/art.d.ts.map +1 -1
  173. package/dist/interactive/art.js +33 -1
  174. package/dist/interactive/art.js.map +1 -1
  175. package/dist/interactive/shell.d.ts.map +1 -1
  176. package/dist/interactive/shell.js +467 -2652
  177. package/dist/interactive/shell.js.map +1 -1
  178. package/dist/mcp/context.d.ts.map +1 -0
  179. package/dist/mcp/context.js +211 -0
  180. package/dist/mcp/context.js.map +1 -0
  181. package/dist/mcp/onboarding.d.ts.map +1 -0
  182. package/dist/mcp/onboarding.js +266 -0
  183. package/dist/mcp/onboarding.js.map +1 -0
  184. package/dist/mcp/resources.d.ts.map +1 -0
  185. package/dist/mcp/resources.js +222 -0
  186. package/dist/mcp/resources.js.map +1 -0
  187. package/dist/mcp/server.d.ts.map +1 -1
  188. package/dist/mcp/server.js +51 -1
  189. package/dist/mcp/server.js.map +1 -1
  190. package/dist/mcp/tools.d.ts.map +1 -1
  191. package/dist/mcp/tools.js +4119 -169
  192. package/dist/mcp/tools.js.map +1 -1
  193. package/dist/mcp/types.d.ts.map +1 -1
  194. package/dist/types/agent-info.d.ts.map +1 -0
  195. package/dist/types/agent-info.js +11 -0
  196. package/dist/types/agent-info.js.map +1 -0
  197. package/dist/ui/components/ScrollableList.d.ts.map +1 -0
  198. package/dist/ui/components/ScrollableList.js +72 -0
  199. package/dist/ui/components/ScrollableList.js.map +1 -0
  200. package/dist/ui/components/ThemeProvider.d.ts.map +1 -0
  201. package/dist/ui/components/ThemeProvider.js +87 -0
  202. package/dist/ui/components/ThemeProvider.js.map +1 -0
  203. package/dist/ui/components/ThemedBox.d.ts.map +1 -0
  204. package/dist/ui/components/ThemedBox.js +24 -0
  205. package/dist/ui/components/ThemedBox.js.map +1 -0
  206. package/dist/ui/components/agent/ChatHeader.d.ts.map +1 -0
  207. package/dist/ui/components/agent/ChatHeader.js +39 -0
  208. package/dist/ui/components/agent/ChatHeader.js.map +1 -0
  209. package/dist/ui/components/agent/Header.d.ts.map +1 -0
  210. package/dist/ui/components/agent/Header.js +14 -0
  211. package/dist/ui/components/agent/Header.js.map +1 -0
  212. package/dist/ui/components/agent/Input.d.ts.map +1 -0
  213. package/dist/ui/components/agent/Input.js +23 -0
  214. package/dist/ui/components/agent/Input.js.map +1 -0
  215. package/dist/ui/components/agent/Output.d.ts.map +1 -0
  216. package/dist/ui/components/agent/Output.js +23 -0
  217. package/dist/ui/components/agent/Output.js.map +1 -0
  218. package/dist/ui/components/chat/TokenChatUI.d.ts.map +1 -0
  219. package/dist/ui/components/chat/TokenChatUI.js +133 -0
  220. package/dist/ui/components/chat/TokenChatUI.js.map +1 -0
  221. package/dist/ui/components/shell/ShellHeader.d.ts.map +1 -0
  222. package/dist/ui/components/shell/ShellHeader.js +31 -0
  223. package/dist/ui/components/shell/ShellHeader.js.map +1 -0
  224. package/dist/ui/components/shell/ShellInput.d.ts.map +1 -0
  225. package/dist/ui/components/shell/ShellInput.js +151 -0
  226. package/dist/ui/components/shell/ShellInput.js.map +1 -0
  227. package/dist/ui/components/shell/ShellOutput.d.ts.map +1 -0
  228. package/dist/ui/components/shell/ShellOutput.js +8 -0
  229. package/dist/ui/components/shell/ShellOutput.js.map +1 -0
  230. package/dist/ui/hooks/useChatWebSocket.d.ts.map +1 -0
  231. package/dist/ui/hooks/useChatWebSocket.js +76 -0
  232. package/dist/ui/hooks/useChatWebSocket.js.map +1 -0
  233. package/dist/ui/hooks/useCommandHistory.d.ts.map +1 -0
  234. package/dist/ui/hooks/useCommandHistory.js +70 -0
  235. package/dist/ui/hooks/useCommandHistory.js.map +1 -0
  236. package/dist/ui/hooks/useDebounce.d.ts.map +1 -0
  237. package/dist/ui/hooks/useDebounce.js +17 -0
  238. package/dist/ui/hooks/useDebounce.js.map +1 -0
  239. package/dist/ui/hooks/useLogStream.d.ts.map +1 -0
  240. package/dist/ui/hooks/useLogStream.js +20 -0
  241. package/dist/ui/hooks/useLogStream.js.map +1 -0
  242. package/dist/ui/hooks/useVirtualScroll.d.ts.map +1 -0
  243. package/dist/ui/hooks/useVirtualScroll.js +70 -0
  244. package/dist/ui/hooks/useVirtualScroll.js.map +1 -0
  245. package/dist/utils/admin.d.ts.map +1 -0
  246. package/dist/utils/admin.js +144 -0
  247. package/dist/utils/admin.js.map +1 -0
  248. package/dist/utils/autoSetup.d.ts.map +1 -0
  249. package/dist/utils/autoSetup.js +252 -0
  250. package/dist/utils/autoSetup.js.map +1 -0
  251. package/dist/utils/build-constants.d.ts.map +1 -0
  252. package/dist/utils/build-constants.js +10 -0
  253. package/dist/utils/build-constants.js.map +1 -0
  254. package/dist/utils/constants.d.ts.map +1 -1
  255. package/dist/utils/errors.d.ts.map +1 -1
  256. package/dist/utils/errors.js +10 -1
  257. package/dist/utils/errors.js.map +1 -1
  258. package/dist/utils/formatting.d.ts.map +1 -1
  259. package/dist/utils/formatting.js +46 -9
  260. package/dist/utils/formatting.js.map +1 -1
  261. package/dist/utils/llm-cli-config.d.ts.map +1 -0
  262. package/dist/utils/llm-cli-config.js +963 -0
  263. package/dist/utils/llm-cli-config.js.map +1 -0
  264. package/dist/utils/llm-cli-detector.d.ts.map +1 -0
  265. package/dist/utils/llm-cli-detector.js +202 -0
  266. package/dist/utils/llm-cli-detector.js.map +1 -0
  267. package/dist/utils/loading.d.ts.map +1 -1
  268. package/dist/utils/loading.js +25 -3
  269. package/dist/utils/loading.js.map +1 -1
  270. package/dist/utils/maintenance.d.ts.map +1 -0
  271. package/dist/utils/maintenance.js +17 -0
  272. package/dist/utils/maintenance.js.map +1 -0
  273. package/dist/utils/mcp-config.d.ts.map +1 -0
  274. package/dist/utils/mcp-config.js +77 -0
  275. package/dist/utils/mcp-config.js.map +1 -0
  276. package/dist/utils/privateKeyPrompt.d.ts.map +1 -1
  277. package/dist/utils/privateKeyPrompt.js +308 -129
  278. package/dist/utils/privateKeyPrompt.js.map +1 -1
  279. package/dist/utils/process-cleanup.d.ts.map +1 -0
  280. package/dist/utils/process-cleanup.js +136 -0
  281. package/dist/utils/process-cleanup.js.map +1 -0
  282. package/dist/utils/retry.d.ts.map +1 -0
  283. package/dist/utils/retry.js +56 -0
  284. package/dist/utils/retry.js.map +1 -0
  285. package/dist/utils/rpc-helpers.d.ts.map +1 -0
  286. package/dist/utils/rpc-helpers.js +70 -0
  287. package/dist/utils/rpc-helpers.js.map +1 -0
  288. package/dist/utils/rpc-transport.d.ts.map +1 -0
  289. package/dist/utils/rpc-transport.js +87 -0
  290. package/dist/utils/rpc-transport.js.map +1 -0
  291. package/dist/utils/shell-setup.d.ts.map +1 -0
  292. package/dist/utils/shell-setup.js +531 -0
  293. package/dist/utils/shell-setup.js.map +1 -0
  294. package/dist/utils/status.d.ts.map +1 -1
  295. package/dist/utils/status.js +34 -5
  296. package/dist/utils/status.js.map +1 -1
  297. package/dist/utils/token-resolver.d.ts.map +1 -1
  298. package/dist/utils/token-resolver.js +51 -8
  299. package/dist/utils/token-resolver.js.map +1 -1
  300. package/dist/utils/x402-caller.d.ts.map +1 -0
  301. package/dist/utils/x402-caller.js +17 -0
  302. package/dist/utils/x402-caller.js.map +1 -0
  303. package/docs/README.md +28 -0
  304. package/docs/agent/README.md +18 -0
  305. package/docs/api/README.md +41 -0
  306. package/docs/cli/README.md +42 -0
  307. package/docs/guides/README.md +26 -0
  308. package/docs/implementation/README.md +18 -0
  309. package/docs/planning/README.md +19 -0
  310. package/docs/testing/README.md +15 -0
  311. package/docs/ux/README.md +16 -0
  312. package/issues.txt +2 -0
  313. package/package.json +24 -9
  314. package/scripts/cat-spin.sh +417 -0
  315. package/scripts/deprecate-rc-versions.js +58 -0
  316. package/scripts/inject-build-constants.js +43 -0
  317. package/scripts/monitor-foobar.js +117 -0
  318. package/swap.logs +61 -0
  319. package/swapping.txt +108 -0
  320. package/test.txt +12 -0
  321. package/tests/fixtures/test-data.json +16 -0
  322. package/Screenshot 2025-12-21 at 8.56.02/342/200/257PM.png +0 -0
@@ -0,0 +1,958 @@
1
+ import { Command } from "commander";
2
+ import { HttpcatClient } from "../client.js";
3
+ import { config } from "../config.js";
4
+ import chalk from "chalk";
5
+ import { printBox, formatCurrency, formatTokenAmount, createTable, } from "../utils/formatting.js";
6
+ import { withLoading } from "../utils/loading.js";
7
+ import { outputJson, outputError } from "../headless/json-output.js";
8
+ import { handleError, getExitCode } from "../utils/errors.js";
9
+ import { promptForPrivateKey } from "../utils/privateKeyPrompt.js";
10
+ // ============================================================================
11
+ // Shared Utilities
12
+ // ============================================================================
13
+ function getPrivateKey(cliPrivateKey, accountIndex) {
14
+ if (cliPrivateKey)
15
+ return cliPrivateKey;
16
+ const envKey = process.env.HTTPCAT_PRIVATE_KEY;
17
+ if (envKey)
18
+ return envKey;
19
+ try {
20
+ const index = accountIndex !== undefined
21
+ ? accountIndex
22
+ : config.getActiveAccountIndex();
23
+ return config.getAccountPrivateKey(index);
24
+ }
25
+ catch (error) {
26
+ return config.get("privateKey");
27
+ }
28
+ }
29
+ function isConfigured(cliPrivateKey) {
30
+ if (cliPrivateKey)
31
+ return true;
32
+ return config.isConfigured();
33
+ }
34
+ async function ensureWalletUnlocked() {
35
+ const password = config.getPassword();
36
+ if (!password) {
37
+ config.ensureSessionValid();
38
+ return;
39
+ }
40
+ if (!config.isSessionValid()) {
41
+ const inquirer = (await import("inquirer")).default;
42
+ const answers = await inquirer.prompt([
43
+ {
44
+ type: "password",
45
+ name: "password",
46
+ message: "Enter password to unlock wallet:",
47
+ mask: "•",
48
+ },
49
+ ]);
50
+ await config.unlockSession(answers.password);
51
+ }
52
+ }
53
+ // Normalize symbol format (BTC/USD, BTC-USD, BTCUSD -> BTC/USD)
54
+ function normalizeSymbol(symbol) {
55
+ // Remove spaces
56
+ symbol = symbol.trim().toUpperCase();
57
+ // If already has /, return as is
58
+ if (symbol.includes("/")) {
59
+ return symbol;
60
+ }
61
+ // If has -, replace with /
62
+ if (symbol.includes("-")) {
63
+ return symbol.replace("-", "/");
64
+ }
65
+ // If it's like BTCUSD, try to split (assume 3-4 char base, rest is quote)
66
+ // This is a heuristic - common pairs are BTC/USD, ETH/USD, etc.
67
+ const commonBases = ["BTC", "ETH", "USDT", "USDC", "BNB", "SOL", "ADA", "DOT", "MATIC", "AVAX"];
68
+ for (const base of commonBases) {
69
+ if (symbol.startsWith(base)) {
70
+ const quote = symbol.substring(base.length);
71
+ if (quote.length >= 2) {
72
+ return `${base}/${quote}`;
73
+ }
74
+ }
75
+ }
76
+ // Default: assume it's already correct or return as is
77
+ return symbol;
78
+ }
79
+ // ============================================================================
80
+ // CEX.IO Command Group
81
+ // ============================================================================
82
+ export function createCexCommand() {
83
+ const cexCommand = new Command("cex")
84
+ .description("CEX.IO exchange trading & market data")
85
+ .addHelpText("after", `
86
+ Examples:
87
+ httpcat cex markets
88
+ httpcat cex ticker BTC/USD
89
+ httpcat cex balance
90
+ httpcat cex orderbook BTC/USD --depth 20
91
+ httpcat cex orders
92
+ httpcat cex order-history --status completed
93
+ httpcat cex trade-history --symbol BTC/USD
94
+ httpcat cex place-order BTC/USD buy limit 0.1 --price 50000
95
+ httpcat cex cancel-order 12345
96
+ `);
97
+ // ============================================================================
98
+ // 1. Markets Command
99
+ // ============================================================================
100
+ cexCommand
101
+ .command("markets")
102
+ .description("Get all available trading pairs on CEX.IO (FREE)")
103
+ .option("--base <currency>", "Filter by base currency (e.g., BTC)")
104
+ .option("--quote <currency>", "Filter by quote currency (e.g., USD)")
105
+ .action(async (options, command) => {
106
+ try {
107
+ const globalOpts = command.parent?.parent?.opts() || {};
108
+ const accountIndex = globalOpts.account;
109
+ await ensureWalletUnlocked();
110
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
111
+ if (!isConfigured(globalOpts.privateKey)) {
112
+ if (globalOpts.json) {
113
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
114
+ process.exit(2);
115
+ }
116
+ privateKey = await promptForPrivateKey();
117
+ }
118
+ const client = await HttpcatClient.create(privateKey);
119
+ const result = await withLoading(async () => {
120
+ const { data } = await client.invoke("cex/markets", {
121
+ baseCurrency: options.base,
122
+ quoteCurrency: options.quote,
123
+ });
124
+ return data;
125
+ }, {
126
+ message: "Fetching markets...",
127
+ json: globalOpts.json,
128
+ quiet: globalOpts.quiet,
129
+ spinner: "cat",
130
+ clearOnSuccess: true,
131
+ });
132
+ if (globalOpts.json) {
133
+ outputJson("cex_markets", {
134
+ command: "cex_markets",
135
+ data: result,
136
+ });
137
+ }
138
+ else if (!globalOpts.quiet) {
139
+ console.log();
140
+ const markets = result.markets || result.pairs || [];
141
+ console.log(chalk.magenta.bold(`📈 CEX.IO Markets (${markets.length} pairs)`));
142
+ console.log();
143
+ if (markets.length > 0) {
144
+ const table = createTable({
145
+ head: ["Pair", "Last Price", "24h Change", "24h Volume"],
146
+ colWidths: [15, 15, 15, 20],
147
+ });
148
+ for (const market of markets.slice(0, 50)) {
149
+ const pair = market.symbol || market.pair || "";
150
+ const lastPrice = market.lastPrice || market.price || 0;
151
+ const change24h = market.change24h || market.priceChange24h || 0;
152
+ const volume24h = market.volume24h || market.totalVolume24h || 0;
153
+ const changeColor = change24h >= 0 ? chalk.green : chalk.red;
154
+ const changeEmoji = change24h >= 0 ? "🟢" : "🔴";
155
+ table.push([
156
+ chalk.cyan(pair),
157
+ formatCurrency(lastPrice),
158
+ changeColor(`${change24h >= 0 ? "+" : ""}${change24h.toFixed(2)}% ${changeEmoji}`),
159
+ formatCurrency(volume24h),
160
+ ]);
161
+ }
162
+ console.log(table.toString());
163
+ if (markets.length > 50) {
164
+ console.log(chalk.dim(`... and ${markets.length - 50} more markets`));
165
+ }
166
+ console.log();
167
+ console.log(chalk.dim(`Total: ${markets.length} markets`));
168
+ }
169
+ else {
170
+ console.log(chalk.dim("No markets found."));
171
+ }
172
+ console.log();
173
+ }
174
+ process.exit(0);
175
+ }
176
+ catch (error) {
177
+ const globalOpts = command.parent?.parent?.opts() || {};
178
+ if (globalOpts.json) {
179
+ outputError("cex_markets", error, getExitCode(error));
180
+ }
181
+ else {
182
+ handleError(error, globalOpts.verbose);
183
+ }
184
+ process.exit(getExitCode(error));
185
+ }
186
+ });
187
+ // ============================================================================
188
+ // 2. Ticker Command
189
+ // ============================================================================
190
+ cexCommand
191
+ .command("ticker")
192
+ .description("Get detailed ticker information for a trading pair (FREE)")
193
+ .argument("<symbol>", "Trading pair (supports BTC/USD, BTC-USD, or BTCUSD)")
194
+ .action(async (symbol, options, command) => {
195
+ try {
196
+ const globalOpts = command.parent?.parent?.opts() || {};
197
+ const accountIndex = globalOpts.account;
198
+ await ensureWalletUnlocked();
199
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
200
+ if (!isConfigured(globalOpts.privateKey)) {
201
+ if (globalOpts.json) {
202
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
203
+ process.exit(2);
204
+ }
205
+ privateKey = await promptForPrivateKey();
206
+ }
207
+ const client = await HttpcatClient.create(privateKey);
208
+ const normalizedSymbol = normalizeSymbol(symbol);
209
+ const result = await withLoading(async () => {
210
+ const { data } = await client.invoke("cex/ticker", {
211
+ symbol: normalizedSymbol,
212
+ });
213
+ return data;
214
+ }, {
215
+ message: "Fetching ticker...",
216
+ json: globalOpts.json,
217
+ quiet: globalOpts.quiet,
218
+ spinner: "cat",
219
+ clearOnSuccess: true,
220
+ });
221
+ if (globalOpts.json) {
222
+ outputJson("cex_ticker", {
223
+ command: "cex_ticker",
224
+ data: result,
225
+ });
226
+ }
227
+ else if (!globalOpts.quiet) {
228
+ console.log();
229
+ console.log(chalk.magenta.bold(`📊 Ticker: ${normalizedSymbol}`));
230
+ console.log();
231
+ const lastPrice = result.lastPrice || result.price || 0;
232
+ const change24h = result.change24h || result.priceChange24h || 0;
233
+ const changeAmount = result.changeAmount24h || 0;
234
+ const bid = result.bid || 0;
235
+ const ask = result.ask || 0;
236
+ const spread = ask - bid;
237
+ const spreadPercent = lastPrice > 0 ? (spread / lastPrice) * 100 : 0;
238
+ const high24h = result.high24h || result.high || 0;
239
+ const low24h = result.low24h || result.low || 0;
240
+ const volume24h = result.volume24h || result.totalVolume24h || 0;
241
+ const changeColor = change24h >= 0 ? chalk.green : chalk.red;
242
+ const changeEmoji = change24h >= 0 ? "🟢" : "🔴";
243
+ const boxData = {
244
+ "Last Price": chalk.green.bold(formatCurrency(lastPrice)),
245
+ "24h Change": changeColor(`${changeAmount >= 0 ? "+" : ""}${formatCurrency(Math.abs(changeAmount))} (${change24h >= 0 ? "+" : ""}${change24h.toFixed(2)}%) ${changeEmoji}`),
246
+ Bid: formatCurrency(bid),
247
+ Ask: formatCurrency(ask),
248
+ Spread: `${formatCurrency(spread)} (${spreadPercent.toFixed(2)}%)`,
249
+ "24h High": formatCurrency(high24h),
250
+ "24h Low": formatCurrency(low24h),
251
+ "24h Volume": formatCurrency(volume24h),
252
+ };
253
+ printBox("Ticker Data", boxData);
254
+ console.log();
255
+ }
256
+ process.exit(0);
257
+ }
258
+ catch (error) {
259
+ const globalOpts = command.parent?.parent?.opts() || {};
260
+ if (globalOpts.json) {
261
+ outputError("cex_ticker", error, getExitCode(error));
262
+ }
263
+ else {
264
+ handleError(error, globalOpts.verbose);
265
+ }
266
+ process.exit(getExitCode(error));
267
+ }
268
+ });
269
+ // ============================================================================
270
+ // 3. Balance Command
271
+ // ============================================================================
272
+ cexCommand
273
+ .command("balance")
274
+ .description("Get all asset balances in CEX.IO account ($0.001)")
275
+ .option("--currency <currency>", "Filter by specific currency (e.g., BTC, USD)")
276
+ .action(async (options, command) => {
277
+ try {
278
+ const globalOpts = command.parent?.parent?.opts() || {};
279
+ const accountIndex = globalOpts.account;
280
+ await ensureWalletUnlocked();
281
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
282
+ if (!isConfigured(globalOpts.privateKey)) {
283
+ if (globalOpts.json) {
284
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
285
+ process.exit(2);
286
+ }
287
+ privateKey = await promptForPrivateKey();
288
+ }
289
+ const client = await HttpcatClient.create(privateKey);
290
+ const result = await withLoading(async () => {
291
+ const { data } = await client.invoke("cex/balance", {
292
+ currency: options.currency,
293
+ });
294
+ return data;
295
+ }, {
296
+ message: "Fetching balance ($0.001)...",
297
+ json: globalOpts.json,
298
+ quiet: globalOpts.quiet,
299
+ spinner: "cat",
300
+ clearOnSuccess: true,
301
+ });
302
+ if (globalOpts.json) {
303
+ outputJson("cex_balance", {
304
+ command: "cex_balance",
305
+ data: result,
306
+ });
307
+ }
308
+ else if (!globalOpts.quiet) {
309
+ console.log();
310
+ console.log(chalk.magenta.bold("💰 CEX.IO Balance"));
311
+ console.log();
312
+ const balances = result.balances || result.assets || [];
313
+ const totalValue = result.totalValue || result.totalPortfolioValue || 0;
314
+ if (totalValue > 0) {
315
+ console.log(chalk.bold(`Total Portfolio Value: ${formatCurrency(totalValue)}`));
316
+ console.log();
317
+ }
318
+ if (balances.length > 0) {
319
+ const table = createTable({
320
+ head: ["Currency", "Available", "Locked in Orders", "Total"],
321
+ colWidths: [12, 18, 20, 18],
322
+ });
323
+ for (const balance of balances) {
324
+ const currency = balance.currency || balance.symbol || "";
325
+ const available = parseFloat(balance.available?.toString() || "0");
326
+ const locked = parseFloat(balance.locked?.toString() || "0");
327
+ const total = parseFloat(balance.total?.toString() || "0");
328
+ table.push([
329
+ chalk.cyan(currency.toUpperCase()),
330
+ formatTokenAmount(available.toString()),
331
+ formatTokenAmount(locked.toString()),
332
+ formatTokenAmount(total.toString()),
333
+ ]);
334
+ }
335
+ console.log(table.toString());
336
+ }
337
+ else {
338
+ console.log(chalk.dim("No balances found."));
339
+ }
340
+ console.log();
341
+ }
342
+ process.exit(0);
343
+ }
344
+ catch (error) {
345
+ const globalOpts = command.parent?.parent?.opts() || {};
346
+ if (globalOpts.json) {
347
+ outputError("cex_balance", error, getExitCode(error));
348
+ }
349
+ else {
350
+ handleError(error, globalOpts.verbose);
351
+ }
352
+ process.exit(getExitCode(error));
353
+ }
354
+ });
355
+ // ============================================================================
356
+ // 4. Orderbook Command
357
+ // ============================================================================
358
+ cexCommand
359
+ .command("orderbook")
360
+ .description("Get current order book for a trading pair ($0.001)")
361
+ .argument("<symbol>", "Trading pair (e.g., BTC/USD)")
362
+ .option("--depth <depth>", "Order book depth", "20")
363
+ .action(async (symbol, options, command) => {
364
+ try {
365
+ const globalOpts = command.parent?.parent?.opts() || {};
366
+ const accountIndex = globalOpts.account;
367
+ await ensureWalletUnlocked();
368
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
369
+ if (!isConfigured(globalOpts.privateKey)) {
370
+ if (globalOpts.json) {
371
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
372
+ process.exit(2);
373
+ }
374
+ privateKey = await promptForPrivateKey();
375
+ }
376
+ const client = await HttpcatClient.create(privateKey);
377
+ const normalizedSymbol = normalizeSymbol(symbol);
378
+ const depth = Math.min(parseInt(options.depth || "20"), 100);
379
+ const result = await withLoading(async () => {
380
+ const { data } = await client.invoke("cex/orderbook", {
381
+ symbol: normalizedSymbol,
382
+ depth,
383
+ });
384
+ return data;
385
+ }, {
386
+ message: "Fetching orderbook ($0.001)...",
387
+ json: globalOpts.json,
388
+ quiet: globalOpts.quiet,
389
+ spinner: "cat",
390
+ clearOnSuccess: true,
391
+ });
392
+ if (globalOpts.json) {
393
+ outputJson("cex_orderbook", {
394
+ command: "cex_orderbook",
395
+ data: result,
396
+ });
397
+ }
398
+ else if (!globalOpts.quiet) {
399
+ console.log();
400
+ console.log(chalk.magenta.bold(`📖 Orderbook: ${normalizedSymbol} (Depth: ${depth})`));
401
+ console.log();
402
+ const asks = result.asks || [];
403
+ const bids = result.bids || [];
404
+ const bestAsk = asks[0]?.[0] || 0;
405
+ const bestBid = bids[0]?.[0] || 0;
406
+ const spread = bestAsk - bestBid;
407
+ const spreadPercent = bestAsk > 0 ? (spread / bestAsk) * 100 : 0;
408
+ console.log(chalk.dim(`Spread: ${formatCurrency(spread)} (${spreadPercent.toFixed(2)}%)`));
409
+ console.log();
410
+ // Create side-by-side table
411
+ const maxRows = Math.max(asks.length, bids.length);
412
+ const table = createTable({
413
+ head: [
414
+ "ASKS (Sell Orders)",
415
+ "",
416
+ "│",
417
+ "BIDS (Buy Orders)",
418
+ "",
419
+ ],
420
+ colWidths: [15, 15, 3, 15, 15],
421
+ });
422
+ for (let i = 0; i < Math.min(maxRows, depth); i++) {
423
+ const ask = asks[i] || [];
424
+ const bid = bids[i] || [];
425
+ table.push([
426
+ ask[0] ? formatCurrency(ask[0]) : "",
427
+ ask[1] ? formatTokenAmount(ask[1].toString()) : "",
428
+ "│",
429
+ bid[0] ? formatCurrency(bid[0]) : "",
430
+ bid[1] ? formatTokenAmount(bid[1].toString()) : "",
431
+ ]);
432
+ }
433
+ console.log(table.toString());
434
+ console.log();
435
+ }
436
+ process.exit(0);
437
+ }
438
+ catch (error) {
439
+ const globalOpts = command.parent?.parent?.opts() || {};
440
+ if (globalOpts.json) {
441
+ outputError("cex_orderbook", error, getExitCode(error));
442
+ }
443
+ else {
444
+ handleError(error, globalOpts.verbose);
445
+ }
446
+ process.exit(getExitCode(error));
447
+ }
448
+ });
449
+ // ============================================================================
450
+ // 5. Orders Command (Open Orders)
451
+ // ============================================================================
452
+ cexCommand
453
+ .command("orders")
454
+ .description("Get all open (active) orders for the account ($0.001)")
455
+ .option("--symbol <symbol>", "Filter by trading pair (e.g., BTC/USD)")
456
+ .option("--limit <limit>", "Maximum orders", "100")
457
+ .action(async (options, command) => {
458
+ try {
459
+ const globalOpts = command.parent?.parent?.opts() || {};
460
+ const accountIndex = globalOpts.account;
461
+ await ensureWalletUnlocked();
462
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
463
+ if (!isConfigured(globalOpts.privateKey)) {
464
+ if (globalOpts.json) {
465
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
466
+ process.exit(2);
467
+ }
468
+ privateKey = await promptForPrivateKey();
469
+ }
470
+ const client = await HttpcatClient.create(privateKey);
471
+ const symbol = options.symbol ? normalizeSymbol(options.symbol) : undefined;
472
+ const result = await withLoading(async () => {
473
+ const { data } = await client.invoke("cex/orders", {
474
+ symbol,
475
+ limit: parseInt(options.limit || "100"),
476
+ });
477
+ return data;
478
+ }, {
479
+ message: "Fetching open orders ($0.001)...",
480
+ json: globalOpts.json,
481
+ quiet: globalOpts.quiet,
482
+ spinner: "cat",
483
+ clearOnSuccess: true,
484
+ });
485
+ if (globalOpts.json) {
486
+ outputJson("cex_orders", {
487
+ command: "cex_orders",
488
+ data: result,
489
+ });
490
+ }
491
+ else if (!globalOpts.quiet) {
492
+ console.log();
493
+ const orders = result.orders || [];
494
+ console.log(chalk.magenta.bold(`📋 Open Orders (${orders.length} orders)`));
495
+ console.log();
496
+ if (orders.length > 0) {
497
+ const table = createTable({
498
+ head: ["ID", "Pair", "Type", "Order Type", "Price", "Amount"],
499
+ colWidths: [10, 12, 8, 12, 15, 15],
500
+ });
501
+ for (const order of orders) {
502
+ const orderId = order.id || order.orderId || "";
503
+ const pair = order.symbol || order.pair || "";
504
+ const type = order.type || order.side || "";
505
+ const orderType = order.orderType || order.type || "Limit";
506
+ const price = order.price || "-";
507
+ const amount = order.amount || order.quantity || 0;
508
+ const typeColor = type.toLowerCase() === "buy" ? chalk.green : chalk.red;
509
+ table.push([
510
+ chalk.cyan(orderId.toString()),
511
+ pair,
512
+ typeColor(type),
513
+ orderType,
514
+ price === "-" ? chalk.dim("-") : formatCurrency(price),
515
+ formatTokenAmount(amount.toString()),
516
+ ]);
517
+ }
518
+ console.log(table.toString());
519
+ console.log();
520
+ console.log(chalk.dim(`Total: ${orders.length} open orders`));
521
+ }
522
+ else {
523
+ console.log(chalk.dim("No open orders."));
524
+ }
525
+ console.log();
526
+ }
527
+ process.exit(0);
528
+ }
529
+ catch (error) {
530
+ const globalOpts = command.parent?.parent?.opts() || {};
531
+ if (globalOpts.json) {
532
+ outputError("cex_orders", error, getExitCode(error));
533
+ }
534
+ else {
535
+ handleError(error, globalOpts.verbose);
536
+ }
537
+ process.exit(getExitCode(error));
538
+ }
539
+ });
540
+ // ============================================================================
541
+ // 6. Order History Command
542
+ // ============================================================================
543
+ cexCommand
544
+ .command("order-history")
545
+ .description("Get historical orders (completed, canceled, failed) ($0.01)")
546
+ .option("--symbol <symbol>", "Filter by trading pair")
547
+ .option("--status <status>", "Filter by status: completed, canceled, failed, or all", "all")
548
+ .option("--limit <limit>", "Maximum orders", "50")
549
+ .option("--since <timestamp>", "ISO timestamp for filtering orders since this time")
550
+ .action(async (options, command) => {
551
+ try {
552
+ const globalOpts = command.parent?.parent?.opts() || {};
553
+ const accountIndex = globalOpts.account;
554
+ await ensureWalletUnlocked();
555
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
556
+ if (!isConfigured(globalOpts.privateKey)) {
557
+ if (globalOpts.json) {
558
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
559
+ process.exit(2);
560
+ }
561
+ privateKey = await promptForPrivateKey();
562
+ }
563
+ const client = await HttpcatClient.create(privateKey);
564
+ const symbol = options.symbol ? normalizeSymbol(options.symbol) : undefined;
565
+ const limit = Math.min(parseInt(options.limit || "50"), 100);
566
+ const result = await withLoading(async () => {
567
+ const { data } = await client.invoke("cex/order-history", {
568
+ symbol,
569
+ status: options.status === "all" ? undefined : options.status,
570
+ limit,
571
+ since: options.since,
572
+ });
573
+ return data;
574
+ }, {
575
+ message: "Fetching order history ($0.01)...",
576
+ json: globalOpts.json,
577
+ quiet: globalOpts.quiet,
578
+ spinner: "cat",
579
+ clearOnSuccess: true,
580
+ });
581
+ if (globalOpts.json) {
582
+ outputJson("cex_order_history", {
583
+ command: "cex_order_history",
584
+ data: result,
585
+ });
586
+ }
587
+ else if (!globalOpts.quiet) {
588
+ console.log();
589
+ const orders = result.orders || [];
590
+ console.log(chalk.magenta.bold(`📜 Order History (${orders.length} orders)`));
591
+ console.log();
592
+ if (orders.length > 0) {
593
+ const table = createTable({
594
+ head: ["ID", "Pair", "Type", "Status", "Price", "Amount"],
595
+ colWidths: [10, 12, 8, 12, 15, 15],
596
+ });
597
+ for (const order of orders) {
598
+ const orderId = order.id || order.orderId || "";
599
+ const pair = order.symbol || order.pair || "";
600
+ const type = order.type || order.side || "";
601
+ const status = order.status || "";
602
+ const price = order.price || 0;
603
+ const amount = order.amount || order.quantity || 0;
604
+ const typeColor = type.toLowerCase() === "buy" ? chalk.green : chalk.red;
605
+ const statusColor = status.toLowerCase() === "completed"
606
+ ? chalk.green
607
+ : status.toLowerCase() === "canceled"
608
+ ? chalk.yellow
609
+ : chalk.red;
610
+ table.push([
611
+ chalk.cyan(orderId.toString()),
612
+ pair,
613
+ typeColor(type),
614
+ statusColor(status),
615
+ formatCurrency(price),
616
+ formatTokenAmount(amount.toString()),
617
+ ]);
618
+ }
619
+ console.log(table.toString());
620
+ console.log();
621
+ const hasMore = result.hasMore || false;
622
+ console.log(chalk.dim(`Total: ${orders.length} orders${hasMore ? " (has more: true)" : ""}`));
623
+ }
624
+ else {
625
+ console.log(chalk.dim("No order history found."));
626
+ }
627
+ console.log();
628
+ }
629
+ process.exit(0);
630
+ }
631
+ catch (error) {
632
+ const globalOpts = command.parent?.parent?.opts() || {};
633
+ if (globalOpts.json) {
634
+ outputError("cex_order_history", error, getExitCode(error));
635
+ }
636
+ else {
637
+ handleError(error, globalOpts.verbose);
638
+ }
639
+ process.exit(getExitCode(error));
640
+ }
641
+ });
642
+ // ============================================================================
643
+ // 7. Trade History Command
644
+ // ============================================================================
645
+ cexCommand
646
+ .command("trade-history")
647
+ .description("Get history of executed trades (fills) ($0.01)")
648
+ .option("--symbol <symbol>", "Filter by trading pair")
649
+ .option("--limit <limit>", "Maximum trades", "50")
650
+ .option("--since <timestamp>", "ISO timestamp for filtering trades since this time")
651
+ .option("--until <timestamp>", "ISO timestamp for filtering trades until this time")
652
+ .action(async (options, command) => {
653
+ try {
654
+ const globalOpts = command.parent?.parent?.opts() || {};
655
+ const accountIndex = globalOpts.account;
656
+ await ensureWalletUnlocked();
657
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
658
+ if (!isConfigured(globalOpts.privateKey)) {
659
+ if (globalOpts.json) {
660
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
661
+ process.exit(2);
662
+ }
663
+ privateKey = await promptForPrivateKey();
664
+ }
665
+ const client = await HttpcatClient.create(privateKey);
666
+ const symbol = options.symbol ? normalizeSymbol(options.symbol) : undefined;
667
+ const limit = Math.min(parseInt(options.limit || "50"), 100);
668
+ const result = await withLoading(async () => {
669
+ const { data } = await client.invoke("cex/trade-history", {
670
+ symbol,
671
+ limit,
672
+ since: options.since,
673
+ until: options.until,
674
+ });
675
+ return data;
676
+ }, {
677
+ message: "Fetching trade history ($0.01)...",
678
+ json: globalOpts.json,
679
+ quiet: globalOpts.quiet,
680
+ spinner: "cat",
681
+ clearOnSuccess: true,
682
+ });
683
+ if (globalOpts.json) {
684
+ outputJson("cex_trade_history", {
685
+ command: "cex_trade_history",
686
+ data: result,
687
+ });
688
+ }
689
+ else if (!globalOpts.quiet) {
690
+ console.log();
691
+ const trades = result.trades || [];
692
+ console.log(chalk.magenta.bold(`💱 Trade History (${trades.length} trades)`));
693
+ console.log();
694
+ if (trades.length > 0) {
695
+ const table = createTable({
696
+ head: ["ID", "Order ID", "Pair", "Type", "Price", "Amount"],
697
+ colWidths: [10, 12, 12, 8, 15, 15],
698
+ });
699
+ for (const trade of trades) {
700
+ const tradeId = trade.id || trade.tradeId || "";
701
+ const orderId = trade.orderId || "";
702
+ const pair = trade.symbol || trade.pair || "";
703
+ const type = trade.type || trade.side || "";
704
+ const price = trade.price || 0;
705
+ const amount = trade.amount || trade.quantity || 0;
706
+ const typeColor = type.toLowerCase() === "buy" ? chalk.green : chalk.red;
707
+ table.push([
708
+ chalk.cyan(tradeId.toString()),
709
+ orderId.toString(),
710
+ pair,
711
+ typeColor(type),
712
+ formatCurrency(price),
713
+ formatTokenAmount(amount.toString()),
714
+ ]);
715
+ }
716
+ console.log(table.toString());
717
+ console.log();
718
+ const hasMore = result.hasMore || false;
719
+ console.log(chalk.dim(`Total: ${trades.length} trades${hasMore ? " (has more: true)" : ""}`));
720
+ }
721
+ else {
722
+ console.log(chalk.dim("No trade history found."));
723
+ }
724
+ console.log();
725
+ }
726
+ process.exit(0);
727
+ }
728
+ catch (error) {
729
+ const globalOpts = command.parent?.parent?.opts() || {};
730
+ if (globalOpts.json) {
731
+ outputError("cex_trade_history", error, getExitCode(error));
732
+ }
733
+ else {
734
+ handleError(error, globalOpts.verbose);
735
+ }
736
+ process.exit(getExitCode(error));
737
+ }
738
+ });
739
+ // ============================================================================
740
+ // 8. Place Order Command (HIGH RISK - requires confirmation)
741
+ // ============================================================================
742
+ cexCommand
743
+ .command("place-order")
744
+ .description("Place a new buy or sell order ($0.05) - HIGH RISK: executes real trades")
745
+ .argument("<symbol>", "Trading pair (e.g., BTC/USD)")
746
+ .argument("<type>", "Order type: buy or sell")
747
+ .argument("<orderType>", "Order type detail: market, limit, or stop-limit")
748
+ .argument("<amount>", "Order amount (decimal, positive)")
749
+ .option("--price <price>", "Order price (required for limit/stop-limit)")
750
+ .option("--stop-price <price>", "Stop price (for stop-limit orders)")
751
+ .option("--confirm", "Skip confirmation prompt (use with caution)")
752
+ .action(async (symbol, type, orderType, amount, options, command) => {
753
+ try {
754
+ const globalOpts = command.parent?.parent?.opts() || {};
755
+ const accountIndex = globalOpts.account;
756
+ await ensureWalletUnlocked();
757
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
758
+ if (!isConfigured(globalOpts.privateKey)) {
759
+ if (globalOpts.json) {
760
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
761
+ process.exit(2);
762
+ }
763
+ privateKey = await promptForPrivateKey();
764
+ }
765
+ // Validate inputs
766
+ const amountNum = parseFloat(amount);
767
+ if (isNaN(amountNum) || amountNum <= 0) {
768
+ throw new Error("Amount must be a positive number");
769
+ }
770
+ if ((orderType === "limit" || orderType === "stop-limit") &&
771
+ !options.price) {
772
+ throw new Error("Price is required for limit and stop-limit orders");
773
+ }
774
+ if (orderType === "stop-limit" && !options.stopPrice) {
775
+ throw new Error("Stop price is required for stop-limit orders");
776
+ }
777
+ if (type !== "buy" && type !== "sell") {
778
+ throw new Error("Type must be 'buy' or 'sell'");
779
+ }
780
+ if (orderType !== "market" &&
781
+ orderType !== "limit" &&
782
+ orderType !== "stop-limit") {
783
+ throw new Error("Order type must be 'market', 'limit', or 'stop-limit'");
784
+ }
785
+ const client = await HttpcatClient.create(privateKey);
786
+ const normalizedSymbol = normalizeSymbol(symbol);
787
+ // Show warning and confirmation (unless --confirm flag)
788
+ if (!options.confirm && !globalOpts.json && !globalOpts.quiet) {
789
+ console.log();
790
+ console.log(chalk.red.bold("⚠️ WARNING: This will place a REAL order on CEX.IO"));
791
+ console.log();
792
+ const priceNum = options.price ? parseFloat(options.price) : 0;
793
+ const estimatedCost = priceNum > 0 ? priceNum * amountNum : 0;
794
+ const orderSummary = {
795
+ Pair: chalk.cyan(normalizedSymbol),
796
+ Type: type === "buy" ? chalk.green(type) : chalk.red(type),
797
+ "Order Type": orderType,
798
+ Amount: formatTokenAmount(amount),
799
+ };
800
+ if (priceNum > 0) {
801
+ orderSummary["Price"] = formatCurrency(priceNum);
802
+ orderSummary["Estimated Cost"] = formatCurrency(estimatedCost);
803
+ }
804
+ if (options.stopPrice) {
805
+ orderSummary["Stop Price"] = formatCurrency(parseFloat(options.stopPrice));
806
+ }
807
+ printBox("Order Details", orderSummary);
808
+ console.log();
809
+ const inquirer = (await import("inquirer")).default;
810
+ const { confirmed } = await inquirer.prompt([
811
+ {
812
+ type: "confirm",
813
+ name: "confirmed",
814
+ message: "Are you sure you want to proceed?",
815
+ default: false,
816
+ },
817
+ ]);
818
+ if (!confirmed) {
819
+ console.log(chalk.yellow("Order canceled by user."));
820
+ process.exit(0);
821
+ }
822
+ }
823
+ const result = await withLoading(async () => {
824
+ const orderData = {
825
+ symbol: normalizedSymbol,
826
+ type,
827
+ orderType,
828
+ amount: amountNum,
829
+ };
830
+ if (options.price) {
831
+ orderData.price = parseFloat(options.price);
832
+ }
833
+ if (options.stopPrice) {
834
+ orderData.stopPrice = parseFloat(options.stopPrice);
835
+ }
836
+ const { data } = await client.invoke("cex/place-order", orderData);
837
+ return data;
838
+ }, {
839
+ message: "Placing order ($0.05)...",
840
+ json: globalOpts.json,
841
+ quiet: globalOpts.quiet,
842
+ spinner: "cat",
843
+ clearOnSuccess: true,
844
+ });
845
+ if (globalOpts.json) {
846
+ outputJson("cex_place_order", {
847
+ command: "cex_place_order",
848
+ data: result,
849
+ });
850
+ }
851
+ else if (!globalOpts.quiet) {
852
+ console.log();
853
+ console.log(chalk.green.bold("✅ Order Placed Successfully"));
854
+ console.log();
855
+ const orderId = result.id || result.orderId || "";
856
+ const status = result.status || "";
857
+ const pair = result.symbol || normalizedSymbol;
858
+ const orderType = result.orderType || "";
859
+ const amount = result.amount || amountNum;
860
+ const price = result.price || options.price || "-";
861
+ const filled = result.filled || result.filledAmount || 0;
862
+ const remaining = result.remaining || result.remainingAmount || amountNum - filled;
863
+ const boxData = {
864
+ "Order ID": chalk.cyan(orderId.toString()),
865
+ Status: status === "open" ? chalk.green(status) : status,
866
+ Pair: pair,
867
+ Type: `${result.type || type} (${orderType})`,
868
+ Amount: formatTokenAmount(amount.toString()),
869
+ Price: price === "-" ? chalk.dim("-") : formatCurrency(price),
870
+ Filled: formatTokenAmount(filled.toString()),
871
+ Remaining: formatTokenAmount(remaining.toString()),
872
+ };
873
+ printBox("Order Details", boxData);
874
+ console.log();
875
+ }
876
+ process.exit(0);
877
+ }
878
+ catch (error) {
879
+ const globalOpts = command.parent?.parent?.opts() || {};
880
+ if (globalOpts.json) {
881
+ outputError("cex_place_order", error, getExitCode(error));
882
+ }
883
+ else {
884
+ handleError(error, globalOpts.verbose);
885
+ }
886
+ process.exit(getExitCode(error));
887
+ }
888
+ });
889
+ // ============================================================================
890
+ // 9. Cancel Order Command
891
+ // ============================================================================
892
+ cexCommand
893
+ .command("cancel-order")
894
+ .description("Cancel an open order by ID ($0.01)")
895
+ .argument("<orderId>", "Order ID to cancel")
896
+ .action(async (orderId, options, command) => {
897
+ try {
898
+ const globalOpts = command.parent?.parent?.opts() || {};
899
+ const accountIndex = globalOpts.account;
900
+ await ensureWalletUnlocked();
901
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
902
+ if (!isConfigured(globalOpts.privateKey)) {
903
+ if (globalOpts.json) {
904
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
905
+ process.exit(2);
906
+ }
907
+ privateKey = await promptForPrivateKey();
908
+ }
909
+ const client = await HttpcatClient.create(privateKey);
910
+ const result = await withLoading(async () => {
911
+ const { data } = await client.invoke("cex/cancel-order", {
912
+ orderId: orderId.toString(),
913
+ });
914
+ return data;
915
+ }, {
916
+ message: "Canceling order ($0.01)...",
917
+ json: globalOpts.json,
918
+ quiet: globalOpts.quiet,
919
+ spinner: "cat",
920
+ clearOnSuccess: true,
921
+ });
922
+ if (globalOpts.json) {
923
+ outputJson("cex_cancel_order", {
924
+ command: "cex_cancel_order",
925
+ data: result,
926
+ });
927
+ }
928
+ else if (!globalOpts.quiet) {
929
+ console.log();
930
+ console.log(chalk.green.bold("✅ Order Canceled"));
931
+ console.log();
932
+ const canceledOrderId = result.id || result.orderId || orderId;
933
+ const status = result.status || "canceled";
934
+ const message = result.message || "Order canceled successfully";
935
+ const boxData = {
936
+ "Order ID": chalk.cyan(canceledOrderId.toString()),
937
+ Status: status === "canceled" ? chalk.yellow(status) : status,
938
+ Message: message,
939
+ };
940
+ printBox("Cancel Result", boxData);
941
+ console.log();
942
+ }
943
+ process.exit(0);
944
+ }
945
+ catch (error) {
946
+ const globalOpts = command.parent?.parent?.opts() || {};
947
+ if (globalOpts.json) {
948
+ outputError("cex_cancel_order", error, getExitCode(error));
949
+ }
950
+ else {
951
+ handleError(error, globalOpts.verbose);
952
+ }
953
+ process.exit(getExitCode(error));
954
+ }
955
+ });
956
+ return cexCommand;
957
+ }
958
+ //# sourceMappingURL=cex.js.map