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
@@ -1,12 +1,16 @@
1
- import inquirer from 'inquirer';
2
- import chalk from 'chalk';
3
- import { formatEther } from 'viem';
1
+ import inquirer from "inquirer";
2
+ import chalk from "chalk";
3
+ import { formatEther } from "viem";
4
4
  // USDC balance checking using viem directly
5
- import { config } from '../config.js';
6
- import { getNetworkConfig } from '../utils/constants.js';
7
- import { printCat } from '../interactive/art.js';
8
- import { formatAddress, printWarning } from '../utils/formatting.js';
9
- import { generateSeedPhrase, validateSeedPhrase, seedPhraseToPrivateKey, getAddressFromPrivateKey, } from './wallet.js';
5
+ import { config } from "../config.js";
6
+ import { getNetworkConfig } from "../utils/constants.js";
7
+ import { printCat } from "../interactive/art.js";
8
+ import { formatAddress, printWarning } from "../utils/formatting.js";
9
+ import { retryWithBackoff } from "./retry.js";
10
+ import { generateSeedPhrase, validateSeedPhrase, seedPhraseToPrivateKey, getAddressFromPrivateKey, } from "./wallet.js";
11
+ import { createMcpConfig } from "./mcp-config.js";
12
+ import { detectInstalledLlms } from "./llm-cli-detector.js";
13
+ import { configureLLM } from "./llm-cli-config.js";
10
14
  /**
11
15
  * Prompts the user to set up their wallet with three options:
12
16
  * 1. Generate new wallet (seed phrase)
@@ -19,47 +23,47 @@ import { generateSeedPhrase, validateSeedPhrase, seedPhraseToPrivateKey, getAddr
19
23
  export async function promptForPrivateKey() {
20
24
  console.log();
21
25
  // Show wizard cat
22
- printCat('wizard');
23
- console.log(chalk.bold.cyan('🔐 Let\'s set up your wallet...\n'));
26
+ printCat("wizard");
27
+ console.log(chalk.bold.cyan("🔐 Let's set up your wallet...\n"));
24
28
  // Security messaging - make it more playful and safe-feeling
25
- console.log(chalk.dim('🔒 Security & Privacy:'));
26
- console.log(chalk.dim(' • Your keys are stored locally on your machine only'));
27
- console.log(chalk.dim(' • They are never sent to any server or third party'));
28
- console.log(chalk.dim(' • They are only used locally to sign transactions'));
29
- console.log(chalk.dim(' • Stored in:'), chalk.cyan(config.getConfigPath()));
29
+ console.log(chalk.dim("🔒 Security & Privacy:"));
30
+ console.log(chalk.dim(" • Your keys are stored locally on your machine only"));
31
+ console.log(chalk.dim(" • They are never sent to any server or third party"));
32
+ console.log(chalk.dim(" • They are only used locally to sign transactions"));
33
+ console.log(chalk.dim(" • Stored in:"), chalk.cyan(config.getConfigPath()));
30
34
  console.log();
31
35
  // Ask user what they want to do - make "generate" the default
32
36
  const setupChoice = await inquirer.prompt([
33
37
  {
34
- type: 'list',
35
- name: 'option',
36
- message: 'How would you like to set up your wallet?',
38
+ type: "list",
39
+ name: "option",
40
+ message: "How would you like to set up your wallet?",
37
41
  choices: [
38
42
  {
39
- name: '✨ Generate new wallet (seed phrase) - Recommended for new users',
40
- value: 'generate',
43
+ name: "✨ Generate new wallet (seed phrase) - Recommended for new users",
44
+ value: "generate",
41
45
  },
42
46
  {
43
- name: '📥 Import existing seed phrase',
44
- value: 'import_seed',
47
+ name: "📥 Import existing seed phrase",
48
+ value: "import_seed",
45
49
  },
46
50
  {
47
- name: '🔑 Import existing private key',
48
- value: 'import_key',
51
+ name: "🔑 Import existing private key",
52
+ value: "import_key",
49
53
  },
50
54
  ],
51
- default: 'generate', // Make generate the default!
55
+ default: "generate", // Make generate the default!
52
56
  },
53
57
  ]);
54
58
  let seedPhrase;
55
59
  let privateKey;
56
60
  let accountIndex = 0;
57
- if (setupChoice.option === 'generate') {
61
+ if (setupChoice.option === "generate") {
58
62
  // Generate new seed phrase
59
63
  seedPhrase = await handleGenerateSeedPhrase();
60
64
  accountIndex = 1; // First seed-derived account
61
65
  }
62
- else if (setupChoice.option === 'import_seed') {
66
+ else if (setupChoice.option === "import_seed") {
63
67
  // Import existing seed phrase
64
68
  seedPhrase = await handleImportSeedPhrase();
65
69
  accountIndex = 1; // First seed-derived account
@@ -87,41 +91,41 @@ export async function promptForPrivateKey() {
87
91
  */
88
92
  export async function handleGenerateSeedPhrase() {
89
93
  console.log();
90
- console.log(chalk.bold.cyan('🌱 Generating new wallet for you...\n'));
94
+ console.log(chalk.bold.cyan("🌱 Generating new wallet for you...\n"));
91
95
  // Ask for word count
92
96
  const wordChoice = await inquirer.prompt([
93
97
  {
94
- type: 'list',
95
- name: 'wordCount',
96
- message: 'How many words?',
98
+ type: "list",
99
+ name: "wordCount",
100
+ message: "How many words?",
97
101
  choices: [
98
- { name: '12 words (recommended) 🎯', value: 12 },
99
- { name: '24 words (more secure) 🔒', value: 24 },
102
+ { name: "12 words (recommended) 🎯", value: 12 },
103
+ { name: "24 words (more secure) 🔒", value: 24 },
100
104
  ],
101
105
  default: 12,
102
106
  },
103
107
  ]);
104
108
  const seedPhrase = generateSeedPhrase(wordChoice.wordCount);
105
109
  console.log();
106
- console.log(chalk.bold.green('✨ Your new wallet is ready! ✨\n'));
107
- console.log(chalk.yellow('⚠️ IMPORTANT: Write down your seed phrase and keep it safe!'));
108
- console.log(chalk.yellow(' If you lose it, you will lose access to your wallet.\n'));
109
- console.log(chalk.bold('Your seed phrase:'));
110
+ console.log(chalk.bold.green("✨ Your new wallet is ready! ✨\n"));
111
+ console.log(chalk.yellow("⚠️ IMPORTANT: Write down your seed phrase and keep it safe!"));
112
+ console.log(chalk.yellow(" If you lose it, you will lose access to your wallet.\n"));
113
+ console.log(chalk.bold("Your seed phrase:"));
110
114
  console.log(chalk.cyan.bold(seedPhrase));
111
115
  console.log();
112
116
  // Confirm they saved it
113
117
  const confirmed = await inquirer.prompt([
114
118
  {
115
- type: 'confirm',
116
- name: 'saved',
117
- message: 'Have you written down your seed phrase?',
119
+ type: "confirm",
120
+ name: "saved",
121
+ message: "Have you written down your seed phrase?",
118
122
  default: false,
119
123
  },
120
124
  ]);
121
125
  if (!confirmed.saved) {
122
126
  console.log();
123
- console.log(chalk.yellow('🐱 The cat wants you to be safe! Please write it down first.'));
124
- throw new Error('You must save your seed phrase before continuing.');
127
+ console.log(chalk.yellow("🐱 The cat wants you to be safe! Please write it down first."));
128
+ throw new Error("You must save your seed phrase before continuing.");
125
129
  }
126
130
  return seedPhrase;
127
131
  }
@@ -130,23 +134,23 @@ export async function handleGenerateSeedPhrase() {
130
134
  */
131
135
  export async function handleImportSeedPhrase() {
132
136
  console.log();
133
- console.log(chalk.bold.cyan('📥 Importing seed phrase...\n'));
137
+ console.log(chalk.bold.cyan("📥 Importing seed phrase...\n"));
134
138
  const answers = await inquirer.prompt([
135
139
  {
136
- type: 'input',
137
- name: 'seedPhrase',
138
- message: 'Enter your seed phrase (12 or 24 words):',
140
+ type: "input",
141
+ name: "seedPhrase",
142
+ message: "Enter your seed phrase (12 or 24 words):",
139
143
  validate: (input) => {
140
144
  const trimmed = input.trim();
141
145
  if (!trimmed) {
142
- return 'Seed phrase is required';
146
+ return "Seed phrase is required";
143
147
  }
144
148
  const words = trimmed.split(/\s+/);
145
149
  if (words.length !== 12 && words.length !== 24) {
146
- return 'Seed phrase must be 12 or 24 words';
150
+ return "Seed phrase must be 12 or 24 words";
147
151
  }
148
152
  if (!validateSeedPhrase(trimmed)) {
149
- return 'Invalid seed phrase. Please check your words.';
153
+ return "Invalid seed phrase. Please check your words.";
150
154
  }
151
155
  return true;
152
156
  },
@@ -159,36 +163,46 @@ export async function handleImportSeedPhrase() {
159
163
  */
160
164
  async function handleImportPrivateKey() {
161
165
  console.log();
162
- console.log(chalk.bold.cyan('🔑 Importing private key...\n'));
166
+ console.log(chalk.bold.cyan("🔑 Importing private key...\n"));
163
167
  // Custom mask function: show first 5 chars, then dots
164
168
  const maskFunction = (input) => {
165
169
  if (!input || input.length === 0)
166
- return '';
170
+ return "";
167
171
  if (input.length <= 5)
168
172
  return input;
169
- return input.substring(0, 5) + ''.repeat(input.length - 5);
173
+ return input.substring(0, 5) + "".repeat(input.length - 5);
170
174
  };
171
175
  const answers = await inquirer.prompt([
172
176
  {
173
- type: 'password',
174
- name: 'privateKey',
175
- message: 'Enter your private key:',
177
+ type: "password",
178
+ name: "privateKey",
179
+ message: "Enter your private key:",
176
180
  mask: maskFunction,
177
181
  validate: (input) => {
178
182
  if (!input) {
179
- return 'Private key is required';
183
+ return "Private key is required";
180
184
  }
181
- if (!input.startsWith('0x')) {
182
- return 'Private key must start with 0x';
185
+ // Normalize: add 0x if missing for validation
186
+ const normalized = input.startsWith("0x") ? input : "0x" + input;
187
+ if (normalized.length !== 66) {
188
+ return "Private key must be 66 characters long (0x + 64 hex chars)";
183
189
  }
184
- if (input.length !== 66) {
185
- return 'Private key must be 66 characters long (0x + 64 hex chars)';
190
+ // Validate hex characters
191
+ const hexPattern = /^0x[0-9a-fA-F]{64}$/;
192
+ if (!hexPattern.test(normalized)) {
193
+ return "Private key must contain only hexadecimal characters (0-9, a-f, A-F)";
186
194
  }
187
195
  return true;
188
196
  },
189
197
  },
190
198
  ]);
191
- return answers.privateKey;
199
+ // Auto-prepend 0x if missing
200
+ let inputPrivateKey = answers.privateKey.trim();
201
+ if (!inputPrivateKey.startsWith("0x")) {
202
+ console.log(chalk.yellow("Adding 0x prefix..."));
203
+ inputPrivateKey = "0x" + inputPrivateKey;
204
+ }
205
+ return inputPrivateKey;
192
206
  }
193
207
  /**
194
208
  * Prompt if user wants to add more accounts after importing private key
@@ -197,9 +211,9 @@ async function promptForAccountCreation() {
197
211
  console.log();
198
212
  const answers = await inquirer.prompt([
199
213
  {
200
- type: 'confirm',
201
- name: 'addMore',
202
- message: 'Want to add more accounts? Generate seed phrase?',
214
+ type: "confirm",
215
+ name: "addMore",
216
+ message: "Want to add more accounts? Generate seed phrase?",
203
217
  default: false,
204
218
  },
205
219
  ]);
@@ -210,67 +224,78 @@ async function promptForAccountCreation() {
210
224
  */
211
225
  async function promptForPassword() {
212
226
  console.log();
213
- console.log(chalk.dim('🔐 Password Protection (optional):'));
214
- console.log(chalk.dim(' • Set a password to encrypt your wallet'));
215
- console.log(chalk.dim('Leave blank to skip password protection'));
216
- console.log(chalk.dim('You\'ll be prompted to unlock when needed\n'));
227
+ console.log(chalk.bold.cyan("🔐 Password Protection (Optional)"));
228
+ console.log();
229
+ console.log(chalk.dim("Password protection is optional"));
230
+ console.log(chalk.dim("Press Enter to skip password (your keys will still be encrypted)"));
231
+ console.log(chalk.dim(" • If you set a password, you'll need it to unlock your wallet"));
232
+ console.log(chalk.dim(" for transactions (session timeout: 15 minutes)\n"));
217
233
  const answers = await inquirer.prompt([
218
234
  {
219
- type: 'password',
220
- name: 'password',
221
- message: 'Enter password (or press Enter to skip):',
222
- mask: '',
235
+ type: "password",
236
+ name: "password",
237
+ message: "Enter password (optional - press Enter to skip):",
238
+ mask: "",
223
239
  },
224
240
  {
225
- type: 'password',
226
- name: 'confirmPassword',
227
- message: 'Confirm password (or press Enter to skip):',
228
- mask: '',
229
- when: (answers) => answers.password !== '',
241
+ type: "password",
242
+ name: "confirmPassword",
243
+ message: "Confirm password (or press Enter to skip):",
244
+ mask: "",
245
+ when: (answers) => answers.password !== "",
230
246
  },
231
247
  ]);
232
248
  if (answers.password) {
233
249
  if (answers.password !== answers.confirmPassword) {
234
- throw new Error('Passwords do not match');
250
+ throw new Error("Passwords do not match");
235
251
  }
236
252
  return answers.password;
237
253
  }
238
- return '';
254
+ return "";
239
255
  }
240
256
  /**
241
257
  * Save wallet configuration
242
258
  */
243
259
  async function saveWalletConfig(seedPhrase, privateKey, password, activeAccountIndex) {
244
260
  console.log();
245
- console.log(chalk.dim('💾 Saving configuration...\n'));
261
+ console.log(chalk.dim("💾 Saving configuration...\n"));
246
262
  // Set password
247
263
  config.setPassword(password);
248
- // Save seed phrase if provided
264
+ // Save private key first if provided (Account 0)
265
+ // This must be done before seed phrase to ensure Account 0 exists first
266
+ if (privateKey) {
267
+ config.setEncryptedPrivateKey(privateKey, password);
268
+ const account0Address = getAddressFromPrivateKey(privateKey);
269
+ const existingAccounts = config.getAllAccounts();
270
+ const account0Exists = existingAccounts.some((acc) => acc.index === 0);
271
+ if (!account0Exists) {
272
+ config.addAccount({
273
+ type: "custom",
274
+ index: 0,
275
+ address: account0Address,
276
+ });
277
+ }
278
+ console.log(chalk.green("✓ Private key saved"));
279
+ console.log(chalk.dim(` Account 0: ${formatAddress(account0Address, 12)}\n`));
280
+ }
281
+ // Save seed phrase if provided (Account 1)
249
282
  if (seedPhrase) {
250
283
  config.setEncryptedSeedPhrase(seedPhrase, password);
251
284
  // Create Account 1 (first seed-derived account)
252
285
  const account1PrivateKey = seedPhraseToPrivateKey(seedPhrase, 0);
253
286
  const account1Address = getAddressFromPrivateKey(account1PrivateKey);
254
- config.addAccount({
255
- type: 'seed',
256
- index: 1,
257
- address: account1Address,
258
- });
259
- console.log(chalk.green('✓ Seed phrase saved'));
287
+ const existingAccounts = config.getAllAccounts();
288
+ const account1Exists = existingAccounts.some((acc) => acc.index === 1);
289
+ if (!account1Exists) {
290
+ config.addAccount({
291
+ type: "seed",
292
+ index: 1,
293
+ address: account1Address,
294
+ });
295
+ }
296
+ console.log(chalk.green("✓ Seed phrase saved"));
260
297
  console.log(chalk.dim(` Account 1: ${formatAddress(account1Address, 12)}\n`));
261
298
  }
262
- // Save private key if provided (Account 0)
263
- if (privateKey) {
264
- config.setEncryptedPrivateKey(privateKey, password);
265
- const account0Address = getAddressFromPrivateKey(privateKey);
266
- config.addAccount({
267
- type: 'custom',
268
- index: 0,
269
- address: account0Address,
270
- });
271
- console.log(chalk.green('✓ Private key saved'));
272
- console.log(chalk.dim(` Account 0: ${formatAddress(account0Address, 12)}\n`));
273
- }
274
299
  // Set active account
275
300
  config.setActiveAccount(activeAccountIndex);
276
301
  // Show balances for active account
@@ -278,75 +303,229 @@ async function saveWalletConfig(seedPhrase, privateKey, password, activeAccountI
278
303
  if (activeAccount) {
279
304
  const activePrivateKey = config.getAccountPrivateKey(activeAccountIndex);
280
305
  await showAccountBalances(activeAccount.address, activePrivateKey);
306
+ console.log(chalk.dim(" Config saved to:"), chalk.cyan(config.getConfigPath()));
307
+ console.log(chalk.green("✓ Configuration saved!"));
308
+ console.log();
309
+ console.log(chalk.dim("🔐 Remember: Your keys stay on your machine."));
310
+ console.log(chalk.dim(" They are never transmitted to any server or third party.\n"));
311
+ // MCP Integration Step:
312
+ // After successfully saving the wallet configuration, we:
313
+ // 1. Create the base MCP config file (~/.config/httpcat/mcp.json)
314
+ // 2. Detect installed LLM CLI tools that support MCP
315
+ // 3. Prompt user to select which tools to configure
316
+ // 4. Configure selected tools with the private key
317
+ // Step 1: Create base MCP configuration file
318
+ // This file serves as a reference and can be used by MCP clients
319
+ // Note: No private key needed - MCP server reads from config file
320
+ try {
321
+ createMcpConfig();
322
+ console.log(chalk.green("✓ MCP configuration file created"));
323
+ }
324
+ catch (error) {
325
+ // Non-fatal error - continue with wizard even if MCP config creation fails
326
+ console.log(chalk.yellow("⚠️ Failed to create MCP config file"));
327
+ }
328
+ // Step 2 & 3: Detect and configure LLM CLI tools
329
+ // This will:
330
+ // - Scan for installed LLM CLI tools (Claude Desktop, Cursor, Codex, Gemini, etc.)
331
+ // - Show user a selection interface if tools are found
332
+ // - Configure selected tools with the httpcat MCP server
333
+ // Note: No private key needed - MCP server reads from config file
334
+ await promptForMcpIntegration();
335
+ }
336
+ }
337
+ /**
338
+ * Prompt for MCP integration with LLM CLI tools
339
+ *
340
+ * This function is called after wallet configuration is complete. It:
341
+ * 1. Detects installed LLM CLI tools that support MCP integration
342
+ * 2. Shows user a selection interface (checkbox) if tools are found
343
+ * 3. Configures each selected tool with the httpcat MCP server
344
+ * 4. Shows success/failure results for each configuration
345
+ *
346
+ * Flow:
347
+ * - If no LLM tools detected: Skip silently (no user interaction needed)
348
+ * - If tools detected: Show selection prompt
349
+ * - If user selects tools: Configure each one
350
+ * - Show results: Success (✓) or failure (✗) for each tool
351
+ *
352
+ * Error Handling:
353
+ * - All errors are caught and logged, but don't break the wizard
354
+ * - Individual tool failures don't stop other tools from being configured
355
+ * - If the entire step fails, it's skipped silently
356
+ *
357
+ * Note: No private key needed - MCP server reads from config file instead.
358
+ */
359
+ async function promptForMcpIntegration() {
360
+ try {
361
+ // Step 1: Detect installed LLM CLI tools
362
+ // Scans system for: Claude Desktop, Cursor, Codex, Gemini, LLM Tools, MCP-Use, MCP Client
363
+ const detectedLlms = await detectInstalledLlms();
364
+ // If no LLM tools found, skip this step silently
365
+ // User can manually configure later if needed
366
+ if (detectedLlms.length === 0) {
367
+ return;
368
+ }
369
+ // Step 2: Show user selection interface
370
+ console.log();
371
+ console.log(chalk.cyan("🔌 LLM CLI Integration"));
372
+ console.log(chalk.dim(` Found ${detectedLlms.length} LLM CLI tool(s) that support MCP integration.\n`));
373
+ // Present checkbox selection to user
374
+ // Each option shows: Tool name + config file path
375
+ const selection = await inquirer.prompt([
376
+ {
377
+ type: "checkbox",
378
+ name: "selectedLlms",
379
+ message: "Which LLM CLI tools would you like to configure with httpcat MCP?",
380
+ choices: detectedLlms.map((llm) => ({
381
+ name: `${llm.name} ${chalk.dim(`(${llm.configPath})`)}`,
382
+ value: llm.id,
383
+ })),
384
+ },
385
+ ]);
386
+ // If user selected nothing, skip configuration
387
+ if (!selection.selectedLlms || selection.selectedLlms.length === 0) {
388
+ console.log(chalk.dim(" Skipping LLM CLI integration.\n"));
389
+ return;
390
+ }
391
+ // Step 3: Configure selected LLM tools
392
+ console.log();
393
+ console.log(chalk.dim("⚙️ Configuring selected LLM CLI tools...\n"));
394
+ // Track results for each tool configuration
395
+ const results = [];
396
+ // Configure each selected tool
397
+ for (const llmId of selection.selectedLlms) {
398
+ const llm = detectedLlms.find((l) => l.id === llmId);
399
+ if (!llm)
400
+ continue; // Skip if LLM not found (shouldn't happen)
401
+ try {
402
+ // Call appropriate configuration function for this LLM tool
403
+ // Each function handles its own format (JSON, TOML, extension JSON, CLI commands)
404
+ // Note: No private key needed - MCP server reads from config file
405
+ const success = await configureLLM(llm);
406
+ results.push({
407
+ name: llm.name,
408
+ success,
409
+ });
410
+ }
411
+ catch (error) {
412
+ // Catch and log errors for individual tools
413
+ // Don't let one failure stop others from being configured
414
+ results.push({
415
+ name: llm.name,
416
+ success: false,
417
+ error: error?.message || "Unknown error",
418
+ });
419
+ }
420
+ }
421
+ // Step 4: Show configuration results
422
+ console.log();
423
+ for (const result of results) {
424
+ if (result.success) {
425
+ console.log(chalk.green(`✓ ${result.name} configured successfully`));
426
+ }
427
+ else {
428
+ console.log(chalk.red(`✗ ${result.name} configuration failed`));
429
+ if (result.error) {
430
+ console.log(chalk.dim(` Error: ${result.error}`));
431
+ }
432
+ }
433
+ }
434
+ console.log();
435
+ }
436
+ catch (error) {
437
+ // If entire step fails, skip silently
438
+ // Don't break the setup wizard for MCP integration issues
439
+ console.log(chalk.dim(" MCP integration step skipped.\n"));
281
440
  }
282
- console.log(chalk.dim(' Config saved to:'), chalk.cyan(config.getConfigPath()));
283
- console.log(chalk.green('✓ Configuration saved!'));
284
- console.log();
285
- console.log(chalk.dim('🔐 Remember: Your keys stay on your machine.'));
286
- console.log(chalk.dim(' They are never transmitted to any server or third party.\n'));
287
441
  }
288
442
  /**
289
443
  * Show account balances
290
444
  */
291
445
  async function showAccountBalances(address, privateKey) {
292
- console.log(chalk.dim('💰 Checking balances on Base Sepolia...\n'));
446
+ // Get network configuration
447
+ const network = config.get("network");
448
+ const networkDisplayName = config.caip2ToNetwork(network);
449
+ // Format network name for display (base-sepolia -> Base Sepolia, base -> Base)
450
+ const networkName = networkDisplayName === "base-sepolia"
451
+ ? "Base Sepolia"
452
+ : networkDisplayName === "base"
453
+ ? "Base"
454
+ : networkDisplayName;
455
+ console.log(chalk.dim(`💰 Checking balances on ${networkName}...\n`));
293
456
  try {
294
- // Get network configuration
295
- const network = config.get("network");
296
457
  const { chain, usdcAddress } = await getNetworkConfig(network);
297
458
  // Create signer using viem for balance checks
298
- const { createPublicClient, http, parseAbi, formatUnits } = await import("viem");
459
+ const { createPublicClient, parseAbi, formatUnits } = await import("viem");
460
+ const { createRpcTransport } = await import("./rpc-transport.js");
299
461
  const publicClient = createPublicClient({
300
462
  chain,
301
- transport: http(),
463
+ transport: createRpcTransport({
464
+ chainId: chain.id,
465
+ // HttpcatClient not available in this context, will use public/Alchemy RPC
466
+ }),
467
+ });
468
+ // Check ETH balance with retry logic for network failures
469
+ const ethBalance = await retryWithBackoff(() => publicClient.getBalance({
470
+ address: address,
471
+ }), {
472
+ maxRetries: 3,
473
+ initialDelay: 500,
474
+ maxDelay: 3000,
302
475
  });
303
- // Check ETH balance
304
- const ethBalance = await publicClient.getBalance({ address: address });
305
476
  const ethFormatted = formatEther(ethBalance);
306
- // Check USDC balance using ERC20 token contract
477
+ // Check USDC balance using ERC20 token contract with retry logic
307
478
  const ERC20_ABI = parseAbi([
308
479
  "function balanceOf(address owner) view returns (uint256)",
309
480
  "function decimals() view returns (uint8)",
310
481
  ]);
311
482
  const [usdcBalance, decimals] = await Promise.all([
312
- publicClient.readContract({
483
+ retryWithBackoff(() => publicClient.readContract({
313
484
  address: usdcAddress,
314
485
  abi: ERC20_ABI,
315
486
  functionName: "balanceOf",
316
487
  args: [address],
488
+ }), {
489
+ maxRetries: 3,
490
+ initialDelay: 500,
491
+ maxDelay: 3000,
317
492
  }).catch(() => BigInt(0)),
318
- publicClient.readContract({
493
+ retryWithBackoff(() => publicClient.readContract({
319
494
  address: usdcAddress,
320
495
  abi: ERC20_ABI,
321
496
  functionName: "decimals",
497
+ }), {
498
+ maxRetries: 3,
499
+ initialDelay: 500,
500
+ maxDelay: 3000,
322
501
  }).catch(() => 6), // Default to 6 decimals for USDC
323
502
  ]);
324
- const usdcFormatted = (Number(formatUnits(usdcBalance, decimals))).toFixed(2);
503
+ const usdcFormatted = Number(formatUnits(usdcBalance, decimals)).toFixed(2);
325
504
  // Display balances
326
- console.log(chalk.dim(' ETH: '), chalk.yellow(`${ethFormatted} ETH`));
327
- console.log(chalk.dim(' USDC:'), chalk.green(`$${usdcFormatted} USDC`));
505
+ console.log(chalk.dim(" ETH: "), chalk.yellow(`${ethFormatted} ETH`));
506
+ console.log(chalk.dim(" USDC:"), chalk.green(`$${usdcFormatted} USDC`));
328
507
  console.log();
329
508
  // Show warnings if balances are low
330
509
  const ethNum = Number(ethFormatted);
331
510
  const usdcNum = Number(usdcFormatted);
332
511
  if (ethNum < 0.001 && usdcNum < 1) {
333
- printWarning('Low balances detected!');
334
- console.log(chalk.dim(' You need Base Sepolia ETH for gas fees'));
335
- console.log(chalk.dim(' You need Base Sepolia USDC for trading\n'));
512
+ printWarning("Low balances detected!");
513
+ console.log(chalk.dim(` You need ${networkName} ETH for gas fees`));
514
+ console.log(chalk.dim(` You need ${networkName} USDC for trading\n`));
336
515
  }
337
516
  else if (ethNum < 0.001) {
338
- printWarning('Low ETH balance - you may not have enough for gas fees\n');
517
+ printWarning("Low ETH balance - you may not have enough for gas fees\n");
339
518
  }
340
519
  else if (usdcNum < 1) {
341
- printWarning('Low USDC balance - you may not have enough for trades\n');
520
+ printWarning("Low USDC balance - you may not have enough for trades\n");
342
521
  }
343
- console.log(chalk.yellow('⚠️ Important:'));
344
- console.log(chalk.dim(' Ensure you have Base Sepolia ETH (for gas fees)'));
345
- console.log(chalk.dim(' and Base Sepolia USDC (for trading) in this wallet!\n'));
522
+ console.log(chalk.yellow("⚠️ Important:"));
523
+ console.log(chalk.dim(` Ensure you have ${networkName} ETH (for gas fees)`));
524
+ console.log(chalk.dim(` and ${networkName} USDC (for trading) in this wallet!\n`));
346
525
  }
347
526
  catch (error) {
348
- console.log(chalk.yellow('⚠️ Could not check balances (network may be slow)'));
349
- console.log(chalk.dim(' Make sure you have Base Sepolia ETH and USDC!\n'));
527
+ console.log(chalk.yellow("⚠️ Could not check balances (network may be slow)"));
528
+ console.log(chalk.dim(` Make sure you have ${networkName} ETH and USDC!\n`));
350
529
  }
351
530
  }
352
531
  /**
@@ -356,9 +535,9 @@ export function formatEthBalance(wei) {
356
535
  const eth = formatEther(wei);
357
536
  const num = parseFloat(eth);
358
537
  if (num === 0)
359
- return '0 ETH';
538
+ return "0 ETH";
360
539
  if (num < 0.0001)
361
- return '< 0.0001 ETH';
540
+ return "< 0.0001 ETH";
362
541
  return `${num.toFixed(4)} ETH`;
363
542
  }
364
543
  /**