troxy-cli 1.0.8 → 1.1.0

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.
package/bin/troxy.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { runInit } from '../src/init.js';
2
+ import { runInit } from '../src/init.js';
3
+ import { runUninstall } from '../src/uninstall.js';
3
4
  import { runMcp } from '../src/mcp-server.js';
4
5
  import { runLogin, clearSession } from '../src/auth.js';
5
6
  import { runCards } from '../src/cards.js';
@@ -31,6 +32,10 @@ switch (command) {
31
32
  await runInit(flags);
32
33
  break;
33
34
 
35
+ case 'uninstall':
36
+ await runUninstall();
37
+ break;
38
+
34
39
  // ── Auth ──────────────────────────────────────────────────────
35
40
  case 'login':
36
41
  await runLogin(flags);
@@ -84,6 +89,7 @@ switch (command) {
84
89
 
85
90
  Setup
86
91
  npx troxy init --key <api-key> Initialize and patch MCP clients
92
+ npx troxy uninstall Remove Troxy from this machine
87
93
  npx troxy login Log in to your dashboard account
88
94
  npx troxy logout Clear local session
89
95
  npx troxy status Check API health
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "troxy-cli",
3
- "version": "1.0.8",
3
+ "version": "1.1.0",
4
4
  "description": "AI payment control — protect your agent's payments with policies",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,119 @@
1
+ import fs from 'fs';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import { execSync } from 'child_process';
5
+ import readline from 'readline';
6
+
7
+ const MCP_CLIENTS = [
8
+ {
9
+ name: 'Claude Desktop',
10
+ path: {
11
+ darwin: path.join(os.homedir(), 'Library/Application Support/Claude/claude_desktop_config.json'),
12
+ win32: path.join(process.env.APPDATA || os.homedir(), 'Claude/claude_desktop_config.json'),
13
+ linux: path.join(os.homedir(), '.config/claude/claude_desktop_config.json'),
14
+ },
15
+ },
16
+ {
17
+ name: 'Cursor',
18
+ path: {
19
+ darwin: path.join(os.homedir(), '.cursor/mcp.json'),
20
+ win32: path.join(os.homedir(), '.cursor/mcp.json'),
21
+ linux: path.join(os.homedir(), '.cursor/mcp.json'),
22
+ },
23
+ },
24
+ {
25
+ name: 'Windsurf',
26
+ path: {
27
+ darwin: path.join(os.homedir(), '.codeium/windsurf/mcp_config.json'),
28
+ win32: path.join(os.homedir(), '.codeium/windsurf/mcp_config.json'),
29
+ linux: path.join(os.homedir(), '.codeium/windsurf/mcp_config.json'),
30
+ },
31
+ },
32
+ ];
33
+
34
+ function prompt(question) {
35
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
36
+ return new Promise(resolve => rl.question(question, ans => { rl.close(); resolve(ans.trim()); }));
37
+ }
38
+
39
+ function removeService() {
40
+ const platform = process.platform;
41
+
42
+ if (platform === 'linux') {
43
+ try { execSync('sudo systemctl stop troxy-mcp 2>/dev/null'); } catch {}
44
+ try { execSync('sudo systemctl disable troxy-mcp 2>/dev/null'); } catch {}
45
+ try { execSync('sudo rm -f /etc/systemd/system/troxy-mcp.service'); } catch {}
46
+ try { execSync('sudo systemctl daemon-reload'); } catch {}
47
+ return true;
48
+
49
+ } else if (platform === 'darwin') {
50
+ const plistPath = path.join(os.homedir(), 'Library/LaunchAgents/ai.troxy.mcp.plist');
51
+ if (fs.existsSync(plistPath)) {
52
+ try { execSync(`launchctl unload ${plistPath} 2>/dev/null`); } catch {}
53
+ fs.unlinkSync(plistPath);
54
+ }
55
+ return true;
56
+ }
57
+
58
+ return false;
59
+ }
60
+
61
+ function removeMcpEntries() {
62
+ const platform = process.platform;
63
+ const patched = [];
64
+
65
+ for (const client of MCP_CLIENTS) {
66
+ const configPath = client.path[platform] ?? client.path.linux;
67
+ if (!fs.existsSync(configPath)) continue;
68
+
69
+ try {
70
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
71
+ if (config.mcpServers?.troxy) {
72
+ delete config.mcpServers.troxy;
73
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
74
+ patched.push(client.name);
75
+ }
76
+ } catch {
77
+ // malformed config — skip
78
+ }
79
+ }
80
+
81
+ return patched;
82
+ }
83
+
84
+ export async function runUninstall() {
85
+ console.log('\n Troxy — Uninstall\n');
86
+
87
+ const answer = await prompt(' This will remove Troxy from this machine. Continue? (y/N): ');
88
+ if (answer.toLowerCase() !== 'y') {
89
+ console.log('\n Cancelled.\n');
90
+ process.exit(0);
91
+ }
92
+
93
+ // 1. Stop and remove background service
94
+ process.stdout.write(' Stopping background service... ');
95
+ const removed = removeService();
96
+ console.log(removed ? '✓' : 'skipped (not supported on this platform)');
97
+
98
+ // 2. Remove troxy from MCP client configs
99
+ process.stdout.write(' Removing from MCP clients... ');
100
+ const patched = removeMcpEntries();
101
+ if (patched.length > 0) {
102
+ console.log(`✓ (${patched.join(', ')})`);
103
+ console.log(' Restart your MCP client to complete removal.');
104
+ } else {
105
+ console.log('none found');
106
+ }
107
+
108
+ // 3. Delete ~/.troxy config
109
+ process.stdout.write(' Removing config (~/.troxy)... ');
110
+ const configDir = path.join(os.homedir(), '.troxy');
111
+ if (fs.existsSync(configDir)) {
112
+ fs.rmSync(configDir, { recursive: true, force: true });
113
+ console.log('✓');
114
+ } else {
115
+ console.log('not found');
116
+ }
117
+
118
+ console.log('\n Troxy removed. Your payments are no longer protected by Troxy.\n');
119
+ }