troxy-cli 1.0.2 → 1.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "troxy-cli",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "AI payment control — protect your agent's payments with policies",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api.js CHANGED
@@ -49,7 +49,7 @@ export const api = {
49
49
  evaluate: (body, apiKey) => request('POST', '/evaluate', { apiKey, body }),
50
50
 
51
51
  // MCP heartbeat (agent API key)
52
- mcpHeartbeat: (apiKey) => request('POST', '/mcp/heartbeat', { apiKey }),
52
+ mcpHeartbeat: (apiKey, agentName) => request('POST', '/mcp/heartbeat', { apiKey, body: agentName ? { agent_name: agentName } : undefined }),
53
53
  };
54
54
 
55
55
  // Named export for backwards compat with init.js + mcp-server.js
package/src/init.js CHANGED
@@ -1,8 +1,15 @@
1
- import fs from 'fs';
2
- import os from 'os';
3
- import path from 'path';
4
- import { saveConfig } from './config.js';
5
- import { evaluatePayment } from './api.js';
1
+ import fs from 'fs';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import readline from 'readline';
5
+ import { execSync } from 'child_process';
6
+ import { saveConfig } from './config.js';
7
+ import { evaluatePayment } from './api.js';
8
+
9
+ function prompt(question) {
10
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
11
+ return new Promise(resolve => rl.question(question, ans => { rl.close(); resolve(ans.trim()); }));
12
+ }
6
13
 
7
14
  // MCP config locations per client and platform
8
15
  const MCP_CLIENTS = [
@@ -66,8 +73,15 @@ export async function runInit({ key } = {}) {
66
73
  console.log('✓');
67
74
  }
68
75
 
76
+ // Ask for agent name
77
+ const agentName = await prompt(' What would you like to name this agent? (e.g. "Shopping Bot"): ');
78
+ if (!agentName) {
79
+ console.error('\n Error: agent name is required.\n');
80
+ process.exit(1);
81
+ }
82
+
69
83
  // Save config
70
- saveConfig({ apiKey: key });
84
+ saveConfig({ apiKey: key, agentName });
71
85
  console.log(' Config saved (~/.troxy/config.json) ✓');
72
86
 
73
87
  // Detect and patch MCP clients
@@ -96,10 +110,83 @@ export async function runInit({ key } = {}) {
96
110
  console.log('\n Restart your MCP client to activate Troxy.');
97
111
  }
98
112
 
113
+ // Install background service so MCP server survives reboots
114
+ console.log('\n Setting up background service...');
115
+ try {
116
+ installService(key, agentName);
117
+ console.log(' Background service installed ✓');
118
+ } catch (err) {
119
+ console.log(` Background service ✗ (${err.message})`);
120
+ console.log(' You can start it manually with: troxy mcp &');
121
+ }
122
+
99
123
  console.log('\n Your payments are now protected.');
100
124
  console.log(' Dashboard → https://dashboard.troxy.ai\n');
101
125
  }
102
126
 
127
+ function installService(apiKey, agentName) {
128
+ const platform = process.platform;
129
+ const troxy = process.execPath.replace(/node$/, 'troxy') ;
130
+
131
+ if (platform === 'linux') {
132
+ const unit = `[Unit]
133
+ Description=Troxy MCP Server
134
+ After=network.target
135
+
136
+ [Service]
137
+ ExecStart=${troxy} mcp
138
+ Restart=always
139
+ RestartSec=10
140
+ User=${os.userInfo().username}
141
+ Environment=TROXY_API_KEY=${apiKey}
142
+ Environment=TROXY_AGENT_NAME=${agentName}
143
+
144
+ [Install]
145
+ WantedBy=multi-user.target
146
+ `;
147
+ fs.writeFileSync('/tmp/troxy-mcp.service', unit);
148
+ execSync('sudo mv /tmp/troxy-mcp.service /etc/systemd/system/troxy-mcp.service');
149
+ execSync('sudo systemctl daemon-reload');
150
+ execSync('sudo systemctl enable troxy-mcp');
151
+ execSync('sudo systemctl restart troxy-mcp');
152
+
153
+ } else if (platform === 'darwin') {
154
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
155
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
156
+ <plist version="1.0">
157
+ <dict>
158
+ <key>Label</key>
159
+ <string>ai.troxy.mcp</string>
160
+ <key>ProgramArguments</key>
161
+ <array>
162
+ <string>${troxy}</string>
163
+ <string>mcp</string>
164
+ </array>
165
+ <key>EnvironmentVariables</key>
166
+ <dict>
167
+ <key>TROXY_API_KEY</key>
168
+ <string>${apiKey}</string>
169
+ <key>TROXY_AGENT_NAME</key>
170
+ <string>${agentName}</string>
171
+ </dict>
172
+ <key>RunAtLoad</key>
173
+ <true/>
174
+ <key>KeepAlive</key>
175
+ <true/>
176
+ </dict>
177
+ </plist>
178
+ `;
179
+ const plistPath = path.join(os.homedir(), 'Library/LaunchAgents/ai.troxy.mcp.plist');
180
+ fs.mkdirSync(path.dirname(plistPath), { recursive: true });
181
+ fs.writeFileSync(plistPath, plist);
182
+ try { execSync(`launchctl unload ${plistPath} 2>/dev/null`); } catch {}
183
+ execSync(`launchctl load ${plistPath}`);
184
+
185
+ } else {
186
+ throw new Error('Auto-start not supported on this platform. Start manually: troxy mcp &');
187
+ }
188
+ }
189
+
103
190
  function mcpEntry(apiKey) {
104
191
  return {
105
192
  troxy: {
package/src/mcp-server.js CHANGED
@@ -8,8 +8,9 @@ import { loadConfig } from './config.js';
8
8
  import { evaluatePayment, api } from './api.js';
9
9
 
10
10
  export async function runMcp() {
11
- const config = loadConfig();
12
- const apiKey = process.env.TROXY_API_KEY || config?.apiKey;
11
+ const config = loadConfig();
12
+ const apiKey = process.env.TROXY_API_KEY || config?.apiKey;
13
+ const agentName = process.env.TROXY_AGENT_NAME || config?.agentName;
13
14
 
14
15
  if (!apiKey) {
15
16
  process.stderr.write(
@@ -70,6 +71,7 @@ export async function runMcp() {
70
71
  }
71
72
 
72
73
  const args = request.params.arguments ?? {};
74
+ if (agentName && !args.agent) args.agent = agentName;
73
75
  const result = await evaluatePayment(args, apiKey);
74
76
 
75
77
  if (result.error) {
@@ -109,7 +111,7 @@ export async function runMcp() {
109
111
  // Must be set up before server.connect() since stdio transport keeps the
110
112
  // event loop running but connect() may not return in all environments.
111
113
  const sendHeartbeat = () =>
112
- api.mcpHeartbeat(apiKey)
114
+ api.mcpHeartbeat(apiKey, agentName)
113
115
  .then(() => process.stderr.write('[troxy] heartbeat ok\n'))
114
116
  .catch(err => process.stderr.write(`[troxy] heartbeat failed: ${err.message}\n`));
115
117
  sendHeartbeat();