troxy-cli 1.4.3 → 1.4.5
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 +24 -15
- package/package.json +1 -1
- package/src/api.js +12 -5
- package/src/mcps.js +8 -10
- package/src/pause.js +23 -15
- package/src/policies.js +24 -2
package/bin/troxy.js
CHANGED
|
@@ -143,7 +143,9 @@ switch (command) {
|
|
|
143
143
|
|
|
144
144
|
// ── Simulate a payment evaluation ────────────────────────────
|
|
145
145
|
case 'pay': {
|
|
146
|
-
|
|
146
|
+
requireJwt();
|
|
147
|
+
const apiKey = loadConfig()?.apiKey || process.env.TROXY_API_KEY;
|
|
148
|
+
if (!apiKey) { console.error(' No API key. Run: troxy init --key txy-...\n'); process.exit(1); }
|
|
147
149
|
const merchant = flags.merchant;
|
|
148
150
|
const amount = parseFloat(flags.amount);
|
|
149
151
|
const card = flags.card || 'Work';
|
|
@@ -286,30 +288,37 @@ switch (command) {
|
|
|
286
288
|
MCP setup (once per machine): troxy init --key <api-key>
|
|
287
289
|
Login for CLI commands (12h): troxy login
|
|
288
290
|
|
|
289
|
-
|
|
291
|
+
Setup (one time, API key required)
|
|
290
292
|
troxy init --key <api-key> Connect this machine as an MCP + save key
|
|
291
|
-
troxy rotate-key Create new MCP key + save it
|
|
292
|
-
troxy rotate-key --revoke-old Same + revoke the old key immediately
|
|
293
293
|
troxy uninstall Remove Troxy from this machine
|
|
294
|
-
troxy status API health +
|
|
295
|
-
|
|
296
|
-
|
|
294
|
+
troxy status API health + MCP status (no login needed)
|
|
295
|
+
|
|
296
|
+
Everything else requires: troxy login
|
|
297
|
+
|
|
298
|
+
MCP
|
|
299
|
+
troxy pause Pause this MCP (blocks all payments)
|
|
300
|
+
troxy resume Resume this MCP
|
|
301
|
+
troxy mcps list All MCPs in your account
|
|
302
|
+
troxy mcps rename --name "x" Rename this machine's MCP
|
|
297
303
|
|
|
298
|
-
|
|
304
|
+
Keys
|
|
305
|
+
troxy rotate-key Create new MCP key + save it locally
|
|
306
|
+
troxy rotate-key --revoke-old Same + revoke the old key immediately
|
|
307
|
+
|
|
308
|
+
Policies
|
|
299
309
|
troxy policies list
|
|
300
310
|
troxy policies describe --name "Block Amazon"
|
|
301
|
-
troxy mcps list
|
|
302
|
-
troxy mcps rename --name "new-name"
|
|
303
|
-
troxy activity [--limit 50] [--mine]
|
|
304
|
-
troxy insights [--period 7]
|
|
305
|
-
|
|
306
|
-
Manage (requires: troxy login)
|
|
307
311
|
troxy policies create --name "X" --action BLOCK --field amount --operator gte --value 500
|
|
312
|
+
troxy policies create --name "X" --action BLOCK --mcp "My Laptop" (scoped to one MCP)
|
|
308
313
|
troxy policies enable --name "X"
|
|
309
314
|
troxy policies disable --name "X"
|
|
310
315
|
troxy policies delete --name "X"
|
|
311
316
|
|
|
312
|
-
|
|
317
|
+
Activity & insights
|
|
318
|
+
troxy activity [--limit 50] [--mine]
|
|
319
|
+
troxy insights [--period 7]
|
|
320
|
+
|
|
321
|
+
Simulate
|
|
313
322
|
troxy pay --merchant "Amazon" --amount 50 --card "Work"
|
|
314
323
|
troxy pay --merchant "Google" --amount 300 --card "Work" --category software
|
|
315
324
|
`);
|
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -58,11 +58,18 @@ export const api = {
|
|
|
58
58
|
// MCP heartbeat (agent API key)
|
|
59
59
|
mcpHeartbeat: (apiKey, agentName) => request('POST', '/mcp/heartbeat', { apiKey, body: agentName ? { agent_name: agentName } : undefined }),
|
|
60
60
|
|
|
61
|
-
// MCP status
|
|
62
|
-
mcpStatus: (apiKey)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
// MCP status (agent API key — no login needed)
|
|
62
|
+
mcpStatus: (apiKey) => request('GET', '/mcp/status', { apiKey }),
|
|
63
|
+
|
|
64
|
+
// MCP pause / resume / rename via JWT (requires troxy login)
|
|
65
|
+
pauseToken: (jwt, id) => request('POST', `/tokens/${id}/pause`, { jwt }),
|
|
66
|
+
resumeToken: (jwt, id) => request('POST', `/tokens/${id}/resume`, { jwt }),
|
|
67
|
+
renameToken: (jwt, id, name) => request('PATCH', `/tokens/${id}/name`, { jwt, body: { name } }),
|
|
68
|
+
|
|
69
|
+
// MCP daemon endpoints (agent API key — used by MCP server only)
|
|
70
|
+
mcpPause: (apiKey) => request('POST', '/mcp/pause', { apiKey }),
|
|
71
|
+
mcpResume: (apiKey) => request('POST', '/mcp/resume', { apiKey }),
|
|
72
|
+
mcpRename: (apiKey, name) => request('PATCH', '/mcp/name', { apiKey, body: { name } }),
|
|
66
73
|
|
|
67
74
|
// Agent read-only API (JWT session auth — run: troxy login)
|
|
68
75
|
agentStatus: (jwt) => request('GET', '/agent/status', { jwt }),
|
package/src/mcps.js
CHANGED
|
@@ -28,18 +28,16 @@ export async function runMcps([sub], flags) {
|
|
|
28
28
|
|
|
29
29
|
case 'rename': {
|
|
30
30
|
const name = flags.name;
|
|
31
|
-
if (!name) {
|
|
32
|
-
|
|
33
|
-
process.exit(1);
|
|
34
|
-
}
|
|
31
|
+
if (!name) { console.error('\n Usage: troxy mcps rename --name "new-name"\n'); process.exit(1); }
|
|
32
|
+
const jwt = requireJwt();
|
|
35
33
|
const config = loadConfig();
|
|
36
|
-
const
|
|
37
|
-
if (!
|
|
38
|
-
console.error('\n No API key found. Run: troxy init --key txy-...\n');
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
34
|
+
const prefix = (config?.apiKey || '').substring(0, 11);
|
|
35
|
+
if (!prefix) { console.error('\n No API key found. Run: troxy init --key txy-...\n'); process.exit(1); }
|
|
41
36
|
process.stdout.write(`\n Renaming MCP to "${name}"... `);
|
|
42
|
-
await api.
|
|
37
|
+
const { tokens = [] } = await api.listTokens(jwt);
|
|
38
|
+
const tok = tokens.find(t => t.prefix === prefix);
|
|
39
|
+
if (!tok) { console.error('\nCould not find this machine\'s MCP. Run: troxy init --key txy-...\n'); process.exit(1); }
|
|
40
|
+
await api.renameToken(jwt, tok.id, name);
|
|
43
41
|
saveConfig({ ...config, agentName: name });
|
|
44
42
|
console.log('✓');
|
|
45
43
|
console.log(' Dashboard and future heartbeats will use the new name.\n');
|
package/src/pause.js
CHANGED
|
@@ -1,25 +1,33 @@
|
|
|
1
1
|
import { loadConfig } from './config.js';
|
|
2
|
+
import { requireJwt } from './auth.js';
|
|
2
3
|
import { api } from './api.js';
|
|
3
4
|
|
|
5
|
+
async function _localTokenId(jwt, config) {
|
|
6
|
+
const prefix = (config?.apiKey || '').substring(0, 11);
|
|
7
|
+
if (!prefix) throw new Error('No API key found. Run: troxy init --key txy-...');
|
|
8
|
+
const { tokens = [] } = await api.listTokens(jwt);
|
|
9
|
+
const tok = tokens.find(t => t.prefix === prefix);
|
|
10
|
+
if (!tok) throw new Error('This machine\'s MCP key was not found in your account. Run: troxy init --key txy-...');
|
|
11
|
+
return tok.id;
|
|
12
|
+
}
|
|
13
|
+
|
|
4
14
|
export async function runPause() {
|
|
15
|
+
const jwt = requireJwt();
|
|
5
16
|
const config = loadConfig();
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
console.log('⏸ MCP paused. All payment evaluations will be blocked.');
|
|
13
|
-
console.log(' Run "troxy resume" to resume.');
|
|
17
|
+
process.stdout.write('\n Pausing MCP... ');
|
|
18
|
+
const id = await _localTokenId(jwt, config);
|
|
19
|
+
await api.pauseToken(jwt, id);
|
|
20
|
+
console.log('✓');
|
|
21
|
+
console.log(' ⏸ All payment evaluations are now blocked.');
|
|
22
|
+
console.log(' Run "troxy resume" to resume.\n');
|
|
14
23
|
}
|
|
15
24
|
|
|
16
25
|
export async function runResume() {
|
|
26
|
+
const jwt = requireJwt();
|
|
17
27
|
const config = loadConfig();
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
await api.mcpResume(apiKey);
|
|
24
|
-
console.log('▶ MCP resumed. Payment evaluations are active again.');
|
|
28
|
+
process.stdout.write('\n Resuming MCP... ');
|
|
29
|
+
const id = await _localTokenId(jwt, config);
|
|
30
|
+
await api.resumeToken(jwt, id);
|
|
31
|
+
console.log('✓');
|
|
32
|
+
console.log(' ▶ Payment evaluations are active again.\n');
|
|
25
33
|
}
|
package/src/policies.js
CHANGED
|
@@ -82,8 +82,30 @@ export async function runPolicies([sub, ...args], flags) {
|
|
|
82
82
|
if (flags.value2) cond.value2 = flags.value2;
|
|
83
83
|
conditions.push(cond);
|
|
84
84
|
}
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
|
|
86
|
+
// --mcp <name>: scope policy to a specific MCP instead of all
|
|
87
|
+
let isGlobal = true;
|
|
88
|
+
let mcpIds = [];
|
|
89
|
+
if (flags.mcp) {
|
|
90
|
+
const { tokens = [] } = await api.listTokens(jwt);
|
|
91
|
+
const needle = flags.mcp.toLowerCase();
|
|
92
|
+
const match = tokens.find(t =>
|
|
93
|
+
(t.name && t.name.toLowerCase() === needle) ||
|
|
94
|
+
(t.agent_name && t.agent_name.toLowerCase() === needle) ||
|
|
95
|
+
(t.prefix && t.prefix.toLowerCase().startsWith(needle))
|
|
96
|
+
);
|
|
97
|
+
if (!match) {
|
|
98
|
+
console.error(`\n MCP "${flags.mcp}" not found. Run: troxy mcps list\n`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
isGlobal = false;
|
|
102
|
+
mcpIds = [match.id];
|
|
103
|
+
console.log(`\n Scoping to MCP: ${match.name || match.agent_name || match.prefix}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const policy = await api.createPolicy(jwt, { name, action, conditions, enabled: true, global: isGlobal, mcp_ids: mcpIds });
|
|
107
|
+
const scope = isGlobal ? 'all MCPs' : (policy.mcps?.[0]?.name || flags.mcp);
|
|
108
|
+
console.log(`\n Policy "${policy.name}" created ✓ (priority: ${policy.priority}, scope: ${scope})\n`);
|
|
87
109
|
break;
|
|
88
110
|
}
|
|
89
111
|
|