troxy-cli 1.4.5 → 1.4.7

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
@@ -61,22 +61,6 @@ switch (command) {
61
61
  break;
62
62
 
63
63
  // ── Auth ──────────────────────────────────────────────────────
64
- case 'connect': {
65
- const k = flags.key;
66
- if (!k || !k.startsWith('txy-')) {
67
- console.error('\n Usage: troxy connect --key txy-...\n');
68
- process.exit(1);
69
- }
70
- // Validate key before saving
71
- process.stdout.write('\n Validating key... ');
72
- await api.agentStatus(k);
73
- console.log('✓');
74
- const { saveConfig } = await import('../src/config.js');
75
- saveConfig({ apiKey: k });
76
- console.log(' Key saved to ~/.troxy/config.json\n');
77
- break;
78
- }
79
-
80
64
  case 'login':
81
65
  await runLogin(flags);
82
66
  break;
@@ -87,6 +71,26 @@ switch (command) {
87
71
  break;
88
72
 
89
73
  case 'rotate-key': {
74
+ if (flags.help || flags.h) {
75
+ console.log(`
76
+ troxy rotate-key [options]
77
+
78
+ Creates a new MCP API key, saves it to ~/.troxy/config.json, and optionally
79
+ revokes the old key. Login required.
80
+
81
+ Options:
82
+ --name <name> Name for the new key (default: "Rotated key")
83
+ --revoke-old Revoke the old key immediately after creating the new one
84
+
85
+ Examples:
86
+ troxy rotate-key
87
+ troxy rotate-key --revoke-old
88
+ troxy rotate-key --name "My Agent Key" --revoke-old
89
+
90
+ After rotating: update TROXY_API_KEY in your MCP config and restart the MCP server.
91
+ `);
92
+ process.exit(0);
93
+ }
90
94
  const jwt = requireJwt();
91
95
  const { loadConfig, saveConfig } = await import('../src/config.js');
92
96
  const oldKey = loadConfig()?.apiKey;
@@ -143,6 +147,28 @@ switch (command) {
143
147
 
144
148
  // ── Simulate a payment evaluation ────────────────────────────
145
149
  case 'pay': {
150
+ if (flags.help || flags.h) {
151
+ console.log(`
152
+ troxy pay --merchant <name> --amount <n> [options]
153
+
154
+ Simulates a payment evaluation request — identical to what your AI agent sends.
155
+ Use this to test your policies. Login required.
156
+
157
+ Required:
158
+ --merchant <name> Merchant name (e.g. "Amazon")
159
+ --amount <n> Payment amount in USD
160
+
161
+ Optional:
162
+ --card <alias> Card alias (default: "Work")
163
+ --category <cat> Merchant category (e.g. travel, software, food)
164
+
165
+ Examples:
166
+ troxy pay --merchant "Amazon" --amount 50
167
+ troxy pay --merchant "Amazon" --amount 350 --card "Work"
168
+ troxy pay --merchant "Delta" --amount 250 --card "Work" --category travel
169
+ `);
170
+ process.exit(0);
171
+ }
146
172
  requireJwt();
147
173
  const apiKey = loadConfig()?.apiKey || process.env.TROXY_API_KEY;
148
174
  if (!apiKey) { console.error(' No API key. Run: troxy init --key txy-...\n'); process.exit(1); }
@@ -179,6 +205,21 @@ switch (command) {
179
205
  break;
180
206
 
181
207
  case 'insights': {
208
+ if (flags.help || flags.h) {
209
+ console.log(`
210
+ troxy insights [options]
211
+
212
+ Shows a spending and decision summary for a given period. Login required.
213
+
214
+ Options:
215
+ --period <days> Number of days to look back (default: 30)
216
+
217
+ Examples:
218
+ troxy insights
219
+ troxy insights --period 7
220
+ `);
221
+ process.exit(0);
222
+ }
182
223
  const jwt = requireJwt();
183
224
  const period = Number(flags.period || 30);
184
225
  const data = await api.agentInsights(jwt, period);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "troxy-cli",
3
- "version": "1.4.5",
3
+ "version": "1.4.7",
4
4
  "description": "AI payment control — protect your agent's payments with policies",
5
5
  "type": "module",
6
6
  "bin": {
package/src/activity.js CHANGED
@@ -1,15 +1,35 @@
1
1
  import { api } from './api.js';
2
2
  import { requireJwt } from './auth.js';
3
+ import { loadConfig } from './config.js';
3
4
  import { table } from './print.js';
4
5
 
5
6
  const ICON = { ALLOW: '✓', BLOCK: '✗', ESCALATE: '⏳', NOTIFY: '~' };
6
7
 
7
8
  export async function runActivity(flags) {
8
- const jwt = requireJwt();
9
- const limit = Number(flags.limit || 20);
10
- const mine = !!flags.mine;
9
+ if (flags.help || flags.h) {
10
+ console.log(`
11
+ troxy activity [options]
11
12
 
12
- const data = await api.agentActivity(jwt, limit, mine);
13
+ Shows recent payment decisions across all your MCPs. Login required.
14
+
15
+ Options:
16
+ --limit <n> Number of rows to show (default: 20, max: 200)
17
+ --mine Show only decisions from this machine's MCP
18
+
19
+ Examples:
20
+ troxy activity
21
+ troxy activity --limit 50
22
+ troxy activity --mine
23
+ `);
24
+ process.exit(0);
25
+ }
26
+
27
+ const jwt = requireJwt();
28
+ const limit = Number(flags.limit || 20);
29
+ const mine = !!flags.mine;
30
+ const tokenPrefix = mine ? (loadConfig()?.apiKey || '').substring(0, 11) : undefined;
31
+
32
+ const data = await api.agentActivity(jwt, limit, mine, tokenPrefix);
13
33
  const rows = data?.activity || [];
14
34
 
15
35
  if (!rows.length) { console.log('\n No activity yet.\n'); return; }
package/src/api.js CHANGED
@@ -66,17 +66,12 @@ export const api = {
66
66
  resumeToken: (jwt, id) => request('POST', `/tokens/${id}/resume`, { jwt }),
67
67
  renameToken: (jwt, id, name) => request('PATCH', `/tokens/${id}/name`, { jwt, body: { name } }),
68
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 } }),
73
-
74
69
  // Agent read-only API (JWT session auth — run: troxy login)
75
70
  agentStatus: (jwt) => request('GET', '/agent/status', { jwt }),
76
71
  agentPolicies: (jwt) => request('GET', '/agent/policies', { jwt }),
77
72
  agentMcps: (jwt) => request('GET', '/agent/mcps', { jwt }),
78
73
  agentCards: (jwt) => request('GET', '/agent/cards', { jwt }),
79
- agentActivity: (jwt, limit, mine) => request('GET', `/agent/activity?limit=${limit || 20}${mine ? '&mine=true' : ''}`, { jwt }),
74
+ agentActivity: (jwt, limit, mine, tokenPrefix) => request('GET', `/agent/activity?limit=${limit || 20}${mine ? `&mine=true&token_prefix=${encodeURIComponent(tokenPrefix || '')}` : ''}`, { jwt }),
80
75
  agentInsights: (jwt, period) => request('GET', `/agent/insights?period=${period || 30}`, { jwt }),
81
76
  };
82
77
 
package/src/mcps.js CHANGED
@@ -3,7 +3,17 @@ import { loadConfig, saveConfig } from './config.js';
3
3
  import { requireJwt } from './auth.js';
4
4
  import { table } from './print.js';
5
5
 
6
+ const HELP = {
7
+ list: ` troxy mcps list\n\n Lists all MCP connections on your account — name, prefix, status, last seen,\n policies assigned, default action, and which one is this machine.\n`,
8
+ rename: ` troxy mcps rename --name <new-name>\n\n Renames this machine's MCP. The new name appears in the dashboard immediately.\n\n Options:\n --name New name for this machine's MCP\n\n Example:\n troxy mcps rename --name "My Laptop"\n`,
9
+ };
10
+
6
11
  export async function runMcps([sub], flags) {
12
+ if (flags.help || flags.h) {
13
+ console.log('\n' + (HELP[sub] || ` troxy mcps <subcommand> [options]\n\n Subcommands:\n list List all MCP connections\n rename Rename this machine's MCP\n\n Run 'troxy mcps <subcommand> --help' for subcommand help.\n`));
14
+ process.exit(0);
15
+ }
16
+
7
17
  switch (sub || 'list') {
8
18
  case 'list': {
9
19
  const jwt = requireJwt();
package/src/policies.js CHANGED
@@ -10,7 +10,21 @@ function _scope(p) {
10
10
  return 'no MCPs applied';
11
11
  }
12
12
 
13
+ const HELP = {
14
+ list: ` troxy policies list\n\n Lists all policies in your account with their action, scope, status, and conditions.\n`,
15
+ describe: ` troxy policies describe --name <policy-name>\n\n Shows full details for a single policy.\n\n Options:\n --name Name of the policy (use single quotes for names with special chars)\n`,
16
+ create: ` troxy policies create --name <name> --action <action> [options]\n\n Creates a new policy. Login required.\n\n Required:\n --name Policy name\n --action ALLOW, BLOCK, NOTIFY, or ESCALATE\n\n Optional conditions:\n --field Field to match: amount, merchant_name, merchant_category,\n merchant_country, currency, agent_name, hour, day_of_week\n --operator eq, neq, gt, gte, lt, lte, contains, between\n --value Comparison value (e.g. 500, amazon, Monday)\n --value2 Upper bound for 'between' operator\n\n Scope:\n --mcp <name> Scope policy to a specific MCP only (default: all MCPs)\n Run 'troxy mcps list' to see MCP names.\n\n Examples:\n troxy policies create --name "Block large" --action BLOCK --field amount --operator gte --value 500\n troxy policies create --name "Block Amazon" --action BLOCK --field merchant_name --operator contains --value amazon\n troxy policies create --name "Cap spend" --action BLOCK --mcp "My Laptop" --field amount --operator gte --value 200\n`,
17
+ enable: ` troxy policies enable --name <policy-name>\n\n Enables a disabled policy.\n\n Options:\n --name Name of the policy to enable\n`,
18
+ disable: ` troxy policies disable --name <policy-name>\n\n Disables a policy without deleting it.\n\n Options:\n --name Name of the policy to disable\n`,
19
+ delete: ` troxy policies delete --name <policy-name>\n\n Permanently deletes a policy.\n\n Options:\n --name Name of the policy to delete\n`,
20
+ };
21
+
13
22
  export async function runPolicies([sub, ...args], flags) {
23
+ if (flags.help || flags.h) {
24
+ console.log('\n' + (HELP[sub] || ` troxy policies <subcommand> [options]\n\n Subcommands:\n list List all policies\n describe Show details for a policy\n create Create a new policy\n enable Enable a policy\n disable Disable a policy\n delete Delete a policy\n\n Run 'troxy policies <subcommand> --help' for subcommand help.\n`));
25
+ process.exit(0);
26
+ }
27
+
14
28
  // Read-only subcommands work with a login session
15
29
  const readOnly = !sub || sub === 'list' || sub === 'describe';
16
30