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,960 @@
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, formatAddress, 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
+ // ============================================================================
54
+ // Market Intelligence Command Group
55
+ // ============================================================================
56
+ export function createMarketCommand() {
57
+ const marketCommand = new Command("market")
58
+ .description("Market intelligence & token analysis")
59
+ .addHelpText("after", `
60
+ Examples:
61
+ httpcat market price <token>
62
+ httpcat market ohlc <token> --interval 1h
63
+ httpcat market liquidity <token>
64
+ httpcat market price-impact <token> <amount> <side>
65
+ httpcat market search bitcoin
66
+ httpcat market coin-data bitcoin --sparkline
67
+ httpcat market chart bitcoin 7
68
+ `);
69
+ marketCommand
70
+ .command("price")
71
+ .description("Get token price data ($0.001)")
72
+ .argument("<tokenIdentifier>", "Token identifier (address, symbol, or name)")
73
+ .option("--timeframe <timeframe>", "Timeframe: 1h, 24h, 7d, 30d")
74
+ .action(async (tokenIdentifier, options, command) => {
75
+ try {
76
+ const globalOpts = command.parent?.parent?.opts() || {};
77
+ const accountIndex = globalOpts.account;
78
+ await ensureWalletUnlocked();
79
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
80
+ if (!isConfigured(globalOpts.privateKey)) {
81
+ if (globalOpts.json) {
82
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
83
+ process.exit(2);
84
+ }
85
+ privateKey = await promptForPrivateKey();
86
+ }
87
+ const client = await HttpcatClient.create(privateKey);
88
+ const params = new URLSearchParams({ tokenIdentifier });
89
+ if (options.timeframe)
90
+ params.append("timeframe", options.timeframe);
91
+ const result = await withLoading(async () => {
92
+ try {
93
+ const data = await client.get(`/market/price?${params.toString()}`);
94
+ return data.output || data;
95
+ }
96
+ catch {
97
+ const { data } = await client.invoke("market/price", {
98
+ tokenIdentifier,
99
+ timeframe: options.timeframe,
100
+ });
101
+ return data;
102
+ }
103
+ }, {
104
+ message: "Fetching price data...",
105
+ json: globalOpts.json,
106
+ quiet: globalOpts.quiet,
107
+ spinner: "cat",
108
+ clearOnSuccess: true,
109
+ });
110
+ if (globalOpts.json) {
111
+ outputJson("market_price", result);
112
+ }
113
+ else if (!globalOpts.quiet) {
114
+ console.log();
115
+ console.log(chalk.magenta.bold("💰 Token Price"));
116
+ console.log();
117
+ const boxData = {
118
+ Token: chalk.cyan(tokenIdentifier),
119
+ Price: chalk.green.bold(formatCurrency(result.price || "0")),
120
+ };
121
+ if (result.priceChange24h !== undefined) {
122
+ const change24h = parseFloat(result.priceChange24h.toString());
123
+ const changeColor = change24h >= 0 ? chalk.green : chalk.red;
124
+ boxData["24h Change"] = changeColor(`${change24h >= 0 ? "+" : ""}${change24h.toFixed(2)}%`);
125
+ }
126
+ if (result.priceChange7d !== undefined) {
127
+ const change7d = parseFloat(result.priceChange7d.toString());
128
+ const changeColor = change7d >= 0 ? chalk.green : chalk.red;
129
+ boxData["7d Change"] = changeColor(`${change7d >= 0 ? "+" : ""}${change7d.toFixed(2)}%`);
130
+ }
131
+ printBox("Price Data", boxData);
132
+ console.log();
133
+ }
134
+ process.exit(0);
135
+ }
136
+ catch (error) {
137
+ const globalOpts = command.parent?.parent?.opts() || {};
138
+ if (globalOpts.json) {
139
+ outputError("market_price", error, getExitCode(error));
140
+ }
141
+ else {
142
+ handleError(error, globalOpts.verbose);
143
+ }
144
+ process.exit(getExitCode(error));
145
+ }
146
+ });
147
+ marketCommand
148
+ .command("ohlc")
149
+ .description("Get OHLC (Open, High, Low, Close) candle data ($0.01)")
150
+ .argument("<tokenIdentifier>", "Token identifier")
151
+ .option("--interval <interval>", "Interval: 1m, 5m, 15m, 1h, 4h, 1d", "1h")
152
+ .option("--limit <limit>", "Limit results", "100")
153
+ .action(async (tokenIdentifier, options, command) => {
154
+ try {
155
+ const globalOpts = command.parent?.parent?.opts() || {};
156
+ const accountIndex = globalOpts.account;
157
+ await ensureWalletUnlocked();
158
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
159
+ if (!isConfigured(globalOpts.privateKey)) {
160
+ if (globalOpts.json) {
161
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
162
+ process.exit(2);
163
+ }
164
+ privateKey = await promptForPrivateKey();
165
+ }
166
+ const client = await HttpcatClient.create(privateKey);
167
+ const params = new URLSearchParams({
168
+ tokenIdentifier,
169
+ interval: options.interval || "1h",
170
+ limit: options.limit || "100",
171
+ });
172
+ const result = await withLoading(async () => {
173
+ try {
174
+ const data = await client.get(`/market/ohlc?${params.toString()}`);
175
+ return data.output || data;
176
+ }
177
+ catch {
178
+ const { data } = await client.invoke("market/ohlc", {
179
+ tokenIdentifier,
180
+ interval: options.interval || "1h",
181
+ limit: parseInt(options.limit || "100"),
182
+ });
183
+ return data;
184
+ }
185
+ }, {
186
+ message: "Fetching OHLC data...",
187
+ json: globalOpts.json,
188
+ quiet: globalOpts.quiet,
189
+ spinner: "cat",
190
+ clearOnSuccess: true,
191
+ });
192
+ if (globalOpts.json) {
193
+ outputJson("market_ohlc", result);
194
+ }
195
+ else if (!globalOpts.quiet) {
196
+ console.log();
197
+ console.log(chalk.magenta.bold(`📊 OHLC Data (${result.candles?.length || 0} candles)`));
198
+ console.log();
199
+ if (result.candles && result.candles.length > 0) {
200
+ const table = createTable({
201
+ head: ["Time", "Open", "High", "Low", "Close", "Volume"],
202
+ colWidths: [20, 15, 15, 15, 15, 20],
203
+ });
204
+ for (const candle of result.candles.slice(0, 20)) {
205
+ table.push([
206
+ new Date(candle.timestamp).toLocaleString(),
207
+ formatCurrency(candle.open),
208
+ chalk.green(formatCurrency(candle.high)),
209
+ chalk.red(formatCurrency(candle.low)),
210
+ formatCurrency(candle.close),
211
+ formatTokenAmount(candle.volume),
212
+ ]);
213
+ }
214
+ console.log(table.toString());
215
+ if (result.candles.length > 20) {
216
+ console.log(chalk.dim(`... and ${result.candles.length - 20} more candles`));
217
+ }
218
+ }
219
+ console.log();
220
+ }
221
+ process.exit(0);
222
+ }
223
+ catch (error) {
224
+ const globalOpts = command.parent?.parent?.opts() || {};
225
+ if (globalOpts.json) {
226
+ outputError("market_ohlc", error, getExitCode(error));
227
+ }
228
+ else {
229
+ handleError(error, globalOpts.verbose);
230
+ }
231
+ process.exit(getExitCode(error));
232
+ }
233
+ });
234
+ marketCommand
235
+ .command("liquidity")
236
+ .description("Get liquidity depth ($0.01)")
237
+ .argument("<tokenIdentifier>", "Token identifier")
238
+ .option("--depth <depth>", "Depth level", "10")
239
+ .action(async (tokenIdentifier, options, command) => {
240
+ try {
241
+ const globalOpts = command.parent?.parent?.opts() || {};
242
+ const accountIndex = globalOpts.account;
243
+ await ensureWalletUnlocked();
244
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
245
+ if (!isConfigured(globalOpts.privateKey)) {
246
+ if (globalOpts.json) {
247
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
248
+ process.exit(2);
249
+ }
250
+ privateKey = await promptForPrivateKey();
251
+ }
252
+ const client = await HttpcatClient.create(privateKey);
253
+ const params = new URLSearchParams({
254
+ tokenIdentifier,
255
+ depth: options.depth || "10",
256
+ });
257
+ const result = await withLoading(async () => {
258
+ try {
259
+ const data = await client.get(`/market/liquidity?${params.toString()}`);
260
+ return data.output || data;
261
+ }
262
+ catch {
263
+ const { data } = await client.invoke("market/liquidity", {
264
+ tokenIdentifier,
265
+ depth: parseInt(options.depth || "10"),
266
+ });
267
+ return data;
268
+ }
269
+ }, {
270
+ message: "Fetching liquidity data...",
271
+ json: globalOpts.json,
272
+ quiet: globalOpts.quiet,
273
+ spinner: "cat",
274
+ clearOnSuccess: true,
275
+ });
276
+ if (globalOpts.json) {
277
+ outputJson("market_liquidity", result);
278
+ }
279
+ else if (!globalOpts.quiet) {
280
+ console.log();
281
+ console.log(chalk.magenta.bold("💧 Liquidity Depth"));
282
+ console.log();
283
+ if (result.bids && result.bids.length > 0) {
284
+ console.log(chalk.green.bold("Bids:"));
285
+ const bidsTable = createTable({
286
+ head: ["Price", "Amount"],
287
+ colWidths: [20, 20],
288
+ });
289
+ for (const bid of result.bids.slice(0, 10)) {
290
+ bidsTable.push([formatCurrency(bid.price), formatTokenAmount(bid.amount)]);
291
+ }
292
+ console.log(bidsTable.toString());
293
+ }
294
+ if (result.asks && result.asks.length > 0) {
295
+ console.log();
296
+ console.log(chalk.red.bold("Asks:"));
297
+ const asksTable = createTable({
298
+ head: ["Price", "Amount"],
299
+ colWidths: [20, 20],
300
+ });
301
+ for (const ask of result.asks.slice(0, 10)) {
302
+ asksTable.push([formatCurrency(ask.price), formatTokenAmount(ask.amount)]);
303
+ }
304
+ console.log(asksTable.toString());
305
+ }
306
+ console.log();
307
+ }
308
+ process.exit(0);
309
+ }
310
+ catch (error) {
311
+ const globalOpts = command.parent?.parent?.opts() || {};
312
+ if (globalOpts.json) {
313
+ outputError("market_liquidity", error, getExitCode(error));
314
+ }
315
+ else {
316
+ handleError(error, globalOpts.verbose);
317
+ }
318
+ process.exit(getExitCode(error));
319
+ }
320
+ });
321
+ marketCommand
322
+ .command("price-impact")
323
+ .description("Calculate price impact for trade ($0.01)")
324
+ .argument("<tokenIdentifier>", "Token identifier")
325
+ .argument("<amount>", "Trade amount")
326
+ .argument("<side>", "Trade side: buy or sell")
327
+ .action(async (tokenIdentifier, amount, side, options, command) => {
328
+ try {
329
+ const globalOpts = command.parent?.parent?.opts() || {};
330
+ const accountIndex = globalOpts.account;
331
+ await ensureWalletUnlocked();
332
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
333
+ if (!isConfigured(globalOpts.privateKey)) {
334
+ if (globalOpts.json) {
335
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
336
+ process.exit(2);
337
+ }
338
+ privateKey = await promptForPrivateKey();
339
+ }
340
+ const client = await HttpcatClient.create(privateKey);
341
+ const params = new URLSearchParams({
342
+ tokenIdentifier,
343
+ amount,
344
+ side,
345
+ });
346
+ const result = await withLoading(async () => {
347
+ try {
348
+ const data = await client.get(`/market/price-impact?${params.toString()}`);
349
+ return data.output || data;
350
+ }
351
+ catch {
352
+ const { data } = await client.invoke("market/price-impact", {
353
+ tokenIdentifier,
354
+ amount,
355
+ side,
356
+ });
357
+ return data;
358
+ }
359
+ }, {
360
+ message: "Calculating price impact...",
361
+ json: globalOpts.json,
362
+ quiet: globalOpts.quiet,
363
+ spinner: "cat",
364
+ clearOnSuccess: true,
365
+ });
366
+ if (globalOpts.json) {
367
+ outputJson("market_price_impact", result);
368
+ }
369
+ else if (!globalOpts.quiet) {
370
+ console.log();
371
+ console.log(chalk.magenta.bold("📉 Price Impact"));
372
+ console.log();
373
+ const impact = parseFloat(result.priceImpact?.toString() || "0");
374
+ const impactColor = impact < 0.5
375
+ ? chalk.green
376
+ : impact < 1
377
+ ? chalk.yellow
378
+ : impact < 3
379
+ ? chalk.red
380
+ : chalk.red.bold;
381
+ printBox("Price Impact", {
382
+ "Price Impact": impactColor(`${impact.toFixed(2)}%`),
383
+ Amount: chalk.cyan(amount),
384
+ Side: chalk.cyan(side),
385
+ });
386
+ console.log();
387
+ }
388
+ process.exit(0);
389
+ }
390
+ catch (error) {
391
+ const globalOpts = command.parent?.parent?.opts() || {};
392
+ if (globalOpts.json) {
393
+ outputError("market_price_impact", error, getExitCode(error));
394
+ }
395
+ else {
396
+ handleError(error, globalOpts.verbose);
397
+ }
398
+ process.exit(getExitCode(error));
399
+ }
400
+ });
401
+ marketCommand
402
+ .command("holders-top")
403
+ .description("Get top token holders ($0.01)")
404
+ .argument("<tokenIdentifier>", "Token identifier")
405
+ .option("--limit <limit>", "Limit results", "10")
406
+ .action(async (tokenIdentifier, options, command) => {
407
+ try {
408
+ const globalOpts = command.parent?.parent?.opts() || {};
409
+ const accountIndex = globalOpts.account;
410
+ await ensureWalletUnlocked();
411
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
412
+ if (!isConfigured(globalOpts.privateKey)) {
413
+ if (globalOpts.json) {
414
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
415
+ process.exit(2);
416
+ }
417
+ privateKey = await promptForPrivateKey();
418
+ }
419
+ const client = await HttpcatClient.create(privateKey);
420
+ const params = new URLSearchParams({
421
+ tokenIdentifier,
422
+ limit: options.limit || "10",
423
+ });
424
+ const result = await withLoading(async () => {
425
+ try {
426
+ const data = await client.get(`/token/holders/top?${params.toString()}`);
427
+ return data.output || data;
428
+ }
429
+ catch {
430
+ const { data } = await client.invoke("token/holders/top", {
431
+ tokenIdentifier,
432
+ limit: parseInt(options.limit || "10"),
433
+ });
434
+ return data;
435
+ }
436
+ }, {
437
+ message: "Fetching top holders...",
438
+ json: globalOpts.json,
439
+ quiet: globalOpts.quiet,
440
+ spinner: "cat",
441
+ clearOnSuccess: true,
442
+ });
443
+ if (globalOpts.json) {
444
+ outputJson("market_holders_top", result);
445
+ }
446
+ else if (!globalOpts.quiet) {
447
+ console.log();
448
+ console.log(chalk.magenta.bold(`👥 Top Holders (${result.holders?.length || 0})`));
449
+ console.log();
450
+ if (result.holders && result.holders.length > 0) {
451
+ const table = createTable({
452
+ head: ["Rank", "Address", "Balance", "Percentage"],
453
+ colWidths: [8, 20, 20, 15],
454
+ });
455
+ for (const holder of result.holders) {
456
+ table.push([
457
+ holder.rank?.toString() || "N/A",
458
+ formatAddress(holder.address, 12),
459
+ formatTokenAmount(holder.balance),
460
+ `${parseFloat(holder.percentage?.toString() || "0").toFixed(2)}%`,
461
+ ]);
462
+ }
463
+ console.log(table.toString());
464
+ }
465
+ console.log();
466
+ }
467
+ process.exit(0);
468
+ }
469
+ catch (error) {
470
+ const globalOpts = command.parent?.parent?.opts() || {};
471
+ if (globalOpts.json) {
472
+ outputError("market_holders_top", error, getExitCode(error));
473
+ }
474
+ else {
475
+ handleError(error, globalOpts.verbose);
476
+ }
477
+ process.exit(getExitCode(error));
478
+ }
479
+ });
480
+ marketCommand
481
+ .command("distribution")
482
+ .description("Get token distribution ($0.01)")
483
+ .argument("<tokenIdentifier>", "Token identifier")
484
+ .action(async (tokenIdentifier, options, command) => {
485
+ try {
486
+ const globalOpts = command.parent?.parent?.opts() || {};
487
+ const accountIndex = globalOpts.account;
488
+ await ensureWalletUnlocked();
489
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
490
+ if (!isConfigured(globalOpts.privateKey)) {
491
+ if (globalOpts.json) {
492
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
493
+ process.exit(2);
494
+ }
495
+ privateKey = await promptForPrivateKey();
496
+ }
497
+ const client = await HttpcatClient.create(privateKey);
498
+ const params = new URLSearchParams({ tokenIdentifier });
499
+ const result = await withLoading(async () => {
500
+ try {
501
+ const data = await client.get(`/token/distribution?${params.toString()}`);
502
+ return data.output || data;
503
+ }
504
+ catch {
505
+ const { data } = await client.invoke("token/distribution", {
506
+ tokenIdentifier,
507
+ });
508
+ return data;
509
+ }
510
+ }, {
511
+ message: "Fetching distribution...",
512
+ json: globalOpts.json,
513
+ quiet: globalOpts.quiet,
514
+ spinner: "cat",
515
+ clearOnSuccess: true,
516
+ });
517
+ if (globalOpts.json) {
518
+ outputJson("market_distribution", result);
519
+ }
520
+ else if (!globalOpts.quiet) {
521
+ console.log();
522
+ console.log(chalk.magenta.bold("📊 Token Distribution"));
523
+ console.log();
524
+ console.log(JSON.stringify(result, null, 2));
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("market_distribution", error, getExitCode(error));
533
+ }
534
+ else {
535
+ handleError(error, globalOpts.verbose);
536
+ }
537
+ process.exit(getExitCode(error));
538
+ }
539
+ });
540
+ marketCommand
541
+ .command("supply")
542
+ .description("Get token supply information ($0.001)")
543
+ .argument("<tokenIdentifier>", "Token identifier")
544
+ .action(async (tokenIdentifier, options, command) => {
545
+ try {
546
+ const globalOpts = command.parent?.parent?.opts() || {};
547
+ const accountIndex = globalOpts.account;
548
+ await ensureWalletUnlocked();
549
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
550
+ if (!isConfigured(globalOpts.privateKey)) {
551
+ if (globalOpts.json) {
552
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
553
+ process.exit(2);
554
+ }
555
+ privateKey = await promptForPrivateKey();
556
+ }
557
+ const client = await HttpcatClient.create(privateKey);
558
+ const params = new URLSearchParams({ tokenIdentifier });
559
+ const result = await withLoading(async () => {
560
+ try {
561
+ const data = await client.get(`/token/supply?${params.toString()}`);
562
+ return data.output || data;
563
+ }
564
+ catch {
565
+ const { data } = await client.invoke("token/supply", {
566
+ tokenIdentifier,
567
+ });
568
+ return data;
569
+ }
570
+ }, {
571
+ message: "Fetching supply info...",
572
+ json: globalOpts.json,
573
+ quiet: globalOpts.quiet,
574
+ spinner: "cat",
575
+ clearOnSuccess: true,
576
+ });
577
+ if (globalOpts.json) {
578
+ outputJson("market_supply", result);
579
+ }
580
+ else if (!globalOpts.quiet) {
581
+ console.log();
582
+ console.log(chalk.magenta.bold("📈 Token Supply"));
583
+ console.log();
584
+ printBox("Supply Information", {
585
+ "Total Supply": chalk.green(formatTokenAmount(result.totalSupply || "0")),
586
+ "Circulating Supply": chalk.cyan(formatTokenAmount(result.circulatingSupply || "0")),
587
+ "Max Supply": result.maxSupply
588
+ ? chalk.yellow(formatTokenAmount(result.maxSupply))
589
+ : chalk.dim("Unlimited"),
590
+ });
591
+ console.log();
592
+ }
593
+ process.exit(0);
594
+ }
595
+ catch (error) {
596
+ const globalOpts = command.parent?.parent?.opts() || {};
597
+ if (globalOpts.json) {
598
+ outputError("market_supply", error, getExitCode(error));
599
+ }
600
+ else {
601
+ handleError(error, globalOpts.verbose);
602
+ }
603
+ process.exit(getExitCode(error));
604
+ }
605
+ });
606
+ marketCommand
607
+ .command("unlocks")
608
+ .description("Get token unlock schedule ($0.01)")
609
+ .argument("<tokenIdentifier>", "Token identifier")
610
+ .action(async (tokenIdentifier, options, command) => {
611
+ try {
612
+ const globalOpts = command.parent?.parent?.opts() || {};
613
+ const accountIndex = globalOpts.account;
614
+ await ensureWalletUnlocked();
615
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
616
+ if (!isConfigured(globalOpts.privateKey)) {
617
+ if (globalOpts.json) {
618
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
619
+ process.exit(2);
620
+ }
621
+ privateKey = await promptForPrivateKey();
622
+ }
623
+ const client = await HttpcatClient.create(privateKey);
624
+ const params = new URLSearchParams({ tokenIdentifier });
625
+ const result = await withLoading(async () => {
626
+ try {
627
+ const data = await client.get(`/token/unlocks?${params.toString()}`);
628
+ return data.output || data;
629
+ }
630
+ catch {
631
+ const { data } = await client.invoke("token/unlocks", {
632
+ tokenIdentifier,
633
+ });
634
+ return data;
635
+ }
636
+ }, {
637
+ message: "Fetching unlock schedule...",
638
+ json: globalOpts.json,
639
+ quiet: globalOpts.quiet,
640
+ spinner: "cat",
641
+ clearOnSuccess: true,
642
+ });
643
+ if (globalOpts.json) {
644
+ outputJson("market_unlocks", result);
645
+ }
646
+ else if (!globalOpts.quiet) {
647
+ console.log();
648
+ console.log(chalk.magenta.bold(`🔓 Token Unlocks (${result.unlocks?.length || 0})`));
649
+ console.log();
650
+ if (result.unlocks && result.unlocks.length > 0) {
651
+ const table = createTable({
652
+ head: ["Date", "Amount", "Percentage"],
653
+ colWidths: [25, 20, 15],
654
+ });
655
+ for (const unlock of result.unlocks) {
656
+ table.push([
657
+ new Date(unlock.date).toLocaleString(),
658
+ formatTokenAmount(unlock.amount),
659
+ `${parseFloat(unlock.percentage?.toString() || "0").toFixed(2)}%`,
660
+ ]);
661
+ }
662
+ console.log(table.toString());
663
+ }
664
+ console.log();
665
+ }
666
+ process.exit(0);
667
+ }
668
+ catch (error) {
669
+ const globalOpts = command.parent?.parent?.opts() || {};
670
+ if (globalOpts.json) {
671
+ outputError("market_unlocks", error, getExitCode(error));
672
+ }
673
+ else {
674
+ handleError(error, globalOpts.verbose);
675
+ }
676
+ process.exit(getExitCode(error));
677
+ }
678
+ });
679
+ // ============================================================================
680
+ // CoinGecko Commands
681
+ // ============================================================================
682
+ marketCommand
683
+ .command("search")
684
+ .description("Search cryptocurrencies (FREE)")
685
+ .argument("<query>", "Search term (name or symbol)")
686
+ .option("--limit <limit>", "Maximum results", "20")
687
+ .action(async (query, options, command) => {
688
+ try {
689
+ const globalOpts = command.parent?.parent?.opts() || {};
690
+ const accountIndex = globalOpts.account;
691
+ await ensureWalletUnlocked();
692
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
693
+ if (!isConfigured(globalOpts.privateKey)) {
694
+ if (globalOpts.json) {
695
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
696
+ process.exit(2);
697
+ }
698
+ privateKey = await promptForPrivateKey();
699
+ }
700
+ const client = await HttpcatClient.create(privateKey);
701
+ const limit = Math.min(parseInt(options.limit || "20"), 100);
702
+ const result = await withLoading(async () => {
703
+ const { data } = await client.invoke("market/search", {
704
+ query,
705
+ limit,
706
+ });
707
+ return data;
708
+ }, {
709
+ message: "Searching cryptocurrencies...",
710
+ json: globalOpts.json,
711
+ quiet: globalOpts.quiet,
712
+ spinner: "cat",
713
+ clearOnSuccess: true,
714
+ });
715
+ if (globalOpts.json) {
716
+ outputJson("market_search", {
717
+ command: "market_search",
718
+ data: result,
719
+ });
720
+ }
721
+ else if (!globalOpts.quiet) {
722
+ console.log();
723
+ console.log(chalk.magenta.bold(`🔍 Market Search Results (${result.coins?.length || 0} found)`));
724
+ console.log();
725
+ if (result.coins && result.coins.length > 0) {
726
+ const table = createTable({
727
+ head: ["Coin ID", "Symbol", "Name"],
728
+ colWidths: [20, 12, 30],
729
+ });
730
+ for (const coin of result.coins) {
731
+ table.push([
732
+ chalk.cyan(coin.id || ""),
733
+ chalk.yellow(coin.symbol?.toUpperCase() || ""),
734
+ coin.name || "",
735
+ ]);
736
+ }
737
+ console.log(table.toString());
738
+ console.log();
739
+ console.log(chalk.dim(`Total: ${result.total || result.coins.length} results`));
740
+ }
741
+ else {
742
+ console.log(chalk.dim("No results found."));
743
+ }
744
+ console.log();
745
+ }
746
+ process.exit(0);
747
+ }
748
+ catch (error) {
749
+ const globalOpts = command.parent?.parent?.opts() || {};
750
+ if (globalOpts.json) {
751
+ outputError("market_search", error, getExitCode(error));
752
+ }
753
+ else {
754
+ handleError(error, globalOpts.verbose);
755
+ }
756
+ process.exit(getExitCode(error));
757
+ }
758
+ });
759
+ marketCommand
760
+ .command("coin-data")
761
+ .description("Get comprehensive coin market data ($0.001)")
762
+ .argument("<coinId>", "CoinGecko coin ID (e.g., 'bitcoin')")
763
+ .option("--currency <currency>", "Currency (usd, eur, btc)", "usd")
764
+ .option("--sparkline", "Include 7-day sparkline")
765
+ .action(async (coinId, options, command) => {
766
+ try {
767
+ const globalOpts = command.parent?.parent?.opts() || {};
768
+ const accountIndex = globalOpts.account;
769
+ await ensureWalletUnlocked();
770
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
771
+ if (!isConfigured(globalOpts.privateKey)) {
772
+ if (globalOpts.json) {
773
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
774
+ process.exit(2);
775
+ }
776
+ privateKey = await promptForPrivateKey();
777
+ }
778
+ const client = await HttpcatClient.create(privateKey);
779
+ const result = await withLoading(async () => {
780
+ const { data } = await client.invoke("market/coin-data", {
781
+ coinId,
782
+ currency: options.currency || "usd",
783
+ sparkline: options.sparkline || false,
784
+ });
785
+ return data;
786
+ }, {
787
+ message: "Fetching coin data ($0.001)...",
788
+ json: globalOpts.json,
789
+ quiet: globalOpts.quiet,
790
+ spinner: "cat",
791
+ clearOnSuccess: true,
792
+ });
793
+ if (globalOpts.json) {
794
+ outputJson("market_coin_data", {
795
+ command: "market_coin_data",
796
+ data: result,
797
+ });
798
+ }
799
+ else if (!globalOpts.quiet) {
800
+ console.log();
801
+ const symbol = result.symbol?.toUpperCase() || "";
802
+ const name = result.name || coinId;
803
+ console.log(chalk.magenta.bold(`💰 Coin Data: ${name} (${symbol})`));
804
+ console.log();
805
+ const currency = (options.currency || "usd").toUpperCase();
806
+ const priceKey = `currentPrice`; // API returns currentPrice
807
+ const price = result[priceKey] || result.price || 0;
808
+ const priceChange24h = result.priceChange24h || result.priceChangePercentage24h || 0;
809
+ const changeColor = priceChange24h >= 0 ? chalk.green : chalk.red;
810
+ const changeEmoji = priceChange24h >= 0 ? "🟢" : "🔴";
811
+ const boxData = {
812
+ Price: chalk.green.bold(formatCurrency(price)),
813
+ "24h Change": changeColor(`${priceChange24h >= 0 ? "+" : ""}${priceChange24h.toFixed(2)}% ${changeEmoji}`),
814
+ };
815
+ if (result.marketCap) {
816
+ boxData["Market Cap"] = formatCurrency(result.marketCap);
817
+ }
818
+ if (result.marketCapRank) {
819
+ boxData["Market Cap Rank"] = `#${result.marketCapRank}`;
820
+ }
821
+ if (result.totalVolume) {
822
+ boxData["Volume 24h"] = formatCurrency(result.totalVolume);
823
+ }
824
+ if (result.high24h) {
825
+ boxData["High 24h"] = formatCurrency(result.high24h);
826
+ }
827
+ if (result.low24h) {
828
+ boxData["Low 24h"] = formatCurrency(result.low24h);
829
+ }
830
+ if (result.circulatingSupply) {
831
+ boxData["Circulating Supply"] = formatTokenAmount(result.circulatingSupply.toString());
832
+ }
833
+ if (result.totalSupply) {
834
+ boxData["Total Supply"] = formatTokenAmount(result.totalSupply.toString());
835
+ }
836
+ if (result.ath) {
837
+ const athChange = result.athChangePercentage || 0;
838
+ boxData["ATH"] = `${formatCurrency(result.ath)} (${athChange.toFixed(1)}%)`;
839
+ }
840
+ if (result.atl) {
841
+ const atlChange = result.atlChangePercentage || 0;
842
+ boxData["ATL"] = `${formatCurrency(result.atl)} (+${atlChange.toFixed(1)}%)`;
843
+ }
844
+ printBox("Coin Data", boxData);
845
+ console.log();
846
+ }
847
+ process.exit(0);
848
+ }
849
+ catch (error) {
850
+ const globalOpts = command.parent?.parent?.opts() || {};
851
+ if (globalOpts.json) {
852
+ outputError("market_coin_data", error, getExitCode(error));
853
+ }
854
+ else {
855
+ handleError(error, globalOpts.verbose);
856
+ }
857
+ process.exit(getExitCode(error));
858
+ }
859
+ });
860
+ marketCommand
861
+ .command("chart")
862
+ .description("Get historical price chart data ($0.01)")
863
+ .argument("<coinId>", "CoinGecko coin ID")
864
+ .argument("<days>", "Timeframe: 1, 7, 14, 30, 90, 180, 365, or max")
865
+ .option("--currency <currency>", "Currency", "usd")
866
+ .option("--interval <interval>", "Interval: daily or hourly")
867
+ .action(async (coinId, days, options, command) => {
868
+ try {
869
+ const globalOpts = command.parent?.parent?.opts() || {};
870
+ const accountIndex = globalOpts.account;
871
+ await ensureWalletUnlocked();
872
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
873
+ if (!isConfigured(globalOpts.privateKey)) {
874
+ if (globalOpts.json) {
875
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
876
+ process.exit(2);
877
+ }
878
+ privateKey = await promptForPrivateKey();
879
+ }
880
+ const client = await HttpcatClient.create(privateKey);
881
+ const result = await withLoading(async () => {
882
+ const { data } = await client.invoke("market/chart", {
883
+ coinId,
884
+ days,
885
+ currency: options.currency || "usd",
886
+ interval: options.interval,
887
+ });
888
+ return data;
889
+ }, {
890
+ message: "Fetching chart data ($0.01)...",
891
+ json: globalOpts.json,
892
+ quiet: globalOpts.quiet,
893
+ spinner: "cat",
894
+ clearOnSuccess: true,
895
+ });
896
+ if (globalOpts.json) {
897
+ outputJson("market_chart", {
898
+ command: "market_chart",
899
+ data: result,
900
+ });
901
+ }
902
+ else if (!globalOpts.quiet) {
903
+ console.log();
904
+ const currency = (options.currency || "usd").toUpperCase();
905
+ console.log(chalk.magenta.bold(`📊 Price Chart: ${coinId} (${days} days)`));
906
+ console.log();
907
+ const dataPoints = result.prices?.length || 0;
908
+ console.log(chalk.dim(`Data Points: ${dataPoints}`));
909
+ console.log(chalk.dim(`Currency: ${currency}`));
910
+ console.log();
911
+ if (result.prices && result.prices.length > 0) {
912
+ console.log(chalk.dim("Sample Data:"));
913
+ const table = createTable({
914
+ head: ["Timestamp", "Price", "Market Cap", "Volume"],
915
+ colWidths: [20, 15, 15, 15],
916
+ });
917
+ // Show first 5 and last 5 data points
918
+ const sampleSize = Math.min(10, result.prices.length);
919
+ const prices = result.prices.slice(0, sampleSize);
920
+ const marketCaps = result.marketCaps?.slice(0, sampleSize) || [];
921
+ const totalVolumes = result.totalVolumes?.slice(0, sampleSize) || [];
922
+ for (let i = 0; i < prices.length; i++) {
923
+ const [timestamp, price] = prices[i];
924
+ const marketCap = marketCaps[i]?.[1] || 0;
925
+ const volume = totalVolumes[i]?.[1] || 0;
926
+ table.push([
927
+ new Date(timestamp).toLocaleString(),
928
+ formatCurrency(price),
929
+ marketCap > 0 ? formatCurrency(marketCap) : "-",
930
+ volume > 0 ? formatCurrency(volume) : "-",
931
+ ]);
932
+ }
933
+ console.log(table.toString());
934
+ if (result.prices.length > sampleSize) {
935
+ console.log(chalk.dim(`... and ${result.prices.length - sampleSize} more data points`));
936
+ }
937
+ console.log();
938
+ console.log(chalk.dim("Use --json to get full data for charting"));
939
+ }
940
+ else {
941
+ console.log(chalk.dim("No chart data available."));
942
+ }
943
+ console.log();
944
+ }
945
+ process.exit(0);
946
+ }
947
+ catch (error) {
948
+ const globalOpts = command.parent?.parent?.opts() || {};
949
+ if (globalOpts.json) {
950
+ outputError("market_chart", error, getExitCode(error));
951
+ }
952
+ else {
953
+ handleError(error, globalOpts.verbose);
954
+ }
955
+ process.exit(getExitCode(error));
956
+ }
957
+ });
958
+ return marketCommand;
959
+ }
960
+ //# sourceMappingURL=market.js.map