troxy-cli 1.3.1 → 1.3.3

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # troxy-cli
2
2
 
3
- The official Troxy CLI — onboard AI agents, manage cards and policies from the terminal.
3
+ The official Troxy CLI — onboard AI agents, manage MCPs and policies from the terminal.
4
4
 
5
5
  ## Prerequisites
6
6
 
@@ -48,12 +48,13 @@ npx troxy-cli <command>
48
48
 
49
49
  | Command | Description |
50
50
  |---------|-------------|
51
- | `troxy init` | Connect an agent to Troxy — validates API key, sets agent name, writes config |
52
- | `troxy login` | Authenticate via magic-link code (enter the code from your email) |
53
- | `troxy cards` | List card aliases |
54
- | `troxy policies` | List policies |
51
+ | `troxy init` | Connect an agent to Troxy — validates API key, sets agent name, patches MCP configs |
52
+ | `troxy login` | Start a 12-hour CLI session (opens browser → copy code paste into terminal) |
53
+ | `troxy mcps` | List connected MCP agents and their status |
54
+ | `troxy policies` | List and manage policies |
55
55
  | `troxy activity` | View recent transaction audit log |
56
- | `troxy status` | Show current config and connection status |
56
+ | `troxy insights` | Spending stats and decision breakdown |
57
+ | `troxy status` | Show connection status and account overview |
57
58
 
58
59
  ## How it works
59
60
 
@@ -68,10 +69,11 @@ The CLI also ships an MCP server (`src/mcp-server.js`) that exposes Troxy as a t
68
69
 
69
70
  ## Auth flow
70
71
 
71
- `troxy login` triggers the same magic-link flow as the dashboard:
72
- - Sends a code to your email
73
- - Prompts you to enter the `XXXX-XXXX` code in the terminal
74
- - Stores the JWT locally for subsequent CLI calls
72
+ `troxy login` uses a device-code flow:
73
+ - Opens your browser to the Troxy login page
74
+ - You log in and copy the code shown on the page
75
+ - Paste the code into the terminal
76
+ - Stores the JWT locally for 12 hours
75
77
 
76
78
  ## Stack
77
79
 
package/bin/troxy.js CHANGED
@@ -31,13 +31,16 @@ try { await _run(); } catch (err) { _handleError(err); }
31
31
  function _handleError(err) {
32
32
  if (err.code === 'UNAUTHORIZED') {
33
33
  const source = getKeySource();
34
- if (source === 'config') {
34
+ if (!source) {
35
+ // JWT-based command — session expired or not logged in
36
+ console.error('\n Session expired or not logged in. Run: troxy login\n');
37
+ } else if (source === 'config') {
35
38
  console.error('\n API key revoked or invalid.');
36
39
  console.error(' Your saved key is no longer accepted by Troxy.');
37
40
  console.error(' Run: npx troxy init --key <new-key> to reconnect.\n');
38
41
  } else {
39
42
  console.error('\n API key invalid or revoked.');
40
- console.error(' Check the key in your Troxy dashboard → Connections.\n');
43
+ console.error(' Check the key in your Troxy dashboard → API Keys.\n');
41
44
  }
42
45
  } else {
43
46
  console.error(`\n Error: ${err.message}\n`);
@@ -137,7 +140,8 @@ switch (command) {
137
140
  const category = flags.category;
138
141
  if (!merchant) { console.error(' --merchant is required\n'); process.exit(1); }
139
142
  if (isNaN(amount)){ console.error(' --amount is required\n'); process.exit(1); }
140
- const body = { card_alias: card, merchant_name: merchant, amount, agent: 'troxy-cli' };
143
+ const agentName = loadConfig()?.agentName || 'troxy-cli';
144
+ const body = { card_alias: card, merchant_name: merchant, amount, agent: agentName };
141
145
  if (category) body.merchant_category = category;
142
146
  const result = await api.evaluate(body, apiKey);
143
147
  const ICON = { ALLOW: '✓', BLOCK: '✗', ESCALATE: '⏳', NOTIFY: '~' };
@@ -251,6 +255,10 @@ switch (command) {
251
255
  console.log(`
252
256
  Troxy — AI payment control
253
257
 
258
+ First time? Run these two commands in order:
259
+ 1) npx troxy-cli init --key txy-... (get key from https://dash.troxy.io)
260
+ 2) troxy login (start a 12h CLI session)
261
+
254
262
  MCP setup (once per machine): troxy init --key <api-key>
255
263
  Login for CLI commands (12h): troxy login
256
264
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "troxy-cli",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "AI payment control — protect your agent's payments with policies",
5
5
  "type": "module",
6
6
  "bin": {
package/src/auth.js CHANGED
@@ -93,18 +93,49 @@ export async function runLogin() {
93
93
  const isHeadless = process.platform === 'linux' && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY;
94
94
  if (isHeadless) {
95
95
  console.log('\n Open this URL in your browser to get a login code:\n');
96
- console.log(` ${session.url}\n`);
96
+ console.log(` ${session.url}`);
97
+ console.log('\n (You\'ll need to sign in to your Troxy account, then copy the displayed code.)\n');
97
98
  } else {
98
99
  console.log('\n Opening browser to complete login...');
99
100
  console.log(` If it didn't open, visit:\n ${session.url}\n`);
100
101
  _openBrowser(session.url);
101
102
  }
102
103
 
103
- // 3. Prompt for the code shown in the browser
104
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
105
- const code = await new Promise(resolve =>
106
- rl.question(' Paste the code from your browser: ', ans => { rl.close(); resolve(ans.trim()); })
107
- );
104
+ // 3. Prompt for the code shown in the browser (masked like a password,
105
+ // one bullet per char so the terminal doesn't look frozen)
106
+ const code = await new Promise(resolve => {
107
+ const rl = readline.createInterface({ input: process.stdin, output: null });
108
+ process.stdout.write(' Paste the code from your browser: ');
109
+ let buf = '';
110
+ process.stdin.setRawMode(true);
111
+ process.stdin.resume();
112
+ process.stdin.setEncoding('utf8');
113
+ const onData = chunk => {
114
+ for (const ch of chunk) {
115
+ if (ch === '\r' || ch === '\n') {
116
+ process.stdin.setRawMode(false);
117
+ process.stdin.pause();
118
+ process.stdin.removeListener('data', onData);
119
+ rl.close();
120
+ process.stdout.write('\n');
121
+ resolve(buf.trim());
122
+ return;
123
+ } else if (ch === '\u0003') { // Ctrl-C
124
+ process.stdout.write('\n');
125
+ process.exit(0);
126
+ } else if (ch === '\u007f' || ch === '\b') { // backspace
127
+ if (buf.length > 0) {
128
+ buf = buf.slice(0, -1);
129
+ process.stdout.write('\b \b');
130
+ }
131
+ } else if (ch >= ' ') {
132
+ buf += ch;
133
+ process.stdout.write('•');
134
+ }
135
+ }
136
+ };
137
+ process.stdin.on('data', onData);
138
+ });
108
139
 
109
140
  if (!code) {
110
141
  console.error('\n No code entered. Run troxy login to try again.\n');
package/src/init.js CHANGED
@@ -73,12 +73,10 @@ export async function runInit({ key } = {}) {
73
73
  console.log('✓');
74
74
  }
75
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
- }
76
+ // Ask for agent name (default to hostname so users don't get stuck)
77
+ const defaultName = os.hostname() || 'my-agent';
78
+ const answer = await prompt(` Name this agent (press Enter for "${defaultName}"): `);
79
+ const agentName = answer || defaultName;
82
80
 
83
81
  // Save config
84
82
  saveConfig({ apiKey: key, agentName });
@@ -121,7 +119,10 @@ export async function runInit({ key } = {}) {
121
119
  }
122
120
 
123
121
  console.log('\n Your payments are now protected.');
124
- console.log(' Dashboard → https://dash.troxy.io\n');
122
+ console.log(' Dashboard → https://dash.troxy.io');
123
+ console.log('\n Try it:');
124
+ console.log(` troxy pay --merchant "Test" --amount 10`);
125
+ console.log(' This will appear in your dashboard within seconds.\n');
125
126
  }
126
127
 
127
128
  function installService(apiKey, agentName) {
package/src/mcp-server.js CHANGED
@@ -20,7 +20,17 @@ export async function runMcp() {
20
20
  }
21
21
 
22
22
  const server = new Server(
23
- { name: 'troxy', version: '0.1.0' },
23
+ {
24
+ name: 'troxy',
25
+ version: '0.1.0',
26
+ instructions:
27
+ 'You are connected to Troxy, a payment control system. ' +
28
+ 'You MUST call the evaluate_payment tool before completing any purchase, payment, or financial transaction. ' +
29
+ 'Never submit a payment form, confirm a checkout, or transfer funds without first receiving an ALLOW decision from evaluate_payment. ' +
30
+ 'If the decision is BLOCK, abort the transaction and inform the user. ' +
31
+ 'If the decision is ESCALATE, wait for human approval before proceeding. ' +
32
+ 'If the decision is NOTIFY, proceed but the user will be notified.',
33
+ },
24
34
  { capabilities: { tools: {} } },
25
35
  );
26
36