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,963 @@
1
+ /**
2
+ * LLM CLI Configuration Writers
3
+ *
4
+ * This module provides configuration functions for each supported LLM CLI tool.
5
+ * Each function handles the specific configuration format and location for its tool.
6
+ *
7
+ * Configuration Strategy:
8
+ * 1. For tools with CLI commands (Codex, Gemini, MCP-Use): Try CLI command first, fall back to file
9
+ * 2. For file-only tools (Claude Desktop, Cursor): Direct file modification
10
+ * 3. All functions update existing MCP server configs if they already exist
11
+ * 4. Private key is always passed via HTTPCAT_PRIVATE_KEY environment variable
12
+ *
13
+ * Supported Configuration Formats:
14
+ * - JSON: Most tools (Claude Desktop, Cursor, LLM Tools, MCP Client)
15
+ * - TOML: Codex CLI (requires custom parser/stringifier)
16
+ * - Extension JSON: Gemini CLI (extension-based architecture)
17
+ *
18
+ * Error Handling:
19
+ * - All functions return boolean (true = success, false = failure)
20
+ * - Errors are logged but don't throw (graceful degradation)
21
+ * - Invalid config files are backed up and recreated
22
+ */
23
+ import fs from "fs";
24
+ import path from "path";
25
+ import { execSync } from "child_process";
26
+ /**
27
+ * Check if httpcat is globally installed
28
+ *
29
+ * Determines whether to use "httpcat" directly or "npx httpcat-cli".
30
+ * This affects the command and args in MCP server configurations.
31
+ *
32
+ * @returns true if httpcat command exists in PATH, false otherwise
33
+ */
34
+ function isHttpcatGlobal() {
35
+ try {
36
+ execSync("which httpcat", { stdio: "ignore" });
37
+ return true;
38
+ }
39
+ catch {
40
+ return false;
41
+ }
42
+ }
43
+ /**
44
+ * Get standardized MCP server configuration
45
+ *
46
+ * Creates a consistent MCP server config object that can be used across all LLM tools.
47
+ * The configuration includes:
48
+ * - command: "httpcat" (if global) or "npx" (if npm package)
49
+ * - args: Appropriate arguments for the installation method
50
+ * - Note: No HTTPCAT_PRIVATE_KEY in env - server reads from config file instead
51
+ *
52
+ * This ensures all tools use the same MCP server setup, just in different formats.
53
+ *
54
+ * @returns MCP server configuration object
55
+ */
56
+ function getMcpServerConfig() {
57
+ const isGlobal = isHttpcatGlobal();
58
+ return {
59
+ command: isGlobal ? "httpcat" : "npx",
60
+ args: isGlobal ? ["mcp", "start"] : ["-y", "httpcat-cli", "mcp", "start"],
61
+ // No env vars - private key is read from ~/.config/httpcat/config.json by MCP server
62
+ };
63
+ }
64
+ /**
65
+ * Configure Claude Desktop
66
+ *
67
+ * Claude Desktop is a desktop application (no CLI). Configuration is done via JSON file:
68
+ * - macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
69
+ * - Windows: %APPDATA%/Claude/claude_desktop_config.json
70
+ * - Linux: ~/.config/Claude/claude_desktop_config.json
71
+ *
72
+ * Configuration format: Standard MCP JSON format with mcpServers object.
73
+ * Note: Private key is NOT included - MCP server reads from config file instead.
74
+ *
75
+ * @param configPath - Full path to claude_desktop_config.json
76
+ * @returns true if configuration succeeded, false otherwise
77
+ */
78
+ export async function configureClaudeDesktop(configPath) {
79
+ try {
80
+ // Ensure config directory exists
81
+ const configDir = path.dirname(configPath);
82
+ fs.mkdirSync(configDir, { recursive: true });
83
+ // Read existing config or start with empty object
84
+ let config = {};
85
+ if (fs.existsSync(configPath)) {
86
+ const content = fs.readFileSync(configPath, "utf-8");
87
+ try {
88
+ config = JSON.parse(content);
89
+ }
90
+ catch {
91
+ // Invalid JSON - create new config (old one may be corrupted)
92
+ config = {};
93
+ }
94
+ }
95
+ // Ensure mcpServers object exists
96
+ if (!config.mcpServers) {
97
+ config.mcpServers = {};
98
+ }
99
+ // Add or update httpcat server configuration
100
+ config.mcpServers.httpcat = getMcpServerConfig();
101
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
102
+ return true;
103
+ }
104
+ catch (error) {
105
+ console.error(`Failed to configure Claude Desktop: ${error}`);
106
+ return false;
107
+ }
108
+ }
109
+ /**
110
+ * Configure Cursor IDE
111
+ *
112
+ * Cursor is a code editor with MCP support. Configuration can be:
113
+ * - Global: ~/.cursor/mcp.json (applies to all projects)
114
+ * - Workspace: .cursor/mcp.json (project-specific)
115
+ *
116
+ * The detector prioritizes global config, but this function works with either.
117
+ * Configuration format: Standard MCP JSON format.
118
+ * Note: Private key is NOT included - MCP server reads from config file instead.
119
+ *
120
+ * @param configPath - Full path to mcp.json (global or workspace)
121
+ * @returns true if configuration succeeded, false otherwise
122
+ */
123
+ export async function configureCursor(configPath) {
124
+ try {
125
+ // Ensure config directory exists
126
+ const configDir = path.dirname(configPath);
127
+ fs.mkdirSync(configDir, { recursive: true });
128
+ // Read existing config or start with empty object
129
+ let config = {};
130
+ if (fs.existsSync(configPath)) {
131
+ const content = fs.readFileSync(configPath, "utf-8");
132
+ try {
133
+ config = JSON.parse(content);
134
+ }
135
+ catch {
136
+ // Invalid JSON - create new config
137
+ config = {};
138
+ }
139
+ }
140
+ // Ensure mcpServers object exists
141
+ if (!config.mcpServers) {
142
+ config.mcpServers = {};
143
+ }
144
+ // Add or update httpcat server configuration
145
+ config.mcpServers.httpcat = getMcpServerConfig();
146
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
147
+ return true;
148
+ }
149
+ catch (error) {
150
+ console.error(`Failed to configure Cursor: ${error}`);
151
+ return false;
152
+ }
153
+ }
154
+ /**
155
+ * Configure LLM Tools MCP
156
+ *
157
+ * LLM Tools MCP is a plugin for Simon Willison's "llm" CLI tool.
158
+ * Requires: "llm" CLI installed AND "llm-tools-mcp" plugin installed.
159
+ *
160
+ * Configuration location: ~/.llm-tools-mcp/mcp.json
161
+ * Configuration format: Standard MCP JSON format.
162
+ * Note: Private key is NOT included - MCP server reads from config file instead.
163
+ *
164
+ * @param configPath - Full path to ~/.llm-tools-mcp/mcp.json
165
+ * @returns true if configuration succeeded, false otherwise
166
+ */
167
+ export async function configureLlmToolsMcp(configPath) {
168
+ try {
169
+ // Ensure config directory exists
170
+ const configDir = path.dirname(configPath);
171
+ fs.mkdirSync(configDir, { recursive: true });
172
+ // Read existing config or start with empty object
173
+ let config = {};
174
+ if (fs.existsSync(configPath)) {
175
+ const content = fs.readFileSync(configPath, "utf-8");
176
+ try {
177
+ config = JSON.parse(content);
178
+ }
179
+ catch {
180
+ // Invalid JSON - create new config
181
+ config = {};
182
+ }
183
+ }
184
+ // Ensure mcpServers object exists
185
+ if (!config.mcpServers) {
186
+ config.mcpServers = {};
187
+ }
188
+ // Add or update httpcat server configuration
189
+ config.mcpServers.httpcat = getMcpServerConfig();
190
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
191
+ return true;
192
+ }
193
+ catch (error) {
194
+ console.error(`Failed to configure LLM Tools MCP: ${error}`);
195
+ return false;
196
+ }
197
+ }
198
+ /**
199
+ * Configure MCP-Use CLI
200
+ *
201
+ * MCP-Use is a standalone MCP client CLI tool. It supports both:
202
+ * 1. CLI commands: "mcp-use server add" (preferred method)
203
+ * 2. File-based config: ~/.mcp-use/config.json (fallback)
204
+ *
205
+ * Strategy: Try CLI command first, fall back to file if CLI fails.
206
+ * This ensures we use the official CLI interface when available.
207
+ * Note: Private key is NOT included - MCP server reads from config file instead.
208
+ *
209
+ * @returns true if configuration succeeded, false otherwise
210
+ */
211
+ export async function configureMcpUse() {
212
+ try {
213
+ // Try CLI command first (preferred method)
214
+ const isGlobal = isHttpcatGlobal();
215
+ const command = isGlobal ? "httpcat" : "npx -y httpcat-cli";
216
+ const args = isGlobal ? "mcp start" : "mcp start";
217
+ try {
218
+ // Execute CLI command to add MCP server
219
+ execSync(`mcp-use server add httpcat --command "${command}" --args "${args}"`, { stdio: "ignore" });
220
+ return true;
221
+ }
222
+ catch {
223
+ // CLI command failed (tool may not support this command or not installed)
224
+ // Fall back to file-based configuration
225
+ const configPath = path.join(process.env.HOME || "", ".mcp-use", "config.json");
226
+ const configDir = path.dirname(configPath);
227
+ fs.mkdirSync(configDir, { recursive: true });
228
+ // Read existing config or start with empty object
229
+ let config = {};
230
+ if (fs.existsSync(configPath)) {
231
+ const content = fs.readFileSync(configPath, "utf-8");
232
+ try {
233
+ config = JSON.parse(content);
234
+ }
235
+ catch {
236
+ config = {};
237
+ }
238
+ }
239
+ // Ensure mcpServers object exists
240
+ if (!config.mcpServers) {
241
+ config.mcpServers = {};
242
+ }
243
+ // Add or update httpcat server configuration
244
+ config.mcpServers.httpcat = getMcpServerConfig();
245
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
246
+ return true;
247
+ }
248
+ }
249
+ catch (error) {
250
+ console.error(`Failed to configure MCP-Use: ${error}`);
251
+ return false;
252
+ }
253
+ }
254
+ /**
255
+ * Configure MCP Client CLI
256
+ *
257
+ * MCP Client CLI is another MCP client implementation.
258
+ * Configuration location: ~/.llm/config.json
259
+ * Configuration format: Standard MCP JSON format.
260
+ *
261
+ * Note: This shares the same config directory as other LLM tools,
262
+ * so we're careful to merge rather than overwrite.
263
+ * Note: Private key is NOT included - MCP server reads from config file instead.
264
+ *
265
+ * @param configPath - Full path to ~/.llm/config.json
266
+ * @returns true if configuration succeeded, false otherwise
267
+ */
268
+ export async function configureMcpClient(configPath) {
269
+ try {
270
+ // Ensure config directory exists
271
+ const configDir = path.dirname(configPath);
272
+ fs.mkdirSync(configDir, { recursive: true });
273
+ // Read existing config or start with empty object
274
+ let config = {};
275
+ if (fs.existsSync(configPath)) {
276
+ const content = fs.readFileSync(configPath, "utf-8");
277
+ try {
278
+ config = JSON.parse(content);
279
+ }
280
+ catch {
281
+ // Invalid JSON - create new config
282
+ config = {};
283
+ }
284
+ }
285
+ // Ensure mcpServers object exists
286
+ if (!config.mcpServers) {
287
+ config.mcpServers = {};
288
+ }
289
+ // Add or update httpcat server configuration
290
+ config.mcpServers.httpcat = getMcpServerConfig();
291
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
292
+ return true;
293
+ }
294
+ catch (error) {
295
+ console.error(`Failed to configure MCP Client: ${error}`);
296
+ return false;
297
+ }
298
+ }
299
+ /**
300
+ * Parse TOML file (simplified parser for Codex config)
301
+ *
302
+ * This is a simplified TOML parser that handles the subset of TOML syntax
303
+ * needed for Codex CLI configuration. It supports:
304
+ * - Section headers: [section.name]
305
+ * - String values: key = "value"
306
+ * - Arrays: key = ["value1", "value2"]
307
+ * - Inline tables: key = { k1 = "v1", k2 = "v2" }
308
+ * - Comments: Lines starting with #
309
+ *
310
+ * Note: This is NOT a full TOML parser. It's designed specifically for
311
+ * the Codex config format. For more complex TOML files, consider using
312
+ * a proper TOML library like @iarna/toml.
313
+ *
314
+ * @param content - TOML file content as string
315
+ * @returns Parsed TOML as JavaScript object
316
+ */
317
+ function parseToml(content) {
318
+ const result = {};
319
+ const lines = content.split("\n");
320
+ let currentSection = null;
321
+ for (const line of lines) {
322
+ const trimmed = line.trim();
323
+ // Skip empty lines and comments
324
+ if (!trimmed || trimmed.startsWith("#"))
325
+ continue;
326
+ // Parse section header: [section.name]
327
+ const sectionMatch = trimmed.match(/^\[([^\]]+)\]$/);
328
+ if (sectionMatch) {
329
+ currentSection = sectionMatch[1];
330
+ if (!result[currentSection]) {
331
+ result[currentSection] = {};
332
+ }
333
+ continue;
334
+ }
335
+ // Parse key = value pairs
336
+ const keyValueMatch = trimmed.match(/^([^=]+)\s*=\s*(.+)$/);
337
+ if (keyValueMatch && currentSection) {
338
+ const key = keyValueMatch[1].trim();
339
+ let value = keyValueMatch[2].trim();
340
+ // Remove quotes from string values
341
+ if ((value.startsWith('"') && value.endsWith('"')) ||
342
+ (value.startsWith("'") && value.endsWith("'"))) {
343
+ value = value.slice(1, -1);
344
+ }
345
+ // Parse arrays: ["value1", "value2"]
346
+ else if (value.startsWith("[") && value.endsWith("]")) {
347
+ value = value.slice(1, -1).split(",").map((v) => v.trim().replace(/^["']|["']$/g, ""));
348
+ }
349
+ // Parse inline tables: { key1 = "value1", key2 = "value2" }
350
+ else if (value.startsWith("{") && value.endsWith("}")) {
351
+ const tableContent = value.slice(1, -1);
352
+ value = {};
353
+ tableContent.split(",").forEach((pair) => {
354
+ const [k, v] = pair.split("=").map((s) => s.trim());
355
+ if (k && v) {
356
+ // Remove quotes from table values
357
+ value[k] = v.replace(/^["']|["']$/g, "");
358
+ }
359
+ });
360
+ }
361
+ result[currentSection][key] = value;
362
+ }
363
+ }
364
+ return result;
365
+ }
366
+ /**
367
+ * Stringify TOML (simplified stringifier for Codex config)
368
+ *
369
+ * Converts a JavaScript object back to TOML format. Handles:
370
+ * - Sections: [section.name]
371
+ * - Strings: key = "value"
372
+ * - Arrays: key = ["value1", "value2"]
373
+ * - Inline tables: key = { k1 = "v1", k2 = "v2" }
374
+ *
375
+ * This is the inverse of parseToml() and is designed for the Codex config format.
376
+ *
377
+ * @param obj - JavaScript object to convert to TOML
378
+ * @returns TOML-formatted string
379
+ */
380
+ function stringifyToml(obj) {
381
+ const lines = [];
382
+ for (const [section, content] of Object.entries(obj)) {
383
+ if (typeof content === "object" && content !== null) {
384
+ // Write section header
385
+ lines.push(`[${section}]`);
386
+ // Write key-value pairs in this section
387
+ for (const [key, value] of Object.entries(content)) {
388
+ if (typeof value === "string") {
389
+ // String value: key = "value"
390
+ lines.push(`${key} = "${value}"`);
391
+ }
392
+ else if (Array.isArray(value)) {
393
+ // Array value: key = ["value1", "value2"]
394
+ lines.push(`${key} = [${value.map((v) => `"${v}"`).join(", ")}]`);
395
+ }
396
+ else if (typeof value === "object" && value !== null) {
397
+ // Inline table: key = { k1 = "v1", k2 = "v2" }
398
+ // Used for nested objects like env = { HTTPCAT_PRIVATE_KEY = "0x..." }
399
+ const tableEntries = Object.entries(value)
400
+ .map(([k, v]) => `${k} = "${String(v)}"`)
401
+ .join(", ");
402
+ lines.push(`${key} = { ${tableEntries} }`);
403
+ }
404
+ }
405
+ // Add blank line after each section for readability
406
+ lines.push("");
407
+ }
408
+ }
409
+ return lines.join("\n");
410
+ }
411
+ /**
412
+ * Configure Codex CLI (OpenAI)
413
+ *
414
+ * Codex CLI supports both CLI commands and TOML file configuration:
415
+ * 1. CLI: "codex mcp add httpcat -- npx -y httpcat-cli mcp start" (preferred)
416
+ * 2. File: ~/.codex/config.toml (fallback)
417
+ *
418
+ * Configuration format: TOML (not JSON like most other tools)
419
+ * Section format: [mcp_servers.httpcat] (uses underscores, not camelCase)
420
+ *
421
+ * Strategy: Try CLI command first, fall back to TOML file modification.
422
+ * Note: Private key is NOT included - MCP server reads from config file instead.
423
+ *
424
+ * @param configPath - Full path to ~/.codex/config.toml
425
+ * @returns true if configuration succeeded, false otherwise
426
+ */
427
+ export async function configureCodex(configPath) {
428
+ try {
429
+ // Try CLI command first (preferred method)
430
+ if (commandExists("codex")) {
431
+ try {
432
+ const isGlobal = isHttpcatGlobal();
433
+ const command = isGlobal ? "httpcat" : "npx";
434
+ const args = isGlobal ? "mcp start" : "-y httpcat-cli mcp start";
435
+ // Execute CLI command to add MCP server
436
+ execSync(`codex mcp add httpcat -- ${command} ${args}`, { stdio: "ignore" });
437
+ return true;
438
+ }
439
+ catch {
440
+ // CLI command failed - fall back to file-based configuration
441
+ }
442
+ }
443
+ // File-based configuration (TOML format)
444
+ const configDir = path.dirname(configPath);
445
+ fs.mkdirSync(configDir, { recursive: true });
446
+ // Read existing TOML config or start with empty object
447
+ let config = {};
448
+ if (fs.existsSync(configPath)) {
449
+ const content = fs.readFileSync(configPath, "utf-8");
450
+ try {
451
+ config = parseToml(content);
452
+ }
453
+ catch {
454
+ // Invalid TOML - create new config
455
+ config = {};
456
+ }
457
+ }
458
+ // Ensure mcp_servers section exists (Codex uses underscores, not camelCase)
459
+ if (!config.mcp_servers) {
460
+ config.mcp_servers = {};
461
+ }
462
+ // Add or update httpcat server configuration
463
+ const mcpConfig = getMcpServerConfig();
464
+ // Store in TOML format (mcp_servers.httpcat section)
465
+ config.mcp_servers.httpcat = {
466
+ command: mcpConfig.command,
467
+ args: mcpConfig.args,
468
+ // No env vars - private key is read from config file
469
+ };
470
+ // Write back as TOML
471
+ fs.writeFileSync(configPath, stringifyToml(config), "utf-8");
472
+ return true;
473
+ }
474
+ catch (error) {
475
+ console.error(`Failed to configure Codex: ${error}`);
476
+ return false;
477
+ }
478
+ }
479
+ /**
480
+ * Configure Gemini CLI (Google)
481
+ *
482
+ * Gemini CLI uses an extension-based architecture. It supports both:
483
+ * 1. CLI: "gemini mcp add httpcat --command ... --args ..." (preferred)
484
+ * 2. Extension file: ~/.gemini/extensions/httpcat/gemini-extension.json (fallback)
485
+ *
486
+ * Extension format: JSON file with name, version, and mcpServers object.
487
+ * This is different from standard MCP config - it's wrapped in an extension structure.
488
+ *
489
+ * Strategy: Try CLI command first, fall back to creating extension JSON file.
490
+ * Note: Private key is NOT included - MCP server reads from config file instead.
491
+ *
492
+ * @param extensionPath - Full path to extension JSON file
493
+ * @returns true if configuration succeeded, false otherwise
494
+ */
495
+ export async function configureGemini(extensionPath) {
496
+ try {
497
+ // Try CLI command first (preferred method)
498
+ if (commandExists("gemini")) {
499
+ try {
500
+ const isGlobal = isHttpcatGlobal();
501
+ const command = isGlobal ? "httpcat" : "npx";
502
+ const args = isGlobal ? "mcp start" : "-y httpcat-cli mcp start";
503
+ // Execute CLI command to add MCP server
504
+ execSync(`gemini mcp add httpcat --command "${command}" --args "${args}"`, { stdio: "ignore" });
505
+ return true;
506
+ }
507
+ catch {
508
+ // CLI command failed - fall back to file-based configuration
509
+ }
510
+ }
511
+ // File-based configuration (extension JSON format)
512
+ // Ensure extension directory exists
513
+ const extensionDir = path.dirname(extensionPath);
514
+ fs.mkdirSync(extensionDir, { recursive: true });
515
+ // Build extension config structure (Gemini-specific format)
516
+ const mcpConfig = getMcpServerConfig();
517
+ const extensionConfig = {
518
+ name: "httpcat",
519
+ version: "1.0.0",
520
+ mcpServers: {
521
+ httpcat: mcpConfig,
522
+ },
523
+ };
524
+ // Add or update extension file
525
+ fs.writeFileSync(extensionPath, JSON.stringify(extensionConfig, null, 2), "utf-8");
526
+ return true;
527
+ }
528
+ catch (error) {
529
+ console.error(`Failed to configure Gemini: ${error}`);
530
+ return false;
531
+ }
532
+ }
533
+ /**
534
+ * Check if a command exists in PATH
535
+ *
536
+ * Helper function used by configuration functions to check if CLI tools are available.
537
+ *
538
+ * @param command - Command name to check (e.g., "codex", "gemini")
539
+ * @returns true if command exists in PATH, false otherwise
540
+ */
541
+ function commandExists(command) {
542
+ try {
543
+ execSync(`which ${command}`, { stdio: "ignore" });
544
+ return true;
545
+ }
546
+ catch {
547
+ return false;
548
+ }
549
+ }
550
+ /**
551
+ * Configure Claude CLI (Anthropic)
552
+ *
553
+ * Claude CLI is Anthropic's command-line tool for Claude.
554
+ * Configuration location: ~/.claude/config.json
555
+ * Configuration format: Standard MCP JSON format.
556
+ *
557
+ * Note: Private key is NOT included - MCP server reads from config file instead.
558
+ *
559
+ * @param configPath - Full path to ~/.claude/config.json
560
+ * @returns true if configuration succeeded, false otherwise
561
+ */
562
+ export async function configureClaudeCli(configPath) {
563
+ try {
564
+ // Ensure config directory exists
565
+ const configDir = path.dirname(configPath);
566
+ fs.mkdirSync(configDir, { recursive: true });
567
+ // Read existing config or start with empty object
568
+ let config = {};
569
+ if (fs.existsSync(configPath)) {
570
+ const content = fs.readFileSync(configPath, "utf-8");
571
+ try {
572
+ config = JSON.parse(content);
573
+ }
574
+ catch {
575
+ // Invalid JSON - create new config
576
+ config = {};
577
+ }
578
+ }
579
+ // Ensure mcpServers object exists
580
+ if (!config.mcpServers) {
581
+ config.mcpServers = {};
582
+ }
583
+ // Add or update httpcat server configuration
584
+ config.mcpServers.httpcat = getMcpServerConfig();
585
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
586
+ return true;
587
+ }
588
+ catch (error) {
589
+ console.error(`Failed to configure Claude CLI: ${error}`);
590
+ return false;
591
+ }
592
+ }
593
+ /**
594
+ * Configure LLM based on detected LLM info
595
+ *
596
+ * Main router function that dispatches to the appropriate configuration function
597
+ * based on the detected LLM tool. This is called by the wizard after the user
598
+ * selects which LLM tools to configure.
599
+ *
600
+ * Note: Private key is NOT passed - MCP server reads from config file instead.
601
+ *
602
+ * @param llm - Detected LLM tool information from detector
603
+ * @returns true if configuration succeeded, false otherwise
604
+ */
605
+ export async function configureLLM(llm) {
606
+ // Route to appropriate configuration function based on LLM ID
607
+ switch (llm.id) {
608
+ case "claude-desktop":
609
+ return await configureClaudeDesktop(llm.configPath);
610
+ case "claude-cli":
611
+ return await configureClaudeCli(llm.configPath);
612
+ case "cursor":
613
+ return await configureCursor(llm.configPath);
614
+ case "llm-tools-mcp":
615
+ return await configureLlmToolsMcp(llm.configPath);
616
+ case "mcp-use":
617
+ return await configureMcpUse();
618
+ case "mcp-client":
619
+ return await configureMcpClient(llm.configPath);
620
+ case "codex":
621
+ return await configureCodex(llm.configPath);
622
+ case "gemini":
623
+ return await configureGemini(llm.configPath);
624
+ default:
625
+ // Unknown LLM ID - return false
626
+ return false;
627
+ }
628
+ }
629
+ /**
630
+ * Remove httpcat MCP server from JSON-based config file
631
+ *
632
+ * @param configPath - Path to JSON config file
633
+ * @returns true if removal succeeded, false otherwise
634
+ */
635
+ function removeFromJsonConfig(configPath) {
636
+ try {
637
+ if (!fs.existsSync(configPath)) {
638
+ return true; // Already removed or doesn't exist
639
+ }
640
+ const content = fs.readFileSync(configPath, "utf-8");
641
+ let config = {};
642
+ try {
643
+ config = JSON.parse(content);
644
+ }
645
+ catch {
646
+ // Invalid JSON - nothing to remove
647
+ return true;
648
+ }
649
+ // Remove httpcat from mcpServers if it exists
650
+ if (config.mcpServers && config.mcpServers.httpcat) {
651
+ delete config.mcpServers.httpcat;
652
+ // If mcpServers is now empty, remove it
653
+ if (Object.keys(config.mcpServers).length === 0) {
654
+ delete config.mcpServers;
655
+ }
656
+ // Write back the updated config
657
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
658
+ }
659
+ return true;
660
+ }
661
+ catch (error) {
662
+ return false;
663
+ }
664
+ }
665
+ /**
666
+ * Remove httpcat MCP server from TOML-based config file (Codex)
667
+ *
668
+ * @param configPath - Path to TOML config file
669
+ * @returns true if removal succeeded, false otherwise
670
+ */
671
+ function removeFromTomlConfig(configPath) {
672
+ try {
673
+ if (!fs.existsSync(configPath)) {
674
+ return true; // Already removed or doesn't exist
675
+ }
676
+ const content = fs.readFileSync(configPath, "utf-8");
677
+ let config = {};
678
+ try {
679
+ config = parseToml(content);
680
+ }
681
+ catch {
682
+ // Invalid TOML - nothing to remove
683
+ return true;
684
+ }
685
+ // Remove httpcat from mcp_servers if it exists
686
+ if (config.mcp_servers && config.mcp_servers.httpcat) {
687
+ delete config.mcp_servers.httpcat;
688
+ // If mcp_servers is now empty, remove it
689
+ if (Object.keys(config.mcp_servers).length === 0) {
690
+ delete config.mcp_servers;
691
+ }
692
+ // Write back the updated TOML
693
+ fs.writeFileSync(configPath, stringifyToml(config), "utf-8");
694
+ }
695
+ return true;
696
+ }
697
+ catch (error) {
698
+ return false;
699
+ }
700
+ }
701
+ /**
702
+ * Remove httpcat extension from Gemini CLI
703
+ *
704
+ * @param extensionPath - Path to Gemini extension JSON file
705
+ * @returns true if removal succeeded, false otherwise
706
+ */
707
+ function removeGeminiExtension(extensionPath) {
708
+ try {
709
+ if (fs.existsSync(extensionPath)) {
710
+ fs.unlinkSync(extensionPath);
711
+ // Also try to remove the directory if it's empty
712
+ const extensionDir = path.dirname(extensionPath);
713
+ try {
714
+ const files = fs.readdirSync(extensionDir);
715
+ if (files.length === 0) {
716
+ fs.rmdirSync(extensionDir);
717
+ }
718
+ }
719
+ catch {
720
+ // Ignore errors removing directory
721
+ }
722
+ }
723
+ return true;
724
+ }
725
+ catch (error) {
726
+ return false;
727
+ }
728
+ }
729
+ /**
730
+ * Remove httpcat MCP server from MCP-Use CLI (try CLI first, fallback to file)
731
+ *
732
+ * @returns true if removal succeeded, false otherwise
733
+ */
734
+ function removeFromMcpUse() {
735
+ try {
736
+ // Try CLI command first
737
+ if (commandExists("mcp-use")) {
738
+ try {
739
+ execSync("mcp-use server remove httpcat", { stdio: "ignore" });
740
+ return true;
741
+ }
742
+ catch {
743
+ // CLI failed, try file-based removal
744
+ }
745
+ }
746
+ // Fallback to file-based removal
747
+ const configPath = path.join(process.env.HOME || "", ".mcp-use", "config.json");
748
+ return removeFromJsonConfig(configPath);
749
+ }
750
+ catch (error) {
751
+ return false;
752
+ }
753
+ }
754
+ /**
755
+ * Remove httpcat MCP server from Codex CLI (try CLI first, fallback to file)
756
+ *
757
+ * @param configPath - Path to Codex TOML config file
758
+ * @returns true if removal succeeded, false otherwise
759
+ */
760
+ function removeFromCodex(configPath) {
761
+ try {
762
+ // Try CLI command first
763
+ if (commandExists("codex")) {
764
+ try {
765
+ execSync("codex mcp remove httpcat", { stdio: "ignore" });
766
+ return true;
767
+ }
768
+ catch {
769
+ // CLI failed, try file-based removal
770
+ }
771
+ }
772
+ // Fallback to file-based removal
773
+ return removeFromTomlConfig(configPath);
774
+ }
775
+ catch (error) {
776
+ return false;
777
+ }
778
+ }
779
+ /**
780
+ * Remove httpcat MCP server from Gemini CLI (try CLI first, fallback to file)
781
+ *
782
+ * @param extensionPath - Path to Gemini extension JSON file
783
+ * @returns true if removal succeeded, false otherwise
784
+ */
785
+ function removeFromGemini(extensionPath) {
786
+ try {
787
+ // Try CLI command first
788
+ if (commandExists("gemini")) {
789
+ try {
790
+ execSync("gemini mcp remove httpcat", { stdio: "ignore" });
791
+ return true;
792
+ }
793
+ catch {
794
+ // CLI failed, try file-based removal
795
+ }
796
+ }
797
+ // Fallback to file-based removal
798
+ return removeGeminiExtension(extensionPath);
799
+ }
800
+ catch (error) {
801
+ return false;
802
+ }
803
+ }
804
+ /**
805
+ * Remove httpcat MCP server from a specific LLM tool
806
+ *
807
+ * @param llm - Detected LLM tool information
808
+ * @returns true if removal succeeded, false otherwise
809
+ */
810
+ export async function removeMcpFromLLM(llm) {
811
+ switch (llm.id) {
812
+ case "claude-desktop":
813
+ case "cursor":
814
+ case "llm-tools-mcp":
815
+ case "mcp-client":
816
+ return removeFromJsonConfig(llm.configPath);
817
+ case "mcp-use":
818
+ return removeFromMcpUse();
819
+ case "codex":
820
+ return removeFromCodex(llm.configPath);
821
+ case "gemini":
822
+ return removeFromGemini(llm.configPath);
823
+ default:
824
+ return false;
825
+ }
826
+ }
827
+ /**
828
+ * Get platform-specific Claude Desktop config path
829
+ *
830
+ * @returns Platform-appropriate config file path
831
+ */
832
+ function getClaudeDesktopConfigPath() {
833
+ const platform = process.platform;
834
+ if (platform === "darwin") {
835
+ return path.join(process.env.HOME || "", "Library", "Application Support", "Claude", "claude_desktop_config.json");
836
+ }
837
+ else if (platform === "win32") {
838
+ return path.join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json");
839
+ }
840
+ else {
841
+ return path.join(process.env.HOME || "", ".config", "Claude", "claude_desktop_config.json");
842
+ }
843
+ }
844
+ /**
845
+ * Remove httpcat MCP configurations from all detected LLM tools
846
+ *
847
+ * This function scans for all LLM tools that have httpcat MCP configured
848
+ * and removes the httpcat server from their configurations.
849
+ * It also checks known config paths directly to ensure cleanup even if
850
+ * tools weren't detected.
851
+ *
852
+ * @returns Array of results showing which tools were cleaned up
853
+ */
854
+ export async function removeAllMcpConfigurations() {
855
+ const { detectInstalledLlms } = await import("./llm-cli-detector.js");
856
+ const detectedLlms = await detectInstalledLlms();
857
+ const results = [];
858
+ // Remove from each detected LLM tool
859
+ for (const llm of detectedLlms) {
860
+ try {
861
+ const success = await removeMcpFromLLM(llm);
862
+ results.push({
863
+ name: llm.name,
864
+ success,
865
+ });
866
+ }
867
+ catch (error) {
868
+ results.push({
869
+ name: llm.name,
870
+ success: false,
871
+ });
872
+ }
873
+ }
874
+ // Also check known config paths directly (in case they weren't detected)
875
+ // This ensures we clean up even if detection missed them
876
+ const knownConfigs = [
877
+ {
878
+ name: "Claude Desktop",
879
+ path: getClaudeDesktopConfigPath(),
880
+ type: "json",
881
+ },
882
+ {
883
+ name: "Cursor IDE",
884
+ path: path.join(process.env.HOME || "", ".cursor", "mcp.json"),
885
+ type: "json",
886
+ },
887
+ {
888
+ name: "LLM Tools MCP",
889
+ path: path.join(process.env.HOME || "", ".llm-tools-mcp", "mcp.json"),
890
+ type: "json",
891
+ },
892
+ {
893
+ name: "MCP Client",
894
+ path: path.join(process.env.HOME || "", ".llm", "config.json"),
895
+ type: "json",
896
+ },
897
+ {
898
+ name: "MCP-Use",
899
+ path: path.join(process.env.HOME || "", ".mcp-use", "config.json"),
900
+ type: "json",
901
+ },
902
+ {
903
+ name: "Codex CLI",
904
+ path: path.join(process.env.HOME || "", ".codex", "config.toml"),
905
+ type: "toml",
906
+ },
907
+ {
908
+ name: "Gemini CLI",
909
+ path: path.join(process.env.HOME || "", ".gemini", "extensions", "httpcat", "gemini-extension.json"),
910
+ type: "extension",
911
+ },
912
+ ];
913
+ // Check each known config path and clean up if it exists
914
+ for (const knownConfig of knownConfigs) {
915
+ // Skip if we already processed it via detection
916
+ const alreadyProcessed = detectedLlms.some((llm) => llm.configPath === knownConfig.path);
917
+ if (!alreadyProcessed && fs.existsSync(knownConfig.path)) {
918
+ try {
919
+ let success = false;
920
+ if (knownConfig.type === "json") {
921
+ success = removeFromJsonConfig(knownConfig.path);
922
+ }
923
+ else if (knownConfig.type === "toml") {
924
+ success = removeFromTomlConfig(knownConfig.path);
925
+ }
926
+ else if (knownConfig.type === "extension") {
927
+ success = removeGeminiExtension(knownConfig.path);
928
+ }
929
+ results.push({
930
+ name: knownConfig.name,
931
+ success,
932
+ });
933
+ }
934
+ catch (error) {
935
+ results.push({
936
+ name: knownConfig.name,
937
+ success: false,
938
+ });
939
+ }
940
+ }
941
+ }
942
+ return results;
943
+ }
944
+ /**
945
+ * Remove the base httpcat MCP config file
946
+ *
947
+ * Removes ~/.config/httpcat/mcp.json if it exists.
948
+ *
949
+ * @returns true if removal succeeded or file doesn't exist, false on error
950
+ */
951
+ export function removeBaseMcpConfig() {
952
+ try {
953
+ const mcpConfigPath = path.join(process.env.HOME || "", ".config", "httpcat", "mcp.json");
954
+ if (fs.existsSync(mcpConfigPath)) {
955
+ fs.unlinkSync(mcpConfigPath);
956
+ }
957
+ return true;
958
+ }
959
+ catch (error) {
960
+ return false;
961
+ }
962
+ }
963
+ //# sourceMappingURL=llm-cli-config.js.map