troxy-cli 1.2.6 → 1.2.8

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
@@ -2,7 +2,8 @@
2
2
  import { runInit } from '../src/init.js';
3
3
  import { runUninstall } from '../src/uninstall.js';
4
4
  import { runMcp } from '../src/mcp-server.js';
5
- import { runLogin, clearSession, requireKey, requireJwt, getKeySource } from '../src/auth.js';
5
+ import { runLogin, clearSession, requireKey, requireJwt, loadSession, getKeySource } from '../src/auth.js';
6
+ import { loadConfig } from '../src/config.js';
6
7
  import { runPolicies } from '../src/policies.js';
7
8
  import { runMcps } from '../src/mcps.js';
8
9
  import { runActivity } from '../src/activity.js';
@@ -162,9 +163,9 @@ switch (command) {
162
163
  break;
163
164
 
164
165
  case 'insights': {
165
- const apiKey = requireKey(flags);
166
+ const jwt = requireJwt();
166
167
  const period = Number(flags.period || 30);
167
- const data = await api.agentInsights(apiKey, period);
168
+ const data = await api.agentInsights(jwt, period);
168
169
  const d = data;
169
170
  console.log(`
170
171
  Insights — last ${d.period_days} days
@@ -204,27 +205,29 @@ switch (command) {
204
205
  process.stdout.write(` DB: ${health.db}\n`);
205
206
  process.stdout.write(` Env: ${health.env}\n`);
206
207
 
207
- // If we have a key, show enriched status
208
- try {
209
- const apiKey = requireKey(flags);
210
- const source = getKeySource();
211
- const data = await api.agentStatus(apiKey);
212
- const { token, account } = data;
213
- const keyNote = source === 'config'
214
- ? '(saved — run `troxy init` to change)'
215
- : source === 'env' ? '(from TROXY_API_KEY env)' : '(passed via --key)';
216
- console.log(`
217
- Key: ${token.prefix} ${keyNote}
218
- MCP: ${token.connected ? '● connected' : '○ offline'} last seen ${token.last_seen}
219
- Fallback: ${token.default_action}
220
-
208
+ // Account info from login session
209
+ const session = loadSession();
210
+ if (session?.jwt) {
211
+ try {
212
+ const data = await api.agentStatus(session.jwt);
213
+ const { account } = data;
214
+ console.log(`
221
215
  Account
222
216
  Active policies: ${account.active_policies}
223
217
  MCPs total: ${account.total_mcps} (${account.connected_mcps} connected)
224
218
  Requests 24h: ${account.requests_24h}
225
219
  Default action: ${account.default_action}
226
220
  `);
227
- } catch (err) { if (err.code === 'UNAUTHORIZED') throw err; console.log(); }
221
+ } catch { console.log(); }
222
+ } else {
223
+ console.log('\n Not logged in. Run: troxy login\n');
224
+ }
225
+
226
+ // MCP connection info from local config (set by troxy init)
227
+ const localKey = loadConfig()?.apiKey;
228
+ if (localKey) {
229
+ console.log(` MCP key: ${localKey.substring(0, 12)}... (saved — run \`troxy init\` to change)\n`);
230
+ }
228
231
 
229
232
  // Version check
230
233
  try {
@@ -248,35 +251,32 @@ switch (command) {
248
251
  console.log(`
249
252
  Troxy — AI payment control
250
253
 
251
- First time on a machine? Run: npx troxy init --key <api-key>
252
- This saves your key to ~/.troxy/config.json — no need to pass --key again.
254
+ MCP setup (once per machine): troxy init --key <api-key>
255
+ Login for CLI commands (12h): troxy login
253
256
 
254
- Setup
255
- troxy connect --key <api-key> Save API key (CLI only no MCP setup)
256
- troxy init --key <api-key> Full setup: save key + configure MCP
257
- troxy rotate-key Create new key + save it (requires login)
257
+ MCP Setup
258
+ troxy init --key <api-key> Connect this machine as an MCP + save key
259
+ troxy rotate-key Create new MCP key + save it
258
260
  troxy rotate-key --revoke-old Same + revoke the old key immediately
259
261
  troxy uninstall Remove Troxy from this machine
260
- troxy status API health + which key is in use
262
+ troxy status API health + account overview
261
263
 
262
- Simulate
263
- troxy pay --merchant "Amazon" --amount 50 --card "Work"
264
- troxy pay --merchant "Google" --amount 300 --card "Work" --category software
265
-
266
- Inspect (uses saved key — no flags needed after init)
264
+ Inspect (requires: troxy login)
267
265
  troxy policies list
268
266
  troxy policies describe --name "Block Amazon"
269
267
  troxy mcps list
270
268
  troxy activity [--limit 50] [--mine]
271
269
  troxy insights [--period 7]
272
270
 
273
- Manage (requires: npx troxy login)
271
+ Manage (requires: troxy login)
274
272
  troxy policies create --name "X" --action BLOCK --field amount --operator gte --value 500
275
273
  troxy policies enable --name "X"
276
274
  troxy policies disable --name "X"
277
275
  troxy policies delete --name "X"
278
276
 
279
- Override key for a single command: --key txy-...
277
+ Simulate (requires MCP key run troxy init first)
278
+ troxy pay --merchant "Amazon" --amount 50 --card "Work"
279
+ troxy pay --merchant "Google" --amount 300 --card "Work" --category software
280
280
  `);
281
281
  process.exit(command ? 1 : 0);
282
282
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "troxy-cli",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
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,15 @@
1
1
  import { api } from './api.js';
2
- import { requireKey } from './auth.js';
2
+ import { requireJwt } from './auth.js';
3
3
  import { table } from './print.js';
4
4
 
5
5
  const ICON = { ALLOW: '✓', BLOCK: '✗', ESCALATE: '⏳', NOTIFY: '~' };
6
6
 
7
7
  export async function runActivity(flags) {
8
- const apiKey = requireKey(flags);
9
- const limit = Number(flags.limit || 20);
10
- const mine = !!flags.mine;
8
+ const jwt = requireJwt();
9
+ const limit = Number(flags.limit || 20);
10
+ const mine = !!flags.mine;
11
11
 
12
- const data = await api.agentActivity(apiKey, limit, mine);
12
+ const data = await api.agentActivity(jwt, limit, mine);
13
13
  const rows = data?.activity || [];
14
14
 
15
15
  if (!rows.length) { console.log('\n No activity yet.\n'); return; }
package/src/api.js CHANGED
@@ -55,13 +55,13 @@ export const api = {
55
55
  // MCP heartbeat (agent API key)
56
56
  mcpHeartbeat: (apiKey, agentName) => request('POST', '/mcp/heartbeat', { apiKey, body: agentName ? { agent_name: agentName } : undefined }),
57
57
 
58
- // Agent read-only API (API key auth — no JWT required)
59
- agentStatus: (apiKey) => request('GET', '/agent/status', { apiKey }),
60
- agentPolicies: (apiKey) => request('GET', '/agent/policies', { apiKey }),
61
- agentMcps: (apiKey) => request('GET', '/agent/mcps', { apiKey }),
62
- agentCards: (apiKey) => request('GET', '/agent/cards', { apiKey }),
63
- agentActivity: (apiKey, limit, mine) => request('GET', `/agent/activity?limit=${limit || 20}${mine ? '&mine=true' : ''}`, { apiKey }),
64
- agentInsights: (apiKey, period) => request('GET', `/agent/insights?period=${period || 30}`, { apiKey }),
58
+ // Agent read-only API (JWT session auth — run: troxy login)
59
+ agentStatus: (jwt) => request('GET', '/agent/status', { jwt }),
60
+ agentPolicies: (jwt) => request('GET', '/agent/policies', { jwt }),
61
+ agentMcps: (jwt) => request('GET', '/agent/mcps', { jwt }),
62
+ agentCards: (jwt) => request('GET', '/agent/cards', { jwt }),
63
+ agentActivity: (jwt, limit, mine) => request('GET', `/agent/activity?limit=${limit || 20}${mine ? '&mine=true' : ''}`, { jwt }),
64
+ agentInsights: (jwt, period) => request('GET', `/agent/insights?period=${period || 30}`, { jwt }),
65
65
  };
66
66
 
67
67
  // Named export for backwards compat with init.js + mcp-server.js
package/src/auth.js CHANGED
@@ -27,7 +27,7 @@ export function clearSession() {
27
27
  export function requireJwt() {
28
28
  const session = loadSession();
29
29
  if (!session?.jwt) {
30
- console.error('\n Not logged in. Run: npx troxy login\n');
30
+ console.error('\n Not logged in. Run: troxy login\n');
31
31
  process.exit(1);
32
32
  }
33
33
  return session.jwt;
package/src/mcps.js CHANGED
@@ -1,14 +1,14 @@
1
- import { api } from './api.js';
2
- import { loadConfig } from './config.js';
3
- import { requireKey } from './auth.js';
4
- import { table } from './print.js';
1
+ import { api } from './api.js';
2
+ import { loadConfig } from './config.js';
3
+ import { requireJwt } from './auth.js';
4
+ import { table } from './print.js';
5
5
 
6
6
  export async function runMcps([sub], flags) {
7
- const apiKey = requireKey(flags);
7
+ const jwt = requireJwt();
8
8
 
9
9
  switch (sub || 'list') {
10
10
  case 'list': {
11
- const data = await api.agentMcps(apiKey);
11
+ const data = await api.agentMcps(jwt);
12
12
  const mcps = data?.mcps || [];
13
13
  if (!mcps.length) { console.log('\n No MCP connections yet.\n'); return; }
14
14
  console.log();
package/src/policies.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { api } from './api.js';
2
- import { requireJwt, requireKey } from './auth.js';
2
+ import { requireJwt } from './auth.js';
3
3
  import { table } from './print.js';
4
4
 
5
5
  const DECISION_ICON = { ALLOW: '✓', BLOCK: '✗', ESCALATE: '⏳', NOTIFY: '~', TIERED: '⊕' };
@@ -11,14 +11,14 @@ function _scope(p) {
11
11
  }
12
12
 
13
13
  export async function runPolicies([sub, ...args], flags) {
14
- // Read-only subcommands work with just an API key
14
+ // Read-only subcommands work with a login session
15
15
  const readOnly = !sub || sub === 'list' || sub === 'describe';
16
16
 
17
17
  if (readOnly) {
18
- const apiKey = requireKey(flags);
18
+ const jwt = requireJwt();
19
19
  switch (sub || 'list') {
20
20
  case 'list': {
21
- const data = await api.agentPolicies(apiKey);
21
+ const data = await api.agentPolicies(jwt);
22
22
  const policies = data?.policies || [];
23
23
  if (!policies.length) { console.log('\n No policies yet.\n'); return; }
24
24
  console.log();
@@ -40,7 +40,7 @@ export async function runPolicies([sub, ...args], flags) {
40
40
  case 'describe': {
41
41
  const name = flags.name;
42
42
  if (!name) { console.error(' --name is required (tip: use single quotes for names with special chars)\n'); process.exit(1); }
43
- const data = await api.agentPolicies(apiKey);
43
+ const data = await api.agentPolicies(jwt);
44
44
  const p = (data?.policies || []).find(x => x.name.toLowerCase() === name.toLowerCase());
45
45
  if (!p) { console.error(` Policy "${name}" not found\n`); process.exit(1); }
46
46