@plexor-dev/claude-code-plugin 0.1.0-beta.7 → 0.1.0-beta.9

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,192 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Plexor Status Command
5
+ * Displays formatted status with usage statistics and ANSI colors
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
+
14
+ // ANSI color codes
15
+ const c = {
16
+ reset: '\x1b[0m',
17
+ bold: '\x1b[1m',
18
+ dim: '\x1b[2m',
19
+ green: '\x1b[32m',
20
+ yellow: '\x1b[33m',
21
+ blue: '\x1b[34m',
22
+ magenta: '\x1b[35m',
23
+ cyan: '\x1b[36m',
24
+ white: '\x1b[37m',
25
+ gray: '\x1b[90m',
26
+ bgBlue: '\x1b[44m',
27
+ bgGreen: '\x1b[42m',
28
+ bgYellow: '\x1b[43m',
29
+ bgGray: '\x1b[100m',
30
+ };
31
+
32
+ async function main() {
33
+ // Read config
34
+ let config;
35
+ try {
36
+ const data = fs.readFileSync(CONFIG_PATH, 'utf8');
37
+ config = JSON.parse(data);
38
+ } catch (err) {
39
+ console.log(`${c.yellow}Not configured.${c.reset} Run ${c.cyan}/plexor-login${c.reset} first.`);
40
+ process.exit(1);
41
+ }
42
+
43
+ const apiKey = config.auth?.api_key;
44
+ const enabled = config.settings?.enabled ?? false;
45
+ const mode = config.settings?.mode || 'balanced';
46
+ const provider = config.settings?.preferred_provider || 'auto';
47
+ const localCache = config.settings?.localCacheEnabled ?? false;
48
+ const apiUrl = config.settings?.apiUrl || 'https://api.plexor.dev';
49
+
50
+ if (!apiKey) {
51
+ console.log(`${c.yellow}Not authenticated.${c.reset} Run ${c.cyan}/plexor-login${c.reset} first.`);
52
+ process.exit(1);
53
+ }
54
+
55
+ // Fetch user info and stats
56
+ let user = { email: 'Unknown', tier: { name: 'Free', limits: {} } };
57
+ let stats = { period: {}, summary: {} };
58
+
59
+ try {
60
+ [user, stats] = await Promise.all([
61
+ fetchJson(apiUrl, '/v1/user', apiKey),
62
+ fetchJson(apiUrl, '/v1/stats', apiKey)
63
+ ]);
64
+ } catch (err) {
65
+ // Continue with defaults if API fails
66
+ }
67
+
68
+ // Extract data
69
+ const email = user.email || 'Unknown';
70
+ const tierName = (user.tier?.name || 'Free').charAt(0).toUpperCase() + (user.tier?.name || 'free').slice(1);
71
+ const monthlyOpts = user.tier?.limits?.monthly_optimizations || 10000;
72
+ const monthlyComps = user.tier?.limits?.monthly_completions || 100000;
73
+
74
+ const period = stats.period || {};
75
+ const summary = stats.summary || {};
76
+
77
+ const formatDate = (iso) => {
78
+ if (!iso) return '?';
79
+ const d = new Date(iso);
80
+ return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
81
+ };
82
+ const weekRange = `${formatDate(period.start)} - ${formatDate(period.end)}`;
83
+
84
+ // Format numbers
85
+ const formatNum = (n) => (n || 0).toLocaleString();
86
+ const formatPct = (n) => (n || 0).toFixed(1);
87
+ const formatCost = (n) => (n || 0).toFixed(2);
88
+
89
+ // Calculate usage percentages for progress bars
90
+ const optsUsed = summary.total_optimizations || 0;
91
+ const compsUsed = summary.total_completions || 0;
92
+ const optsPct = Math.min((optsUsed / monthlyOpts) * 100, 100);
93
+ const compsPct = Math.min((compsUsed / monthlyComps) * 100, 100);
94
+
95
+ // Progress bar renderer
96
+ const progressBar = (pct, width = 30) => {
97
+ const filled = Math.round((pct / 100) * width);
98
+ const empty = width - filled;
99
+ const color = pct < 50 ? c.bgBlue : pct < 80 ? c.bgYellow : c.bgGreen;
100
+ return `${color}${' '.repeat(filled)}${c.reset}${c.bgGray}${' '.repeat(empty)}${c.reset}`;
101
+ };
102
+
103
+ const status = enabled ? `${c.green}● Active${c.reset}` : `${c.gray}○ Inactive${c.reset}`;
104
+ const optStatus = enabled ? `${c.green}Enabled${c.reset}` : `${c.gray}Disabled${c.reset}`;
105
+ const cacheStatus = localCache ? `${c.green}Enabled${c.reset}` : `${c.gray}Disabled${c.reset}`;
106
+ const cacheRate = formatPct((summary.cache_hit_rate || 0) * 100);
107
+
108
+ // Build dashboard URL
109
+ const dashboardUrl = apiUrl.replace('.api.', '.').replace('/api', '') + '/dashboard.html';
110
+
111
+ // Savings highlight
112
+ const savingsPct = summary.cost_saved_percent || 0;
113
+ const savingsColor = savingsPct > 50 ? c.green : savingsPct > 20 ? c.yellow : c.white;
114
+
115
+ console.log(`
116
+ ${c.bold}${c.cyan}Plexor Status${c.reset}
117
+
118
+ ${c.bold}Account${c.reset}
119
+ ${c.gray}Tier:${c.reset} ${c.cyan}${tierName}${c.reset}
120
+ ${c.gray}Email:${c.reset} ${email}
121
+ ${c.gray}Status:${c.reset} ${status}
122
+
123
+ ${c.bold}This Week${c.reset} ${c.dim}(${weekRange})${c.reset}
124
+ ${c.gray}Requests:${c.reset} ${formatNum(summary.total_requests)}
125
+ ${c.gray}Original tokens:${c.reset} ${formatNum(summary.original_tokens)}
126
+ ${c.gray}Optimized tokens:${c.reset} ${formatNum(summary.optimized_tokens)}
127
+ ${c.gray}Tokens saved:${c.reset} ${c.green}${formatNum(summary.tokens_saved)}${c.reset} ${c.dim}(${formatPct(summary.tokens_saved_percent)}%)${c.reset}
128
+ ${c.gray}Baseline cost:${c.reset} $${formatCost(summary.baseline_cost)}
129
+ ${c.gray}Actual cost:${c.reset} $${formatCost(summary.total_cost)}
130
+ ${c.gray}Cost saved:${c.reset} ${savingsColor}$${formatCost(summary.cost_saved)}${c.reset} ${c.dim}(${formatPct(savingsPct)}%)${c.reset}
131
+
132
+ ${c.bold}Usage Limits${c.reset}
133
+ ${c.gray}Optimizations${c.reset}
134
+ ${progressBar(optsPct)} ${formatPct(optsPct)}% used
135
+ ${c.dim}${formatNum(optsUsed)} / ${formatNum(monthlyOpts)} this month${c.reset}
136
+
137
+ ${c.gray}Completions${c.reset}
138
+ ${progressBar(compsPct)} ${formatPct(compsPct)}% used
139
+ ${c.dim}${formatNum(compsUsed)} / ${formatNum(monthlyComps)} this month${c.reset}
140
+
141
+ ${c.bold}Performance${c.reset}
142
+ ${c.gray}Cache hit rate:${c.reset} ${cacheRate}%
143
+
144
+ ${c.bold}Settings${c.reset}
145
+ ${c.gray}Optimization:${c.reset} ${optStatus}
146
+ ${c.gray}Local cache:${c.reset} ${cacheStatus}
147
+ ${c.gray}Mode:${c.reset} ${c.cyan}${mode}${c.reset}
148
+ ${c.gray}Provider routing:${c.reset} ${c.cyan}${provider}${c.reset}
149
+
150
+ ${c.dim}Dashboard:${c.reset} ${c.blue}${dashboardUrl}${c.reset}
151
+ `);
152
+ }
153
+
154
+ function fetchJson(apiUrl, endpoint, apiKey) {
155
+ return new Promise((resolve, reject) => {
156
+ const url = new URL(`${apiUrl}${endpoint}`);
157
+
158
+ const options = {
159
+ hostname: url.hostname,
160
+ port: 443,
161
+ path: url.pathname,
162
+ method: 'GET',
163
+ headers: {
164
+ 'X-Plexor-Key': apiKey
165
+ }
166
+ };
167
+
168
+ const req = https.request(options, (res) => {
169
+ let data = '';
170
+ res.on('data', chunk => data += chunk);
171
+ res.on('end', () => {
172
+ try {
173
+ resolve(JSON.parse(data));
174
+ } catch {
175
+ reject(new Error('Invalid response'));
176
+ }
177
+ });
178
+ });
179
+
180
+ req.on('error', reject);
181
+ req.setTimeout(5000, () => {
182
+ req.destroy();
183
+ reject(new Error('Timeout'));
184
+ });
185
+ req.end();
186
+ });
187
+ }
188
+
189
+ main().catch(err => {
190
+ console.error(`${c.red}Error:${c.reset} ${err.message}`);
191
+ process.exit(1);
192
+ });
@@ -4,95 +4,21 @@ description: Show Plexor optimization statistics and savings (user)
4
4
 
5
5
  # Plexor Status
6
6
 
7
- Show current Plexor proxy status, configuration, and usage statistics.
7
+ Display Plexor optimization statistics with colors and progress bars.
8
8
 
9
- ## Steps
9
+ ## Instructions
10
10
 
11
- **Step 1: Read the configuration file**
11
+ Run the status script and show its output:
12
12
 
13
- Use the Read tool to read the file `~/.plexor/config.json`. If the file doesn't exist, tell the user to run `/plexor-login` first.
14
-
15
- **Step 2: Parse configuration and check authentication**
16
-
17
- The config file contains:
18
- - `enabled`: boolean - whether Plexor proxy is enabled
19
- - `apiUrl`: string - the API URL (e.g., "https://api.plexor.dev")
20
- - `apiKey`: string - the user's API key (starts with "plx_")
21
- - `mode`: string - optimization mode ("eco", "balanced", "quality", "passthrough")
22
- - `preferredProvider`: string - provider preference ("auto", "claude", "openai", etc.)
23
- - `localCacheEnabled`: boolean - whether local caching is enabled
24
-
25
- If `apiKey` is missing or empty, tell the user to run `/plexor-login` first.
26
-
27
- **Step 3: Call the APIs**
28
-
29
- First, get user info:
30
- ```
31
- GET {apiUrl}/v1/user
32
- X-Plexor-Key: {apiKey}
33
- ```
34
-
35
- Then, get usage statistics:
36
- ```
37
- GET {apiUrl}/v1/stats
38
- X-Plexor-Key: {apiKey}
39
- ```
40
-
41
- The stats response contains:
42
- - `summary.total_requests`: number of requests
43
- - `summary.original_tokens`: tokens before optimization
44
- - `summary.optimized_tokens`: tokens after optimization
45
- - `summary.tokens_saved`: tokens saved
46
- - `summary.tokens_saved_percent`: percentage saved
47
- - `summary.baseline_cost`: cost without optimization
48
- - `summary.total_cost`: actual cost
49
- - `summary.cost_saved`: money saved
50
- - `summary.cost_saved_percent`: percentage saved
51
- - `summary.cache_hit_rate`: cache hit rate
52
- - `period.start` / `period.end`: date range
53
-
54
- **Step 4: Display the status**
55
-
56
- Show the user a formatted status display:
57
-
58
- ```
59
- ┌─────────────────────────────────────────────┐
60
- │ Plexor Status │
61
- ├─────────────────────────────────────────────┤
62
- │ Account: [tier from /v1/user] │
63
- │ Email: [email from /v1/user] │
64
- │ Status: ● Active │
65
- ├─────────────────────────────────────────────┤
66
- │ This Week ([period.start] - [period.end]) │
67
- │ ├── Requests: [total_requests] │
68
- │ ├── Original tokens: [original_tokens] │
69
- │ ├── Optimized tokens: [optimized_tokens] │
70
- │ ├── Tokens saved: [tokens_saved] ([tokens_saved_percent]%) │
71
- │ ├── Baseline cost: $[baseline_cost] │
72
- │ ├── Actual cost: $[total_cost] │
73
- │ └── Cost saved: $[cost_saved] ([cost_saved_percent]%) │
74
- ├─────────────────────────────────────────────┤
75
- │ Performance │
76
- │ └── Cache hit rate: [cache_hit_rate]% │
77
- ├─────────────────────────────────────────────┤
78
- │ Limits │
79
- │ ├── Monthly optimizations: [from tier] │
80
- │ └── Monthly completions: [from tier] │
81
- ├─────────────────────────────────────────────┤
82
- │ Settings │
83
- │ ├── Optimization: [Enabled/Disabled] │
84
- │ ├── Local cache: [Enabled/Disabled] │
85
- │ ├── Mode: [mode] │
86
- │ └── Provider routing: [preferredProvider] │
87
- └─────────────────────────────────────────────┘
88
-
89
- Dashboard: [apiUrl]/dashboard
13
+ ```bash
14
+ node ~/.claude/plugins/plexor/commands/plexor-status.js
90
15
  ```
91
16
 
92
- Notes:
93
- - Use "● Active" (green dot) if enabled, "○ Inactive" if disabled
94
- - Format token counts with commas (e.g., 46,700)
95
- - Format costs with 2 decimal places (e.g., $8.02)
96
- - Multiply cache_hit_rate by 100 for percentage display
17
+ The script outputs colored terminal UI with:
18
+ - Account info and status
19
+ - Weekly usage statistics
20
+ - Progress bars for usage limits
21
+ - Cost savings breakdown
22
+ - Current settings
97
23
 
98
- If the API call fails, show the configuration status and mention the API is unavailable.
24
+ Do not add commentary - the script output is the complete response.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plexor-dev/claude-code-plugin",
3
- "version": "0.1.0-beta.7",
3
+ "version": "0.1.0-beta.9",
4
4
  "description": "LLM cost optimization plugin for Claude Code - Save up to 90% on AI costs",
5
5
  "main": "lib/constants.js",
6
6
  "scripts": {
package/lib/constants.js DELETED
@@ -1,40 +0,0 @@
1
- /**
2
- * Plexor Claude Code Plugin - Constants
3
- */
4
-
5
- const path = require('path');
6
- const os = require('os');
7
-
8
- module.exports = {
9
- // API endpoints
10
- PLEXOR_API_URL: process.env.PLEXOR_API_URL || 'https://api.plexor.dev',
11
- PLEXOR_GATEWAY_URL: process.env.PLEXOR_GATEWAY_URL || 'https://api.plexor.dev/v1',
12
- PLEXOR_AUTH_URL: 'https://plexor.dev/auth/device',
13
-
14
- // File paths
15
- PLEXOR_CONFIG_DIR: process.env.PLEXOR_CONFIG_DIR || path.join(os.homedir(), '.plexor'),
16
- PLEXOR_CONFIG_FILE: path.join(
17
- process.env.PLEXOR_CONFIG_DIR || path.join(os.homedir(), '.plexor'),
18
- 'config.json'
19
- ),
20
- CLAUDE_COMMANDS_DIR: path.join(os.homedir(), '.claude', 'commands'),
21
-
22
- // Config schema version
23
- CONFIG_VERSION: 1,
24
-
25
- // Default settings
26
- DEFAULTS: {
27
- enabled: true,
28
- preferred_provider: 'auto',
29
- telemetry: true,
30
- local_cache: false
31
- },
32
-
33
- // API key prefix for identification
34
- API_KEY_PREFIX: 'plx_',
35
-
36
- // Timeouts (ms)
37
- DEVICE_CODE_POLL_INTERVAL: 5000,
38
- DEVICE_CODE_TIMEOUT: 900000, // 15 minutes
39
- API_TIMEOUT: 30000
40
- };