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 +3 -2
- package/package.json +1 -1
- package/src/activity.js +2 -3
- package/src/policies.js +24 -5
- package/src/cards.js +0 -63
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
|
-
|
|
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
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', '
|
|
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, {
|
|
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
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
}
|