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,679 @@
1
+ import { Command } from "commander";
2
+ import { HttpcatClient } from "../client.js";
3
+ import { config } from "../config.js";
4
+ import { privateKeyToAccount } from "viem/accounts";
5
+ // Import command functions
6
+ import { checkBalance, displayBalance } from "./balances.js";
7
+ import { getPositions, displayPositions } from "./positions.js";
8
+ import { getTransactions, displayTransactions } from "./transactions.js";
9
+ // Import utilities
10
+ import { withLoading } from "../utils/loading.js";
11
+ import { outputJson, outputError } from "../headless/json-output.js";
12
+ import { handleError, getExitCode } from "../utils/errors.js";
13
+ import { promptForPrivateKey } from "../utils/privateKeyPrompt.js";
14
+ // ============================================================================
15
+ // Shared Utilities (duplicated from index.ts to avoid circular dependencies)
16
+ // ============================================================================
17
+ function getPrivateKey(cliPrivateKey, accountIndex) {
18
+ if (cliPrivateKey)
19
+ return cliPrivateKey;
20
+ const envKey = process.env.HTTPCAT_PRIVATE_KEY;
21
+ if (envKey)
22
+ return envKey;
23
+ // Use account system
24
+ try {
25
+ const index = accountIndex !== undefined
26
+ ? accountIndex
27
+ : config.getActiveAccountIndex();
28
+ return config.getAccountPrivateKey(index);
29
+ }
30
+ catch (error) {
31
+ // Fall back to legacy format if account system not set up
32
+ return config.get("privateKey");
33
+ }
34
+ }
35
+ function isConfigured(cliPrivateKey) {
36
+ if (cliPrivateKey)
37
+ return true;
38
+ return config.isConfigured();
39
+ }
40
+ async function ensureWalletUnlocked() {
41
+ const password = config.getPassword();
42
+ if (!password) {
43
+ // No password required - ensure session is initialized
44
+ config.ensureSessionValid();
45
+ return;
46
+ }
47
+ if (!config.isSessionValid()) {
48
+ // Need to prompt for password
49
+ const inquirer = (await import("inquirer")).default;
50
+ const answers = await inquirer.prompt([
51
+ {
52
+ type: "password",
53
+ name: "password",
54
+ message: "Enter password to unlock wallet:",
55
+ mask: "•",
56
+ },
57
+ ]);
58
+ await config.unlockSession(answers.password);
59
+ }
60
+ }
61
+ // ============================================================================
62
+ // Portfolio Command Group
63
+ // ============================================================================
64
+ export function createPortfolioCommand() {
65
+ const portfolioCommand = new Command("portfolio")
66
+ .description("Portfolio & history management")
67
+ .addHelpText("after", `
68
+ Examples:
69
+ httpcat portfolio balances
70
+ httpcat portfolio positions
71
+ httpcat portfolio transactions
72
+ `);
73
+ // Balances subcommand
74
+ portfolioCommand
75
+ .command("balances")
76
+ .alias("bal")
77
+ .description("Check wallet balances (FREE)")
78
+ .addHelpText("after", `
79
+ Examples:
80
+ httpcat portfolio balances
81
+ httpcat portfolio balances --json
82
+ `)
83
+ .action(async (options, command) => {
84
+ try {
85
+ const globalOpts = command.parent?.parent?.opts() || {};
86
+ const accountIndex = globalOpts.account;
87
+ await ensureWalletUnlocked();
88
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
89
+ if (!isConfigured(globalOpts.privateKey)) {
90
+ if (globalOpts.json) {
91
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
92
+ process.exit(2);
93
+ }
94
+ privateKey = await promptForPrivateKey();
95
+ }
96
+ const silent = globalOpts.json || globalOpts.quiet;
97
+ const result = await withLoading(() => checkBalance(privateKey, silent), {
98
+ message: "Fetching balances...",
99
+ json: globalOpts.json,
100
+ quiet: globalOpts.quiet,
101
+ spinner: "cat",
102
+ clearOnSuccess: true,
103
+ });
104
+ if (globalOpts.json) {
105
+ outputJson("balances", result);
106
+ }
107
+ else if (!globalOpts.quiet) {
108
+ displayBalance(result);
109
+ }
110
+ process.exit(0);
111
+ }
112
+ catch (error) {
113
+ const globalOpts = command.parent?.parent?.opts() || {};
114
+ if (globalOpts.json) {
115
+ outputError("balances", error, getExitCode(error));
116
+ }
117
+ else {
118
+ handleError(error, globalOpts.verbose);
119
+ }
120
+ process.exit(getExitCode(error));
121
+ }
122
+ });
123
+ // Positions subcommand
124
+ portfolioCommand
125
+ .command("positions")
126
+ .alias("pos")
127
+ .description("Get all positions across products (FREE)")
128
+ .option("--active", "Show only active (non-graduated) positions")
129
+ .option("--graduated", "Show only graduated positions")
130
+ .addHelpText("after", `
131
+ Examples:
132
+ httpcat portfolio positions
133
+ httpcat portfolio positions --active
134
+ httpcat portfolio positions --graduated
135
+ `)
136
+ .action(async (options, command) => {
137
+ try {
138
+ const globalOpts = command.parent?.parent?.opts() || {};
139
+ const accountIndex = globalOpts.account;
140
+ await ensureWalletUnlocked();
141
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
142
+ if (!isConfigured(globalOpts.privateKey)) {
143
+ if (globalOpts.json) {
144
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
145
+ process.exit(2);
146
+ }
147
+ privateKey = await promptForPrivateKey();
148
+ }
149
+ const client = await HttpcatClient.create(privateKey);
150
+ // Derive user address from private key
151
+ const account = privateKeyToAccount(privateKey);
152
+ const userAddress = account.address;
153
+ let result = await withLoading(() => getPositions(client, userAddress), {
154
+ message: "Fetching positions...",
155
+ json: globalOpts.json,
156
+ quiet: globalOpts.quiet,
157
+ spinner: "cat",
158
+ clearOnSuccess: true,
159
+ });
160
+ // Determine filter
161
+ const filter = options.active
162
+ ? "active"
163
+ : options.graduated
164
+ ? "graduated"
165
+ : "all";
166
+ // Filter results for JSON output
167
+ if (globalOpts.json && filter !== "all") {
168
+ const filteredPositions = result.positions.filter((p) => filter === "active"
169
+ ? p.token.status !== "graduated"
170
+ : p.token.status === "graduated");
171
+ result = {
172
+ ...result,
173
+ positions: filteredPositions,
174
+ total: filteredPositions.length,
175
+ };
176
+ outputJson("positions", result);
177
+ }
178
+ else if (globalOpts.json) {
179
+ outputJson("positions", result);
180
+ }
181
+ else if (!globalOpts.quiet) {
182
+ displayPositions(result, filter);
183
+ }
184
+ process.exit(0);
185
+ }
186
+ catch (error) {
187
+ const globalOpts = command.parent?.parent?.opts() || {};
188
+ if (globalOpts.json) {
189
+ outputError("positions", error, getExitCode(error));
190
+ }
191
+ else {
192
+ handleError(error, globalOpts.verbose);
193
+ }
194
+ process.exit(getExitCode(error));
195
+ }
196
+ });
197
+ // Summary subcommand
198
+ portfolioCommand
199
+ .command("summary")
200
+ .description("Get portfolio summary ($0.001)")
201
+ .option("--wallet <address>", "Wallet address (defaults to active account)")
202
+ .addHelpText("after", `
203
+ Examples:
204
+ httpcat portfolio summary
205
+ httpcat portfolio summary --wallet 0x...
206
+ httpcat portfolio summary --json
207
+ `)
208
+ .action(async (options, command) => {
209
+ try {
210
+ const globalOpts = command.parent?.parent?.opts() || {};
211
+ const accountIndex = globalOpts.account;
212
+ await ensureWalletUnlocked();
213
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
214
+ if (!isConfigured(globalOpts.privateKey)) {
215
+ if (globalOpts.json) {
216
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
217
+ process.exit(2);
218
+ }
219
+ privateKey = await promptForPrivateKey();
220
+ }
221
+ const client = await HttpcatClient.create(privateKey);
222
+ // Derive wallet address if not provided
223
+ let walletAddress = options.wallet;
224
+ if (!walletAddress) {
225
+ const account = privateKeyToAccount(privateKey);
226
+ walletAddress = account.address;
227
+ }
228
+ const result = await withLoading(async () => {
229
+ try {
230
+ const data = await client.get(`/portfolio/summary?wallet=${walletAddress}`);
231
+ return data.output || data;
232
+ }
233
+ catch {
234
+ const { data } = await client.invoke("portfolio/summary", {
235
+ wallet: walletAddress,
236
+ });
237
+ return data;
238
+ }
239
+ }, {
240
+ message: "Fetching portfolio summary...",
241
+ json: globalOpts.json,
242
+ quiet: globalOpts.quiet,
243
+ spinner: "cat",
244
+ clearOnSuccess: true,
245
+ });
246
+ if (globalOpts.json) {
247
+ outputJson("summary", result);
248
+ }
249
+ else if (!globalOpts.quiet) {
250
+ displayPortfolioSummary(result);
251
+ }
252
+ process.exit(0);
253
+ }
254
+ catch (error) {
255
+ const globalOpts = command.parent?.parent?.opts() || {};
256
+ if (globalOpts.json) {
257
+ outputError("summary", error, getExitCode(error));
258
+ }
259
+ else {
260
+ handleError(error, globalOpts.verbose);
261
+ }
262
+ process.exit(getExitCode(error));
263
+ }
264
+ });
265
+ // PnL subcommand
266
+ portfolioCommand
267
+ .command("pnl")
268
+ .description("Get portfolio P&L ($0.001)")
269
+ .option("--wallet <address>", "Wallet address (defaults to active account)")
270
+ .option("--timeframe <timeframe>", "Timeframe: 1d, 7d, 30d, all (default: all)")
271
+ .addHelpText("after", `
272
+ Examples:
273
+ httpcat portfolio pnl
274
+ httpcat portfolio pnl --timeframe 7d
275
+ httpcat portfolio pnl --wallet 0x... --json
276
+ `)
277
+ .action(async (options, command) => {
278
+ try {
279
+ const globalOpts = command.parent?.parent?.opts() || {};
280
+ const accountIndex = globalOpts.account;
281
+ await ensureWalletUnlocked();
282
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
283
+ if (!isConfigured(globalOpts.privateKey)) {
284
+ if (globalOpts.json) {
285
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
286
+ process.exit(2);
287
+ }
288
+ privateKey = await promptForPrivateKey();
289
+ }
290
+ const client = await HttpcatClient.create(privateKey);
291
+ // Derive wallet address if not provided
292
+ let walletAddress = options.wallet;
293
+ if (!walletAddress) {
294
+ const account = privateKeyToAccount(privateKey);
295
+ walletAddress = account.address;
296
+ }
297
+ const result = await withLoading(async () => {
298
+ const params = new URLSearchParams({
299
+ wallet: walletAddress,
300
+ });
301
+ if (options.timeframe) {
302
+ params.append("timeframe", options.timeframe);
303
+ }
304
+ try {
305
+ const data = await client.get(`/portfolio/pnl?${params.toString()}`);
306
+ return data.output || data;
307
+ }
308
+ catch {
309
+ const { data } = await client.invoke("portfolio/pnl", {
310
+ wallet: walletAddress,
311
+ timeframe: options.timeframe || "all",
312
+ });
313
+ return data;
314
+ }
315
+ }, {
316
+ message: "Fetching portfolio P&L...",
317
+ json: globalOpts.json,
318
+ quiet: globalOpts.quiet,
319
+ spinner: "cat",
320
+ clearOnSuccess: true,
321
+ });
322
+ if (globalOpts.json) {
323
+ outputJson("pnl", result);
324
+ }
325
+ else if (!globalOpts.quiet) {
326
+ displayPortfolioPnl(result);
327
+ }
328
+ process.exit(0);
329
+ }
330
+ catch (error) {
331
+ const globalOpts = command.parent?.parent?.opts() || {};
332
+ if (globalOpts.json) {
333
+ outputError("pnl", error, getExitCode(error));
334
+ }
335
+ else {
336
+ handleError(error, globalOpts.verbose);
337
+ }
338
+ process.exit(getExitCode(error));
339
+ }
340
+ });
341
+ // Trades subcommand
342
+ portfolioCommand
343
+ .command("trades")
344
+ .description("Get trade history ($0.001)")
345
+ .option("--wallet <address>", "Wallet address (defaults to active account)")
346
+ .option("--limit <number>", "Limit results (default: 50)", "50")
347
+ .option("--offset <number>", "Pagination offset (default: 0)", "0")
348
+ .addHelpText("after", `
349
+ Examples:
350
+ httpcat portfolio trades
351
+ httpcat portfolio trades --limit 100
352
+ httpcat portfolio trades --wallet 0x...
353
+ `)
354
+ .action(async (options, command) => {
355
+ try {
356
+ const globalOpts = command.parent?.parent?.opts() || {};
357
+ const accountIndex = globalOpts.account;
358
+ await ensureWalletUnlocked();
359
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
360
+ if (!isConfigured(globalOpts.privateKey)) {
361
+ if (globalOpts.json) {
362
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
363
+ process.exit(2);
364
+ }
365
+ privateKey = await promptForPrivateKey();
366
+ }
367
+ const client = await HttpcatClient.create(privateKey);
368
+ // Derive wallet address if not provided
369
+ let walletAddress = options.wallet;
370
+ if (!walletAddress) {
371
+ const account = privateKeyToAccount(privateKey);
372
+ walletAddress = account.address;
373
+ }
374
+ const result = await withLoading(async () => {
375
+ const params = new URLSearchParams({
376
+ wallet: walletAddress,
377
+ limit: options.limit || "50",
378
+ offset: options.offset || "0",
379
+ });
380
+ try {
381
+ const data = await client.get(`/history/trades?${params.toString()}`);
382
+ return data.output || data;
383
+ }
384
+ catch {
385
+ const { data } = await client.invoke("history/trades", {
386
+ wallet: walletAddress,
387
+ limit: parseInt(options.limit || "50"),
388
+ offset: parseInt(options.offset || "0"),
389
+ });
390
+ return data;
391
+ }
392
+ }, {
393
+ message: "Fetching trade history...",
394
+ json: globalOpts.json,
395
+ quiet: globalOpts.quiet,
396
+ spinner: "cat",
397
+ clearOnSuccess: true,
398
+ });
399
+ if (globalOpts.json) {
400
+ outputJson("trades", result);
401
+ }
402
+ else if (!globalOpts.quiet) {
403
+ displayTradeHistory(result);
404
+ }
405
+ process.exit(0);
406
+ }
407
+ catch (error) {
408
+ const globalOpts = command.parent?.parent?.opts() || {};
409
+ if (globalOpts.json) {
410
+ outputError("trades", error, getExitCode(error));
411
+ }
412
+ else {
413
+ handleError(error, globalOpts.verbose);
414
+ }
415
+ process.exit(getExitCode(error));
416
+ }
417
+ });
418
+ // Transactions subcommand
419
+ portfolioCommand
420
+ .command("transactions")
421
+ .alias("txs")
422
+ .description("Get transaction history ($0.001)")
423
+ .option("--wallet <address>", "Wallet address (defaults to active account)")
424
+ .option("--limit <number>", "Limit results (default: 50)", "50")
425
+ .option("--offset <number>", "Pagination offset (default: 0)", "0")
426
+ .addHelpText("after", `
427
+ Examples:
428
+ httpcat portfolio transactions
429
+ httpcat portfolio transactions --limit 100
430
+ httpcat portfolio transactions --wallet 0x...
431
+ `)
432
+ .action(async (options, command) => {
433
+ try {
434
+ const globalOpts = command.parent?.parent?.opts() || {};
435
+ const accountIndex = globalOpts.account;
436
+ await ensureWalletUnlocked();
437
+ let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
438
+ if (!isConfigured(globalOpts.privateKey)) {
439
+ if (globalOpts.json) {
440
+ console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
441
+ process.exit(2);
442
+ }
443
+ privateKey = await promptForPrivateKey();
444
+ }
445
+ const client = await HttpcatClient.create(privateKey);
446
+ // Derive wallet address if not provided
447
+ let walletAddress = options.wallet;
448
+ if (!walletAddress) {
449
+ const account = privateKeyToAccount(privateKey);
450
+ walletAddress = account.address;
451
+ }
452
+ const result = await withLoading(async () => {
453
+ // Try new endpoint first, fallback to old endpoint
454
+ const params = new URLSearchParams({
455
+ wallet: walletAddress,
456
+ limit: options.limit || "50",
457
+ offset: options.offset || "0",
458
+ });
459
+ try {
460
+ const data = await client.get(`/history/transactions?${params.toString()}`);
461
+ return data.output || data;
462
+ }
463
+ catch {
464
+ // Fallback to old endpoint for backward compatibility
465
+ try {
466
+ const { data } = await client.invoke("history/transactions", {
467
+ wallet: walletAddress,
468
+ limit: parseInt(options.limit || "50"),
469
+ offset: parseInt(options.offset || "0"),
470
+ });
471
+ return data;
472
+ }
473
+ catch {
474
+ // Final fallback to tokens/transactions
475
+ return await getTransactions(client, {
476
+ userAddress: walletAddress,
477
+ limit: parseInt(options.limit || "50"),
478
+ offset: parseInt(options.offset || "0"),
479
+ });
480
+ }
481
+ }
482
+ }, {
483
+ message: "Fetching transactions...",
484
+ json: globalOpts.json,
485
+ quiet: globalOpts.quiet,
486
+ spinner: "cat",
487
+ clearOnSuccess: true,
488
+ });
489
+ if (globalOpts.json) {
490
+ outputJson("transactions", result);
491
+ }
492
+ else if (!globalOpts.quiet) {
493
+ // Use appropriate display function based on response structure
494
+ if (result.transactions && Array.isArray(result.transactions)) {
495
+ if (result.transactions[0]?.txHash) {
496
+ // New format from /history/transactions
497
+ displayTransactionHistory(result);
498
+ }
499
+ else {
500
+ // Old format from /tokens/transactions
501
+ displayTransactions(result);
502
+ }
503
+ }
504
+ else {
505
+ displayTransactionHistory(result);
506
+ }
507
+ }
508
+ process.exit(0);
509
+ }
510
+ catch (error) {
511
+ const globalOpts = command.parent?.parent?.opts() || {};
512
+ if (globalOpts.json) {
513
+ outputError("transactions", error, getExitCode(error));
514
+ }
515
+ else {
516
+ handleError(error, globalOpts.verbose);
517
+ }
518
+ process.exit(getExitCode(error));
519
+ }
520
+ });
521
+ return portfolioCommand;
522
+ }
523
+ // Display functions for portfolio commands
524
+ function displayPortfolioSummary(summary) {
525
+ const chalk = require("chalk");
526
+ const { printBox, formatCurrency } = require("../utils/formatting.js");
527
+ console.log();
528
+ console.log(chalk.magenta.bold("📊 Portfolio Summary"));
529
+ console.log();
530
+ const boxData = {};
531
+ if (summary.wallet) {
532
+ boxData["Wallet"] = chalk.cyan(summary.wallet);
533
+ }
534
+ if (summary.totalValue !== undefined) {
535
+ boxData["Total Value"] = chalk.green.bold(formatCurrency(summary.totalValue));
536
+ }
537
+ if (summary.totalInvested !== undefined) {
538
+ boxData["Total Invested"] = chalk.cyan(formatCurrency(summary.totalInvested));
539
+ }
540
+ if (summary.totalPnl !== undefined) {
541
+ const pnlColor = parseFloat(summary.totalPnl) >= 0 ? chalk.green : chalk.red;
542
+ boxData["Total P&L"] = pnlColor(formatCurrency(summary.totalPnl));
543
+ }
544
+ if (summary.totalPnlPercentage !== undefined) {
545
+ const pnlPctColor = summary.totalPnlPercentage >= 0 ? chalk.green : chalk.red;
546
+ const sign = summary.totalPnlPercentage >= 0 ? "+" : "";
547
+ boxData["P&L %"] = pnlPctColor(`${sign}${summary.totalPnlPercentage.toFixed(2)}%`);
548
+ }
549
+ if (summary.positions !== undefined) {
550
+ boxData["Positions"] = chalk.cyan(summary.positions.toString());
551
+ }
552
+ if (summary.tokens !== undefined) {
553
+ boxData["Tokens"] = chalk.cyan(summary.tokens.toString());
554
+ }
555
+ printBox("Portfolio Summary", boxData);
556
+ console.log();
557
+ }
558
+ function displayPortfolioPnl(pnl) {
559
+ const chalk = require("chalk");
560
+ const { printBox, formatCurrency, createTable } = require("../utils/formatting.js");
561
+ console.log();
562
+ console.log(chalk.magenta.bold("💰 Portfolio P&L"));
563
+ console.log();
564
+ const boxData = {};
565
+ if (pnl.wallet) {
566
+ boxData["Wallet"] = chalk.cyan(pnl.wallet);
567
+ }
568
+ if (pnl.timeframe) {
569
+ boxData["Timeframe"] = chalk.cyan(pnl.timeframe.toUpperCase());
570
+ }
571
+ if (pnl.pnl !== undefined) {
572
+ const pnlColor = parseFloat(pnl.pnl) >= 0 ? chalk.green : chalk.red;
573
+ boxData["P&L"] = pnlColor(formatCurrency(pnl.pnl));
574
+ }
575
+ if (pnl.pnlPercentage !== undefined) {
576
+ const pnlPctColor = pnl.pnlPercentage >= 0 ? chalk.green : chalk.red;
577
+ const sign = pnl.pnlPercentage >= 0 ? "+" : "";
578
+ boxData["P&L %"] = pnlPctColor(`${sign}${pnl.pnlPercentage.toFixed(2)}%`);
579
+ }
580
+ printBox("Portfolio P&L", boxData);
581
+ if (pnl.breakdown && Array.isArray(pnl.breakdown) && pnl.breakdown.length > 0) {
582
+ console.log();
583
+ console.log(chalk.cyan.bold("Breakdown by Token:"));
584
+ console.log();
585
+ const table = createTable({
586
+ head: ["Token", "P&L", "P&L %"],
587
+ colWidths: [30, 20, 15],
588
+ });
589
+ for (const item of pnl.breakdown) {
590
+ const pnlColor = parseFloat(item.pnl) >= 0 ? chalk.green : chalk.red;
591
+ const pnlPctColor = item.pnlPercentage >= 0 ? chalk.green : chalk.red;
592
+ const sign = item.pnlPercentage >= 0 ? "+" : "";
593
+ table.push([
594
+ item.token || "N/A",
595
+ pnlColor(formatCurrency(item.pnl)),
596
+ pnlPctColor(`${sign}${item.pnlPercentage.toFixed(2)}%`),
597
+ ]);
598
+ }
599
+ console.log(table.toString());
600
+ }
601
+ console.log();
602
+ }
603
+ function displayTradeHistory(trades) {
604
+ const chalk = require("chalk");
605
+ const { formatAddress, formatCurrency, formatTokenAmount, createTable } = require("../utils/formatting.js");
606
+ console.log();
607
+ console.log(chalk.magenta.bold(`📈 Trade History (${trades.total || trades.trades?.length || 0} total)`));
608
+ console.log();
609
+ if (!trades.trades || trades.trades.length === 0) {
610
+ console.log(chalk.yellow("No trades found."));
611
+ console.log();
612
+ return;
613
+ }
614
+ const table = createTable({
615
+ head: ["Date", "Type", "Token In", "Token Out", "Amount In", "Amount Out", "TX"],
616
+ colWidths: [20, 10, 15, 15, 20, 20, 15],
617
+ });
618
+ for (const trade of trades.trades) {
619
+ const date = trade.timestamp
620
+ ? new Date(trade.timestamp).toLocaleString()
621
+ : "N/A";
622
+ const typeColor = trade.type === "buy"
623
+ ? chalk.green
624
+ : trade.type === "sell"
625
+ ? chalk.red
626
+ : chalk.cyan;
627
+ table.push([
628
+ chalk.dim(date),
629
+ typeColor(trade.type?.toUpperCase() || "N/A"),
630
+ trade.tokenIn ? formatAddress(trade.tokenIn, 8) : "N/A",
631
+ trade.tokenOut ? formatAddress(trade.tokenOut, 8) : "N/A",
632
+ trade.amountIn
633
+ ? formatTokenAmount(trade.amountIn)
634
+ : "N/A",
635
+ trade.amountOut
636
+ ? formatTokenAmount(trade.amountOut)
637
+ : "N/A",
638
+ trade.txHash ? formatAddress(trade.txHash, 8) : "N/A",
639
+ ]);
640
+ }
641
+ console.log(table.toString());
642
+ console.log();
643
+ }
644
+ function displayTransactionHistory(transactions) {
645
+ const chalk = require("chalk");
646
+ const { formatAddress, createTable } = require("../utils/formatting.js");
647
+ console.log();
648
+ console.log(chalk.magenta.bold(`📜 Transaction History (${transactions.total || transactions.transactions?.length || 0} total)`));
649
+ console.log();
650
+ if (!transactions.transactions || transactions.transactions.length === 0) {
651
+ console.log(chalk.yellow("No transactions found."));
652
+ console.log();
653
+ return;
654
+ }
655
+ const table = createTable({
656
+ head: ["Date", "Type", "Status", "Gas Used", "TX Hash"],
657
+ colWidths: [20, 15, 12, 15, 20],
658
+ });
659
+ for (const tx of transactions.transactions) {
660
+ const date = tx.timestamp
661
+ ? new Date(tx.timestamp).toLocaleString()
662
+ : "N/A";
663
+ const statusColor = tx.status === "success" || tx.status === "confirmed"
664
+ ? chalk.green
665
+ : tx.status === "pending"
666
+ ? chalk.yellow
667
+ : chalk.red;
668
+ table.push([
669
+ chalk.dim(date),
670
+ chalk.cyan(tx.type || "N/A"),
671
+ statusColor(tx.status?.toUpperCase() || "N/A"),
672
+ tx.gasUsed || "N/A",
673
+ tx.txHash ? formatAddress(tx.txHash, 10) : "N/A",
674
+ ]);
675
+ }
676
+ console.log(table.toString());
677
+ console.log();
678
+ }
679
+ //# sourceMappingURL=portfolio.js.map