troxy-cli 1.2.4 → 1.2.6

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,7 @@
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, getKeySource } from '../src/auth.js';
5
+ import { runLogin, clearSession, requireKey, requireJwt, getKeySource } from '../src/auth.js';
6
6
  import { runPolicies } from '../src/policies.js';
7
7
  import { runMcps } from '../src/mcps.js';
8
8
  import { runActivity } from '../src/activity.js';
@@ -141,7 +141,8 @@ switch (command) {
141
141
  const result = await api.evaluate(body, apiKey);
142
142
  const ICON = { ALLOW: '✓', BLOCK: '✗', ESCALATE: '⏳', NOTIFY: '~' };
143
143
  const icon = ICON[result.decision] || '?';
144
- console.log(`\n ${icon} ${result.decision}${result.policy ? ` "${result.policy}"` : ' (default action)'}`);
144
+ const suffix = result.policy ? ` ← "${result.policy}"` : result.reason ? ` ${result.reason}` : ' (default action)';
145
+ console.log(`\n ${icon} ${result.decision}${suffix}`);
145
146
  if (result.audit_id) console.log(` audit: ${result.audit_id}`);
146
147
  console.log();
147
148
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "troxy-cli",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
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
@@ -16,7 +16,7 @@ export async function runActivity(flags) {
16
16
 
17
17
  console.log();
18
18
  table(
19
- ['Decision', 'Merchant', 'Category', 'Amount', 'Policy', 'Card', 'Agent', 'When'],
19
+ ['Decision', 'Merchant', 'Category', 'Amount', 'Policy', 'Agent', 'When'],
20
20
  rows.map(r => {
21
21
  const icon = ICON[r.decision?.split('→')[0]] || ' ';
22
22
  return [
@@ -24,8 +24,7 @@ export async function runActivity(flags) {
24
24
  r.merchant,
25
25
  r.category,
26
26
  r.amount ? `$${Number(r.amount).toFixed(2)}` : '—',
27
- r.policy,
28
- r.card,
27
+ r.decision_source === 'budget' ? 'budget limit' : r.policy,
29
28
  r.agent,
30
29
  r.when,
31
30
  ];
package/src/policies.js CHANGED
@@ -39,7 +39,7 @@ export async function runPolicies([sub, ...args], flags) {
39
39
 
40
40
  case 'describe': {
41
41
  const name = flags.name;
42
- if (!name) { console.error(' --name is required\n'); process.exit(1); }
42
+ if (!name) { console.error(' --name is required (tip: use single quotes for names with special chars)\n'); process.exit(1); }
43
43
  const data = await api.agentPolicies(apiKey);
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); }
@@ -105,7 +105,16 @@ export async function runPolicies([sub, ...args], flags) {
105
105
  const { policies = [] } = await api.listPolicies(jwt);
106
106
  const policy = policies.find(p => p.name === name);
107
107
  if (!policy) { console.error(` Policy "${name}" not found\n`); process.exit(1); }
108
- await api.updatePolicy(jwt, policy.id, { enabled: sub === 'enable' });
108
+ await api.updatePolicy(jwt, policy.id, {
109
+ name: policy.name,
110
+ action: policy.action,
111
+ description: policy.description || '',
112
+ conditions: policy.conditions || [],
113
+ or_conditions: policy.or_conditions || [],
114
+ tiers: policy.tiers || null,
115
+ global: policy.global !== false,
116
+ enabled: sub === 'enable',
117
+ });
109
118
  console.log(`\n Policy "${name}" ${sub}d ✓\n`);
110
119
  break;
111
120
  }
@@ -126,7 +135,17 @@ function _condSummary(p) {
126
135
  }
127
136
 
128
137
  function _condDetail(p) {
129
- const c = p.conditions || [];
130
- if (!c.length) return 'none (always matches)';
131
- return c.map(x => `${x.field} ${x.operator} ${x.value || ''}${x.value2 ? '–'+x.value2 : ''}`).join(' AND ');
138
+ const c = p.conditions || [];
139
+ const or = p.or_conditions || [];
140
+ const parts = [];
141
+ if (c.length) {
142
+ parts.push(c.map(x => `${x.field} ${x.operator} ${x.value || ''}${x.value2 ? '–'+x.value2 : ''}`).join(' AND '));
143
+ }
144
+ if (or.length) {
145
+ or.forEach(row => {
146
+ const conds = (row.conditions || []).map(x => `${x.field} ${x.operator} ${x.value || ''}`).join(' AND ');
147
+ parts.push(`${row.action}${conds ? ' if ' + conds : ''}`);
148
+ });
149
+ }
150
+ return parts.length ? parts.join('\n ') : 'none (always matches)';
132
151
  }
package/src/cards.js DELETED
@@ -1,63 +0,0 @@
1
- import { api } from './api.js';
2
- import { requireJwt, requireKey } from './auth.js';
3
- import { table } from './print.js';
4
-
5
- export async function runCards([sub, ...args], flags) {
6
- // list is read-only — works with API key
7
- if (!sub || sub === 'list') {
8
- const apiKey = requireKey(flags);
9
- const data = await api.agentCards(apiKey);
10
- const cards = data?.cards || [];
11
- if (!cards.length) { console.log('\n No cards yet.\n'); return; }
12
- console.log();
13
- table(
14
- ['Name', 'Last 4', 'Status', 'Budget', 'Used', 'Remaining', 'Default Action'],
15
- cards.map(c => [
16
- c.name,
17
- c.last_four ? `···${c.last_four}` : '—',
18
- c.status,
19
- c.monthly_budget ? `$${c.monthly_budget}` : 'no limit',
20
- `$${Number(c.budget_used || 0).toFixed(2)}`,
21
- c.budget_remaining != null ? `$${Number(c.budget_remaining).toFixed(2)}` : '—',
22
- c.default_action || 'ALLOW',
23
- ]),
24
- );
25
- return;
26
- }
27
-
28
- // Write operations need JWT
29
- const jwt = requireJwt();
30
-
31
- switch (sub) {
32
- case 'create': {
33
- const name = flags.name;
34
- if (!name) { console.error(' --name is required\n'); process.exit(1); }
35
- const body = {
36
- alias_name: name,
37
- monthly_budget: flags.budget ? Number(flags.budget) : null,
38
- provider: flags.provider || null,
39
- card_number: flags['card-number'] || null,
40
- status: 'active',
41
- };
42
- const card = await api.createCard(jwt, body);
43
- console.log(`\n Card "${card.alias_name}" created ✓\n`);
44
- break;
45
- }
46
-
47
- case 'delete': {
48
- const name = flags.name;
49
- if (!name) { console.error(' --name is required\n'); process.exit(1); }
50
- const data = await api.listCards(jwt);
51
- const card = (data?.cards || []).find(c => c.name === name);
52
- if (!card) { console.error(` Card "${name}" not found\n`); process.exit(1); }
53
- await api.deleteCard(jwt, card.id);
54
- console.log(`\n Card "${name}" deleted ✓\n`);
55
- break;
56
- }
57
-
58
- default:
59
- console.error(` Unknown subcommand: ${sub}`);
60
- console.error(' Usage: troxy cards [list|create|delete]\n');
61
- process.exit(1);
62
- }
63
- }