@plexor-dev/claude-code-plugin 0.1.0-beta.2 → 0.1.0-beta.20

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.
@@ -0,0 +1,134 @@
1
+ ---
2
+ description: First-time setup wizard for Plexor with Claude Code (user)
3
+ ---
4
+
5
+ # Plexor Setup Wizard
6
+
7
+ Guide users through first-time Plexor setup, handling both Claude MAX subscribers and API key users.
8
+
9
+ ## Steps
10
+
11
+ **Step 1: Check if already configured**
12
+
13
+ Use the Read tool to check if `~/.plexor/config.json` exists and has valid configuration.
14
+
15
+ If configured, show:
16
+ ```
17
+ Plexor Setup
18
+ ============
19
+ Already configured!
20
+
21
+ API URL: [apiUrl from config]
22
+ Mode: [mode from config]
23
+ Status: [Enabled/Disabled]
24
+
25
+ Run /plexor-status to see your usage.
26
+ Run /plexor-settings to modify configuration.
27
+ ```
28
+
29
+ **Step 2: Ask about Claude MAX subscription**
30
+
31
+ Use the AskUserQuestion tool:
32
+
33
+ Question: "Do you have a Claude MAX subscription (Pro/Team/Enterprise)?"
34
+ Header: "Subscription"
35
+ Options:
36
+ 1. **Yes, I have Claude MAX** - I'm already logged into Claude Code with OAuth
37
+ 2. **No, I'll use a Plexor API key** - I want to use Plexor's provider routing
38
+
39
+ **Step 3A: Claude MAX User Setup**
40
+
41
+ If user selected "Yes, I have Claude MAX":
42
+
43
+ 1. Use the Write tool to create `~/.plexor/config.json`:
44
+ ```json
45
+ {
46
+ "version": 1,
47
+ "auth": {
48
+ "mode": "oauth_passthrough",
49
+ "authenticated_at": "[current ISO timestamp]"
50
+ },
51
+ "settings": {
52
+ "enabled": true,
53
+ "apiUrl": "https://api.plexor.dev",
54
+ "mode": "balanced",
55
+ "localCacheEnabled": true
56
+ }
57
+ }
58
+ ```
59
+
60
+ 2. Show the user:
61
+ ```
62
+ Plexor Setup - Claude MAX User
63
+ ==============================
64
+ Your Claude MAX subscription will be used with Plexor optimization.
65
+
66
+ Add this to your shell profile (~/.bashrc or ~/.zshrc):
67
+
68
+ export ANTHROPIC_BASE_URL="https://api.plexor.dev/gateway/anthropic"
69
+
70
+ Then restart your terminal or run: source ~/.bashrc
71
+
72
+ How it works:
73
+ - Claude Code sends your OAuth token through Plexor
74
+ - Plexor optimizes prompts and tracks usage
75
+ - You keep your MAX benefits ($0 cost, 20x rate limits)
76
+
77
+ Run /plexor-status to verify setup.
78
+ ```
79
+
80
+ **Step 3B: API Key User Setup**
81
+
82
+ If user selected "No, I'll use a Plexor API key":
83
+
84
+ 1. Ask for their Plexor API key:
85
+ "Please provide your Plexor API key (starts with 'plx_')."
86
+ "Get one at: https://plexor.dev/dashboard"
87
+
88
+ 2. Once they provide the key, use the Write tool to create `~/.plexor/config.json`:
89
+ ```json
90
+ {
91
+ "version": 1,
92
+ "auth": {
93
+ "api_key": "[user's API key]",
94
+ "mode": "api_key",
95
+ "authenticated_at": "[current ISO timestamp]"
96
+ },
97
+ "settings": {
98
+ "enabled": true,
99
+ "apiUrl": "https://api.plexor.dev",
100
+ "preferred_provider": "auto",
101
+ "mode": "balanced",
102
+ "localCacheEnabled": true
103
+ }
104
+ }
105
+ ```
106
+
107
+ 3. Show the user:
108
+ ```
109
+ Plexor Setup - API Key User
110
+ ===========================
111
+ Your Plexor API key has been configured.
112
+
113
+ Add these lines to your shell profile (~/.bashrc or ~/.zshrc):
114
+
115
+ export ANTHROPIC_BASE_URL="https://api.plexor.dev/gateway/anthropic"
116
+ export ANTHROPIC_API_KEY="[their plexor key]"
117
+
118
+ Then restart your terminal or run: source ~/.bashrc
119
+
120
+ How it works:
121
+ - Requests route through Plexor gateway
122
+ - Plexor picks the best provider (can save up to 90%)
123
+ - Your Plexor key goes in ANTHROPIC_API_KEY (this is correct!)
124
+
125
+ Run /plexor-status to verify setup.
126
+ ```
127
+
128
+ **Step 4: Offer to auto-configure shell (optional)**
129
+
130
+ Ask: "Would you like me to add this to your shell profile automatically?"
131
+
132
+ If yes, use the Edit tool to append the export lines to `~/.bashrc` (or `~/.zshrc` if it exists).
133
+
134
+ **IMPORTANT**: After completing setup, STOP. Do not run additional commands.
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Plexor Status Command
5
+ * Displays formatted status with usage statistics
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const https = require('https');
11
+
12
+ const CONFIG_PATH = path.join(process.env.HOME, '.plexor', 'config.json');
13
+ const SESSION_PATH = path.join(process.env.HOME, '.plexor', 'session.json');
14
+ const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
15
+
16
+ function loadSessionStats() {
17
+ try {
18
+ const data = fs.readFileSync(SESSION_PATH, 'utf8');
19
+ const session = JSON.parse(data);
20
+ // Check if session has expired
21
+ if (Date.now() - session.last_activity > SESSION_TIMEOUT_MS) {
22
+ return null;
23
+ }
24
+ return session;
25
+ } catch {
26
+ return null;
27
+ }
28
+ }
29
+
30
+ async function main() {
31
+ // Read config
32
+ let config;
33
+ try {
34
+ const data = fs.readFileSync(CONFIG_PATH, 'utf8');
35
+ config = JSON.parse(data);
36
+ } catch (err) {
37
+ console.log('Not configured. Run /plexor-login first.');
38
+ process.exit(1);
39
+ }
40
+
41
+ const apiKey = config.auth?.api_key;
42
+ const enabled = config.settings?.enabled ?? false;
43
+ const mode = config.settings?.mode || 'balanced';
44
+ const provider = config.settings?.preferred_provider || 'auto';
45
+ const localCache = config.settings?.localCacheEnabled ?? false;
46
+ const apiUrl = config.settings?.apiUrl || 'https://api.plexor.dev';
47
+
48
+ if (!apiKey) {
49
+ console.log('Not authenticated. Run /plexor-login first.');
50
+ process.exit(1);
51
+ }
52
+
53
+ // Fetch user info and stats
54
+ let user = { email: 'Unknown', tier: { name: 'Free', limits: {} } };
55
+ let stats = { period: {}, summary: {} };
56
+
57
+ try {
58
+ [user, stats] = await Promise.all([
59
+ fetchJson(apiUrl, '/v1/user', apiKey),
60
+ fetchJson(apiUrl, '/v1/stats', apiKey)
61
+ ]);
62
+ } catch (err) {
63
+ // Continue with defaults if API fails
64
+ }
65
+
66
+ // Load session stats
67
+ const session = loadSessionStats();
68
+
69
+ // Extract data
70
+ const email = user.email || 'Unknown';
71
+ const tierName = user.tier?.name || 'Free';
72
+ const monthlyOpts = user.tier?.limits?.monthly_optimizations || '∞';
73
+ const monthlyComps = user.tier?.limits?.monthly_completions || '∞';
74
+
75
+ const period = stats.period || {};
76
+ const summary = stats.summary || {};
77
+
78
+ const formatDate = (iso) => {
79
+ if (!iso) return '?';
80
+ const d = new Date(iso);
81
+ return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
82
+ };
83
+ const weekRange = `${formatDate(period.start)} - ${formatDate(period.end)}`;
84
+
85
+ // Format numbers
86
+ const formatNum = (n) => (n || 0).toLocaleString();
87
+ const formatPct = (n) => (n || 0).toFixed(1);
88
+ const formatCost = (n) => (n || 0).toFixed(2);
89
+
90
+ const status = enabled ? '● Active' : '○ Inactive';
91
+ const optEnabled = enabled ? 'Enabled' : 'Disabled';
92
+ const cacheEnabled = localCache ? 'Enabled' : 'Disabled';
93
+ const cacheRate = formatPct((summary.cache_hit_rate || 0) * 100);
94
+
95
+ // Build dashboard URL from API URL
96
+ // API: https://api.plexor.dev or https://staging.api.plexor.dev
97
+ // Dashboard: https://plexor.dev/dashboard or https://staging.plexor.dev/dashboard
98
+ let dashboardUrl = 'https://plexor.dev/dashboard';
99
+ try {
100
+ const url = new URL(apiUrl);
101
+ // Remove 'api.' prefix from hostname if present
102
+ const host = url.hostname.replace(/^api\./, '').replace(/\.api\./, '.');
103
+ dashboardUrl = `${url.protocol}//${host}/dashboard`;
104
+ } catch {
105
+ // If URL parsing fails, use default
106
+ }
107
+
108
+ // Output formatted status - each line is exactly 43 chars inner width
109
+ const line = (content) => ` │ ${content.padEnd(43)}│`;
110
+
111
+ // Session stats formatting
112
+ const formatDuration = (startedAt) => {
113
+ if (!startedAt) return '0m';
114
+ const elapsed = Date.now() - new Date(startedAt).getTime();
115
+ const minutes = Math.floor(elapsed / 60000);
116
+ if (minutes < 60) return `${minutes}m`;
117
+ const hours = Math.floor(minutes / 60);
118
+ return `${hours}h ${minutes % 60}m`;
119
+ };
120
+
121
+ const sessionDuration = session ? formatDuration(session.started_at) : '0m';
122
+ const sessionRequests = session ? formatNum(session.requests) : '0';
123
+ const sessionOptimizations = session ? formatNum(session.optimizations) : '0';
124
+ const sessionCacheHits = session ? formatNum(session.cache_hits) : '0';
125
+ const sessionTokensSaved = session ? formatNum(session.tokens_saved) : '0';
126
+ const sessionTokensSavedPct = session && session.original_tokens > 0
127
+ ? formatPct((session.tokens_saved / session.original_tokens) * 100)
128
+ : '0.0';
129
+ const sessionCostSaved = session ? formatCost(session.cost_saved) : '0.00';
130
+
131
+ // Build session section (only show if session exists)
132
+ const sessionSection = session ? ` ├─────────────────────────────────────────────┤
133
+ ${line(`This Session (${sessionDuration})`)}
134
+ ${line(`├── Requests: ${sessionRequests}`)}
135
+ ${line(`├── Optimizations: ${sessionOptimizations}`)}
136
+ ${line(`├── Cache hits: ${sessionCacheHits}`)}
137
+ ${line(`├── Tokens saved: ${sessionTokensSaved} (${sessionTokensSavedPct}%)`)}
138
+ ${line(`└── Cost saved: $${sessionCostSaved}`)}
139
+ ` : '';
140
+
141
+ console.log(` ┌─────────────────────────────────────────────┐
142
+ ${line('Plexor Status')}
143
+ ├─────────────────────────────────────────────┤
144
+ ${line(`Account: ${tierName}`)}
145
+ ${line(`Email: ${email}`)}
146
+ ${line(`Status: ${status}`)}
147
+ ${sessionSection} ├─────────────────────────────────────────────┤
148
+ ${line(`This Week (${weekRange})`)}
149
+ ${line(`├── Requests: ${formatNum(summary.total_requests)}`)}
150
+ ${line(`├── Original tokens: ${formatNum(summary.original_tokens)}`)}
151
+ ${line(`├── Optimized tokens: ${formatNum(summary.optimized_tokens)}`)}
152
+ ${line(`├── Tokens saved: ${formatNum(summary.tokens_saved)} (${formatPct(summary.tokens_saved_percent)}%)`)}
153
+ ${line(`├── Baseline cost: $${formatCost(summary.baseline_cost)}`)}
154
+ ${line(`├── Actual cost: $${formatCost(summary.total_cost)}`)}
155
+ ${line(`└── Cost saved: $${formatCost(summary.cost_saved)} (${formatPct(summary.cost_saved_percent)}%)`)}
156
+ ├─────────────────────────────────────────────┤
157
+ ${line('Performance')}
158
+ ${line(`└── Cache hit rate: ${cacheRate}%`)}
159
+ ├─────────────────────────────────────────────┤
160
+ ${line('Limits')}
161
+ ${line(`├── Monthly optimizations: ${formatNum(monthlyOpts)}`)}
162
+ ${line(`└── Monthly completions: ${formatNum(monthlyComps)}`)}
163
+ ├─────────────────────────────────────────────┤
164
+ ${line('Settings')}
165
+ ${line(`├── Optimization: ${optEnabled}`)}
166
+ ${line(`├── Local cache: ${cacheEnabled}`)}
167
+ ${line(`├── Mode: ${mode}`)}
168
+ ${line(`└── Provider routing: ${provider}`)}
169
+ └─────────────────────────────────────────────┘
170
+
171
+ Dashboard: ${dashboardUrl}
172
+ `);
173
+ }
174
+
175
+ function fetchJson(apiUrl, endpoint, apiKey) {
176
+ return new Promise((resolve, reject) => {
177
+ const url = new URL(`${apiUrl}${endpoint}`);
178
+
179
+ const options = {
180
+ hostname: url.hostname,
181
+ port: 443,
182
+ path: url.pathname,
183
+ method: 'GET',
184
+ headers: {
185
+ 'X-Plexor-Key': apiKey
186
+ }
187
+ };
188
+
189
+ const req = https.request(options, (res) => {
190
+ let data = '';
191
+ res.on('data', chunk => data += chunk);
192
+ res.on('end', () => {
193
+ try {
194
+ resolve(JSON.parse(data));
195
+ } catch {
196
+ reject(new Error('Invalid response'));
197
+ }
198
+ });
199
+ });
200
+
201
+ req.on('error', reject);
202
+ req.setTimeout(5000, () => {
203
+ req.destroy();
204
+ reject(new Error('Timeout'));
205
+ });
206
+ req.end();
207
+ });
208
+ }
209
+
210
+ main().catch(err => {
211
+ console.error('Error:', err.message);
212
+ process.exit(1);
213
+ });
@@ -1,46 +1,21 @@
1
1
  ---
2
- description: Show Plexor optimization statistics and savings
2
+ description: Show Plexor optimization statistics and savings (user)
3
3
  ---
4
4
 
5
5
  # Plexor Status
6
6
 
7
- Display current Plexor status, configuration, and usage statistics.
7
+ Run this command to display Plexor statistics:
8
8
 
9
- ## Instructions
10
-
11
- 1. Read the Plexor configuration from ~/.plexor/config.json
12
- 2. If not authenticated, show a message to run /plexor-login
13
- 3. If authenticated, call the Plexor API to get usage stats
14
- 4. Display a formatted summary including:
15
- - Account status (Free/Pro/Team)
16
- - This session: requests optimized, tokens saved, estimated savings
17
- - This week: total requests, total tokens saved, total savings
18
- - Current settings: optimization enabled, local cache status
9
+ ```bash
10
+ node ~/.claude/plugins/plexor/commands/plexor-status.js
11
+ ```
19
12
 
20
- ## Output Format
13
+ Use the Bash tool to execute this single command.
21
14
 
22
- ```
23
- ┌─────────────────────────────────────────────┐
24
- │ Plexor Status │
25
- ├─────────────────────────────────────────────┤
26
- │ Account: Pro ($19/mo) │
27
- │ Status: ● Active │
28
- ├─────────────────────────────────────────────┤
29
- │ This Session │
30
- │ ├── Requests: 47 │
31
- │ ├── Tokens saved: 12,847 (31%) │
32
- │ └── Est. savings: $0.42 │
33
- ├─────────────────────────────────────────────┤
34
- │ This Week │
35
- │ ├── Requests: 1,247 │
36
- │ ├── Tokens saved: 482,938 (34%) │
37
- │ └── Est. savings: $14.23 │
38
- ├─────────────────────────────────────────────┤
39
- │ Settings │
40
- │ ├── Optimization: Enabled │
41
- │ ├── Local cache: Enabled │
42
- │ └── Provider routing: DeepSeek preferred │
43
- └─────────────────────────────────────────────┘
15
+ **IMPORTANT**: After running this command and displaying the output, STOP. Do not:
16
+ - Read any files
17
+ - Explore the codebase
18
+ - Run additional commands
19
+ - Ask follow-up questions
44
20
 
45
- Dashboard: https://plexor.dev/dashboard
46
- ```
21
+ The command output is the complete response. Simply show the output and wait for the user's next input.