troxy-cli 1.21.1 → 1.23.0

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
@@ -50,8 +50,9 @@ npx troxy-cli <command>
50
50
  |---------|-------------|
51
51
  | `troxy init` | Connect an agent to Troxy — validates API key, sets agent name, patches MCP configs |
52
52
  | `troxy login` | Start a 12-hour CLI session (opens browser → copy code → paste into terminal) |
53
+ | `troxy tools` | Scan for installed AI coding tools and set your subscription plan for each |
53
54
  | `troxy mcps` | List connected MCP agents and their status |
54
- | `troxy policies` | List and manage policies |
55
+ | `troxy policies` | List every org/space policy that applies to you (creating one is admin-only) |
55
56
  | `troxy activity` | View recent transaction audit log |
56
57
  | `troxy insights` | Spending stats and decision breakdown |
57
58
  | `troxy status` | Show connection status and account overview |
package/bin/troxy.js CHANGED
@@ -9,24 +9,32 @@ import { runPolicies } from '../src/policies.js';
9
9
  import { runMcps } from '../src/mcps.js';
10
10
  import { runActivity } from '../src/activity.js';
11
11
  import { runSettings } from '../src/settings.js';
12
- import { runChatBudget } from '../src/chat-budget.js';
13
12
  import { runApprovals } from '../src/approvals.js';
14
13
  import { runAccount } from '../src/account.js';
15
14
  import { runSecrets } from '../src/secrets.js';
16
15
  import { api } from '../src/api.js';
17
16
  import { table } from '../src/print.js';
17
+ import { printSimHelp, runSend, runSignin, runAction, runModelCall, runScan } from '../src/simulate.js';
18
18
 
19
19
  const [,, command, sub, ...rest] = process.argv;
20
20
  const allArgs = [sub, ...rest].filter(Boolean);
21
21
 
22
- // Parse --flag value pairs
22
+ // Parse --flag value pairs. `flags[key]` keeps its original "last occurrence
23
+ // wins" behavior unchanged, for every existing caller that reads it as a
24
+ // plain string. `multiFlags[key]` is new and purely additive: every
25
+ // occurrence of a repeatable flag (e.g. `--and field=... --and field=...`,
26
+ // used by `policies create` to build multi-condition policies), in order.
27
+ // Nothing that doesn't opt into reading multiFlags is affected.
23
28
  const flags = {};
29
+ const multiFlags = {};
24
30
  const positional = [];
25
31
  for (let i = 0; i < allArgs.length; i++) {
26
32
  if (allArgs[i].startsWith('--')) {
27
33
  const key = allArgs[i].slice(2);
28
34
  const next = allArgs[i + 1];
29
- flags[key] = next && !next.startsWith('--') ? allArgs[++i] : true;
35
+ const val = next && !next.startsWith('--') ? allArgs[++i] : true;
36
+ flags[key] = val;
37
+ (multiFlags[key] ||= []).push(val);
30
38
  } else {
31
39
  positional.push(allArgs[i]);
32
40
  }
@@ -77,6 +85,33 @@ switch (command) {
77
85
  await runInit(flags);
78
86
  break;
79
87
 
88
+ case 'tools': {
89
+ if (flags.help || flags.h) {
90
+ console.log(`
91
+ troxy tools
92
+
93
+ Re-scans this machine for AI coding tools (Claude Code, Cursor, GitHub
94
+ Copilot, Windsurf, Continue, Aider) and lets you set the subscription plan
95
+ for each, so the dashboard shows what you actually pay instead of raw
96
+ token estimates. Run this any time your plan changes.
97
+ `);
98
+ process.exit(0);
99
+ }
100
+ const apiKey = loadConfig()?.apiKey || process.env.TROXY_API_KEY;
101
+ if (!apiKey) {
102
+ console.error('\n Not connected. Run "troxy init --key <your-key>" first.\n');
103
+ process.exit(1);
104
+ }
105
+ const { runToolDetection, detectAiTools } = await import('../src/tool_detect.js');
106
+ if (detectAiTools().every(d => !d.installed)) {
107
+ console.log('\n No supported AI coding tools detected on this machine.\n');
108
+ break;
109
+ }
110
+ await runToolDetection(apiKey, { interactive: true });
111
+ console.log(' Saved ✓ See it at https://dash.troxy.io\n');
112
+ break;
113
+ }
114
+
80
115
  case 'uninstall':
81
116
  await runUninstall();
82
117
  break;
@@ -286,9 +321,39 @@ switch (command) {
286
321
  break;
287
322
  }
288
323
 
324
+ // ── Simulate the other five checkpoints ────────────────────────
325
+ // `pay` above covers /evaluate (payment). Until these existed it was the
326
+ // only checkpoint testable from the CLI, even though the product had
327
+ // grown five more - api.js already had wrappers for four of them sitting
328
+ // unused, and evaluateSecrets was missing outright. See src/simulate.js.
329
+ case 'send':
330
+ if (flags.help || flags.h) { printSimHelp('send'); process.exit(0); }
331
+ await runSend(flags);
332
+ break;
333
+
334
+ case 'signin':
335
+ if (flags.help || flags.h) { printSimHelp('signin'); process.exit(0); }
336
+ await runSignin(flags);
337
+ break;
338
+
339
+ case 'action':
340
+ if (flags.help || flags.h) { printSimHelp('action'); process.exit(0); }
341
+ await runAction(flags);
342
+ break;
343
+
344
+ case 'model-call':
345
+ if (flags.help || flags.h) { printSimHelp('model-call'); process.exit(0); }
346
+ await runModelCall(flags);
347
+ break;
348
+
349
+ case 'scan':
350
+ if (flags.help || flags.h) { printSimHelp('scan'); process.exit(0); }
351
+ await runScan(flags);
352
+ break;
353
+
289
354
  // ── Resources (read-only: --key or saved config; write: login) ─
290
355
  case 'policies':
291
- await runPolicies(positional, flags);
356
+ await runPolicies(positional, flags, multiFlags);
292
357
  break;
293
358
 
294
359
  case 'mcps':
@@ -303,10 +368,6 @@ switch (command) {
303
368
  await runSettings(positional, flags);
304
369
  break;
305
370
 
306
- case 'chat-budget':
307
- await runChatBudget(positional, flags);
308
- break;
309
-
310
371
  case 'approvals':
311
372
  await runApprovals(positional, flags);
312
373
  break;
@@ -588,6 +649,7 @@ switch (command) {
588
649
  troxy init --key <api-key> Connect this machine as an MCP + save key
589
650
  troxy init --key <api-key> --name "My Agent" Same, no interactive prompt
590
651
  (for cloud/scripted agents that can't answer stdin)
652
+ troxy tools Scan for AI tools + set your subscription plans
591
653
  troxy restart Restart the MCP background service
592
654
  troxy uninstall Remove Troxy from this machine
593
655
  troxy status API health + MCP status (no login needed)
@@ -609,17 +671,27 @@ switch (command) {
609
671
  Keys
610
672
  troxy rotate-key Rotate MCP key (revokes old, saves new locally)
611
673
 
612
- Policies
613
- troxy policies list
674
+ Policies (all six checkpoints: payment, comms, access, destructive, model, secrets)
675
+ Admin-only: every write below requires --org. Personal and per-MCP policies
676
+ no longer exist - a policy is always org-wide or space-wide, and org acts as
677
+ a ceiling a space policy can never be looser than. list/describe/test need
678
+ no --org and show every org + space policy that applies to you.
679
+ troxy policies list / list --org
614
680
  troxy policies describe --name "Block Amazon"
615
- troxy policies create --describe "block Amazon purchases over $200" (AI builder)
616
- troxy policies create --name "X" --action BLOCK --field amount --operator gte --value 500
617
- troxy policies create --name "X" --action BLOCK --mcp "My Laptop,Server" (scoped to specific MCPs)
618
- troxy policies create --name "X" --action ESCALATE --chat (scoped to Troxy Chat only)
619
- troxy policies set-priority --name "X" --priority 10
620
- troxy policies pause --name "X"
621
- troxy policies resume --name "X"
622
- troxy policies delete --name "X"
681
+ troxy policies templates (browse the built-in library)
682
+ troxy policies fields --domain secrets (see what each checkpoint supports)
683
+ troxy policies create --describe "block Amazon purchases over $200" --org (AI builder, payment/comms only)
684
+ troxy policies create --name "X" --template "Block a secret going somewhere public" --org
685
+ troxy policies create --name "X" --action BLOCK --domain payment --field amount --operator gte --value 500 --org
686
+ troxy policies create --name "X" --action BLOCK --domain access --field login_action --operator eq --value signup --org
687
+ troxy policies create --name "X" --action BLOCK --domain comms --or "field=recipient_domain,operator=contains,value=gmail.com" --org
688
+ troxy policies create --name "X" --action BLOCK --domain secrets --field has_api_key --operator eq --value true --org
689
+ troxy policies test --domain payment --field amount --operator gt --value 100 --example '{"amount": 150}'
690
+ troxy policies set-priority --name "X" --priority 10 --org
691
+ troxy policies pause --name "X" --org
692
+ troxy policies resume --name "X" --org
693
+ troxy policies delete --name "X" --org
694
+ (--org needs admin access; run 'troxy policies create --help' for the full condition syntax)
623
695
 
624
696
  Approvals (ESCALATE holds)
625
697
  troxy approvals list
@@ -629,10 +701,8 @@ switch (command) {
629
701
  Settings
630
702
  troxy settings show
631
703
  troxy settings set --default-action BLOCK --approval-timeout 4
632
- troxy chat-budget show
633
- troxy chat-budget set --currency USD --limit 500
634
704
 
635
- LLM keys (Troxy Chat)
705
+ LLM provider keys
636
706
  troxy secrets list
637
707
  troxy secrets set --name "OpenAI"
638
708
  troxy secrets delete --name "OpenAI"
@@ -645,9 +715,14 @@ switch (command) {
645
715
  troxy activity [--limit 50] [--mine]
646
716
  troxy insights [--period 7]
647
717
 
648
- Simulate
718
+ Simulate (test your policies against every checkpoint, not just payment)
649
719
  troxy pay --merchant "Amazon" --amount 50
650
720
  troxy pay --merchant "Google" --amount 300 --category software
721
+ troxy send --recipient jane@gmail.com --body "the password is hunter2"
722
+ troxy signin --site coinbase.com --type signup
723
+ troxy action --verb delete --resource "prod users table" --items 500
724
+ troxy model-call --model claude-opus-5 --provider anthropic --cost 4.50
725
+ troxy scan --content "AWS_SECRET_ACCESS_KEY=..." --destination public --do push
651
726
  `);
652
727
  process.exit(command ? 1 : 0);
653
728
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "troxy-cli",
3
- "version": "1.21.1",
4
- "description": "Control layer for AI agents: check payments, emails, logins and destructive actions against your policies",
3
+ "version": "1.23.0",
4
+ "description": "A secure control layer for AI agents: policies across payments, messages, logins, destructive actions, model usage, and secrets, all enforceable from the CLI",
5
5
  "homepage": "https://troxy.io",
6
6
  "bugs": {
7
7
  "email": "support@troxy.io"
@@ -26,9 +26,12 @@
26
26
  "keywords": [
27
27
  "mcp",
28
28
  "ai",
29
- "payments",
29
+ "agents",
30
30
  "policy",
31
- "agents"
31
+ "guardrails",
32
+ "control-layer",
33
+ "payments",
34
+ "secrets"
32
35
  ],
33
36
  "license": "MIT"
34
37
  }
package/src/api.js CHANGED
@@ -52,6 +52,17 @@ export const api = {
52
52
  createPolicy: (jwt, b) => request('POST', '/dashboard/policies', { jwt, body: b }),
53
53
  updatePolicy: (jwt, id, b) => request('PATCH', `/dashboard/policies/${id}`, { jwt, body: b }),
54
54
  deletePolicy: (jwt, id) => request('DELETE', `/dashboard/policies/${id}`, { jwt }),
55
+ // Would-this-rule-fire, without saving it. Same evaluator the checkpoints
56
+ // use, so a condition that previews as firing is trusted, not guessed.
57
+ previewPolicy: (jwt, b) => request('POST', '/dashboard/policies/preview', { jwt, body: b }),
58
+
59
+ // Org (admin can write, any active member can read - see orgs.py's
60
+ // is_org_admin vs is_org_member split). org_id comes from currentOrg().
61
+ currentOrg: (jwt) => request('GET', '/orgs/current', { jwt }),
62
+ listOrgPolicies: (jwt, orgId) => request('GET', `/orgs/${orgId}/policies`, { jwt }),
63
+ createOrgPolicy: (jwt, orgId, b) => request('POST', `/orgs/${orgId}/policies`, { jwt, body: b }),
64
+ updateOrgPolicy: (jwt, orgId, id, b) => request('PATCH', `/orgs/${orgId}/policies/${id}`, { jwt, body: b }),
65
+ deleteOrgPolicy: (jwt, orgId, id) => request('DELETE', `/orgs/${orgId}/policies/${id}`, { jwt }),
55
66
 
56
67
  // Activity + insights
57
68
  activity: (jwt, limit) => request('GET', `/dashboard/activity?limit=${limit || 20}`, { jwt }),
@@ -67,7 +78,6 @@ export const api = {
67
78
  // Account settings
68
79
  getSettings: (jwt) => request('GET', '/dashboard/settings', { jwt }),
69
80
  updateSettings: (jwt, b) => request('PATCH', '/dashboard/settings', { jwt, body: b }),
70
- updateChatBudget: (jwt, b) => request('PATCH', '/dashboard/chat-budget', { jwt, body: b }),
71
81
 
72
82
  // Approvals
73
83
  listApprovals: (jwt) => request('GET', '/dashboard/approvals', { jwt }),
@@ -94,6 +104,9 @@ export const api = {
94
104
  // Only the pair produces usable data. The estimate alone is the agent's own
95
105
  // guess, and Token Optimization says so on every agent that never reports.
96
106
  evaluateModel: (body, apiKey) => request('POST', '/evaluate/model', { apiKey, body }),
107
+ // Was missing entirely - every other checkpoint had a wrapper here, secrets
108
+ // did not, which is part of why nothing in the CLI could exercise it.
109
+ evaluateSecrets: (body, apiKey) => request('POST', '/evaluate/secrets', { apiKey, body }),
97
110
  reportModelUsage: (body, apiKey) => request('POST', '/evaluate/model/complete', { apiKey, body }),
98
111
  // Real, host-captured usage for a turn that already happened - not an
99
112
  // agent's self-report of what it thinks it used. Called only by the
@@ -119,6 +132,10 @@ export const api = {
119
132
  // MCP status (agent API key — no login needed)
120
133
  mcpStatus: (apiKey) => request('GET', '/mcp/status', { apiKey }),
121
134
 
135
+ // AI tool inventory + subscription plans, self-reported by `troxy init` /
136
+ // `troxy tools`. Agent API key auth, same as the evaluate/heartbeat paths.
137
+ reportToolPlans: (apiKey, tools) => request('POST', '/agents/tool-plans', { apiKey, body: { tools } }),
138
+
122
139
  // Setup instructions for an agent with no MCP client to configure. Fetched
123
140
  // rather than hardcoded so a new checkpoint reaches agents without an npm
124
141
  // release — a cloud agent runs init once and never upgrades the package.